数据结构:优先队列

优先队列(Java版)

引入优先队列

说明: 

    优先队列是一种抽象数据类型,它是一种排序的机制,它有两个核心操作:找出键值最大(优先级最高)的元素、插入新的元素,效果就是他在维护一个动态的队列

  可以收集一些元素,并快速取出键值最大的元素,对其操作后移出队列,然后再收集更多的元素,再处理当前键值最大的元素,如此这般。

  比如我们有一台能够运行多个程序的计算机。计算机通过给每个应用一个优先级属性,将应用根据优先级进行排列,计算机总是处理下一个优先级最高的元素。 

泛型优先队列的API

  优先队列最重要的操作是删除最大元素和插入元素。

  

优先队列的初级实现

  数组实现(无序)

  ?思想:
    我们维护一个数组,因为不考虑数组顺序,所以我们的插入算法就很简单了。
    对于查找最大值,我们利用了选择排序,在找到最大值后,将其与最后一个元素交换,并使长度-1.
  ? 只给出最简单核心实现步骤:

 package queueDemo;
    public class QueueANO<T extends Comparable<T>> {
        private T[] array;
        private int n; 

        public QueueANO(int capacity)
        {
            array=(T[]) new Comparable[capacity];
            n=0;
        }
        ........
        public void insert(T t)
        {
            array[n]=t;n++;
        }
        public T delMax()
        {
            int max=0;
            for(int i=1;i<n;i++) //找出最大元素
            {
                if(less(max,i))
                    max=i;
            }
            exch(max,n-1);        //将最大元素交换到最后
            n--;                  //长度-1
            return array[n];
        }
    }

  数组实现(有序)

  ?思想:
    由于我们维护一个有序数组,所以每次插入元素的时候都要给他找到一个合适位置,来保证数组有序性,删除操作就会很简单了。

  ?代码:

public class OrderArrayPriorityQueue <Key extends Comparable<Key>>{
    private Key[] pq;          // elements
    private int n;             // number of elements

    public  OrderArrayPriorityQueue(int capacity) {
        pq = (Key[]) (new Comparable[capacity]);
        n = 0;
    }

    public boolean isEmpty() { return n == 0;  }
    public int size()        { return n;       }
    public Key delMax()      { return pq[--n]; }

    public void insert(Key key) {
        int i = n-1;
        while (i >= 0 && less(key, pq[i])) {
            pq[i+1] = pq[i];
            i--;
        }
        pq[i+1] = key;
        n++;
    }

    private boolean less(Key v, Key w) {
        return v.compareTo(w) < 0;
    }

    public static void main(String[] args) {
        OrderArrayPriorityQueue<String> pq = new  OrderArrayPriorityQueue<String>(10);
        pq.insert("this");
        pq.insert("is");
        pq.insert("a");
        pq.insert("test");
        while (!pq.isEmpty())
            System.out.println(pq.delMax());
    }
}

堆的定义

说明:
    二叉堆能够很好的实现优先队列的基本操作,二叉堆就是一颗二叉树,但是是按一种特定的组织结构排列
    即在二叉堆中每一个元素都要保证大于等于另外两个特定位置的元素(子节点)。
图示:
  

说明:
  
这是一个堆有序的二叉树。所谓堆有序就是一颗二叉树的每个节点都大于等于它的两个子节点。

二叉堆表示法:

?我们来组织一种堆有序的二叉树,这种有序的结构便于我们实现了优先队列。
  
我们可以使用指针来表示,但是这并不是最方便的。通过观察二叉有序堆,我们会发现它是一种完全二叉树,并且完全二叉树可以用数组来表示。

  用数组实现二叉有序堆:

    具体方法就是将二叉树的节点按照层序顺序放入数组中,根节点位置在1,它的子节点位置在2,3.依次类推。 

?两条重要的性质:   

  1.在一个二叉堆中,位置为K的节点的父节点的位置为|_K/2_|,而它的两个子节点位置为2K和2K+1
  2.一颗大小为N的完全二叉树的高度为|_LgN_|

用堆实现优先队列

由下至上的堆有序化

