问题:
现在有一个合法的二进制表达式,请计算出该表达式的值
———————————————————————————————————
Input
输入一行字符串,表示一个二进制表达式。长度不超过 100,000
Ouput
输出表达式的值
Input Output
(0&1^0|1)|1&0 ^1 1
———————————————————————————————————
两种方法
1:被动
遇到右括号再进行运算,直至左括号
#include<stdio.h>
#include<string.h>
char op(char a,char b,char c){
if(b=='&'){
return ((a-'0')&(c-'0'))+'0';
}
if(b=='|'){
return ((a-'0')|(c-'0'))+'0';
}
if(b=='^'){
return ((a-'0')^(c-'0'))+'0';
}
}
char a[100000000];
char f[100000000];
char s[100000000];
char f1[100000000];
char s1[100000000];
int main(){
//char a[100];
//此处在原有字符串首尾分别加上'(',')',是为了能在结束时处理最后剩余的没有
//在括号内的运算,可以不加,但要在最后再处理一次,如果还有运算符剩下
scanf("%s",a+1);
a[0]='(';
a[strlen(a+1)+1]=')';
a[strlen(a+1)+2]='\0';
int fi=0;
int fj=0;
int sj=0;
int si=0;
int i=0;
while(a[i]!='\0'){
switch(a[i]){
case '(':
f[fi++]='(';
break;
case ')':
if(f[fi-1]=='('){
fi--;
break;
}
while(f[fi-1]!='('){
if(f[fi-1]=='&'){
s[si-2]=op(s[si-2],'&',s[si-1]);
si--;
fi--;
}else{
s1[sj++]=s[--si];
f1[fj++]=f[--fi];
}
}
while(fj){
f[fi++]=f1[--fj];
s[si++]=s1[--sj];
}
while(f[fi-1]!='('){
if(f[fi-1]=='^'){
s[si-2]=op(s[si-2],'^',s[si-1]);
si--;
fi--;
}else{
s1[sj++]=s[--si];
f1[fj++]=f[--fi];
}
}
while(fj){
f[fi++]=f1[--fj];
s[si++]=s1[--sj];
}
while(f[fi-1]!='('){
if(f[fi-1]=='|'){
s[si-2]=op(s[si-2],'|',s[si-1]);
si--;
fi--;
}else{
s1[sj++]=s[--si];
f1[fj++]=f[--fi];
}
}
while(fj){
f[fi++]=f1[--fj];
s[si++]=s1[--sj];
}
fi--;
break;
case '0':
case '1':
s[si++]=a[i];
break;
default:
f[fi++]=a[i];
break;
}
i++;
}
printf("%d",s[0]-'0');
}
理解:
1:
使用栈分别存储数字和运算符及’(’,当遇到’)'时进行运算
2:
考虑到优先级的原因,须按优先级的顺序处理运算符,先处理所有最高的优先级,然后次之,因此外加一个存储数字和一个存储运算符的栈,来暂时存储位于较靠近栈顶位置又优先级小的运算符及其算子
———————————————————————————————————
2:主动
#include<stdio.h>
char op(char a,char b,char c){
if(b=='&'){
return ((a-'0')&(c-'0'))+'0';
}
if(b=='|'){
return ((a-'0')|(c-'0'))+'0';
}
if(b=='^'){
return ((a-'0')^(c-'0'))+'0';
}
}
int taller(char c,char c1){//c > c1返回1
if(c1=='&'){
return 0;
}
if(c=='&'){
return 1;
}
if(c1=='^'){
return 0;
}
if(c=='^'){
return 1;
}
return 0;
}
char a[100000000];
char stack[100000000];
int top;
char queue[1000000000];
int front,tail;
void push(char c){
stack[top++]=c;
}
char pop(){
return stack[--top];
}
void enqueue(char c){
queue[tail++]=c;
tail%=1000000000;
}
char dequeue(){
char c=queue[front++];
front%=1000000000;
return c;
}
int main(){
scanf("%s",&a);
int i=0,flag=0;
char c;
while(a[i]!='\0'){
switch(a[i]){
case '(':
push(a[i]);
break;
case ')':
c=pop();
while(c!='('){
enqueue(c);
c=pop();
}
break;
case '0':
case '1':
enqueue(a[i]);
break;
default:
if(top!=0){
c=pop();
while(c!='('&&!taller(a[i],c)){
enqueue(c);
if(top==0){//已经没有符号可比
flag=1;
break;
}
c=pop();
}
if(!flag){//不符合循环跳出的要重新入栈
push(c);
}
flag=0;
}
push(a[i]);//将新符号加入栈中
break;
}
i++;
}
while(top){//将剩余符号全部加入队列
enqueue(pop());
}
i=front;
while(i!=tail){//后缀表达式
printf("%c",queue[i++]);
}
char a,b;
while(tail!=front){
c=dequeue();
if(c=='0'||c=='1'){
push(c);
}else{
b=pop();
a=pop();
push(op(a,c,b));
}
}
printf("\n%c",pop());
}
理解:
1:
若栈顶运算符优先级大于或等于新运算符,则优先级保证可以先运算栈顶运算符
2:
遇到右括号可一直运算到左括号,因为有1保证前面的运算符优先级总比后面小
3.
中缀表达式转后缀表达式:(可以不需要转换,直接算,以上代码有转换)
从左到右遍历,遇数字入队列,若是左括号,入栈,若是右括号,全部运算符出栈入队列,直至左括号,
若是运算符,若栈不空且栈顶不是左括号且栈顶运算符优先级不比该运算符小,取出栈顶运算符加入队列,继续判断,再将该运算符入栈,遍历结束后将运算符全部出栈入队列