คิวลำดับความสำคัญใน. สุทธิ [ปิด]


216

ฉันกำลังมองหา. NET การใช้งานคิวลำดับความสำคัญหรือโครงสร้างข้อมูลกอง

คิวลำดับความสำคัญคือโครงสร้างข้อมูลที่ให้ความยืดหยุ่นมากกว่าการเรียงลำดับแบบง่าย ๆ เนื่องจากอนุญาตให้องค์ประกอบใหม่เข้าสู่ระบบตามช่วงเวลาที่กำหนด มันคุ้มค่ากว่าการแทรกงานใหม่ลงในคิวลำดับความสำคัญมากกว่าจัดเรียงทุกอย่างในการมาถึงแต่ละครั้ง

คิวลำดับความสำคัญพื้นฐานรองรับการดำเนินงานหลักสามประการ:

  • แทรก (Q, x) ระบุไอเท็ม x ด้วยคีย์ k ให้แทรกลงในคิวลำดับความสำคัญ Q
  • ค้นหาขั้นต่ำ (Q) ส่งกลับตัวชี้ไปยังรายการที่มีค่าคีย์น้อยกว่าคีย์อื่นในคิวลำดับความสำคัญ Q
  • ลบ-ขั้นต่ำ (Q) ลบรายการออกจากคิวลำดับความสำคัญ Q ซึ่งมีคีย์น้อยที่สุด

นอกจากว่าฉันกำลังมองหาสถานที่ที่ไม่ถูกต้องไม่มีใครอยู่ในกรอบ มีใครตระหนักถึงสิ่งที่ดีหรือฉันควรจะม้วนตัวเอง?


34
FYI ฉันได้พัฒนาความง่ายต่อการใช้งานที่ดีที่สุดอย่าง C # ลำดับความสำคัญคิวซึ่งสามารถพบได้ที่นี่ มันได้รับการพัฒนาโดยเฉพาะสำหรับแอปพลิเคชั่นการบอกทาง (A * ฯลฯ ) แต่ควรทำงานได้อย่างสมบูรณ์แบบสำหรับแอปพลิเคชันอื่นเช่นกัน ฉันจะโพสต์สิ่งนี้เป็นคำตอบ แต่คำถามเพิ่งถูกปิด ...
BlueRaja - Danny Pflughoeft

1
ParallelExtensionsExtras มีรหัส ConcurrentPriorityQueue พร้อมกัน. msdn.microsoft.com/ParExtSamples
VoteCoffee โหวต

แนะนำPriorityQueueอย่างไม่มีส่วนร่วมซึ่งเป็นส่วนหนึ่งของความพยายามในการพอร์ต Java concurrent API เป็น. net สำหรับ Spring.Net มันเป็นทั้งกองและคิวพร้อมการสนับสนุนเต็มรูปแบบ Binary สามารถดาวน์โหลดได้ที่นี่
Kenneth Xu

@ BlueRaja-DannyPflughoeft คุณช่วยเพิ่มคำตอบนั้นได้ไหม?
mafu

1
เพียงเพื่อสรุป ไม่มีโครงสร้างข้อมูลฮีปใน. net ไม่อยู่ใน. net core ในตอนนี้ แม้ว่าArray.Sortผู้ใช้เป็นจำนวนมาก มีการนำไปใช้ภายใน
Artyom

คำตอบ:


44

ฉันชอบใช้OrderedBagและOrderedSetคลาสในPowerCollectionsเป็นลำดับความสำคัญ


60
OrderedBag / OrderedSet ทำงานได้มากกว่าที่จำเป็นพวกเขาใช้ต้นไม้สีแดงดำแทนที่จะเป็นกอง
Dan Berindei

3
@DanBerindei: ไม่จำเป็นต้องใช้งานถ้าคุณต้องการทำการคำนวณ (ลบรายการเก่า), ฮีปสนับสนุนการลบขั้นต่ำหรือสูงสุดเท่านั้น
Svisstack

69

คุณอาจชอบ IntervalHeap จากห้องสมุดเก็บ C5 ทั่วไป เพื่ออ้างอิงคู่มือผู้ใช้

