티스토리 뷰
이 챕터는 Sorting의 한 방법인 Quick Sort에 대해 배운다. Average case의 Time Complexity 증명은 생략하지만, Worst case n2에 average case nlgn인 알고리즘이라고 생각하면 될 것 같다. worst case의 증명은 쉬우니까 알고리즘을 설명하고 한 번 하고 가겠다.
(1) QuickSort Algorithm의 설명
QuickSort algorithm은 다음과 같은 재귀적 알고리즘이다.
(i) 배열의 원소 중 하나의 원소를 골라 Pivot으로 선정한다.
(-->이 Pivot선정을 Randomize시켜야 average nlgn이 나온다.)
(ii)그 Pivot보다 작은 놈들을 Pivot왼쪽에, 큰 놈들을 Pivot오른쪽에 놓는다.(called Partition) Pivot은 q번째 위치에 왔다고 해보자.
(iii)그러면 Pivot은 q번째로 작은 수이다.(왜냐면 pivot보다 작은 놈이 q-1개 나머지는 큰 놈이니까)
(iv)따라서 pivot은 적절한 위치에 왔다고 볼 수 있고 왼쪽과 오른쪽 sub array만 정렬하면 된다.
(v)따라서 recursively 왼쪽과 오른쪽의 subarray에 대해 콜한다.
이 과정을 코드로 나타내보면 다음과 같다.
void QuickSort(int* arr, int p,int r) {
if (p < r) {
int q = Partition(arr, p, r);
QuickSort(arr, p, q - 1);
QuickSort(arr, q + 1, r);
}
}
퀵 소트 자체 구현은 쉽다. 문제는 Partition과정이다.
(2) Partition 과정의 구현
Partition은 위의 그림과 같은 형식으로 구현할 것인데, 우선 주어진 배열의 마지막 원소인 arr[r]을 pivot으로 선정하고 j라는 iterator를 p부터 r-1까지 움직일 것이다. 그리고 다음과 같은 비교를 한다.
(i)arr[j]가 pivot보다 크다면 그냥 j만 증가시킨다.
(ii)arr[j]가 pivot보다 작다면 i를 1 증가시킨 뒤 arr[i]와 arr[j]를 교환한다.
이 과정을 i=p-1로 초기화 한 뒤 반복하게 한다면 arr[i]까지는 pivot보다 작은놈 arr[i+1]~arr[r]은 pivot보다 큰 놈만 있는 상황이 될 것이다.
그러면 arr[i] 바로 뒤가 pivot이 들어갈 자리가 되므로 arr[i+1]과 arr[r]을 swap하면 partition의 역할이 끝난다. 밑은 Partition 코드다.
int Partition(int* arr, int p, int r) {
int pivot = arr[r];
//last element is pivot
int i = p-1; //i+1번째부터 pivot보다 큰 원소들이라고 생각
for (int j = p; j < r; j++) {
if (arr[j] < pivot)
swapPos(arr[++i], arr[j]);
}
swap(arr[i + 1], arr[r]);
return (i + 1);
}
테스트 코드를 포함한 전체 코드는 다음과 같다.
#include<iostream>
#include<time.h>
using namespace std;
void swapPos(int& arr1, int& arr2) {
int temp = arr1;
arr1 = arr2;
arr2 = temp;
}
int Partition(int* arr, int p, int r) {
int pivot = arr[r];
//last element is pivot
int i = p-1; //i+1번째부터 pivot보다 큰 원소들이라고 생각
for (int j = p; j < r; j++) {
if (arr[j] < pivot)
swapPos(arr[++i], arr[j]);
}
swap(arr[i + 1], arr[r]);
return (i + 1);
}
void QuickSort(int* arr, int p,int r) {
if (p < r) {
int q = Partition(arr, p, r);
QuickSort(arr, p, q - 1);
QuickSort(arr, q + 1, r);
}
}
bool Issort(int* arr, int size) {
for (int i = 0; i < size - 1; i++) {
if (arr[i] > arr[i + 1]) return false;
}
return true;
}
int main() {
int arrsize;
cout << "Enter size of array: ";
cin >> arrsize;
const int range = 10000;
int* arr = new int[arrsize];
double m_ratio = 0.5; //Change the ratio of negative numbers
srand((unsigned int)time(NULL));
for (int i = 0; i < arrsize; i++)
{
arr[i] = rand() % range - int(m_ratio * range);
}
QuickSort(arr, 0, arrsize - 1);
cout << ((Issort(arr, arrsize)) ? "success" : "false")<<endl;
for (int i = 0; i < arrsize;i++)
cout << "arr[" << i << "]: " << arr[i]<<endl;
}
Time complexity생각해보면 Quick Sort은 Partition + recursive call이다. 따라서
T(n) = T(q)+T(n-q-1)+n
꼴이 되어서 q가 어디 잘 잡히는지에 의해 복잡도는 바뀔 것이다.
(n은 partition하는데 j가 움직이는 시간)
풀어보면 q가 극단적(p or r)인 경우가 계속 걸릴 때는 n2이 되고 평균적으로는 nlogn이 걸린다고 한다.
'알고리즘의 기초' 카테고리의 다른 글
3-Elementary Data Structure (0) | 2020.02.01 |
---|---|
2-(3) Sorting in Linear time-Counting Sort (0) | 2020.01.30 |
2-(1) HeapSort (0) | 2020.01.24 |
2-(0) (i)Heap (0) | 2020.01.23 |
1-(4) Divide and Conquer-(i) The maximum-subarray problem (0) | 2020.01.21 |
- Total
- Today
- Yesterday
- 사진구조
- gradient descent
- RGB이미지
- 인덱스 이미지
- 이미지
- 이산 신호
- 밑바닥부터 시작하는 딥러닝
- 영상처리
- 연속 신호
- CS
- 영상구조
- Andrew ng
- rnn
- 머신 러닝
- 컴퓨터 과학
- 신경망
- 매트랩
- 이미지처리
- 컴퓨터과학
- ML
- 신호 및 시스템
- 순환 신경망
- 매트랩 함수
- Neural Network
- NLP
- 머신러닝
- Logistic Regression
- 자연어 처리
- 딥러닝
- CNN
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |