Hàng đợi ưu tiên trong .Net [đã đóng]


216

Tôi đang tìm kiếm một triển khai .NET của hàng đợi ưu tiên hoặc cấu trúc dữ liệu heap

Hàng đợi ưu tiên là các cấu trúc dữ liệu cung cấp tính linh hoạt hơn so với sắp xếp đơn giản, vì chúng cho phép các phần tử mới vào hệ thống theo các khoảng thời gian tùy ý. Sẽ hiệu quả hơn nhiều khi chèn một công việc mới vào hàng đợi ưu tiên hơn là sắp xếp lại mọi thứ trên mỗi lần đến như vậy.

Hàng đợi ưu tiên cơ bản hỗ trợ ba thao tác chính:

  • Chèn (Q, x). Cho một mục x có khóa k, chèn nó vào hàng ưu tiên Q.
  • Tìm tối thiểu (Q). Trả về một con trỏ tới mục có giá trị khóa nhỏ hơn bất kỳ khóa nào khác trong hàng ưu tiên Q.
  • Xóa-Tối thiểu (Q). Xóa mục khỏi hàng ưu tiên Q có khóa tối thiểu

Trừ khi tôi đang tìm sai chỗ, không có cái nào trong khuôn khổ. Có ai biết về một cái tốt, hay tôi nên tự lăn?


34
FYI Tôi đã phát triển một hàng đợi ưu tiên C # dễ sử dụng, được tối ưu hóa cao, có thể tìm thấy ở đây . Nó được phát triển riêng cho các ứng dụng tìm đường (A *, v.v.), nhưng cũng hoạt động hoàn hảo cho bất kỳ ứng dụng nào khác. Tôi sẽ đăng bài này dưới dạng câu trả lời, nhưng câu hỏi gần đây đã bị đóng ...
BlueRaja - Danny Pflughoeft

1
ParallelExtensionsExtras có mã đồng thờiP WarriorityQueue.msdn.microsoft.com/ParExtSamples
VoteCoffee

Không biết xấu hổ giới thiệu PriorityQueue , như một phần trong nỗ lực chuyển API đồng thời java sang .net cho Spring.Net. Đó là cả một đống và hàng đợi với sự hỗ trợ chung chung. Nhị phân có thể được tải xuống ở đây .
Kenneth Xu

@ BlueRaja-DannyPflughoeft Bạn có thể thêm câu trả lời không?
mafu

1
Chỉ để tóm tắt. Hiện tại không có cấu trúc dữ liệu heap trong .net, cũng không phải trong lõi .net. Mặc dù Array.Sort người dùng nó cho số lượng lớn. Thực hiện nội bộ tồn tại.
Artyom

Câu trả lời:


44

Tôi thích sử dụng OrderedBagOrderedSetcác lớp trong PowerCollections làm hàng đợi ưu tiên.


60
OrderedBag / Orderedset làm nhiều việc hơn mức cần thiết, họ sử dụng cây đỏ đen thay vì một đống.
Dan Berindei

3
@DanBerindei: không cần thiết nếu bạn cần thực hiện tính toán chạy (xóa các mục cũ), heap chỉ hỗ trợ xóa tối thiểu hoặc tối đa
Svisstack

69

Bạn có thể thích IntervalHeap từ Thư viện Bộ sưu tập Chung C5 . Để báo hướng dẫn sử dụng

Lớp IntervalHeap<T>thực hiện giao diện IPriorityQueue<T>bằng cách sử dụng một heap khoảng thời gian được lưu trữ dưới dạng một mảng các cặp. Các hoạt động FindMin và FindMax và trình truy cập của người lập chỉ mục, mất thời gian O (1). Các hoạt động DeleteMin, DeleteMax, Thêm và Cập nhật và trình truy cập thiết lập của người lập chỉ mục, mất thời gian O (log n). Trái ngược với hàng đợi ưu tiên thông thường, một heap khoảng cung cấp cả hoạt động tối thiểu và tối đa với cùng hiệu quả.

API đủ đơn giản

> var heap = new C5.IntervalHeap<int>();
> heap.Add(10);
> heap.Add(5);
> heap.FindMin();
5

Cài đặt từ Nuget https://www.nuget.org/packages/C5 hoặc GitHub https://github.com/sestoft/C5/


3
Đây có vẻ là một thư viện rất vững chắc và nó đi kèm với 1400 bài kiểm tra đơn vị.
ECC-Dan

