ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
### 6.5.2 堆栈 堆栈(stack)也是一种数据集合体,其中的数据构成一种具有“后进先出(LIFO)”性 质的数据结构,即最后加入堆栈的数据总是首先取出。现实中堆栈的例子俯拾皆是,例如碗橱里的一摞碗、纸箱里的一摞书、弹夹中的子弹等等(图 6.10),他们共同的特点是先放进 去的东西垫底,最后放进去的东西在顶上,而取东西的顺序正好相反。 ![](https://box.kancloud.cn/2016-02-22_56cafce31b248.png) 图 6.10 现实中的堆栈例子 如果忽略各种具体堆栈中无关紧要的成分,如所堆放的东西(碗、书、子弹)、容器(纸箱、碗橱、弹夹)和放入/取出的具体实现(人工、机械),那么我们可以抽象地定义堆栈。 所谓堆栈,是以如下两个操作进行处理的数据结构: + push(x):在堆栈顶部推入一个新数据 x,x 即成为新的栈顶元素; + pop():从堆栈中取出栈顶元素,显然被取出的元素只能是最后加入堆栈的元素。 为了完善这两个操作,还需提供一些辅助操作,如: + isFull():检查堆栈是否已满。如果堆栈具有固定大小,那么满了之后是无法执行 push()的; + isEmpty():检查堆栈是否为空。如果堆栈是空的,那么 pop()操作将出错。 此前介绍的数据类型大多是具体的,即它们的实现方式是给定的,例如 int 类型是以 4 个字节来表示,字符串类型是特定编码的字节串等等。而现在我们所讨论的堆栈则是抽象数 据类型,因为我们只规定了堆栈的操作方式,并没有规定操作的具体实现方式。 在具体应用中,可以采用多种不同的方式来实现堆栈这个抽象数据类型。例如,可以采 用列表来实现堆栈。令列表 stack 是存放数据的堆栈,按照堆栈的要求,对 stack 只能执行 push 和 pop 操作,不能像列表那样可以随机存取任何一个元素。假设以列表头为栈底,以 列表尾为栈顶,那么向堆栈中放入元素就只能在尾部添加,Python 列表对象提供的 append 方法正好提供堆栈所需的功能,因此可以用 append 来实现 push(),形如: ``` def push(stack,x): stack.append(x) ``` 另外,Python 列表对象的 pop()方法的功能是取出列表的最后一个元素,恰好符合堆栈的 pop()方法的要求,因此可以这样实现堆栈 pop 操作: ``` def pop(stack): return stack.pop() ``` 为了防止从空堆栈中取数据的错误,我们定义一个检测堆栈是否为空的函数: ``` def isEmpty(stack): return (stack == []) ``` 利用上述以列表实现堆栈的技术,程序 6.5 首先通过用户输入数据创建一个堆栈,然后 再逐个取出堆栈成员。输出恰好是输入的逆序,这是由堆栈的 LIFO 性质决定的。可见,利 用堆栈来逆序显示列表数据是非常容易的。 【程序 6.5】stack.py ``` def push(stack,x): stack.append(x) def pop(stack): return stack.pop() def isEmpty(stack): return (stack == []) def main(): stack = [] print "Pushing..." x = raw_input("Enter a string: ") while x != "": push(stack,x) x = raw_input("Enter a string: ") print "Popping..." while not isEmpty(stack): print pop(stack), main() ``` 下面是程序 6.5 的一次执行情况: ``` Pushing... Enter a string: 1st Enter a string: 2nd Enter a string: 3rd Enter a string: 4th Enter a string: Popping... 4th 3rd 2nd 1st ``` 堆栈在计算机科学中非常有用,一个常见的用例是实现表达式的计算。 读者都熟悉算术表达式的中缀形式,但在用计算机处理表达式时常将表达式写成后缀形式,例如“1 + 2”可写成“1 2 +”、“3 + 4 * 5”可写成“3 4 5 * +”。后缀形式的表达式可以 利用堆栈来非常方便地求值,算法如下: 1\. 扫描后缀形式的表达式,每次读一个符号(运算数或者运算符); 2\. 如果读到的是运算数,则 push 到堆栈中;如果读到的是运算符,则从堆栈 pop 两个运算 数,并执行该运算,然后将运算结果 push 入堆栈; 3\. 重复 1、2,直至到达表达式尾。这时堆栈中应该只剩一个运算数,就是表达式的结果值。 图 6.11 显示的是“3 4 5 * +”的计算过程。 ![](https://box.kancloud.cn/2016-02-22_56cafce334c11.png) 图 6.11 利用堆栈对后缀表达式求值 以上求值部分非常容易实现,但要想对用户输入的中缀形式的算术表达式进行求值,还 需要先对输入进行语法分析,拆分出运算符和运算数,然后改成后缀形式。这部分编程有点 复杂,所以在此我们就不实现这个程序了。有兴趣的读者可以尝试解决这个问题。