前言
最近在學習資料結構及演算法,打算用PHP實現一些經典的排序演算法,來鞏固一下所學的內容,如果有不對的地方,歡迎大佬指教。
因為時間的關係,這裡只展示程式碼,關於演算法原理或者思路,後續可能會寫專門的部落格出來,感謝大家支援。
氣泡排序
/**
* 給指定陣列按照從小到大排序
*
* @param array $arr [待排序的陣列]
* @return [type] [返回為陣列]
*/
public function sort($arr=array(1,2,3,6,4,3)){
//對整個陣列進行遍歷
for($i=0;$i<count($arr)-1;$i++){
//每一輪的冒泡處理
for($j=0;$j<count($arr)-1-$i;$j++){
//如果當前迴圈元素比他的後一位大
if($arr[$j]>$arr[$j+1]){
//暫存當前迴圈的值
$tmp=$arr[$j];
//交換兩個元素的位置
$arr[$j]=$arr[$j+1];
$arr[$j+1]=$tmp;
}
}
}
//列印結果
var_dump($arr);
}
當然這只是冒泡的初步使用,不難可以看出,有很大的優化空間。比如說在第二輪迴圈完畢就已經是一個有序的陣列了,但是我們的程式還是會迴圈6次,在這種情況下,我們需要對我們的冒泡進行優化:
/**
* 給指定陣列按照從小到大排序
*
* @param array $arr [待排序的陣列]
* @return [type] [返回為陣列]
*/
public function sort($arr=array(1,2,3,6,4,3)){
//對整個陣列進行遍歷
for($i=0;$i<count($arr)-1;$i++){
//有序標記,預設為true,用1表示
$isSorten=1;
//每一輪的冒泡處理
for($j=0;$j<count($arr)-1-$i;$j++){
//如果當前迴圈元素比他的後一位大
if($arr[$j]>$arr[$j+1]){
//暫存當前迴圈的值
$tmp=$arr[$j];
//交換兩個元素的位置
$arr[$j]=$arr[$j+1];
$arr[$j+1]=$tmp;
//因為有元素交換,所以將true改為false,用0表示
$isSorten=0;
}
}
//如果$isSorted為真,結束迴圈
if ($isSorten) {
break;
}
}
//列印結果
var_dump($arr);
}
這是第二版優化,當然,有第二版就有第三版。第三版我們主要側重優化一下效能,當然示例的陣列可能不太明顯看出來,如果換成array(3,1,4,5,6,7)可能會容易看出來,那就是其實1後面的循序已經是我們想要的了,但是我們的程式還是會挨個比較,讓我們來解決他:
/**
* 給指定陣列按照從小到大排序
*
* @param array $arr [待排序的陣列]
* @return [type] [返回為陣列]
*/
public function sort($arr=array(1,2,3,6,4,3)){
//記錄最後一次交換順序的位置
$listChangeIndex=0;
//表示邊界,即每次比較到這裡就可以了
$sortBorber =count($arr)-1;
//對整個陣列進行遍歷
for($i=0;$i<count($arr)-1;$i++){
//有序標記,預設為true,用1表示
$isSorten=1;
//每一輪的冒泡處理
for($j=0;$j<$sortBorber;$j++){
//如果當前迴圈元素比他的後一位大
if($arr[$j]>$arr[$j+1]){
//暫存當前迴圈的值
$tmp=$arr[$j];
//交換兩個元素的位置
$arr[$j]=$arr[$j+1];
$arr[$j+1]=$tmp;
//因為有元素交換,所以將true改為false,用0表示
$isSorten=0;
//更新為最後一次交換元素的位置
$listChangeIndex=$j;
}
}
$sortBorber=$listChangeIndex;
//如果$isSorted為真,結束迴圈
if ($isSorten) {
break;
}
}
//列印結果
var_dump($arr);
}
雞尾酒排序
如你所見,冒泡演算法是從左到右進行比較的。如果說冒泡演算法是單向,那麼雞尾酒演算法就是雙向,就像現在的火車,有兩個車頭,一頭開到終點後,另外一頭接著開。
/**
* 給指定陣列按照從小到大排序
*
* @param array $arr [待排序的陣列]
* @return [type] [返回為陣列]
*/
public function sort($arr=array(1,2,3,6,4,3,6,3,8)){
$tem=0;
//對整個陣列進行遍歷
for($i=0;$i<count($arr)/2;$i++){
//有序標記,預設為true,用1表示
$isSorten=1;
//基數輪
for($j=1;$j<count($arr)-1-$i;$j++){
//如果當前迴圈元素比他的後一位大
if($arr[$j]>$arr[$j+1]){
//暫存當前迴圈的值
$tmp=$arr[$j];
//交換兩個元素的位置
$arr[$j]=$arr[$j+1];
$arr[$j+1]=$tmp;
//因為有元素交換,所以將true改為false,用0表示
$isSorten=0;
}
}
//如果$isSorted為真,結束迴圈
if ($isSorten) {
break;
}
//偶數輪開始前重新定義為true,用1表示
$isSorten=1;
//偶數輪,從右向左比較
for($j=count($arr)-1-$i;$j>1;$j--){
//如果當前迴圈元素比他的後一位小
if($arr[$j]<$arr[$j-1]){
//暫存當前迴圈的值
$tmp=$arr[$j];
//交換兩個元素的位置
$arr[$j]=$arr[$j-1];
$arr[$j-1]=$tmp;
//因為有元素交換,所以將true改為false,用0表示
$isSorten=0;
}
}
//如果$isSorted為真,結束迴圈
if ($isSorten) {
break;
}
}
//列印結果
var_dump($arr);
}
兩者的特點呢也比較容易區分,雞尾酒排序減少了排序的回合,相比於氣泡排序,程式碼量幾乎是增加了一倍。
比較氣泡排序,雞尾酒排序更適合大部分元素已經有序的情況。
其他演算法待補充……
本作品採用《CC 協議》,轉載必須註明作者和本文連結