1. 程式人生 > >演算法:快速排序穩定性

演算法:快速排序穩定性

快速排序(Quick Sort)使用分治法策略
它的基本思想是:選擇一個基準數,通過一趟排序將要排序的資料分割成獨立的兩部分;其中一部分的所有資料都比另外一部分的所有資料都要小。然後,再按此方法對這兩部分資料分別進行快速排序,整個排序過程可以遞迴進行,以此達到整個資料變成有序序列。

快速排序流程:
(1) 從數列中挑出一個基準值。
(2) 將所有比基準值小的擺放在基準前面,所有比基準值大的擺在基準的後面(相同的數可以到任一邊);在這個分割槽退出之後,該基準就處於數列的中間位置。
(3) 遞迴地把"基準值前面的子數列"和"基準值後面的子數列"進行排序。

快速排序穩定性
快速排序是不穩定的演算法,它不滿足穩定演算法的定義。
演算法穩定性 -- 假設在數列中存在a[i]=a[j],若在排序之前,a[i]在a[j]前面;並且排序之後,a[i]仍然在a[j]前面。則這個排序演算法是穩定的!

快速排序時間複雜度
快速排序的時間複雜度在最壞情況下是O(N2),平均的時間複雜度是O(N*lgN)。
這句話很好理解:假設被排序的數列中有N個數。遍歷一次的時間複雜度是O(N),需要遍歷多少次呢?至少lg(N+1)次,最多N次。
(01) 為什麼最少是lg(N+1)次?快速排序是採用的分治法進行遍歷的,我們將它看作一棵二叉樹,它需要遍歷的次數就是二叉樹的深度,而根據完全二叉樹的定義,它的深度至少是lg(N+1)。因此,快速排序的遍歷次數最少是lg(N+1)次。
(02) 為什麼最多是N次?這個應該非常簡單,還是將快速排序看作一棵二叉樹,它的深度最大是N。因此,快讀排序的遍歷次數最多是N次。

/**
 * 快速排序:C++
 *
 * @author skywang
 * @date 2014/03/11
 */

#include <iostream>
using namespace std;

/*
 * 快速排序
 *
 * 引數說明:
 *     a -- 待排序的陣列
 *     l -- 陣列的左邊界(例如,從起始位置開始排序,則l=0)
 *     r -- 陣列的右邊界(例如,排序截至到陣列末尾,則r=a.length-1)
 */
void quickSort(int* a, int l, int r)
{
    if (l < r)
    {
        int i,j,x;

        i = l;
        j = r;
        x = a[i];
        while (i < j)
        {
            while(i < j && a[j] > x)
                j--; // 從右向左找第一個小於x的數
            if(i < j)
                a[i++] = a[j];
            while(i < j && a[i] < x)
                i++; // 從左向右找第一個大於x的數
            if(i < j)
                a[j--] = a[i];
        }
        a[i] = x;
        quickSort(a, l, i-1); /* 遞迴呼叫 */
        quickSort(a, i+1, r); /* 遞迴呼叫 */
    }
}

int main()
{
    int i;
    int a[] = {30,40,60,10,20,50};
    int ilen = (sizeof(a)) / (sizeof(a[0]));

    cout << "before sort:";
    for (i=0; i<ilen; i++)
        cout << a[i] << " ";
    cout << endl;

    quickSort(a, 0, ilen-1);

    cout << "after  sort:";
    for (i=0; i<ilen; i++)
        cout << a[i] << " ";
    cout << endl;

    return 0;
}