国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【JAVA】優(yōu)先級(jí)隊(duì)列(堆)

這篇具有很好參考價(jià)值的文章主要介紹了【JAVA】優(yōu)先級(jí)隊(duì)列(堆)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。


優(yōu)先級(jí)隊(duì)列(堆)

羨慕別人就讓自己變得更好!

  1. 優(yōu)先級(jí)隊(duì)列(堆)可用于topK問題
  2. 有大小根堆
  3. 注意堆的模擬實(shí)現(xiàn)

堅(jiān)持真的很難但是真的很酷!

一、優(yōu)先級(jí)隊(duì)列

1. 概念

  1. 隊(duì)列是一種先進(jìn)先出(FIFO)的數(shù)據(jù)結(jié)構(gòu),但有些情況下,操作的數(shù)據(jù)可能帶有優(yōu)先級(jí),一般出隊(duì)列時(shí),可能需要優(yōu)先級(jí)高的元素先出隊(duì)列。
  2. 此時(shí),數(shù)據(jù)結(jié)構(gòu)應(yīng)該提供兩個(gè)最基本的操作,一個(gè)是返回最高優(yōu)先級(jí)對(duì)象,一個(gè)是添加新的對(duì)象。這種數(shù)據(jù)結(jié)構(gòu)就是優(yōu)先級(jí)隊(duì)列(Priority Queue)。
  3. 優(yōu)先級(jí)隊(duì)列實(shí)現(xiàn)了Queue接口。

二、優(yōu)先級(jí)隊(duì)列的模擬實(shí)現(xiàn)

JDK1.8中的PriorityQueue底層使用了堆的數(shù)據(jù)結(jié)構(gòu),而堆實(shí)際就是在完全二叉樹的基礎(chǔ)之上進(jìn)行了一些元素的調(diào)整。

1. 堆的概念

  1. 將根節(jié)點(diǎn)最大的堆叫做最大堆或大根堆,根節(jié)點(diǎn)最小的堆叫做最小堆或小根堆。
    (即: 大根堆:根結(jié)點(diǎn)值比左右子樹的值都大;
    小根堆:根結(jié)點(diǎn)值比左右子樹的值都小)
  2. 堆的性質(zhì):
  • 堆中某個(gè)節(jié)點(diǎn)的值總是不大于或不小于其父節(jié)點(diǎn)的值;(也就是有小大根堆之分)
  • 堆總是一棵完全二叉樹。

2. 堆的存儲(chǔ)方式

  1. 堆是一棵完全二叉樹,因此可以層序的規(guī)則采用順序的方式來高效存儲(chǔ)
  2. 注意:對(duì)于非完全二叉樹,則不適合使用順序方式進(jìn)行存儲(chǔ),因?yàn)闉榱四軌蜻€原二叉樹,空間中必須要存儲(chǔ)空節(jié)點(diǎn),就會(huì)導(dǎo)致空間利用率比較低。
  3. 也就是說:
    完全二叉樹適合使用數(shù)組進(jìn)行存儲(chǔ),層序遍歷; 一般二叉樹不適合順序方式進(jìn)行存儲(chǔ),浪費(fèi)存儲(chǔ)空節(jié)點(diǎn)的空間。
  4. 注意如何推導(dǎo)孩子結(jié)點(diǎn)以及父親結(jié)點(diǎn):

將元素存儲(chǔ)到數(shù)組中后,可以根據(jù)二叉樹的性質(zhì)對(duì)樹進(jìn)行還原。假設(shè)i為節(jié)點(diǎn)在數(shù)組中的下標(biāo),則有:

  • 如果i為0,則i表示的節(jié)點(diǎn)為根節(jié)點(diǎn),否則i節(jié)點(diǎn)的雙親節(jié)點(diǎn)為 (i - 1)/2
  • 如果2 * i + 1 小于節(jié)點(diǎn)個(gè)數(shù),則節(jié)點(diǎn)i的左孩子下標(biāo)為2 * i + 1,否則沒有左孩子
  • 如果2 * i + 2 小于節(jié)點(diǎn)個(gè)數(shù),則節(jié)點(diǎn)i的右孩子下標(biāo)為2 * i + 2,否則沒有右孩子

3. 堆的創(chuàng)建

