漫画算法-小灰的算法之旅(12)
文章目录
1. 什么是优先队列
队列的特点是什么?
队列的特点: 先进先出(FIFO),入队列,将新元素置于队尾;出队列,队头元素最先被移出。
什么是优先队列?
优先队列不再遵循先进先出的原则,而是分为两种情况。
- 最大优先队列:无论入队顺序如何,都是当前最大的元素优先出队。
- 最小优先队列:无论入队顺序如何,都是当前最小的元素优先出队。
要实现优先队列,利用线性数据结构并非不能实现,但时间复杂度较高。可以采用二叉堆实现。
2. 优先队列的实现
我们知道二叉堆的特性:
- 最大堆的堆顶是整个堆中的最大元素
- 最小堆的堆顶是整个堆中的最小元素
因此可以采用,最大堆来实现最大优先队列,这样的话,每次入队操作就是堆的插入操作,每次出队操作就是删除堆顶节点。
入队操作
具体步骤如下:
插入新节点5
新节点5**"上浮"操作**到合适位置。
出队操作
具体步骤如下:
让原堆顶节点10出队
把最后一个节点1替换到堆顶位置
节点1**"下沉"操作**,节点9成为新堆顶。
时间复杂度
优先队列的入队和出队操作,时间复杂度是多少?
因为二叉堆节点“上浮”和“下沉”的时间复杂度都是O(logn);所以优先队列入队和出队的时间复杂度都是O(logn).
3. 代码实现
private int[] array;
private int size;
public PriorityQueue(){
//队列初始长度为32
array=new int[32];
}
/**
* 入队
* param key 入队元素
*/
public void enQueue(int key){
//队列长度超出范围,扩容
if(size>=array.length){
resize();
}
array[size++]=key;
upAdjust();
}
/**
* 出队
*/
public int deQueue()throws Exception{
if(size<=0){
throw new Exception("the Queue is empty");
}
// 获取堆顶元素
int head=array[0];
//让最后一个元素移动到堆顶
array[0]=array[--size];
downAdjust();
return head;
}
/**
* "上浮"调整
*/
public void upAdjust(){
int childIndex =size-1;
int parentIndex=(childIndex-1)/2;
//temp保存插入的叶子节点值,用于最后的赋值
int temp=array[childIndex];
while(childIndex>0 && temp>array[parentIndex]){
//无须真正交换,单向赋值即可
array[childIndex]=array[parentIndex];
childIndex=parentIndex;
parentIndex=parentIndex/2;
}
array[childIndex]=temp;
}
/**
* “下沉”操作
*/
private void downAdjust(){
//temp保存父节点的值,用于最后的赋值
int parentIndex=0;
int temp=array[parentIndex];
int childIndex=1;
while(childIndex<size){
//如果有右孩子,且右孩子大于左孩子的值,则定位到右孩子,
if(childIndex+1 <size && array[childIndex+1] >array[childIndex]){
childIndex++;
}
// 如果父节点大于任何一个孩子的值,直接跳出
if(temp>=array[childIndex]){
break;
}
// 无须真正交互,单向赋值即可
array[parentIndex]=array[childIndex];
parentIndex=childIndex;
childIndex=2*childIndex+1;
}
array[parentIndex]=temp;
}
/**
* 队列扩容
*/
private void resize(){
//队列容量翻倍
int newSize=this.size*2;
this.array=Array.copyOf(this.array,newSize);
}
publice static void main(String[] args) throws Exception{
priorityQueue priorityQueue =new PriorityQueue();
priorityQueue.enQueue(3);
priorityQueue.enQueue(5);
priorityQueue.enQueue(10);
priorityQueue.enQueue(2);
priorityQueue.enQueue(7);
System.out.println("出队元素"+priorityQueue.deQueue());
System.out.println("出队元素"+priorityQueue.deQueue());
}
4. 总结
什么是树?
树是n个节点的有限集合,有且仅有一个特定的称为根的节点,当n>1时,其余节点可以分为m个互不相交的有限集合,每一个集合本身右是一个树,并称为根的子树。
什么是二叉树?
二叉树是树的一种特殊形式,每一个节点最多有两个孩子节点。二叉树包含完全二叉树、满二叉树两种特殊形式。
二叉树的遍历方式有几种
根据遍历节点之间的关系,可以分为前序遍历、中序遍历、后序遍历、层序遍历几种方式;从更宏观的角度划分,可以划分为深度优先遍历和广度优先遍历
什么是二叉堆
二叉堆是一种特殊的完全二叉树,分为最大堆和最小堆。
在最大堆中,任何一个父节点的值,都大于或等于它左、右孩子节点的值。
在最小堆中,任何一个父节点的值,都小于或等于他左、右孩子节点的值。
什么是优先队列
优先队列分为最大优先队列和最小优先队列。
最大优先队列: 无论入队顺序如何,当前最大的元素都会优先出队列,基于最大堆实现。
最小优先队列:无论入队顺序如何,当前最小的元素都会优先出队,基于最小堆实现。