堆<>在C#中实现

时间:2010-07-09 17:25:19

标签: c# stack

我最近一直在实现递归目录搜索实现,我正在使用Stack来跟踪路径元素。当我使用string.Join()加入路径元素时,我发现它们被颠倒了。当我调试方法时,我查看了堆栈,发现元素本身在Stack的内部数组中是相反的,即最近的Push()ed元素位于内部数组的开头,而最近最近的Push() ed元素位于内部数组的末尾。这似乎是落后的,非常反直觉。有人可以告诉我为什么微软会以这种方式实现堆栈吗?

6 个答案:

答案 0 :(得分:35)

我认为你错了。

Stack<T>.Push内部不在内部数组的开头插入一个项目(它没有)。相反,它从顶部到底部进行枚举,因为这是一种直观地通过堆栈进行枚举的方式(想想一堆煎饼:你从顶部开始向下工作)。

如果从Visual Studio的调试器中查看集合的内容,我认为它将按照它们枚举的顺序显示给你 - 而不是它们在内部存储的顺序*。

查看Reflector中的Stack<T>.Push方法,您会发现代码基本上与您期望的完全相同:

// (code to check array size)
this._array[this._size++] = item;
// (code to update internal version number)

因此,堆栈在内部将新元素添加到其内部数组的末尾。这是让你感到困惑的Stack<T>.Enumerator类,而不是Stack<T>类本身。

*我不知道这一般是否属实,但Stack<T>是正确的。请参阅Hans Passant's excellent answer了解原因。

答案 1 :(得分:17)

你让我去那里一点,确实看起来完全低音。然而,还有其他事情发生了。堆栈&lt;&gt; class有一个名为System_StackDebugView&lt;&gt;的调试器可视化工具。这是一个内部类,您必须使用Reflector查看它。

该可视化工具具有Items属性,这是您在调试器中展开节点时所看到的内容。 Items属性使用Stack&lt;&gt; .ToArray()。看起来像这样:

public T[] ToArray()
{
    T[] localArray = new T[this._size];
    for (int i = 0; i < this._size; i++)
    {
        localArray[i] = this._array[(this._size - i) - 1];
    }
    return localArray;
}
是的,倒退。

答案 2 :(得分:11)

您所描述的正确的实现,因为堆栈是LIFO(后进先出)结构。想象它就像一堆盘子,最近放入堆叠的元素是第一个被移除的元素。你有没有遇到过FIFO的堆栈?

FIFO将是一个队列。

答案 3 :(得分:2)

以下是堆栈的push和pops方法的实现方式。请注意,它使用的是数组中的最后一个索引,而不是第一个索引。因此,必须有其他一些问题让你倒退。

   public virtual void Push(object obj)
    {
        if (this._size == this._array.Length)
        {
            object[] destinationArray = new object[2 * this._array.Length];
            Array.Copy(this._array, 0, destinationArray, 0, this._size);
            this._array = destinationArray;
        }
        this._array[this._size++] = obj;
        this._version++;
    }


 public virtual object Pop()
    {
        if (this._size == 0)
        {
            throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EmptyStack"));
        }
        this._version++;
        object obj2 = this._array[--this._size];
        this._array[this._size] = null;
        return obj2;
    }

答案 4 :(得分:1)

要添加到其他答案,如果在调试器中向下滚动到Stack&lt;&gt;元素的底部并打开Raw View-&gt;非公开成员 - &gt; _array您可以看到内容用于保存项目的实际内部数组,并验证它们是否按预期顺序排列。

答案 5 :(得分:0)

我不知道在他们认为堆栈顶端的哪个方面很重要,只要你现在知道它到底是哪一端。实际上更有意义的是,当你将某些东西推到堆叠上时,你将它推到顶部(开始)并将其他物品向下移动......