魔王语言解释
问题描述
有一个魔王总是使用自己的一种非常精练而抽象的语言讲话,没有人能听得懂,但他的语言是可以逐步解释成人能听懂的语言,因为他的语言是由以下两种形式的规则由人的语言逐步抽象上去的:
在这两种形式中,从左到右均表示解释。试写一个魔王语言的解释系统,把他的话解释成人能听得懂的话。
基本要求
用下述两条具体规则和上述规则形式(2)实现。设大写字母表示魔王语言的词汇;小写字母表示人的语言词汇,希腊字母表示可以用大写字母或小写字母代换的变量。魔王语言可含人的词汇。
测试数据
B(ehnxgz)B
解释成tsaedsaeezegexenehetsaedsae
。
若将小写字母与汉字建立下表所示的对应关系,则魔王说的话是:“天上一只鹅地上只鹅鹅追鹅赶鹅下鹅蛋鹅恨鹅天上一只鹅地上一只鹅”。
实现提示
将魔王的语言自右至左进栈,总是处理栈顶字符。若是开括号,则逐一出栈,将字母顺序入队列,直至闭括号出栈,并按规则要求逐一出队列再处理后入。其他情形较简单,请读者思考应如何处理。应首先实现栈和队列的基本操作。
选作内容
- 由于问题的特殊性,可以实现栈和队列的顺序存储空间共享。
- 代换变量的数目不限,则在程序开始运行时首先读入一组第一种形式的规则,而不是把规则固定在程序中(第二种形式的规则只能固定在程序中)。
思路
首先,定义一个栈数据结构LinkedStack
,包含栈顶指针top
和栈大小size
,并定义栈节点StackNode
,包含元素data
和下一个节点指针next
。这是一个链式栈的实现。
接下来,定义了一系列栈操作,包括初始化栈initStack
,栈插入元素stackPush
,判断栈是否为空stackEmpty
,栈顶元素出栈stackPop
,获取栈顶元素stackTop
。这些都是常见的栈操作。
定义了两个字符串A_NEW
和B_NEW
,分别对应魔王语言中的"A"和"B"的解释。
定义了四个函数fa
, fb
, fc
和fd
,分别对应四种不同的处理步骤。fa
函数将字符串中的"B"替换为tAdA
,fb
函数将字符串中的"A"替换为sae
。这两个函数对应魔王语言的解释规则。
fc
函数处理括号内的内容,它使用了栈数据结构。对于每个括号内的内容,首先初始化一个栈,将括号内的内容从左到右入栈,然后将栈内的元素逆序输出,每个元素前后都加上希腊字母,然后替换原来的括号内的内容。这个函数对应魔王语言的第二种解释规则。
fd
函数将解释后的魔王语言转换为汉字,对于每个字符,根据对应关系,将其替换为对应的汉字。
在main
函数中,首先从输入中读取魔王语言的字符串,然后依次调用fa
, fb
, fc
和fd
函数,将魔王语言解释为人能听懂的话,最后输出。
算法分析
时间复杂度分析:字符串替换操作的时间复杂度为
O
(
n
)
O(n)
O(n),其中
n
n
n为字符串的长度。在fa
和fb
函数中,每次替换操作都会遍历整个字符串,因此这两个函数的时间复杂度为
O
(
n
2
)
O(n^2)
O(n2)。在fc
函数中,每次处理括号内的内容时,都会进行一次栈的入栈和出栈操作,时间复杂度为
O
(
n
)
O(n)
O(n)。因此,整个程序的时间复杂度为
O
(
n
2
)
O(n^2)
O(n2)。
空间复杂度分析:除了输入的字符串外,还需要额外的空间存储栈,栈的大小最大为字符串的长度 n n n,因此,空间复杂度为 O ( n ) O(n) O(n)。
AC代码
#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
using Status = int;
using ElemType = char;
const int N = 1e4 + 7;
const int TRUE = 1;
const int FALSE = 0;
const int OK = 1;
const int ERROR = 0;
const int INFEASIBLE = -1;
// const int OVERFLOW = -2;
const string A_NEW = "sae";
const string B_NEW = "tAdA";
struct StackNode {
ElemType data;
StackNode *next;
};
struct LinkedStack {
StackNode *top;
int size;
};
Status initStack(LinkedStack &S) {
S.top = nullptr;
S.size = 0;
return OK;
}
Status stackPush(LinkedStack &S, ElemType e) {
StackNode *newNode = (StackNode *)malloc(sizeof(StackNode));
if (!newNode) {
return ERROR;
}
newNode->data = e;
newNode->next = S.top;
S.top = newNode;
S.size++;
return OK;
}
bool stackEmpty(LinkedStack S) { return !S.top; }
Status stackPop(LinkedStack &S) {
if (stackEmpty(S)) {
return ERROR;
}
StackNode *p = S.top;
S.top = p->next;
free(p);
p = nullptr;
S.size--;
return OK;
}
ElemType stackTop(LinkedStack S) {
if (stackEmpty(S)) {
return NULL;
}
return S.top->data;
}
string fa(string str) {
int pos = 0;
while ((pos = str.find('B', pos)) != string::npos) {
str.replace(pos, 1, B_NEW);
pos += B_NEW.length();
}
return str;
}
string fb(string str) {
int pos = 0;
while ((pos = str.find('A', pos)) != string::npos) {
str.replace(pos, 1, A_NEW);
pos += A_NEW.length();
}
return str;
}
string fc(string str) {
for (int i = 0; i < str.length(); i++) {
if (str[i] == '(') {
string s = "";
LinkedStack stk;
initStack(stk);
int begin = i;
char xita = str[++i];
while (str[++i] != ')') {
stackPush(stk, str[i]);
// cout << str[i] << endl;
}
int len = stk.size;
while (stk.size) {
char t = stackTop(stk);
stackPop(stk);
s += xita;
s += t;
}
s += xita;
// cout << s << endl;
str.replace(begin, len + 3, s);
i = begin + len * 2 + 1;
}
}
return str;
}
string fd(string str) {
string ret = "";
for (const auto i : str) {
switch (i) {
case 't':
ret += "天";
break;
case 'd':
ret += "地";
break;
case 's':
ret += "上";
break;
case 'a':
ret += "一只";
break;
case 'e':
ret += "鹅";
break;
case 'z':
ret += "追";
break;
case 'g':
ret += "赶";
break;
case 'x':
ret += "下";
break;
case 'n':
ret += "蛋";
break;
case 'h':
ret += "恨";
break;
}
}
return ret;
}
int main() {
string str;
cin >> str;
str = fa(str);
str = fb(str);
str = fc(str);
str = fd(str);
cout << str << endl;
return 0;
}