Simple priority queue in C# - what will be better than List with custom Sorter : IComparer?

丶灬走出姿态 提交于 2019-12-06 07:18:27

问题


I would like to implement a priority queue which would inject my objects - Nodes to the queue with respect to one field - f. I have already written List with custom comparer but this would require from me to:

  • enqueue - sort the List after each insertion
  • dequeue - remove the last(instead of first for performance) like so

    myList.RemoveAt(myList.Count - 1);
    

My List should be always sorted according to some field (here I need it to be sorted by f). I also need the ability to add and dequeue the object with lowest value from the list.

Can someone tell me what would be the best approach to this ?

EDIT

dasblinkenlight has a very good answer but just I have realised that I should be able to store duplicates in this container.


回答1:


If you are in .NET 4 or later, you can use a SortedSet<T> class with a custom IComparer<T>.

The class lets you add new objects with the Add method common to all mutable collections. You can retrieve the max element using the Max property, and then call Remove to erase the max from the collection.

Edit: (in response to an edit of the question) If you need to store duplicates, you can use a SortedDictionary<Key,int>, and make a counted set out of it. Again, you have an option of using a custom IComparer<T>. When you enqueue an element, check if it exists already, and increment its count. When dequeueing, again check the count, decrement it, and remove the key only when the count reaches zero.




回答2:


As mentioned earlier, a SortedDictionary gets you part way there, you just need a way of dealing with duplicate priorities. The way of dealing with duplicates in any Map based structure (Dictionary, SortedDictionary, etc.) is to make the value a collection of what you really want the values to be. In your case, it makes the most sense for the value to be a Queue<T>.

Here is a starting place. You can add additional methods such as Count, implementations of IEnumerable, etc. if needed.

/// <summary>
/// 
/// </summary>
/// <typeparam name="TElement">The type of the actual elements that are stored</typeparam>
/// <typeparam name="TKey">The type of the priority.  It probably makes sense to be an int or long, \
/// but any type that can be the key of a SortedDictionary will do.</typeparam>
public class PriorityQueue<TElement, TKey>
{
    private SortedDictionary<TKey, Queue<TElement>> dictionary = new SortedDictionary<TKey, Queue<TElement>>();
    private Func<TElement, TKey> selector;


    public PriorityQueue(Func<TElement, TKey> selector)
    {
        this.selector = selector;
    }

    public void Enqueue(TElement item)
    {
        TKey key = selector(item);
        Queue<TElement> queue;
        if (!dictionary.TryGetValue(key, out queue))
        {
            queue = new Queue<TElement>();
            dictionary.Add(key, queue);
        }

        queue.Enqueue(item);
    }

    public TElement Dequeue()
    {
        if (dictionary.Count == 0)
            throw new Exception("No items to Dequeue:");
        var key = dictionary.Keys.First();

        var queue = dictionary[key];
        var output = queue.Dequeue();
        if (queue.Count == 0)
            dictionary.Remove(key);

        return output;
    }
}


来源:https://stackoverflow.com/questions/13981406/simple-priority-queue-in-c-sharp-what-will-be-better-than-list-with-custom-sor

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!