堆结构是一种非常重要的基础数据结构,也是算法的重要内容,很多题目甚至只能用堆来进行。
由于堆的构造和维护过程都非常复杂,因此面试时一般不需要手写堆的实现过程,但是java、python、C++已经提供了一些工具,因此需要知道思路就可以。
本关主要介绍堆如何增删改查的,不用管代码怎么写,后面再介绍如何使用堆来解决问题
堆的概念与特征
堆是将一组数据按照完全二叉树的存储顺序,将数据存储在一个一维数组中的结构。堆有两种结构,一种称为大顶堆,一种称为小顶堆。
- 小顶堆:任意节点的值均小于等于它的左右孩子,并且最小的值位于堆顶,即根节点处。
- 大顶堆:任意节点的值均大于等于它的左右孩子,并且最大的值位于堆顶,即根节点处。
有些地方也叫大根堆、小根堆,或者最大堆、最小堆。
区分优先队列与堆
优先队列:说到底还是一种队列,它的工作就是poll / peek出队列中最大/最小的那个元素,所以叫带有优先级的队列。能够实现优先功能的策略不一定只有堆,例如二项堆、平衡树、线段树、C++里会用二进制分组的vector来实现一个优先队列。
堆: 堆是一个很大的概念,它并不一定是完全二叉树。我们之前用完全二叉树是因为这样数据容易被数组储存。但是除了这种二叉堆之外,我们还有二项堆、斐波那契堆,这些堆就不属于二叉树。
所以说,优先队列和堆不是一个同level的概念 ,但是java的PriorityQueue就是堆实现的,因此在java领域可以认为堆就是优先级队列,优先级队列就是堆,换做其他场景则不行
堆的构造过程
若父节点下标为 i (从0开始记),则左孩子下标为 2i+1,左孩子下标为 2i+2.
所以,若左孩子的下标为 j ,则父节点下标为 (j - 1) / 2;若右孩子的下标为 j ,则父节点下标为 (j - 2) / 2
构造过程、插入操作、删除操作请移步链接