这是我想知道的更一般性问题的一个小前奏:
我最近正在编写一个编程挑战,你应该编写一个方法来检查给定String中括号的平衡。该方法应该接受一个String并返回第一个额外')'或'('括号所在的索引,或者如果它们相等则返回String的长度。一些样本输入将如此:“)() asdf)))“ - 0; “((((asdf)))” - 0;“((((asdf))” - 1;“(ab)(((cd)(asdf)” - 5。
我开始尝试为括号的每个方向创建一个List,它将所有这些的索引存储在String中。然后我会遍历String中的每个字符,如果匹配则将其索引添加到任一列表中,并检查它们是否已经不匹配。这种策略适用于某些情况,但某些情况仍然失败。感觉卡住了,我检查了挑战中的其他一些答案,并看到他们使用堆栈存储左括号的索引,他们会在必要时推送并弹出。这种方式工作得更好,更好,我觉得有点尴尬,因为我没有想到它。
这让我想到了我的问题......我如何知道何时使用Stack而不是其他各种收藏?有什么常见的事情可以让我使用Stack而不是任何其他Collection?
我知道Stacks是如何工作的,并且已经在一些教程中使用过它们,但是从来没有真正发现自己在现实世界中使用过它们......在看到它们带来的挑战所带来的简单性之后,让我觉得我有错过了一些制作更简单/更好代码的机会。
答案 0 :(得分:1)
何时需要使用LIFO(后进先出) 比如在调用函数或使用后缀表示法时。
答案 1 :(得分:1)
就像其他人所说的那样,当您需要收藏品具有后进先出(LIFO)行为时,会使用堆栈。无论何时处理"最顶层的信息,这都可以表现出来。或者"最新的"某事。
你谈到的例子是一个很好的例子,为了最有效地处理括号组,你将左括号存储在一个集合中,并在你遇到右括号时删除最近的左括号
堆栈也可用于某些树/图遍历算法。深度优先方法将使用堆栈来存储仍然需要遍历的节点列表,因为使用堆栈结合一致的插入模式具有搜索树的固有属性。深度超过他们的广度。 (另一方面,广度优先遍历算法使用队列代替。)
另一种可能的用途是一副纸牌。对于大多数游戏而言,你并不关心某个地方中心的内容。当玩家需要一张牌时,他们只需从顶部取出一张牌。由于这完全模仿了Stack的行为,因此Stack可能是这类应用程序的可能考虑因素。 (毕竟,"套牌"只是一堆牌。)
还有许多其他应用程序。他们的共同点是,当你想要最上面的项目或最新的集合项目时,它们可以工作。了解您的特定应用程序是否会从Stack中获益只需要了解如何识别这些场景的经验。
编辑:哦,当然还有.NET用于方法范围和临时变量的 堆栈。它与数据结构共享其名称并非巧合。当在方法中声明变量时,它的内存分配将添加到堆栈的末尾。然后当方法返回并且变量超出范围时,该内存将从堆栈中弹出并传递给垃圾收集器。
答案 2 :(得分:1)
堆叠的另一个好例子是当你输入一些你最终会离开的“背景”时。更重要的是,如果你存储的信息只在两个时刻之间有效,并且一旦离开这个“背景”就会被遗忘。
在括号示例中,只要您匹配(
并在匹配)
时“离开”括号块,就会“输入”。当你在括号内时,你需要记住起始(
的位置(如果它没有匹配的)
),但是一旦找到匹配的)
,你就会忘记资讯
答案 3 :(得分:0)
以下是从SO问题中复制的所选答案:When to use the Stack collection in C#?
P.S。我不是在抄袭。我写了这个答案。
理想情况下,您可以根据需要使用或创建反映现实世界中工作方式的类,以及您在代码中建模的内容。这些类为我们提供了抽象级别,因此我们可以根据我们的建模/模拟进行编码。另外,在编写一些复杂的东西时,使用熟悉的范例会有所帮助。即:哦,这个Fuzzinator类使用Stack。我知道堆栈是什么以及它是如何工作的。
其次,更高级别的抽象类为我们提供了有效的代码(我们假设.NET框架已经过测试)并为我们节省了重新发明轮子的时间和痛苦。
第三,代码更易于阅读,更易于理解,更易于更改等。它更易于维护。
使用具有更多细化功能的类有助于限制我们使用它的方式。
总的来说,当你的应用程序以适当的抽象级别进行编码时,它的应用程序会更好。
Stack是其中一个类。
我的HP-41X计算器使用堆栈进行算术。这种计算方式称为RPN - 反向波兰表示法。
如果我正在模拟一个自助餐厅,那么Stack将非常适合那些盘子。板从顶部进出堆叠。不是中间,不是结束;只是顶部。一堆。我只能使用Push()和Pop()板,这使得代码更加简单明了。
或者,想象使用C#等效的子原子粒子进行编码 - 通用集合或通用IEnumerable等。我最终使用通用实用方法和属性,通用名称具有多变量数量的参数,这些参数总体上模糊了事实上,我正在堆积盘子。