一、广义表操作思路
1.创建思路
typedef struct node
{
int tag; //用于识别单元素与子表
union //大括号中多选一
{
char data; //单元素
struct node *child; //子表
}val;
struct node *next; //指向下一个元素
}GLNode;
由图可看出,tag=1时,为子表的头结点,tag=0时,为子表元素;并且头结点有一个指向孩子结点的child指针,元素结点有一个指向兄弟结点的next指针。
那创建思路不就来了
- 先不考虑外面的括号,如果字符串不为结束符,就申请存储空间。
- 如果字符为(,就说明进入一个新的子串,那就把标识符赋值1,然后递归创建它的孩子结点。
- 如果字符为),就说名子串结束,将表置空。
- 如果为正常字符,tag=0,孩子结点的数据=这个字符。
- 如果字符等于 ‘ ,’,说明有另一个子串,递归创建它的兄弟指针。
创建思路还有一个是将串分解,用到String 类库的 个别函数。个人尝试过,有点复杂,最后没调试通,感兴趣的可以去看看广义表创建
2、遍历思路
- 表不为空是大前提
- 如果tag==0,说明是元素结点,输出值。
- 如果为tag==1,说明进入子串了,所以输出(,并且递归遍历它的孩子结点,最后输出)。
- 如果兄弟结点不为空,则输出‘ ,’,并且递归遍历它的兄弟结点。
二、代码实现
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int tag;
union {
char data;
struct node *child;
} val;
struct node *next;
} GLNode;
// 创建广义表
GLNode *Create(const char **elem) {
if (!**elem) return NULL;
GLNode *L = (GLNode *)malloc(sizeof(GLNode));
if (!L) return NULL;
char c = **elem;
(*elem)++;
if (c == '(') {
L->tag = 1;
L->val.child = Create(elem);
} else if (c == ')') {
free(L); // 释放当前节点,因为')'意味着子表结束
return NULL;
} else {
L->tag = 0;
L->val.data = c;
}
L->next = Create(elem); // 继续处理兄弟节点
return L;
}
// 输出广义表
void Print(GLNode *s) {
if (!s) return;
if (s->tag == 0) {
printf("%c", s->val.data);
} else {
printf("(");
Print(s->val.child);
printf(")");
}
if (s->next) {
printf(",");
Print(s->next);
}
}
// 求广义表长度
int Getlength(GLNode *s) {
if (!s) return 0;
int len = Getlength(s->next); // 兄弟节点的长度
if (s->tag == 1) {
// 如果是子表,加上子表的长度(这里假设子表长度函数已定义,但这里直接递归调用Getlength)
len += 1 + Getlength(s->val.child); // 1代表子表本身
} else {
len += 1; // 原子节点长度为1
}
return len;
}
// 求深度
int Getdepth(GLNode *s) {
if (!s) return 0;
int depth = 0;
if (s->tag == 1) {
depth = Getdepth(s->val.child) + 1;
}
int nextDepth = Getdepth(s->next);
if (nextDepth > depth) depth = nextDepth;
return depth;
}
// 求原子结点个数
int Number(GLNode *s) {
if (!s) return 0;
int count = 0;
if (s->tag == 0) count++;
count += Number(s->val.child);
count += Number(s->next);
return count;
}
int main() {
char *str = "(a,(b,c,d))";
GLNode *L = Create(&str);
printf("广义表L为:");
Print(L);
printf("\n广义表的长度:");
printf("%d\n", Getlength(L));
printf("广义表的深度:");
printf("%d\n", Getdepth(L));
printf("广义表的元素个数为:");
printf("%d\n", Number(L));
// 释放内存(此处略过,实际使用时需要添加)
return 0;
}
三、运行。
搞了将近八个小时,大部分时间都用在对字符串进行分割的创建思路上,随后看看大神们写的,突然茅塞顿开,最重要的还是先明白广义表的存储结构,怎么运行的,其次在合理运用递归,还是能简单的搞出来的,代码可运行,需要的可复制。