《算法》2.4-優(yōu)先隊(duì)列

1. 基本概念

比如:輸入N個字符串吭狡,我們需要找打最大的M個字符串宅倒。我們可以將N個字符串進(jìn)行排序攘宙,然后取最大的M個。也可以將新的輸入和已知的M個最大字符串進(jìn)行比較戚揭。只要我們用優(yōu)先隊(duì)列能高效的實(shí)現(xiàn)insert()和delMin()就能解決該問題窗宇。


API
public class TopM {   

    // This class should not be instantiated.
    private TopM() { }

    /**
     *  Reads a sequence of transactions from standard input; takes a
     *  command-line integer m; prints to standard output the m largest
     *  transactions in descending order.
     *
     * @param args the command-line arguments
     */
    public static void main(String[] args) {
        int m = Integer.parseInt(args[0]); 
        MinPQ<Transaction> pq = new MinPQ<Transaction>(m+1);

        while (StdIn.hasNextLine()) {
            // Create an entry from the next line and put on the PQ. 
            String line = StdIn.readLine();
            Transaction transaction = new Transaction(line);
            pq.insert(transaction); 

            // remove minimum if m+1 entries on the PQ
            if (pq.size() > m) 
                pq.delMin();
        }   // top m entries are on the PQ

        // print entries on PQ in reverse order
        Stack<Transaction> stack = new Stack<Transaction>();
        for (Transaction transaction : pq)
            stack.push(transaction);
        for (Transaction transaction : stack)
            StdOut.println(transaction);
    } 
} 

2. 堆的定義

定義:當(dāng)一顆二叉樹的每個結(jié)點(diǎn)都大于等于它的兩個子結(jié)點(diǎn)時炉媒,它被稱為堆有序。根節(jié)點(diǎn)是堆有序的二叉樹中的最大結(jié)點(diǎn)铺韧。
堆的表示:
①按照樹的層級結(jié)構(gòu)來存儲
②不使用數(shù)組中的第一個位置。
③一顆大小為N的完全二叉樹的高度為lgN向下取整缓淹。當(dāng)N的數(shù)量達(dá)到2的整數(shù)次冪時樹的高度加1
④位置k的結(jié)點(diǎn)的父節(jié)點(diǎn)是? k/2? 哈打,子節(jié)點(diǎn)分別為2k或2k+1


堆的表示

高度=? lg 11 ? 向下取整=3

3. 堆的算法

我們用長度為N+1的pq[]來表示一個大小為N的堆,不使用pq[0]讯壶。

由下至上的堆有序化(上噶险獭)
某個結(jié)點(diǎn)比自己的父結(jié)點(diǎn)更大,交換它和它的父節(jié)點(diǎn)伏蚊,直到滿足堆有序立轧。

private void swim(int k) {
        while (k > 1 && less(k/2, k)) {
            exch(k, k/2);
            k = k/2;
        }
    }

上浮

由上至下的堆有序化(下沉)
某個結(jié)點(diǎn)比它的兩個子結(jié)點(diǎn)或是其中之一要小,將它與兩個子節(jié)點(diǎn)中較大的值進(jìn)行交換躏吊,直到保證堆有序氛改。

 private void sink(int k) {
        while (2*k <= n) {
            int j = 2*k;
            if (j < n && less(j, j+1)) j++;
            if (!less(k, j)) break;
            exch(k, j);
            k = j;
        }
    }

下沉

插入元素
將新的元素添加到數(shù)組末尾,增加堆的大小比伏,不斷上浮

插入元素

刪除最大的元素
從數(shù)組頂端刪除最大的元素胜卤,并將數(shù)組的最后一個元素放到頂端,減小堆的大小凳怨,并讓這個元素下沉到合適的位置瑰艘。
刪除最大的元素

基于堆的優(yōu)先隊(duì)列

public class MaxPQ<Key extends Comparable<Key>>
{
    private Key[] pq; // heap-ordered complete binary tree
    private int N = 0; // in pq[1..N] with pq[0] unused
    public MaxPQ(int maxN)
    { pq = (Key[]) new Comparable[maxN+1]; }
    public boolean isEmpty()
    { return N == 0; }
    public int size()
    { return N; }
    public void insert(Key v)
    {
        pq[++N] = v;
        swim(N);
    }
    public Key delMax()
    {
        Key max = pq[1]; // Retrieve max key from top.
        exch(1, N--); // Exchange with last item.
        pq[N+1] = null; // Avoid loitering.
        sink(1); // Restore heap property.
        return max;
    }
    // See pages 145-147 for implementations of these helper methods.
    private boolean less(int i, int j)
    private void exch(int i, int j)
    private void swim(int k)
    private void sink(int k)
}

⑥性能分析
長度為N的基于堆的優(yōu)先隊(duì)列,插入元素操作只需要不超過lgN+1次比較肤舞,刪除最大元素操作紫新,不超過2lgN次比較(確定是否上浮和確定子結(jié)點(diǎn)中的最大值)。

4. 索引優(yōu)先隊(duì)列

可以當(dāng)做:能夠快速訪問其中最小元素的數(shù)組李剖。you can think of an IndexMinPQ named pq as representing a subset of an array pq[0..N-1] of items. Think of the call pq.insert(k, item) as adding k to the subset and setting pq[k] = item and the call pq.change(k, item) as setting pq[k] = item芒率。
問題:多個有序的輸入流如何歸并成一個有序的輸出流?

public class Multiway { 

    // This class should not be instantiated.
    private Multiway() { }

