首页 技术 正文
技术 2022年11月20日
0 收藏 788 点赞 3,362 浏览 7496 个字

C# 优先级队列

前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);        }    }
相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,024
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,514
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,362
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,143
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,776
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,854