用 PHP 實現經典排序演算法

Jouzeyu發表於2020-04-06

前言

最近在學習資料結構及演算法,打算用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 協議》,轉載必須註明作者和本文連結

空舟湖上~
     ——Jouzeyu

相關文章