您的位置:首页
栈的典型应用-表达式求值【转】
2016-10-04 14:25
405 查看
本文转载自:http://www.voidcn.com/blog/lub0807/article/p-1510616.html
栈的一个应用是求四则运算表达式的值,这里的表达式包含数字、加减乘除4种运算符,以及小括号。
由于输入是一个字符串,因此解决这个问题需要以下3个步骤:
1、输入字符串转化为中缀表达式;
2、中缀表达式转化为后缀表达式;
3、后缀表达式求值。
现在表达式为:9 + ( 3 - 1 )* 3 + 10 / 2 ,先看一下运行结果:
首先解释一下中缀表达式和后缀表达式的概念。所谓中缀表达式,就是我们平常书写的表达式,因为运算符是写在两个参与运算的数字中间,所以叫中缀表达式,例如1 + 2 。与此对应,后缀表达式就是运算符写在数字后面,比如刚才的算式就要写成1 2 + ,我们看起来的确有点奇怪,不过计算机却很喜欢这种表达式。下面分析解决问题的3个步骤。
1、输入字符串转化为中缀表达式
运算符号和括号好办,本身就是字符,只需要把字符串形式的数字转成相应的整数。我采用的方法是,用一个数组num[]存储整数的各位数字,用一个整型变量count记录位数。当下一个字符是运算符或者括号时,表示整数已经读取完毕。这时候,把num数组的各位数字乘以10的某次方就可还原出该整数。该部分代码如下:
2、中缀表达式转后缀表达式
这里需要一个栈用来暂时存储运算符和括号,具体地,对中缀表达式从左到右按以下规则操作:
(1)遇到数字,则直接输出;
(2)遇到左括号,则左括号进栈;
(3)遇到右括号,从栈顶开始依次输出所有运算符,直到遇到左括号,这个左括号也出栈;
(4)遇到加号或减号,从栈顶开始依次输出所有运算符,直到遇到左括号,但此时这个左括号不出栈,并且当前运算符进栈;
(5)遇到乘号或除号,如果栈顶是乘号或除号,则输出,否则不输出,并且当前运算符进栈。
这部分代码如下:
3、后缀表达式求值
这里还需要一个栈,只不过这回是用来暂时存储数字,注意到后缀表达式中不含有括号了。具体地,对后缀表达式从左到右按以下规则操作:
(1)遇到数字,则数字进栈;
(2)遇到运算符,则栈顶数字出栈,记为num1,此时栈顶数字再出栈,记为num2,那么记num2 运算 num1 = num3,将num3进栈。还是举个例子好了,比如遇到运算符+,栈顶数字是1,好了,1出栈。现在栈顶数字变为2了,好,2也出栈。现在计算2+1=3,此时,3进栈。
这部分代码如下:
整个工作完成,不过,程序要想正确运行,对输入有一些要求,比如:
(1)输入不能有空字符;
(2)输入的数字只能是整数,而且除数不能是0;
(3)确保中间的运算结果也都是整数,否则会舍弃小数部分,从而影响精度。
全部代码如下:
栈的一个应用是求四则运算表达式的值,这里的表达式包含数字、加减乘除4种运算符,以及小括号。
由于输入是一个字符串,因此解决这个问题需要以下3个步骤:
1、输入字符串转化为中缀表达式;
2、中缀表达式转化为后缀表达式;
3、后缀表达式求值。
现在表达式为:9 + ( 3 - 1 )* 3 + 10 / 2 ,先看一下运行结果:
首先解释一下中缀表达式和后缀表达式的概念。所谓中缀表达式,就是我们平常书写的表达式,因为运算符是写在两个参与运算的数字中间,所以叫中缀表达式,例如1 + 2 。与此对应,后缀表达式就是运算符写在数字后面,比如刚才的算式就要写成1 2 + ,我们看起来的确有点奇怪,不过计算机却很喜欢这种表达式。下面分析解决问题的3个步骤。
1、输入字符串转化为中缀表达式
运算符号和括号好办,本身就是字符,只需要把字符串形式的数字转成相应的整数。我采用的方法是,用一个数组num[]存储整数的各位数字,用一个整型变量count记录位数。当下一个字符是运算符或者括号时,表示整数已经读取完毕。这时候,把num数组的各位数字乘以10的某次方就可还原出该整数。该部分代码如下:
//字符串转换成中缀表达式 void StringToMidExp(const char exp[], Stack *ps) { int num[MAX_INT]; int k, n, count, temp; Stack m_stack; Stack *pm; Node *q; k = 0; count = 0; pm = &m_stack; InitStack(pm); while (exp[k] != '\0') { if (exp[k] >= '0' && exp[k] <= '9') //数字0到9 { count++; //count记录整数的位数 num[count-1] = exp[k] - 48; //num数组记录整数的每一位 } else if ((exp[k] >= 40 && exp[k] <= 43) || exp[k] == 45 || exp[k] == 47) //运算符 { if (count > 0) //转换该运算符之前的数字 { n = 0; temp = 0; while (n < count) { temp += num * TenPow(count - n -1); //每一位乘以10的某次方 n++; } q = (Node *)malloc(sizeof(Node)); q->type = NUM; q->number = temp; Push(pm, q); } count = 0; //位数清零 q = (Node *)malloc(sizeof(Node)); q->type = OP; q->operation = exp[k]; Push(pm, q); } k++; } if (count > 0) //把最后一个数字转换出来 { n = 0; temp = 0; while (n < count) { temp += num * TenPow(count - n -1); n++; } q = (Node *)malloc(sizeof(Node)); q->type = NUM; q->number = temp; Push(pm, q); } Reverse(pm, ps); //颠倒一下次序 } //计算10的n次方 int TenPow(int n) { if (n == 0) { return 1; } else { int i, k; i = 0; k = 1; while (i < n) { k *= 10; i++; } return k; } }
2、中缀表达式转后缀表达式
这里需要一个栈用来暂时存储运算符和括号,具体地,对中缀表达式从左到右按以下规则操作:
(1)遇到数字,则直接输出;
(2)遇到左括号,则左括号进栈;
(3)遇到右括号,从栈顶开始依次输出所有运算符,直到遇到左括号,这个左括号也出栈;
(4)遇到加号或减号,从栈顶开始依次输出所有运算符,直到遇到左括号,但此时这个左括号不出栈,并且当前运算符进栈;
(5)遇到乘号或除号,如果栈顶是乘号或除号,则输出,否则不输出,并且当前运算符进栈。
这部分代码如下:
//中缀表达式转换成后缀表达式 void MidExpToBackExp(Stack *pm, Stack *pb) { Stack tempStack, oprStack; Stack *pt, *pr; Node *q, *r; pt = &tempStack; //临时存储后缀表达式 pr = &oprStack; //用来决定运算符的顺序 InitStack(pt); InitStack(pr); while (pm->top) { q = (Node *)malloc(sizeof(Node)); Pop(pm, q); if (q->type == NUM) { Push(pt, q); } else { if (q->operation == '+' || q->operation == '-') { while (pr->top && pr->top->operation != '(') { r = (Node *)malloc(sizeof(Node)); Pop(pr, r); Push(pt, r); } Push(pr, q); } else if (q->operation == '*' || q->operation == '/') { while (pr->top && pr->top->operation != '(' && pr->top->operation != '+' && pr->top->operation != '-') { r = (Node *)malloc(sizeof(Node)); Pop(pr, r); Push(pt, r); } Push(pr, q); } else if (q->operation == '(') { Push(pr, q); } else { while (pr->top) { if (pr->top->operation == '(') { r = (Node *)malloc(sizeof(Node)); Pop(pr, r); free(r); break; } r = (Node *)malloc(sizeof(Node)); Pop(pr, r); Push(pt, r); } free(q); } } } while (pr->top) //栈内剩余运算符全部出栈 { r = (Node *)malloc(sizeof(Node)); Pop(pr, r); Push(pt, r); } Reverse(pt, pb); //颠倒一下次序 }
3、后缀表达式求值
这里还需要一个栈,只不过这回是用来暂时存储数字,注意到后缀表达式中不含有括号了。具体地,对后缀表达式从左到右按以下规则操作:
(1)遇到数字,则数字进栈;
(2)遇到运算符,则栈顶数字出栈,记为num1,此时栈顶数字再出栈,记为num2,那么记num2 运算 num1 = num3,将num3进栈。还是举个例子好了,比如遇到运算符+,栈顶数字是1,好了,1出栈。现在栈顶数字变为2了,好,2也出栈。现在计算2+1=3,此时,3进栈。
这部分代码如下:
//根据后缀表达式计算结果 int BackExpToResult(Stack *ps) { if (!ps->top) //空栈说明表达式有误 { return NO_RESULT; } Stack tempStack; Stack *pt; Node *q; int num_left, num_right, result; pt = &tempStack; InitStack(pt); while (ps->top) { if (ps->top->type == NUM) { q = (Node *)malloc(sizeof(Node)); Pop(ps, q); Push(pt, q); } else { q = (Node *)malloc(sizeof(Node)); Pop(pt, q); num_right = q->number; free(q); if (!pt->top) //pt栈内没有第2个数了,说明表达式有误 { return NO_RESULT; } q = (Node *)malloc(sizeof(Node)); Pop(pt, q); num_left = q->number; free(q); q = (Node *)malloc(sizeof(Node)); Pop(ps, q); switch(q->operation) { case '+': result = num_left + num_right; break; case '-': result = num_left - num_right; break; case '*': result = num_left * num_right; break; case '/': result = num_left / num_right; break; } free(q); q = (Node *)malloc(sizeof(Node)); q->type = NUM; q->number = result; Push(pt, q); } } q = (Node *)malloc(sizeof(Node)); Pop(pt, q); result = q->number; free(q); if (pt->top) //pt栈内还有数字,说明表达式有误 { return NO_RESULT; } else { return result; } }
整个工作完成,不过,程序要想正确运行,对输入有一些要求,比如:
(1)输入不能有空字符;
(2)输入的数字只能是整数,而且除数不能是0;
(3)确保中间的运算结果也都是整数,否则会舍弃小数部分,从而影响精度。
全部代码如下:
#include <STDIO.H>
#include <STDLIB.H>
#define MAX_EXP 100 //表达式最大长度
#define MAX_INT 10 //整数最大位数
#define NO_RESULT -99999 //计算异常的返回值
enum node_type{ NUM, OP };
struct node{
int number;
char operation;
enum node_type type;
struct node *next;
};
struct stack{
struct node *top;
int length;
};
typedef struct node Node;
typedef struct stack Stack;
int GetResult(const char []);
void StringToMidExp(const char [], Stack *);
int TenPow(int);
void MidExpToBackExp(Stack *, Stack *);
int BackExpToResult(Stack *);
void ShowStack(const Stack *);
void ShowNode(const Node *);
void InitStack(Stack *);
void Push(Stack *, Node *);
void Pop(Stack *, Node *);
void ClearStack(Stack *);
void Reverse(Stack *, Stack *);
int main(void)
{
char expression[MAX_EXP];
int result;
printf("输入四则运算表达式:\n");
scanf("%s", expression);
result = GetResult(expression);
if (result == NO_RESULT)
{
printf("表达式有误,计算失败。\n");
}
else
{
printf("计算结果是:%d\n", result);
}
return 0;
}
//根据表达式的字符串计算结果
int GetResult(const char exp[])
{
Stack middleExp, backExp;
Stack *pm, *pb;
pm = &middleExp;
pb = &backExp;
InitStack(pm);
InitStack(pb);
StringToMidExp(exp, pm);
printf("中缀表达式:");
ShowStack(pm);
MidExpToBackExp(pm, pb);
printf("后缀表达式:");
ShowStack(pb);
return BackExpToResult(pb);
}
//字符串转换成中缀表达式 void StringToMidExp(const char exp[], Stack *ps) { int num[MAX_INT]; int k, n, count, temp; Stack m_stack; Stack *pm; Node *q; k = 0; count = 0; pm = &m_stack; InitStack(pm); while (exp[k] != '\0') { if (exp[k] >= '0' && exp[k] <= '9') //数字0到9 { count++; //count记录整数的位数 num[count-1] = exp[k] - 48; //num数组记录整数的每一位 } else if ((exp[k] >= 40 && exp[k] <= 43) || exp[k] == 45 || exp[k] == 47) //运算符 { if (count > 0) //转换该运算符之前的数字 { n = 0; temp = 0; while (n < count) { temp += num * TenPow(count - n -1); //每一位乘以10的某次方 n++; } q = (Node *)malloc(sizeof(Node)); q->type = NUM; q->number = temp; Push(pm, q); } count = 0; //位数清零 q = (Node *)malloc(sizeof(Node)); q->type = OP; q->operation = exp[k]; Push(pm, q); } k++; } if (count > 0) //把最后一个数字转换出来 { n = 0; temp = 0; while (n < count) { temp += num * TenPow(count - n -1); n++; } q = (Node *)malloc(sizeof(Node)); q->type = NUM; q->number = temp; Push(pm, q); } Reverse(pm, ps); //颠倒一下次序 } //计算10的n次方 int TenPow(int n) { if (n == 0) { return 1; } else { int i, k; i = 0; k = 1; while (i < n) { k *= 10; i++; } return k; } }
//中缀表达式转换成后缀表达式 void MidExpToBackExp(Stack *pm, Stack *pb) { Stack tempStack, oprStack; Stack *pt, *pr; Node *q, *r; pt = &tempStack; //临时存储后缀表达式 pr = &oprStack; //用来决定运算符的顺序 InitStack(pt); InitStack(pr); while (pm->top) { q = (Node *)malloc(sizeof(Node)); Pop(pm, q); if (q->type == NUM) { Push(pt, q); } else { if (q->operation == '+' || q->operation == '-') { while (pr->top && pr->top->operation != '(') { r = (Node *)malloc(sizeof(Node)); Pop(pr, r); Push(pt, r); } Push(pr, q); } else if (q->operation == '*' || q->operation == '/') { while (pr->top && pr->top->operation != '(' && pr->top->operation != '+' && pr->top->operation != '-') { r = (Node *)malloc(sizeof(Node)); Pop(pr, r); Push(pt, r); } Push(pr, q); } else if (q->operation == '(') { Push(pr, q); } else { while (pr->top) { if (pr->top->operation == '(') { r = (Node *)malloc(sizeof(Node)); Pop(pr, r); free(r); break; } r = (Node *)malloc(sizeof(Node)); Pop(pr, r); Push(pt, r); } free(q); } } } while (pr->top) //栈内剩余运算符全部出栈 { r = (Node *)malloc(sizeof(Node)); Pop(pr, r); Push(pt, r); } Reverse(pt, pb); //颠倒一下次序 }
//根据后缀表达式计算结果 int BackExpToResult(Stack *ps) { if (!ps->top) //空栈说明表达式有误 { return NO_RESULT; } Stack tempStack; Stack *pt; Node *q; int num_left, num_right, result; pt = &tempStack; InitStack(pt); while (ps->top) { if (ps->top->type == NUM) { q = (Node *)malloc(sizeof(Node)); Pop(ps, q); Push(pt, q); } else { q = (Node *)malloc(sizeof(Node)); Pop(pt, q); num_right = q->number; free(q); if (!pt->top) //pt栈内没有第2个数了,说明表达式有误 { return NO_RESULT; } q = (Node *)malloc(sizeof(Node)); Pop(pt, q); num_left = q->number; free(q); q = (Node *)malloc(sizeof(Node)); Pop(ps, q); switch(q->operation) { case '+': result = num_left + num_right; break; case '-': result = num_left - num_right; break; case '*': result = num_left * num_right; break; case '/': result = num_left / num_right; break; } free(q); q = (Node *)malloc(sizeof(Node)); q->type = NUM; q->number = result; Push(pt, q); } } q = (Node *)malloc(sizeof(Node)); Pop(pt, q); result = q->number; free(q); if (pt->top) //pt栈内还有数字,说明表达式有误 { return NO_RESULT; } else { return result; } }
//显示栈中元素
void ShowStack(const Stack *ps)
{
if (ps->top)
{
Node *p = ps->top;
while (p->next)
{
ShowNode(p);
printf(" ");
p = p->next;
}
ShowNode(p);
printf("\n");
}
else
{
printf("无\n");
}
}
//显示一个节点元素
void ShowNode(const Node *p)
{
if (p->type == NUM)
{
printf("%d", p->number);
}
else
{
printf("%c", p->operation);
}
}
//初始化栈
void InitStack(Stack *ps)
{
ps->length = 0;
ps->top = NULL;
}
//节点入栈
void Push(Stack *ps, Node *pn)
{
pn->next = ps->top;
ps->top = pn;
ps->length++;
}
//节点出栈
void Pop(Stack *ps, Node *pn)
{
if (ps->top)
{
Node *q = ps->top;
pn->next = NULL;
pn->number = q->number;
pn->operation = q->operation;
pn->type = q->type;
ps->top = q->next;
free(q);
ps->length--;
}
else
{
pn = NULL;
}
}
//清空栈
void ClearStack(Stack *ps)
{
Node *q;
while (ps->top)
{
q = ps->top;
ps->top = q->next;
free(q);
ps->length--;
}
}
//反转栈中元素的次序
void Reverse(Stack *ps1, Stack *ps2)
{
if (ps1->top)
{
Node *q;
ClearStack(ps2);
while (ps1->top)
{
q = (Node *)malloc(sizeof(Node));
Pop(ps1, q);
Push(ps2, q);
}
}
else
{
ps2->top = NULL;
ps2->length = 0;
}
}
相关文章推荐
- 数据结构:栈的典型应用之二:四则运算表达式求值(C++)
- “栈”的典型应用—表达式求值(C语言实现)
- “栈”的典型应用—表达式求值(C语言实现)
- 四则运算表达式求值(栈的应用)
- 表达式求值 数据结构 C/C++ 栈的应用
- 表达式求值,栈的应用(C语言)
- 栈的经典应用之一——表达式求值
- 数据结构之应用 "栈(Stack)" 实现: 解析算术表达式及计算求值 (C#/Java)
- 栈应用——表达式求值
- 中缀表达式转后缀表达式求值(栈的应用)
- 表达式求值——栈的应用
- 栈的应用实例---表达式求值(C语言)
- 数据结构习作之应用 "栈(Stack)" 实现: 解析算术表达式及计算求值 (C#/Java) (技术含量少许)
- 数据结构之应用 "栈(Stack)" 实现: 解析算术表达式及计算求值 (C#/Java)
- 实验一 线性表及其应用 算术表达式求值
- NYOJ 35 表达式求值【栈的应用】
- 数据结构 栈的应用-- 表达式求值
- 栈的应用——表达式求值
- 回顾数据结构之栈的应用-表达式求值
- 栈的应用-四则运算表达式求值