目录
一、概念
1.优先级队列(堆)︰按照优先级的大小动态出队(动态指的是元素个数动态变化,而非固定)
2.普通队列:FIFO按照元素的入队顺序出队,先入先出。
I
现实生活中的优先级队列
例子 PriorityQueue
1.医生根据病人病情排手术排期
病情相同的情况下按照先来先排,若病情较重,优先安排手术。
二、时间复杂度
普通的链式队列 o(logn) 入队 o(1) 出队(出当前队列的最大值)(on)
优先级队列(堆) o(logn) 入队o(logn) 出队(出当前队列的最大值)(on)
基于二叉树的堆(二叉堆,应用最广泛的堆)d叉堆,索引堆
三、二叉堆的特点:
1.一颗完全二叉树,基于数组存储(元素都是靠左排列,数组中存储时不会浪费空间)
只有完全二叉树适合使用这种结构来存储
其他的二叉树都要用链式结构2关于节点值:
堆中根节点值>=子树节点中的值(最大堆,大根堆)
堆中根节点值<=子树中节点的值(最小堆,小根堆)
最大堆:堆中树根>=子树中所有节点,所有子树也仍然满足堆的定义
注意点
1.节点的层次和节点的大小没有任何关系只能保证当前树中,树根是最大值。其他节点层次大小关系不确定
2.JDK中的PriorityQueue默认是基于最小堆的实现。
3.因为堆是基于数组来存储的,节点的之间的关系通过数组下标来表示从O开始编号,数组下标也是从0开始。
假设此时结点编号为i,且存在父子节点
父节点编号parent = (i - 1)/2;
左子树的编号left = 2*i+1;右子树的编号left = 2*i+ 2;
按照数组【60,40,30,29,15,22,12,18,16,14,】保存
节点之间通过数组的索引下标来找到父子节点
四、实现代码
/**
* 基于动态数组实现的最大堆
*
**/
public class MaxHeap {
// 实际存储元素的数组
private List<Integer> elementData;
// 当前堆中元素个数
private int size;
public MaxHeap() {
this(10);
}
public MaxHeap(int size) {
elementData = new ArrayList<>(size);
}
public void add(int val) {
// 1.直接向数组末尾添加元素
elementData.add(val);
size ++;
// 2.进行元素的上浮操作
siftUp(size - 1);
}
private void siftUp(int k) {
while (k > 0 && elementData.get(k) > elementData.get(parent(k))) {
swap(k,parent(k));
k = parent(k);
}
}
private void swap(int k, int parent) {
int child = elementData.get(k);
int parentVal = elementData.get(parent);
elementData.set(k,parentVal);
elementData.set(parent,child);
}
public int getSize() {
return size;
}
public boolean isEmpty() {
return size == 0;
}
/**
* 找到结点k对应的父节点的索引
* @param k
* @return
*/
private int parent(int k) {
return (k - 1) >> 1;
}
/**
* 找到结点k对应的左子树的索引
* @param k
* @return
*/
private int leftChild(int k) {
return (k << 1) + 1;
}
/**
* 找到结点k对应的右子树的索引
* @param k
* @return
*/
private int rightChild(int k) {
return (k << 1) + 2;
}
@Override
public String toString() {
return elementData.toString();
}
}