算法通关村第十四关——原来这就是堆

1.什么是堆?

概念:按照完全二叉树的存储顺序将一组数据存储在一个数组中。

结构

大顶堆(大根堆、最大堆):任意节点的值均大于等于它的左右孩子,并且最大值位于堆顶,也就是根节点处。

算法通关村第十四关——原来这就是堆_第1张图片

小顶堆(小根堆、最小堆):任意节点的值均小于等于它的左右孩子,并且最小值位于堆顶,也就是根节点处。

算法通关村第十四关——原来这就是堆_第2张图片

优先队列和堆的区别

优先队列: 在JavaScript中可以参考Github里这个项目datastructures-js/priority-queue。还是属于队列数据结构,能够front()或者back()出最大或者最小的元素,所以是具有优先级的的队列。实现优先功能的策略不一定只有堆,例如二项堆、平衡树、线段树。

堆:堆是一个很大的的概念。除了用完全二叉树实现的堆之外,还有二项堆、斐波那契堆。

2.堆的构造过程

使用数组构建就是先按照层次将所有元素依次填入二叉树中,使其成为二叉树,然后再不断调整,最终使其符合堆结构。

假设一个节点下标为i:当i = 0时,为根节点。当 i >= 1时,父节点为 i − 1 2 \frac{i - 1}{2} 2i1,size就是元素的个数,从1开始计数。

以大顶堆的构建为例:

1)二叉树位置索引从0开始,当i >= 1时,父节点为(size - 2) / 2 = 4。找到数组中的4号下标,69大于其孩子,满足大顶堆性质,不用交换。

算法通关村第十四关——原来这就是堆_第3张图片

2)然后i = i - 1,用4和其孩子比较,4和301交换,交换之后301所在子树满足大顶堆性质。然后是53和其孩子比较,进行交换。

算法通关村第十四关——原来这就是堆_第4张图片

3)接着是27和其孩子比较并交换,一直到满足大顶堆性质,最后是16和其孩子比较并交换,直到满足大顶堆性质。最后得到大顶堆。

算法通关村第十四关——原来这就是堆_第5张图片

3.插入操作

将元素插入到保持其为完全二叉树的最后一个位置,然后顺着这条支路一直向上调整,每前进一层就要保证其子树都满足堆否则就去处理子树,直到完全满足要求。例如在大顶堆插入215,如下图所示。

算法通关村第十四关——原来这就是堆_第6张图片

4.删除操作

堆中数据操作一般都是对堆顶元素进行操作,实际策略是先将堆中最后一个元素(假如为A)和堆顶元素进行替换,然后删除堆中最后一个元素。之后再从根开始逐步与左右比较,谁更大谁上位。然后A再继续与子树比较,如果有更大的继续交换,直到自己所在的子树也满足大顶堆。

举例,删除堆顶元素301:

算法通关村第十四关——原来这就是堆_第7张图片

15与301交换位置后,继续与其孩子进行比较并交换,直到满足大顶堆性质。

算法通关村第十四关——原来这就是堆_第8张图片

5.总结

关于堆的问题总结为口诀:

查找:找大用小,大的进;找小用大,小的进。就是找第K大的数,就用小顶堆,后续数据只有比根元素大的时才允许进入堆。如果时找第K小的数,就用大顶堆,后续数据只有比跟元素小才能进堆。

排序:升序用小,降序用大。升序用小顶堆,从根节点开始到叶子节点逐渐增大,降序用大顶堆,从根节点开始到叶子节点逐渐减小。

你可能感兴趣的:(算法,算法,数据结构,前端)