소프트웨어 공부/자료구조

[자료구조] 퀵 셀렉트

야곰야곰+책벌레 2021. 12. 27. 14:36
728x90
반응형

무작위로 정렬된 배열이 있을 때, 정렬은 안 해도 되지만 배열에서 열 번째로 작은 값 혹은 열다섯 번째로 큰 값을 알고 싶다고 하자. 가령 수많은 시험 점수가 있을 때 25번째 백분위수나 중간 점수를 알고 싶을 때 도움이 될 것이다. 전체 배열을 정렬한 후 적절한 셀을 바로 찾아보면 확실히 문제를 해결할 수 있지만 퀵 셀렉트라고 알려진 뛰어난 작은 알고리즘으로 훨씬 더 나은 성능을 낼 수 있다. 퀵 셀렉트도 퀵 정렬처럼 분할에 기반하며, 퀵 정렬과 이진 검색의 하이브리드 정도로 생각할 수 있다.

 

값이 8개인 배열이 있을 때 이 배열 내에서 두 번째로 작은 값을 찾고 싶다고 하자. 먼저 전체 배열을 분할한다.

분할 후 피벗은 배열의 중간 부분에 있을 것이다.

이제 피벗은 올바른 위치며, 다섯 번째 셀이므로 어떤 값이 배열 내에서 다섯 번째로 작은지 알게 됐다. 두 번째로 작은 값은 피벗의 왼쪽 어딘가에 있다는 것도 안다. 이제 피벗 오른쪽에 있는 모든 수는 무시한다. 퀵 정렬과 유사하지만 퀵 셀렉트는 나눠진 반쪽에만 집중한다.

이제 피벗 왼쪽에 있는 하위 배열을 분할한다. 새 피벗은 세 번째 셀로 하자.

이제 세 번째 셀의 값이 올바른 위치에 있게 됐고, 이 값이 배열에서 세 번째로 작은 값임을 안다. 두 번째 작은 값을 구하기 위해 또 한 번 왼쪽에 있는 하위 배열을 분할하자.

분할이 끝나면 가장 작은 값과 두 번째로 작은 값이 배열 내에서 올바른 위치에 있게 된다. 이제 이 값을 가져와 사용할 수 있다. 퀵 셀렉트의 훌륭한 점 중 하나는 전체 배열을 정렬하지 않고도 올바른 값을 찾을 수 있다는 것이다.

#include <vector>
#include <iostream>
using namespace std;

class CSortArray
{
public:
	CSortArray() = default;
	CSortArray(vector<int>& arr)
	{
		array = arr;
	}

	int partition(int lptr, int rptr)
	{
		int pivot_pos = rptr;
		int pivot = array[pivot_pos];
		rptr--;

		while (true)
		{
			while (array[lptr] < pivot)
				lptr++;
			while (array[rptr] > pivot)
				rptr--;

			if (lptr >= rptr)
				break;
			else
				swap(lptr, rptr);
		}

		swap(lptr, pivot_pos);
		return lptr;
	}

	void swap(int ptr1, int ptr2)
	{
		int tmp_value = array[ptr1];
		array[ptr1] = array[ptr2];
		array[ptr2] = tmp_value;
	}

	vector<int> array;
};

class CQuickSelection : public CSortArray
{
public:
	CQuickSelection() = default;
	CQuickSelection(vector<int>& arr) : CSortArray(arr) {};

	int quickselection(int lowest_value, int leftIndex, int rightIndex)
	{
		if (rightIndex - leftIndex <= 0)
			return array[leftIndex];

		int pivot_pos = partition(leftIndex, rightIndex);

		if (lowest_value < pivot_pos)
			return quickselection(lowest_value, leftIndex, pivot_pos - 1);
		else if (lowest_value > pivot_pos)
			return quickselection(lowest_value, pivot_pos + 1, rightIndex);
		
		return array[pivot_pos];
	}
};

int main()
{
	vector<int> testArr = { 0, 50, 20, 10, 60, 30 };
	CQuickSelection quickSort(testArr);
	int n = quickSort.quickselection(3, 0, testArr.size() - 1);

	cout << n << endl;
	return 0;
}

index는 0부터 시작하므로 4번째를 찾으려고 3을 기입했다. 결과는 4번째 값인 30이 출력되었다.

728x90
반응형

'소프트웨어 공부 > 자료구조' 카테고리의 다른 글

[자료구조] 이진 트리  (0) 2021.12.28
[자료구조] 연결 리스트(linked list)  (0) 2021.12.27
[자료구조] 퀵 정렬  (0) 2021.12.27
[자료구조] 분할  (0) 2021.12.27
[자료구조] 재귀(recursion)  (0) 2021.12.27