[问题描述]
有一个魔王总是使用自己的一种非常精练而又抽象的语言讲话,没有人能听得懂,但他的语言是可以逐步解释成人能听懂的语言,因为他的语言是由以下两种形式的规则由人的语言逐步抽象上去的:
(1) α -> β1β2…βm
(2)(θδ1δ2…δn)->θδnθδn-1… θδ1θ
在这两种形式中,从左到右均表示解释。试写一个魔王语言的解释系统,把他的话解释成人能听得懂的话。
[基本要求]
用下述两条具体规则和上述规则形式(2)实现。设大写字母表示魔王语言的词汇;小写字母表示人的语言词汇;希腊字母表示可以用大写字母或小写字母代换的变量。魔王语言可含人的词汇。
(1)B -> tAdA
(2)A -> sae
[测试数据]
B(ehnxgz)B解释成tsaedsaeezegexenehetsaedsae
解题思路:
将魔王语言作为一个字符串读入进来,首先检查括号是否匹配,如果不匹配就无法解释。如果匹配,然后将字符串从尾到头依次压入栈S中,将栈S中的内容依次弹出压入栈S2中,直至遇到右括号,将其压入栈S1中,并将栈S2弹出依次压入栈S1中,直至遇到左括号压入栈S1中,这样栈S1中存放的内容就是匹配的第一个内重括号,将栈S1栈顶元素左括号弹出,将左括号下面的那个元素保存在e1变量中,然后将其他元素弹出依次压入栈S3中,在将e1与栈S3中依次弹出的元素压入栈S2中,重复这个过程,直至将魔王语言中所有的括号都处理完为止,所以这个思路可以处理多重括号嵌套的问题。。
完整的实现代码如下:
#include "iostream" #include "string" using namespace std; class SqStack //使用链表实现栈类 { private: struct Node { int content; char word; Node *next; } ; Node *top,*base; public: SqStack(); virtual ~SqStack(); bool push(char e); bool pop(char &e); bool StackEmpty(); }; //栈的基本操作 SqStack::SqStack() { top=base=new Node; } SqStack::~SqStack() { } bool SqStack::push(char e) //压栈操作 { Node *p=new Node; if(p==NULL) { cout<<"Stack is overflow"<<endl; return false; } else { p->word=e; p->next=top; top=p; return true; } } bool SqStack::pop(char &e) //出栈操作 { if(top==NULL) { cout<<"Stack is empty"<<endl; return false; } else { if(top==base) return false; Node *p=top; top=top->next; e=p->word; delete p; return true; } } bool SqStack::StackEmpty() //判断是否为空栈 { return top==base; } class SqQueue //使用链表实现队列类 { private: struct Node { int content; char word; Node *next; } ; Node *head,*last; public: SqQueue(); virtual ~SqQueue(); bool EnQueue(char e); bool DeQueue(char &e); bool QueueEmpty(); void OutQueue(); void EnQueue_A(); void EnQueue_B(); }; //队列的基本操作 SqQueue::SqQueue() { head=last=new Node; } SqQueue::~SqQueue() { } bool SqQueue::EnQueue(char e) //入队列 { Node *p=new Node; if(p==NULL) { cout<<"Queue is overflow"<<endl; return false; } else { p->word=e; last->next=p; last=p; p->next=NULL; return true; } } bool SqQueue::DeQueue(char &e) //出队列 { if(head==NULL) { cout<<"Queue is empty"<<endl; return false; } else { Node *p=head; head=head->next; e=p->word; delete p; return true; } } void SqQueue::OutQueue() //输出队列中的数据 { for(Node *p=head->next;p!=NULL;p=p->next) cout<<p->word; cout<<endl; } bool SqQueue::QueueEmpty() { return head==last; } void SqQueue::EnQueue_A() { EnQueue('s'); EnQueue('a'); EnQueue('e'); } void SqQueue::EnQueue_B() { EnQueue('t'); EnQueue_A(); EnQueue('d'); EnQueue_A(); } bool read_language(SqStack &S) //将魔王语言倒置压入栈中 { int i,n,left=0,right=0; string m; cout<<"请输入魔王语言:"<<endl; cin>>m; n=m.length(); //求字符串长度 for(i=0;i<n;i++) { if(m[i]=='(') left++; else if(m[i]==')') right++; } if(left!=right) return false; for(i=n-1;i>=0;i--) { S.push(m[i]); } return true; } void push_and_pop(SqStack &S1,SqStack &S2) //处理规则2 { char e,e1; SqStack S3; //栈S3作为进行转换的中间变量 SqStack(); while(!S1.StackEmpty()) { S1.pop(e); if(e=='(') { S1.pop(e); e1=e; //e1中保存的就是魔王语言中(右边的第一个字母,就是第二种规则中的θ if(e!=')') S1.pop(e); while(e!=')') { S3.push(e); S1.pop(e); } while(!S3.StackEmpty()) { S2.push(e1); //根据第二种解释规则,将θ进行多次压栈操作 S3.pop(e); S2.push(e); } S2.push(e1); } } } int main(void) { char e; bool flag; SqStack S,S1,S2; SqQueue Q; SqStack(); SqQueue(); flag=read_language(S); //读入魔王语言 if(!flag) { cout<<"括号不匹配,无法解释!"<<endl; system("pause"); return 0; } while(!S.StackEmpty()) { S.pop(e); if(e==')') { S1.push(e); S2.pop(e); while(e!='(') { S1.push(e); S2.pop(e); } if(e=='(') S1.push(e); push_and_pop(S1,S2); } else S2.push(e); } //魔王语言的前面部分在栈S2的底部,后面部分在栈S2的顶部,需要转换一下 while(!S2.StackEmpty()) { S2.pop(e); S.push(e); //魔王语言的后面部分在栈S的底部,前面部分在栈S的顶部 } //上面的操作进行的是第二种解释规则 //下面的操作进行的是第一种解释规则 while(!S.StackEmpty()) { S.pop(e); if(e=='A') Q.EnQueue_A(); if(e=='B') Q.EnQueue_B(); else Q.EnQueue(e); } cout<<"魔王语言可以解释为:"<<endl; Q.OutQueue(); system("pause"); return 0; }
运行结果如下:
一重括号:
括号不匹配: