-
728x90
퀵 정렬 : 하나의 큰 문제를 두 개의 작은 문제로 분할하는 정렬 알고리즘이다.
특정한 값을 기준(pivot)으로 큰 숫자와 작은 숫자를 선택해 서로 교환한 뒤 배열을 반으로 나눈다. 일반적으로 pivot은 첫번째 원소부터 설정된다.
Ex)
pivot을 기준으로 왼쪽에선 큰값을 찾고, 오른쪽에선 작은 값을 찾는다.
3 7 8 1 5 9 6 10 2 4
3 2 8 1 5 9 6 10 7 4
3 2 1 8 5 9 6 10 7 4
(작은 값의 인덱스가 큰 값의 인덱스보다 작아 엇갈릴 때 작은 값과 pivot이 교환되어 첫번째 분할이 일어남.)
1 2 3 8 5 9 6 10 7 4
(3을 기준으로하여 왼쪽의 집합과 오른쪽의 집합에서 각각 pivot이 정해진 뒤 정렬을 수행함.)
위의 과정 반복
1 2 3 8 5 4 6 10 7 9
1 2 3 8 5 4 6 7 10 9
1 2 3 7 5 4 6 8 10 9
1 2 3 6 5 4 7 8 10 9
~
1 2 3 4 5 6 7 8 9 10
정렬을 수행했을 때 왼쪽과 오른쪽이 계속 나눠진다.
시간복잡도 : 선택, 버블, 삽입 정렬에 비해 훨씬 빠른 분할 정복 알고리즘으로 평균적인 시간복잡도는 O(N*logN)이다.데이터의 개수가 n개이고, 반씩 분할되므로 O(N*logN)이 나오게 된다.
그러나, 최악의 경우 O(N^2)이 나오는데 이미 정렬이 되어있는 경우 pivot을 설정하고 분할이 되지않으므로(엇갈릴 때 계속 자기 자신과 스왑하므로) 연산 횟수가 N^2/2번이 나오게 된다. 이러한 경우 삽입 정렬을 사용하는 것이 속도가 빠르다.
#include <iostream> using namespace std; int n = 10; int data[10] = {1, 10, 5, 8, 7, 6, 4, 3, 2, 9}; void Quick_Sort(int* data, int start, int end) { if(start >= end) // 원소가 1개인 경우 return; int pivot = start; // pivot은 처음에 첫번째 원소로 설정됨. int i = start + 1; // 왼쪽 출발 지점 int j = end; // 오른쪽 출발 지점 int temp; while(i<=j) { // 엇갈릴 때까지 반복 while(data[i]<=data[pivot]) // 피봇 값보다 큰 값을 만날때까지 오른쪽 이동 i++; while(data[j]>=data[pivot] && j > start) // 피봇 값보다 작은 값을 만날때까지 왼쪽 이동 j--; if(i>j) { // 현재 엇갈린 상태면 피봇 값과 교체 temp = data[j]; data[j] = data[pivot]; data[pivot] = temp; } else { temp = data[i]; data[i] = data[j]; data[j] = temp; } } // 엇갈렸을 때 스왑한 후 분할이 일어나고 다시 왼쪽과 오른쪽에서 퀵정렬이 수행된다. Quick_Sort(data, start, j-1); Quick_Sort(data, j+1, end); } int main() { Quick_Sort(data, 0, n-1); for(int i = 0; i<n; i++) { cout<<data[i]<<' '; } }
728x90