2
Tôi đã cố gắng sử dụng nó nhưng nó có sai sót nghiêm trọng. IntervalHeap không có khái niệm ưu tiên tích hợp và buộc bạn phải triển khai IComparable hoặc IComparer khiến nó trở thành một bộ sưu tập được sắp xếp không phải là "Ưu tiên". Thậm chí tệ hơn là không có cách trực tiếp để cập nhật mức độ ưu tiên của một số mục trước đó !!!
morteza khosravi

52

Đây là nỗ lực của tôi tại một đống .NET

public abstract class Heap<T> : IEnumerable<T>
{
    private const int InitialCapacity = 0;
    private const int GrowFactor = 2;
    private const int MinGrow = 1;

    private int _capacity = InitialCapacity;
    private T[] _heap = new T[InitialCapacity];
    private int _tail = 0;

    public int Count { get { return _tail; } }
    public int Capacity { get { return _capacity; } }

    protected Comparer<T> Comparer { get; private set; }
    protected abstract bool Dominates(T x, T y);

    protected Heap() : this(Comparer<T>.Default)
    {
    }

    protected Heap(Comparer<T> comparer) : this(Enumerable.Empty<T>(), comparer)
    {
    }

    protected Heap(IEnumerable<T> collection)
        : this(collection, Comparer<T>.Default)
    {
    }

    protected Heap(IEnumerable<T> collection, Comparer<T> comparer)
    {
        if (collection == null) throw new ArgumentNullException("collection");
        if (comparer == null) throw new ArgumentNullException("comparer");

        Comparer = comparer;

        foreach (var item in collection)
        {
            if (Count == Capacity)
                Grow();

            _heap[_tail++] = item;
        }

        for (int i = Parent(_tail - 1); i >= 0; i--)
            BubbleDown(i);
    }

    public void Add(T item)
    {
        if (Count == Capacity)
            Grow();

        _heap[_tail++] = item;
        BubbleUp(_tail - 1);
    }

    private void BubbleUp(int i)
    {
        if (i == 0 || Dominates(_heap[Parent(i)], _heap[i])) 
            return; //correct domination (or root)

        Swap(i, Parent(i));
        BubbleUp(Parent(i));
    }

    public T GetMin()
    {
        if (Count == 0) throw new InvalidOperationException("Heap is empty");
        return _heap[0];
    }

    public T ExtractDominating()
    {
        if (Count == 0) throw new InvalidOperationException("Heap is empty");
        T ret = _heap[0];
        _tail--;
        Swap(_tail, 0);
        BubbleDown(0);
        return ret;
    }

    private void BubbleDown(int i)
    {
        int dominatingNode = Dominating(i);
        if (dominatingNode == i) return;
        Swap(i, dominatingNode);
        BubbleDown(dominatingNode);
    }

    private int Dominating(int i)
    {
        int dominatingNode = i;
        dominatingNode = GetDominating(YoungChild(i), dominatingNode);
        dominatingNode = GetDominating(OldChild(i), dominatingNode);

        return dominatingNode;
    }

    private int GetDominating(int newNode, int dominatingNode)
    {
        if (newNode < _tail && !Dominates(_heap[dominatingNode], _heap[newNode]))
            return newNode;
        else
            return dominatingNode;
    }

    private void Swap(int i, int j)
    {
        T tmp = _heap[i];
        _heap[i] = _heap[j];
        _heap[j] = tmp;
    }

    private static int Parent(int i)
    {
        return (i + 1)/2 - 1;
    }

    private static int YoungChild(int i)
    {
        return (i + 1)*2 - 1;
    }

    private static int OldChild(int i)
    {
        return YoungChild(i) + 1;
    }

    private void Grow()
    {
        int newCapacity = _capacity*GrowFactor + MinGrow;
        var newHeap = new T[newCapacity];
        Array.Copy(_heap, newHeap, _capacity);
        _heap = newHeap;
        _capacity = newCapacity;
    }

