常用演算法PHP版本-排序演算法和查詢演算法
阿新 • • 發佈:2019-06-22
常用演算法PHP版本
常用排序演算法
排序演算法說明
//排序演算法
//幾種排序演算法的結果都是一樣的,都可以進行升序或降序操作
//排序速度: 快速排序(在有序陣列時效率是最差的) > 直接插入排序演算法 > 選擇排序 > 冒泡
氣泡排序(升序)
<?php $arr = [5, 6, 3, 4, 2, 0, 1, 8, 9, 7]; /** * 氣泡排序(升序) * 主要思路: * 1.遍歷陣列,遍歷次數為陣列長度 * 2.遍歷陣列,每次將將當前元素和後一個做對比 * 3.從頭開始, 比較相鄰的元素。如果第一個比第二個大,就交換他們兩個,再比第二個和第三個,以此類推。 * * @param array $data */ function bubbleSort(array $data) { //統計陣列長度 $length = count($data); //控制要冒泡的總輪數 for ($i = 1; $i < $length; ++$i) { /** * 在本輪中遍歷所有剩餘的元素,$length - $i是因為對比過的就不用對比了, 因為對比過的他肯定比後面的小 * 比如: * 這裡說的是升序 * 第一步驟,下標為0對比下標為1,如果0>1,就把1挪到0,再把0挪到1. * 第二步, 在用下標1和下標2的對比,如果1>2,就把2挪到1,再把1挪到2. */ for ($j = 0; $j < $length - $i; ++$j) { //如果第一個比第二個大,這裡是升序排序 if ($data[$j] > $data[$j + 1]) { //將第二個放到一個臨時變數中 $tmp = $data[$j + 1]; //將第一個放到第二個位置中 $data[$j + 1] = $data[$j]; //將第二個放到第一個的位置中 $data[$j] = $tmp; } } } return $data; }
選擇排序(升序)
<?php $arr = [5, 6, 3, 4, 2, 0, 1, 8, 9, 7]; /** * 選擇排序(升序) * 主要思路: * 1.先在未排序序列中找到最小元素,存放到排序序列的起始位置. * 2.然後,再從剩餘未排序元素中繼續尋找最小元素,然後放到排序序列末尾。 * 3.以此類推,直到所有元素均排序完畢。 * * @param [type] $data */ function selectSort($data) { //獲取陣列長度 $length = count($data); //按照長度,從0開始遍歷陣列 for ($i = 0; $i < $length - 1; ++$i) { //假設當前元素的下標為最小元素的下標 $minIndex = $i; //逐個遍歷當前下標後面的所有元素,這就是為了判斷當前元素是不是所有元素裡面最小的元素 for ($j = $i + 1; $j < $length; ++$j) { //如果該元素<最小元素 if ($data[$j] < $data[$minIndex]) { //則把該元素的下標放到最小下標裡面 $minIndex = $j; } } //已經確定了當前的最小值的位置,儲存到$p中。 //如果 最小值的下標與當前假設的下標$i不同,則互換位置 if ($minIndex != $i) { $tmp = $data[$minIndex]; $data[$minIndex] = $data[$i]; $data[$i] = $tmp; } } return $data; }
快速排序(升序)
<?php $arr = [5, 6, 3, 4, 2, 0, 1, 8, 9, 7]; /** * 快速排序(升序). * 主要思路: * 從數列中挑出一個元素,稱為 "基準"(pivot); * 重新排序數列,所有元素比基準值小的擺放在基準前面,所有元素比基準值大的擺在基準的後面(相同的數可以到任一邊)。 * 在這個分割槽退出之後,該基準就處於數列的中間位置。這個稱為分割槽(partition)操作; * 遞迴地(recursive)把小於基準值元素的子數列和大於基準值元素的子數列排序; * * @param [type] $data */ function fastSort($data) { $length = count($data); //必須滿足長度,否則返回原陣列 if ($length <= 1) { return $data; } //定義空陣列 $leftArray = []; $rightArray = []; //遍歷陣列,遍歷次數為陣列的長度 for ($i = 1; $i < $length; ++$i) { //判斷當前元素是否小於陣列的第一個元素 if ($data[$i] < $data[0]) { //當前元素<陣列的第一個元素,把當前元素放入$leftArray中 $leftArray[] = $data[$i]; } else { //當前元素>=陣列的第一個元素,把當前元素放入$rightArray中 $rightArray[] = $data[$i]; } } //遞迴呼叫 $leftArray = fastSort($leftArray); //同時把$data[0]也追加進leftArray數組裡 $leftArray[] = $data[0]; $rightArray = fastSort($rightArray); //合併陣列 $mergeArr = array_merge($leftArray, $rightArray); return $mergeArr; }
直接插入排序(升序) 撮合引擎最常用的演算法
<?php
$arr = [5, 6, 3, 4, 2, 0, 1, 8, 9, 7];
/**
* 直接插入排序(升序) 撮合引擎最常用的演算法.
* 主要原理:
* 工作原理是通過構建有序序列,對於未排序資料,在已排序序列中從後向前掃描,找到相應位置並插入。
* 因而在從後向前掃描過程中,需要反覆把已排序元素逐步向後挪位,為最新元素提供插入空間。
*
* @param [type] $data
*/
function insertSrot($data)
{
//獲取陣列長度
$length = count($data);
//遍歷陣列,遍歷次數為陣列的長度
for ($i = 1; $i < $length; ++$i) {
//當前元素
$current = $data[$i];
//另一個遍歷方式,這種方式其實看起來更加的清晰,更容易理解
// for ($j = $i - 1; $j >= 0; --$j) {
// if ($current < $data[$j]) {
// $data[$j + 1] = $data[$j];
// $data[$j] = $current;
// } else {
// break;
// }
// }
//前一個鍵
$prefix = $i - 1;
//如果下標不為0 並且前一個元素比當前元素大
//這裡這個邏輯,基本上就是不斷的用前一個元素和當前元素比大小,如果前一個元素>當前元素,則把當前元素當到前面,然後在用當前元素繼續和前一個的前一個做對比
//直到比到前一個元素不比當前元素小,則將當前元素放在這個元素的後面
while ($prefix >= 0 && $data[$prefix] > $current) {
//將前一個元素插入到當前位置
$data[$prefix + 1] = $data[$prefix];
--$prefix;
}
//否則將當前元素放到,最後一個比當前元素大的位置,再進行下一個迴圈
$data[$prefix + 1] = $current;
}
return $data;
}
echo '氣泡排序'.PHP_EOL;
print_r(bubbleSort($arr));
echo '選擇排序'.PHP_EOL;
print_r(selectSort($arr));
echo '快速排序'.PHP_EOL;
print_r(fastSort($arr));
echo '插入排序'.PHP_EOL;
print_r(insertSrot($arr));
常用查詢演算法
二分查詢(不支援亂序查詢,所以要做好排序)
<?php
//二分查詢,因為每次可以捨去一半查詢區間,所以會將時間複雜度減少到O(logn),演算法更優。
//十個數,索引陣列下標到9
$arr = [5, 6, 3, 4, 2, 0, 1, 8, 9, 7];
$arr1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
/**
* 非遞迴的二分查詢,對亂序陣列無效.
* 主要思路:
* 先取陣列中間的值floor((lower+higher)/2),
* 然後通過與所需查詢的數字進行比較,若比中間值大,則將首值替換為中間位置下一個位置,繼續第一步的操作;若比中間值小,則將尾值替換為中間位置上一個位置,繼續第一步操作
* 重複第二步操作直至找出目標數字.
*
* @param array $data 被查詢的內容
* @param [type] $search 要查詢的內容
*/
function binarySearch(array $data, $search)
{
$length = count($data);
$lower = 0;
$higher = $length - 1;
while ($lower <= $higher) {
//取出陣列中間的下標
$middle = floor(($lower + $higher) / 2);
//判斷屬於左右哪個部分
if ($data[$middle] > $search) {
//如果當前元素>搜尋元素, 向左移動一位即刪除右邊的資料
$higher = $middle - 1;
} elseif ($data[$middle] < $search) {
//如果當前元素<搜尋元素, 向又移動一位即刪除左邊的資料
$lower = $middle + 1;
} else {
//等於這個數,即為找到, 則返回
return $middle;
}
}
//沒有找到,返回 -1
return -1;
}
echo '非遞迴的二分查詢'.PHP_EOL;
//不支援亂序
print_r(binarySearch($arr, 7));
echo PHP_EOL;
//支援順序
print_r(binarySearch($arr1, 7));
echo PHP_EOL;
/**
* 遞迴二分查詢,對亂序陣列無效.
*
* @param [type] $data 被查詢的資料
* @param [type] $search 要查詢的元素
* @param [type] $lower 最小的鍵
* @param [type] $higher 最大的鍵
*/
function binarySearchRecursion($data, $search, $lower, $higher)
{
//上面看懂了這裡就不用說什麼了
$middle = floor(($lower + $higher) / 2);
if ($lower > $higher) {
return -1;
}
if ($search > $data[$middle]) {
$result = binarySearchRecursion($data, $search, $middle + 1, $higher);
} elseif ($search < $data[$middle]) {
$result = binarySearchRecursion($data, $search, $lower, $middle - 1);
} else {
$result = $middle;
}
return $result;
}
echo '遞迴二分查詢'.PHP_EOL;
//不支援亂序
print_r(binarySearchRecursion($arr, 7, 0, count($arr) - 1));
echo PHP_EOL;
//支援順序
print_r(binarySearchRecursion($arr1, 7, 0, count($arr1) - 1));
順序查詢
<?php
$arr = [5, 6, 3, 4, 2, 0, 1, 8, 9, 7];
/**
* 順序查詢, 很顯然順序查詢就是從頭到尾挨個對比,比二分查詢的效能差很多倍
* 基本上沒什麼難度,這裡在PHP中其實可以直接用foreach更好.
*
* @param [type] $data 被查詢的陣列
* @param [type] $search 要查詢的內容
*/
function sequenceSearch($data, $search)
{
$length = count($data);
for ($i = 0; $i < $length; ++$i) {
if ($data[$i] == $search) {
return $i + 1;
}
}
return -1;
}
print_r('順序查詢'.PHP_EOL);
print_r(sequenceSearch($arr, 9));