https://www.cnblogs.com/chenweichu/articles/5710567.html
https://blog.csdn.net/zsc2014030403015/article/details/45872737
https://www.jianshu.com/p/d174f1862601?utm_campaign=haruki&utm_content=note&utm_medium=reader_share&utm_source=weixin
目录
1、堆
2、堆与二叉搜索树
3、堆的插入和删除
3、c++里实现堆的几个方法
4、引申真题
5、使用Python实现堆的构建,并且实现堆排序
堆(英语:heap)是一类特殊的数据结构的统称。堆通常可以被看做一棵树的数组对象。是非线性数据结构,相当于一维数组。
堆就是用数组实现的二叉树,所有它没有使用父指针或者子指针。堆总是满足下列性质:
堆中某个节点的值总是不大于或不小于其父节点的值;
堆总是一棵完全二叉树。
堆分为两种:最大堆和最小堆,两者的差别在于节点的排序方式。在最大堆中,父节点的值比每一个子节点的值都要大。在最小堆中,父节点的值比每一个子节点的值都要小。这就是所谓的“堆属性”,并且这个属性对堆中的每一个节点都成立。上图是一个最大堆。可以看出最大堆的根节点就是这些节点中的最大值。所以堆可以用作优先队列使用,队列中先出现的其实就是最大/最小的值。但是要注意的是!top是最大或最小值,最后一个值不一定是最小/大值。我们只能确定最小/大值是叶子节点中的一个但是不知道是哪个。
二叉搜索树是一种排序好的树,其左子树的值一定小于根,根一定小于右子树的值。
但是这两者首先排序方式不同,其次数据结构本身就不同。而且堆仅仅用数组表示树的结构可以大幅度降低内存使用,但是树的结构受限。
二叉搜索树必须是“平衡”的情况下,其大部分操作的复杂度才能达到O(log n)。堆中实际上不需要整棵树都是有序的。我们只需要满足对属性即可,所以在堆中平衡不是问题。因为堆中数据的组织方式可以保证O(log n) 的性能。(插入删除)
在二叉树中搜索会很快,但是在堆中搜索会很慢。在堆中搜索不是第一优先级,因为使用堆的目的是将最大(或者最小)的节点放在最前面,从而快速的进行相关插入、删除操作。(查找)
总之堆适合找当前最大的数和最小的数。
(下面我们都假设数组第一个数是1)
3.1插入、建堆
当我们有一个无序序列,99、5、36、7、22、17、46、12、2、19、25、28、1和92,把他们建成一个最小堆。堆是用数组存储。所以我们这里就不用树状图表示过程,直接使用数组。
首先定义一个数组a[14]。之后把第一个数放进去[_,99]。n=1 i=n, while(i!=1) {} else 加入下一个点
之后5进来。n=2 i=n【_,99,5】。while(i!=1) {if(a[i/2]>a[i]) swap(a[i/2],a[i]); i=i/2 }else 加入下一个点 //所以[_,5,99]
之后36进来。n=3 i=n [_,5,99,36] 。while(i!=1) {if(a[i/2]>a[i]) swap(a[i/2],a[i]);else {break;} i=i/2 }else 加入下一个点 //所以[5,99,36]
之后7进来。n=4 i=n [_,5,99,36,7] 。i=4,a[i/2]=99 99>7 所以交换得到[_,5,7,36,99]。i=2.a[i/2]=5 5<7break;
之后22进来。 n=5 i=n [_,5,7,36,99,22]。i=5,a[i/2]=7 7<22,break.
之后17进来。n=6 i=n [_,5,7,36,99,22,17]。i=6,a[i/2]=36 36>17,所以交换得到[_,5,7,17,99,22,36]。i=3.a[i/2]=5 5<17break;
之后46进来。n=7 i=n [_,5,7,17,99,22,36,46]。i=7,a[i/2]=36 17<46,break;
之后12进来。n=8 i=n [_,5,7,17,99,22,36,46,12]。i=8,a[i/2]=99 99>12,所以交换得到[_,5,7,17,12,22,36,46,99].i=4.a[i/2]=7 7<12 break;
之后2进来。n=9 i=n [_,5,7,17,12,22,36,46,99,2]。i=9,a[i/2]=12 12>2,所以交换得到[_,5,7,17,2,22,36,46,99,12].i=4,a[i/2]=7 7>2 所以交换得到 [_,5,2,17,7,22,36,46,99,12]i=2 a[i/2]=5 5>2 所以交换得到 [_,2,5,17,7,22,36,46,99,12]
之后19进来。n=10 i=n [_,2,5,17,7,22,36,46,99,12,19]。i=10 a[i/2]=22 ,22>19,所以交换得到[_,2,5,17,7,19,36,46,99,12,22] i=5 a[i/2]=5 5<19 break
之后25进来。n=11 i=n [_,2,5,17,7,19,36,46,99,12,22,25]。i=11 a[i/2]=19 19<25,break
之后28进来。n=12 i=n [_,2,5,17,7,19,36,46,99,12,22,25,28]。i=12 a[i/2]=36 36>28,所以交换得到[_,2,5,17,7,19,28,46,99,12,22,25,36] i=6 a[i/2]=17<28 break.
之后1进来。n=13 i=n [_,2,5,17,7,19,28,46,99,12,22,25,36,1] i=13 a[i/2]=28>1,所以交换得到[_,2,5,17,7,19,1,46,99,12,22,25,36,28] i=6 a[i/2]=17>1,所以交换得到[_,2,5,1,7,19,17,46,99,12,22,25,36,28] i=3 a[i/2]=2>1,所以交换得到[_,1,5,2,7,19,17,46,99,12,22,25,36,28]
之后92进来。n=14 i=n [_,1,5,2,7,19,17,46,99,12,22,25,36,28,92] i=14 a[i/2]=46<92 break
所以最终得到最小堆[1,5,2,7,19,17,46,99,12,22,25,36,28,92]
删除当前的最小值。[1,5,2,7,19,17,46,99,12,22,25,36,28,92],及去掉1.方法是把第一个数1替换成序列的最后一个值,之后进行判断是不是最小堆。得到[92,5,2,7,19,17,46,99,12,22,25,36,28]
。所以对于i=1,首先去看a[i*2]和a[i*2+1]谁小,再判断小的那个是不是比a[i]小,如果小则小的那个是新的a[i]。j=a[i*2]
对于i=1 a[i*2]=5>a[i*2+1]=2,j=3,且2<92,则交换得到[2,5,92,7,19,17,46,99,12,22,25,36,28,92],i=3