前6行是优先队列,后6行是C#原生的queue

Min Heap Priority Queue

Works withC# version 3.0+/DotNet 3.5+

The above code is not really a true Priority Queue as it does not allow duplicate keys; also, the SortedList on which it is based does not have O(log n) insertions and removals for random data as a true Priority Queue does. The below code implements a true Min Heap Priority Queue:

namespace PriorityQ {
  using KeyT = UInt32;
  using System;
  using System.Collections.Generic;
  using System.Linq;
  class Tuple<K, V> { // for DotNet 3.5 without Tuple's
    public K Item1; public V Item2;
    public Tuple(K k, V v) { Item1 = k; Item2 = v; }
    public override string ToString() {
      return "(" + Item1.ToString() + ", " + Item2.ToString() + ")";
    }
  }
  class MinHeapPQ<V> {
    private struct HeapEntry {
      public KeyT k; public V v;
      public HeapEntry(KeyT k, V v) { this.k = k; this.v = v; }
    }
    private List<HeapEntry> pq;
    private MinHeapPQ() { this.pq = new List<HeapEntry>(); }
    ; } }
    private int sz {
      get {
        var cnt = pq.Count;
        ) ?  : cnt - ;
      }
    }
    private Tuple<KeyT, V> pkmn {
      get {
        ) return null;
        else {
          ];
          return new Tuple<KeyT, V>(mn.k, mn.v);
        }
      }
    }
    private void psh(KeyT k, V v) { // add extra very high item if none
      ) pq.Add(new HeapEntry(UInt32.MaxValue, v));
      ]); // copy bottom item...
      ; ni > ; i >>= , ni >>= ) {
        ];
        ] = t; else break;
      }
      pq[i - ] = new HeapEntry(k, v);
    }
    private void siftdown(KeyT k, V v, int ndx) {
      ; var i = ndx;
      ; ni < cnt; ni = ni + ni + ) {
        ].k;
        var nk = k;
        if (k > lk) { i = ni; nk = lk; }
        ; i = ni; }
        if (i != oi) pq[oi] = pq[i]; else break;
      }
      pq[i] = new HeapEntry(k, v);
    }
    private void rplcmin(KeyT k, V v) {
      ) siftdown(k, v, );
    }
    private void dltmin() {
      ;
      ) pq.Clear();
      else {
        var lkv = pq[lsti];
        pq.RemoveAt(lsti); siftdown(lkv.k, lkv.v, );
      }
    }
    private void reheap(int i) {
      ;
      if (lfti < sz) {
        ; reheap(lfti); reheap(rghti);
        var ckv = pq[i]; siftdown(ckv.k, ckv.v, i);
      }
    }
    private void bld(IEnumerable<Tuple<KeyT, V>> sq) {
      var sqm = from e in sq
                select new HeapEntry(e.Item1, e.Item2);
      pq = sqm.ToList<HeapEntry>();
      var sz = pq.Count;
      ) {
        ];
        pq.Add(new HeapEntry(KeyT.MaxValue, lkv.v));
        reheap();
      }
    }
    private IEnumerable<Tuple<KeyT, V>> sq() {
      return from e in pq
             where e.k != KeyT.MaxValue
             select new Tuple<KeyT, V>(e.k, e.v); }
    private void adj(Func<KeyT, V, Tuple<KeyT, V>> f) {
      ;
      ; i < cnt; ++i) {
        var e = pq[i];
        var r = f(e.k, e.v);
        pq[i] = new HeapEntry(r.Item1, r.Item2);
      }
      reheap();
    }
    public static MinHeapPQ<V> empty { get { return new MinHeapPQ<V>(); } }
    public static bool isEmpty(MinHeapPQ<V> pq) { return pq.mt; }
    public static int size(MinHeapPQ<V> pq) { return pq.sz; }
    public static Tuple<KeyT, V> peekMin(MinHeapPQ<V> pq) { return pq.pkmn; }
    public static MinHeapPQ<V> push(KeyT k, V v, MinHeapPQ<V> pq) {
      pq.psh(k, v); return pq; }
    public static MinHeapPQ<V> replaceMin(KeyT k, V v, MinHeapPQ<V> pq) {
      pq.rplcmin(k, v); return pq; }
    public static MinHeapPQ<V> deleteMin(MinHeapPQ<V> pq) { pq.dltmin(); return pq; }
    public static MinHeapPQ<V> merge(MinHeapPQ<V> pq1, MinHeapPQ<V> pq2) {
      return fromSeq(pq1.sq().Concat(pq2.sq())); }
    public static MinHeapPQ<V> adjust(Func<KeyT, V, Tuple<KeyT, V>> f, MinHeapPQ<V> pq) {
      pq.adj(f); return pq; }
    public static MinHeapPQ<V> fromSeq(IEnumerable<Tuple<KeyT, V>> sq) {
      var pq = new MinHeapPQ<V>(); pq.bld(sq); return pq; }
    public static Tuple<Tuple<KeyT, V>, MinHeapPQ<V>> popMin(MinHeapPQ<V> pq) {
      var rslt = pq.pkmn; if (rslt == null) return null;
      pq.dltmin(); return new Tuple<Tuple<KeyT, V>, MinHeapPQ<V>>(rslt, pq); }
    public static IEnumerable<Tuple<KeyT, V>> toSeq(MinHeapPQ<V> pq) {
      for (; !pq.mt; pq.dltmin()) yield return pq.pkmn; }
    public static IEnumerable<Tuple<KeyT, V>> sort(IEnumerable<Tuple<KeyT, V>> sq) {
      return toSeq(fromSeq(sq)); }
  }
}