1. 堆向下調(diào)整

  1. 【向下調(diào)整】:調(diào)整時(shí),找左右孩子中的最大值(最小值),然后與根結(jié)點(diǎn)進(jìn)行比較并交換就ok。調(diào)整都是從每棵子樹的根結(jié)點(diǎn)開始的。

  2. 問題:
    1)如何確定最后一顆子樹的根結(jié)點(diǎn)位置:
    (數(shù)組長度-1) 是最后一個(gè)結(jié)點(diǎn)位置,而根據(jù)子結(jié)點(diǎn)是可以確定父
    親節(jié)點(diǎn)的,即:(數(shù)組長度-1-1)/2
    2)如何確定下一顆子樹根結(jié)點(diǎn)的位置:當(dāng)前根結(jié)點(diǎn)-1(倒序)
    其實(shí)就是去寫每個(gè)子樹的調(diào)整即可。

  3. 在代碼實(shí)現(xiàn)時(shí),每棵子樹結(jié)束的位置是不一樣的,為啥直接寫個(gè)usedSize作為結(jié)束標(biāo)志?
    因?yàn)樽詈竺空n子樹的下標(biāo)其實(shí)都是>=usedSize的。

  4. 【向下調(diào)整】時(shí)間復(fù)雜度分析:(n為結(jié)點(diǎn)總數(shù))
    最壞的情況即從根一路比較到葉子,比較的次數(shù)為完全二叉樹的高度,即時(shí)間復(fù)雜度為java 優(yōu)先隊(duì)列,Note-數(shù)據(jù)結(jié)構(gòu),java,算法,數(shù)據(jù)結(jié)構(gòu),優(yōu)先級(jí)隊(duì)列,堆

  5. 注意:在調(diào)整以parent為根的二叉樹時(shí),必須要滿足parent的左子樹和右子樹已經(jīng)是堆了才可以向下調(diào)整。

2. 建堆

  1. 時(shí)間復(fù)雜度:
    最壞情況是滿二叉樹,(每層的節(jié)點(diǎn)個(gè)數(shù) * 該層移動(dòng)的層數(shù))之和,
    最后就類似于等差數(shù)列 * 等比數(shù)列求和–用q乘以數(shù)列再相減進(jìn)行計(jì)算
    (即:差比數(shù)列求和 用錯(cuò)位相減法)
    so:建堆的時(shí)間復(fù)雜度是:O(n)

  2. 注意:對(duì)于二叉樹而言
    總結(jié)點(diǎn)個(gè)數(shù)n= 2^層數(shù)h-1
    而每層節(jié)點(diǎn)個(gè)數(shù)最多:2^(層數(shù)h-1)

4. 堆的插入與刪除

1. 堆的插入

  1. 插入之后仍然要保證原來的大根堆(小根堆)不變:
    先插入到最后一棵子樹的空的孩子結(jié)點(diǎn)處(考慮是否需要擴(kuò)容),然后該節(jié)點(diǎn)直接與根結(jié)點(diǎn)進(jìn)行比較,根據(jù)大小堆關(guān)系必要時(shí)互換,一旦產(chǎn)生互換就進(jìn)行現(xiàn)在根節(jié)點(diǎn)與孩子節(jié)點(diǎn)的變換,不斷重復(fù),直至到達(dá)根結(jié)點(diǎn)。
  2. 注意每次交換父親節(jié)點(diǎn)與孩子節(jié)點(diǎn)值后后,child和parent都要發(fā)生變化??!
    什么時(shí)候停止循環(huán):child==0 or parent<0
  3. 注意:插入是插入到最后,然后再慢慢進(jìn)行【向上調(diào)整】!

2. 堆的刪除

  1. 刪除(出隊(duì)):出的是優(yōu)先級(jí)最高的元素;即:優(yōu)先級(jí)隊(duì)列的刪除只能刪除堆頂?shù)脑亍?/li>
  2. 堆頂元素與最后一個(gè)元素進(jìn)行交換,然后usedSize就–(此時(shí)隊(duì)列中有效長度范圍內(nèi)就不包含已經(jīng)交換至最后的堆頂元素了)
    此時(shí)只需要【向下調(diào)整】0下標(biāo)開始的子樹即可。

5. 用堆模擬實(shí)現(xiàn)優(yōu)先級(jí)隊(duì)列

// 優(yōu)先級(jí)隊(duì)列(堆)的模擬實(shí)現(xiàn)

import java.util.Arrays;

public class PriorityQueue {
    public int[] elem;
    public int usedSize;

    // 構(gòu)造方法:進(jìn)行變量初始化
    public PriorityQueue() {
        this.elem = new int[10];
        this.usedSize = 0; // 有效長度
    }

    // 初始化數(shù)組
    public void initArray(int[]arr) {
        this.elem = Arrays.copyOf(arr,arr.length); //將數(shù)組中元素拷貝給數(shù)組
        this.usedSize = this.elem.length;
    }

