php实现堆排序(完全二叉树,可用一维数组存储)
转, 原文:https://www.cnblogs.com/iampeter/p/3223487.html
------------------------------------------
堆排序有点小复杂,分成三块:
第一块,什么是堆,什么是最大堆
第二块,怎么将堆调整为最大堆,这部分是重点
第三块,堆排序介绍
第一块,什么是堆,什么是最大堆
什么是堆
这里的堆(二叉堆),指得不是堆栈的那个堆,而是一种数据结构。
堆可以视为一棵完全的二叉树,完全二叉树的一个“优秀”的性质是,除了最底层之外,每一层都是满的,这使得堆可以利用数组来表示,每一个结点对应数组中的一个元素.
数组与堆之间的关系
二叉堆一般分为两种:最大堆和最小堆。
什么是最大堆
堆中每个父节点的元素值都大于等于其孩子结点(如果存在),这样的堆就是一个最大堆
因此,最大堆中的最大元素值出现在根结点(堆顶)
节点与数组索引关系
对于给定的某个结点的下标i,可以很容易的计算出这个结点的父结点、孩子结点的下标,而且计算公式很漂亮很简约
第二块,怎么将堆调整为最大堆,这部分是重点
整个过程如下图所示
在4,14,7这个小堆里边,父节点4小于左孩子14,所以两者交换
在4,2,8这个小堆里边,父节点4小于右孩子8,所以两者交换
上图展示了一趟调整的过程,这个过程递归实现,直到调整为最大堆为止
第三块,堆排序介绍
堆排序就是把堆顶的最大数取出,
将剩余的堆继续调整为最大堆,具体过程在第二块有介绍,以递归实现
剩余部分调整为最大堆后,再次将堆顶的最大数取出,再将剩余部分调整为最大堆,这个过程持续到剩余数只有一个时结束
下边三张图详细描述了整个过程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | /** * 使用异或交换2个值,原理:一个值经过同一个值的2次异或后,原值不变 * @param int $a * @param int $b */ function swap(& $a ,& $b ){ $a = $a ^ $b ; $b = $a ^ $b ; $a = $a ^ $b ; } /** * 整理当前树节点($n),临界点$last之后为已排序好的元素 * @param int $n * @param int $last * @param array $arr * */ function adjustNode( $n , $last ,& $arr ){ $l = $n <<1; // 左孩子 if ( !isset( $arr [ $l ])|| $l > $last ){ return ; } $r = $l +1; // 右孩子 // 如果右孩子比左孩子大,则让父节点与右孩子比 if ( $r <= $last && $arr [ $r ]> $arr [ $l ] ){ $l = $r ; } // 如果其中子节点$l比父节点$n大,则与父节点$n交换 if ( $arr [ $l ]> $arr [ $n ] ){ swap( $arr [ $l ], $arr [ $n ]); // 交换之后,父节点($n)的值可能还小于原子节点($l)的子节点的值,所以还需对原子节点($l)的子节点进行调整,用递归实现 adjustNode( $l , $last , $arr ); } } /** * 堆排序(最大堆) * @param array $arr */ function heapSort(& $arr ){ // 最后一个蒜素位 $last = count ( $arr ); // 堆排序中常忽略$arr[0] array_unshift ( $arr , 0); // 最后一个非叶子节点 $i = $last >>1; // 整理成最大堆,最大的数放到最顶,并将最大数和堆尾交换,并在之后的计算中,忽略数组最后端的最大数(last),直到堆顶(last=堆顶) while (true){ adjustNode( $i , $last , $arr ); if ( $i >1 ){ // 移动节点指针,遍历所有节点 $i --; } else { // 临界点$last=1,即所有排序完成 if ( $last ==1 ){ break ; } swap( $arr [ $last ], $arr [1]); $last --; } } // 弹出第一个元素 array_shift ( $arr ); } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
2020-01-21 非正常退出网页
2019-01-21 bash shell中可以使用wait
2019-01-21 【转】Linux基础与Linux下C语言编程基础