C# 프로그래밍 기초 실습 전자책

C# / .NET 알고리즘과 퀴즈
본 알고리즘 퀴즈 문제는 C#/.NET 개발자를 위한 알고리즘 인터뷰 혹은 C# 프로그래밍을 통한
문제 해결 알고리즘을 연구해 보는데 도움이 되고자 작성되었습니다.


퀴즈 질문


예상답변/설명

입력 데이타가 스트림으로 계속 들어오기 때문에, 미리 전체 입력 자료의 수를 알 수 없다. 따라서 입력을 해가면서 중간값 상태를 계속 유지할 필요가 있다. 중간값을 구하기 위해서 현재까지 입력된 데이타를 2개의 서브셋으로 나눌 수 있다. 만약 전체 입력 수가 짝수라면, 두 서브셋의 갯수는 동일하며, 첫 서브셋의 최대값과 두번째 서브셋의 최소값이 중간값을 구하는데 사용될 수 있다. 만약 입력 수가 홀수라면, 두 서브셋중 하나(최대 혹은 최소)에서 중간값을 구할 수 있다. 이러한 서브셋을 구현하기 위해 MaxHeap과 MinHeap을 사용할 수 있는데, 이는 Heap이 정렬되지 않은 집합에서도 항상 최대 혹은 최소를 즉시 (O(1)) 구할 수 있는 장점을 이용할 수 있기 때문이다.

연속적인 데이타라는 특성을 반영하기 위해서 maxheap, minheap을 private field로 두고 데이타를 입력받는 메서드와 특정 싯점에 중간값을 출력하는 메서드를 아래와 같이 생각해 볼 수 있다. (MaxHeap, MinHeap은 힙 자료구조(http://www.csharpstudy.com/DS/heap.aspx) 예제 참조)

class Median
{
    private MaxHeap maxHeap = new MaxHeap();
    private MinHeap minHeap = new MinHeap();   

    public void AddValue(int num)
    {
        if (minHeap.Count == maxHeap.Count)
        {
            if (minHeap.Count > 0 && maxHeap.Peek() > num)
            {
                minHeap.Add(maxHeap.RemoveOne());
                maxHeap.Add(num);
            }
            else
                minHeap.Add(num);
        }
        else //같지 않으면 minheap이 1개 많음
        {
            if (minHeap.Peek() < num)
            {
                maxHeap.Add(minHeap.RemoveOne());
                minHeap.Add(num);
            }
            else
            {
                maxHeap.Add(num);
            }
        }
    }

    public int GetMedian()
    {
        if (maxHeap.Count == minHeap.Count)
            return (maxHeap.Peek() + minHeap.Peek()) / 2;
        else
            return minHeap.Peek();
    }
}

// 테스트
var m = new Median();
for (int i = 1; i <= 10; i++)  m.AddValue(i);
Console.WriteLine(m.GetMedian());
for (int i = 11; i <= 20; i++)  m.AddValue(i);
Console.WriteLine(m.GetMedian());