    /**
     * 建堆的時(shí)間復(fù)雜度:差比數(shù)列求和--O(N)
     * 注意:從最后一個(gè)根節(jié)點(diǎn)依次向上的根結(jié)點(diǎn)遍歷,以使得每棵子樹都是大堆形式--使用根結(jié)點(diǎn)循環(huán)
     * @param array
     */
    public void createHeap(int[] array) {
        // 注意:如果這里不傳參時(shí),usedSize就不用重新計(jì)算,直接使用initArray中已經(jīng)初始化好的就行;
        // 其實(shí),就算傳入數(shù)組參數(shù)也可以直接使用this.usedSize
        int usedSize = array.length;
        for (int parent=(usedSize-1)/2; parent>=0; parent--) {
            shiftDown(parent,usedSize);  // 注意結(jié)束條件是數(shù)組長度!
        }
    }

    /**
     * 向下調(diào)整(一次針對(duì)的是一棵子樹)--大根堆
     * 比較左右孩子結(jié)點(diǎn)大小,找到最大,然后與根結(jié)點(diǎn)進(jìn)行比較,若果根結(jié)點(diǎn)小就進(jìn)行交換--循環(huán)實(shí)現(xiàn)
     * @param root 是每棵子樹的根節(jié)點(diǎn)的下標(biāo)
     * @param len  是每棵子樹調(diào)整結(jié)束的結(jié)束條件
     * 向下調(diào)整的時(shí)間復(fù)雜度:O(logn)
     */
    private void shiftDown(int root,int len) {
        int child = 2*root+1; // 左孩子結(jié)點(diǎn)
        while(child < len) { // 進(jìn)入循環(huán)的條件其實(shí)是:好孩子結(jié)點(diǎn)要小于數(shù)組長度
            // 判斷左右孩子結(jié)點(diǎn)大?。?/span>
            if((child+1<len) && (elem[child]<elem[child+1])) {
                child++; // 赤裸裸的記錄最大孩子結(jié)點(diǎn)的下標(biāo)
            }
            // 來到這兒說明兩種情況:只有左孩子or左孩子小于右孩子--兩種情況都是child結(jié)點(diǎn)有最大值
            // 判斷最大子結(jié)點(diǎn)和父親節(jié)點(diǎn)的大小 -- 進(jìn)行交換swap
            if(elem[child] > elem[root]) {
                swap(elem,child,root);
                // child root變化
                root = child;
                child = 2*root+1;
            } else {
                // 說明是:父親節(jié)點(diǎn)大
                break;
            }
        }
    }

    private void swap(int[] elem, int child, int root) {
        int tmp = elem[child];
        elem[child] = elem[root];
        elem[root] = tmp;
    }


    /**
     * 入隊(duì)是先加在尾部 然后進(jìn)行向上調(diào)整
     * 入隊(duì):仍然要保持是大根堆
     * @param val
     */
    public void push(int val) {
        if(isFull()) {
            // 進(jìn)行擴(kuò)容
            this.elem = Arrays.copyOf(elem,2*elem.length);
        }
        // 要么擴(kuò)容成功,要么未滿 就開始進(jìn)行尾插
        this.elem[this.usedSize] = val;
        this.usedSize++; // 要注意++?。?/span>
        // 向上調(diào)整:
        shiftUp(this.usedSize-1); // 因?yàn)橹耙呀?jīng)usedSize++l,此時(shí)有效下標(biāo)需要--
    }

    // 向上調(diào)整:也是孩子結(jié)點(diǎn)與父親節(jié)點(diǎn)比較
    private void shiftUp(int child) {
        int parent = (child-1)/2;
        // 注意調(diào)整條件:child>0
        while(child>0) {
            // 直接與父親節(jié)點(diǎn)進(jìn)行比較就行,不需要再與另一個(gè)孩子結(jié)點(diǎn)進(jìn)行比較,因?yàn)槠渌呀?jīng)是有序的大根堆
            if(this.elem[parent] < this.elem[child]) {
                swap(this.elem,child,parent);
                // 注意交換后一定要進(jìn)行變量的變化
                child = parent;
                parent = (child-1)/2;
            } else {
                break;
            }
        }
    }

    public boolean isFull() {
        return this.usedSize==this.elem.length;
    }

