堆排序:是一种特殊形式的选择排序,他是简单选择排序的一种改进。

什么是堆?

具有n个元素的序列:{k1,k2,ki,…,kn}

(ki <= k2i,ki <= k2i+1) 或者 (ki >= k2i,ki >= k2i+1), (i = 1,2,3,4...n/2)

满足这个条件时,该序列就是一个堆。第一个条件称为小顶堆,第二个条件称为大顶堆。

为了方便,下边论述基于大顶堆,并且下标从1开始。

将堆的元素放在一棵完全二叉树中,方便我们讨论堆的特性和排序,一般谈到堆也都是一棵完全二叉树。

完全二叉树:若二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。

堆的特性(括号道标下标从0开始的计算方法) :

  • 非叶子结点个数:n / 2 (n / 2 - 1)
  • 节点i的左子树下标 :2*i (2*i+ 1)
  • 节点i的右子树下标:2*i + 1 (2*i + 2)

堆排序:

核心思想:

  1. 将原始序列构成一个堆。(建立初始堆)
  2. 交换堆的第一个元素(最大值)和最后一个元素的位置,把堆长度减一后剩余的序列再转换为一个堆。(调整堆)
  3. 重复2过程n-1次。

经过上述操作,就可以将一个无序序列从小到大排序。(因为大顶堆每次把最大值交换到最后了,所以想要降序排列就要用小顶堆)

先说调堆,调堆就是把当前节点和其左子树,右子树中最大值交换,依次把需要调整的节点调一遍。这样一次循环下来根节点肯定放的是最大值。但是有可能循环中的某次交换把之前排好序的结构打乱,需要递归调整。

再说建堆,建堆就是从最后一个非叶子节点开始,到第一个节点为止,依次进行调堆。

for ($i = floor(count($arr) / 2) - 1; $i >=0; $i--) {
adjustHeap($arr);
}

借用网上的一张图说明一下:

从floor(9/2)-1开始,也就是key=3,val=5的地方开始,循环调堆,到图1.6处循环完成,最大值顺利到达根节点,但是发现val=1节点还是需要调整,这就需要在调堆里执行循环调整,使其符合堆的特性。

代码实现:

$arr = [49, 38, 65, 97, 76, 13, 27, 50];
sortHeap($arr);
print_r($arr); function sortHeap(&$arr)
{
//先建堆
buildHeap($arr); //把第一个节点和最后一个节点交换,直到节点数为1
$count = count($arr);
while ($count > 1) {
swap($arr, $count - 1, 0); //交换第一个和最后一个元素
$count--; //去掉最后一个元素后剩余元素再进行调整
adjustHeap($arr, $count, 0);
}
} function buildHeap(&$arr)
{
$node = floor(count($arr) / 2) - 1; //非叶子节点的最大节点,下标从0开始
for ($i = $node; $i >= 0; $i--) { //从最大非叶子节点循环调整每个节点
adjustHeap($arr, count($arr), $i);
}
} //调整堆,接受maxLen为当前堆需要调整的元素最大值,node为当前要调整的节点
function adjustHeap(&$arr, $maxLen, $node)
{
$lchild = 2 * $node + 1; //左子树
$rchild = 2 * $node + 2; //右子树 $max = $node; //设置当前节点为最大值的节点,方便后边最大值节点变化时与当前节点比较,确认是否需要交换 while ($lchild < $maxLen || $rchild < $maxLen) { //左子树和右子树任一个符合条件就进入循环 if ($lchild < $maxLen && $arr[$lchild] > $arr[$max]) { //左子树大于当前节点值得话设置设置$max
$max = $lchild;
} if ($rchild < $maxLen && $arr[$rchild] > $arr[$max]) {
$max = $rchild;
} if ($max != $node) {
swap($arr, $max, $node);
$node = $max; //把当前节点切换为最大值的那个节点,迭代使其符合堆特性
$lchild = 2 * $node + 1;
$rchild = 2 * $node + 2;
} else {
break; //没有发生交换就退出
}
}
} function swap(&$arr, $m, $n)
{
$arr[$m] = $arr[$m] ^ $arr[$n];
$arr[$n] = $arr[$n] ^ $arr[$m];
$arr[$m] = $arr[$m] ^ $arr[$n];
}

