C# 有效移除SortedSet中的第一个元素<;T>;

C# 有效移除SortedSet中的第一个元素<;T>;,c#,sortedset,C#,Sortedset,我有一个SortedSet,我正在向其中添加项目(以不受控制的顺序,显然是利用了它的排序功能) 集合中的项目始终按顺序使用和移除,一次一个 set.Min.Process(); set.Remove(set.Min); 然而,我所面临的问题是由于Remove方法的O(logn)方面,以及SortedSet的二进制搜索性质,这导致对每个Remove进行最大可能的比较次数(~logn) 在我看来,一个基于访问最小和最大项的集合并没有一个有效的方法来删除它们,这似乎很奇怪 实际上,我想要的是一个se

我有一个SortedSet,我正在向其中添加项目(以不受控制的顺序,显然是利用了它的排序功能)

集合中的项目始终按顺序使用和移除,一次一个

set.Min.Process();
set.Remove(set.Min);
然而,我所面临的问题是由于Remove方法的O(logn)方面,以及SortedSet的二进制搜索性质,这导致对每个Remove进行最大可能的比较次数(~logn)

在我看来,一个基于访问最小和最大项的集合并没有一个有效的方法来删除它们,这似乎很奇怪

实际上,我想要的是一个set.RemoveMin()方法,它使用更优化的方法(无需比较)来获取第一个元素

有没有办法做到这一点?
是否有任何现有的可供选择的SortedSet实现我可以利用?

[EDIT]我对此进行了检测,它似乎并不比仅使用
SortedSet
更快,因此这可能不是一个好答案

@randomman159-如果在您尝试后,这没有帮助,请对此答案发表评论,我将删除它


你所描述的是一个例子

下面是一个使用堆的基本实现

对于
Enqueue()
Dequeue()
,其复杂性都是O(LogN):