?说明:
 
 如果堆的有序化因为某个节点X变得比它的父节点更大而打破,我们需要交换它和它的父节点来修复堆,但是可能交换后X还是很大,所以我们需要X一次次的它的祖先节点进行比较,直到找打它最合适的位置。
  根据二叉堆的性质,我们不难发现只要记住位置为K的节点的父节点为 |_K/2_|,一切都很简单了。
?图示:

?代码

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

由上至下的堆有序化

?说明:
  如果堆的有序话因为某个节点X变得比它的两个子节点或其一更小而打破,我们需要交换它和它的子节点中较大的节点来修复堆,但是可能交换后X还是很小,所以我们需要X一次次的它的子节点进行比较并交换,直到找打它最合适的位置。
?图示:
  
?代码

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;
        }
    } 

基于堆的优先序列

?思路:
  我们每次插入元素到数组尾,这样可能会破坏堆的有序化,所以我们对其进行上浮操作
  当我们取出并删除最大元素的时候,第一个位置不能空着,我们的做法是将让最后一个元素移到第一个,然后进行下沉操作
?这样子我们就可以给出完整代码

class MaxPQ<Key extends Comparable<Key>> {

    private Key[] pq;
    private int N = 0;

    public MaxPQ(int maxN) {
        pq = (Key[]) new Comparable[maxN + 1];
    }

    public static void main(String[] args) {
        MaxPQ<Integer> maxPQ = new MaxPQ<Integer>(10);
        for(int i = 0; i < 10; i++)
        {
            maxPQ.insert((int)(Math.random() * 10 + 1));
        }
        while(!maxPQ.isEmpty())
        {
            System.out.println(maxPQ.delMax());
        }
    }

    public int size() {
        return N;
    }

    public boolean isEmpty() {
        return N == 0;
    }

    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 boolean less(int i, int j) {
        return pq[i].compareTo(pq[j]) < 0;
    }

    private void exch(int i, int j) {
        Key temp = pq[i];
        pq[i] = pq[j];
        pq[j] = temp;
    }

    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 void swim(int k) {
        while (k > 1 && less(k/2,k)) {

            exch(k/2, k);
            k = k/2;
        }
    }

} 
时间: 2024-08-10 17:34:25

数据结构:优先队列的相关文章

数据结构--优先队列(堆排序)