堆排序分析及php实现的更多相关文章

  1. Java实现---堆排序 Heap Sort

    堆排序与快速排序,归并排序一样都是时间复杂度为O(N*logN)的几种常见排序方法.学习堆排序前,先讲解下什么是数据结构中的二叉堆. 堆的定义 n个元素的序列{k1,k2,…,kn}当且仅当满足下列关 ...

  2. 浅谈C++之冒泡排序、希尔排序、快速排序、插入排序、堆排序、基数排序性能对比分析之后续补充说明(有图有真相)

    如果你觉得我的有些话有点唐突,你不理解可以想看看前一篇<C++之冒泡排序.希尔排序.快速排序.插入排序.堆排序.基数排序性能对比分析>. 这几天闲着没事就写了一篇<C++之冒泡排序. ...

  3. 八大排序算法——堆排序(动图演示 思路分析 实例代码java 复杂度分析)

    一.动图演示 二.思路分析 先来了解下堆的相关概念:堆是具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆:或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆.如 ...

  4. 排序算法(三)堆排序及有界堆排序Java实现及分析

    1.堆排序基数排序适用于大小有界的东西,除了他之外,还有一种你可能遇到的其它专用排序算法:有界堆排序.如果你在处理非常大的数据集,你想要得到前 10 个或者前k个元素,其中k远小于n,它是很有用的. ...

  5. Javascript中的冒泡排序,插入排序,选择排序,快速排序,归并排序,堆排序 算法性能分析

    阿里面试中有一道题是这样的: 请用JavaScript语言实现 sort 排序函数,要求:sort([5, 100, 6, 3, -12]) // 返回 [-12, 3, 5, 6, 100],如果你 ...

  6. 9, java数据结构和算法: 直接插入排序, 希尔排序, 简单选择排序, 堆排序, 冒泡排序,快速排序, 归并排序, 基数排序的分析和代码实现

    内部排序: 就是使用内存空间来排序 外部排序: 就是数据量很大,需要借助外部存储(文件)来排序. 直接上代码: package com.lvcai; public class Sort { publi ...

  7. STL堆排序&时间复杂度分析

    1. 逻辑&时间复杂度分析 pop 和 initialize 的时间复杂度请参考: [DSAAinC++] 大根堆的pop&remove&initialize 将数组初始化为一 ...

  8. 堆排序与优先队列——算法导论(7)

    1. 预备知识 (1) 基本概念     如图,(二叉)堆是一个数组,它可以被看成一个近似的完全二叉树.树中的每一个结点对应数组中的一个元素.除了最底层外,该树是完全充满的,而且从左向右填充.堆的数组 ...

  9. 堆排序(python实现)

    堆排序是利用最大最或最小堆,废话不多说: 先给出几个概念: 二叉树:二叉树是每个节点最多有两个子树的树结构.通常子树被称作“左子树”(left subtree)和“右子树” 完全二叉树:除最后一层外, ...

随机推荐

  1. gitflow以及git

    git大概只会用常用的那几个命令,自己用的最多的也只是add commit push pull之类的,然后那天电话面试问我版本回退怎么办我都忘记了. 然后又看了看教程,此时想起来做项目的时候师兄说的g ...

  2. Oracle ORA-07445 evaopn2()+128错误问题

    Oracle ORA-07445 evaopn2()+128错误问题 问题描述 Plsql developer执行一段sql报错: 经查alert log详细报错信息为: ORA-07445: exc ...

  3. 解决安装rpm包依赖关系的烦恼 - yum工具介绍及本地源配置方法

    版权声明:本文发布于http://www.cnblogs.com/yumiko/,版权由Yumiko_sunny所有,欢迎转载.转载时,请在文章明显位置注明原文链接.若在未经作者同意的情况下,将本文内 ...

  4. python-copy模块使用

    浅拷贝 import copy dic = { "cpu":[80,], "mem":[80,], "disk":[80,] } print ...

  5. 域普通用户执行金蝶K/3权限不够解决方法

    一.问题 公司财务部的机器加入域后,用户一直授予本地管理员的权限,主管坚持要撤销管理员权限,而金蝶K3没管理员权限又无法执行. 报错信息为“注册表许可权不够,请参考安装目录的帮助档案进行许可权的配置. ...

  6. Centos7 关闭防火墙

    CentOS 7.0默认使用的是firewall作为防火墙,使用iptables必须重新设置一下 1.直接关闭防火墙 systemctl stop firewalld.service #停止firew ...

  7. js 页面无滚动条添加滚轮事件

    当页面无滚动条时,滑动滚轮时window.onscroll事件不会相应,此时应该去添加滚轮事件 var MouseWheelHandler=function(e){ e.preventDefault( ...

  8. JavaScript代码段整理笔记系列(一)

    30段JavaScript代码——上篇 1.如何区分IE及非IE浏览器: if(!+[1,]){ //IE 11 不支持 alert("这是 IE 浏览器"): }else{ al ...

  9. Servlet过滤器

    Servlet过滤器 [TOC] 1.过滤器的基本概念 1.1.基本概念 过滤器(Filter)属于tomcat服务器中的Servlet功能.在普通的javaweb服务中,jsp中的请求要被Servl ...

  10. javamail文件上传

    //创建entity package cn.bdqn.pojo; import java.io.File; public class Mail { private String from; priva ...