数据结构-栈(5)

栈的作用

栈的引入简化了程序设计的问题,划分了不同关注层次,使得思考范围缩小,更加聚焦于我们要解决的问题核心。

反之,像数组等,要分散精力去思考数组的下标增减等细节问题,反而遮盖了问题的本质。

栈的应用-递​归

栈的一个很重要的应用: 在程序设计语言中实现了递归。

经典的递归例子: 斐波那契数列 (Fibonacci)。

前面相邻两项之和,构成了后一项

F(n) = {

0,当n=0

1, 当n=1

F(n-1)+F(n-2),当n>1

}

我们把一个直接调用自己或通过一系列的调用语句间接地调用自己的函数,称为递归函数。

每个递归定义必须至少有一个条件,满足时递归不再进行,即不再引用自身而是返回值退出。

迭代和递归的区别是: 迭代使用的是循环结构,递归使用的是选择结构。

递归代码的结构更清晰,更简洁,更容易让人理解,但是大量的递归调用会建立函数副本,会耗费大量的

时间和内存。迭代则不需要反复调用函数和占用额外的内存。

递归过程退回的顺序是它前行顺序的逆序。

在前行阶段,对于每一层递归,函数的局部变量,参数值以及返回地址都压入栈中。

在退回阶段,位于栈顶的局部变量,参数值和返回地址被弹出,用于返回调用层次中执行代码的其余部分,

也就是恢复了调用的状态。

栈的应用-四则运算表达式求值

​后缀(逆波兰)表示法定义

示例: 9 + (3 - 1) * 3 + 10 /2 = 20

后缀表达式: 9 3 1 - 3 * + 10 2 / +

所有的符号都是在要运算数字的后面出现。

规则: 

从左到右遍历表达式的每个数字和符号,遇到数字就进栈,遇到符号就将处于栈顶两个数字出栈,

然后运算,运算结果进栈,一直到最终获得结果。

计算过程:

    1. 9、3、1 先进栈 ,当前栈数据 1,3,9
    2. 发现符号 - ,1、3 出栈 , 1作为减数,3作为被减数,运算 3-1 = 2 , 2进栈 ,当前栈数据 2, 9
    3. 3进栈,当前栈数据3,2,9
    4. 发现符号 * ,3,2出栈,运算2 * 3 = 6,6进栈,当前栈数据6,9
    5. 发现符号 + ,6,9出栈,运算9 + 6 = 15,15进栈,当前栈数据15
    6. 10、2进栈,当前栈数据2, 10, 15
    7. 发现符号 / , 2, 10出栈 ,运算10/2 = 5, 5进栈, 当前栈数据5, 15
    8. 发现符号 + , 5, 15出栈, 运算15+5=20,20进栈,当前栈数据20
    9. 结果20出栈,栈变为空。

9 + (3 - 1) * 3 + 10 /2 叫做中缀表达式。因为所有的运算符号都在两数字中间。

中缀表达式转化成后缀表达式的规则:

从左到右遍历中缀表达式的每个数字和符号,若是数字就输出, 即成为后缀表达式的一部分;

如果是符号,判断其与栈顶符号的优先级,如果是右括号或优先级低于栈顶符号(乘除优先加减)

则栈顶元素依次出栈输出,并将当前符号进栈,一直到最终输出后缀表达式为止。

计算过程:

a. 输出9,符号+进栈, 当前输出9, 当前栈数据 +

b. 符号 ( 只是左括号,还未配对,进栈,当前输出9,当前栈数据 ( +

c. 输出3,接着 - 进栈, 当前输出9、3 ,当前栈数据 - ( +

d. 输出1,后面是符号 ) , 需要匹配 前面的左括号 ( , 栈顶依次出栈,并输出,直到 ( 出栈位置。

因此当前输出 9、3、1、-, 当前栈数据 +

e. 符号* 进栈,输出3,当前输出 9、3、1、- 、3, 当前栈数据 *、 +

f. 符号+ 优先级比栈顶符号 * 低,* 出栈, 当前输出 9、3、1、- 、3、*、+, 当前栈数据 +

g. 输出10, 符号 / 进栈,当前输出 9、3、1、- 、3、*、+、10, 当前栈数据/、 +

h. 输出2, 当前输出9、3、1、- 、3、*、+、10、2, 当前栈数据/、 +

i. 符号/ + 出栈, 当前输出9、3、1、- 、3、*、+、10、2、/、+, 当前栈数据

计算最重要的两步:

  1. 将中缀表达式转化为后缀表达式(栈用来进出运算的符号)。
  2. 将后缀表达式进行运算得出结果(栈用来进出运算的数组)。

猜你喜欢

转载自www.cnblogs.com/1994jinnan/p/13369335.html