PHP演算法之四大基礎演算法

weixin_33840661發表於2018-09-19

page_img_url

前言

雖然工作中,你覺得自己並沒有涉及到演算法這方面的東西,但是演算法是程式的核心,一個程式的好與差,關鍵是這個程式演算法的優劣,所以對於氣泡排序、插入排序、選擇排序、快速排序這四種基本演算法,我想還是要掌握的。

氣泡排序法

氣泡排序大概的意思是依次比較相鄰的兩個數,然後根據大小做出排序,直至最後兩位數。由於在排序過程中總是小數往前放,大數往後放,相當於氣泡往上升,所以稱作氣泡排序。

冒泡是從前往後冒,所以,每輪比較的次數也是逐漸減少的,最後一個數不用比較,其時間複雜度為O(n²),演算法如下:

/**
 * 氣泡排序演算法
 * @param array $arr
 * @return array
 */
function bubble_sort($arr) {
    // 判斷引數是否為陣列,且不為空
    if (!is_array($arr) || empty($arr)) {
        return $arr;
    }
    // 迴圈需要冒泡的輪數
    for ($i = 1, $len = count($arr); $i < $len; $i++) {
        // 迴圈每輪需要比較的次數
        for ($j = 0; $j < $len - $i; $j++) {
            // 大的數,交換位置,往後挪
            if ($arr[$j] > $arr[$j + 1]) {
                $temp = $arr[$j + 1];
                $arr[$j + 1] = $arr[$j];
                $arr[$j] = $temp;
            }
        }
    }
    return $arr;
}

選擇排序法

選擇排序的原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然後,再從剩餘未排序元素中繼續尋找最小(大)元素,然後放到已排序序列的末尾;以此類推,直到所有元素均排序完畢。

選擇是每一次從假定一個最小值的位置,然後用假定最小值和後面的值依次比較,找到實際的最小值來放到假定最小值的位置上,其時間複雜度也為O(n²),演算法如下:

/**
 * 選擇排序法
 * @param array $arr
 * @return array
 */
function select_sort($arr) {
    // 判斷引數是否為陣列,且不為空
    if (!is_array($arr) || empty($arr)) {
        return $arr;
    }
    $len = count($arr);
    for ($i = 0; $i < $len - 1; $i++) {
        // 假設最小數的位置
        $min = $i;
        // 用假設的最小數和$i後面的數迴圈比較,找到實際的最小數
        for ($j = $i + 1; $j < $len; $j++) {
            // 後面的數比假設的最小數小,替換最小數
            if ($arr[$min] > $arr[$j]) {
                $min = $j;
            }
        }
        // 假設的最小數和實際不符,交換位置
        if ($min != $i) {
            $temp = $arr[$min];
            $arr[$min] = $arr[$i];
            $arr[$i] = $temp;
        }
    }
    return $arr;
}

插入排序法

插入排序的原理:每次將一個待排序的記錄,按其關鍵字大小插入到前面已經排好序的子序列中的適當位置,直到全部記錄插入完成為止。

插入排序法是先將排序元素的前兩個元素排序,然後將第三個元素插入已經排序好的兩個元素中,所以這三個元素仍然是從小到大排序,接著將第四個元素插入,重複操作直到所有元素都排序好;其時間複雜度同樣為O(n²),演算法如下:

/**
 * 插入排序法
 * @param array $arr
 * @return array
 */
function insert_sort($arr) {
    // 判斷引數是否為陣列,且不為空
    if (!is_array($arr) || empty($arr)) {
        return $arr;
    }
    $len = count($arr);
    for ($i = 1; $i < $len; $i++) {
        // 當前需要比較的臨時數
        $tmp = $arr[$i];
        // 迴圈比較臨時數所在位置前面的數
        for ($j = $i - 1; $j >= 0; $j--) {
            // 前面的數比臨時數大,則交換位置
            if ($arr[$j] > $tmp) {
                $arr[$j + 1] = $arr[$j];
                $arr[$j] = $tmp;
            }
        }
    }
    return $arr;
}

快速排序法

快速排序法是對氣泡排序的一種改進。他的基本原理是:通過一趟排序將待排記錄分割成獨立的兩部分,其中一部分的關鍵字均比另一部分記錄的關鍵字小,則可分別對這兩部分記錄繼續進行快速排序,整個排序過程可以遞迴進行,以達到整個序列有序的目的。

快速排序法是從數列中挑出第一個數(最後一個數)作為基準元素,然後迴圈所有數,和基準書比較分為左右兩列,然後重複這樣的步驟繼續劃分為左右兩列,演算法如下:

/**
 * 快速排序法
 * @param array $arr
 * @return array
 */
function quick_sort($arr) {
    // 判斷引數是否為陣列,且不為空
    if (!is_array($arr) || empty($arr)) {
        return $arr;
    }
    // 陣列長度為1停止排序
    $len = count($arr);
    if ($len == 1) {
        return $arr;
    }
    // 宣告左右兩個空陣列
    $left = $right = [];
    // 迴圈遍歷,把第一個元素當做基準數
    for ($i = 1; $i < $len; $i++) {
        // 比較當前數的大小,並放入對應的左右陣列
        if ($arr[$i] > $arr[0]) {
            $right[] = $arr[$i];
        } else {
            $left[] = $arr[$i];
        }
    }
    // 遞迴比較
    $left = quick_sort($left);
    $right = quick_sort($right);
    // 左右兩列以及基準數合併
    return array_merge($left, [$arr[0]], $right);
}

使用方法

宣告一個待排序的陣列,然後呼叫對應的排序方法即可得到返回的排序好的陣列;說明一下,我這裡的排序設計都是遞增的,如果需要遞減,需要修改一下排序演算法的比較替換符就行。

// 待排序陣列
$arr = [1, 4, 5, 9, 3, 8, 6];
// 呼叫排序方法
$sort_arr = bubble_sort($arr);
// 輸出列印
print_r($sort_arr);

分析演算法

通常,對於一個給定的演算法,我們要做兩項分析:第一是從數學上證明演算法的正確性,這一步主要用到形式化證明的方法及相關推理模式,如迴圈不變式、數學歸納法等。而在證明演算法是正確的基礎上,第二步就是分析演算法的時間複雜度。演算法的時間複雜度反映了程式執行時間隨輸入規模增長而增長的量級,在很大程度上能很好反映出演算法的優劣與否。還有我們通常說的:演算法優化無非就是以時間換空間,以空間換時間,一般這兩者是不可兼得。

結束語

實現一個程式,肯定是有多種演算法的,大家有其他想說的,都可以留言和我交流,謝謝!如有問題,也歡迎指出,我會及時改正,謝謝!

相關文章