作用:
栈的引入简化了程序设计的问题,划分了不同的关注层次,使得思考范围缩小,更加聚焦于要解决的问题核心。反之,像数组等,因为要分散精力去考虑数组的下标增减等细节问题,反而掩盖了问题的本质。
应用一:递归,斐波那契数列
/* 斐波那契序列的两种表示 */
#include<stdio.h>
/* 迭代表示法 */
/* 斐波那契序列的两种表示 */
#include<stdio.h>
/* 迭代表示法 */
void fbi_iterator(int len);
/* 递归表示法 */
int fbi_recur(int len);
int main(void)
{
fbi_iterator(10);
for(int i=0;i<10;i++)
{
printf("%d,",fbi_recur(i));
}
return 0;
}
void fbi_iterator(int len)
{
int a=0,b=1;
printf("%d,",a);
printf("%d,",b);
for(int i=2;i<len;i++)
{
int tmp = b;
b = a+b;
a = tmp;
printf("%d,",b);
}
printf("\n");
}
int fbi_recur(int index)
{
if(index<2)
{
return index==0?0:1;
}
return fbi_recur(index-1)+fbi_recur(index-2);
}
把一个直接调用自己或通过一系列语句间接地调用自己的函数,称为递归函数。
每个递归定义必须至少有一个条件,当满足时退出。
迭代和递归的区别是:迭代使用的是循环结构,递归使用的是选择结构。递归能使程序的结构更清晰简洁更易理解。但大量的递归调用会建立函数的副本,会耗费大量的时间和内存。而迭代不会。
递归过程的退回顺序是它前行顺序的逆序。这种存储某些数据,并在后面又以存储的逆序恢复这些数据,以提供之后使用的需求,即符合栈这种数据结构。
应用二:四则运算——后缀(逆波兰)表示法
对于一个四则去处表达式:9 + (3-1)*3+10/2,使用后缀表达式 9 3 1 - 3 * + 10 2 / +,之所以叫它后缀表达式是因为所有的符号都是在要运算的数字后面出现,相似的,普通的表达式称为中缀表达式。
对于后缀表达式:9 3 1 - 3 * + 10 2 / +
求值规则:从左到右遍历表达式的每个数字和符号,遇到是数字就进栈,遇到是符号,就将处于栈顶的两个数字出栈进行运算,运算结果进栈,一直到最终获得结果。
即9、3、1进栈,然后 -出现时,将3 1出栈,即3-1=2,将2进栈,然后是将3进栈,然后有*,即2*3=6,将6进栈,然后是+即将9+6=15进栈,然后是10、2进栈,然后是符号/,即10/2=5进栈,然后是+号即15+5=20,20进栈再出栈。
对于中缀表达式:9 + (3-1)*3+10/2
转化规则:从左到右遍历中缀表达式的每个数字和符号,苦是数字就输出,即成为后缀表达式的一部分;若是符号,则判断其与栈顶符号的优先级,是右括号或优先级低于栈顶符号(乘除优先加减)则栈顶元素依次出栈并输出,并将当前符号进栈,一直到最终输出表达式为止。
即9输出,+、(进栈,3输出,-进栈,1输出,)时将-输出,即9 3 1 -然后是*(*优先级高于栈顶符号+因此入栈),然后是3输出,即9 3 1 - 3然后是+,+低于*,因此出栈即 9 3 1- 3 *+,并将当前+的入栈,然后是10输出,然后是/进栈,然后是2输出,即9 3 1 - 3 * +10 2 然后全部出栈 9 3 1 - 3 *10 2 / +