4가지 통계값 찾기 문제를 다른방법으로 풀어보자2

2018, Aug 13    

이전 포스팅에서 Median 값을 찾기 위해 QuickSelect 를 이용했었다. QuickSelect의 경우 pivot 값이 무엇인지에 따라 속도가 달라질 수 있다. 중위값 찾는 함수를 median of median 알고리즘을 이용하여 pivot 값을 찾고 median 값을 구하는 함수로 수정해보자.

다음은 이전에 구현한 중위값을 찾는 함수이다. 여기서는 pivotIndex 를 가장 마지막 인덱스로 지정했다. 이부분을 바꿔보자.

int partition(int* arr, int left, int right, int pivotIndex)
{
	swap(arr + pivotIndex, arr + right);
	int res_pivotIdx = right; int l = left;
	for(int i = left; i< right; i++)
	{
		if(arr[i] > arr[res_pivotIdx])
			continue;
		swap(arr+i, arr+l++);
	}

	swap(arr+l , arr+res_pivotIdx);
	res_pivotIdx = l;
	return res_pivotIdx;
}

int QuickSelect(int* arr, int left, int right, int k)
{
	int pivotIndex = right;
	pivotIndex = partition(arr, left, right, pivotIndex);

	if(k < pivotIndex)
		return QuickSelect(arr, left, pivotIndex-1, k);
	else if(k < pivotIndex +1 )
		return arr[pivotIndex];
	else
		return QuickSelect(arr, pivotIndex + 1, right, k);
}

int FindMiddleValue(int* arr, int size)
{
	return QuickSelect(arr, 0, size-1, size /2 );
}
int QuickSelect(int* arr, int left, int right, int k)
{
    /// 이 부분을 수정한다.
	/// int pivotIndex = right;
    int pivot = MedianOfMedian(arr, size);
    int pivotIndex;
    for(int i=0; i<size; i++)
    {
        if(pivot == arr[i])
        {
            pivotIndex = i;
            break;
        }
    }
	pivotIndex = partition(arr, left, right, pivotIndex);

	if(k < pivotIndex)
		return QuickSelect(arr, left, pivotIndex-1, k);
	else if(k < pivotIndex +1 )
		return arr[pivotIndex];
	else
		return QuickSelect(arr, pivotIndex + 1, right, k);
}

MedianOfMedian 을 구현해보자

int MedianOfMedian(int* arr, int size)
{
    if(size < 5)
    {
        for(int i=0; i<size-1; i++)
        {
            int minIndex = i;
            for(int j=1; j<size; j++)
            {
                if(arr[minIndex] > arr[j])
                    minIndex = j;
            }
            swap(arr + i, arr + minIndex);
        }
        return arr[size/2];
    }

    int m = size / 5;
    int* medians = new int[m];
    for(int i=0; i<m; i++)
    {
        int* w = arr + i*5;
        for(int j=0; j<3; j++)
        {
            int minIndex = j;
            for(int k=j+1; k<5; k++)
            {
                if(w[minIndex] > w[k])
                    minIndex = k;
            }
            swap(w + j, w + minIndex);
        }
        medians[i] = w[2];
    }

    int pivot = MedianOfMedian(medians, m);
    delete[] medians;
    return pivot;
}