คลาสIntervalHeap<T>ใช้อินเทอร์เฟซIPriorityQueue<T>โดยใช้ช่วงเวลาฮีปที่จัดเก็บเป็นอาร์เรย์ของคู่ การดำเนินการ FindMin และ FindMax และตัวรับค่าดัชนีของใช้เวลา O (1) การดำเนินการ DeleteMin, DeleteMax, เพิ่มและอัปเดตและ set-accessor ของตัวทำดัชนีใช้เวลา O (บันทึก n) ตรงกันข้ามกับคิวลำดับความสำคัญปกติช่วงเวลาฮีปมีทั้งการดำเนินงานขั้นต่ำและสูงสุดด้วยประสิทธิภาพเดียวกัน

API นั้นง่ายพอ

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

ติดตั้งจาก Nuget https://www.nuget.org/packages/C5หรือ GitHub https://github.com/sestoft/C5/


3
ดูเหมือนว่าจะเป็นห้องสมุดที่แข็งแกร่งและมาพร้อมกับการทดสอบ 1,400 หน่วย
ECC-Dan

2
ฉันพยายามใช้ แต่มีข้อบกพร่องร้ายแรง IntervalHeap ไม่มีแนวคิดในการจัดลำดับความสำคัญในตัวและบังคับให้คุณใช้งาน IComparable หรือ IComparer ทำให้เป็นคอลเล็กชันที่เรียงลำดับไม่ใช่ "ลำดับความสำคัญ" ยิ่งกว่านั้นไม่มีวิธีโดยตรงในการอัปเดตลำดับความสำคัญของรายการก่อนหน้าบาง !!!
morteza khosravi

52

นี่คือความพยายามของฉันใน. NET heap

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

การทดสอบบางอย่าง:

[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
ฉันขอแนะนำให้ล้างค่าฮีปใน ExtractDominating ดังนั้นจึงไม่เก็บไว้กับออบเจ็กต์ที่อ้างถึงนานเกินความจำเป็น (หน่วยความจำที่มีโอกาสรั่วไหล) สำหรับประเภทค่าเห็นได้ชัดว่าไม่มีความกังวล
Wout

5
ดี แต่คุณไม่สามารถลบรายการออกจากมันได้? นั่นเป็นการดำเนินการที่สำคัญสำหรับลำดับความสำคัญคิว
Tom Larkworthy

ดูเหมือนว่าวัตถุต้นแบบเป็นอาร์เรย์ นี่จะไม่ดีกว่าต้นไม้ไบนารีหรือไม่?
Grunion Shaftoe

1
@OhadSchneider เจ๋งมากฉันแค่มองหา min heap และพยายามทำสิ่งที่คุณทำให้เป็นเรื่องธรรมดาและ min หรือ max heap! ผลงานยอดเยี่ยม
Gilad

1
@Gilad IEqualityComparer<T>คงไม่เพียงพอเท่าที่จะบอกคุณได้ว่ารายการสองรายการนั้นเท่ากันหรือไม่ในขณะที่คุณต้องทราบความสัมพันธ์ระหว่างพวกเขา (ผู้ที่เล็กกว่า / ใหญ่กว่า) มันเป็นความจริงที่ฉันสามารถใช้งานได้IComparer<T>แม้ว่า ...
Ohad Schneider

23

นี่คือสิ่งที่ฉันเพิ่งเขียนบางทีมันอาจจะไม่ได้รับการปรับปรุงให้ดีที่สุด (แค่ใช้พจนานุกรมเรียง) แต่เข้าใจง่าย คุณสามารถแทรกวัตถุต่างชนิดได้ดังนั้นจึงไม่มีคิวทั่วไป

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

        }
    }
}

สิ่งนี้ไม่อนุญาตให้มีหลายรายการที่มีลำดับความสำคัญเท่ากันหรือไม่
Letseatlunch

