堆栈和队列枚举顺序

时间:2016-06-09 12:02:18

标签: c# .net

我知道List枚举器保证枚举顺序并尊重最后一次排序操作,我知道DictionaryHashSet不是,即你可以确保

Dictionary<string, string> dictionary = ...;

foreach(var pair in dictionary)
{

}

将按照附加顺序处理对。

StackQueue怎么样?他们的调查员是否保证任何订单?

3 个答案:

答案 0 :(得分:9)

对于Stack,枚举当前由一个名为StackEnumerator的嵌套私有类完成(这来自Reference Source):

private class StackEnumerator : IEnumerator, ICloneable
{
    private Stack _stack;
    private int _index;
    private int _version;
    private Object currentElement;

    internal StackEnumerator(Stack stack) {
        _stack = stack;
        _version = _stack._version;
        _index = -2;
        currentElement = null;
    }

    public Object Clone()
    {
        return MemberwiseClone();
    }

    public virtual bool MoveNext() {
        bool retval;
        if (_version != _stack._version) throw new InvalidOperationException(Environment.GetResourceString(ResId.InvalidOperation_EnumFailedVersion));
        if (_index == -2) {  // First call to enumerator.
            _index = _stack._size-1;
            retval = ( _index >= 0);
            if (retval)
                currentElement = _stack._array[_index];
            return retval;
        }
        if (_index == -1) {  // End of enumeration.
            return false;
        }

        retval = (--_index >= 0);
        if (retval)
            currentElement = _stack._array[_index];
        else
            currentElement = null;
        return retval;
    }

    public virtual Object Current {
        get {
            if (_index == -2) throw new InvalidOperationException(Environment.GetResourceString(ResId.InvalidOperation_EnumNotStarted));
            if (_index == -1) throw new InvalidOperationException(Environment.GetResourceString(ResId.InvalidOperation_EnumEnded));
            return currentElement;
        }
    }

    public virtual void Reset() {
        if (_version != _stack._version) throw new InvalidOperationException(Environment.GetResourceString(ResId.InvalidOperation_EnumFailedVersion));
        _index = -2;
        currentElement = null;
    }
}    

注意它是如何枚举的,从索引设置为_stack._size-1开始,并递减索引以返回LIFO顺序中的每个元素。

但是,因为没有记录,你不能保证它总是这样(虽然微软改变枚举器现在的工作方式会很疯狂!)

您可以检查嵌套QueueEnumerator类的实现,同样确定枚举是按照项目出列的顺序完成的。

Stack.GetEnumerator()强烈暗示使用了LIFO订单。

如果查看the example for Stack<T>.GetEnumerator() in Microsoft's documentation并检查所述输出,您可以看到它是LIFO顺序。

这强烈暗示微软完全打算以LIFO顺序枚举一个堆栈 - 但是他们忘记了(或者没有理由)明确记录这个!

答案 1 :(得分:6)

Queue是先进先出(FIFO)集合(在文档中正确说明)。这意味着枚举器按照添加顺序为您提供项目。

Stack是一个后进先出(LIFO)集合。这意味着枚举器以与添加方式相反的顺序为您提供项目。

堆栈和队列是非常标准的计算机科学构造,因此如果没有严重的反弹,它们真的无法重新定位。当您查看GetEnumerator()函数的示例时,它会清楚地记录枚举的顺序:

Stack Enumeration:

    Stack<string> numbers = new Stack<string>();
    numbers.Push("one");
    numbers.Push("two");
    numbers.Push("three");
    numbers.Push("four");
    numbers.Push("five");

    // A stack can be enumerated without disturbing its contents.
    foreach( string number in numbers )
    {
        Console.WriteLine(number);
    }

    /* This code example produces the following output:

     five
     four
     three
     two
     one

    */

Queue Enumeration:

    Queue<string> numbers = new Queue<string>();
    numbers.Enqueue("one");
    numbers.Enqueue("two");
    numbers.Enqueue("three");
    numbers.Enqueue("four");
    numbers.Enqueue("five");

    // A queue can be enumerated without disturbing its contents.
    foreach( string number in numbers )
    {
        Console.WriteLine(number);
    }

    /* This code example produces the following output:

     one
     two
     three
     four
     five

    */

同样,对于基本的计算机科学定义,枚举器或迭代器必须以集合的自然顺序呈现元素。特定的集合类型具有已定义的顺序。

<强>买者

请注意,虽然枚举过程确实反映了FIFO和LIFO集合(ref)的自然顺序,但这不是队列(ref)和堆栈(ref)的方式是打算使用。它们旨在与Enqueue() / Dequeue()Push() / Pop() / Peek()互动使用。 Microsoft包含枚举器以使所有内容与基本ICollection<T>接口保持一致,并使枚举器保持在集合的自然顺序中。

队列的目的是提供可以按顺序处理的工作流程。 Stack的目的是提供一种在本地工作完成时返回到先前上下文的方法。它们旨在一次处理一个项目。使用枚举器类整个集合迭代整个目的并且不从队列/堆栈中删除项目。它基本上是对所有物品的窥视。

答案 2 :(得分:1)

是。它似乎没有明确记录,但元素的枚举顺序与弹出/出列的顺序相同。