    // merge together the sorted input streams and write the sorted result to standard output
    private static void merge(In[] streams) {
        int n = streams.length;
        IndexMinPQ<String> pq = new IndexMinPQ<String>(n);
        for (int i = 0; i < n; i++)
            if (!streams[i].isEmpty())
                pq.insert(i, streams[i].readString());

        // Extract and print min and read next from its stream. 
        while (!pq.isEmpty()) {
            StdOut.print(pq.minKey() + " ");
            int i = pq.delMin();
            if (!streams[i].isEmpty())
                pq.insert(i, streams[i].readString());
        }
        StdOut.println();
    }
public static void main(String[] args) {
        int n = args.length;
        In[] streams = new In[n];
        for (int i = 0; i < n; i++)
            streams[i] = new In(args[i]);
        merge(streams);
    }

命令行:java Multiway m1.txt m2.txt m3.txt
A A B B B C D E F F G H I I J N P Q Q Z
% more m1.txt
A B C F G I I Z
% more m2.txt
B D H P Q Q
% more m3.txt
A B E F J N

關(guān)鍵:將多路輸入和索引相關(guān)連篙顺,每次都從刪除最小的元素的輸入流中繼續(xù)添加元素偶芍。

5. 堆排序

堆的構(gòu)造
方法1:構(gòu)造N個元素的堆充择,從左至右依次將每個元素添加至數(shù)組的末尾,然后不斷的上浮匪蟀,直到將N個元素都添加至堆中椎麦。NlgN
方法2:從右至左不斷下沉構(gòu)造堆。
**利用下沉操作構(gòu)建堆只需要2N比較和N交換材彪。

i堆排序

將堆中最大元素刪除观挎,然后放入堆縮小后數(shù)組中空出的位置

 public static void sort(Comparable[] pq) {
        int n = pq.length;
        for (int k = n/2; k >= 1; k--)
            sink(pq, k, n);
        while (n > 1) {
            exch(pq, 1, n--);
            sink(pq, 1, n);
        }
    }

分析
將N個元素排序,堆排序只需要少于2NlgN+2N次比較段化,以及一半的交換次數(shù)嘁捷。2N來自于堆的構(gòu)建,2NlgN來自于每次下沉操作最大可能次數(shù)显熏。
堆排序是唯一可以同時利用空間和時間的方法雄嚣,但是許多應(yīng)用中很少使用它,原因是堆排序沒有利用緩存喘蟆,數(shù)組元素很少和相鄰的其他元素進(jìn)行比較缓升,因此緩存未命中的次數(shù)遠(yuǎn)遠(yuǎn)高于其它的算法(快速、歸并履肃、甚至希爾)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末仔沿,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子尺棋,更是在濱河造成了極大的恐慌封锉,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件膘螟,死亡現(xiàn)場離奇詭異成福,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)荆残,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進(jìn)店門奴艾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人内斯,你說我怎么就攤上這事蕴潦。” “怎么了俘闯?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵潭苞,是天一觀的道長。 經(jīng)常有香客問我真朗,道長此疹,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮蝗碎,結(jié)果婚禮上湖笨,老公的妹妹穿的比我還像新娘。我一直安慰自己蹦骑,他們只是感情好慈省,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著脊串,像睡著了一般辫呻。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上琼锋,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天,我揣著相機(jī)與錄音祟昭,去河邊找鬼缕坎。 笑死,一個胖子當(dāng)著我的面吹牛篡悟,可吹牛的內(nèi)容都是我干的谜叹。 我是一名探鬼主播,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼搬葬,長吁一口氣:“原來是場噩夢啊……” “哼荷腊!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起急凰,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤女仰,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后抡锈,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體疾忍,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年床三,在試婚紗的時候發(fā)現(xiàn)自己被綠了一罩。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡撇簿,死狀恐怖聂渊,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情四瘫,我是刑警寧澤汉嗽,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站莲组,受9級特大地震影響诊胞,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一撵孤、第九天 我趴在偏房一處隱蔽的房頂上張望迈着。 院中可真熱鬧,春花似錦邪码、人聲如沸裕菠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽奴潘。三九已至,卻和暖如春影钉,著一層夾襖步出監(jiān)牢的瞬間画髓,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工平委, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留奈虾,地道東北人。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓廉赔,卻偏偏與公主長得像肉微,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子蜡塌,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 數(shù)據(jù)結(jié)構(gòu)與算法--優(yōu)先隊(duì)列和堆排序 在某些數(shù)據(jù)處理的例子中碉纳,總數(shù)據(jù)量太大,無法排序(甚至無法全部裝進(jìn)內(nèi)存)馏艾。例如劳曹,...
    sunhaiyu閱讀 1,041評論 0 2
  • 概述 排序有內(nèi)部排序和外部排序,內(nèi)部排序是數(shù)據(jù)記錄在內(nèi)存中進(jìn)行排序攒至,而外部排序是因排序的數(shù)據(jù)很大厚者,一次不能容納全部...
    蟻前閱讀 5,186評論 0 52
  • 概述:排序有內(nèi)部排序和外部排序,內(nèi)部排序是數(shù)據(jù)記錄在內(nèi)存中進(jìn)行排序迫吐,而外部排序是因排序的數(shù)據(jù)很大库菲,一次不能容納全部...
    每天刷兩次牙閱讀 3,732評論 0 15
  • 1.插入排序—直接插入排序(Straight Insertion Sort) 基本思想: 將一個記錄插入到已排序好...
    依依玖玥閱讀 1,258評論 0 2
  • 概述排序有內(nèi)部排序和外部排序,內(nèi)部排序是數(shù)據(jù)記錄在內(nèi)存中進(jìn)行排序志膀,而外部排序是因排序的數(shù)據(jù)很大熙宇,一次不能容納全部的...
    Luc_閱讀 2,275評論 0 35