1.【问题描述】
有一个魔王总是使用自己的一种非常精练而抽象的语言讲话,没有人能昕得懂,但他的语言是可以逐步解释成人能听懂的语言,因为他的语言是由以下两种形式的规则由人的语言逐步抽象上去的:
(1)α->β1β2β3
(2)(θδ1δ2δ3)->θδ1θδ2θδ3θ
在这两种形式中,从左到右均表示解释。试写一个魔王语言的解释系统,把他的话解释成人能听得懂的话。
2.【基本要求】
用下述两条具体规则和上述规则形式(2)实现。设大写字母表示魔王语言的词汇;小写字母表示人的语言词汇;希腊字母表示可以用大写字母或小写字母代换的变量。魔王语言可含人的词汇。
(1)B->tAdA
(2)A->sae
3. 【测试数据】
B(ehnxgz)B解释成tsaedsaeezegexenehetsaedsae
若将小写字母与汉字建立下表所示的对应关系,则魔王说的话是“天上一只鹅地上一只鹅鹅追鹅赶鹅下鹅蛋鹅恨鹅天上一只鹅地上一只鹅”。
t | d | s | a | e | z | g | x | n | h |
天 | 地 | 上 | 一只 | 鹅 | 追 | 赶 | 下 | 蛋 | 恨 |
#include <iostream>
#include <string>
using namespace std;
//类不是实体,是一种抽象类型,不占存储空间
class SqStack //使用链表实现栈类,SqStack为类名
{
private: //声明为私有的
struct Node //声明一个名为Node的结构体类型
{
int content; //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的优点是将错误返回给调用环境,由调用环境决定程序的下一步走向
//返回0/1
bool SqStack::push(char e) //压栈操作
{
Node *p=new Node;
//用new运算符动态建立一个对象,与delete配合使用
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; //p指针指向栈顶元素
top=top->next; //指针下移,元素出栈
e=p->word; //返回值e
delete p; //删除new出来的p
return true;
}
}
bool SqStack::StackEmpty() //判断是否为空栈
{
return top==base; //top==base时栈空
}
class SqQueue //使用链表实现队列类
{
private:
struct Node
{
int content;
char word;
Node *next;
} ;
Node *front,*rear;
public:
SqQueue();
virtual ~SqQueue();
bool EnQueue(char e);
bool DeQueue(char &e);
bool QueueEmpty();
void OutQueue();
void EnQueue_A();
void EnQueue_B();
};
//队列的基本操作
SqQueue::SqQueue()
{
front=rear=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;
rear->next=p;
rear=p;
p->next=NULL;
return true;
}
}
bool SqQueue::DeQueue(char &e) //出队列
{
if(front==NULL)
{
cout<<"Queue is empty"<<endl;
return false;
}
else
{
Node *p=front;
front=front->next;
e=p->word;
delete p;
return true;
}
}
void SqQueue::OutQueue() //输出队列中的数据
{
for(Node *p=front->next;p!=NULL;p=p->next)
{cout<<p->word;}
cout<<endl<<endl;
cout<<"其对应的汉语为:"<<endl<<endl;
for(Node *p=front->next;p!=NULL;p=p->next)
{
if(p->word=='t')cout<<"天";
else if(p->word=='d')cout<<"地";
else if(p->word=='s')cout<<"上";
else if(p->word=='a')cout<<"一只";
else if(p->word=='e')cout<<"鹅";
else if(p->word=='z')cout<<"追";
else if(p->word=='g')cout<<"赶";
else if(p->word=='x')cout<<"下";
else if(p->word=='n')cout<<"蛋";
else if(p->word=='h')cout<<"恨";
}
cout<<endl<<endl;
}
bool SqQueue::QueueEmpty()
{
return front==rear;
//front==rear时队列为空
}
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;
while(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); //在S3中存入出栈的元素,入栈操作
S1.pop(e); //S1继续出栈
}
while(!S3.StackEmpty())
{
S2.push(e1);
//根据第二种解释规则,将θ进行多次压栈操作
S3.pop(e);
S2.push(e);
}
S2.push(e1);
}
}
}
int main()
{
char e;
bool flag;
SqStack S,S1,S2; //用栈类定义三个结构体变量
SqQueue Q; //用队列类定义一个结构体变量Q
SqStack(); //建一个空栈
SqQueue(); //建一个空队列
cout<<" ======================================="<<endl;
cout<<" ======================================="<<endl;
cout<<" || 欢迎使用 ||"<<endl;
cout<<" || 魔王语言翻译 ||"<<endl;
cout<<" ======================================="<<endl;
cout<<" ======================================="<<endl;
cout<<endl<<endl;
while(1)
{
Start:flag=read_language(S);//读入魔王语言,存入栈S中
if(!flag)
{
cout<<"括号不匹配,无法解释!"<<endl<<endl;
goto Start;
}
while(!S.StackEmpty()) //当S栈不为空
{
S.pop(e); //S中元素出栈
if(e==')') //当元素是右括号
{
S1.push(e); //S1将该元素入栈
S2.pop(e); //S2将元素出栈
while(e!='(') //当S2出栈的不是左括号
{
S1.push(e);//S1将元素入栈
S2.pop(e); //S2将元素出栈
}
if(e=='(') //当S2出栈的是左括号
S1.push(e); //S1将左括号入栈
//S1内是一个完整括号内容,用第二种规则处理
//S1栈顶是左括号,栈底是右括号
push_and_pop(S1,S2);
}
else
S2.push(e);
//若S出栈的不是右括号,S2就将其入栈
}
//S2存储的是经过第二种处理后的魔王语言
//魔王语言的前面部分在栈S2的底部,后面部分在栈S2的顶部,需要转换一下
//转换后存入S中
while(!S2.StackEmpty())
{
S2.pop(e);
S.push(e);
//魔王语言的后面部分在栈S的底部,前面部分在栈S的顶部
}
//上面的操作进行的是第二种解释规则
//下面的操作进行的是第一种解释规则
while(!S.StackEmpty())
{
S.pop(e);
if(e=='A') //如果出栈的是A
Q.EnQueue_A(); //就将sae入队列,即进行第一种解释
if(e=='B') //如果出栈的是B
Q.EnQueue_B(); //就将tAtA入队列
else
Q.EnQueue(e); //否则的话只将出栈元素入队列就好
}
cout<<"魔王语言可以初步解释为:"<<endl<<endl;
Q.OutQueue(); //先进先出,输出队列中经过第一种处理的魔王语言
cout<<"感谢您使用魔王语言解释程序,您可以继续输入:)"<<endl<<endl;
}
return 0;
}