1、優先隊列的特點
隊列 的特點是 先進先出, 入隊列,將新元素置於隊尾:
出隊列,隊頭元素最先被移出:
優先隊列不再遵循先入先出的原則,而是分爲兩種情況:
- 最大優先隊列,無論入隊順序如何,都是當前最大的元素優先出隊
- 最小優先隊列,無論入隊順序如何,都是當前最小的元素優先出隊
例:
有一個最大優先隊列,其中的最大元素是8,那麼雖然8並不是隊頭元素,
但出隊時仍然讓元素8首先出隊
2、優先隊列的實現
二叉堆的特性:
- 最大堆的堆頂是整個堆中的最大元素
- 最小堆的堆頂是整個堆中的最小元素
可以用最大堆來實現最大優先隊列:
每一次 入隊 操作就是堆的 插入 操作;
每一次 出隊 操作就是刪除堆頂節點
入隊操作 步驟如下:
- 插入新節點5
- 新節點5“上浮”到合適位置
出隊操作 步驟如下: - 讓原堆頂節點10出隊
- 把最後一個節點1替換到堆頂位置
- 節點1“下沉”,節點9成爲新堆頂
二叉堆節點“上浮”和“下沉”的時間複雜度都是 O(logn)
所以優先隊列入隊和出隊的時間複雜度也是 O(logn)
3、優先隊列的代碼實現
採用數組來存儲二叉堆的元素,當元素數量超過數組長度時,需要進行擴容來擴大數組長度
import java.util.Arrays;
//構建隊列
public class TreeNode4 {
private int[] array;
private int size;
public TreeNode4(){
//隊列初始長度爲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;
}
/**
* “下沉操作”
*/
public 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;
}
/**
* “隊列擴容”
*/
public void resize() {
//隊列容量翻倍
int newSize = this.size * 2;
this.array = Arrays.copyOf(this.array,newSize);
}
public static void main(String[] args) throws Exception{
TreeNode4 priorityQueue = new TreeNode4();
priorityQueue.enQueue(3);
priorityQueue.enQueue(5);
priorityQueue.enQueue(10);
priorityQueue.enQueue(2);
priorityQueue.enQueue(7);
System.out.println("出隊元素:" + priorityQueue.deQueue());
System.out.println("出隊元素2:" + priorityQueue.deQueue());
}
}
編譯輸出:
4、總結
- 樹
樹是n個節點的有限集,有且僅有一個特定的稱爲根的節點。當n>1時,其餘節 點可分爲m個互不相交的有限集,每一個集合本身又是一個樹,並稱爲根的子樹; - 二叉樹
二叉樹是樹的一種特殊形式,每一個節點最多有兩個孩子節點。二叉樹包含完
全二叉樹和滿二叉樹兩種特殊形式; - 二叉樹的遍歷方式
根據遍歷節點之間的關係,可以分爲前序遍歷、中序遍歷、後序遍歷、層序遍歷這4種方式;
從更宏觀的角度劃分,可以劃分爲深度優先遍歷和廣度優先遍歷兩大類; - 二叉堆
二叉堆是一種特殊的完全二叉樹,分爲最大堆和最小堆:
在最大堆中,任何一個父節點的值,都大於或等於它左、右孩子節點的值。
在最小堆中,任何一個父節點的值,都小於或等於它左、右孩子節點的值。 - 優先隊列
優先隊列分爲最大優先隊列和最小優先隊列;
在最大優先隊列中,無論入隊順序如何,當前最大的元素都會優先出隊,這是 基於最大堆實現的;
在最小優先隊列中,無論入隊順序如何,當前最小的元素都會優先出隊,這是 基於最小堆實現的。
———————————————————————————————————————
內容來源:《漫畫算法》
關注公衆號,回覆 【算法】,獲取高清算法書!