1. 程式人生 > >「改進的快速排序」時間複雜度接近O(n)

「改進的快速排序」時間複雜度接近O(n)

1.快速排序知識點回顧:

快速排序採用了一種分治的策略,通常稱其為分治法(Divide-and-Conquer)。

平均時間複雜度為:O(nlogn)

        最好時間複雜度為:O(nlogn), 每次找的基準數最佳,為每個區間的中值。

        最壞時間複雜度為:O(n2), 陣列遞增或者遞減。

空間複雜度:快速排序在系統內部需要一個棧來實現遞迴。若每次劃分較為均勻,則其遞迴樹的高度為 O(lgn), 故遞迴後所需棧空間為 O(lgn) 。最壞情況下,遞迴樹的高度為 O(n), 所需的棧空間為 O(n) 

該方法的基本思想是:

1.先從數列中取出一個數作為基準數。

2.分割槽過程,將比這個數大的數全放到它的右邊,小於或等於它的數全放到它的左邊。

3.再對左右區間重複第二步,直到各區間只有一個數。

快速排序程式碼:

int partition(int arr[], const int& left, const int& right)
{
    if(left < right)
    {
        medianAsPivot(arr, left, right);
        int i = left;
        int j = right;
        int key = arr[i]; // 首元素作為pivot
        while(i < j)
        {
            while(i<j && arr[j]>=key) j--;
            if(i < j) arr[i++] = arr[j];
            while(i<j && arr[i]<key) i++;
            if(i < j) arr[j--] = arr[i];
        }
        arr[i] = key;
        return i;
    }
    return left;
}

// 快速排序遞迴實現
void quickSort(int arr[], const int& left, const int& right)
{
    if(left < right)
    {
        int p = partition(arr, left, right);
        quickSort(arr, left, p-1);
        quickSort(arr, p+1, right);
    }
}

2.Kth Largest Element

http://www.lintcode.com/en/problem/kth-largest-element/

要接近O(n)的解法,必須每次選擇區間的中值最為基準值。

void adjustPivot(vector<int> &nums, int left, int right)
{
    int middle = (left & right) + ((left ^ right) >> 1);
    if(nums[middle] >= min(nums[left], nums[right]) && nums[middle] <= max(nums[left], nums[right]))
        swap(nums[left], nums[middle]);
    else if(nums[right] >= min(nums[left], nums[middle]) && nums[right] <= max(nums[left], nums[middle]))
        swap(nums[left], nums[right]);
}

int partition(vector<int> &nums, int left, int right)
{
    if(left < right)
    {
        adjustPivot(nums, left, right);
        int pivot = nums[left];
        while(left < right)
        {
            while(left < right && nums[right] > pivot) 
                right--;
            if(left < right) nums[left++] = nums[right];
            while(left < right && nums[left] <= pivot) 
                left++;
            if(left < right) nums[right--] = nums[left];
        }
        nums[left] = pivot;
    }
    return left;
}

int kthLargestElement(int k, vector<int> nums)
{
    int size = nums.size();
    if(k <= 0 || k > size) 
        return -1;
    int left = 0;
    int right = size - 1;
    while(true)
    {
        int position = partition(nums, left, right);
        if(position < size-k) left = position + 1; 
        else if(position > size-k) right = position - 1;
        else return nums[size - k];
    }
}