    /**
     * 出隊(duì)【刪除】:每次刪除的都是優(yōu)先級(jí)高的元素!! 即:刪除的是堆頂元素!
     * 仍然要保持是大根堆
     * 把堆頂數(shù)據(jù)域最后一個(gè)數(shù)據(jù)進(jìn)行交換,然后進(jìn)行向下調(diào)整成大根堆
     */
    public void pollHeap() {
        if(isEmpty()) {
            return;
        }
        int old = this.elem[0];
        swap(this.elem,this.usedSize-1,0);
        this.usedSize--; // 此時(shí)有效數(shù)據(jù)中被換到最后的數(shù)據(jù)就不被包含在內(nèi)

        // 注意該方法其實(shí)是在<usdSize時(shí)進(jìn)行變換,所以不需要-1?。?!
        //shiftDown(0,this.usedSize-1); // 向下調(diào)整
        shiftDown(0,this.usedSize);
        System.out.println(old);
    }

    public boolean isEmpty() {
        return this.usedSize == 0;
    }

    /**
     * 獲取堆頂元素
     * @return
     */
    public int peekHeap() {
        return this.elem[0];
    }
}

6. 常見習(xí)題

  1. 下列關(guān)鍵字序列為堆的是:()

A: 100,60,70,50,32,65
B: 60,70,65,50,32,100
C: 65,100,70,32,50,60
D: 70,65,100,32,50,60
E: 32,50,100,70,65,60
F: 50,100,70,65,60,32

思路

此題沒有指明大小堆,那就都有可能; 但是該關(guān)鍵字系列其實(shí)是完全二叉樹層序遍歷的結(jié)果,所以其實(shí)是可以確定的。
然后該題需要復(fù)習(xí)大小根堆的定義。

  1. 已知小根堆為8,15,10,21,34,16,12,刪除關(guān)鍵字8之后需重建堆,在此過程中,關(guān)鍵字之間的比較次數(shù)是()

A: 1 B: 2 C: 3 D: 4

思路

小根堆:根節(jié)點(diǎn)比孩子節(jié)點(diǎn)??; 刪除關(guān)鍵字之后依舊要保持原來的小根堆不變。
注意:出隊(duì)出的是優(yōu)先級(jí)最高的堆頂元素,堆頂元素與最后一個(gè)元素交換,然后usedSize–,【向下調(diào)整:左右孩子節(jié)點(diǎn)的大小比較,孩子節(jié)點(diǎn)與父親節(jié)點(diǎn)的比較】
注意:大小堆的定義–根結(jié)點(diǎn)比左右子樹都大(?。?,但是左右子樹結(jié)點(diǎn)
大小沒關(guān)系

題解

12是最后一個(gè)節(jié)點(diǎn),12與8進(jìn)行交換,進(jìn)行【向下調(diào)整】:15與10比較(①),10更小,10與12進(jìn)行比較(②),10小,10與12進(jìn)行交換;16與12進(jìn)行比較(③),12小,不交換。

  1. 一組記錄排序碼為(5 11 7 2 3 17),則利用堆排序方法建立的初始堆為()

A: (11 5 7 2 3 17)
B: (11 5 7 2 17 3)
C: (17 11 7 2 3 5)
D: (17 11 7 5 3 2)
E: (17 7 11 3 5 2)
F: (17 7 11 3 2 5)

思路
堆排序方法:
(根節(jié)點(diǎn)與最后一個(gè)節(jié)點(diǎn)交換,向下調(diào)整;重復(fù)這兩個(gè)步驟 最后一個(gè)節(jié)點(diǎn)不斷往前推進(jìn))

public void heapSort() {
        int end = this.usedSize-1;
        // 循環(huán)變換
        while(end>0) {
            // 進(jìn)行交換
            swap(this.array,0,end);
            // 先進(jìn)行【向下調(diào)整】,需要到end,因?yàn)楸容^時(shí)本來就不包含邊界,所以先不進(jìn)行—-
            shiftDown(0,end);
            end--;
        }
    }

題解

根節(jié)點(diǎn)與最后一個(gè)節(jié)點(diǎn)交換一下就行。
寫題時(shí),堆排序默認(rèn)是升序的(即:大根堆),如果不行再使用降序來做

  1. 最小堆[0,3,2,5,7,4,6,8],在刪除堆頂元素0之后,其結(jié)果是()

A: [3,2,5,7,4,6,8]
B: [2,3,5,7,4,6,8]
C: [2,3,4,5,7,8,6]
D: [2,3,4,5,6,7,8]

思路

刪除(出隊(duì)):只能是堆頂元素,堆頂元素與最后一個(gè)元素交換,usedSize–,然后比較左右子結(jié)點(diǎn)的大小,然后拿最小值與根結(jié)點(diǎn)進(jìn)行比較與交換,重復(fù)每棵子樹即可。

答案

1.A
2.C
3.C
4.C


三、 常用接口介紹

1. PriorityQueue的特性

  1. Java集合框架中提供了PriorityQueue和PriorityBlockingQueue兩種類型的優(yōu)先級(jí)隊(duì)列,PriorityQueue是線程不安全的,PriorityBlockingQueue是線程安全的。本文重點(diǎn)是PriorityQueue。
  2. PriorityQueue的底層默認(rèn)是小根堆!
  3. 接口關(guān)系圖:
    java 優(yōu)先隊(duì)列,Note-數(shù)據(jù)結(jié)構(gòu),java,算法,數(shù)據(jù)結(jié)構(gòu),優(yōu)先級(jí)隊(duì)列,堆
  4. 關(guān)于PriorityQueue的使用要注意
    1)使用時(shí)必須導(dǎo)入PriorityQueue所在的包,即:
