对栈的一个应用:表达式求值 进行实现
这个表达式求值实现与知道中缀表达式求后缀表达式方法差不多
这是因为 后缀表达式运算符按计算顺序出现,也即知道后缀表达式后可以求出这个算式的值
运算优先级定义
你可以把
θ
1
\theta1
θ1看成栈的的元素,
θ
2
\theta2
θ2看成式准备入站的元素(对应代码中为 c)
是不是很麻烦???你可以这么理解
- 对于’(‘,当其准备入栈时,他的优先级可以理解为最高,所以在栈顶的四则运算优先级都比他低
- 对于’(‘, 当其入了栈后,他的优先级变低,所以他之后的四则运算的优先级都比他高
- 对于’ )‘, 其优先级与入栈后的’(‘ 优先级相同,所以其为准备入栈时,比在栈顶的四则运算优先级低
- 对于四则运算,这四个运算符都是左结合性,所以对于四则运算,当准备入栈元素和栈顶元素的相同时,以栈顶的优先级大
- 我们定义’#‘ 为表达式的结束标式,这个符号的优先级是最低的
代码实现
定义操作数与操作符栈
为了实现简单,我都是用了字符型的Data成员的结构体,所以每个操作数仅仅为一位(当然你也可以实现多位数的运算,仅仅是把操作数栈单数实现)
#include"stdio.h"
#include"stdlib.h"
#define add 10
//建立栈 有操作数和操作符栈,为了方便统一设置成char类型成员的结构体 以顺序栈实现 为了程序简单,在malloc后统一没有增加失败检验
//注意我为了方便才讲数据栈和操作符栈统一写成有char域的结构体, 你可以讲数据栈写成有int域的结构体
typedef struct SNode {
char* Data; /* 存储元素的数组 */
int Top; /* 栈顶指针 */
int MaxSize; /* 堆栈最大容量 */
}* PNode;//运算符 操作数
对栈的相关操作
void InitStack(PNode stack) {
stack->MaxSize = 5; //开始的栈大小为5 之后不够再加
stack->Top = 0;
stack->Data = (char*)malloc(sizeof(char) * stack->MaxSize);
}
void Push(PNode stack, char e) {
if (stack->Top == stack->MaxSize + 1) {
stack->Data = (char*)realloc(stack, sizeof(char)*(stack->MaxSize + add));
stack->MaxSize = stack->MaxSize + add;
}
stack->Data[stack->Top++] = e;
}
void Pop(PNode stack, char* e) {
if (stack->Top != 0)
*e = stack->Data[--stack->Top];
}
char GetTop(PNode stack) {
return stack->Data[stack->Top - 1];
}
表达式求值相关函数实现
定义运算符的优先级
注意我只实现了 + − ∗ / + - * / +−∗/相关的运算符的优先级,如果你需要实现其他的,你要考虑该操作符与’(’, ‘)’, '#和’ + − ∗ / + - * / +−∗/等的相关关系,还要考虑这个运算符和结合性(比如指数运算位右结合性)
/*栈的应用:表达式求值:*/
//假设仅有 + - * / 四个运算 和( ) 对应ASCII 43 45 42 47 40 41 # 35 代表起始符和终止符
//若想增加指数运算可以定义优先级 但要注意:指数为右结合
char Precede(PNode optr, char c) { //比较栈顶op与c的优先级
char op = GetTop(optr);
if (op == c && c == '(') return '<'; // 处理((情况
else if (op == '(' && c == ')') return '=';
else if (op == '(') return '<';
else if (c == '(') return '<';
else if (c == '#') return '>';
else if (c == ')') return '>';
else if (op == '#') return '<';
else if (c == op && (c == 43 || c == 45 || c == 42 || c == 47))
return '>'; //+ - * / 为左结合性
else if ((op == 42 || op == 47) && (c == 43 || c == 45))
return '>';
else if (((op == 43 || op == 45) && (c == 43 || c == 45)) || ((op == 42 || op == 47) && (c == 42 || c == 47)))
return '>'; //同一级运算符 从左到右结合
else if (((op == 43 || op == 45) && (c == 42 || c == 47)))
return '<'; //c的优先级大
}
实现计算函数
char Operate(char num1, char x, char num2) { //进行运算 在此时已近转化成了int值对应的char
int n1 = num1 - 48;
int n2 = num2 - 48;
printf("operate %d %c %d\n", n1, x, n2);
switch (x){
case'+': return n1 + n2 + 48;
case'-': return n1 - n2 + 48;
case'*': return n1 * n2 + 48;
case'/': return n1 / n2 + 48;
}
}
实现输入数值函数
注意 “#” 代表输入表达式结束
int EvaluateExpression() {
PNode optr = (PNode)malloc(sizeof(struct SNode));
PNode opnd = (PNode)malloc(sizeof(struct SNode));;
InitStack(optr); InitStack(opnd);
Push(optr, '#'); printf("%c", GetTop(optr)); char c = getchar();
char x; //保存弹出来的操作符
char num1, num2; //保存弹出来的数字
while (c != '#' || GetTop(optr) != '#') {
//printf("%c\n", c);
if (c > 47 && c < 58) { // 输入的位操作数
Push(opnd, c); c = getchar();
}
else {
switch (Precede(optr, c)) {
case'<': Push(optr, c); c = getchar(); break;
case'=': Pop(optr, &x); c = getchar(); break;
case'>': Pop(optr, &x); Pop(opnd, &num2); Pop(opnd, &num1);
Push(opnd, Operate(num1, x, num2)); break;
}
}
}
int num = GetTop(opnd) - 48; //转化成int
return num;
}
int main() {
int a = EvaluateExpression();
printf("结果是: %d", a);
}