接着上次的栈的应用一,我们接着说说栈在计算机中的一些具体应用。我们知道计算机的最初的本质工作就是做数学运算,那么计算机是如何读入字符串“9+(3-1)*5+8/2”并计算值的呢?
在此我们就引入了后缀表达式这个新有概念:
后缀表达式更符合计算机运算规则。
那么后缀表达式又是怎样的呢?又如何在c语言中将中缀表达式转换成后缀表达式了?
解决方案:
遍历中缀表达式中的数字和符号
对于数字:直接输出
对于符号:
左括号:进栈
符号:与栈顶符号进行优先级比较
若栈顶符号优先级低:进栈
若栈顶符号优先级不低:将栈顶符号弹出并输出,之后进栈
右括号:将栈顶符号弹出并输出,直到匹配到做括号
遍历结束:将栈中的所有符号弹出并输出
上面给出的解决方案就是中缀表达式转后缀表达式的具体方法.
下面用几个例子来对此作以说明:
实例: 5 + 3 => 5 3 +
1+2*3=>123*+
9+(3-1)5 =>931-5+
那么,在C语言中实现的算法又是怎样的呢?
当然,算法是建立在栈完成的基础上,栈又是基于线性表的。在之前也有贴出过栈与线性表的代码,有兴趣也可以在我的代码片里面查看。
下面就是具体的中缀转后缀的代码
#include <stdio.h>
#include "LinkStack.h"
int isNumber(char c)
{
return ('0' <= c) && (c <= '9');
}
int isOperator(char c)
{
return (c == '+') || (c == '-') || (c == '*') || (c == '/');
}
int isLeft(char c)
{
return (c == '(');
}
int isRight(char c)
{
return (c == ')');
}
int priority(char c)
{
int ret = 0;
if( (c == '+') || (c == '-') )
{
ret = 1;
}
if( (c == '*') || (c == '/') )
{
ret = 2;
}
return ret;
}
void output(char c)
{
if( c != '\0' )
{
printf("%c", c);
}
}
void transform(const char* exp)
{
LinkStack* stack = LinkStack_Create();
int i = 0;
while( exp[i] != '\0' )
{
if( isNumber(exp[i]) )
{
output(exp[i]);
}
else if( isOperator(exp[i]) )
{
while( priority(exp[i]) <= priority((char)(int)LinkStack_Top(stack)) )
{
output((char)(int)LinkStack_Pop(stack));
}
LinkStack_Push(stack, (void*)(int)exp[i]);
}
else if( isLeft(exp[i]) )
{
LinkStack_Push(stack, (void*)(int)exp[i]);
}
else if( isRight(exp[i]) )
{
char c = '\0';
while( !isLeft((char)(int)LinkStack_Top(stack)) )
{
output((char)(int)LinkStack_Pop(stack));
}
LinkStack_Pop(stack);
}
else
{
printf("Invalid expression!");
break;
}
i++;
}
while( (LinkStack_Size(stack) > 0) && (exp[i] == '\0') )
{
output((char)(int)LinkStack_Pop(stack));
}
LinkStack_Destroy(stack);
}
int main()
{
transform("9+(3-1)*5+8/2");
printf("\n");
return 0;
}
下来我们接着说后缀是如何在计算机中进行计算的?
计算机对后缀表达式的运算时基于栈的,那么问题来了,在计算机中他是如何基于后缀表达式计算的呢?
围绕这个问题,我们提出解决方案。
解决方案:
遍历后缀表达式中的数字和符号
对于数字:进栈
对于符号:
从栈中弹出右操作数
从栈中弹出左操作数
根据符号进行运算
将运算结果压入栈中
遍历结束:栈中的唯一数字即为运算结果
到这后缀表达式转换为计算机中的计算方式我想大家对此都有所了解了。
下面来给出大家后缀运算的C语言算法框架。
具体实现代码如下:
#include <stdio.h>
#include "LinkStack.h"
int isNumber(char c)
{
return ('0' <= c) && (c <= '9');
}
int isOperator(char c)
{
return (c == '+') || (c == '-') || (c == '*') || (c == '/');
}
int value(char c)
{
return (c - '0');
}
int express(int left, int right, char op)
{
int ret = 0;
switch(op)
{
case '+':
ret = left + right;
break;
case '-':
ret = left - right;
break;
case '*':
ret = left * right;
break;
case '/':
ret = left / right;
break;
default:
break;
}
return ret;
}
int compute(const char* exp)
{
LinkStack* stack = LinkStack_Create();
int ret = 0;
int i = 0;
while( exp[i] != '\0' )
{
if( isNumber(exp[i]) )
{
LinkStack_Push(stack, (void*)value(exp[i]));
}
else if( isOperator(exp[i]) )
{
int right = (int)LinkStack_Pop(stack);
int left = (int)LinkStack_Pop(stack);
int result = express(left, right, exp[i]);
LinkStack_Push(stack, (void*)result);
}
else
{
printf("Invalid expression!");
break;
}
i++;
}
if( (LinkStack_Size(stack) == 1) && (exp[i] == '\0') )
{
ret = (int)LinkStack_Pop(stack);
}
else
{
printf("Invalid expression!");
}
LinkStack_Destroy(stack);
return ret;
}
int main()
{
printf("9 + (3 - 1) * 5 + 8 / 2 = %d\n", compute("931-5*+82/+"));
return 0;
}
小结:中缀表达式符合人类的阅读习惯
后缀表达式是计算机喜欢的表达式
通过栈可以方便的将中缀表达式变换为后缀表达式
中缀表达式的计算过程类似程序编译运行的过程
这篇博客是就到这了,需要强调的是,这篇是补充昨天的博客,今天的晚上会更新今天的博客。