圖解數據結構(09) -- 優先隊列

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種方式;
    從更宏觀的角度劃分,可以劃分爲深度優先遍歷和廣度優先遍歷兩大類;
  • 二叉堆
    二叉堆是一種特殊的完全二叉樹,分爲最大堆和最小堆
    在最大堆中,任何一個父節點的值,都大於或等於它左、右孩子節點的值。
    在最小堆中,任何一個父節點的值,都小於或等於它左、右孩子節點的值。
  • 優先隊列
    優先隊列分爲最大優先隊列和最小優先隊列
    在最大優先隊列中,無論入隊順序如何,當前最大的元素都會優先出隊,這是 基於最大堆實現的;
    在最小優先隊列中,無論入隊順序如何,當前最小的元素都會優先出隊,這是 基於最小堆實現的。
    ———————————————————————————————————————
    內容來源:《漫畫算法》
    關注公衆號,回覆 【算法】,獲取高清算法書!
    在這裏插入圖片描述
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章