快速排序通常是用于排序的最佳實用選擇,雖然最壞情況下時間性能為O(n*n),但其平均時間性能為O(nlgn)且記號中隱含的常數因子很小,且為原地排序。
快速排序也是一種分治模式,其基本思想如下:找出一個元素(理論上可以隨便找一個)作為基準(pivot),然后對數組進行分區(Partition,核心部分)操作,使基準左邊元素的值都不大于基準值,基準右邊的元素值 都不小于基準值,如此作為基準的元素調整到排序后的正確位置;然后再按次方法對這兩部分數據分別進行快速排序,整個排序過程可以遞歸進行,以此達到整個數據變成有序序列。
//Partition PHP實現?
function Partition(&$array,$p,$r){
? ? $key=$array[$p];
? ? $i=$p; ? $j=$r;
? ? while($i<$j){
? ? while($i<$j&&$array[$j]>$key){$j--;}
? ? if($i<$j){$array[$i]=$array[$j]; i++;}
? ? while($i<$j&&$array[$i]<$key){$i++;}
? ? if($i<$j){$array[$j]=$array[$i]; ?$j--;}
? ? }
? ?$array[$i]=$key;
return $i;
}
//快速排序 ?PHP實現
function Quick_sort(&$array,$p,$r){
? ? if($p<$r){
? ? ? ? $pivot=Partition($array,$p,$r);
? ? ? ? Quick_sort($array,$p,$pivot-1);
? ? ? ? Quick_sort($array,$pivot+1,$r);
? ? }
}
快速排序的運行時間與劃分是否對稱有關,而后者又與選擇了哪個元素進行劃分有關;如果劃分是對稱的,那么本算法從漸近意義上和合并排序一樣快,如果劃分不對稱,本算法從漸近意義和插入排序一樣慢。
//快速排序的隨機化版本
Random_Partition(&$array,$p,$r){
? ? $i=rand($p,$r);
? ? swap($array[$i],$array[p]);
? ? return Partition($array,$p,$r);
}
2. 荷蘭國旗問題和三路快速排序
問題描述:荷蘭國旗有紅、白、藍三種顏色。現有這三種顏色的小球混放在一起,要求對小球排序,使得相同顏色的小球相鄰擺放。問題模型化:假設用數字0,1,2代表紅、白、藍三種顏色。數組array混亂存放著這些代表球的顏色的元素值。
//荷蘭國旗 PHP實現
function Threeflag(&$array,$p,$r){
? ? $beg=$p; $end=$r; $curr=$p;
? ? while($curr<=$end){
? ? ? ? if($array[$curr]==0){
? ? ? ? ? ? swap($array[$beg],$array[$curr]);
? ? ? ? ? ? $curr++; ?$beg++;
? ? ? ? }elseif($array[$curr]==2){
? ? ? ? ? ? swap($array[$end],$array[$curr]);
? ? ? ? ? ? $end--;
? ? ? ? }elseif($array[$curr]==1){
? ? ? ? ? ? $curr++;
? ? ? ? }
? ? }
}
快速排序算法擴展之三路快速排序算法:
隨機快排雖然能很大程度上解決子問題劃分不均的情況,但當排序對象中有很多重復的元素時,快排劃分情況很不盡人意。例如:當所有元素都相等時,在每次遞歸中,左邊部分是空的(沒有元素比關鍵元素小),而右邊部分只能一個一個遞減移動。結果導致耗費了二次方時間來排序相等元素。為了解決這個問題(有時叫做荷蘭國旗問題),我們將快排劃分擴展為三路快排:即排序對象被劃分為三部分:<$privot,=$privot,>$privot
//三路快速排序 PHP實現
function quick_sort(&$array,$p,$r){
? ? if ($p<$r) {
? ? ? ? $pivot=ThreePartition($array,$p,$r);
? ? ? ? quick_sort($array,$p,$pivot[0]);
? ? ? ? quick_sort($array,$pivot[1]+1,$r);
? ? ? ? // $pivot=Partition($array,$p,$r);
? ? ? ? // quick_sort($array,$p,$pivot-1);
? ? ? ? // quick_sort($array,$pivot+1,$r);
? ? }
}
//three partition
function ThreePartition(&$array,$p,$r){
? ? $key=$array[$p];
? ? $i=$p;? $j=$r; $k=$p;
? ? while ($k<=$j) {
? ? ? ? if ($array[$k]<$key) {
? ? ? ? ? ? swap($array[$i],$array[$k]);
? ? ? ? ? ? $i++;$k++;
? ? ? ? }elseif ($array[$k]>$key) {
? ? ? ? ? ? swap($array[$j],$array[$k]);
? ? ? ? ? ? $j--;
? ? ? ? }elseif ($array[$k]==$key) {
? ? ? ? ? ? $k++;
? ? ? ? }
? ? }
return array($i,$j);
}