何时使用堆栈 C# 中的集合?
我确实了解 Stack()
和 Stack
的工作原理,但我真的看不到数组、List
的任何场景code> 或 IEnumerable
并不是更好、更简单的选择。
谁能给我提供一个使用 Stack
的真实示例?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(12)
理想情况下,您使用或根据需要创建反映现实世界中事物如何工作的类,以及您在代码中建模的事物。这些类为我们提供了一定程度的抽象,因此我们可以根据我们正在建模/模拟的内容进行编码。此外,在编码一些复杂的东西时,使用熟悉的范例会有所帮助。也就是说:哦,这个 Fuzzinator 类使用了一个 Stack。我知道什么是堆栈以及它是如何工作的。
其次,更高级别的抽象类为我们提供了有效的代码(我们假设 .NET 框架已经过测试),并节省了我们重新发明轮子的时间和痛苦。
第三,代码更容易阅读、更容易理解、更容易更改等等。它更易于维护。
使用具有更精细功能的类有助于限制我们在使用它时可能会出错的情况。
总的来说,当您的应用程序以适当的抽象级别进行编码时,它会更好。
堆栈就是这些类之一。
我的 HP-41X 计算器使用堆栈进行算术。这种计算方式称为 RPN - 逆波兰表示法。
如果我要模拟一家自助餐厅,那么 Stack 将非常适合那堆盘子。盘子从顶部进出栈。不是中间,也不是结束;只是顶部。一个堆栈。我只能Push()和Pop()板,这使得代码更加简单和清晰。
或者,想象一下用 C# 等价的亚原子粒子进行编码 - 泛型集合或泛型 IEnumerable 等。我最终使用通用实用程序方法和属性,其通用名称具有多变量数量的参数,这总体上掩盖了以下事实:我正在堆放盘子。
Ideally you use, or create as needed, classes that reflect how things work in the real world, the things you are modeling in code. Such classes give us a level of abstraction so we can code in terms of what we are modeling/simulating. Additionally when coding some complex thing, using a familiar paradigm helps. To wit: Oh, this Fuzzinator class uses a Stack. I know what a stack is and how it works.
Second, that higher-level-of-abstraction class gives us code that works (we assume the .NET framework was tested) and saves us the time and pain of re-inventing the wheel.
Third, the code is easier to read, easier to understand, easier to change and so on. It is more maintainable.
Using classes with more refined functionality helps limit how we might screw up in using it.
On the whole your application is simply better when it's coded at appropriate levels of abstraction.
Stack is one of these classes.
My HP-41X calculator does its arithmetic using a stack. This way of calculation is called RPN - Reverse Polish Notation.
If I were simulating a cafeteria the Stack would be perfect for that stack of plates. Plates get on and off the stack from the top. Not the middle, not the end; just the top. A Stack. I can only Push() and Pop() plates which makes the code more simple and clear.
Alternatively, imagine coding with the C# equivalent of sub-atomic particles - generic collection or generic IEnumerable, etc. I end up using general utility methods and properties with general names with multi-variable numbers of parameters which in the aggregate obscure the fact that I'm stacking plates.
深度优先树遍历。与队列相反,用于广度优先树遍历。
管理在用户浏览时向用户呈现不同的屏幕。显示屏幕会将其推入堆栈,“返回”会将其弹出。绘制顶部屏幕。
当您想要一个可以添加内容并始终知道何时获取内容的集合时,它是最近添加的。
实现撤消/重做功能。
Depth first tree traversal. As opposed to a queue, for breadth first tree traversal.
Managing presenting different screens to a user as they navigate around them. Showing a screen pushes it to the stack, going 'back' pops it. Draw the top screen.
When you want a collection where you can add things and always know when you get something out it's the most recently added.
Implementing Undo/Redo functionality.
深度优先搜索(DFS)是使用堆栈的一个很好的现实示例。
http://www.cs.toronto.edu/~heap/270F02/node36 .html
Depth First Search (DFS) is a good real-world example of the use of a stack.
http://www.cs.toronto.edu/~heap/270F02/node36.html
如果您进行表达式求值和语法解析,堆栈可能是有用的数据结构。
If you do expression evaluation and syntax parsing, stack could be useful data structure.
这是我使用 Stack 的一种方式:
我有一个类似向导的页面,其中有 5 个用户控件需要按特定顺序显示和处理,并且用户应该能够在任何时候按顺序返回到最后一页。
我使用基于堆栈的状态机来跟踪用户通过向导的进度。
每次他们向前移动时,我都会将状态机的状态推入会话存储的堆栈中,如果他们请求返回,我会弹出顶部值并将机器设置为新的顶部堆栈值。 (反过来,显示并加载适当的控件)
还有一个:
我必须为一些非常自定义的服务器应用程序构建一个安装应用程序。我最终所做的是将安装的每个步骤分解为自己的通用组件,即复制文件的组件、写入注册表值的组件等。每个组件都必须执行以下操作:执行安装操作、撤消安装操作。
安装的每一步,组件都会被推入堆栈中。
现在,每当出现错误时,我们只需将每个组件从堆栈中弹出,然后运行撤消操作即可为我们提供细粒度的安装事务。
堆栈是你的朋友!
Heres one way I've used Stack:
I have a wizard like page where there are 5 user controls that need to be dispalyed and processed in a specific sequence, and the user should be able at any point to return to the last page in order.
I use a stack based state machine to track the users progress through the wizard.
Each time they move forward, I push the state of the state machine into a session stored stack, and if they request to go back, I pop off the top value and set the machine to the new top stack value. (Which in turn, displays and loads the proper control)
One more:
I had to build an install application for some very custom server applications. What I ended up doing was breaking each step of the install into its own generic component, ie, a component to copy a file, a component to write a registry value, ect. Each compontent had to methods: Do the install action, Undo the install action.
Each step of the install, the component is pushed into a stack.
Now, at any time I have an error, we just pop each component back off the stack, and run the undo action giving us fine grained install transactions.
Stack's are your friend!
通过控制堆栈内外的局部变量,您可以更轻松地将递归方法重写为迭代方法。查看 Jon Skeet 使用堆栈的排序 此处。
You can rewrite recursive methods as iterative counterparts much easier by controlling the locals on and off the stack. Check out Jon Skeet's sort using the stack here.
将表达式从中缀表示法转换为前缀表示法时,堆栈非常有用。例如:
a + b
到(+ ab)
stacks are useful when converting an expression from infix notation to prefix notation. For example:
a + b
to(+ a b)
堆栈和队列在内部使用数组。如果您以聪明的方式使用数组,那么您很可能已经像时尚一样在堆栈或队列中使用了它们。通常您需要在堆栈和队列之间做出选择。
需要 Stack 的典型示例是深度优先搜索。如果将集合更改为队列,则您已经实现了广度优先搜索。
另一个例子是重型多线程,如果处理顺序不相关,则可以通过堆栈在生产者和消费者之间传递数据。其背后的基本原理是,如果要处理大量数据,CPU 最好使用最新添加的数据块在另一个线程上进行进一步处理,以获得更好的缓存局部性。
名单还在继续......
Stack and Queue use internally an array. If you were using arrays in smart ways the chances are good that you have used them in a stack or queue like fashion already. Usually you need to decide between Stack and Queue.
A typical example where a Stack is needed is depth first search. If you change the collection to a queue you have implemented a breadth first search.
Another example is heavy multithreading where you pass data between a producer and consumer via a stack if the processing order is not relevant. The rationale behind this is that if much data is going to be processed it is better for the CPU to use the latest added data chunk for further processing on the other thread to get better cache locality.
And the list goes on ....
堆栈经常用于文本解析算法,例如“4+5+6”的评估。有关使用堆栈解析文本的应用程序的实际示例,请参阅 HTMLAgilityPack。该组件用于解析 HTML,它包含源代码,因此您可以了解如何以及在何处使用堆栈...
Stacks are frequently used in text parsing algorithms, such as the evaluation of "4+5+6". For a real-world example of an application that uses stacks to parse text, see HTMLAgilityPack. This component is used to parse HTML, and it includes the source code, so you can see how and where stacks are used...
我想说的是,如果你正在建模概念上是堆栈的东西。假设您正在建模一个小而深的抽屉,并且您正在将书籍放入抽屉中。这将遵循“先进后出”范例,这通常是堆栈的要点。
您没有书籍列表或某种枚举 - 您有它们的特定顺序......即,与它们添加的顺序相反。
I'd say if you were modeling something that is conceptually a stack. Say you're modeling a small, but deep drawer and you're putting books in the drawer. This will follow a "first in, last out" paradigm, which is the point of a stack in general.
You don't have a list of books or some kind of enumeration - you have a specific ordering of them... namely, the opposite of the order in which they were added.
Stack
的功能确实看起来像是List
的子集(带有一些重命名的方法),所以我同意它看起来并不是最重要的本身很有用的收藏。当在算法内部使用时,List
可以轻松替代它,即使这可能不太惯用。仅当堆栈行为公开时才需要强制执行。但在这种情况下,在内部集合上公开某种包装器通常是一个更好的主意,因此它似乎对此也不是很有用。我当然会看到 接口,但对于普通集合类
IStack
IStackStack
来说就不那么重要了。我的结论是,我不会在框架中包含
Stack
类,而只包含IStack
接口。在我看来,BCL 的系列通常看起来并不是经过深思熟虑的。另一方面,ConcurrentStack 似乎更有用。
Stack<T>
's functionality really seems like a subset ofList<T>
(with a few renamed methods), so I agree it doesn't seem like the most useful collection by itself. When used internally in an algorithm,List<T>
can easily substitute for it, even if that may be slightly less idiomatic.Enforcing stack behavior is only necessary if it is exposed publicly. But it that case it's usually a better idea to expose some kind of wrapper over the internal collection, so it doesn't really seem very useful for that either.I'd certainly see use for a
IStack<T>
interface, but not so much for a plain collection classStack<T>
.My conclusion is that I wouldn't have included a
Stack<T>
class in the framework, just aIStack<T>
interface. The BCL collections generally don't look very well thought out to me.ConcurrentStack<T>
on the other hand seems much more useful.跟踪浏览器历史记录是堆栈的一个用途。此外,“撤消”编辑等。
类似地,一些仓库控制系统使用堆栈和队列来管理需要选择装运的物品的顺序。
Keeping track of Browser History is a use for the stack. Also, "undo" for edits, etc.
Similarly, some warehouse control systems use stacks and queues for managing the order in which items need to be selected for shipments.