堆排序
来源:互联网 发布:mac apache 关联php7 编辑:程序博客网 时间:2024/04/29 18:34
堆的定义:n个元素的序列{Kl,K2,…,Kn}当且仅当满足如下关系时,称之为堆。
(1) ki≤K2i且ki≤K2i+1 或(2)Ki≥K2i且ki≥K2i+1(1≤i≤ )
若将和此序列对应的一维数组(即以一维数组作为此序列的存储结构)看成是一个完全二叉树,则堆的含义表明,完全二叉树中所有非终端节点的值均不大于(或不小于)其左右孩子节点的值。由此,若序列{Kl,K2,…,Kn}是堆,则堆顶元素(或完全二叉树的根)必为序列中n个元素的最小值(或最大值)。
序列{96,83,27,38,11,09}为堆,对应的二叉树如下图:
若在输出输出堆顶的最大值(最小值)之后,使得剩余的(n-1)个元素的序列重又建成一个堆,则得到n个元素中的次大(小)值。如此反复执行,便能的得到一个有序序列,这个过程称为堆排序。
堆排序是一种树形选择排序,堆排序和直接选择排序的区别:
直接选择排序中,为了从R[1..n]中选出关键字最小的记录,必须进行n-1次比较,然后在R[2..n]中选出关键字最小的记录,又需要做n-2次比较。事实上,后面的n-2次比较中,有许多比较可能在前面的n-1次比较中已经做过,但由于前一趟排序时未保留这些比较结果,所以后一趟排序时又重复执行了这些比较操作。堆排序可通过树形结构保存部分比较结果,可减少比较次数。
实现堆排序需要解决两个问题:(1)如何由一个无序序列构造一个堆?(2)如何在输出堆顶元素后,调整剩余的元素成为一个新的堆?
因为构造初始堆需要用到堆得调整操作,所以我们先讨论“如何在输出堆顶元素后,调整剩余的元素成为一个新的堆”。
堆得调整(heapify):如图pic2所示的一个小根堆,假设输出堆顶元素之后,以堆中最后一个元素代替堆顶的元素,如图pic3所示。此时根节点的左右子树均为堆,则仅需自上自下向下调整即可。
首先以堆顶的元素和其左右子树的根结点的值进行比较,由于右子树的根节点小于左子树的根节点并且小于根节点的值。所以要将27和97交换,如图pic3种箭头所示。
由于97代替27之后破坏了右子树的堆的性质,则要将右子树进行核上述相同的调整,直至叶子节点。
pic2
pic3
我们称这个自堆顶至叶子节点的调整过程为“筛选”。
从一个无序序列构建堆得过程就是一个反复“筛选”的过程。若将此序列看成是一个完全二叉树,则最后一个非终端节点是第 个元素,由此“筛选”只需从第 个元素开始。
筛选函数heapify的算法如下:
/** * 调整a[i...j]使其成为一个大顶堆 * @param s表示需要调整的堆的堆顶的坐标 * @param m表示堆中索引的下限 * */protected void heapify(int[]a,int s,int m){int rc=a[s];for(int j=2*s;j<=m;j*=2){if(j<m&&a[j]<a[j+1])++j;if(rc>=a[j])break;a[s]=a[j];s=j;}a[s]=rc;}
构建初始堆的算法如下:
protected void buildheap(int[]a){int n=a.length/2;//最后一个非终端节点for(int i=n;i>=0;--i)this.heapify(a, i, a.length -1);}堆排序:
public void heapsort(int[]a){this.buildheap(a);int temp=0;for(int i=a.length-1;i>0;i--){temp=a[0];a[0]=a[i];a[i]=temp;this.heapify(a, 0, i-1);}}
- 堆及堆排序
- 堆/堆排序特点
- 【二叉堆、堆排序】
- 二叉堆 & 堆排序
- 二叉堆 & 堆排序
- 堆与堆排序
- 堆与堆排序
- 堆与堆排序
- 堆与堆排序
- 堆与堆排序
- 堆与堆排序
- 堆和堆排序
- 堆排序(最大堆)
- 堆和堆排序
- 堆和堆排序
- 堆及堆排序
- 堆和堆排序
- 堆与堆排序
- 暴力+数学 HDU1394 Minimum Inversion Number
- 如何判断设备处于静音模式
- 内建获取调用地址
- GPS-NMEA解析代码
- android 之 画图
- 堆排序
- prolog判断手绘流程图的合法性
- OpenERP雇员(员工)表与用户表关联字段解析[2]
- WiFi Air Sniffer
- 黑马程序员--- 学习笔记(第二十一天)
- 关于json字符串解析
- Web开发常见的几个漏洞解决方法
- Oracle按月份累计求和
- css+div中解决英文和数字的溢出问题