画出下列广义表的存储结构图
广义表(Generalized List)是一种常见的数据结构,可以看作是线性表的扩展。广义表中的元素可以是单个数据元素,也可以是另一个广义表,因此广义表是一个递归定义的结构,适合于表示各种复杂的结构。
在实际运用中,广义表常被用于表示树形结构、图形结构、符号表等等,因此了解广义表的存储结构是非常重要的。本文将从两个角度分析广义表的存储结构,分别是链表存储和顺序存储。
一、链表存储
链表存储法是广义表的一种基本存储结构,将广义表中的每个元素都看作单独的节点,这些节点通过指针来连接,形成一个链表。这种方式比较适合于存储不规则的广义表,而且在读取和添加元素时也更加方便。
下面以广义表((1,2),3,(4,(5,6),7))为例,讲解链表存储法的具体实现过程。
首先定义广义表节点的结构体类型如下:
```
typedef struct GLNode {
int tag;
union {
int data;
struct GLNode* hp;
}u;
struct GLNode* tp;
}*GList;
```
其中tag用来标记当前节点是一个子表还是单个数据元素,data表示当前节点存储的数据,hp表示指向子表的指针,tp表示指向下一个节点的指针。
接下来是广义表的创建过程:
```
void CreateGList(GList& L, char* str) {
if(*str == '\0') {
L = NULL;
return;
}
L = (GList)malloc(sizeof(GLNode));
if(*str == '(') {
L->tag = 1;
GList p = L->u.hp = NULL;
++str;
CreateGList(p, str);
L->tp = (GList)malloc(sizeof(GLNode));
L = L->tp;
L->tag = 0;
L->tp = NULL;
++str;
} else {
L->tag = 0;
L->u.data = atoi(str);
L->tp = (GList)malloc(sizeof(GLNode));
L = L->tp;
L->tag = 0;
L->tp = NULL;
while(*str != ',' && *str != ')' && *str != '\0') ++str;
if(*str == ',') {
++str;
CreateGList(L, str);
} else {
L = NULL;
}
}
}
```
该函数会根据输入的字符串str递归地构造广义表,并将结果存储在L中。
到此为止,我们已经完成了链表存储法的广义表实现。当需要遍历、访问或者修改广义表中的元素时,只需要通过指针进行类似链表的操作即可。
二、顺序存储
顺序存储法是将广义表中的各个元素按照定义的线性次序依次存储在一块连续的存储区里,如果当前元素是一个子表,则在存储区中分配一段连续的存储空间来存储子表。顺序存储的优点是可以利用数组等高效数据结构进行实现,查找和访问元素时速度较快。
下面以广义表((1,2),3,(4,(5,6),7))为例,讲解顺序存储法的具体实现过程。
首先定义一个预设最大长度的数组,用于存储广义表元素:
```
#define MAXSIZE 100
typedef struct {
int tag[MAXSIZE];
union {
int data[MAXSIZE];
int sub[MAXSIZE];
}u;
int length;
}*GList;
```
其中tag数组用来标记当前元素是单个数据元素还是子表,data和sub数组用来分别存储数据元素和子表,length表示存储区的长度。
接着是广义表的创建过程:
```
void CreateGList(GList& L, char* str) {
if(*str == '\0') {
L = NULL;
return;
}
L = (GList)malloc(sizeof(GLNode));
L->length = 0;
while(*str != '\0') {
if(*str == '(') {
GList subList = NULL;
CreateGList(subList, str);
L->tag[L->length] = 1;
L->u.sub[L->length++] = (int)subList;
} else if(*str == ' ' || *str == ',') {
++str;
} else if(*str == ')') {
++str;
return;
} else {
int num = 0;
while(*str >= '0' && *str <= '9') {
num = num * 10 + (*str - '0');
++str;
}
L->tag[L->length] = 0;
L->u.data[L->length++] = num;
}
}
}
```
与链表存储法相比,顺序存储法较为直观,由于其本质上是一个数组,因此访问某个元素时可以直接通过下标进行访问和修改。
综上所述,链表存储以及顺序存储对广义表的存储均有其独特的优点。在具体实现过程中,应当根据广义表的具体性质进行选择。本文通过两个角度分析了广义表的存储结构以及两种实现方法,希望能对读者有所启发。