数据结构与算法之堆与堆排序

  在数据结构中,其实就是一棵完全二叉树。我们知道内存中也有一块叫做堆的存储区域,但是这与数据结构中的堆是完全不同的概念。在数据结构中,堆分为大根堆小根堆,大根堆就是根结点的关键字大于等于任一个子节点的关键字,而它的左右子树又分别都是大根堆;小根堆与大根堆恰好相反。在C++的STL中优先队列priority_queue结构就是实现的堆结构。下来自己动手现实一个堆结构,包括heap_init,heap_insert,heap_top等操作。

1、堆的实现

  因为堆是一棵完全二叉树,所以我们可以用顺序表来实现,而且堆也只能用顺序表。我们用vector。

  (1) 堆的初始化

  对堆的初始化基本思想:首先初始数组是一个杂乱无章的序列,但是如果堆中只有一个元素heap[0],那么heap[0]本身是一个堆,然后加入heap[1]调整堆;继续加入heap[2].....直到完成所有元素的调整。

void sift_up(vector<int> &heap,int index){while((index+1)/2-1 >= 0){if(heap[(index+1)/2-1] < heap[index]){swap(&heap[(index+1)/2-1],&heap[index]);index = (index+1)/2-1;}elsebreak;}
}void heap_init(vector<int> &heap){if(heap.empty())return ;for(int i=1; i<heap.size(); i++){sift_up(heap,i);}
}

  (2) 向堆中插入元素

  把插入的元素放入堆的末尾,然后向上调整堆。

void heap_insert(vector<int> &heap,int element){heap.push_back(element);sift_up(heap,heap.size()-1);
}

  (3) 取出堆顶的元素

  取出一个元素后,用最后一个元素填补第一个元素的位置,然后向下依次调整堆。

void sift_down(vector<int> &heap,int index){while(index*2+2 < heap.size()){if(heap[index*2+1]>=heap[index*2+2] && heap[index]<heap[index*2+1]){swap(&heap[index],&heap[index*2+1]);index = index*2+1;}else if(heap[index*2+1]<heap[index*2+2] && heap[index]<heap[index*2+2]){swap(&heap[index],&heap[index*2+2]);index = index*2+2;}elsebreak;}
}
bool heap_top(vector<int> &heap,int *res){if(heap.empty())return false;*res = heap[0];heap[0] = heap[heap.size()-1];heap.erase(heap.end()-1);sift_down(heap,0);return true;
}

2、堆排序

  首先初始化堆,然后依次取出堆顶的值。这里为大根堆,所以是从大到小排序。

void heap_sort(vector<int> &vec){heap_init(vec);int len = vec.size();while(len--){int num;heap_top(vec,&num);printf("%d ",num);}
}

  堆排序的时间复杂度为O(nlog2n),从上面排序的步骤可以看出它是不稳定的排序。但是它与选择排序,归并排序一样时间复杂度不随序列的分布变化而变化。而对于插入排序和冒泡排序来说,当输入序列有序或者基本有序时,它们的复杂度会递减为O(n),而快速排序则会退化成O(n2)。

  所以在具体应用中,要根据输入序列来选择哪种排序方法,具体问题具体分析。由于堆排序特殊的排序结构和优良的性能,所以在很多时候下都可以采用堆排序。

