栈的应用——四则运算表达式求值
2017-06-29 21:08
507 查看
最开始的计算器只能进行两个数之间的运算,而不能进行复杂的如“9+((3*2)+(3-1))/2” 这样的四则运算。后来一名波兰的逻辑学家发明了后缀表达式(或称为逆波兰表达式),非常巧妙地解决了程序实现四则运算的难题。
后缀表达式是一种把所有运算符都放在运算数字后面出现的式子,所以被称为后缀表达式,这样就解决了运算优先级和括号的问题。而中缀表达式就是我们平常用的标准四则运算表达式,即“9+((3*2)+(3-1))/2”。在计算机计算一个标准四则运算表达式时,都是先将中缀表达式转化为后缀表达式,然后进行计算。
例如中缀表达式“9+((3*2)+(3-1))/2”转化为后缀表达式“9 3 2 * 3 1 - + 2 / +”。
中缀表达式转化为后缀表达式规则:
1、在转化前先建立两个栈,暂且命名为s1和s2。用栈s1存储后缀表达式,用栈s2存储符号;
2、在转化的过程中需从左到右遍历中缀表达式的每一个数字和符号,若是数字就压入栈s1中即成为后缀表达式的一部分;
3、若遍历到的是符号,则判断其与栈s2栈顶符号的优先级,若其优先级小于栈顶符号则将栈顶符号依次出栈,并依次压入栈s1,然后将其压入栈s2。若其是右括号则将栈顶符号依次出栈并压入栈s1,直至遇到左括号并将左括号出栈,但不再压入栈s1;
4、若最后栈s2中还有符号,则将其依次出栈,并压入栈s1。最终完成转化过程。
中缀表达式转化为后缀表达式:
以中缀表达式“9+((3*2)+(3-1))/2”的转化为例介绍栈s1和栈s2的情况:
注:数字和符号的顺序是按在栈中的顺序排列的。
(1)遍历到字符“9”时:
栈s1:9 ;
栈s2:空 ;
(1)遍历到符号“+”时:
栈s1:9 ;
栈s2:+ ;
(1)遍历到符号“(”时:
栈s1:9 ;
栈s2:( + ;
(2)遍历到符号“(”时:
栈s1:9 ;
栈s2:( ( + ;
(3)遍历到字符“3”时:
栈s1:3 9 ;
栈s2:( ( +;
(4)遍历到符号“*”时:
栈s1:3 9 ;
栈s2:* ( ( + ;
(5)遍历到字符“2”时:
栈s1:2 3 9 ;
栈s2:* ( ( + ;
(6)遍历到符号“)”时:
栈s1:2 3 9 ;
栈s2:* ( ( + ;
此时开始比较,比较之后:
栈s1:* 2 3 9 ;
栈s2:( + ;
(7)遍历到符号“+”时:
栈s1:* 2 3 9 ;
栈s2:+ ( +;
(8)遍历到符号“(”时:
栈s1:* 2 3 9 ;
栈s2:( + ( + ;
(9)遍历到字符“3”时:
栈s1:3 * 2 3 9 ;
栈s2:( + ( + ;
(10)遍历到符号“-”时:
栈s1:3 * 2 3 9 ;
栈s2:- ( + ( + ;
(11)遍历到字符“1”时:
栈s1:1 3 * 2 3 9 ;
栈s2:- ( + ( + ;
(12)遍历到符号“)”时:
栈s1:1 3 * 2 3 9 ;
栈s2:- ( + ( + ;
此时开始比较,比较之后:
栈s1:- 1 3 * 2 3 9 ;
栈s2:+ ( +;
(13)遍历到符号“)”时:
栈s1:- 1 3 * 2 3 9 ;
栈s2:+ ( +;
此时开始比较,比较之后:
栈s1:+ - 1 3 * 2 3 9 ;
栈s2:+;
(14)遍历到符号“/”时:
栈s1:+ - 1 3 * 2 3 9 ;
栈s2:/ + ;
(15)遍历到字符“2”时:
栈s1:2 + - 1 3 * 2 3 9 ;
栈s2:/ + ;
(16)遍历结束,但栈s2中还有符号,所以将栈s2中的符号全部依次压入栈s1中,此时:
栈s1:+ / 2 + - 1 3 * 2 3 9 ;
栈s2:空;
所以后缀表达式为:9 3 2 * 3 1 - + 2 / + ;
后缀表达式计算结果规则:
从左到右遍历整个后缀表达式的每一个数字和字符,遇到符号就将处于该符号前的两个数字做当前符号的运算,然后用结果代替原来的两个数字,一直到最终获得结果(栈顶元素即为结果)。
#include<stdio.h>
#include<ctype.h>
typedef struct node{
char ch;
struct node *next;
}*LinkList;
typedef struct Node{
int num;
struct Node *Next;
}*Linklist;
int cmp(char c1, char c2);
int counter(int a, int b, char c);
int main()
{
int i, flag=0, logo;
char str[30];
Linklist Head = new Node, pre, L = new Node;
LinkList head = new node, pot, p, q;
Head->Next = NULL;
L->num = 0;
head->ch = '#';
head->next = NULL;
gets(str);
for(i = 0; ; i++){
if(isdigit(str[i])){
logo = 1;
L->num = L->num * 10 + str[i] - '0';
}
else{
if(logo){
L->Next = Head->Next;
Head->Next = L;
if('\0' == str[i])/*当对到读到'\0'时结束遍历,在这结束时为了将最后一个数字压入栈顶*/
break;
L = new Node;
logo = L->num = 0;
}
if(head->next != NULL)
flag = cmp(head->next->ch, str[i]);
else
flag = cmp(head->ch, str[i]);
if(flag){
while(head->next){
pot = head->next;
if('(' != pot->ch){
pre = Head->Next;
pre->Next->num = counter(pre->Next->num, pre->num, pot->ch);
Head->Next = pre->Next;
delete pre;
head->next = pot->next;
delete pot;
}
else if('(' == pot->ch){
if(1 == flag)
pot->ch = str[i];
else{
head->next = pot->next;
delete pot;
}
break;
}
}
if(!head->next){
p = new node;
p->ch = str[i];
p->next = head->next;
head->next = p;
}
}
else{
p = new node;
p->ch = str[i];
p->next = head->next;
head->next = p;
}
}
}
while(head->next){
pot = head->next;
pre = Head->Next;
pre->Next->num = counter(pre->Next->num, pre->num, pot->ch);
Head->Next = pre->Next;
delete pre;
head->next = pot->next;
delete pot;
}
printf("%d\n", Head->Next->num);
return 0;
}
int cmp(char c1, char c2)
{
if('#' == c1)
return 0;
if(')' == c2)
return 2;
if('(' == c2)
return 0;
if('*' == c2 || '/' == c2)
return 0;
if('+' == c2 || '-' == c2){
if('*' == c1 || '/' == c1)
return 1;
return 0;
}
}
int counter(int a, int b, char c)
{
switch(c){
case '+':
return a+b;
case '-':
return a-b;
case '*':
return a*b;
case '/':
return a/b;
}
}
后缀表达式是一种把所有运算符都放在运算数字后面出现的式子,所以被称为后缀表达式,这样就解决了运算优先级和括号的问题。而中缀表达式就是我们平常用的标准四则运算表达式,即“9+((3*2)+(3-1))/2”。在计算机计算一个标准四则运算表达式时,都是先将中缀表达式转化为后缀表达式,然后进行计算。
例如中缀表达式“9+((3*2)+(3-1))/2”转化为后缀表达式“9 3 2 * 3 1 - + 2 / +”。
中缀表达式转化为后缀表达式规则:
1、在转化前先建立两个栈,暂且命名为s1和s2。用栈s1存储后缀表达式,用栈s2存储符号;
2、在转化的过程中需从左到右遍历中缀表达式的每一个数字和符号,若是数字就压入栈s1中即成为后缀表达式的一部分;
3、若遍历到的是符号,则判断其与栈s2栈顶符号的优先级,若其优先级小于栈顶符号则将栈顶符号依次出栈,并依次压入栈s1,然后将其压入栈s2。若其是右括号则将栈顶符号依次出栈并压入栈s1,直至遇到左括号并将左括号出栈,但不再压入栈s1;
4、若最后栈s2中还有符号,则将其依次出栈,并压入栈s1。最终完成转化过程。
中缀表达式转化为后缀表达式:
以中缀表达式“9+((3*2)+(3-1))/2”的转化为例介绍栈s1和栈s2的情况:
注:数字和符号的顺序是按在栈中的顺序排列的。
(1)遍历到字符“9”时:
栈s1:9 ;
栈s2:空 ;
(1)遍历到符号“+”时:
栈s1:9 ;
栈s2:+ ;
(1)遍历到符号“(”时:
栈s1:9 ;
栈s2:( + ;
(2)遍历到符号“(”时:
栈s1:9 ;
栈s2:( ( + ;
(3)遍历到字符“3”时:
栈s1:3 9 ;
栈s2:( ( +;
(4)遍历到符号“*”时:
栈s1:3 9 ;
栈s2:* ( ( + ;
(5)遍历到字符“2”时:
栈s1:2 3 9 ;
栈s2:* ( ( + ;
(6)遍历到符号“)”时:
栈s1:2 3 9 ;
栈s2:* ( ( + ;
此时开始比较,比较之后:
栈s1:* 2 3 9 ;
栈s2:( + ;
(7)遍历到符号“+”时:
栈s1:* 2 3 9 ;
栈s2:+ ( +;
(8)遍历到符号“(”时:
栈s1:* 2 3 9 ;
栈s2:( + ( + ;
(9)遍历到字符“3”时:
栈s1:3 * 2 3 9 ;
栈s2:( + ( + ;
(10)遍历到符号“-”时:
栈s1:3 * 2 3 9 ;
栈s2:- ( + ( + ;
(11)遍历到字符“1”时:
栈s1:1 3 * 2 3 9 ;
栈s2:- ( + ( + ;
(12)遍历到符号“)”时:
栈s1:1 3 * 2 3 9 ;
栈s2:- ( + ( + ;
此时开始比较,比较之后:
栈s1:- 1 3 * 2 3 9 ;
栈s2:+ ( +;
(13)遍历到符号“)”时:
栈s1:- 1 3 * 2 3 9 ;
栈s2:+ ( +;
此时开始比较,比较之后:
栈s1:+ - 1 3 * 2 3 9 ;
栈s2:+;
(14)遍历到符号“/”时:
栈s1:+ - 1 3 * 2 3 9 ;
栈s2:/ + ;
(15)遍历到字符“2”时:
栈s1:2 + - 1 3 * 2 3 9 ;
栈s2:/ + ;
(16)遍历结束,但栈s2中还有符号,所以将栈s2中的符号全部依次压入栈s1中,此时:
栈s1:+ / 2 + - 1 3 * 2 3 9 ;
栈s2:空;
所以后缀表达式为:9 3 2 * 3 1 - + 2 / + ;
后缀表达式计算结果规则:
从左到右遍历整个后缀表达式的每一个数字和字符,遇到符号就将处于该符号前的两个数字做当前符号的运算,然后用结果代替原来的两个数字,一直到最终获得结果(栈顶元素即为结果)。
#include<stdio.h>
#include<ctype.h>
typedef struct node{
char ch;
struct node *next;
}*LinkList;
typedef struct Node{
int num;
struct Node *Next;
}*Linklist;
int cmp(char c1, char c2);
int counter(int a, int b, char c);
int main()
{
int i, flag=0, logo;
char str[30];
Linklist Head = new Node, pre, L = new Node;
LinkList head = new node, pot, p, q;
Head->Next = NULL;
L->num = 0;
head->ch = '#';
head->next = NULL;
gets(str);
for(i = 0; ; i++){
if(isdigit(str[i])){
logo = 1;
L->num = L->num * 10 + str[i] - '0';
}
else{
if(logo){
L->Next = Head->Next;
Head->Next = L;
if('\0' == str[i])/*当对到读到'\0'时结束遍历,在这结束时为了将最后一个数字压入栈顶*/
break;
L = new Node;
logo = L->num = 0;
}
if(head->next != NULL)
flag = cmp(head->next->ch, str[i]);
else
flag = cmp(head->ch, str[i]);
if(flag){
while(head->next){
pot = head->next;
if('(' != pot->ch){
pre = Head->Next;
pre->Next->num = counter(pre->Next->num, pre->num, pot->ch);
Head->Next = pre->Next;
delete pre;
head->next = pot->next;
delete pot;
}
else if('(' == pot->ch){
if(1 == flag)
pot->ch = str[i];
else{
head->next = pot->next;
delete pot;
}
break;
}
}
if(!head->next){
p = new node;
p->ch = str[i];
p->next = head->next;
head->next = p;
}
}
else{
p = new node;
p->ch = str[i];
p->next = head->next;
head->next = p;
}
}
}
while(head->next){
pot = head->next;
pre = Head->Next;
pre->Next->num = counter(pre->Next->num, pre->num, pot->ch);
Head->Next = pre->Next;
delete pre;
head->next = pot->next;
delete pot;
}
printf("%d\n", Head->Next->num);
return 0;
}
int cmp(char c1, char c2)
{
if('#' == c1)
return 0;
if(')' == c2)
return 2;
if('(' == c2)
return 0;
if('*' == c2 || '/' == c2)
return 0;
if('+' == c2 || '-' == c2){
if('*' == c1 || '/' == c1)
return 1;
return 0;
}
}
int counter(int a, int b, char c)
{
switch(c){
case '+':
return a+b;
case '-':
return a-b;
case '*':
return a*b;
case '/':
return a/b;
}
}
相关文章推荐
- 四则运算表达式求值(栈的应用)
- 栈的应用--四则运算表达式求值(java代码)
- 栈的应用-四则运算表达式求值
- 栈的应用--递归与四则运算表达式求值
- 栈的应用--四则运算表达式求值(java语言)
- 栈的应用:四则运算表达式求值
- 栈的应用-四则运算表达式求值
- 四则运算表达式求值(栈的应用)
- 栈的应用:四则运算表达式求值
- 四则运算表达式求值(栈的应用)
- 【数据结构】栈的应用---四则运算表达式求值(中缀表达式与后缀表达式转换)
- [数据结构与算法] 5,栈的应用-四则运算表达式求值
- 栈的应用二--四则运算表达式求值(逆波兰表示:后缀表达式)
- 栈的应用-四则运算表达式的求值
- 栈的应用---四则运算表达式求值
- 数据结构:栈的典型应用之二:四则运算表达式求值(C++)
- 四则运算表达式求值(栈的应用)
- 四则运算-表达式求值
- 数据结构之栈的应用——四则表达式求值
- 栈的应用——四则表达式求值