import java.util.PriorityQueue;

2) PriorityQueue中放置的元素必須要能夠比較大小,不能插入無法比較大小的對(duì)象,否則會(huì)拋出ClassCastException異常
3) 不能插入null對(duì)象,否則會(huì)拋出NullPointerException
4) 沒有容量限制,可以插入任意多個(gè)元素,其內(nèi)部可以自動(dòng)擴(kuò)容
5) 插入和刪除元素的時(shí)間復(fù)雜度為:O(logN)
6) PriorityQueue底層使用了堆數(shù)據(jù)結(jié)構(gòu)
7) PriorityQueue默認(rèn)情況下是小堆—即每次獲取到的元素都是最小的元素

2. PriorityQueue常用接口介紹

  1. 此處列出了PriorityQueue中常見的幾種構(gòu)造方式:
    java 優(yōu)先隊(duì)列,Note-數(shù)據(jù)結(jié)構(gòu),java,算法,數(shù)據(jù)結(jié)構(gòu),優(yōu)先級(jí)隊(duì)列,堆
  2. 注意:默認(rèn)情況下,PriorityQueue隊(duì)列是小堆,如果需要大堆需要用戶提供比較器。
    用戶自己定義的比較器:直接實(shí)現(xiàn)Comparator接口,然后重寫該接口中的compare方法即可;或者實(shí)現(xiàn)Comparable接口,重寫compareTo方法。
  3. 插入/刪除/獲取優(yōu)先級(jí)最高的元素:
    java 優(yōu)先隊(duì)列,Note-數(shù)據(jù)結(jié)構(gòu),java,算法,數(shù)據(jù)結(jié)構(gòu),優(yōu)先級(jí)隊(duì)列,堆
  4. 在JDK 1.8中,PriorityQueue的擴(kuò)容方式:

如果容量小于64時(shí),是按照oldCapacity的2倍方式擴(kuò)容的
如果容量大于等于64,是按照oldCapacity的1.5倍方式擴(kuò)容的
如果容量超過MAX_ARRAY_SIZE,按照MAX_ARRAY_SIZE來進(jìn)行擴(kuò)容

  1. 小結(jié):

