全文代碼使用PHP7.2語法編寫流程圖生成工具:https://visualgo.netphp
冒泡排序 是一種交換排序,它的基本思想是:對待排序記錄從後往前(逆序)進行多遍掃描,當發現相鄰兩條記錄的次序與排序要求的規則不符時,就將這兩個記錄進行交換。這樣,值較小的記錄將逐漸從後面向前移動,就像氣泡在水中向上浮同樣。算法
假設須要排序的記錄有 n 個,其值保存在數組 A 中,使用冒泡排序法,需對數組 A 進行 n-1 次掃描,完成排序操做。具體過程以下:數組
/** * 冒泡排序 * @param array $arr */ function bubbleSort(array &$arr) : void { $length = count($arr); // 外層循環,從數組首部開始,每完成一次循環,可肯定 $arr[$i] 位置的元素 for ($i = 0; $i < $length; $i++){ // 內層循環,$j 從後往前循環 for ($j = $length - 1; $j > $i; $j--) { // 若前面的值大於後面的值,則互換位置 if ($arr[$j] < $arr[$j - 1]) { // 互換數組兩個位置的值 [$arr[$j], $arr[$j - 1]] = [$arr[$j - 1], $arr[$j]]; } } } }
選擇排序是經過 n-i
次關鍵字間的比較,從 n-i+1
個記錄中選出關鍵字最小的記錄,並和第 i ( 1 <= i <= n )
個記錄交換。工具
/** * 選擇排序 * @param array $arr */ function selectionSort(array &$arr) : void { $length = count($arr); // 外層循環,從數組首部開始,每完成一次循環,可肯定一個元素的位置 for ($i = 0; $i < $length - 1; $i++) { // 選定的最小值的索引 $minIdx = $i; // 從 $i + 1 位開始循環,判斷當前選定的元素是不是當次循環的最小值 for ($j = $i + 1; $j < $length; $j++) { // 若出現比選定的值還小的值,則替換最小值的索引 if ($arr[$minIdx] > $arr[$j]) { $minIdx = $j; } } // 互換數組兩個位置的值 [$arr[$i], $arr[$minIdx]] = [$arr[$minIdx], $arr[$i]]; } }
/** * 選擇排序 - 方法2 * @param array $arr */ function selectionSort2(array &$arr) : void { $length = count($arr); // 外層循環,從數組首部開始,每完成一次循環,依次肯定數組元素的位置 for ($i = 0; $i < $length; $i++) { // 從 $i + 1 位開始循環,依次斷定 $arr[$i] 與 $arr[$j] 的大小 for ($j = $i + 1; $j < $length; $j++) { // 若 $arr[$i] 比 $arr[$j] 大,則互換兩個元素的位置 if ($arr[$i] > $arr[$j]) { // 互換數組兩個位置的值 [$arr[$j], $arr[$i]] = [$arr[$i], $arr[$j]]; } } } }
插入排序 是經過構建有序序列,從未排序數據中選擇一個元素,在已排序序列中從後向前掃描,找到相應位置並插入。插入排序在從後向前掃描過程當中,須要把已排序元素逐個向後移動,爲最新元素提供插入空間。ui
/** * 插入排序 * @param array $arr */ function insertionSort(array &$arr) : void { $length = count($arr); // 從數組首部開始排序,每完成一次循環,可肯定一個元素的位置 for ($i = 0; $i < $length - 1; $i++) { // 內層循環從 $i + 1 個元素開始,一位一位向前比較 // 若前面的值比本身大,則替換,直到前面的值比本身小了,中止循環 for ($j = $i + 1; $j > 0; $j--) { if ($arr[$j] >= $arr[$j - 1]) { break; } [[$arr[$j], $arr[$j - 1]]] = [[$arr[$j - 1], $arr[$j]]]; } } }
/** * 插入排序 - 方法2 * @param array $arr */ function insertionSort2(array &$arr) : void { $length = count($arr); // 從數組首部開始排序,每完成一次循環,可肯定一個元素的位置 for ($i = 0; $i < $length - 1; $i++) { // 從第二個元素開始,選擇固定位置的值做爲基準值 $currentVal = $arr[$i + 1]; // 初始鍵位於選定值的前一個位置 $preIdx = $i; // 拿基準值一步一步向前比較,直到基準值比前面的值小,則兩值互換位置 while ($preIdx >= 0 && $currentVal < $arr[$preIdx]) { $arr[$preIdx + 1] = $arr[$preIdx]; $arr[$preIdx] = $currentVal; $preIdx--; } } }
快速排序是經過一趟排序將待排記錄分割成獨立的兩部分,其中一部分記錄的關鍵字均比另外一部分記錄的關鍵字小,則可分別對這兩部分記錄繼續進行排序,以達到整個序列有序的目的。spa
快速排序使用分治策略來把待排序數據序列分爲兩個子序列,具體步驟以下:.net
/** * 快速排序 * @param $arr */ function quickSort(& $arr) : void { $length = count($arr); // 若數組爲空,則不須要運行 if ($length <= 1) { return; } $middle = $arr[0]; // 選定一箇中間值 $left = []; // 接收小於中間值 $right = [];// 接收大於中間值 // 循環比較 for ($i = 1; $i < $length; $i++) { if ($middle < $arr[$i]) { // 大於中間值 $right[] = $arr[$i]; } else { // 小於或等於中間值 $left[] = $arr[$i]; } } // 遞歸排序劃分好的左右兩邊 quickSort($left); quickSort($right); $arr = array_merge($left, [$middle], $right); }
歸併是一種典型的序列操做,其工做是把兩個或更多有序序列合併爲一個有序序列。基於歸併的思想也能夠實現排序,稱爲歸併排序。基本方法以下:code
這種歸併方法也稱爲簡單的二路歸併排序,其中每次操做都是把兩個有序序列合併爲一個有序序列。也可考慮三路歸併或更多路的歸併。blog
/** * 歸併排序 * @param array $arr * @return array */ function mergeSort(array $arr) { // 計算數組長度,若長度不大於1,則不須要排序 $length = count($arr); if ($length <= 1) { return $arr; } // 獲取數組中間位置的索引 $midIdx = floor($length / 2); // 把數組從中間拆分紅左右兩部分 $left = mergeSort(array_slice($arr, 0, $midIdx)); $right = mergeSort(array_slice($arr, $midIdx)); // 合併兩部分,同時進行排序 return merge($left, $right); } /** * 合併數組,同時進行排序 * @param array $left * @param array $right * @return array */ function merge(array $left, array $right) { // 分別計算左右兩數組的長度 $lLength = count($left); $rLength = count($right); // 左右兩數組的索引 $l = $r = 0; $lists = []; // 只有左右兩數組都未遍歷完成時,纔有必要繼續遍歷 // 當其中一個數組的元素遍歷完成,說明另外一個數組中未遍歷過的值比遍歷過的值都大 while ($l < $lLength && $r < $rLength) { // 比較 $left[$l] 和 $right[$r],取其中較小的值加入到 $lists 數組中 if ($left[$l] < $right[$r]) { $lists[] = $left[$l]; $l++; } else { $lists[] = $right[$r]; $r++; } } // 合併 $lists 和 $left、$right 中剩餘的元素 return array_merge($lists, array_slice($left, $l), array_slice($right, $r)); }
/** * 合併數組,同時進行排序 - 方法2 * @param array $left * @param array $right * @return array */ function merge2(array $left, array $right) { // 分別計算左右兩數組的長度 $lLength = count($left); $rLength = count($right); // 左右兩數組的索引 $l = $r = 0; $lists = []; // 只有左右兩數組都未遍歷完成時,纔有必要繼續遍歷 // 當其中一個數組的元素遍歷完成,說明另外一個數組中未遍歷過的值比遍歷過的值都大 while ($l < $lLength && $r < $rLength) { // 比較 $left[$l] 和 $right[$r],取其中較小的值加入到 $lists 數組中 if ($left[$l] < $right[$r]) { $lists[] = $left[$l]; // PHP 中 unset 掉數組中的元素後,其餘元素的鍵名不變 unset($left[$l]); $l++; } else { $lists[] = $right[$r]; unset($right[$r]); $r++; } } // 合併 $lists 和 $left、$right 中剩餘的元素 return array_merge($lists, $left, $right); }
/** * 合併數組,同時進行排序 - 方法3 * @param array $left * @param array $right * @return array */ function merge3(array $left, array $right) { // 分別計算左右兩數組的長度 $lLength = count($left); $rLength = count($right); $lists = []; // 只有左右兩數組都未遍歷完成時,纔有必要繼續遍歷 // 當其中一個數組的元素遍歷完成,說明另外一個數組中未遍歷過的值比遍歷過的值都大 while ($lLength > 0 && $rLength > 0) { // 比較 $left[$l] 和 $right[$r],取其中較小的值加入到 $lists 數組中 if ($left[0] < $right[0]) { $lists[] = $left[0]; // PHP中 unset 掉數組中的元素後,其餘元素的鍵名不變 unset($left[0]); // 重建數組索引,始終讓比較的值在第一位 $left = array_values($left); $lLength--; } else { $lists[] = $right[0]; unset($right[0]); $right = array_values($right); $rLength--; } } // 合併 $lists 和 $left、$right 中剩餘的元素 return array_merge($lists, $left, $right); }