The above class code offers a full set of static methods and properties:

 1.  "empty" to create a new empty queue,
 2.  "isEmpty" to test if a queue is empty,
 3.  "size" to get the number of elements in the queue,
 4.  "peekMin" to retrieve the lowest priority key/value pair entry as a Tuple (possibly null for empty queues),
 5.  "push" to insert an entry,
 6.  "deleteMin" to remove the lowest priority entry,
 7.  "replaceMin" to replace the lowest priority and adjust the queue according to the value (faster than a "deleteMin" followed by a "push"),
 8.  "adjust" to apply a function to every key/value entry pair and reheapify the result,
 9.  "merge" to merge two queues into a single reheapified result,
 10. "fromSeq" to build a queue from a sequence of key/value pair tuples,
 11. "popMin" which is a convenience function combining a "peekMin" with a "deleteMin", returning null if the queue is empty and a tuple of the result otherwise,
 12. "toSeq" to output an ordered sequence of the queue contents as Tuple's of the key/value pairs, and
 13. "sort" which is a convenience function combining "fromSeq" followed by "toSeq".

The first four are all O(1) and the remainder O(log n) except "adjust" and "fromSeq" are O(n), "merge" is O(m + n) where m and n are the sizes of the two queues, and "toSeq" and "sort" are O(n log n); "replaceMin" is still O(log n) but faster than a "deleteMin" followed by a "push" by a constant factor.

Note that the Key type "KeyT" is not generic in order to give better comparison efficiency than using generic comparison using the IComparible interface but can be changed to different numeric types using the "using KeyT = ???" type alias.

The above code can be tested as per the page specification by the following code:

static void Main(string[] args) {
      Tuple<uint, string>[] ins = { new Tuple<uint,string>(3u, "Clear drains"),
                                    new Tuple<uint,string>(4u, "Feed cat"),
                                    new Tuple<uint,string>(5u, "Make tea"),
                                    new Tuple<uint,string>(1u, "Solve RC tasks"),
                                    new Tuple<uint,string>(2u, "Tax return") };

      var spq = ins.Aggregate(MinHeapPQ<string>.empty, (pq, t) => MinHeapPQ<string>.push(t.Item1, t.Item2, pq));
      foreach (var e in MinHeapPQ<string>.toSeq(spq)) Console.WriteLine(e); Console.WriteLine();

      foreach (var e in MinHeapPQ<string>.sort(ins)) Console.WriteLine(e); Console.WriteLine();

      var npq = MinHeapPQ<string>.fromSeq(ins);
      foreach (var e in MinHeapPQ<string>.toSeq(MinHeapPQ<string>.merge(npq, npq)))
        Console.WriteLine(e); Console.WriteLine();

      var npq = MinHeapPQ<string>.fromSeq(ins);
      foreach (var e in MinHeapPQ<string>.toSeq(MinHeapPQ<string>.merge(npq, npq)))
        Console.WriteLine(e);

      foreach (var e in MinHeapPQ<string>.toSeq(MinHeapPQ<string>.adjust((k, v) => new Tuple<uint,string>(6u - k, v), npq)))
        Console.WriteLine(e); Console.WriteLine();
    }