1) java的優(yōu)先級(jí)隊(duì)列底層數(shù)組默認(rèn)大小是11
2) 當(dāng)對(duì)優(yōu)先級(jí)隊(duì)列指定大小的時(shí)候,不要給<=0的容量,一定要>1,否則會(huì)拋出異常。
3) 比較器Comparator是需要自己傳入的,不傳入就會(huì)默認(rèn)這個(gè)變量是可比較的;默認(rèn)實(shí)現(xiàn)的是Comparable接口。
4) 當(dāng)使用比較器Comparator的對(duì)象作為參數(shù)傳入時(shí),不管走的哪個(gè)方法,數(shù)組的容量都是被賦予的。
5) offer是如何維護(hù)的?如何保證小根堆的呢?
其實(shí)就是在重寫compare方法(Compara比較器)時(shí),如果o1-o2就是默認(rèn)的小堆,o2-o1則是大堆;因?yàn)橐坏﹥蓚€(gè)相減<0就進(jìn)行就進(jìn)行交換。
(o1就是當(dāng)前傳入的對(duì)象?。。?mark hidden color="red">文章來源:http://www.zghlxwxcb.cn/news/detail-614275.html


四、堆的應(yīng)用

1. PriorityQueue的模擬實(shí)現(xiàn)

用堆作為底層結(jié)構(gòu)封裝優(yōu)先級(jí)隊(duì)列。文章來源地址http://www.zghlxwxcb.cn/news/detail-614275.html

2. 堆排序

  1. 在原數(shù)組本身上進(jìn)行堆排序:
    從小到大排序建立大根堆:
    堆頂元素與最后一個(gè)結(jié)點(diǎn)進(jìn)行交換,然后進(jìn)行【向下】調(diào)整(左右孩子最大值,然后與堆頂元素進(jìn)行交換);不斷重復(fù)
    即:每次讓0下標(biāo)的值與end下標(biāo)的值進(jìn)行交換,【向下調(diào)整】調(diào)整;當(dāng)end==0就結(jié)束
  2. 大小根堆的堆排序方法都一樣,交換+【向下調(diào)整】
  3. 源代碼在習(xí)題中
  4. 寫題時(shí),堆排序默認(rèn)是升序的(即:大根堆),如果不行再使用降序來做

3.topK問題

  1. top-k應(yīng)用:求前k個(gè)最大(建小根堆)/最小、求第k大(建小根堆–堆頂元素)/小。
  2. top-k問題:
    假設(shè):100個(gè)數(shù)據(jù)中,找前k個(gè)最大(最?。?/li>
  3. 方法一:將數(shù)據(jù)放入大根堆(小根堆)中–堆頂元素就是max(min),然后出k次–每出一次都會(huì)進(jìn)行調(diào)整成大小根堆
    (注意在建優(yōu)先級(jí)隊(duì)列時(shí)直接傳入比較器Comparator)和重寫compare方法)
    缺陷:如果堆較大的話,時(shí)間復(fù)雜度會(huì)較高:O(N*log2N)
  4. 優(yōu)化方法:如果是找前k個(gè)最大
    先建立一個(gè)k大小的小根堆(注意是小根堆)來存儲(chǔ)數(shù)組的前k個(gè)元素,然后從k下標(biāo)開始依次遍歷,與堆頂元素進(jìn)行比較,如果堆頂元素<當(dāng)前元素,那么堆頂元素一定不是所要找的前k個(gè)最大之一,所以將堆頂元素進(jìn)行出堆poll(堆頂元素與最后一個(gè)元素互換),然后調(diào)整成小根堆,再將當(dāng)前元素放置最后一個(gè)元素位置,再調(diào)整小根堆offer。循環(huán)遍歷。
    時(shí)間復(fù)雜度:O(N*log2K) (N是結(jié)點(diǎn)個(gè)數(shù),K是前K個(gè))
  5. 代碼:(以 找前k個(gè)最大值為例)
// 方法一:放入相同堆中,出k次
    public void topK1(int[] arr,int k) {
        if(k==0) {
            return;
        }
        // 注意傳入比較器
        PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2-o1; // 大根堆
            }
        });
        // 放入堆中
        for (int i = 0; i < arr.length; i++) {
            priorityQueue.offer(arr[i]);
        }
        // 出k次
        for (int i = 0; i < k; i++) {
            System.out.print(priorityQueue.poll() + " ");
        }
    }

    // 方法二:k大小的相反堆 + 遍歷比較出堆
    public int[] topK2(int[] arr, int k) {
    // 建立一個(gè)數(shù)組用于存儲(chǔ)所找的前k個(gè)元素
        int[] ret = new int[k];
        if (k==0) {
            return ret;
        }
        // 同樣傳入比較器:但是此時(shí)找小根堆
        PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(k,new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1-o2; // 小根堆
            }
        });
        // 建立k大小的小根堆(數(shù)組元素進(jìn)行存入)
        for (int i = 0; i < arr.length; i++) {
            if(priorityQueue.size()<k) {
                priorityQueue.offer(arr[i]);
            } else {
                // 說明已經(jīng)建好了k堆,要進(jìn)行比較變換
                // 獲取棧頂元素
                int top = priorityQueue.peek();
                // 棧頂元素與數(shù)組遍歷的i下標(biāo)的元素去比較大小
                // 找前k個(gè)最大的
                if(arr[i] > top) {
                    // 要是新元素大,則說明堆頂元素不包含在內(nèi)
                    priorityQueue.poll();
                    priorityQueue.offer(arr[i]);
                }
            }
        }
        // 然后進(jìn)行出k個(gè)元素:
        for (int i = 0; i < k; i++) {
            int val = priorityQueue.poll();
            ret[i] = val;
        }
        return ret;
    }

總結(jié)

  1. 優(yōu)先級(jí)隊(duì)列:底層是堆(完全二叉樹的層序遍歷)
  2. 優(yōu)先級(jí)隊(duì)列模擬實(shí)現(xiàn)
  3. 優(yōu)先級(jí)隊(duì)列常用方法
  4. 優(yōu)先級(jí)隊(duì)列應(yīng)用:堆排序、topK問題等。

