一、问题重述
有一个魔王总是用自己一种非常精练而抽象的语言讲话,没有人能听懂,但他的语言可以逐步的转换成人的语言,他的语言由以下两种转换规则由人的语言逐步抽象上去的:
(1)α->β1β2......βm
(2)(θδ1δ2......δn)->θδnθδn-1θ......θδ1θ
在这两种形式中从左到右表解释。要求编写一个魔王语言解释系统,把他的话转换成人能听懂的语言。
设大写字母表示魔王语言的词汇;小写字母表示人的词汇;希腊字母表示可以用大写字母或小写字母代换的变量。魔王语言可以含人的词汇。
(1)B->tAdA;
(2)A->sae.
(3)
|---|---|---|----|---|---|---|---|---|---|
| t | d | s | a | e | z | g | x | n | i |
| 天 | 第 | 上 | 一个 | 鹅 | 追 | 赶 | 下 | 蛋 | 恨 |
[魔王语言翻译]
二、主要思路分析
(1)遍历字符数组,将字符数组中的大写字母转换成对应的小写字母
(2)去掉字符串中的括号
1.首先找到'('和对应的')',将中间的小写字母按照(θδ1δ2......δn)->θδnθδn-1θ......θδ1θ进行翻译。在翻译过程中,首先保存第一个字母θ,因为是逆序输出,所以要用栈(后进先出)来存储括号中剩余的字母。
2.将括号前的字母,翻译后的括号中的字母,括号后的字母连接成一个字符串,即得到最终字符串。
3.将字符串与汉字一一对应,输出最终的魔王语言。
三、源代码
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
char ans[10001];
char mp[10001];
char s[10000];
typedef struct Stack {
char data;
struct Stack* next;
}*sta;
//将栈初始化
void init(sta* now) {
*now = NULL;
}
//判断栈时候为空
int isEmpty(sta now) {
return now == NULL;
}
//入栈(头插)
void pushStack(sta* now, char e) {
//为栈中新的节点开辟空间
sta p = (sta)malloc(sizeof(struct Stack));
//利用头插,将节点放入栈中
p->data = e;
p->next = *now;
*now = p;
}
//出栈(头删)
void pop(sta* now) {
if (isEmpty(*now)) {
printf("栈空,无法出栈");
exit(0);
}
sta p = *now;
*now = p->next;
free(p);
}
//返回栈顶元素
char top(sta now) {
if (isEmpty(now)) {
printf("栈空,无法出栈\n");
exit(0);
}
return now->data;
}
void Change() {
char temp[10001]="";
for (int i = 0; i < strlen(s); i++) {
if (s[i] == 'B') {
strcat(temp, "tAdA");
}
else {
strncat(temp, &s[i], 1);
}
}
strcpy(s, temp);
temp[0] = '\0';
for (int i = 0; i < strlen(s); i++) {
if (s[i] == 'A') {
strcat(temp, "sae");
}
else {
strncat(temp, &s[i], 1);
}
}
strcpy(s, temp);
/*s = "";
for (int i = 0; i < strlen(temp); i++) {
if (temp[i] == 'A') {
strcat(s, "sae");
}
else {
strncat(s, &temp[i], 1);
}
}*/
}
void dfs(int pi) {
sta st;
init(&st);
//记录下'('后面的字母,方便后面使用
char s1 = s[pi + 1];
int ded;//用来标记')'的位置
//为什么要从pi+2开始遍历
//是为了将从pi+2开始的所有括号中的字母放入栈中
//pi和pi+1已经记录下了
for (int i = pi + 2; i < strlen(s); i++) {
if (s[i] == '(') {
dfs(i);//利用递归,消除嵌套的'()'
}
else if (s[i] == ')') {
ded = i;
break;
}
else {
//将括号中的字母入栈
//虽然st为一级指针,但是st的头会改变,需要传地址,利用二级指针
//将括号中间的字母放入栈中
pushStack(&st, s[i]);
}
}
char p1[10001], p2[10001], p3[10001] = "";
//将括号前的所有字母赋值给p1,这里也包括了'('
strncpy(p1, s, pi+ 1);
p1[pi + 1] = '\0';
//将括号后的所有字母赋值给p2
strncpy(p2, s + ded + 1, strlen(s) - ded - 1);
p2[strlen(s) - ded - 1] = '\0';
//将括号中的字母按照规律存放到p3中
while (!isEmpty(st)) {
//将括号中的第一个字母放入p3
strncat(p3, &s1, 1);
//将其他的字母按照规律放入p3
char temp = top(st);
strncat(p3, &temp,1);
//将使用过的字母出栈,始终保持要使用的元素在栈顶
pop(&st);
}
strncat(p3, &s1, 1);
//将所有变换后的字母赋值给s
//是为最后翻译过的字母
sprintf(s, "%s%s%s", p1, p3, p2);
}
char* find() {
char answer[10001];
answer[0] = '\0';
for (int i = 0; i < strlen(s); i++) {
if (s[i] == '(') {
//如果检测到'('要消去(,并要把()里面的字母按照规定排列
dfs(i);//记录下'('的位置
}
else {
strncat(answer, &s[i], 1);
}
}
return answer;
}
void translate() {
for (int i = 0; i < strlen(ans); i++) {
if (ans[i] == 't') {
printf("天");
}
else if (ans[i] == 'd') {
printf("地");
}
else if (ans[i] == 's') {
printf("上");
}
else if (ans[i] == 'a') {
printf("一只");
}
else if (ans[i] == 'e') {
printf("鹅");
}
else if (ans[i] == 'z') {
printf("追");
}
else if (ans[i] == 'g') {
printf("赶");
}
else if (ans[i] == 'x') {
printf("下");
}
else if (ans[i] == 'n') {
printf("蛋");
}
else if (ans[i] == 'h') {
printf("恨");
}
}
}
Print() {
int i = 0;
for (i = 0; i < strlen(s); i++) {
printf("%c", s[i]);
}
}
int main() {
printf("请输入魔王语言:");
scanf("%s", s);
//将A转化为sae,将B转化为tAdA
Change();
strcpy(ans, find());
printf("整理后的魔王语言为:\n");
printf("%s\n", ans);
printf("翻译后的魔王语言是:\n");
translate();
return 0;
}
四、样例输出
例如:魔王语言为:B(ehnxgz)B,翻译后的字符串:tsaedsaeezegexenehetsaedsae。
对应的中文:天上一只鹅地上一只鹅鹅追鹅赶鹅下鹅蛋鹅恨鹅天上一只鹅地上一只鹅