2
มันทำ เมื่อคุณเรียกใช้ Enqueue วิธีมันจะเพิ่มรายการในคิวของลำดับความสำคัญนั้น (ส่วนอื่นในวิธีการ
เข้าคิว

5
คุณหมายถึงอะไรโดย "มันไม่ใช่คิวลำดับความสำคัญในความหมายด้านวิทยาศาสตร์คอมพิวเตอร์"? แล้วมันทำให้คุณเชื่อว่านี่ไม่ใช่คิวลำดับความสำคัญ
Mark Byers

14
-1 สำหรับไม่ใช้ยาสามัญ
cdiggins

2
หนึ่งในผลประโยชน์ที่ใหญ่ที่สุดของ Heap / PriorityQueue คือความซับซ้อนของ O (1) ของการสกัดต่ำสุด / สูงสุดเช่นการทำงานของ Peek และที่นี่มันเกี่ยวข้องกับการตั้งค่าตัวแจงนับสำหรับ for-loop ฯลฯ ทำไม!? นอกจากนี้การดำเนินการ "Enqueue" แทนที่จะเป็น O (logN) - คุณลักษณะที่สำคัญอีกประการหนึ่งของฮีปมีการปัด O (longN) หนึ่งรายการเนื่องจาก "ประกอบด้วยคีย์" หนึ่งรายการ (อีกครั้ง O (longN)) เพื่อเพิ่มรายการคิว (หากจำเป็น) หนึ่งในสามเพื่อดึงคิว (บรรทัดที่เก็บข้อมูล [prio]) และสุดท้ายเป็นการเพิ่มเชิงเส้นในคิวนั้น นี่เป็นสิ่งวิกลจริตอย่างแท้จริงในแง่ของการใช้อัลกอริทึมหลัก
Jonan Georgiev

10

ฉันพบหนึ่งโดย Julian Bucknall ในบล็อกของเขาที่นี่ - http://www.boyet.com/Articles/PriorityQueueCSharp3.html

เราปรับเปลี่ยนเล็กน้อยเพื่อให้ไอเท็มที่มีลำดับความสำคัญต่ำในคิวในที่สุดจะ 'เพิ่มฟอง' ไปด้านบนเมื่อเวลาผ่านไปดังนั้นพวกเขาจะไม่ได้รับความอดอยาก


9

ดังที่ได้กล่าวไว้ในMicrosoft Collections for .NET , Microsoft ได้เขียน (และแบ่งปันออนไลน์) 2 ระดับความสำคัญภายในลำดับความสำคัญของคลาสภายใน. NET Framework รหัสของพวกเขาสามารถทดลองใช้ได้

แก้ไข: ตามที่ @ mathusum-mut แสดงความคิดเห็นมีข้อผิดพลาดในหนึ่งในคลาส PriorityQueue ภายในของ Microsoft (ชุมชน SO มีแน่นอนให้การแก้ไขสำหรับมัน): ข้อผิดพลาดใน PriorityQueue <T> ภายในของ Microsoft?


10
พบข้อบกพร่องในการใช้งานอย่างใดอย่างหนึ่งที่นี่: stackoverflow.com/questions/44221454/ …
MathuSum Mut

โอ๋! ฉันเห็นว่าคลาสเหล่านี้ทั้งหมดPriorityQueue<T>ในแหล่งที่มาที่ใช้ร่วมกันของ Microsoft ถูกทำเครื่องหมายด้วยตัวinternalระบุการเข้าถึง ดังนั้นจึงถูกใช้โดยฟังก์ชันการทำงานภายในของกรอบเท่านั้น พวกเขาไม่สามารถใช้ได้สำหรับการบริโภคทั่วไปเพียงแค่อ้างอิงwindowsbase.dllในโครงการ C # วิธีเดียวคือการคัดลอกแหล่งข้อมูลที่ใช้ร่วมกันลงในโครงการของตัวเองภายในไฟล์คลาส
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;
    }
}

ง่าย.


13
บางครั้งฉันเห็นสิ่งที่ชอบ for (var n2 = n / 2; n > 0 && comparer.Compare(v, heap[n2]) > 0; n = n2, n2 /= 2) heap[n] = heap[n2]; และสงสัยว่ามันคุ้มค่ากับการใช้งานแบบแถว

1
@DustinBreakey สไตล์ส่วนตัว :)
Shimou Dong

3
แต่คนอื่นไม่สามารถอ่านได้แน่นอน ลองเขียนโค้ดที่ไม่มีเครื่องหมายคำถามลอยอยู่เหนือหัวนักพัฒนา
alzaimar

3

ใช้ตัวแปล Java to C # ในการนำ Java ไปใช้ (java.util.PriorityQueue) ในเฟรมเวิร์ก Java Collections หรือใช้อัลกอริทึมและรหัสหลักอย่างชาญฉลาดแล้วเสียบเข้ากับคลาส C # ของคุณเองเพื่อให้เป็นไปตามกรอบ C # Collections API สำหรับ Queues หรืออย่างน้อย Collections


วิธีนี้ใช้ได้ผล แต่น่าเสียดายที่ IKVM ไม่รองรับจาวาทั่วไปดังนั้นคุณจึงสูญเสียความปลอดภัยของประเภท
หอยทากวิศวกรรม