到了這里,關(guān)于【JAVA】優(yōu)先級(jí)隊(duì)列(堆)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 數(shù)據(jù)結(jié)構(gòu)與算法-優(yōu)先級(jí)隊(duì)列

    Gitee上開源的數(shù)據(jù)結(jié)構(gòu)與算法代碼庫:數(shù)據(jù)結(jié)構(gòu)與算法Gitee代碼庫 優(yōu)先級(jí)隊(duì)列,按照優(yōu)先級(jí)別依次輸出 計(jì)算機(jī)科學(xué)中,堆是一種基于樹的數(shù)據(jù)結(jié)構(gòu),通常用 完全二叉樹 實(shí)現(xiàn)。堆的特性如下 在大頂堆中,任意節(jié)點(diǎn) C 與它的父節(jié)點(diǎn) P 符合 P . v a l u e ≥ C . v a l u e P.value geq C.val

    2024年02月13日
    瀏覽(36)
  • 數(shù)據(jù)結(jié)構(gòu) 之 優(yōu)先級(jí)隊(duì)列(堆) (PriorityQueue)

    數(shù)據(jù)結(jié)構(gòu) 之 優(yōu)先級(jí)隊(duì)列(堆) (PriorityQueue)

    ??歡迎大家觀看AUGENSTERN_dc的文章(o゜▽゜)o☆?? ??感謝各位讀者在百忙之中抽出時(shí)間來垂閱我的文章,我會(huì)盡我所能向的大家分享我的知識(shí)和經(jīng)驗(yàn)?? ??希望我們在一篇篇的文章中能夠共同進(jìn)步?。?! ??個(gè)人主頁:AUGENSTERN_dc ??個(gè)人專欄:C語言?|?Java | 數(shù)據(jù)結(jié)構(gòu) ?個(gè)人

    2024年03月20日
    瀏覽(27)
  • 數(shù)據(jù)結(jié)構(gòu)之優(yōu)先級(jí)隊(duì)列【堆】(Heap)

    數(shù)據(jù)結(jié)構(gòu)之優(yōu)先級(jí)隊(duì)列【堆】(Heap)

    目錄 1. 優(yōu)先級(jí)隊(duì)列(Priority Queue) 2.堆的概念 3.堆的存儲(chǔ)方式 4.堆的創(chuàng)建 5.用堆模擬實(shí)現(xiàn)優(yōu)先級(jí)隊(duì)列 ?6.PriorityQueue常用接口介紹 6.1?PriorityQueue的特點(diǎn) 6.2?PriorityQueue幾種常見的構(gòu)造方式 7.top-k問題 8.堆排序 本篇主要內(nèi)容總結(jié) (1)優(yōu)先級(jí)隊(duì)列底層是堆來實(shí)現(xiàn)的 (2)堆的本質(zhì)是

    2024年02月01日
    瀏覽(52)
  • 【數(shù)據(jù)結(jié)構(gòu)與算法】03 隊(duì)列(順序隊(duì)列--循環(huán)隊(duì)列--優(yōu)先級(jí)隊(duì)列--鏈隊(duì)列)

    【數(shù)據(jù)結(jié)構(gòu)與算法】03 隊(duì)列(順序隊(duì)列--循環(huán)隊(duì)列--優(yōu)先級(jí)隊(duì)列--鏈隊(duì)列)

    隊(duì)列( queue )是一種常見的數(shù)據(jù)結(jié)構(gòu),它遵循先進(jìn)先出(FIFO)的原則。隊(duì)列可以理解為一個(gè)具有兩個(gè)端點(diǎn)的線性數(shù)據(jù)結(jié)構(gòu),其中一個(gè)端點(diǎn)稱為\\\"隊(duì)尾\\\"(rear),用于插入新元素,另一個(gè)端點(diǎn)稱為\\\"隊(duì)首\\\"(front),用于移除元素。新元素被插入到隊(duì)尾,而最早插入的元素總是在隊(duì)

    2024年02月08日
    瀏覽(21)
  • 【一起學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)與算法】優(yōu)先級(jí)隊(duì)列(堆)

    【一起學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)與算法】優(yōu)先級(jí)隊(duì)列(堆)

    如果我們給每個(gè)元素都分配一個(gè)數(shù)字來標(biāo)記其優(yōu)先級(jí),不妨設(shè)較小的數(shù)字具有較高的優(yōu)先級(jí),這樣我們就可以在一個(gè)集合中訪問優(yōu)先級(jí)最高的元素并對(duì)其進(jìn)行查找和刪除操作了。這樣,我們就引入了 優(yōu)先級(jí)隊(duì)列 這種數(shù)據(jù)結(jié)構(gòu)。 優(yōu)先級(jí)隊(duì)列(priority queue) 是0個(gè)或多個(gè)元素的集

    2024年01月19日
    瀏覽(24)
  • 【數(shù)據(jù)結(jié)構(gòu)】 優(yōu)先級(jí)隊(duì)列(堆)與堆的建立

    【數(shù)據(jù)結(jié)構(gòu)】 優(yōu)先級(jí)隊(duì)列(堆)與堆的建立

    前面介紹過隊(duì)列, 隊(duì)列是一種先進(jìn)先出(FIFO)的數(shù)據(jù)結(jié)構(gòu) ,但有些情況下,操作的數(shù)據(jù)可能帶有優(yōu)先級(jí),一般出隊(duì)列時(shí),可能需要優(yōu)先級(jí)高的元素先出隊(duì)列,該中場景下,使用隊(duì)列顯然不合適。 比如:在手機(jī)上玩游戲的時(shí)候,如果有來電,那么系統(tǒng)應(yīng)該優(yōu)先處理打進(jìn)來的電話

    2024年02月10日
    瀏覽(19)
  • 數(shù)據(jù)結(jié)構(gòu) - 6(優(yōu)先級(jí)隊(duì)列(堆)13000字詳解)

    數(shù)據(jù)結(jié)構(gòu) - 6(優(yōu)先級(jí)隊(duì)列(堆)13000字詳解)

    堆分為兩種:大堆和小堆。它們之間的區(qū)別在于元素在堆中的排列順序和訪問方式。 大堆(Max Heap): 在大堆中,父節(jié)點(diǎn)的值比它的子節(jié)點(diǎn)的值要大。也就是說,堆的根節(jié)點(diǎn)是堆中最大的元素。大堆被用于實(shí)現(xiàn)優(yōu)先級(jí)隊(duì)列,其中根節(jié)點(diǎn)的元素始終是隊(duì)列中最大的元素。 大堆

    2024年02月08日
    瀏覽(25)
  • Java優(yōu)先級(jí)隊(duì)列-堆

    大家好,我是曉星航。今天為大家?guī)淼氖?Java優(yōu)先級(jí)隊(duì)列(堆) 的講解!?? 使用數(shù)組保存二叉樹結(jié)構(gòu),方式即將二叉樹用 層序遍歷 方式放入數(shù)組中。 一般只適合表示完全二叉樹,因?yàn)榉峭耆鏄鋾?huì)有空間的浪費(fèi)。 這種方式的主要用法就是堆的表示。 已知雙親(parent)的下

    2023年04月16日
    瀏覽(21)
  • 【JAVA】優(yōu)先級(jí)隊(duì)列(堆)

    【JAVA】優(yōu)先級(jí)隊(duì)列(堆)

    羨慕別人就讓自己變得更好! 優(yōu)先級(jí)隊(duì)列(堆)可用于topK問題 有大小根堆 注意堆的模擬實(shí)現(xiàn) 堅(jiān)持真的很難但是真的很酷! 隊(duì)列是一種先進(jìn)先出(FIFO)的數(shù)據(jù)結(jié)構(gòu),但有些情況下,操作的數(shù)據(jù)可能帶有優(yōu)先級(jí),一般出隊(duì)列時(shí),可能需要優(yōu)先級(jí)高的元素先出隊(duì)列。 此時(shí),數(shù)據(jù)結(jié)

    2024年02月15日
    瀏覽(22)
  • 【Java】PriorityQueue--優(yōu)先級(jí)隊(duì)列

    【Java】PriorityQueue--優(yōu)先級(jí)隊(duì)列

    目錄 ?一、優(yōu)先級(jí)隊(duì)列? (1)概念 二、優(yōu)先級(jí)隊(duì)列的模擬實(shí)現(xiàn) (1)堆的概念? (2)堆的存儲(chǔ)方式 ? (3)堆的創(chuàng)建 堆向下調(diào)整 (4)堆的插入與刪除 堆的插入 ?堆的刪除 三、常用接口介紹 1、PriorityQueue的特性 2、PriorityQueue常用接口介紹 ? (1)優(yōu)先級(jí)隊(duì)列的構(gòu)造 (2)插入

    2024年02月11日
    瀏覽(21)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包