栈的应用
1.数制的转换[问题描述]
十进制数N和其他d进制数的转换时计算机实现计算的基本问题,其解决方法很多,其中一个简单算法基于下列原理:
N=(N div d)*d +N mod d (其中,div为整除运算,mod为求余运算)
例如:(1348)10=(2504)8,其运算过程如下:
N N div 8 N mod 8
1348 168 4165 21 0
21 2 5
2 0 2
假设现要编制一个满足下列要求的程序:对于输入的任意一个非负十进制整数, 打印输出与其的八进制数. 上述计算过程是从低位到高位顺序产生八进制的各个数位; 而打印输出过程, 一般来说, 应从高位到低位进行, 恰好和计算过程相反, 因而我们可以使用栈来解决这个问题.
[算法思想]首先将按照上述计算过程中得到的八进制的各位依次进栈, 然后将栈中的八进制依次出栈输出,输出结果就是该十进制转换得到的八进制.
[算法描述] void conversion()
{ /*对于输入的任意一个非负十进制数,打印输出与其等值的八进制*/
InitStack(S); /*构造空栈*/
cin>>N;
while(N)
{
Push(S,N%8);
N/=8;
}
while(!StackEmpty(S)) /*当栈非空时*/
{
Pop(S,e);
cout<
这是利用栈的后进先出特性的最简单的例子. 栈的引入简化了程序设计的问题, 划分了不同的关注层次, 使思考范围缩小.
2.括号的匹配
[算法思想]
初始化一个空栈, 扫描表达式, 依次读入字符, 直到表达式扫描完或出现错误匹配. 对于读入的每个字符, 分以下几种情况处理:
1) 如果是 "[" 或 "(" , 则将其压入栈;
2) 如果是 ")" , 则根据当前栈顶元素的值分情况考虑. 若栈顶元素是"(", 则匹配成功, 否则为非法情况.
3) 如果是 "]" , 同上面的处理方法, 根据当前栈顶元素的值分情况考虑, 若栈顶元素是 "[", 则匹配成功, 否则为非法情况.
[算法描述]
Status Matching()
{ /*检验表达式中所含括号是否正确匹配,如果匹配,则返回true,否则返回false*/
/*表达式以"#"结束*/
int flag=1; /*标记查找结果以控制循环及返回结果*/
cin>>c; /*读入第一个字符*/
while(c!='#' && flag)
{
switch(c)
{
case '[' || '(': /*若是左括号,则将其压入栈*/
Push(S,c);
break;
case ')': /*若是右括号")",则根据当前栈顶元素的值分情况考虑*/
x=GetTop(S);
if(x == '(') /*若栈非空且栈顶元素是"(",则匹配成功*/
{
Pop(S,x);
}
else /*若栈空或栈顶元素不是"(",则非法*/
{
flag=0;
}
break;
case ']': /*若是右括号"]",则根据当前栈顶元素的值分情况考虑*/
x=GetTop(S);
if(x == '[') /*若栈非空且栈顶元素是"[",则匹配成功*/
{
Pop(S,x);
}
else /*若栈空或栈顶元素不是"[",则非法*/
{
flag=0;
}
break;
} /*switch*/
cin>>c; /*继续读入下一个字符*/
} /*while*/
if(StackEmpty(S) &&flag)
{
return true;
}
else
{
return false;
}
}
3.表达式求值
[问题描述]
表达式求值是程序设计语言编译中的一个最基本问题,其实现是栈应用的又一个典型例子.这里介绍一种简单直观、广义使用的算法,通常称为"算法优先法".
要把一个表达式翻译成正确求值的一个机器指令序列,或者直接对表达式求值,首先要能够正确解释表达式.例如,要对下面的算术表达式求值: 4+2*3-10/5
首先要了解算术四则运算的规则.即:
1)先乘除,后加减;
2)从左算到右;
3)先括号内,后括号外.
由此,这个算术表达式的计算顺序应为 4+2*3-10/5 = 4+6-10/5 = 10-2=8
为实现算符优先算法, 可以使用两个工作栈, 一个称作OPTR, 用以寄存运算符; 另一个称作OPND, 用以寄存操作数或运算结果.
[算法思想]
1)建立并初始化OPTR栈和OPND栈, 将表达式起始符" #" 压入OPTR栈.
2)依次读入表达式中每个字符ch, 循环执行(3)至)(5), 直至求出整个表达式的值为止.
3)取出OPTR的栈顶元素, 当OPTR的栈顶元素和当前读入的字符ch均为 "#" 时, 整个表达式求值完毕, 这时OPND的栈顶元素为表达式的值.
4)若ch不是运算符, 则压入OPND栈, 读入下一字符ch.
5)若ch是运算符, 则根据OPTR的栈顶元素和ch的优先权比较结果, 做不同的处理.
①若是小于栈顶元素, 则ch压入OPTR栈, 读入下一字符ch.
②若是大于栈顶元素, 则弹出OPTR栈顶的运算符, 从OPND栈弹出两个数, 进行相应运算,结果压入OPND栈.
③若是等于, 则OPTR的栈顶元素是 "(" 且ch是 ")" , 这时弹出OPTR栈顶的 "(" ,相当于去掉括号, 然后读入下一字符ch.
[算法描述]
OperandType EvaluateExpression()
{ /*算术表达式求值的算符优先算法.设OPTR和OPND分别为运算符栈和操作数栈*/
/*OP为运算符集合*/
InitStack(OPTR);
Push(OPTR,'#');
InitStack(OPND);
cin>>ch;
while(ch != '#' || GetTop(OPTR)!= '#')
{
if(!In(ch,OP)) /*ch不是运算符则进栈*/
{
Push(OPND,ch);
cin>>ch;
}
else
{
switch(Precede(GetTop(OPTR), ch) ) /*比较OPTR的栈顶元素和ch的优先权*/
{
case'<' : /*当前字符ch压入OPTR栈,读入下字符ch*/
Push(OPTR,ch);
cin>>ch;
break;
case '>': /*弹出OPTR栈顶的运算符进行相应运算,并将运算结果入栈*/
Pop(OPTR,theta);
Pop(OPND,b);
Pop(OPND,a);
Push(OPND,Operate(a,theta,b));
break;
case '=': /*脱括号并接收下一字符*/
Pop(OPTR,x);
cin>>ch;
break;
}
}
}
return GetTop(OPND);
}
算法调用的三个函数需要读者自行补充完成,其中函数In是判定读入的字符ch是否为运算符,Precede是判定运算符栈的栈顶元素与读入的运算符之间优先关系的函数,Operate为进行二元运算的函数.