数据结构--优先队列(堆排序) 优先队列:不是先进先出啦,下面的代码是大顶堆,大的先出. 在之前理解堆排序的基础上,在来理解优先队列. 还是用这个公式: leftNo = parentNo*2+1 rightNo = parentNo*2+2 parentNo = (nodeNo-1)/2 每次进队列是从最后进,在慢慢上浮. 每次出队列,堆顶先出,在把队尾调到堆顶,在下浮. 上代码 package sy181002; import java.util.Arrays; /** * 优先队列 * *

JAVA数据结构--优先队列(堆实现)

优先队列(堆)的定义 堆(英语:Heap)是计算机科学中一类特殊的数据结构的统称.堆通常是一个可以被看做一棵树的数组对象.在队列中,调度程序反复提取队列中第一个作业并运行,因为实际情况中某些时间较短的任务将等待很长时间才能结束,或者某些不短小,但具有重要性的作业,同样应当具有优先权.堆即为解决此类问题设计的一种数据结构. 我个人比较通俗的理解就是比如我们平常下载视频看,我们打算下载两部视频,一部2G,一部只有200M.优先队列的思想就是先下载那部体积较小的视频,这样也比较合理,可以下完200M后

javascript数据结构-优先队列

这里之所以扩充一个 有限队列 是因为,生活使用中队列通常会附加优先级,比如排队买票,一般老人和军人等会有优先权限. 实现:继承上篇的 普通队列实现.这里用一种方法,入队的时候,进行排序插入到指定位置,输出不变. 优先队列类 //继承自 Queue function PriorityQueue(){ Queue.call(this); } 继承原型方法 function base(p, c){ var h = {}, P = p.prototype, C = c.prototype; for(va

数据结构----------------优先队列

优先队列 主要用于:1.插入 2.删除最大元素 基于实现这两项功能,用二叉堆来实现, 分析: ____________MaxPQ<Key>implementsIterator<Key>_______________________ insert() delMax()    优先队列的2个主要功能 ----------------------------------------------------------------------------------------------

深入理解空间搜索算法 ——数百万数据中的瞬时搜索

转自 干货|深入理解空间搜索算法 ——数百万数据中的瞬时搜索 2017-05-01 10:50 全球人工智能:专注为AI开发者提供全球最新AI技术动态和社群交流.用户来源包括:北大.清华.中科院.复旦.麻省理工.卡内基梅隆.斯坦福.哈佛.牛津.剑桥等世界名校的AI技术硕士.博士和教授:以及谷歌.腾讯.百度.脸谱.微软.华为.阿里.海康威视.滴滴.英伟达等全球名企的AI开发者和AI科学家. 文章来源:medium 编译:孙菁 上图为全球138,000个热门地点的R-tree的可视化图示 我这个人沉

奶牛晒衣服(题解)

奶牛晒衣服[问题描述]在熊大妈英明的带领下,时针和他的同伴生下了许多牛宝宝.熊大妈决定给每个宝宝都穿上可爱的婴儿装.于是,为牛宝宝洗晒衣服就成了很不爽的事情.圣人王担负起了这个重任.洗完衣服后,你就要弄干衣服.衣服在自然条件下用1 的时间可以晒干A 点湿度.抠门的熊大妈买了1 台烘衣机.使用烘衣机可以让你用1 的时间使1件衣服除开自然晒干的A 点湿度外,还可烘干B 点湿度,但在1 的时间内只能对1 件衣服使用.N 件的衣服因为种种原因而不一样湿,现在告诉你每件衣服的湿度,要你求出弄干所有衣服的最

数据结构Java实现07----队列:顺序队列&amp;顺序循环队列、链式队列、顺序优先队列

数据结构Java实现07----队列:顺序队列&顺序循环队列.链式队列.顺序优先队列 一.队列的概念: 队列(简称作队,Queue)也是一种特殊的线性表,队列的数据元素以及数据元素间的逻辑关系和线性表完全相同,其差别是线性表允许在任意位置插入和删除,而队列只允许在其一端进行插入操作在其另一端进行删除操作. 队列中允许进行插入操作的一端称为队尾,允许进行删除操作的一端称为队头.队列的插入操作通常称作入队列,队列的删除操作通常称作出队列. 下图是一个依次向队列中插入数据元素a0,a1,...,an-

数据结构课程设计题目十二_计算机学院学生会的打印机(优先队列)

本文出自:http://blog.csdn.net/svitter 题目12:计算机学院学生会的打印机(优先队列) 小明抱怨学生会的打印机不符合FIFO的原则,看到很多在他后面来打印的同学比他先打印出来.五分钟前,小明的文件就是下一个候选的,如今小明的文件又排到了后面.学生会的同学给小明解释说,学生会的打印机不是採用传统的队列方式,而是採用一种自定义的优先队列方式:每一个要打印的文件被赋予了一个从1到9的优先级(9最高,1最低).打印规定例如以下: 将队列中要打印的文件f从队列中拿出来: 假设在

【数据结构】优先队列和堆

优先队列(priority queue) 对于一般的队列是在队列的尾部添加数据,在头部删除,以便先进先出. 而优先队列中的每个元素都有一个优先级,每次将一个元素放入队列中,而每次出队时都是将优先级最大的那个元素出队,称为高进先出(largest-in,first-out). 优先队列必须实现以下几个操作 1.入队(push):将一个元素放入队列中. 2.出队(pop):将优先级最高的元素从队列中删除. 要实现上面的操作可以维护一个有序的链表.每次插入数据时维护整个链表有序,即使用插入法,每次出队

优先队列 - 数据结构 (二叉堆)

优先队列包括二叉堆.d-堆.左式堆.斜堆.二项队列等 1.二叉堆 堆是一棵被完全填满的二叉树,有可能例外的是在底层,底层上的元素从左到右填入.这样的树称为完全二叉树. 堆序的性质:在一个堆中,对于每一个节点X,X的父亲的关键字小于(或等于)X中的关键字,根节点除外(它没有父节点).完全二叉树可以用数组实现. //关于二叉堆的头文件定义 如果要插入的元素是新的最小值,那么它将一直被推向堆顶.这样在某一个时刻,i将是1,我们就需要另Insert函数令程序跳出while循环,这个值必须保证小于或者至少