PHP資料結構(二十三) ——快速排序
PHP資料結構(二十三)——選擇排序
(原創內容,轉載請註明來源,謝謝)
一、概述
選擇排序的基本思想,是每一趟在n-i+1(i=1,2…n-1)個記錄中選取關鍵字最小的記錄作為第i個記錄。選擇排序分為簡單選擇排序、樹形選擇排序、堆排序。
二、簡單選擇排序
簡單選擇排序,即完全按照上述的說法進行排序。時間複雜度O(n2)。由於比較簡單,不具體描述。
1、演算法
1)遍歷整個陣列,找到最小值放置於第一個位置。
2)遍歷從第二個位置至末尾的陣列,找到最小值放在第二個位置。
3)重複上述操作直到排序完成。
2、實現原始碼如下
//簡單選擇排序 public function simpleSelectSort(array$arr = array()){ $arr= $this->_checkNeedSort($arr); if(!$arr){ return$arr; } //長度只有1直接返回 if(1== count($arr)){ return$arr; } //遍歷陣列,第i次取第i小值放置於第i-1的位置 //由於n-1次已經可以遍歷完,故不需要第n次遍歷 for($i=0;$i<count($arr)-1;$i++){ //暫存臨時最小值與關鍵字 $min= $arr[$i]; $minIndex= $i; for($j=$i+1;$j<count($arr);$j++){ //如果最小值比暫存小,則更新暫存 if($arr[$j]<$min){ $min= $arr[$j]; $minIndex= $j; } } //將暫存的最小值替換到第i個位置 $tmp= $arr[$i]; $arr[$i]= $arr[$minIndex]; $arr[$minIndex]= $tmp; } return$arr; }
三、樹形選擇排序
樹形選擇排序是利用簡單選擇排序在每一次排序的結果進行的排序,又被稱為錦標賽排序。兩兩進行排序,小的值再兩兩排序,直至選出最小值。再進行第二輪的排序選擇次小值。樹形選擇排序時間複雜度是O(nlogn)。
1、演算法
1)構造一棵滿二叉樹,其葉子節點都在同一層,且葉子節點包含了所有的待排序陣列。
2)兩兩節點進行比較,關鍵字對應的值小的那一個進入父節點,葉子節點的位置值置成無窮大。
3)直至比出根節點。則為最小值。
4)再次遍歷此樹,直至構造完成全部的值。
實際實現中,由於樹形選擇排序必須用完全二叉樹,而完全二叉樹的父節點和其子節點的編號關係是確定的,可以用陣列來表達。
陣列表達的方式,假設根節點為0,從左往右、從上往下編號,則第一層為0,第二層為1、2(父節點都是0),第三層為3、4、5、6(父節點3、4的是1,5、6的是2)。
依次類推,兩兩一組,可以確定,父節點編號=(左節點編號-1)/2,或父節點編號=右節點編號/2-1。因此可以兩兩一組進行遍歷。
2、樹形選擇排序如下圖所示(圖片來自網路):
3、實現原始碼如下
//樹形選擇排序 publicfunction treeSelectSort(array $arr = array()){ $arr= $this->_checkNeedSort($arr); if(!$arr){ return$arr; } //長度只有1直接返回 if(1== count($arr)){ return$arr; } //確定陣列長度,即完全二叉樹葉子節點的個數 $arrLength= count($arr); //完全二叉樹 $arrTreeNodes= array(); //完全二叉樹節點總數為葉子節點個數*2-1 $treeNodesLength= 2 * $arrLength -1; //倒序將陣列放置於完全二叉樹陣列的末尾,構造葉子節點 for($i=$arrLength-1,$j=0;$i>=0;$i--,$j++){ $arrTreeNodes[$treeNodesLength-1-$j]= $arr[$i]; } //補全完全二叉樹葉子節點以外的節點。i每兩個進行比較,從最後一個節點起,相當於每次都在右節點,因此其父節點位置為i/2-1 for($i=$treeNodesLength-1;$i>0;$i=$i-2){ //取小的值為父節點的值 $arrTreeNodes[$i/2-1]= $arrTreeNodes[$i] < $arrTreeNodes[$i-1] ? $arrTreeNodes[$i] :$arrTreeNodes[$i-1]; } //從0起生成最終的陣列 $low= 0; while($low< $arrLength){ //每次生成樹後,其當前的第一個值(下標是0)即為最小值 $curMin= $arrTreeNodes[0]; //最小值放入最終的陣列 $arr[$low++]= $curMin; //從最後一個元素起,找結果為最小值的下標 $curMinIndex= $treeNodesLength - 1; //相等時找到下標 while($curMin!= $arrTreeNodes[$curMinIndex]){ $curMinIndex--; } //將結果最小的值設定成無窮大 $arrTreeNodes[$curMinIndex]= INF; //找其父節點即父節點的父節點,直至根節點 while(0< $curMinIndex){ //如果是偶數,說明是右節點,父節點是i/2-1,要比較的是i和i-1 if(0== $curMinIndex%2){ $arrTreeNodes[$curMinIndex/2-1]= $arrTreeNodes[$curMinIndex] < $arrTreeNodes[$curMinIndex-1] ?$arrTreeNodes[$curMinIndex] : $arrTreeNodes[$curMinIndex-1]; $curMinIndex= $curMinIndex / 2 - 1; }else{ //如果是奇數,說明是左節點,父節點是(i-1)/2,要比較的是i和i+1 $arrTreeNodes[($curMinIndex-1)/2]= $arrTreeNodes[$curMinIndex] < $arrTreeNodes[$curMinIndex+1] ?$arrTreeNodes[$curMinIndex] : $arrTreeNodes[$curMinIndex+1]; $curMinIndex= ($curMinIndex - 1) / 2; } } } return$arr; }
4、評價
樹形選擇排序由於需要額外的空間較多,而且有大量的INF(PHP中表示無窮大的值),浪費空間較多,實際中不常用,而往往使用優化版的樹形選擇排序——堆排序。
堆排序的內容見下文。
——written by linhxx 2017.07.20
相關閱讀: