堆排序
来源:互联网 发布:vpn 绕过公司网络监控 编辑:程序博客网 时间:2024/05/21 10:17
堆排序是基于完全二叉树实现的,堆分为大顶堆和小顶堆,顾名思义,大顶堆是指每个非终端节点的值大于其孩子节点的值,这样的构造使得根节点的值为数组中的最大值。对小顶堆也是同样的构造,将数组中最小的数放置在根节点,每一个双亲节点的值都小于孩子节点的值。
具体算法如下:
1、大顶堆算法实现:
public class Heap { public static void main(String[] args){ int[] s={50,10,90,30,70,40,80,60,20}; HeapSort(s); }//HeapSort的目标是初建大顶堆,并且针对调整后的数组进行重新调整。private static void HeapSort(int[] s) { int len=s.length/2; for(int i=len-1;i>=0;i--){ //该步进行大顶堆的初始化 HeapAdjust(s,i,s.length); } for(int i=s.length-1;i>1;i--){ //从最后一个节点开始向前调整,直到最后一个节点被调整 swap(s,0,i); //0所在的位置就是根节点,也就是数组中的最大值,与数组中最后一个值进行交换 //HeapAdjust(s,0,i-1); //对除数组中最后一个元素以外的剩余数组元素重新进行大顶堆调整 //HeapAdjust(s,0,i-1)从这个函数可以看出,(i-1)!=0,所以i肯定不能等于1,所以i>1位此次循环的结束条件 SmallHeapAdjust(s,0,i-1); }}private static void swap(int[] s, int i, int i2) { int a=s[i]; s[i]=s[i2]; s[i2]=a;}private static void HeapAdjust(int[] s, int k, int len) { int temp=s[k]; //temp中存放双亲节点的值 k为当前双亲节点的下标 for(int j=2*k;j<len;j*=2){ //k是双亲节点,那么2k是其左孩子节点 if(j<(len-1)&&s[j]<s[j+1]) // j是k的左孩子,那么j+1就是k的右孩子 j++; if(temp>=s[j]) break; //若双亲节点大于孩子节点中较大的,则该子树已满足大顶堆的定义,直接退出循环 s[k]=s[j]; //否则的话,让双亲节点的值为孩子节点中最大的值 k=j; //将和双亲节点进行交换的孩子节点的下标保存,用于下一次循环,或者退出循环后的赋值。 } s[k]=temp; for(int i=0;i<s.length;i++){ System.out.print(s[i]+" "); } System.out.println(); }}
排序过程及结果如下:
50 10 90 80 70 40 30 60 20 50 10 90 80 70 40 30 60 20 50 90 70 80 20 40 30 60 10 90 80 70 60 20 40 30 50 10 80 70 40 60 20 10 30 50 90 70 60 40 50 20 10 30 80 90 60 50 40 30 20 10 70 80 90 50 40 10 30 20 60 70 80 90 40 20 10 30 50 60 70 80 90 30 20 10 40 50 60 70 80 90 10 20 30 40 50 60 70 80 90
2、小顶堆算法是在大定堆的基础上进行了简单修改,具体修改部分如下:
public static void SmallHeapAdjust(int[] s,int k,int len){ int temp=s[k]; for(int j=2*k;j<len;j*=2){ if(j<(len-1)&&s[j]>s[j+1])//既然是构造小顶堆,那自然得找两个孩子里的较小的值 j++; //j指向较小的值 if(temp<=s[j]) //此处同理也是找双亲节点和孩子节点中的较小值保存到双亲节点中 break; s[k]=s[j]; k=j; } s[k]=temp; for(int i=0;i<s.length;i++){ System.out.print(s[i]+" "); } System.out.println(); }
调用此段代码的结果如下:
50 10 90 30 70 40 80 60 20 50 10 40 30 70 90 80 60 20 50 10 40 30 70 90 80 60 20 10 30 40 50 70 90 80 60 20 20 30 40 50 70 90 80 60 10 30 40 60 50 70 90 80 20 10 40 50 60 80 70 90 30 20 10 50 60 90 80 70 40 30 20 10 60 70 90 80 50 40 30 20 10 70 80 90 60 50 40 30 20 10 90 80 70 60 50 40 30 20 10
从两段代码的运行情况来看,堆排序基本没有浪费每一步的排序,即没有原地踏步走的情况,说明堆排序是一种比较好的排序方式,但是考虑到堆排序的比较与交换是跳跃式的,因此堆排序是一种不稳定的排序方式。而且堆排序无论是在最好、最坏还是平均情况下,其时间复杂度都为O(nlogn),空间消耗只有swap()函数的空间使用,因此堆排序是一种很好的排序方法。
0 0
- 堆及堆排序
- 堆/堆排序特点
- 【二叉堆、堆排序】
- 二叉堆 & 堆排序
- 二叉堆 & 堆排序
- 堆与堆排序
- 堆与堆排序
- 堆与堆排序
- 堆与堆排序
- 堆与堆排序
- 堆与堆排序
- 堆和堆排序
- 堆排序(最大堆)
- 堆和堆排序
- 堆和堆排序
- 堆及堆排序
- 堆和堆排序
- 堆与堆排序
- java [ 静态(接口)代理 ,动态(接口)代理,CglibProxy动态(实体类)代理]
- Mysql小知识
- weui upLoader
- Android学习历程--Sqlite的使用(商品展示案例)
- SMP硬实时调度算法
- 堆排序
- 深入理解Java内存模型(二)——重排序
- CEF
- MySQL索引使用的数据结构:B-Tree和B+Tree
- jQuery源码解析data
- 运营推广经理技能图谱
- springmvc注解
- 关于SQL完全卸载
- 二叉树知识总结