It tests building the queue the slow way using repeated "push"'s - O(n log n), the faster "fromSeq" (included in the "sort") - O(n), and also tests the "merge" and "adjust" methods.

The output of the above test is as follows:

Output:
(1, Solve RC tasks)
(2, Tax return)
(3, Clear drains)
(4, Feed cat)
(5, Make tea)

(1, Solve RC tasks)
(2, Tax return)
(3, Clear drains)
(4, Feed cat)
(5, Make tea)

(1, Solve RC tasks)
(1, Solve RC tasks)
(2, Tax return)
(2, Tax return)
(3, Clear drains)
(3, Clear drains)
(4, Feed cat)
(4, Feed cat)
(5, Make tea)
(5, Make tea)

(1, Make tea)
(2, Feed cat)
(3, Clear drains)
(4, Tax return)
(5, Solve RC tasks)

再贴上自己写的一点扩展方法
    public static class MinHeapPQEX
    {
        /// <summary>
        /// 创建一个空的优先级队列O(1)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static PriorityQueue<T> CreatPriorityQueue<T>()
        {
            return PriorityQueue<T>.empty;
        }

        /// <summary>
        /// 进队 O(log n)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="pq"></param>
        /// <param name="priority"></param>
        /// <param name="model"></param>
        public static void Enqueue<T>(this PriorityQueue<T> pq, UInt32 priority, T model)
        {
            PriorityQueue<T>.push(priority, model, pq);
        }

        /// <summary>
        /// 出队  peek+delete
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="pq"></param>
        /// <returns></returns>
        public static T Dequeue<T>(this PriorityQueue<T> pq)
        {
            return PriorityQueue<T>.popMin(pq).Item1.Item2;
        }

        /// <summary>
        /// 检索,但不出队 O(1)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="pq"></param>
        /// <returns></returns>
        public static T Peek<T>(this PriorityQueue<T> pq)
        {
            return PriorityQueue<T>.peekMin(pq).Item2;
        }

        /// <summary>
        /// 判断队列是否为空 O(1)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="pq"></param>
        /// <returns></returns>
        public static bool IsEmpty<T>(this PriorityQueue<T> pq)
        {
            return PriorityQueue<T>.isEmpty(pq);
        }

        /// <summary>
        /// 统计 O(1)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="pq"></param>
        /// <returns></returns>
        public static int Count<T>(this PriorityQueue<T> pq)
        {
            return PriorityQueue<T>.size(pq);
        }

        /// <summary>
        /// 删除即将出队的元素
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="pq"></param>
        public static void Delete<T>(this PriorityQueue<T> pq)
        {
            PriorityQueue<T>.deleteMin(pq);
        }
    }

