3.5讲栈的应用
栈的应用举例
栈结构所具有的“ 后进先出”特性,使得栈成为程序设计中的有用工具。本节将讨论栈应用的两个典型例子:
1、括号匹配问题
假设表达式中包含三种括号:
圆括号、方括号和花括号,它们可互相嵌套,如 ( [ { } ] ( [ ] ) )或( { ( [ ] [ ( ) ] ) } )等均为正确的格式,而 { [ ] } ) }或 { [ ( ) ] 或 ( [ ] }均为不正确的格式。
在检验算法中可设置一个栈,每读入一个括号,若是左括号,则直接入栈,等待相匹配的同类右括号;若读入的是右括号,且与当前栈顶的左括号同类型,则二者匹配,将栈顶的左括号出栈,否则属于不合法的情况。
另外,如果输入序列已读尽,而栈中仍有等待匹 的左括号,或者读入了一个右括号,而栈中已无等待匹配的左括号,均属不合法的情况。当输入序列和栈同时变为空时,说明所有括号完全匹配。
括号匹配算法
void BracketMatch(char *str) /* str[]中为输入的字符串,利用堆栈技术来检查该字符串中的括号是否匹配*/
{
Stack S;
int i;
char ch;
InitStack(&S);
For(i=0; str[i]!=’\0’; i++) /*对字符串中的字符逐一扫描*/
{
switch(str[i])
{
case ‘(‘:
case ‘[‘:
case ‘{‘:
Push(&S,str[i]);
break;
case ‘)’:
case ‘]’:
case ‘}’:
if(IsEmpty(&S))
{
printf("\n 右括号多余!");
return;
}
else
{
GetTop (&S,&ch);
if(Match(ch,str[i])) /*用 Match 判断两个括号是否匹配*/
Pop(&S,&ch); /*已匹配的左括号出栈*/
else
{
printf("\n 对应的左右括号不同类!");
return;
}
}
}/*switch*/
}/*for*/
if(IsEmpty(&S))
printf("\n 括号匹配!");
else
printf("\n 左括号多余!");
}
表达式求值
表达式求值是高级语言编译的一个基本问题,是栈的典型应用实例。
任何一个表达式都是由运算数(operand)、运算符(operator)和界限符(delimiter)组成的。
运算数既可以是常数, 也可以是被说明为变量或常量的标识符;运算符可以分为算术运算符、关系运算符和逻辑运 算符三类;基本界限符有左右括号和表达式结束符等。
仅讨论无括号算术表达式求值的求值问题。 由于某些运算符可能具有比别的运算符更高的优先级,因此表达式求值不可能严格地从左到右进行,如下图 所示,其中↑为幂运算,#是表达式结束符,这是为运算方便引入的一个特殊符号。
为了正确的处理表达式,使用栈来实现正确的指令序列是一个重要的技术。下面以无括号表达式为例进行说明。
【算法思想】
(1)规定运算符的优先级表
(2)设置两个栈:OVS(运算数栈)、OPTR(运算符栈)
(3)自左向右扫描,进行如下处理:
①遇到运算数则进 OVS 栈;
②遇到运算符则与 OPTR 栈的栈顶运算符进行优先级比较:
- 如果当前运算符>OPTR 栈顶运算符,则当前运算符进 OPTR 栈;
- 如果当前运算符≤OPTR 栈顶运算符,则 OPTR退栈一次,得到栈顶运算符θ,OVS 连续退栈两次,得到运算数 a、运算数 b,对 a,b 执行θ运算,得到结果 T(i),将 T(i) 进OVS 栈。
例 3-1 在实现 A/B↑C+DE 的运算过程中,栈区变化情况如图 3.9 所示。为运算方便,在表达式后面加上一个结束符#,并将其视为一个优先级最低的特殊运算符,所以实际输入 的表达式为:A/B↑C+DE#。
【算法描述】无括号算术表达式处理算法
int ExpEvaluation()
/*读入一个简单算术表达式并计算其值。operator 和 operand 分别为运算符栈和运算数栈, OPS 为运算符集合*/
{
InitStack(&operand);
InitStack(&operator);
Push(&operator,'#');
printf("\n\nPlease input an expression (Ending with #) :");
ch=getchar();
while(ch!='#'||GetTop(operator)!='#') /* GetTop()通过函数值返回栈顶元素*/
{
if(!In(ch,OPS))
/*不是操作符,是操作数*/
{
n=GetNumber(ch);
push(&operand,n);
}
else
switch(Compare(ch, GetTop(operator)))
{
case '>':
Push(&operator,ch);
ch=getchar();
break;
case '=':
case '<':
Pop(&operator,&op);
Pop(&operand,&b);
Pop(&operand,&a);
v=Execute(a,op,b); /* 对 a 和 b 进行 op 运算 */
Push(&operand,v);
break;
}
}
v=GetTop(operand);
return (v);
}