- 🎥 个人主页:Dikz12
- 📕格言:那些在暗处执拗生长的花,终有一日会馥郁传香
- 欢迎大家👍点赞✍评论⭐收藏
目录
1.优先级队列
2.优先级队列的模拟实现
2.1 堆的概念
2.2 堆的创建
2.3 堆的插入和删除
2.4 建堆的时间复杂度
3.PriorityQueue接口介绍
1.优先级队列
有些情况下,操作的数据可能带有优先级,一般出队列时,可能需要优先级高的元素先出队列,该中场景下,使用队列显然不合适,比如:初中那会班主任排座位时可能会让成绩好的同学先挑座位。
2.优先级队列的模拟实现
优先级队列 ( Priority Queue)底层使用了堆这种数据结构,而堆实际上就是对完全二叉树进行了一些调整。
2.1 堆的概念
堆的性质:
- 堆中某个节点的值总是不大于或不小于其父(根)节点的值;
- 堆是一颗完全二叉树
所以,堆可以分为大根堆和小根堆,也都是完全二叉树。
- 小根堆:根节点 比 左右孩子都小;左右孩子谁最小没有关系,只考虑根和左右孩子的关系
- 大根堆: 根节点 比 左右孩子都大
2.2 堆的创建
对于集合{ 27,15,19,18,28,34,65,49,25,37 }中的数据,如果将其创建成堆呢?
可以采用向下调整方式,创建大/小根堆:
创建大根堆 :
整个调整过程:
1.从最后一颗子树开始调整
2.找到左右孩子的最大值 和 根节点进行比较,如果比根节点大,那么就交换
3.如果能够知道子树的根节点下标,那么下一颗子树的位置就是当前根节点下标 -1
4.一直调整到下标为0结束
关键问题:
1.每棵子树调整的时候,什么时候结束?
就是孩子的下标要小于length
2.最后一颗子树的根节点下标如何确定?
(9-1) / 2 => (length -1) / 2
public void createBigHeap() {for (int parent = (usedSize - 1 - 1) / 2; parent >= 0; parent--) {siftDown(parent,usedSize);}}public void siftDown(int parent, int end) {int child = parent * 2 + 1;while (child < end) {if (child + 1 < usedSize && elem[child] < elem[child + 1]) {child++;}//开始调整 此时child下标,一定是最大值if (elem[child] > elem[parent]) {//交换swap(child, parent);//交换之后,验证下面是否还满足大根堆parent = child;child = parent * 2 + 1;} else {//都满足break;}}}public void swap(int i,int j) {int tmp = elem[i];elem[i] = elem[j];elem[j] = tmp;}
2.3 堆的插入和删除
插入:
1.判断是否需要扩容
2.把插入的值放到最后
3.开始向上调整
关键问题:
什么时候调整结束?
4 到---> 1 : (p - 1)/ 2 ,在 c = p, 由此推-> 当 c == 0 或者 p < 0 结束 。
插入后:
//插入public void offer(int val) {//1.是否需要扩容if (isFull()) {this.elem = Arrays.copyOf(elem,2*elem.length);}//2.向上调整elem[usedSize] = val;siftUp(usedSize);usedSize++;}public void siftUp(int child) {int parent = (child - 1) / 2;while (child > 0) {if (elem[child] > elem[parent]) {swap(child,parent);child = parent;parent = (child - 1) / 2;} else {break;}}}public boolean isFull() {return usedSize == elem.length;}
删除:
1.交换0 和 最后一个下标的值,uesdSize--
2.在向下调整就行
//删除public int poll() {if (empty()) {return -1;}int delVal = elem[0];swap(0,usedSize-1);usedSize--;siftDown(0,usedSize);return delVal;}public boolean empty() {return usedSize == 0;}
2.4 建堆的时间复杂度
因此,堆向下调整建堆的时间复杂度为O(n)。
3.PriorityQueue接口介绍
注意:
1. 使用时必须导入PriorityQueue所在的包,即:
import java.util.PriorityQueue;
2. PriorityQueue中放置的元素必须要能够比较大小,不能插入无法比较大小的对象,否则会抛出
ClassCastException异常。
3. 不能插入null对象,否则会抛出NullPointerException。
4. 没有容量限制,可以插入任意多个元素,其内部可以自动扩容。
5. 插入和删除元素的时间复杂度为O(log2N)。
6. PriorityQueue底层使用了堆数据结构。
7. PriorityQueue默认情况下是小堆---即每次获取到的元素都是最小的元素。