algorithm-4th 排序-优先队列

PriorityQueue是一种抽象数据类型,它表示了一组值和对这些值的操作,支持两种操作:删除最大元素和插入元素。它的适用场景可能是金融事务,你需要从中找出最大的那些;或是农产品中的杀虫剂含量,这时你需要从
中找出最小的那些, 等等

java 版的 MaxPQ 模板

public class MaxPQ <Key extends Comparable<Key>> {
    MaxPQ(Key[] a)       用 a[] 中的元素创建一个优先队列
    void insert(Key v)   向优先队列中插入一个元素
    Key max()            返回最大元素
    Key delMax()         删除并返回最大元素
    boolean isEmpty()    返回队列是否为空
    int size()           返回优先队列中的元素个数
}

使用二叉堆实现优先队列

二叉堆定义

二叉堆是一组能够用堆有序的完全二叉树排序的元素,并在数组中按照层级储存(不使
用数组的第一个位置)

在一个堆中,位置 k 的结点的父结点的位置为k/2,而它的两个子结点的位置则分别为 2k 和 2k+1。在排序算法中,我们只通过私有辅助函数 less() 和 exch() 来访问元素

堆.png

用它们我们将能实现对数级别的插入元素和删除最大元素的操作。利用在数组中无需指针即可沿树上下移动的便利和以下性质,算法保证了对数复杂度的性能。

堆的表示.png

堆的算法

我们用长度为 N+1 的私有数组 pq[] 来表示一个大小为 N 的堆,我们不会使 用 pq[0], 堆 元 素 放 在 pq[1] 至pq[N] 中。

由下至上的堆有序化(上浮 swim)

swim.png

由上至下的堆有序化(下沉 sink)

sink.png

堆的操作

插入元素: 我们将新元素加到数组末尾,增加堆的大小并让这个新元素上浮到合适的位置

删除最大元素: 我们从数组顶端删去最大的元素并将数组的最后一个元素放到顶端,减小堆的大小并让这个元素下沉到合适的位置

堆的操作.png

实现

public class MaxPQ<Key extends Comparable<Key>> { 
     private Key[] pq; // 基于堆的完全二叉树
     private int N = 0; // 存储于pq[1..N]中,pq[0]没有使用
     
     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];  // 从根结点得到最大元素
         exch(1, N--);     // 将其和最后一个结点交换
         pq[N+1] = null;   // 防止对象游离
         sink(1);          // 恢复堆的有序性
         return max; 
     }
     
     private void swim(int k) {
         while (k > 1 && less(k/2, k)) { 
             exch(k/2, k); 
             k = k/2;  // java 中向下取整
         }
     }
     
     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; 
         }
     }
     
    private boolean less(int i, int j) { 
        return pq[i].compareTo(pq[j]) < 0; 
    }
     
    private void exch(int i, int j) { 
        Key t = pq[i]; 
        pq[i] = pq[j]; 
        pq[j] = t; 
    }
 
}

堆排序

public static void sort(Comparable[] a) { 
    int N = a.length; 
    
    for (int k = N/2; k >= 1; k--) { // for 循环构造了堆
        sink(a, k, N); 
    }
 
    while (N > 1) { // while 循环将最大的元素 a[1] 和 a[N] 交换并修复了堆,如此重复直到堆变空。
       exch(a, 1, N--); 
       sink(a, 1, N); 
    } 
}
堆的构造和下沉排序.png

小结

堆排序在排序复杂性的研究中有着重要的地位,因为它是我们所知的唯一能够同时最优地利用空间和时间的方法——在最坏的情况下它也能保证使用~ 2NlgN 次比较和恒定的额外空间。

当空间十分紧张的时候(例如在嵌入式系统或低成本的移动设备中)它很流行,因为它只用几行就能实现(甚至机器码也是)较好的性能。但现代系统的许多应用很少使用它,因为它无法利用缓存。数组元素很少和相邻的其他元素进行比较,因此缓存未命中的次数要远远高于大多数比较都在相邻元素间进行的算法,如快速排序、归并排序,甚至是希尔排序。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,539评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,911评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,337评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,723评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,795评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,762评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,742评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,508评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,954评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,247评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,404评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,104评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,736评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,352评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,557评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,371评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,292评论 2 352

推荐阅读更多精彩内容