php实现堆排序

时间:2019-03-19
本文章向大家介绍php实现堆排序,主要包括php实现堆排序使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
  1. <?php  
  2.   
  3. $arr = [4,1,3,2,16,9,10,1,14,9,8,7,];//注意有重复值。  
  4. $arr = heap_sort($arr);  
  5. var_dump($arr);  
  6. //排序结果如下:  
  7. // [1,1,2,3,4,7,8,9,9,10,14,16,]  
  8.   
  9.   
  10. /** 
  11.  * 从小到大 的排序。 
  12.  *  
  13.  * 1、初始化最大堆,把一维数组改变成映射为最大堆的一维数组。 
  14.  * 2、把堆顶的最大值和堆最后一个结点交换。(于是最大值出现,并放好位置了。) 
  15.  * 3、排除最后一个结点,把堆重新调整为最大堆。 
  16.  * 4、把堆顶和倒数第2个结点交换。(于是次大值出现,也放好位置了。) 
  17.  * 5、排除最后两个结点,把堆调整为最大推。 
  18.  * 6、重复2和3,直到最后一个结点即堆顶。堆顶不需排,因为必然最小。 
  19.  *  
  20.  * @param array $arr 
  21.  * @return array 
  22.  */  
  23. function heap_sort($arr) {  
  24.     $len = count($arr);  
  25.     //初始化,i從最後一個父節點開始調整  
  26.     // 初始化的目的是建立一个最大堆。  
  27.     // 要点是,必须自底向上,而不能自顶向下,否则bug。  
  28.     for ($index = ceil($len/2) - 1; $index >= 0; $index--) {  
  29.         max_heapify($arr, $index, $len);  
  30.     }  
  31.       
  32.     // 推排序是很有规律的,先找出最大值,放到堆的最后,然后假装堆的结点数减少,  
  33.     // 继续排序,找出次大的,等等。  
  34.     // 巧妙利用堆和数组的映射,实现排序。  
  35.     for ($index = $len - 1; $index > 0; $index--) {  
  36.         $arr = swap ( $arr, 0, $index );  
  37.         max_heapify($arr, 0, $index);  
  38.     }  
  39.     return $arr;  
  40. }  
  41.   
  42. /** 
  43.  * 堆排序核心算法, 
  44.  * 对于一个给定的堆,给定的起始下标和结束下标,进行堆排序,会递归调用。 
  45.  * 事实上,只排序起始下标指向的父节点,结束下标仅仅用于递归判断的返回。 
  46.  * 这是指针形式的调用,这样的话,代码速度快,且代码容易理解。 
  47.  *  
  48.  * @param array $arr 
  49.  * @param int $start_index 
  50.  * @param int $end_index 
  51.  */  
  52. function max_heapify(&$arr, $start_index, $end_index) {  
  53.     //建立父節點指標和子節點指標  
  54.     $dad_index = $start_index;  
  55.     $son_index = $dad_index * 2 + 1;  
  56.     //若子節點指標超過範圍直接跳出函數  
  57.     if ($son_index >= $end_index) {  
  58.         return;  
  59.     }  
  60.     //先比較兩個子節點大小,選擇最大的  
  61.     if ($son_index + 1 < $end_index && $arr[$son_index] < $arr[$son_index + 1]) {  
  62.         $son_index++;  
  63.     }  
  64.     //如果父節點小於子節點時,交換父子內容再繼續子節點和孫節點比較  
  65.     if ($arr[$dad_index] < $arr[$son_index]) {  
  66.         $arr = swap($arr, $dad_index, $son_index);  
  67.         max_heapify($arr, $son_index, $end_index);  
  68.     }  
  69. }  
  70.   
  71. /** 
  72.  * 交换一个数组中两个不同下标的值。 
  73.  * @param array $arr 
  74.  * @param int $index1 
  75.  * @param int $index2 
  76.  * @return array 
  77.  */  
  78. function swap($arr, $index1, $index2) {  
  79.     list( $arr[$index1], $arr[$index2] ) = [ $arr[$index2], $arr[$index1] ];  
  80.     return $arr;  
  81. }  



其实可以看到,堆排序代码并不算多,关键在于理解。 

本文有参考:http://bubkoo.com/2014/01/14/sort-algorithm/heap-sort/ 
作者不知是谁,描述的很清楚。 

  • 堆是一棵二叉数。
  • 堆是一棵完全二叉数,于是,堆可以轻松用数组表达
  • 假设下标是i,则父节点和子节点都有下标计算公式。
  • 堆排序算法是先初始化成最大堆,然后交换堆顶和堆最后结点,然后结点数减1,再依次操作,就排序好了。



下图仅供参考,注意开始已经初始化过最大堆了。