3、堆排序的应用

  在一个n个数的序列中取其中最大的k个数(Top k问题)。

    这是一个很常见的排序算法题。

  方法一:直接对这这n个数进行排序,然后取k个数。时间复杂度最少为O(nlog2n)。

  方法二:借鉴快排的思路,并不需要完整地实现快排,只需要实现快排的一部分即可得到最大的k个数。复杂度为O(nlog2k)。

  方法三:可以采用哈希排序,先把n中开始的k个数放入hash表中,然后依次从剩下的的n-k个数中取出一个,与hash表中的k个数比较,每次淘汰最小的那个数。时间复杂度为O((n-k)*k)。

  方法四:取出n中开始的k个数,建立一个小根堆,然后从剩下的n-k个数中,每次取出一个数插入小根堆中,然后删除堆顶的那个元素(堆中的最小值)。时间复杂度为O(*(n-k)*lg2k)。

  不可否认,采用堆来求最大的k个数性能是最好的,但是好处还不止这么一点点!!我们试想一下,如果输入的序列很大,也就是n值很大,以致于无法全部存放在内存中,那么这时候,方法一和方法二就不管用了,当然方法一采用归并排序可以达到目的,但是这时候需要多少次IO??。如果选择方法四,最多只需要(n-k)次IO,当然方法三也是如此,只是每次需要比较k次。

  完整代码详见:https://github.com/whc2uestc/DataStructure-Algorithm/tree/master/heap

  版权所有,欢迎转载,转载请注明出处。

转载于:https://www.cnblogs.com/whc-uestc/p/4719355.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/459004.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

非法操作 login.php,阅文游戏中心 h5游戏接入wiki

阅文游戏中心《h5游戏 CP接口规范》接口要求规范游戏方接口说明&#xff1a;游戏方需按照规范提供&#xff0c;阅文进行调用阅文接口说明&#xff1a;阅文提供&#xff0c;游戏方调用参数 time 为Unix 时间戳(January 1 1970 00:00:00 GMT 起的秒数) &#xff0c;单位为秒编码统…

串口通信与编程:串口基础知识

*************************************************** 更多精彩&#xff0c;欢迎进入&#xff1a;http://shop115376623.taobao.com *************************************************** 串口是串行接口&#xff08;serial port&#xff09;的简称&#xff0c;也称为串行通信…

jmeter上传文件搞了一天,才搞定,没高人帮忙效率就是低,赶紧记下来,以备后用...

jmeter上传文件搞了一天&#xff0c;才搞定&#xff0c;没高人帮忙效率就是低&#xff0c;赶紧记下来&#xff0c;以备后用 先用谷歌浏览器抓包&#xff0c;抓到的包类似这样&#xff1a; 在jmeter里添加一个http请求&#xff0c;配置好参数&#xff0c;方法&#xff0c;端口&a…

自定义dialog

