1、利用栈将中缀表达式求值:
计算规则:设两个栈,s1用来存储操作数,s2用来存储运算符。从左往右扫描表达式,遇到操作数就将入栈s1,遇到运算符就入栈s2。
当前扫描到的运算符优先级大于栈顶的运算符的优先级,则入栈,否则,就出栈s1中的两个操作数,进行计算,将计算结果入栈s1。且栈顶的操作数先出栈,放在运算符的右边,栈顶下面的一个操作数后出栈,放在运算符的左边。
如果遇到左括号就直接入栈s2,直到遇到右括号,此时,从栈顶到左括号的运算符都出栈进行计算。出栈的运算符都不再入栈。
如果表达式全部扫描完毕,s2栈中还有运算符的话就挨个出栈进行计算,计算结果依次放入s1栈中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
| int getpriority(char op) { if(op=='+'||op == '-') return 0; else return 1; }
int calSub(float opandl,char,op,float opand2,float &result) { if(op=='+') result = opandl+opand2; if(op=='-') result = opandl-opand2; if(op=='*') result = opandl*opand2; if(op=='/') { if(fabs(opand2)<MIN) { return 0; } else { result = opandl / opand2;
} } return 1; }
float calInfix(char exp[]) { float s1[maxSize];int top1=-1; char s2[maxSize];int top2=-1; int i=0; while(exp[i]!='\0') { if('0'<=exp[i] && exp[i]<='9') { s1[++top1]=exp[i] -'0'; ++i; } else if (exp[i]=='(') { s2=[++top2]='('; ++i; } else if (exp[i]=='+'||exp[i]=='-'||exp[i]=='*'||exp[i]=='/') { if(top2==-1||s2[top2]=='(' || getpriority(exp[i])>getpriority(s2[top2])) { s2[++top2]=exp[i]; ++i; } else { float opnd1,opnd2,result; char op; int flag; opnd2=s1[top--]; opnd1=s1[top--]; op=s2[top2--]; flag=calSub(opnd1,op,opnd2,result); if(flag==0) { std::cout<<"error"<<std::endl; return 0; } s1[++top1]=result; } } else if (exp[i]==')') { while(s2[top2] !='(') { float opnd1,opnd2,result; char op; int flag; opnd2=s1[top--]; opnd1=s1[top--]; op=s2[top2--]; flag=calSub(opnd1,op,opnd2,result); if(flag==0) { std::cout<<"error"<<std::endl; return 0; } s1[++top1]=result; } --top2; ++i; } } while(top2!=-1) { float opnd1,opnd2,result; char op; int flag; opnd2=s1[top--]; opnd1=s1[top--]; op=s2[top2--]; flag=calSub(opnd1,op,opnd2,result); if(flag==0) { std::cout<<"error"<<std::endl; return 0; } s1[++top1]=result; } retunr s1[top1]; }
|
2、用栈求后缀表达式值:
从左往右扫描这个表达式串,当遇到操作数的时候就入栈,当遇到运算符就出栈两个操作数,进行运算,先出栈的操作数放在运算符的左边,后出战的操作数放在运算符的右边。计算出结果,然后将这个结果入栈。一直将运算符全部运算完,最后一个计算结果即所求的值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| float calPostFix(char exp[]) { float s[maxsize];int top=-1; for(int i=0;exp[i]!='\0';++i) { if('\0'<=exp[i] && exp[i]<='9') s[++top]=exp[i]-'0'; else { float opnd1,opnd2,result; char op; int flag; opnd2=s[top--]; opnd1=s[top--]; op=exp[i]; flag=calSub(opnd1,op,opnd2,result); if(flag==0) { std::cout<<"error"<<std::endl; break; } s[++top]=result; } } return s[top]; }
|
3、用栈求前缀表达式:
从右往左扫描这个表达式。当遇到操作数的时候就入栈,当遇到运算符就出栈两个操作数,进行运算,先出栈的数放在运算符的右边,后出栈的放在运算符的左边。其他操作和后缀表达式计算方式一样。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
| float calPreFix(char exp[],int len) { float s[maxsize];int top=-1; for(int i=len-1;i>=0;--i) { if('\0'<=exp[i] && exp[i]<='9') s[++top]=exp[i]-'0'; else { float opnd1,opnd2,result; char op; int flag; opnd1=s[top--]; opnd2=s[top--]; op=exp[i]; flag=calSub(opnd1,op,opnd2,result); if(flag==0) { std::cout<<"error"<<std::endl; return 0; } s[++top]=result; } } return s[top]; }``` 这里就可以看出,中缀形式求值明显比用后缀或者前缀来的复杂,所以,这就是为什么计算机中会出现在生活中不会使用到的后缀和前缀形式。就像十进制一样,为人们所习惯,而计算机中普遍使用的是二进制。所以我们也必须为计算机的发展创造出能被计算机所方便使用和接受的规则。
**4、中缀转后缀:** 转化规则:从左到右扫描中缀表达式,如果遇到操作数就直接将其写入结果表达式,(这个结果表达式的书写顺序是从左往右书写)如果遇到运算符就将其入栈。 且如果这个即将入栈的运算符**小于等于**当前栈顶的运算符,则将当前栈顶的运算符出栈,写入当前得到的结果表达式中,**这样一直比较下去**,直到即将入栈的运算符的优先级大于当前栈顶的运算符,此时再将这个即将入栈的运算符入栈。如果栈空,就直接入栈,不需要上述的比较。 如果遇到左括号,就直接入栈,当栈顶元素是左括号的时候,所有扫描到的运算符都入栈。当扫描到右括号的时候,执行一系列的出栈操作。将当前栈顶到左括号的运算符全部出栈,并将其写入结果表达式中,其中出栈的括号直接扔掉,左右括号都不写入结果表达式。一个左括号配一个右括号。 此时如果全部扫描完表达式,栈中还有运算符,则将其全部出栈,写入结果表达式中即可。
```c++ void infixToPostFix(char infix[],char s2[],int &top2) { char s1[maxSize];int top1=-1; int i=0; while(infix[i]!='\0') { if('0'<=infix[i] && infix[i]<='9') { s2[++top2]=infix[i]; ++i; } else if(infix[i]='(') { s1[++top]='('; ++i; } else if(infix[i]=='+'||infix[i]=='-'||infix[i]='*'||infix[i]='/') { if(top1==-1||s1[top1]=='(' || getpriority(exp[i])>getpriority(s1[top1])) { s1[++top1]=infix[i]; ++i; } else s2[++top2]=s1[top1--]; } else if(infix[i]==')') { while (s1[top1]!='(') s2[++top2]=s1[top--]; --top1; ++i; } } while(top1!=1) s2[++top2]=s1[top1--]; }
|
5、中缀转前缀:
转化规则:
从右往左扫描,书写结果表达式的方向是从右往左写。遇到右括号直接入栈,遇到左括号就将当前栈顶到右括号的运算符出栈。
当前运算符如果小于栈顶的运算符时,则当前栈顶的运算符出栈。
其他的操作和中缀转后缀式一样的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| void infixToPreFix(char infix[],char s2[],int &top2,int len) { char s1[maxSize];int top1=-1; int i=len-1; while(i>=0) { if('0'<=infix[i] && infix[i]<='9') { s2[++top2]=infix[i]; --i; } else if(infix[i]=')') { s1[++top]=')'; --i; } else if(infix[i]=='+'||infix[i]=='-'||infix[i]='*'||infix[i]='/') { if(top1==-1||s1[top1]==')' || getpriority(exp[i])>=getpriority(s1[top1])) { s1[++top1]=infix[i]; --i; } else s2[++top2]=s1[top1--]; } else if(infix[i]=='(') { while (s1[top1]!=')') s2[++top2]=s1[top--]; --top1; --i; } } while(top1!=1) s2[++top2]=s1[top1--]; }
|
6、括号匹配问题:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| int isMatched(char left,char right) { if(left=='(' && right==')') return 1; if(left=='[' && right==']') return 1; if(left=='{' && right=='}') return 1; else return 0; }
int isParenthesesBalanced(char exp[]) { char s[maxSize];int top=-1; for(int i=0;exp[i]!='\0';++i) { if(exp[i]=='('||exp[i]=='['||exp[i]=='{') s[++top]=exp[i]; if(exp[i]==')'||exp[i]==']'||exp[i]=='}') { if(top==-1) return 0;
char left =s[top--]; if(isMatched(left,exp[i])==0) return 0; }
} if(top>-1) return 0; return 1; }
|
7、计算问题:
类似于这类问题,可以用递归去处理,不过递归的实质也是用栈,只是这个栈是系统分配的栈,我们这里是自己定义了一个栈。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| int calF(int m) { int cum=1; int s[maxSize],top=-1; while(m!=0) { s[++top]=m; m /= 3;
} while(top!=-1) cum *=s[top--]; return cum; }
|
8、共享栈:
这样来定义共享栈:(假设共享栈由s1和s2两个栈共享)
1 2
| int satck[maxsize]; int top1=-1,top2=maxsize;
|
可以看到,无非就是在栈尾后面一个位置定义一个top2去指向他,在栈首的前一个位置定义一个top1去指向他。
一般的,为了更好的同一形式,不用定义两个新的量去指向这些位置,而是定义一个数组,数组中有两个值,分别指向这两个位置。即:top[2]={-1,maxsize};就可以了。分别用top[0],top[1]去使用它们。
s1栈为空:top[0]==-1;s2栈为空:top[1]==maxsize;
s1入栈:stack[++top[0]] = x;
s2入栈:stack[–top[1]] = x;
栈满判断:top[0]+1==top[1];
9、用栈来模拟队列:
用两个栈来实现,即要将栈的“先进后出”变为队列的“先进先出”。