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組,將每一段數據分配到外部,切分的大小符合節點內存大小限制;
第二步:這樣每個節點各自對分配數據進行排序,採用歸併排序或快速排序皆可(多節點則節點處理,單機則逐個處理);
第三步:將每個排序好的節點按照歸併算法整合到一個節點(多路歸併);