2019独角兽企业重金招聘Python工程师标准>>> R.layout.layout_insert_dialog自定义布局 View mViewLayoutInflater.from(MainActivity.this).inflate(R.layout.layout_insert_dialog, null); AlertDialog.Builder dialognew AlertDialog.Builder (MainActivity.this…

js unescape 对应php的函数,php实现Javascript的escape和unescape函数

由于需要用到php调用js文件&#xff0c;在网上找了相关的资料&#xff0c;并改写了相关的方法。php实现 Javascript的escape函数方法&#xff1a;function escape($str) {preg_match_all("/[/xc2-/xdf][/x80-/xbf]|[/xe0-/xef][/x80-/xbf]{2}|[/xf0-/xff][/x80-/xbf]{3}|[…

字符数组,字符串、数字转化

<p style"margin-top: 5px; margin-bottom: 5px; padding-top: 0px; padding-bottom: 0px; line-height: 26px; word-wrap: break-word; color: rgb(102, 102, 102); font-family: 宋体, Arial; font-size: 16px;">//****************************************…

PE文件RV转FOA及FOA转RVA

/************************************************************************/ /* 功能:虚拟内存相对地址和文件偏移的转换 参数&#xff1a;stRVA&#xff1a; 虚拟内存相对偏移地址 lpFileBuf: 文件起始地址 返回&#xff1a;转换后的文件偏移地址 */ /*****************…

SurfaceView类透明背景设置

将SurfaceView背景设置为透明&#xff0c;主要添加以下几句话就可以了&#xff1a; 在SurfaceView创建后设置一下下面的参数&#xff1a; setZOrderOnTop(true); getHolder().setFormat(PixelFormat.TRANSLUCENT); 还有在draw方法中绘制背景颜色的时候以下面的方式进行绘制就可…

oracle的env函数用法,env命令_Linux env 命令用法详解:显示系统中已存在的环境变量...

env命令用于显示系统中已存在的环境变量&#xff0c;以及在定义的环境中执行指令。该命令只使用"-"作为参数选项时&#xff0c;隐藏了选项"-i"的功能。若没有设置任何选项和参数时&#xff0c;则直接显示当前的环境变量。如果使用env命令在新环境中执行指令…

网络通信的工作原理

*************************************************** 更多精彩&#xff0c;欢迎进入&#xff1a;http://shop115376623.taobao.com *************************************************** 1、什么是计算机网络&#xff1f; 计算机网络是由两台或两台以上的计算机通过网络设备…

Bossie Awards 2015: The best open source applicati

2019独角兽企业重金招聘Python工程师标准>>> Read about more open source winners InfoWorlds Best of Open Source Awards for 2014 celebrate more than 100 open source projects, from the bottom of the stack to the top. Follow these links to more open s…

oracle中pga指什么,oracle学习SGA跟PGA理解

SGA&#xff1a;SystemGlobal Area是OracleInstance的基本组成部分&#xff0c;在实例启动时分配;系统全局域SGA主要由三部分构成&#xff1a;数据库缓冲区、日志缓冲区、共享池&#xff0c;还可能包含&#xff1a;大池&#xff0c;JAVA池&#xff0c;流池。注意点&#xff1a;…

oracle重做日志教程,Oracle教程:重做日志文件基本维护

重做日志文件最重要的用途就是用来恢复数据(其实你也可以用来logminer)&#xff0c;它记录着system global area(sga)当中的database bu重做日志文件最重要的用途就是用来恢复数据(其实你也可以用来logminer)&#xff0c;它记录着system global area(sga)当中的database buffer…

以太网,局域网,万维网

*************************************************** 更多精彩&#xff0c;欢迎进入&#xff1a;http://shop115376623.taobao.com *************************************************** 以太网是一种通信协议标准 万维网WWW 是 Internet 的多媒体信息查询工具 以太网: 以…

java的自动类型转换和强制类型转换

在程序运行时&#xff0c;经常需要将一种数值类型进行转换成另一种类型。下面给出了一个合法的转换。数值之间的合法转换上图中有6个实心箭头&#xff0c;表示无信息丢失的转换&#xff0c;有三个虚箭头&#xff0c;表示可能有精度丢失的转换。例如123456789是一个大整数&#…

Class 泛型

Java Class 泛型的例子说明&#xff1a; http://blog.chinaunix.net/uid-1911213-id-3085866.html http://blog.163.com/sir_876/blog/static/1170522320121216273111/转载于:https://www.cnblogs.com/yedu/p/4514016.html

java动态代理的实现

动态代理作为代理模式的一种扩展形式&#xff0c;广泛应用于框架&#xff08;尤其是基于AOP的框架&#xff09;的设计与开发&#xff0c;本文将通过实例来讲解Java动态代理的实现过程。友情提示&#xff1a;本文略有难度&#xff0c;读者需具备代理模式相关基础知识&#xff0c…

常见的网络类型

*************************************************** 更多精彩&#xff0c;欢迎进入&#xff1a;http://shop115376623.taobao.com *************************************************** 我们经常听到Internet网、星形网等名词&#xff0c;它们表示什么&#xff1f;是怎样分…

oracle放在内存里,oracle如中何把小表钉住在内存中

buffer_pool_defualtbuffer_pool_keepbuffer_pool_recycle如果要把表钉死在内存中&#xff0c;也就是把表钉在keep区。相关的命令为&#xff1a;alter table ..... storage(buffer_pool keep);这句命令把表示表如果缓存的话是缓存在keep区。可以通过语句&#xff1a;select tab…

C++基础之this指针的详解

*************************************************** 更多精彩&#xff0c;欢迎进入&#xff1a;http://shop115376623.taobao.com *************************************************** 关于C中的this指针&#xff0c;建议大家看看这篇文章&#xff0c;《C中的this指针》&a…