目录
优先级队列
1.概念
前面介绍过队列,队列是一种先进先出的数据结构。
但有些情况下,操作的数据可能带有优先级,一般出队列时,可能需要优先级高的元素先出队列,在该场景下,使用队列显然不合适,比如,在玩游戏的时候,如果有来电,系统会优先处理打进来的电话。
在这种情况下,数据结构应该提供两个基本的操作,一个是返回最高优先级对象,一个是添加新对象,这种数据结构是优先级队列(Priority Queue)。
2.
优先级队列的模拟实现
JDK1.8中的PriorityQueue底层使用了堆这种
数据结构,而堆实际就是在完全二叉树的基础上进行了一些调整。
堆
1. 堆的概念
如果有一个 关键码的集合 K = {k0 , k1 , k2 , … , kn-1},把它的所有元素 按完全二叉树的顺序存 储方式存储 在一 个一维数组中,并满足: Ki <= K2i+1 且 Ki<= K2i+2 (Ki >= K2i+1 且Ki >=K2i+2) i = 0,1,2…,则 称为 小堆(或大 堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。
堆的性质:
●堆中某个节点的值总是不大于或不小于其父节点的值;
●堆总是一棵完全二叉树。
2.堆的存储方式
从堆的概念可知,
堆是一棵完全二叉树,因此可以层序的规则采用顺序的方式来高效存储,
注意:对于
非完全二叉树,则不适合使用顺序
方式进行存储,因为为了能够还原二叉树,
空间中必须要存储空节 点,就会导致空间利用率比较低。
将元素存储到数组中后,可以根据二叉树章节的性质5对树进行还原。假设i为节点在数组中的下标,则有:
如果i为0,则i表示的节点为根节点,否则i节点的双亲节点为 (i - 1)/2如果2 * i + 1 小于节点个数,则节点i的左孩子下标为2 * i + 1,否则没有左孩子如果2 * i + 2 小于节点个数,则节点i的右孩子下标为2 * i + 2,否则没有右孩
3. 堆的创建
对于集合{ 27,15,19,18,28,34,65,49,25,37 }中的数据,如果将其创建成大根堆呢?
1. 让parent标记需要调整的节点,child标记parent的左孩子(注意:parent如果有孩子一定先是有左孩子)
2. 如果parent的左孩子存在即:即:child<usedSize, 进行以下操作,直到parent的左孩子不存在
判断 parent右孩子是否存在,存在找到左右孩子中最大的孩子,让child始终指向最大值孩子将parent与较大的孩子child比较,如果:●parent大于较大的孩子child,调整结束●否则:交换parent与较大的孩子child,交换完成之后,parent中大的元素向下移动,可能导致子 树不满足堆的性质,因此需要继续向下调整,即parent = child;child = parent*2+1; 然后继续2。
代码实现
注意:在调整以
parent
为根的二叉树时,必须要满足
parent
的左子树和右子树已经是堆了才可以向下调整。
时间复杂度分析:最坏的情况即图示的情况, 从根一路比较到叶子,比较的次数为完全二叉树的高度,即时间复杂度为
4. 建堆的时间复杂度
因为堆是完全二叉树,而满二叉树也是完全二叉树,此处为了简化使用满二叉树来证明(时间复杂
度本来看的就是 近似值,多几个节点不影响最终结果)
时间复杂度O(N)
总结
优先队列常使用完全二叉树实现,本文主要让大家了解优先级队列和堆的相关概念,并学会了堆的存储方式和堆的创建。关于堆的其他操作会在后续文章中讲解。