很早以前看過快排算法覺得自己掌握了,,課今天用的時候發現老出錯,認真想想發現自己一直搞錯了。。。
下面先說一下我的想法:
首先,快排的思想就是
- 從數列中挑出一個元素,稱為 "基准"(pivot),
- 重新排序數列,所有元素比基准值小的擺放在基准前面,所有元素比基准值大的擺在基准的后面(相同的數可以到任一邊)。在這個分區退出之后,該基准就處於數列的中間位置。這個稱為分區(partition)操作。
- 遞歸地(recursive)把小於基准值元素的子數列和大於基准值元素的子數列排序
那么這里需要考慮的就是如何進行分區,這個是最重要的,先來看看我的分區的實現:(這里的provit我就不用隨機數來實現了,直接選第一個)
int partition(int array[], int begin, int end) {
int index = begin;
int proviet = array[begin];
swap(array[index], array[end]);//將provit換到最后
for(int i = begin; i != end; i++) {//將小於provit的元素放到左邊,大的放到右邊
if (array[i] < proviet)
swap(array[index++], array[i]);
}
swap(array[index], array[end]);
return index;
}
首先,將provit移到數組的最后一位,這樣在數組分區的時候就不會影響到provit,也就是這句
swap(array[index], array[end]);
假設我們要分區的數組是6 7 4 3 56 5, 那么到現在數組應該變成這樣了 
然后,就要將除 provit 意外的全部元素進行遍歷,此時 index 是 0,i 也從 0 開始。那么因為第一個 5 < 6,所以變成這樣
,
到第三步,因為7>6, 所以 index 沒變,而 i 自增,即這樣
,那么此時因為 4 < 6, 所以將 4 和 7 交換,變成這樣
。
下面的一招這個原理即可。那么,到 for 循環完成后,數組變成如下:
,這時,因為 index 位的數大於等於 privot, 所以將他們交換,最后達到的效果就是大的全在右邊,小的全在左邊。
然后是 quickSort()的內容:
void quickSort(int array[], int begin, int end) {
if (begin >= end)
return;
int position = partition(array, begin, end);
quickSort(array, begin, position - 1);
quickSort(array, position + 1, end);
}
這里就是用遞歸的方法將數列分段進行大小分區,這個應該不難理解。因為每一段內部的元素的都比他后面段的所有元素都小,那么排出來的就應該是一個有序列了。
對於provit的選擇,其實沒有太多的要求,只是說你用隨機數來產生的話更可能得到一個好的 provit 使得分區更好得到更好的速度。因為使用隨機數法使得輸入數據的次序對算法不產生影響。只有在隨機數產生器給出了一個很不巧的排列時,隨機化算法的最壞情況性態才會出現。事實上可以證明幾乎所有的排列都可使快速排序接近平均情況性態,只有非常少的幾個排列才會導致算法的近最壞情況性態。所以一般情況下采用隨機數法。
如果你想用隨機數來實現,可以看看這個http://code.wikia.com/wiki/Random_number
