我们已经阅读或了解了堆栈类,但是我们中的许多人可能从未找到使用LIFO对象的理由。我很想知道使用这个对象的真实解决方案及其原因。
http://msdn.microsoft.com/en-us/library/system.collections.stack.aspx
我最近看到一个例子,程序员在遍历分层数据源时使用堆栈来跟踪他当前的位置。当他向下移动层次结构时,他将位置标识符推到堆栈上,当他向后移动时,他将物品从堆栈中弹出。我认为这是一种非常有效的方式来跟踪他在乳房等级中的当前位置。我以前从未见过这个。
其他人有任何例子吗?
答案 0 :(得分:17)
我用它们来跟踪撤消和重做动作。
我使用这样的界面:
interface ICommand
{
void Execute();
void Undo();
string Description { get; }
}
撤消和重做都属于Stack<ICommand>
类型。然后我为给定的动作创建一个具体的类。在类的构造函数中,我传递了我需要保留的任何信息。 Execute
最初执行操作,并重做它;显然,Undo
撤消了它。它的工作原理如下:
我发现你必须要小心你正在彻底解决所做的事情。例如,假设您有一个包含两个列表框的UI,每个列表框中都有五个项目。您的操作可能是单击按钮将左侧列表中的所有内容移动到右侧列表(因此它现在有10个,左侧列表为零)。
撤消操作不将所有内容移回;撤消动作只是向后移动你实际移动的五个,而离开其他动作。
答案 1 :(得分:7)
堆栈用于表达式评估(例如在计算器或编译器中),首先将表达式转换为RPN,然后使用简单的堆栈计算机进行评估。当您看到操作数将其推入堆栈时,其工作方式如下。当您看到操作符弹出操作数并进行评估时。
example
5 6 + 3 *
steps-
see 5 push 5
see 6 push 6
see + pop 2 times and apply + get 11 push 11
see 3 push 3
see * pop 2 times and apply get 33 push 33
result is on the top of the stack.
答案 2 :(得分:5)
如果您有递归算法,通常可以使用堆栈重写它们。 (因为递归算法隐式已经使用了堆栈)
答案 3 :(得分:3)
您可以验证需要平衡令牌的字符串输入。想想LISP:
(+ (- 3 2) (+ (+ 4 5) 11))
当你遇到开场白时:
stack.Push("(")
然后当你遇到一个结束时:
stack.Pop()
如果完成后你的筹码中还剩下任何令牌,那就不平衡了。
您可以获得更好的功能,并在HTML等输入中验证正确的嵌套。在一个高度设计的例子中:
//see opening body
stack.Push("body")
//see opening div
stack.Push("div")
//see opening p
stack.Push("p")
///see closing div
if(!stack.Pop().Equal("div")){
//not balanced
}
答案 4 :(得分:1)
我已经使用堆栈进行图像处理,其中必须在URL中指定“处理语言”。基于堆栈的表单允许您以易于解析,易于思考的形式表示操作树。
请参阅:
http://www.hackification.com/2008/10/29/stack-based-processing-part-1/
和
http://www.hackification.com/2008/10/29/stack-based-processing-part-2/
答案 5 :(得分:1)
在一个实际使用中,postscript生成器类具有“current_font”状态,用作绘制文本的任何操作的字体。有时函数需要暂时设置字体,然后让它恢复原样。我们可以使用临时变量来保存和恢复字体:
def draw_body
old_font = ps.get_font
ps.set_font('Helvetica 10')
draw_top_section
draw_bottom_section
ps.set_font(old_font)
end
但是你第三次这样做,你会想要不再重复自己。所以让我们让ps对象为我们保存和恢复字体:
class PS
def save_font
old_font = get_font
end
def restore_font
set_font(old_font)
end
end
现在来电者变成:
def draw_body
ps.save_font
ps.set_font('Helvetica 10')
draw_top_section
draw_bottom_section
ps.restore_font
end
这很好用,直到我们在draw_page调用的子程序中使用相同的模式:
def draw_top_section
ps.save_font
ps.set_font('Helvetica-bold 14')
# draw the title
ps.restore_font
# draw the paragraph
end
当draw_top_section调用“save_font”时,它会破坏draw_page保存的字体。是时候使用堆栈了:
def PS
def push_font
font_stack.push(get_font)
end
def pop_font
set_font(font_stack.pop)
end
end
在来电者中:
def draw_top_section
ps.push_font
ps.set_font('Helvetica-bold 14')
# draw the title
ps.pop_font
# draw the body
end
还有进一步的改进,例如让PS类自动保存和恢复字体,但没有必要进入那些以查看堆栈的值。
答案 6 :(得分:0)
我发现堆栈在多线程应用程序中非常有用,能够以反时限方式跟踪状态......
每个线程都会在同步的共享堆栈中放置一条状态消息,并且您对所发生的事情有一种“痕迹”。
不是.NET但是......这是我的意见=)
答案 7 :(得分:0)
这是深度比较的实现,其中Stack用于跟踪当前被比较对象的路径。
C# implementation of deep/recursive object comparison in .net 3.5
我也在类似的代码类型中使用它,为特定的xml节点生成xpath语句。
答案 8 :(得分:0)
提供一个具体的例子来说明其他人正在评论的内容:要实现一个Z机器解释器,应该使用三个不同的堆栈。一个调用堆栈,以及几种不同类型的对象堆栈。 (具体要求可以找到here.)请注意,与所有这些示例一样,虽然使用堆栈并非严格必需,但它是显而易见的选择。
调用堆栈跟踪对子例程的递归调用,而对象堆栈用于跟踪内部项目。
答案 9 :(得分:0)
在计算机图形类(不是.NET)中,我们使用Stack来跟踪屏幕上绘制的对象。这允许每次刷新时在屏幕上重绘所有对象,并跟踪每个对象的顺序或“z层”,因此当它们移动时,它们可以与其他对象重叠。