栈是一种重要的数据结构
从概念上讲,栈是一种只能在一端进行插入和删除操作的特殊线性表。它就像一个一端封闭的盒子,元素只能从开口的一端进出。把元素插入栈的操作叫入栈,从栈中删除元素的操作叫出栈。这种特殊的操作规则使得栈具有后进先出(LIFO,Last - In - First - Out)的特性。
例如,有一摞盘子,每次只能从最上面放盘子(入栈)或者取盘子(出栈),最后放在上面的盘子会最先被取走。
在实际应用中,栈有多种实现方式。可以用数组来实现,这种方式相对简单,需要记录栈顶元素的位置;也可以用链表来实现,这样在动态分配内存等方面更具灵活性。栈在计算机科学中有许多用途,比如函数调用时的栈帧(用来存储函数的局部变量、参数等信息)、表达式求值(例如将中缀表达式转换为后缀表达式)、浏览器的后退功能(浏览的网页依次入栈,点击后退就出栈)等。
以下是用栈来解决的经典问题:
1. 括号匹配
- 问题描述:在一个表达式中,有多种括号,如小括号"()"、中括号"[]"、大括号"{}",需要判断这些括号是否匹配正确。例如"{[()]}"是匹配的,而"{[(])}"是不匹配的。
- 解决思路:使用栈来处理。遍历表达式,当遇到左括号(如'(''[''{')时就将其入栈。当遇到右括号时,就检查栈顶元素是否与之匹配的左括号。如果是,则将栈顶元素出栈;如果不是,则表达式括号不匹配。最后,如果栈为空,则表达式括号匹配正确,否则匹配错误。
- 函数调用
- 问题描述:在程序执行过程中,当一个函数被调用时,系统需要保存当前函数的执行状态,包括局部变量、返回地址等,当被调用函数执行完毕后,系统要恢复调用函数的执行。
- 解决思路:系统会为每个函数调用创建一个栈帧,并将其压入程序栈中。栈帧中包含了函数的参数、局部变量、返回地址等信息。当函数返回时,栈帧出栈,从而使得程序能够正确地返回到调用点继续执行。
- 逆波兰表达式求值
- 问题描述:逆波兰表达式(后缀表达式)是一种运算符紧跟在操作数之后的表达式。例如,"3 4 +"是一个逆波兰表达式,表示3加4。需要对给定的逆波兰表达式求值。
- 解决思路:使用栈来存储操作数。从左到右扫描表达式,当遇到操作数时,将其入栈;当遇到运算符时,就从栈中弹出两个操作数,进行运算,并将结果重新入栈。扫描完整个表达式后,栈顶元素就是表达式的值。
- 汉诺塔问题
- 问题描述:有三根柱子A、B、C。A柱子上有n个圆盘,圆盘从上到下逐渐增大。要求把所有圆盘从A柱移到C柱,移动过程中可以借助B柱,并且规定每次只能移动一个圆盘,且小圆盘不能放在大圆盘的下面。
- 解决思路:可以通过递归的方法,每次将最大圆盘之上的n - 1个圆盘借助目标柱移到中间柱,再将最大圆盘移到目标柱,最后将n - 1个圆盘从中间柱移到目标柱。递归过程可以用栈来模拟,将每次的操作(移动圆盘的源柱、目标柱)信息压入栈中,然后按照栈的顺序依次执行操作。
栈的实现
如果大家想自己也实现一下的话,我用的是编译器是vs2019。https://gitee.com/tgxqqcom/
这是我的gitee账号链接,上面可能有大家需要的源码,需要自取。