Description
大家都学过了布尔表达式的翻译,其中有一个拉链-回填技术,这次我们就练习这个技术。
Input
输入为一行字符串,例如: a < b or c < d and e < f
每个符号都用空格间隔。
其中逻辑运算符包含 and 和 or , 关系运算符包含 < 、> 、<= 、 >= 、== 、 != 。
Output
假链跳到0,真链跳到1,表达式序号从100开始排。
Sample
Input
a < b or c < d and e < f
Output
100(j<,a,b,1) 101(j,_,_,102) 102(j<,c,d,104) 103(j,_,_,0) 104(j<,e,f,100) 105(j,_,_,103)
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
/********************************
M - 翻译布尔表达式
时间:2021 - 5 - 5
注意事项:首先要注意 and 和 or 之间是存在优先级关系的
如果 or 和and 一起出现的话,那么 这个bool 表达式的假出口 一定是
在最后一个or后面(即全为假的时候),而这个bool表达式的真出口 4一定在
第一or的前面,因为or的话有一个为真其余全为真,接下来的关键就是找到这个位置,
即假出口和真出口的位置,所以无论真出口还是假出口都是遇到or 开始操作的 或者是
走到最后才进行的操作,为了能处理最后一个or后面的操作,所以需要一个结束的标志
这里我选择#,及遇到#号然后进行操作
********************************/
// 一个结构体队列用来存储 表达式
typedef struct{
char left ; // 表达式左边的字符
char right; // 表达式右边的字符
char op[4] ; // 由于 op可以最大可以为 2个 , 为了 让其形成字符串,后面还要加一个 \0 故至少需要三个
}Queue;
int top = 0 ; // 记录队列的起始位置
int cur = 0 ; // 记录队列的当前位置
int count = 100; // 记录 序列号
int TRUE = 1 ; //记录真出口,真出口 一定是1 有上面的分析很容易得出
int FALSE = 100 ;// 记录假出口 , 由于假出口一开始无法确定位置,所以先把假出口放到第一个位置,然后遍历找到真正的假出口
char str[100000] ; // 用来接收输入的字符串
char temp[5] ; // 记录临时数据
int tcount = 0; // 临时数据表的指针
int main(){
gets(str) ; // 从键盘上获得数据
// 为 数据添加# 代表结束
int len = strlen(str) ;
str[len] = '#' ;
str[len+1] = '\0' ;
len = strlen(str) ;
Queue s[100000] ;
int i = 0;
// 遍历新补充好了的str 来获得 的数据
for(;i<len ; i++){
// 如果是空格就跳过
if(str[i] == ' '){
continue ;
}
else {
temp[tcount++] = str[i] ; // 先将数据存入temp 中,然后在给s
if(str[i] == '#'){
// 也就是最后 ,那么假出口一定在最后
FALSE = 0 ; // 其余情况不变化
for(;top<cur-1 ; top++){
// 由于最后一个and 连接的 表达式可以决定 真出口 ,这时就要分开进行讨论
printf("%d(j%s,%c,%c,%d)\n",count,s[top].op,s[top].left,s[top].right,count+2) ;
count++ ; //跳到下一条表达式上
//假出口
printf("%d(j,_,_,%d)\n",count,FALSE) ;
// 记录当前的假出口,方便回填
FALSE = count ;
count++ ;
}
// or前面的部分确定真出口
printf("%d(j%s,%c,%c,%d)\n",count,s[top].op,s[top].left,s[top].right,TRUE) ;
// 记录真出口方便回填
TRUE = count ;
count++ ; //跳到下一条表达式上
//假出口
printf("%d(j,_,_,%d)\n",count,FALSE) ;
count++ ;
// 将当前队列进行清空
top = cur ;
// 初始化temp
tcount = 0;
temp[tcount] = '\0' ;
}
if(tcount == 2){
temp[tcount] = '\0' ;
// 判断是否为or
if(strcmp(temp,"or") ==0){
// 由于假出口一定在or 后面
FALSE += 2 ;
// 遍历当前队列中的数据,即or 前面的数据,都是由and组成的
for(;top<cur-1 ; top++){
// 由于最后一个and 连接的 表达式可以决定 真出口 ,这时就要分开进行讨论
printf("%d(j%s,%c,%c,%d)\n",count,s[top].op,s[top].left,s[top].right,count+2) ;
count++ ; //跳到下一条表达式上
//假出口
printf("%d(j,_,_,%d)\n",count,FALSE) ;
// 记录当前的假出口,方便回填
FALSE = count ;
count++ ;
}
// or前面的部分确定真出口
printf("%d(j%s,%c,%c,%d)\n",count,s[top].op,s[top].left,s[top].right,TRUE) ;
// 记录真出口方便回填
TRUE = count ;
count++ ; //跳到下一条表达式上
//假出口
printf("%d(j,_,_,%d)\n",count,FALSE) ;
// 可能大家会在这儿疑惑 ,为什么上面回填 FALSE ,这儿就不回填FLASE
// 原因是 其实这里的FALSE 实际上是的前的and表达式构成的假出口
count++ ;
// 将当前队列进行清空
top = cur ;
// 初始化temp
tcount = 0;
temp[tcount] = '\0' ;
}
else {
continue ;
}
}
else if(tcount == 3){
//判断是否为and ,或者三个字符长度的表达式
temp[tcount] = '\0' ;
if(strcmp(temp,"and") == 0){
FALSE +=2; // 遇到一个and 假出口就加2
// 初始化 temp
tcount = 0;
temp[tcount] = '\0' ;
}
else if(str[i] != '=') {
// 如果不是 = 的话,说明当前的表达式 是一个长度为3 的表达式,然后将其放入队列中
s[cur].left = temp[0] ;
s[cur].right = temp[2] ;
temp[0] = temp[1] ;
temp[1] = '\0' ;
strcpy(s[cur].op,temp) ;
cur++ ;
// 初始化temp
tcount = 0;
temp[tcount] = '\0' ;
}
else {
continue;
}
}
else if(tcount == 4){
//这种情况必是表达式
s[cur].left = temp[0] ;
s[cur].right = temp[3] ;
temp[0] = temp[1] ;
temp[1] = temp[2] ;
temp[2] = '\0' ;
strcpy(s[cur].op,temp) ;
cur++ ;
// 初始化temp
tcount = 0;
temp[tcount] = '\0' ;
}
}
}
return 0 ;
}