概论
广义表是一种重要的数据结构,可以看作内置数据类型数组的扩展,即推广数组的定义,可以将另一个数组作为这个数组的元素,再进一步推广,内涵数组中的元素还可以是一个数组,即广义表中的元素可以是一个广义表
如下
数组:[a,b,c,d,e,f,g]
广义表:[a,b,c,[e,[f,g]]]
在python等语言中已经将广义表作为合法数据类型
存储结构
广义表中的元素有两类,一类是广义表,一类是原子,并且一个位置出现的类型是唯一的,所以使用union数据类型来存储元素
同时使用链表类型来构建广义表能节省很大的工作量
typedef struct Glnode //头尾链表存储结构
{
ElemTage type; //用于区存储数据是元素还是子表
union //由于有两种数据类型使用共用体来存储相应元素(注意union中的数据只能出现一种)
{
char n; //元素
struct Glnode* begin;
};
struct Glnode* next;
}*glode;
头尾结点存储(这种办法使得后续构建广义表更加复杂)
typedef struct GLNode
{
ElemTage type;
union
{
int n;
struct GLNode* hp,*tp;
};
}*GList;
初始化广义表
初始化广义表实际就是创建第一个结点,并初始化其中的指针(注意指针在使用和结束以后都要初始化,将指针指向一个安全的区域,否则很可能在后续程序的运行过程中出现内存错误,野指针给cpp的内存操作等提供了很大的便捷性,但是同时也给cpp的内存安全造成很大麻烦)
glode CreatList(glode head,strin S)
{
glode dim;
dim = head;
S->count0 += 1;
while (S->count0 != S->count-1)
{
if (S->string[S->count0] <= 'z' && S->string[S->count0] >= 'a') //在表中所有元素都是原子时实际上可以直接看作是一个链表的构建
{
dim->type = ATOM;
dim->n = S->string[S->count0];
if (S->string[S->count0+1] == ')') //这个条件实际是用来判定递归什么时候终止
{
dim->next = NULL; //同时将最后一个指针指向NULL(实际上这个NULL最好在初始化函数中定义)初始化指针很重要否则cpp中的野指针可能造成很大的麻烦
return head;
}
dim->next = new Glnode;
dim = dim->next;
S->count0 += 1;
continue;
}
if (S->string[S->count0] == '(') //在遇到子表时就需要考虑侧枝的构建
{
dim->type = LIST;
dim->begin = new Glnode;
dim->begin = CreatList(dim->begin, S); //这里通过递归的方法来构建侧链
if (S->string[S->count0 + 1] == ')')
{
dim->next = NULL;
return head;
}
else
{
dim->next = new Glnode;
dim = dim->next;
}
//其实把构建侧枝的语句删去,剩下的其实就是链表构建语句
S->count0 += 1;
continue;
}
S->count0 += 1;
}
return head;
}
销毁广义表
在数据结构使用结束后应当及时释放内存,初始化指针,否则内存被大量无用数据占用可能会出现内存溢出等问题
void Distorylist(glode head) //同样用递归的方法销毁广义表
{
glode dim;
dim = head;
while (dim->next != NULL)
{
if (dim->type == ATOM)
{
head = head->next;
free(dim);
dim = head;
}
else if (dim->type == LIST)
{
head = head->next;
Distorylist(dim->begin); //递归删除支链
free(dim);
dim = head;
}
}
if (dim->next == NULL)
{
free(dim);
}
cout << "广义表成功销毁";
}
广义表深度
即内部最多嵌套的括号的数目
void Deep(glode head)
{
int count = 1;
int middle = 0;
glode dim;
dim = head;
while (dim->next != NULL)
{
if (dim->type == LIST)
{
middle += 1;
Deep(dim->begin);
}
if (middle > count)
{
count = middle;
middle = 1;
}
dim = dim->next;
}
if (dim->next == NULL)
{
if (dim->type == LIST)
{
middle += 1;
Deep(dim->begin);
}
if (middle > count)
{
count = middle;
}
}
cout << "最深层数" << count << endl;
}
打印广义表
同样使用递归的方法遍历广义表以输出数据
void Print(glode head)
{
glode dim = head;
cout << '(';
while (dim->next != NULL)
{
if (dim->type == ATOM)
{
cout << dim->n << ',';
dim = dim->next;
}
else if (dim->type == LIST)
{
Print(dim->begin);
dim = dim->next;
cout << ')';
}
}
if (dim->next == NULL)
{
if (dim->type == ATOM)
{
cout << dim->n;
cout << ')';
}
if (dim->type == LIST)
{
Print(dim->begin);
cout << ')';
}
}
}
完整代码
经过测试能够正常运行
#include<iostream>
#include<stdio.h>
using namespace std;
const int maxsize = 20;
typedef enum{ATOM,LIST}ElemTage;
//以下为辅助函数
typedef struct sqstring //使用数据结构串来为广义表导入数据
{
char string[maxsize];
int count; //(目前需要的)总数
int count0 = 0; //起始元素位置
}str, * strin;
strin Initstring() //创建并初始化串
{
strin str1;
str1 = (strin)malloc(sizeof(str));
if (!str1)
{
cout << "串空间分配失败" << endl;
abort();
}
str1->count = 0;
str1->count0 = 0;
return str1;
}
strin Insertstring() //一个专门为广义表构建的串输入函数
{
strin a;
a = Initstring();
cout << "请输入广义表序列" << endl;
char ap;
cin >> ap;
while (ap != '#')
{
a->string[a->count] = ap;
a->count += 1;
cin >> ap;
}
return a;
}
void Print(strin S)
{
int countt = S->count;
for (int i = 0; i < S->count; i++)
{
cout << S->string[i] << " ";
}
cout << endl;
}
//广义表的数据类型包括子表和元素,所以使用链表来存储相应结构
//对广义表可以这么理解,如果将所有元素一视同仁则可以看作是一个链表,再分开来看子表实际上相当于在主链上加上侧链
typedef struct Glnode //头尾链表存储结构
{
ElemTage type; //用于区存储数据是元素还是子表
union //由于有两种数据类型使用共用体来存储相应元素
{
char n; //元素
struct Glnode* begin;
};
struct Glnode* next;
}*glode;
glode InitList() //初始化广义表
{
glode head;
head = (glode)malloc(sizeof(Glnode));
if (!head) //如果初始化失败直接终止程序,弹出错误
{
cout << "初始化分配空间失败" << endl;
abort();
}
head->next = NULL;
return head;
}
void Distorylist(glode head) //同样用递归的方法销毁广义表
{
glode dim;
dim = head;
while (dim->next != NULL)
{
if (dim->type == ATOM)
{
head = head->next;
free(dim);
dim = head;
}
else if (dim->type == LIST)
{
head = head->next;
Distorylist(dim->begin); //递归删除支链
free(dim);
dim = head;
}
}
if (dim->next == NULL)
{
free(dim);
}
cout << "广义表成功销毁";
}
glode CreatList(glode head,strin S)
{
glode dim;
dim = head;
S->count0 += 1;
while (S->count0 != S->count-1)
{
if (S->string[S->count0] <= 'z' && S->string[S->count0] >= 'a') //在表中所有元素都是原子时实际上可以直接看作是一个链表的构建
{
dim->type = ATOM;
dim->n = S->string[S->count0];
if (S->string[S->count0+1] == ')') //这个条件实际是用来判定递归什么时候终止
{
dim->next = NULL; //同时将最后一个指针指向NULL(实际上这个NULL最好在初始化函数中定义)初始化指针很重要否则cpp中的野指针可能造成很大的麻烦
return head;
}
dim->next = new Glnode;
dim = dim->next;
S->count0 += 1;
continue;
}
if (S->string[S->count0] == '(') //在遇到子表时就需要考虑侧枝的构建
{
dim->type = LIST;
dim->begin = new Glnode;
dim->begin = CreatList(dim->begin, S); //这里通过递归的方法来构建侧链
if (S->string[S->count0 + 1] == ')')
{
dim->next = NULL;
return head;
}
else
{
dim->next = new Glnode;
dim = dim->next;
}
//其实把构建侧枝的语句删去,剩下的其实就是链表构建语句
S->count0 += 1;
continue;
}
S->count0 += 1;
}
return head;
}
void Print(glode head)
{
glode dim = head;
cout << '(';
while (dim->next != NULL)
{
if (dim->type == ATOM)
{
cout << dim->n << ',';
dim = dim->next;
}
else if (dim->type == LIST)
{
Print(dim->begin);
dim = dim->next;
cout << ')';
}
}
if (dim->next == NULL)
{
if (dim->type == ATOM)
{
cout << dim->n;
cout << ')';
}
if (dim->type == LIST)
{
Print(dim->begin);
cout << ')';
}
}
}
void Deep(glode head) //还未经过测试
{
int count = 1;
int middle = 0;
glode dim;
dim = head;
while (dim->next != NULL)
{
if (dim->type == LIST)
{
middle += 1;
Deep(dim->begin);
}
if (middle > count)
{
count = middle;
middle = 1;
}
dim = dim->next;
}
if (dim->next == NULL)
{
if (dim->type == LIST)
{
middle += 1;
Deep(dim->begin);
}
if (middle > count)
{
count = middle;
}
}
cout << "最深层数" << count << endl;
}
int main()
{
glode head;
head = InitList();
strin S;
S = Insertstring();
Print(S);
head = CreatList(head, S);
Print(head);
}