PHP版常用算法

PHP版常用算法

最近準備面試的資料,順便整理一下以前的基本算法,寫個DEMO記錄一下

冒泡

//冒泡
//逐行對比,滿足條件則交換
function bubbleSort($arrData,$sort = 'desc')
{
    if(empty($arrData)) return $arrData;

    //默認有序
    $isSorted = true;
    $nCount = count($arrData);
    for($i = 0; $i < $nCount; $i++) {

        //對比次數隨着循環逐漸減少,因爲後面的數據已經處理爲有序
        for($j = 0; $j < ($nCount - $i - 1); $j++) {
            //執行判斷
            $isChange = $sort == 'desc' ? $arrData[$j] < $arrData[$j+1] : $arrData[$j] > $arrData[$j+1];

            if($isChange) {
                //首次對比,判斷是否有序
                $isSorted = false;

                $temp = $arrData[$j];
                $arrData[$j] = $arrData[$j+1];
                $arrData[$j+1] = $temp;
            }
        }

        if($isSorted) break;
    }

    return $arrData;
}

快速排序

//快速排序
//選取一個標準,和其他數據對比後將數據分爲兩批,遞歸執行後合併
function quickSort(&$arr, $sort = 'asc'){

    //檢查數據,多於一個數據才執行
    $nCount = count($arr);
    if($nCount > 1) {
        //選取標準(第一個數據)
        $nStandard = $arr[0];
        $arrLeftData = [];
        $arrRightData = [];
        //遍歷,注意這裏從1開始比較
        for($i = 1; $i < $nCount; $i++) {

            if($sort == 'desc') {
                $arr[$i] > $nStandard ? $arrLeftData[] = $arr[$i] : $arrRightData[] = $arr[$i];
            } else {
                $arr[$i] > $nStandard ? $arrRightData[] = $arr[$i] : $arrLeftData[] = $arr[$i];
            }
        }
        $arr = array_merge($this->quickSort($arrLeftData, $sort), array($nStandard), $this->quickSort($arrRightData, $sort));
    }
    return $arr;
}

歸併排序

//利用歸併(合併)的思想實現的排序方法。
//它的原理是假設初始序列含有 n 個元素,則可以看成是 n 個有序的子序列,每個子序列的長度爲 1,然後兩兩歸併
//得到n/2個長度爲2或1 的有序序列;再兩兩歸併,······,如此重複
//直至得到一個長度爲 n 的有序序列爲止,這種排序方法就成爲 2 路歸併排序

//merge函數將指定的兩個有序數組(arr1,arr2)合併並且排序
//我們可以找到第三個數組,然後依次從兩個數組的開始取數據哪個數據小就先取哪個的,然後刪除掉剛剛取過的數據
function al_merge($arrA,$arrB)
{
    $arrC = array();
    while(count($arrA) && count($arrB)){
        //這裏不斷的判斷哪個值小,就將小的值給到arrC,但是到最後肯定要剩下幾個值,
        //不是剩下arrA裏面的就是剩下arrB裏面的而且這幾個有序的值,肯定比arrC裏面所有的值都大
        $arrC[] = $arrA[0] < $arrB[0] ? array_shift($arrA) : array_shift($arrB);
    }
    return array_merge($arrC, $arrA, $arrB);
}

//歸併排序函數
function al_merge_sort($arr){
    $len = count($arr);
    if($len <= 1) return $arr;//遞歸結束條件,到達這步的時候,數組就只剩下一個元素了,也就是分離了數組

    //分離數組元素
    $mid = intval($len/2);//取數組中間
    $left_arr = array_slice($arr, 0, $mid);//拆分數組0-mid這部分給左邊left_arr
    $right_arr = array_slice($arr, $mid);//拆分數組mid-末尾這部分給右邊right_arr
    $left_arr = $this->al_merge_sort($left_arr);//左邊拆分完後開始遞歸合併往上走
    $right_arr = $this->al_merge_sort($right_arr);//右邊拆分完畢開始遞歸往上走

    $arr = $this->al_merge($left_arr, $right_arr);//合併兩個數組,繼續遞歸
    return $arr;
}

二分查找

//二分查找
//假設數據是按升序排序的,對於給定值x,從序列的中間位置開始比較,如果當前位置值等於x,則查找成功;
//若x小於當前位置值,則在數列的前半段中查找;若x大於當前位置值則在數列的後半段中繼續查找,直到找到爲止
function binSearch($toSearch,$arr)
{
    //確定當前的檢索範圍
    $nCount = count($arr);
    //低位鍵,初始爲0
    $nLowNum = 0;
    //高位鍵,初始爲末尾 
    $nHighNum = $nCount - 1;

    while($nLowNum <= $nHighNum) {
        //選定大概中間鍵
        $nMiddleNum = intval(($nHighNum + $nLowNum)/2);

        if($arr[$nMiddleNum] > $toSearch) {
            //比檢索值大
            $nHighNum = $nMiddleNum - 1;
        } elseif ($arr[$nMiddleNum] < $toSearch) {
            //比檢索值小
            $nLowNum = $nMiddleNum + 1;
        } else {
            return $nMiddleNum;
        }
    }

    return false;
}

順序查找

//順序查找
function seqSearch($arr,$toSearch)
{
    $nCount = count($arr);

    for ($i=0; $i < $nCount; $i++) {
        if ($arr[$i] == $toSearch) {
            return $i;
        }
    }
    return -1;
}

選擇排序

//在第一次循環中,假設第一個數是最小的;然後跟第二個數比較,一直比到最後,找出最小值,然後把最小值跟第一個數的位置互換;
//再進行下一次循環,找出最小值跟第二個位置的數互換;一直循環數組的個數減去1次;數組就成了有序的了 
function selectSort($arr)
{

    $nCount = count($arr);
    //遍歷取得需要排序的數
    for($i = 0; $i < $nCount; $i++) {

        //選擇需要比較的數,從$i開始到結束
        for($j = $i + 1; $j < $nCount; $j++) {
            //比較
            if($arr[$j] < $arr[$i]) {
                $temp = $arr[$i];
                $arr[$i] = $arr[$j];
                $arr[$j] = $temp;
            }
        }
    }
    return $arr;  
}

外部排序+多路歸併

思路參考:
https://blog.csdn.net/itermeng/article/details/77824866

面試中經常問到一些關於 並行計算 或者 在一臺內存不多的機器上進行大文件排序 的問題,這些其實思路都可以藉助外部排序+多路歸併去解決:

只能一部分放在放在內存數組中,另一部分放在內存之外(硬盤或網絡其它節點),這就是所謂的外部排序;
歸併排序:將數據分爲左右兩部分,分別排序,再把兩個有序子數組進行歸併;
重點就是歸併過程,就是兩個已排序好的數組來比較頭部的元素,取最小值放入最終數組中;

思路:

第一步:將數據進行切分,例如以100m將1G的文件分爲10組,將每一段數據分配到外部,切分的大小符合節點內存大小限制;
第二步:這樣每個節點各自對分配數據進行排序,採用歸併排序或快速排序皆可(多節點則節點處理,單機則逐個處理);
第三步:將每個排序好的節點按照歸併算法整合到一個節點(多路歸併);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章