    public IEnumerator<T> GetEnumerator()
    {
        return _heap.Take(Count).GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

public class MaxHeap<T> : Heap<T>
{
    public MaxHeap()
        : this(Comparer<T>.Default)
    {
    }

    public MaxHeap(Comparer<T> comparer)
        : base(comparer)
    {
    }

    public MaxHeap(IEnumerable<T> collection, Comparer<T> comparer)
        : base(collection, comparer)
    {
    }

    public MaxHeap(IEnumerable<T> collection) : base(collection)
    {
    }

    protected override bool Dominates(T x, T y)
    {
        return Comparer.Compare(x, y) >= 0;
    }
}

public class MinHeap<T> : Heap<T>
{
    public MinHeap()
        : this(Comparer<T>.Default)
    {
    }

    public MinHeap(Comparer<T> comparer)
        : base(comparer)
    {
    }

    public MinHeap(IEnumerable<T> collection) : base(collection)
    {
    }

    public MinHeap(IEnumerable<T> collection, Comparer<T> comparer)
        : base(collection, comparer)
    {
    }

    protected override bool Dominates(T x, T y)
    {
        return Comparer.Compare(x, y) <= 0;
    }
}

Một số xét nghiệm:

[TestClass]
public class HeapTests
{
    [TestMethod]
    public void TestHeapBySorting()
    {
        var minHeap = new MinHeap<int>(new[] {9, 8, 4, 1, 6, 2, 7, 4, 1, 2});
        AssertHeapSort(minHeap, minHeap.OrderBy(i => i).ToArray());

        minHeap = new MinHeap<int> { 7, 5, 1, 6, 3, 2, 4, 1, 2, 1, 3, 4, 7 };
        AssertHeapSort(minHeap, minHeap.OrderBy(i => i).ToArray());

        var maxHeap = new MaxHeap<int>(new[] {1, 5, 3, 2, 7, 56, 3, 1, 23, 5, 2, 1});
        AssertHeapSort(maxHeap, maxHeap.OrderBy(d => -d).ToArray());

        maxHeap = new MaxHeap<int> {2, 6, 1, 3, 56, 1, 4, 7, 8, 23, 4, 5, 7, 34, 1, 4};
        AssertHeapSort(maxHeap, maxHeap.OrderBy(d => -d).ToArray());
    }

    private static void AssertHeapSort(Heap<int> heap, IEnumerable<int> expected)
    {
        var sorted = new List<int>();
        while (heap.Count > 0)
            sorted.Add(heap.ExtractDominating());

        Assert.IsTrue(sorted.SequenceEqual(expected));
    }
}

2
Tôi sẽ khuyên bạn nên xóa giá trị heap trong ExtractDominating, vì vậy nó không giữ đối tượng được tham chiếu lâu hơn mức cần thiết (rò rỉ bộ nhớ tiềm năng). Đối với các loại giá trị rõ ràng là không quan tâm.
Wout

5
Đẹp nhưng bạn không thể loại bỏ các mục từ nó? Đó là một hoạt động quan trọng cho hàng đợi ưu tiên.
Tom Larkworthy

Có vẻ như đối tượng cơ bản là một mảng. Điều này sẽ không tốt hơn như là một cây nhị phân?
Grunion Shaftoe

1
@OhadSchneider rất rất tuyệt, tôi chỉ nhìn vào heap min và cố gắng làm những gì bạn đã làm cho nó chung chung và heap tối thiểu hoặc tối đa! công việc tuyệt vời
Gilad

1
@Gilad IEqualityComparer<T>sẽ không đủ, vì điều đó sẽ chỉ cho bạn biết hai mục có bằng nhau hay không, trong khi bạn cần biết mối quan hệ giữa chúng (nhỏ hơn / lớn hơn). Đúng là tôi có thể đã sử dụng IComparer<T>mặc dù ...
Ohad Schneider

23

Đây là một cái tôi vừa viết, có thể nó không được tối ưu hóa (chỉ sử dụng một từ điển được sắp xếp) nhưng dễ hiểu. bạn có thể chèn các đối tượng của các loại khác nhau, do đó không có hàng đợi chung.

using System;
using System.Diagnostics;
using System.Collections;
using System.Collections.Generic;

namespace PrioQueue
{
    public class PrioQueue
    {
        int total_size;
        SortedDictionary<int, Queue> storage;

        public PrioQueue ()
        {
            this.storage = new SortedDictionary<int, Queue> ();
            this.total_size = 0;
        }

        public bool IsEmpty ()
        {
            return (total_size == 0);
        }

        public object Dequeue ()
        {
            if (IsEmpty ()) {
                throw new Exception ("Please check that priorityQueue is not empty before dequeing");
            } else
                foreach (Queue q in storage.Values) {
                    // we use a sorted dictionary
                    if (q.Count > 0) {
                        total_size--;
                        return q.Dequeue ();
                    }
                }

                Debug.Assert(false,"not supposed to reach here. problem with changing total_size");

                return null; // not supposed to reach here.
        }

        // same as above, except for peek.

        public object Peek ()
        {
            if (IsEmpty ())
                throw new Exception ("Please check that priorityQueue is not empty before peeking");
            else
                foreach (Queue q in storage.Values) {
                    if (q.Count > 0)
                        return q.Peek ();
                }

                Debug.Assert(false,"not supposed to reach here. problem with changing total_size");

                return null; // not supposed to reach here.
        }

        public object Dequeue (int prio)
        {
            total_size--;
            return storage[prio].Dequeue ();
        }

        public void Enqueue (object item, int prio)
        {
            if (!storage.ContainsKey (prio)) {
                storage.Add (prio, new Queue ());
              }
            storage[prio].Enqueue (item);
            total_size++;

        }
    }
}

Điều này không cho phép nhiều mục có cùng mức độ ưu tiên?
Letseatlunch

2
nó làm khi bạn gọi phương thức Enqueue, nó sẽ thêm mục vào hàng đợi ưu tiên đó. (phần khác trong phương pháp enqueue.)
kobi7

5
Ý bạn là gì khi "nó không thực sự là một hàng đợi ưu tiên trong ý nghĩa khoa học máy tính"? Điều gì về nó khiến bạn tin rằng đây không phải là một hàng đợi ưu tiên?
Mark Byers

13
-1 vì không sử dụng thuốc generic.
cdiggins

2
Một trong những lợi ích lớn nhất của Heap / PriorityQueue là độ phức tạp O (1) của khai thác tối thiểu / tối đa, tức là hoạt động Peek. Và ở đây nó liên quan đến việc thiết lập điều tra viên, vòng lặp, v.v ... Tại sao!? Ngoài ra, thao tác "Enqueue" chứ không phải là O (logN) - một tính năng quan trọng khác của heap, có một lần vuốt O (longN) vì "ContainsKey", lần thứ hai (lại là O (longN)) để thêm mục Hàng đợi (nếu cần), một phần ba để thực sự truy xuất Hàng đợi (dòng lưu trữ [tiên tri]) và cuối cùng là thêm tuyến tính vào hàng đợi đó. Điều này thực sự điên rồ trong ánh sáng của việc thực hiện thuật toán cốt lõi.
Jonan Georgiev

10

Tôi đã tìm thấy một của Julian Bucknall trên blog của anh ấy ở đây - http://www.boyet.com/Articles/P WarriorityQueueCSharp3.html

Chúng tôi đã sửa đổi nó một chút để các mục ưu tiên thấp trong hàng đợi cuối cùng sẽ 'nổi bong bóng' lên đầu theo thời gian, vì vậy chúng sẽ không bị đói.


9

Như đã đề cập trong Bộ sưu tập Microsoft cho .NET , Microsoft đã viết (và chia sẻ trực tuyến) 2 lớp PriorityQueue nội bộ trong .NET Framework. Mã của họ có sẵn để thử.

EDIT: Như @ mathusum-mut đã nhận xét, có một lỗi trong một trong các lớp PriorityQueue nội bộ của Microsoft (tất nhiên, cộng đồng SO đã cung cấp các bản sửa lỗi cho nó): Lỗi trong PriorityQueue <T> của Microsoft?


10
Một lỗi đã được tìm thấy trong một trong những triển khai ở đây: stackoverflow.com/questions/44221454/
Khăn

ồ Tôi có thể thấy rằng tất cả các lớp này PriorityQueue<T>trong nguồn chia sẻ của Microsoft được đánh dấu bằng internalchỉ định truy cập. Vì vậy, chúng chỉ được sử dụng bởi các chức năng nội bộ của khung. Chúng không có sẵn cho tiêu dùng chung chỉ bằng cách tham khảo windowsbase.dlltrong một dự án C #. Cách duy nhất là sao chép nguồn chia sẻ vào chính dự án trong một tệp lớp.
RBT


7
class PriorityQueue<T>
{
    IComparer<T> comparer;
    T[] heap;
    public int Count { get; private set; }
    public PriorityQueue() : this(null) { }
    public PriorityQueue(int capacity) : this(capacity, null) { }
    public PriorityQueue(IComparer<T> comparer) : this(16, comparer) { }
    public PriorityQueue(int capacity, IComparer<T> comparer)
    {
        this.comparer = (comparer == null) ? Comparer<T>.Default : comparer;
        this.heap = new T[capacity];
    }
    public void push(T v)
    {
        if (Count >= heap.Length) Array.Resize(ref heap, Count * 2);
        heap[Count] = v;
        SiftUp(Count++);
    }
    public T pop()
    {
        var v = top();
        heap[0] = heap[--Count];
        if (Count > 0) SiftDown(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[n] = heap[n2];
        heap[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[n] = heap[n2];
        }
        heap[n] = v;
    }
}

dễ dàng.


13
Đôi khi tôi thấy những thứ như for (var n2 = n / 2; n > 0 && comparer.Compare(v, heap[n2]) > 0; n = n2, n2 /= 2) heap[n] = heap[n2]; và tự hỏi liệu nó có đáng giá một lần hay không

1
@DustinBreakey phong cách cá nhân :)
Shimou Dong

3
nhưng chắc chắn không thể đọc được cho người khác Xem xét việc viết mã không để lại dấu chấm hỏi trên đầu của nhà phát triển.
alzaimar

3

Sử dụng trình dịch Java sang C # khi triển khai Java (java.util.P WarriorityQueue) trong khung công tác Bộ sưu tập Java hoặc sử dụng thuật toán và mã lõi một cách thông minh hơn và cắm nó vào lớp C # của riêng bạn để tuân thủ khung C # Collections API cho Hàng đợi hoặc ít nhất là Bộ sưu tập.


Điều này hoạt động, nhưng không may là IKVM không hỗ trợ các tổng quát Java, do đó bạn mất an toàn kiểu.
Ốc cơ khí

8
Không có thứ gọi là "Java genericics" khi bạn đang xử lý mã byte Java được biên dịch. IKVM không thể hỗ trợ nó.
Đánh dấu

3

AlgoKit

Tôi đã viết một thư viện mã nguồn mở có tên AlgoKit , có sẵn thông qua NuGet . Nó chứa:

  • Các đống d-ary tiềm ẩn (ArrayHeap),
  • Đống nhị thức ,
  • Ghép cặp .

Mã này đã được thử nghiệm rộng rãi. Tôi chắc chắn khuyên bạn nên thử nó.

Thí dụ

var comparer = Comparer<int>.Default;
var heap = new PairingHeap<int, string>(comparer);

heap.Add(3, "your");
heap.Add(5, "of");
heap.Add(7, "disturbing.");
heap.Add(2, "find");
heap.Add(1, "I");
heap.Add(6, "faith");
heap.Add(4, "lack");

while (!heap.IsEmpty)
    Console.WriteLine(heap.Pop().Value);

Tại sao ba đống đó?

Sự lựa chọn tối ưu của việc triển khai phụ thuộc nhiều vào đầu vào - như Larkin, Sen và Tarjan thể hiện trong Một nghiên cứu thực nghiệm cơ bản về hàng đợi ưu tiên , arXiv: 1403.0252v1 [cs.DS] . Họ đã thử nghiệm các đống d-ary ngầm, các đống ghép, các đống Fibonacci, các đống nhị phân, các đống d-ary rõ ràng, các đống ghép xếp hạng, các đống quake, các đống vi phạm, các đống yếu của bậc

AlgoKit có ba loại đống có vẻ hiệu quả nhất trong số các loại được thử nghiệm.

Gợi ý lựa chọn

Đối với một số lượng phần tử tương đối nhỏ, bạn có thể sẽ quan tâm đến việc sử dụng các đống ẩn, đặc biệt là các đống thứ tư (4-ary ngầm). Trong trường hợp vận hành ở kích thước heap lớn hơn, các cấu trúc được khấu hao như đống nhị phân và đống ghép sẽ hoạt động tốt hơn.



1

Tôi đã có cùng một vấn đề gần đây và cuối cùng đã tạo ra một gói NuGet cho việc này.

Điều này thực hiện một hàng đợi ưu tiên dựa trên heap tiêu chuẩn. Nó cũng có tất cả các đặc tính thông thường của các bộ sưu tập BCL: ICollection<T>IReadOnlyCollection<T>triển khai, IComparer<T>hỗ trợ tùy chỉnh , khả năng chỉ định công suất ban đầu và DebuggerTypeProxyđể làm cho bộ sưu tập dễ dàng hoạt động hơn trong trình gỡ lỗi.

Ngoài ra còn có một phiên bản Inline của gói chỉ cài đặt một tệp .cs vào dự án của bạn (hữu ích nếu bạn muốn tránh lấy các phụ thuộc có thể nhìn thấy bên ngoài).

Thêm thông tin có sẵn trên trang github .


1

Một thực hiện Heap Max đơn giản.

https://github.com/bharathkumarms/AlerskymsMade EAS/blob/master/AlacticmsMade EAS/MaxHeap.cs

using System;
using System.Collections.Generic;
using System.Linq;

namespace AlgorithmsMadeEasy
{
    class MaxHeap
    {
        private static int capacity = 10;
        private int size = 0;
        int[] items = new int[capacity];

        private int getLeftChildIndex(int parentIndex) { return 2 * parentIndex + 1; }
        private int getRightChildIndex(int parentIndex) { return 2 * parentIndex + 2; }
        private int getParentIndex(int childIndex) { return (childIndex - 1) / 2; }

        private int getLeftChild(int parentIndex) { return this.items[getLeftChildIndex(parentIndex)]; }
        private int getRightChild(int parentIndex) { return this.items[getRightChildIndex(parentIndex)]; }
        private int getParent(int childIndex) { return this.items[getParentIndex(childIndex)]; }

        private bool hasLeftChild(int parentIndex) { return getLeftChildIndex(parentIndex) < size; }
        private bool hasRightChild(int parentIndex) { return getRightChildIndex(parentIndex) < size; }
        private bool hasParent(int childIndex) { return getLeftChildIndex(childIndex) > 0; }

        private void swap(int indexOne, int indexTwo)
        {
            int temp = this.items[indexOne];
            this.items[indexOne] = this.items[indexTwo];
            this.items[indexTwo] = temp;
        }

        private void hasEnoughCapacity()
        {
            if (this.size == capacity)
            {
                Array.Resize(ref this.items,capacity*2);
                capacity *= 2;
            }
        }

        public void Add(int item)
        {
            this.hasEnoughCapacity();
            this.items[size] = item;
            this.size++;
            heapifyUp();
        }

        public int Remove()
        {
            int item = this.items[0];
            this.items[0] = this.items[size-1];
            this.items[this.size - 1] = 0;
            size--;
            heapifyDown();
            return item;
        }

        private void heapifyUp()
        {
            int index = this.size - 1;
            while (hasParent(index) && this.items[index] > getParent(index))
            {
                swap(index, getParentIndex(index));
                index = getParentIndex(index);
            }
        }

        private void heapifyDown()
        {
            int index = 0;
            while (hasLeftChild(index))
            {
                int bigChildIndex = getLeftChildIndex(index);
                if (hasRightChild(index) && getLeftChild(index) < getRightChild(index))
                {
                    bigChildIndex = getRightChildIndex(index);
                }

                if (this.items[bigChildIndex] < this.items[index])
                {
                    break;
                }
                else
                {
                    swap(bigChildIndex,index);
                    index = bigChildIndex;
                }
            }
        }
    }
}

/*
Calling Code:
    MaxHeap mh = new MaxHeap();
    mh.Add(10);
    mh.Add(5);
    mh.Add(2);
    mh.Add(1);
    mh.Add(50);
    int maxVal  = mh.Remove();
    int newMaxVal = mh.Remove();
*/

-3

Việc thực hiện sau đây của việc PriorityQueuesử dụng SortedSettừ thư viện Hệ thống.

using System;
using System.Collections.Generic;

namespace CDiggins
{
    interface IPriorityQueue<T, K> where K : IComparable<K>
    {
        bool Empty { get; }
        void Enqueue(T x, K key);
        void Dequeue();
        T Top { get; }
    }

    class PriorityQueue<T, K> : IPriorityQueue<T, K> where K : IComparable<K>
    {
        SortedSet<Tuple<T, K>> set;

        class Comparer : IComparer<Tuple<T, K>> {
            public int Compare(Tuple<T, K> x, Tuple<T, K> y) {
                return x.Item2.CompareTo(y.Item2);
            }
        }

        PriorityQueue() { set = new SortedSet<Tuple<T, K>>(new Comparer()); }
        public bool Empty { get { return set.Count == 0;  } }
        public void Enqueue(T x, K key) { set.Add(Tuple.Create(x, key)); }
        public void Dequeue() { set.Remove(set.Max); }
        public T Top { get { return set.Max.Item1; } }
    }
}

6
Sortedset.Add sẽ thất bại (và trả về false) nếu bạn đã có một mục trong tập hợp có cùng mức "ưu tiên" như mục bạn đang cố gắng thêm. Vì vậy, nếu A.Compare (B) == 0 và A đã có trong danh sách, chức năng PriorityQueue.Enqueue của bạn sẽ âm thầm thất bại.
Joseph

Tâm trí để giải thích những gì T xK key? Tôi đoán đây là một mẹo để cho phép trùng lặp T xvà tôi cần tạo một khóa duy nhất (ví dụ: UUID)?
Thariq Nugrohotomo
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.