///优先级队列数据结构。
/// 
///以传统方式实现,使用堆。
///基于源代码http://www.vcskicks.com/priority-queue.php
/// 
///也看到http://en.wikipedia.org/wiki/Heap_(数据结构)
///及http://en.wikipedia.org/wiki/Priority_queue
/// 
[System.Diagnostics.CodeAnalysis.SuppressMessage(“Microsoft.Naming”,“CA1711:IdentifierShouldnothaveIncorrectSuffix”)]
公共密封类优先队列
{
///构造器。
///类型为T>的项目的比较函数。
公共优先级队列(比较比较器)
{
_比较器=比较器;
_heap=新列表{default(T)};
}
///队列中的项目数。
public int Count=>\u heap.Count-1;
/// 
///返回优先级队列头部的值,而不删除该值。
///如果队列为空,则引发异常。
/// 
公共T Peek()
{
如果(this.Count>0)
{
return _heap[1];//队列头位于[1],而不是[0]。
}
其他的
{
抛出新的InvalidOperationException(“尝试将Peek()放入空的PriorityQueue”);
}
}
///向优先级队列添加一个值
公共无效排队(T值)
{
_添加(值);
this.bubbleUp(_heap.Count-1);//冒泡以保留heap属性,从插入的值开始。
}
///返回优先级队列的前端。
公共T出列()
{
如果(this.Count>0)
{
T minValue=this._heap[1];//优先级队列中的最小值是数组中的第一项
if(this.\u heap.Count>2)//如果有多个项,则用最后一个项替换数组中的第一个项。
{
T lastValue=this.\u heap[\u heap.Count-1];
这个。_heap.RemoveAt(_heap.Count-1);//将最后一个节点移动到头部
此._heap[1]=lastValue;
这是bubbleDown(1);
}
else//队列中只有一项。
{
_heap.RemoveAt(1);//删除队列中存储的唯一值。
}
返回最小值;
}
其他的
{
抛出新的InvalidOperationException(“尝试从空的PriorityQueue中出列());
}
}
///恢复子值和父值之间向上的堆顺序属性。
专用空泡泡(int startCell)
{
//需要(startCell>=0);
//需要(startCell<_heap.Count);
int单元=startCell;
while(this.isParentBigger(cell))//只要父对象较大,就会冒泡。
{
//获取父级和子级的值。
T parentValue=this._heap[cell/2];
T childValue=this._heap[cell];
//交换值。
此._heap[cell/2]=childValue;
此._heap[cell]=parentValue;
单元格//=2;//向上移动。
}
}
///在向下的子值和父值之间恢复heap order属性。
私有空泡泡城(int startCell)
{
//需要(startCell>0);
//需要(startCell<_heap.Count);
int单元=startCell;
//只要两个孩子中的任何一个小一些,泡沫就会消失。
while(this.isLeftChildSmaller(cell)| | this.isRightChildSmaller(cell))
{
int child=this.compareChild(单元格);
if(child==-1)//左子级。
{
//交换值。
T parentValue=_堆[cell];
T leftChildValue=_堆[2*单元格];
_heap[cell]=leftChildValue;
_堆[2*单元]=父值;
cell=2*cell;//下移到左侧子级。
}
else if(child==1)//右子级。
{
//交换值。
T parentValue=_堆[cell];
T rightChildValue=_堆[2*单元格+1];
_堆[单元]=rightChildValue;
_堆[2*单元格+1]=父值;
cell=2*cell+1;//向下移动到右子级。
}
}
}
///父对象的值是否大于其子对象的值?
私人布尔伊斯帕伦特比格(int childCell)
{
//需要(childCell>=0);
//需要(childCell<_heap.Count);
if(childCell==1)
{
返回false;//堆的顶部,没有父级。
}
其他的
{
返回_比较器(_heap[childCell/2],_heap[childCell])>0;
}
}
///
/// <summary>Priority Queue data structure.</summary>
/// <remarks>
/// Implemented in traditional fashion, using a heap.
/// Based on code from http://www.vcskicks.com/priority-queue.php
/// 
/// Also see http://en.wikipedia.org/wiki/Heap_(data_structure)
/// and http://en.wikipedia.org/wiki/Priority_queue
/// </remarks>

[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix")]

public sealed class PriorityQueue<T>
{
    /// <summary>Constructor.</summary>
    /// <param name="comparer">A comparison function for items of type T>.</param>

    public PriorityQueue(Comparison<T> comparer)
    {
        _comparer = comparer;
        _heap = new List<T> {default(T)};
    }

    /// <summary>The number of items in the queue.</summary>

    public int Count => _heap.Count - 1;

    /// <summary>
    /// Returns the value at the head of the Priority Queue without removing it.
    /// Throws an exception if the queue is empty.
    /// </summary>

    public T Peek()
    {
        if (this.Count > 0)
        {
            return _heap[1]; // Head of the queue is at [1], not [0].
        }
        else
        {
            throw new InvalidOperationException("Attempt to Peek() into an empty PriorityQueue<T>");
        }
    }

    /// <summary>Adds a value to the Priority Queue</summary>

    public void Enqueue(T value)
    {
        _heap.Add(value);
        this.bubbleUp(_heap.Count - 1); // Bubble up to preserve the heap property, starting at the inserted value.
    }

    /// <summary>Returns the front of the Priority Queue.</summary>

    public T Dequeue()
    {
        if (this.Count > 0)
        {
            T minValue = this._heap[1]; // The smallest value in the Priority Queue is the first item in the array

            if (this._heap.Count > 2) // If there's more than one item, replace the first item in the array with the last one.
            {
                T lastValue = this._heap[_heap.Count - 1];

                this._heap.RemoveAt(_heap.Count - 1);       // Move last node to the head
                this._heap[1] = lastValue;
                this.bubbleDown(1);
            }
            else  // Only one item in the queue.
            {
                _heap.RemoveAt(1);  // Remove the only value stored in the queue.
            }

            return minValue;
        }
        else
        {
            throw new InvalidOperationException("Attempt to Dequeue() from an empty PriorityQueue<T>");
        }
    }

    /// <summary>Restores the heap-order property between child and parent values going up towards the head.</summary>

    private void bubbleUp(int startCell)
    {
        // Requires(startCell >= 0);
        // Requires(startCell < _heap.Count);

        int cell = startCell;

        while (this.isParentBigger(cell))   // Bubble up as long as the parent is greater.
        {
            // Get values of parent and child.

            T parentValue = this._heap[cell/2];
            T childValue  = this._heap[cell];

            // Swap the values.

            this._heap[cell/2] = childValue;
            this._heap[cell]   = parentValue;

            cell /= 2; // Go up parents.
        }
    }

    /// <summary>Restores the heap-order property between child and parent values going down towards the bottom.</summary>

    private void bubbleDown(int startCell)
    {
        // Requires(startCell > 0);
        // Requires(startCell < _heap.Count);

        int cell = startCell;

        // Bubble down as long as either child is smaller.

        while (this.isLeftChildSmaller(cell) || this.isRightChildSmaller(cell))
        {
            int child = this.compareChild(cell);

            if (child == -1) // Left Child.
            {
                // Swap values.

                T parentValue    = _heap[cell];
                T leftChildValue = _heap[2*cell];

                _heap[cell]   = leftChildValue;
                _heap[2*cell] = parentValue;

                cell = 2*cell; // Move down to left child.
            }
            else if (child == 1) // Right Child.
            {
                // Swap values.

                T parentValue     = _heap[cell];
                T rightChildValue = _heap[2*cell+1];

                _heap[cell]     = rightChildValue;
                _heap[2*cell+1] = parentValue;

                cell = 2*cell+1; // Move down to right child.
            }
        }
    }

    /// <summary>Is the value of a parent greater than its child?</summary>

    private bool isParentBigger(int childCell)
    {
        // Requires(childCell >= 0);
        // Requires(childCell < _heap.Count);

        if (childCell == 1)
        {
            return false;  // Top of heap, no parent.
        }
        else
        {
            return _comparer(_heap[childCell/2], _heap[childCell]) > 0;
        }
    }

    /// <summary>
    /// Returns whether the left child cell is smaller than the parent cell.
    /// Returns false if a left child does not exist.
    /// </summary>

    private bool isLeftChildSmaller(int parentCell)
    {
        // Requires(parentCell >= 0);
        // Requires(parentCell < _heap.Count);

        if (2*parentCell >= _heap.Count)
        {
            return false; // Out of bounds.
        }
        else
        {
            return _comparer(_heap[2*parentCell], _heap[parentCell]) < 0;
        }
    }

    /// <summary>
    /// Returns whether the right child cell is smaller than the parent cell.
    /// Returns false if a right child does not exist.
    /// </summary>

    private bool isRightChildSmaller(int parentCell)
    {
        // Requires(parentCell >= 0);
        // Requires(parentCell < _heap.Count);

        if (2 * parentCell + 1 >= _heap.Count)
        {
            return false; // Out of bounds.
        }
        else
        {
            return _comparer(_heap[2*parentCell+1], _heap[parentCell]) < 0;
        }
    }

    /// <summary>
    /// Compares the children cells of a parent cell. -1 indicates the left child is the smaller of the two,
    /// 1 indicates the right child is the smaller of the two, 0 inidicates that neither child is smaller than the parent.
    /// </summary>

    private int compareChild(int parentCell)
    {
        // Requires(parentCell >= 0);
        // Requires(parentCell < _heap.Count);

        bool leftChildSmaller  = this.isLeftChildSmaller(parentCell);
        bool rightChildSmaller = this.isRightChildSmaller(parentCell);

        if (leftChildSmaller || rightChildSmaller)
        {
            if (leftChildSmaller && rightChildSmaller)
            {
                // Figure out which of the two is smaller.

                int leftChild  = 2 * parentCell;
                int rightChild = 2 * parentCell + 1;

                T leftValue  = this._heap[leftChild];
                T rightValue = this._heap[rightChild];

                // Compare the values of the children.

                if (_comparer(leftValue, rightValue) <= 0)
                {
                    return -1; // Left child is smaller.
                }
                else
                {
                    return 1; // Right child is smaller.
                }
            }
            else if (leftChildSmaller)
            {
                return -1; // Left child is smaller.
            }
            else
            {
                return 1; // Right child smaller.
            }
        }
        else
        {
            return 0; // Both children are bigger or don't exist.
        }
    }

    private readonly List<T>       _heap;
    private readonly Comparison<T> _comparer;
}