File d'attente prioritaire in.Net [fermé]

je suis à la recherche d'un .NET de la mise en œuvre d'une file d'attente de priorité ou d'un segment de structure de données

les files D'attente prioritaires sont des structures de données qui offrent plus de flexibilité que le simple tri, car elles permettent à de nouveaux éléments d'entrer dans un système à intervalles arbitraires. Il est beaucoup plus rentable d'insérer un nouvel emploi dans une file d'attente prioritaire que de tout trier de nouveau à chaque arrivée.

la file d'attente de priorité de base prend en charge trois opérations principales:

  • insérer(Q,x). Étant donné un élément x avec la touche k, insérez-le dans la file D'attente prioritaire Q.
  • Trouvez-Minimum(Q). Retourne un pointeur sur l'élément dont la valeur clé est plus petite que toute autre clé de la file d'attente prioritaire Q.
  • Supprimer-Minimum (Q). Supprimer L'élément de la file D'attente prioritaire Q dont la clé est minimum

sauf si je regarde au mauvais endroit, il n'existe pas dans le cadre. Quelqu'un est-il au courant d'un bon, ou devrais-je rouler mon propre?

195
demandé sur Colonel Panic 2008-09-19 18:43:54

14 réponses

j'ai comme l'utilisation de la OrderedBag et OrderedSet classes en PowerCollections que les files d'attente de priorité.

37
répondu Ben Hoffstein 2008-09-19 14:48:02

vous pourriez aimer IntervalHeap de la C5 collection générique Bibliothèque . Pour citer le guide de l'utilisateur

Classe IntervalHeap<T> implémente l'interface IPriorityQueue<T> à l'aide d'un intervalle de tas stocké sous forme d'un tableau de paires. La FindMin et FindMax opérations, et l'indexeur de l'obtenir-accesseur, prenez le temps O(1). Le DeleteMin, DeleteMax, ajouter et mettre à jour les opérations, et le set-accessor de l'indexeur, prendre du temps O (log et.) Contrairement à une file d'attente de priorité ordinaire, un tas d'intervalle offre à la fois un minimum et des opérations maximales avec la même efficacité.

L'API est assez simple

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

Install from Nuget https://www.nuget.org/packages/C5 ou GitHub https://github.com/sestoft/C5 /

63
répondu jaras 2015-11-04 10:12:56

Voici ma tentative .NET tas

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

quelques essais:

[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));
    }
}
45
répondu Ohad Schneider 2012-12-08 10:32:02

en voici un que je viens d'écrire, peut-être qu'il n'est pas aussi optimisé (utilise juste un dictionnaire trié) mais simple à comprendre. vous pouvez insérer des objets de différents types, donc pas de file d'attente Générique.

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

        }
    }
}
20
répondu kobi7 2014-01-24 18:36:10

J'en ai trouvé un de Julian Bucknall sur son blog ici - http://www.boyet.com/Articles/PriorityQueueCSharp3.html

nous l'avons légèrement modifié pour que les articles de faible priorité sur la file d'attente finissent par "rebondir" vers le haut avec le temps, pour qu'ils ne souffrent pas de famine.

8
répondu Duncan 2008-10-14 13:36:28

vous pouvez trouver utile cette mise en œuvre: http://www.codeproject.com/Articles/126751/Priority-queue-in-Csharp-with-help-of-heap-data-st.aspx

il est générique et basé sur la structure de données tas

6
répondu Alexey 2010-11-11 21:05:51
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;
    }
}

facile.

5
répondu Shimou Dong 2015-11-24 08:16:08

, Comme mentionné dans Microsoft Collections pour .NET , Microsoft a écrit (et partagé en ligne) 2 interne PriorityQueue classes au sein de la .NET Framework. Leur code est disponible pour essai.

éditer: comme @mathusum-mut a commenté, Il y a un bug dans L'une des classes internes de Microsoft PriorityQueue (la communauté SO A, Bien sûr, fourni des correctifs pour elle): Bug dans la PriorityQueue interne de Microsoft?

5
répondu weir 2017-05-30 17:44:44

utiliser un java pour C# translator sur L'implémentation Java (java.util.PriorityQueue) dans le cadre Java Collections, ou plus intelligemment utiliser l'algorithme et le code de base et le brancher dans une Classe C# de votre propre fabrication qui adhère à L'API C# Collections framework pour les Files d'attente, ou au moins Collections.

3
répondu JeeBee 2008-09-19 14:49:19

Voici l'autre implémentation de l'équipe de NGenerics:

NGenerics PriorityQueue

2
répondu husayt 2011-07-08 14:45:56

AlgoKit

j'ai écrit une bibliothèque open source appelée AlgoKit , disponible via NuGet . Il contient:

  • stock d-ary implicite (ArrayHeap),
  • tas Binomial ,
  • pairage tas .

le code a été largement testé. Je vous recommande vraiment de vous donner un essai.

exemple

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

Pourquoi ces trois tas?

Le choix optimal de la mise en œuvre est fortement dépendantes de l'entrée - comme Larkin, Sen, et Tarjan afficher dans Un retour aux sources empiriques de l'étude des files d'attente de priorité , arXiv:1403.0252v1 [cs.DS] . Ils ont testé des tas de d-ary implicites, des tas d'appariements, des tas de Fibonacci, des tas binomiaux., des tas d-ary explicites, des tas d'appariement de grades, des tas de tremblements, des tas de violations, des tas faibles décontractés, et des tas de Fibonacci stricts.

AlgoKit dispose de trois types de tas qui semblent être les plus efficaces parmi ceux testés.

Conseil sur le choix

pour un nombre relativement petit d'éléments, vous seriez probablement intéressé à utiliser des tas implicites, en particulier des tas quaternaires (implicite 4-ary). En cas d'opération sur un tas plus grand les tailles, les structures amorties comme les tas binomiaux et les tas d'appariement devraient donner de meilleurs résultats.

2
répondu Patryk Gołębiowski 2016-08-24 19:20:33

j'ai eu le même problème récemment et j'ai fini par créer un paquet NuGet pour ceci.

ceci implémente une file d'attente de priorité standard basée sur le tas. Il a aussi toutes les subtilités habituelles des collections BCL: ICollection<T> et IReadOnlyCollection<T> implémentation, support personnalisé IComparer<T> , possibilité de spécifier une capacité initiale, et un DebuggerTypeProxy pour rendre la collection plus facile à travailler dans le débogueur.

il y a aussi une version Inline du paquet qui vient d'installer un simple .le fichier cs dans votre projet (utile si vous voulez éviter de prendre des dépendances externes-visibles).

plus d'information est disponible sur le GitHub page .

1
répondu ChaseMedallion 2016-07-29 11:05:42

Un Simple Tas Max De Mise En Œuvre.

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();
*/
1
répondu Bharathkumar V 2017-02-01 08:02:29

l'implémentation suivante d'un PriorityQueue utilise SortedSet de la bibliothèque système.

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; } }
    }
}
-2
répondu cdiggins 2013-01-01 21:31:51