堆栈和队列枚举顺序

我知道List枚举器保证枚举顺序并尊重最后一个排序操作,我知道DictionaryHashSet不能,即你不能确定

 Dictionary dictionary = ...; foreach(var pair in dictionary) { } 

将按照附加顺序处理对。

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

对于Stack ,枚举当前由一个名为StackEnumerator的嵌套私有类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顺序。

如果您查看Microsoft文档中的Stack.GetEnumerator()示例并检查所述输出,您可以看到它是LIFO顺序。

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

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

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

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

堆栈枚举:

  Stack numbers = new Stack(); 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 numbers = new Queue(); 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 )的自然顺序,但这并不是要使用Queues( ref )和Stacks( ref )的方式。 它们旨在与Enqueue() / Dequeue()Push() / Pop() / Peek()交互一起使用。 Microsoft包含枚举器以使所有内容与基本ICollection接口保持一致,并使枚举器保持在集合的自然顺序中。

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

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