漫画:什么是优先队列
轉(zhuǎn)載自??漫畫:什么是優(yōu)先隊(duì)列
在之前的漫畫中,我們介紹了二叉堆和堆排序。沒看過的小伙伴可以看一看前文:
漫畫:什么是二叉堆?(修正版)
漫畫:什么是堆排序?
這一次,我們來講一講二叉堆的另外一個(gè)應(yīng)用:優(yōu)先隊(duì)列
隊(duì)列的特點(diǎn)是什么?
?
聰明的小伙伴們都知道,是先進(jìn)先出(FIFO)。
入隊(duì)列:
?
出隊(duì)列:
那么,優(yōu)先隊(duì)列又是什么樣子呢?
優(yōu)先隊(duì)列不再遵循先入先出的原則,而是分為兩種情況:
最大優(yōu)先隊(duì)列,無論入隊(duì)順序,當(dāng)前最大的元素優(yōu)先出隊(duì)。
最小優(yōu)先隊(duì)列,無論入隊(duì)順序,當(dāng)前最小的元素優(yōu)先出隊(duì)。
比如有一個(gè)最大優(yōu)先隊(duì)列,它的最大元素是8,那么雖然元素8并不是隊(duì)首元素,但出隊(duì)的時(shí)候仍然讓元素8首先出隊(duì):
要滿足以上需求,利用線性數(shù)據(jù)結(jié)構(gòu)并非不能實(shí)現(xiàn),但是時(shí)間復(fù)雜度較高,最壞時(shí)間復(fù)雜度O(n),并不是最理想的方式。
至于為什么最壞時(shí)間復(fù)雜度是O(n),大家可以思考下。
?
讓我們回顧一下二叉堆的特性:
1.最大堆的堆頂是整個(gè)堆中的最大元素
2.最小堆的堆頂是整個(gè)堆中的最小元素
因此,我們可以用最大堆來實(shí)現(xiàn)最大優(yōu)先隊(duì)列,每一次入隊(duì)操作就是堆的插入操作,每一次出隊(duì)操作就是刪除堆頂節(jié)點(diǎn)。
入隊(duì)操作:
1.插入新節(jié)點(diǎn)5
2.新節(jié)點(diǎn)5上浮到合適位置。
出隊(duì)操作:
1.把原堆頂節(jié)點(diǎn)10“出隊(duì)”
2.最后一個(gè)節(jié)點(diǎn)1替換到堆頂位置
3.節(jié)點(diǎn)1下沉,節(jié)點(diǎn)9成為新堆頂
?
public class PriorityQueue { private int[] array; private int size;public PriorityQueue(){//隊(duì)列初始長(zhǎng)度32array = new int[32]; }/** * 入隊(duì) * @param key ?入隊(duì)元素 */ private void enQueue(int key) {//隊(duì)列長(zhǎng)度超出范圍,擴(kuò)容if(size >= array.length){resize();}array[size++] = key;upAdjust(); }/** * 出隊(duì) */ private int deQueue() throws Exception {if(size <= 0){throw new Exception("the queue is empty !");}//獲取堆頂元素int head = array[0];//最后一個(gè)元素移動(dòng)到堆頂array[0] = array[--size];downAdjust();return head; }/** * 上浮調(diào)整 */ private void upAdjust() {int childIndex = size-1;int parentIndex = childIndex/2;// temp保存插入的葉子節(jié)點(diǎn)值,用于最后的賦值int temp = array[childIndex];while (childIndex > 0 && temp > array[parentIndex]){//無需真正交換,單向賦值即可array[childIndex] = array[parentIndex];childIndex = parentIndex;parentIndex = parentIndex / 2;}array[childIndex] = temp; }/** * 下沉調(diào)整 */ private void downAdjust() {// temp保存父節(jié)點(diǎn)值,用于最后的賦值int parentIndex = 0;int temp = array[parentIndex];int childIndex = 1;while (childIndex < size) {// 如果有右孩子,且右孩子大于左孩子的值,則定位到右孩子if (childIndex + 1 < size && array[childIndex + 1] > array[childIndex]) {childIndex++;}// 如果父節(jié)點(diǎn)大于任何一個(gè)孩子的值,直接跳出if (temp >= array[childIndex])break;//無需真正交換,單向賦值即可array[parentIndex] = array[childIndex];parentIndex = childIndex;childIndex = 2 * childIndex + 1;}array[parentIndex] = temp; }/** * 擴(kuò)容調(diào)整 */ private void resize() {//隊(duì)列容量翻倍int newSize = this.size * 2;this.array = Arrays.copyOf(this.array, newSize); }public 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("出隊(duì)元素:" + priorityQueue.deQueue());System.out.println("出隊(duì)元素:" + priorityQueue.deQueue()); } }代碼中采用數(shù)組來存儲(chǔ)二叉堆的元素,因此當(dāng)元素超過數(shù)組范圍的時(shí)候,需要進(jìn)行resize來擴(kuò)大數(shù)組長(zhǎng)度。
?
總結(jié)
以上是生活随笔為你收集整理的漫画:什么是优先队列的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 选择大公司还是小公司
- 下一篇: sleep( ) 和 wait( ) 的