8
ไม่มีสิ่งเช่น "Java generics" เมื่อคุณจัดการกับ Java bytecode ที่คอมไพล์แล้ว IKVM ไม่สามารถรองรับได้
ทำเครื่องหมาย

3

AlgoKit

ฉันเขียนไลบรารีโอเพนซอร์สที่เรียกว่า AlgoKit , สามารถใช้ได้ผ่านทางNuGet มันมี:

  • กอง d-ary โดยนัย (ArrayHeap)
  • กองทวินาม ,
  • การจับคู่กองการจับคู่กอง

รหัสได้รับการทดสอบอย่างกว้างขวาง ฉันขอแนะนำให้คุณลองทำดู

ตัวอย่าง

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

ทำไมต้องเป็นสามกอง

ทางเลือกที่ดีที่สุดของการนำไปใช้งานนั้นขึ้นอยู่กับอินพุตเป็นอย่างมากเช่น Larkin, Sen และ Tarjan แสดงในการศึกษาเชิงประจักษ์ของคิวลำดับความสำคัญ , arXiv: 1403.0252v1 [cs.DS][cs.DS] พวกเขาทำการทดสอบ d-ary heaps โดยนัย, การจับคู่ heaps, ฮีปแบบ Fibonacci, heom binomial, heaps d-ary ที่ชัดเจน, heaps การจับคู่อันดับ, heake quake, heaps การละเมิด, heaps ที่อ่อนแออันดับที่ผ่อนคลายและ Fibonacci ที่เข้มงวด

AlgoKit มี heap สามประเภทที่ดูเหมือนว่ามีประสิทธิภาพมากที่สุดในบรรดาการทดสอบ

คำแนะนำในการเลือก

สำหรับองค์ประกอบจำนวนค่อนข้างน้อยคุณน่าจะสนใจใช้ heap implicit โดยเฉพาะ heaps quaternary (โดยนัย 4-ary) ในกรณีที่ใช้งานฮีปที่มีขนาดใหญ่กว่าโครงสร้างที่ตัดจำหน่ายเช่นฮีโนมีเนียมและฮีปการจับคู่ควรทำงานได้ดีขึ้น



1

ฉันมีปัญหาเดียวกันเมื่อเร็ว ๆ นี้และจบลงด้วยการสร้างแพ็คเกจ NuGetสำหรับสิ่งนี้

สิ่งนี้ใช้คิวลำดับความสำคัญอิงฮีปมาตรฐาน นอกจากนี้ยังมีคอลเลคชั่น BCL ตามปกติทั้งหมด: ICollection<T>และIReadOnlyCollection<T>การนำไปใช้งาน, IComparer<T>การสนับสนุนที่กำหนดเอง, ความสามารถในการระบุความจุเริ่มต้นและDebuggerTypeProxyเพื่อให้การรวบรวมง่ายขึ้นในการทำงานกับดีบักเกอร์

นอกจากนี้ยังมีอินไลน์แพ็คเกจเวอร์ชันที่เพิ่งติดตั้งไฟล์. cs หนึ่งไฟล์ลงในโครงการของคุณ (มีประโยชน์หากคุณต้องการหลีกเลี่ยงการพึ่งพาภายนอกที่มองเห็นได้)

ข้อมูลเพิ่มเติมสามารถดูได้ที่หน้า GitHub


1

การใช้งาน Max Heap อย่างง่าย

https://github.com/bharathkumarms/AlgorithmsMadeEasy/blob/master/AlgorithmsMadeEasy/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

การนำไปใช้งานต่อไปนี้ของการPriorityQueueใช้งานSortedSetจากไลบรารีระบบ

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 จะล้มเหลว (และคืนค่าเท็จ) หากคุณมีรายการอยู่ในชุดที่มี "ลำดับความสำคัญ" เช่นเดียวกับรายการที่คุณพยายามเพิ่ม ดังนั้น ... ถ้า A.Compare (B) == 0 และ A อยู่ในรายการแล้วฟังก์ชัน PriorityQueue.Enqueue ของคุณจะล้มเหลวอย่างเงียบ ๆ
Joseph

ใจที่จะอธิบายสิ่งที่T xและK key? ฉันเดาว่านี่เป็นเคล็ดลับในการอนุญาตการทำซ้ำT xและฉันจำเป็นต้องสร้างคีย์เฉพาะ (เช่น UUID) หรือไม่
Thariq Nugrohotomo
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.