C# 优先级队列的更多相关文章

  1. 体验Rabbitmq强大的【优先级队列】之轻松面对现实业务场景

    说到队列的话,大家一定不会陌生,但是扯到优先级队列的话,还是有一部分同学是不清楚的,可能是不知道怎么去实现吧,其实呢,,,这东西已 经烂大街了...很简单,用“堆”去实现的,在我们系统中有一个订单催付 ...

  2. Java中的队列Queue,优先级队列PriorityQueue

    队列Queue 在java5中新增加了java.util.Queue接口,用以支持队列的常见操作.该接口扩展了java.util.Collection接口. Queue使用时要尽量避免Collecti ...

  3. 如何基于RabbitMQ实现优先级队列

    概述 由于种种原因,RabbitMQ到目前为止,官方还没有实现优先级队列,只实现了Consumer的优先级处理. 但是,迫于种种原因,应用层面上又需要优先级队列,因此需求来了:如何为RabbitMQ加 ...

  4. ACM/ICPC 之 优先级队列+设置IO缓存区(TSH OJ-Schedule(任务调度))

    一个裸的优先级队列(最大堆)题,但也有其他普通队列的做法.这道题我做了两天,结果发现是输入输出太过频繁,一直只能A掉55%的数据,其他都是TLE,如果将输入输出的数据放入缓存区,然后满区输出,可以将I ...

  5. java中PriorityQueue优先级队列使用方法

    优先级队列是不同于先进先出队列的另一种队列.每次从队列中取出的是具有最高优先权的元素. PriorityQueue是从JDK1.5开始提供的新的数据结构接口. 如果不提供Comparator的话,优先 ...

  6. stl的优先级队列

    #include <iostream> #include <vector> #include <queue> using namespace std; class ...

  7. 【python cookbook】【数据结构与算法】5.实现优先级队列

    问题:要实现一个队列,它能够以给定的优先级对元素排序,且每次pop操作时都会返回优先级最高的那个元素: 解决方案:采用heapq模块实现一个简单的优先级队列 # example.py # # Exam ...

  8. POJ 2227 The Wedding Juicer (优先级队列+bfs+dfs)

    思路描述来自:http://hi.baidu.com/perfectcai_/item/701f2efa460cedcb0dd1c820也可以参考黑书P89的积水. 题意:Farmer John有一个 ...

  9. 《Java数据结构与算法》笔记-CH4-6优先级队列

    /** * 优先级队列 * 效率:插入O(n),删除O(1).第12章介绍如何通过堆来改进insert时间 */ class PriorityQueue { private int maxSize; ...

  10. STL学习系列七:优先级队列priority_queue容器

    1.简介 最大值优先级队列.最小值优先级队列 优先级队列适配器 STL priority_queue 用来开发一些特殊的应用,请对stl的类库,多做扩展性学习 这里给个例子: #include< ...

随机推荐

  1. java判断字符串是否为数字

    我们在做安卓开发中,一定会遇到判断某字符串是否是数字的问题,本文使用正则表达式可以很方便的判断出来,希望本文对安卓开发者有所帮助.   1 public boolean isNumeric(Strin ...

  2. jquery-3 jquery选择器

    jquery-3 jquery选择器 一.总结 一句话总结:选择器使用的时候可以结合参考手册,里面都已经详细归类好了.(多用才能熟啊) 1.$(:input).css({'color':'#98765 ...

  3. js如何实现动态点击改变单元格颜色?

    js如何实现动态点击改变单元格颜色? 一.总结 1.通过table的rows属性,遍历表格所有行,然后通过cells属性,遍历每一行中的单元格. 2.遍历的过程中,动态的为每一个单元格定义单击事件,改 ...

  4. 《高性能MySQL》--复制笔记

    复制解决的问题 1,数据分布 MySQL复制通常不会对带宽造成很大的压力,但在5.1版本引入的基于行的复制会比传统的基于语句的复制模式的带宽压力更大.你可以随意地停止或开始复制,并在不同的地理位置来分 ...

  5. Go 快速入门

    入门 Go 语言需要多久?答案是 -- 读完这篇文章的时间!不妨找一个周末的下午,踏上 Go 之旅吧! 更新记录: 2016.12.12: 完成重制 2016.11.02: 增加重点理解和参考链接 2 ...

  6. SWIFT学习笔记04

    1.在实际编译时,Swift 编译器会优化字符串的使用.使实际的复制仅仅发生在绝对必要的情况下,这意味着您将字符串作为值类型的同一时候能够获得极高的性能. 2.for character in &qu ...

  7. mybatis结合log4j打印SQL日志

    mybatis结合log4j打印SQL日志 1.Maven引用jar包 默认的mybatis不能打印出SQL日志,不便于查看调试,须要结合log4jdbc-log4j2就能够完整的输入SQL的调试信息 ...

  8. 【t101】小明搬家

    Time Limit: 1 second Memory Limit: 128 MB [问题描述] 小明要搬家了,大家都来帮忙. 小明现在住在第N楼,总共K个人要把X个大箱子搬上N楼. 最开始X个箱子都 ...

  9. 【erlang 网络编程学习】 分析cowboy acceptor实现

    http://www.tuicool.com/articles/vuymei 不知道为什么就看了cowboy代码,就继续看了下去了. 分析一下吧,主要写写cowboy 的acceptor pool 的 ...

  10. [GeekBand] 设计模式——工厂模式学习笔记

     本文参考文献:GeekBand课堂内容,授课老师:李建忠 :大话设计模式 其余的模式方法请自行查看Geekband相关课程,在此不累述. 这周的课题是: 针对DrawingSystem中的基类Sha ...