广义嘛,有点类似类比的意思,那么广义表就是线性表的推广,也称列表。
逻辑结构为
GL = (a1,a2,…ai,…an)
广义表具有以下的特性:
- 广义表中的数据元素是相对有次序的;
- 广义表的长度要取层次的最外层;
- 广义表的深度为包含括号的层数,比如原子是孤儿所以他就没有深度,空表连原子都没有偏偏就占一个深度;
- 广义i傲视可以被共享的,可以被共享的广义表被称为再入表(目前没发现有啥卵用);
- 广义表可以是递归的表,我觉得这取决于它的存储结构,这种递归在前面的链表哪里就讲得很透彻了;
一般的广义表都长下面这样
- 啥都没有只有括号的是空表
- 小写字母表示没有儿子的原子
- 大写字母表示一个有若干儿子的表(表名)
- 一个括号表示一个表,就像套娃娃一样可以查里面添加括号(子表)
若是把表名写在表(括号)的前面,没名字用”·“表示,那么上面的哪些广义表又变成了虾米那这样子:
大概也就这意思:
广义表的存储结构
这里又扯到前面所讲的递归了,只不过是用共用体改进了一下;
就我看来有点和双链表相似
tag给他存上一个int型的数据,如果:
- tag=0,表示这个结点存的是原子(DATA),后面的link是一个指针域,要是还有其他的同级原子或者表,那么就用link指向他们,没有就置空(NULL);
- tag=1,表示这个结点是一个表结点(sublist),存放一个地址指向它的儿子们。后面的link同样是一个指针域,要是还有其他的同级原子或者表,那么就用link指向他们,没有就置空(NULL);
代码示意
typedef struct lnode {
int tag ; //存放标识符0/1
union {
ElemType data ; //任意数据类型(原子)
struct londe *sublist ; //指向子表的指针域
}val;
struct lnode *link; //指向下一个元素
}GLnode; //广义表的结点类型
广义表通用算法设计模式
void funl (GLnode *g) {
GLnode *g1 = g ->val.sublist; //g1指向第一个头结点
while (g1!=NULL) {
if (g1 ->tag ==1) //当为子表时递归处理里面的原子
funl(g1)
else
Operation(); //否则调用处理原子的方法
g1 = g1->link; //刷新次要用的g1值
}
}
求广义表的长度
长度并不是原子个数,而是同级结点的个数
int GLLength (GLonde *g) {
int n = 0; //长度初始化
GLnode *g1 = g ->val.sublist; //指向首元结点
while (*g1!=NUll) { //只要节点不为空
++n; //长度加1
g1 = g1->link; //刷新g1值
}
return n;
}
求广义表的深度
深度dep = 所有元素最大深度+1
算法模型:
f(g) = 0 若g是原子
f(g) = 1 若g是空表
(g)= MAX{f(subg)}+1 subg是g的子表
int GLDepth (GLNode *g) {
GLNode *g1;
int maxd = 0,dep;
if (g ->tag ==0) //传进来的是一个原子
return 0;
g1 = g ->val.sublist; //g1指向第一个元素
if (g1==NULL)
return 1;
while (g1 !==NULL) {
if (g1 ->tag==1) { //元素为表
dep = GLDepth(g1) //递归
if (dep>maxd)
maxd = dep;
}
g1 = g1 ->link; //刷新g1值
}
return (maxd+1); //返回深度
}
广义表的输出
void DispGL (GLNode *g) {
if(g!=NULL) {
if (g ->tag ==0)
cout<< g->val.data;
}else{
cout<<"(";
if(g ->val.sublist ==NULL)
cout<<"#";
else
DispGL(g->val.sublist)
cout<<")";
}
if(g ->link !=NULL) {
cout<<",";
DispGL(g ->link);
}
}
}
来源:CSDN
作者:Erase Me
链接:https://blog.csdn.net/qq_44957186/article/details/104554123