List<T>
中的 System.Collections.Generic
可以完成 Stack<T>
所做的一切,甚至更多——它们基于相同的底层数据结构。什么情况下选择Stack<T>
才是正确的?
如果您需要后进先出的项目集合,则可以使用堆栈。 列表将允许您在任何索引处访问其项目。 还有很多其他差异,但我想说这是最基本的。
发表评论后更新:
我想说,使用
Stack<T>
声明了您希望如何使用此代码。为未来做计划总是好的,但如果您现在需要 Stack<T>
,并且没有令人信服的理由使用 List<T>
,那么我会选择 Stack<T>
。
为什么我会人为地限制自己在新代码中使用 Stack
这就是您的答案 - 当您需要强制执行合同期望,即所使用的数据结构只能作为堆栈进行操作时,您应该使用
Stack
。 当然,您真正想要这样做的次数是有限的,但在适当的时候它是一个重要的工具。
例如,假设除非强制执行堆栈顺序,否则正在处理的数据没有任何意义。 在这些情况下,如果您将数据作为列表提供,就会给自己带来麻烦。 通过使用
Stack
(或 Queue
,或任何其他顺序敏感结构),您可以在代码中准确指定数据的使用方式。
好吧,如果您在逻辑上尝试表示堆栈,则需要使用
Stack
。 如果您使用堆栈,它将在整个代码中传达程序员的意图,并且它将防止无意中误用数据结构(无意中添加/删除/读取一端以外的其他位置)。
当然有可能,
Stack
可能只是一个接口,而不是具体的实现。 然后,您可以使用类似 List
的东西来实现该接口。 那里的问题主要是便利性问题。 如果有人需要一个堆栈,他们需要选择一些特定的实现并记住(“哦,是的,List 是首选的堆栈实现”),而不是仅仅更新具体类型。
一切都与概念有关。列表是列表,堆栈是堆栈,它们做两件截然不同的事情。它们唯一的共同点是它们的通用性和可变长度。
列表是一个可变长度的项目集合,其中的任何元素都可以通过索引访问和覆盖,并且可以在任何此类索引处添加项目以及从中删除项目。
堆栈是支持后进先出访问模型的可变长度项目集合;只能访问堆栈的顶部元素,并且只能向集合的该“端点”添加或删除元素。 “顶部”的第 3 项元素只能通过“弹出”其上方的两个元素以暴露它来访问。
使用正确的工具来完成工作;当您需要“随机”访问集合中的任何元素时,请使用列表。当您想要对数组中的元素实施更有限的“仅限顶部”访问时,请使用堆栈。当您想要强制执行 FIFO“管道”时,请使用队列;物品从一端进,从另一端出。
除了概念上的不同之外,正如其他答案已经指出的那样,
Stack
中还有不同的方法,可以使您的代码比使用List
时的相应代码更干净(并且您的生活更轻松)。
例如,使用
Stack
时的简单对象池片段:
if (!pool.TryPop(out var obj))
{
obj = new Foo();
}
同样写成
List
,同时保持操作 O(1):
Foo obj;
int count = pool.Count;
if (count > 0)
{
obj = pool[--count];
pool.RemoveAt(count);
}
else
{
obj = new Foo();
}