首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

用 C# 實現帶鍵值的優先隊列(一)

     編輯:關於C語言

首先定義一個介面,用於取得鍵、值以及設定值:

namespace Skyiv.Util
{
    interface IKeyValue<T, K, V>
    {
        K GetKey(T x);
        V GetValue(T x);
        void SetValue(T x, V v);
    }
}

接著實作帶鍵值的優先隊列 KeyedPriorityQueue<T, K, V>:

using System;
using System.Collections.Generic;

namespace Skyiv.Util
{
    class KeyedPriorityQueue<T, K, V>
    {
        IComparer<T> comparer;
        IKeyValue<T, K, V> kver;
        Dictionary<K, int> keys;
        bool hasKey;
        T[] heap;

        public int Count { get; private set; }
        public KeyedPriorityQueue(IKeyValue<T, K, V> kv) : this(null, kv) { }
        public KeyedPriorityQueue(int capacity, IKeyValue<T, K, V> kv) : this(capacity, null, kv) { }
        public KeyedPriorityQueue(IComparer<T> comparer, IKeyValue<T, K, V> kv) : this(16, comparer, kv) { }

        public KeyedPriorityQueue(int capacity, IComparer<T> comparer, IKeyValue<T, K, V> kver)
        {
            this.keys = new Dictionary<K, int>();
            this.comparer = (comparer == null) ? Comparer<T>.Default : comparer;
            this.kver = kver;
            this.hasKey = (kver != null);
            this.heap = new T[capacity];
        }

        public bool ContainsKey(K key)
        {
            return keys.ContainsKey(key);
        }

        public void Update(T v)
        {
            if (!hasKey) throw new NotSupportedException();
            if (typeof(T).IsValueType) throw new InvalidOperationException("T 不能是值類型");
            if (!ContainsKey(kver.GetKey(v))) throw new ArgumentOutOfRangeException("v", v, "更新優先隊列時無此健值");
            var id = keys[kver.GetKey(v)];
            var cmp = comparer.Compare(v, heap[id]);
            kver.SetValue(heap[id], kver.GetValue(v)); // 注意:此行要求 T 為參考類型
            if (cmp < 0) SiftDown(id);
            else if (cmp > 0) SiftUp(id);
        }

        public void Push(T v)
        {
            if (Count >= heap.Length) Array.Resize(ref heap, Count * 2);
            if (hasKey) keys[kver.GetKey(v)] = Count;
            heap[Count] = v;
            SiftUp(Count++);
        }

        public T Pop()
        {
            var v = Top();
            if (hasKey) keys.Remove(kver.GetKey(v));
            heap[0] = heap[--Count];
            if (Count > 0) SiftDown(hasKey ? (keys[kver.GetKey(heap[0])] = 0) : 0);
            return v;
        }

        public T Top()
        {
            if (Count > 0) return heap[0];
            throw new InvalidOperationException("優先隊列為空");
        }

        void SiftUp(int n)
        {
            var v = heap[n];
            for (var n2 = n / 2; n > 0 && comparer.Compare(v, heap[n2]) > 0; n = n2, n2 /= 2)
                heap[hasKey ? (keys[kver.GetKey(heap[n2])] = n) : n] = heap[n2];
            heap[hasKey ? (keys[kver.GetKey(v)] = n) : n] = v;
        }

        void SiftDown(int n)
        {
            var v = heap[n];
            for (var n2 = n * 2; n2 < Count; n = n2, n2 *= 2)
            {
                if (n2 + 1 < Count && comparer.Compare(heap[n2 + 1], heap[n2]) > 0) n2++;
                if (comparer.Compare(v, heap[n2]) >= 0) break;
                heap[hasKey ? (keys[kver.GetKey(heap[n2])] = n) : n] = heap[n2];
            }
            heap[hasKey ? (keys[kver.GetKey(v)] = n) : n] = v;
        }
    }
}
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved