컴퓨터 알고리즘 2023-03-20 수업정리

Flow

Divide and Conquer - Quicksort


Quicksort Algorithm(퀵 정렬)

Worst-case Complexity of Quicksort

Average-case time complexity of Quicksort

n개의 서로 다른 원소를 가지는 배열에서 Mn = total comparison이라고 하자. $$M_n = \sum_{j=1}^n(n-1 + M_{j-1} + M_{n-j})\frac{1}{n}$$ $$M_n =n-1 + \frac{2}{n}\sum_{k=1}^{n-1}M_k$$ $$nM_n = n(n-1)+2\sum_{k=1}^{n-1}\ \ ...\ (1)$$ 이렇게 얻어진 식의 n에 n+1을 대입하면$$(n+1)M_{n+1} = n(n+1) + 2\sum_{k=1}^{n}M_k\ \ \ ...\ (2)$$(2) - (1)을 하면$$(n+1)M_{n+1} = (n+2)M_n+2n$$$$\frac{M_{n+1}}{n+2} = \frac{M_n}{n+1}+\frac{2n}{(n+1)(n+2)}$$ $$\frac{M_{n+1}}{n+2} = \frac{M_{n-1}}{n} + \frac{2(n-1)}{n(n+1)} +\frac{2n}{(n+1)(n+2)} = 2 \sum_{k=0}^{n-1}\frac{n-k}{(n+1-k)(n+2-k)}$$ n-k를 i로 치환하면$$M_{n+1} = 2(n+2)\sum_{k=0}^{n-1}\frac{n-k}{(n+1-k)(n+2-k)} = 2(n+2)\sum_{i=1}^{n}\frac{i}{(i+1)(i+2)}$$ 부분분수로 분리하면$$M_{n+1} = 2(n+2)\sum_{i=1}^n[\frac{2}{i+2}-\frac{1}{i+1}]$$ Average-case에 대해 Time complexity를 고려중이다. 분포는 균일분포이며, 이때의 평균값을 Average-case라 말할 수 있으므로 정적분을 취해 계산을 이어갈 수 있다.$$M_{n+1} = 2(n+2)[\int_3^{n+2}\frac{2}{x}dx - \int_2^{n+1}\frac{1}{x}dx] = 2(n+2)[2log(n+2) - log(n+1) + log2 - 2log3]$$ $$M_{n+1} = 2(n+2)[log(n+2) + log(\frac{n+2}{n+1}) + log2 - 2log3]$$

따라서 Quicksort Algorithm의 Average-Case Time Complexity는 다음과 깉이 말할 수 있다. $$M_n \in \Theta(nlogn)$$

Implementataion

#include <iostream>
using namespace std;
 
int partition(int arr[], int pivot, int first, int last)
{
    int pivotIndex = first++;
    while(first <= last)
    {
        if(arr[first] > pivot && arr[last] <= pivot)
        {
            int tmp = arr[first];
            arr[first] = arr[last];
            arr[last] = tmp;
        }
 
        if(arr[first] <= pivot) first++;
        if(arr[last] > pivot) last--;
    }
 
    return last;
}
 
void quickSort(int arr[], int first, int last)
{
    if(first < last)
    {
        int pivot = arr[first];
        int splitPoint = partition(arr, pivot, first, last);
 
        arr[first] = arr[splitPoint];
        arr[splitPoint] = pivot;
 
        quickSort(arr, first, splitPoint-1);
        quickSort(arr, splitPoint+1, last);
    }
}
 
int main()
{
    int arrSize; cin >> arrSize;
 
    int * arr = new int[arrSize];
    for(int i = 0; i < arrSize; i++)
        cin >> arr[i];
 
    quickSort(arr, 0, arrSize-1);
 
    for(int i = 0; i < arrSize; i++)
        cout << arr[i] << " ";
    cout << endl;
 
    return 0;
}