广义表,又称为列表。记作:
广义表可以看作是线性表的推广。两者区别是:线性表中的数据元素只能表示单个数据元素;广义表中的单个数据元素 ai ,既可以是单个元素,也可以是广义表。
原子和子表
在广义表中,单个元素被称为 “原子”;包含的广义表被称为 “子表”。
例如:
- A = () :A 表示一个广义表,只不过表是空的,广义表 A 的长度为 0。
- B = (e) :广义表 B 中只有一个原子 e ,长度为 1。
- C = (a,(b,c,d)) :广义表 C 中有两个元素,原子 a 和子表 (b,c,d) ,广义表C的长度为 2。
- D = (A,B,C) :广义表 D 中有三个元素:子表 A、B、C,长度为 3 ,这种表示方式等同于: D = ((),(e),(b,c,d)) 。
- E = (a,E) :广义表 E 中有两个元素,原子 a 和它本身,长度为 2 。这是一个递归的表,等同于:E = (a,(a,(a,…)))。
表头和表尾
当广义表不为空时,称表中的第一个元素为表的 “表头” ;剩余所有元素组成的表为 “表尾” 。
例如:上边例子中的 D = (A,B,C) ,子表 A 为广义表 D 的表头;而 (B,C) 组成的表为 D 的表尾。
非空广义表是由表头和表尾构成,反过来说也对:给定一个表头和表尾,可以唯一确定一个广义表。
广义表中结点结构
由于广义表中的数据元素类型分为原子和子表,难以使用顺序存储结构表示,所以通常采用链式存储结构。
根据原子和子表的不同,链式存储中的结点需要用两种不同的结构表示。对于原子来说,需要由两部分组成:标志位 + 值域(如图1(A));子表需要由三部分组成:标志位 + 指向表头的指针域 + 指向表尾的指针域(如图1(B))。

图1 广义表的链表结点结构
代码表示:
typedef struct GLNode{
int tag; //标志域
union {
char atom; //原子结点的值域
struct {
struct GLNode *hp, *tp;
}ptr; //子表结点的指针域,hp指向表头;tp指向表尾
};
}*Glist;
例如,使用图1的链表结构表示广义表 C = (a,(b,c,d)),效果图为:

图2 广义表C的结构示意图
实现代码为:
Glist creatGlist(Glist C){
// 广义表C
C = (Glist)malloc(sizeof(Glist));
C->tag = 1;
// 表头原子‘a’
C->ptr.hp = (Glist)malloc(sizeof(Glist));
C->ptr.hp->tag = 0;
C->ptr.hp->atom = 'a';
// 表尾子表(b,c,d),是一个整体
C->ptr.tp = (Glist)malloc(sizeof(Glist));
C->ptr.tp->tag = 1;
C->ptr.tp->ptr.hp = (Glist)malloc(sizeof(Glist));
C->ptr.tp->ptr.tp = NULL;
// 开始存放下一个数据元素(b,c,d), 表头为‘b’,表尾为(c,d)
C->ptr.tp->ptr.hp->tag = 1;
C->ptr.tp->ptr.hp->ptr.hp = (Glist)malloc(sizeof(Glist));
C->ptr.tp->ptr.hp->ptr.hp->tag = 0;
C->ptr.tp->ptr.hp->ptr.hp->atom = 'b';
C->ptr.tp->ptr.hp->ptr.tp = (Glist)malloc(sizeof(Glist));
// 存放子表(c,d),表头为c,表尾为d
C->ptr.tp->ptr.hp->ptr.tp->tag = 1;
C->ptr.tp->ptr.hp->ptr.tp->ptr.hp = (Glist)malloc(sizeof(Glist));
C->ptr.tp->ptr.hp->ptr.tp->ptr.hp->tag = 0;
C->ptr.tp->ptr.hp->ptr.tp->ptr.hp->atom = 'c';
C->ptr.tp->ptr.hp->ptr.tp->ptr.tp = (Glist)malloc(sizeof(Glist));
// 存放表尾d
C->ptr.tp->ptr.hp->ptr.tp->ptr.tp->tag = 1;
C->ptr.tp->ptr.hp->ptr.tp->ptr.tp->ptr.hp = (Glist)malloc(sizeof(Glist));
C->ptr.tp->ptr.hp->ptr.tp->ptr.tp->ptr.hp->tag = 0;
C->ptr.tp->ptr.hp->ptr.tp->ptr.tp->ptr.hp->atom = 'd';
C->ptr.tp->ptr.hp->ptr.tp->ptr.tp->ptr.tp = NULL;
return C;
}
结点结构的另一种表示方式
除了上边的那种表示结点的方式,还可以采用另外一种表示形式,不同在于:表结点和原子结点都添加了一个指向下一个数据元素的指针;而子表结点中只保留了指向表头结点的指针,删除了指向表尾的指针。

图3 广义表的另一种结点结构
代码表示为:
typedef struct GLNode{
int tag; //标志域
union {
int atom; //原子结点的值域
struct GLNode *hp; //子表结点的指针域,hp指向表头
};
struct GLNode *tp; //这里的tp相当于链表的next指针,用于指向下一个数据元素
}*Glist;
例如,用这种结构结构表示C = (a,(b,c,d)),效果图为:

图4 广义表C的结构示意图
实现代码:
Glist creatGlist(Glist C){
C = (Glist)malloc(sizeof(Glist));
C->tag = 1;
C->hp = (Glist)malloc(sizeof(Glist));
C->tp = NULL;
// 表头原子a
C->hp->tag = 0;
C->atom = 'a';
C->hp->tp = (Glist)malloc(sizeof(Glist));
C->hp->tp->tag = 1;
C->hp->tp->hp = (Glist)malloc(sizeof(Glist));
C->hp->tp->tp = NULL;
// 原子b
C->hp->tp->hp->tag = 0;
C->hp->tp->hp->atom = 'b';
C->hp->tp->hp->tp = (Glist)malloc(sizeof(Glist));
// 原子c
C->hp->tp->hp->tp->tag = 0;
C->hp->tp->hp->tp->atom = 'c';
C->hp->tp->hp->tp->tp = (Glist)malloc(sizeof(Glist));
// 原子d
C->hp->tp->hp->tp->tp->tag = 0;
C->hp->tp->hp->tp->tp->atom = 'd';
C->hp->tp->hp->tp->tp->tp = NULL;
return C;
}
总结
在编写代码时,一定要注意不要破坏广义表中数据元素之间的关系,例如:C1 = (a,b,c,d)和 C2 = (a,(b,c),d),两个广义表中数据元素是一样的,但是数据元素之间的关系不同,在 C1 中,各原子之间是并列的,而 C2 中,原子 a 和子表 (b,c) 和 d 是并列的。
补:M元多项式的表示
例如:
这是一个3元多项式(有3个变量:x,y,z),使用广义表表示M元多项式,首先需要对多项式做一下变形:
经过变形后,P(x,y,z)可以这样表示:
经过两轮转化后,P这个 3 元多项式分解成了由 A 多项式和 B 多项式组成的一元多项式(只有一个变元 z ),而 A 也变成了由 C 多项式和 D 多项式组成的一元多项式,…。
当全部转化成能用一元多项式表示时,每一个一元多项式只需要存储各项的指数和系数就可以了。
广义表中每个结点的构成如图5所示:

图5 多项式结点构成
代码表示:
typedef struct MPNode{
int tag; //区分原子结点和子表结点(0代表原子;1代表子表)
int exp; //存放指数域
union {
int coef; //存放多项式的系数
struct MPNode *hp; //当多项式系数为子表时,用它
};
struct MPNode *tp; //相当于线性链表的next,指向下一个数据元素
}*MPList;
实现代码:
MPList initP(MPList P){
char a[] = "xyz";
MPList F = (MPList)malloc(sizeof(MPList));
F->tag = 1;
F->exp = 0; // 表示F这个一员多项式中的变元位a[0],也就是x
F->hp = NULL;
F->tp = (MPList)malloc(sizeof(MPList));
F->tp->tag = 0;
F->tp->exp = 0; // x的指数为0
F->tp->coef = 2; // 系数为2
F->tp->tp = NULL; // tp截止,说明F=2;
MPList E = (MPList)malloc(sizeof(MPList));
E->tag = 1;
E->exp = 0; // E中变元位a[0],即x
E->hp = NULL;
E->tp = (MPList)malloc(sizeof(MPList));
E->tp->tag = 0;
E->tp->exp = 4;
E->tp->coef = 1;
E->tp->tp = (MPList)malloc(sizeof(MPList));
E->tp->tp->tag = 0;
E->tp->tp->exp = 3;
E->tp->tp->coef = 6;
E->tp->tp->tp = NULL;// 截止,E=1*x4+6*x3(x后为它的指数)
MPList D = (MPList)malloc(sizeof(MPList));
D->tag = 1;
D->exp = 0;// D中变元为a[0],即x
D->hp = NULL;
D->tp = (MPList)malloc(sizeof(MPList));
D->tp->tag = 0;
D->tp->exp = 5;
D->tp->coef = 3;
D->tp->tp = NULL; // 截止,D=3*x5(5是x的指数);
MPList C = (MPList)malloc(sizeof(MPList));
C->tag = 1;
C->exp = 0; // C中变元为a[0]=x;
C->hp = NULL;
C->tp = (MPList)malloc(sizeof(MPList));
C->tp->tag = 0;
C->tp->exp = 10;
C->tp->coef = 1;
C->tp->tp = (MPList)malloc(sizeof(MPList));
C->tp->tp->tag = 0;
C->tp->tp->exp = 6;
C->tp->tp->coef = 2;
C->tp->tp->tp = NULL; // C=1*x10+2*x6
MPList B = (MPList)malloc(sizeof(MPList));
B->tag = 1;
B->exp = 1; // B中变元为a[1]=y
B->hp = NULL;
B->tp = (MPList)malloc(sizeof(MPList));
B->tp->tag = 1;
B->tp->exp = 4;
B->tp->hp = E;
B->tp->tp = (MPList)malloc(sizeof(MPList));
B->tp->tp->tag = 1;
B->tp->tp->exp = 1;
B->tp->tp->hp = F;
B->tp->tp->tp = NULL; // B=E*y4+F*x1;
MPList A = (MPList)malloc(sizeof(MPList));
A->tag = 1;
A->exp = 1; // A中变元为a[1]=y;
A->hp = NULL;
A->tp = (MPList)malloc(sizeof(MPList));
A->tp->tag = 1;
A->tp->exp = 3;
A->tp->hp = C;
A->tp->tp = (MPList)malloc(sizeof(MPList));
A->tp->tp->tag = 1;
A->tp->tp->exp = 2;
A->tp->tp->hp = D;
A->tp->tp->tp = NULL; // A=C*y3+D*y2;
P = (MPList)malloc(sizeof(MPList));
P->tag = 1;
P->exp = 3; // 表示表元的数量
P->hp = (MPList)malloc(sizeof(MPList));
P->tp = NULL;
P->hp->tag = 1;
P->hp->exp = 2; // P中变元为a[2]=z;
P->hp->hp = NULL;
P->hp->tp = (MPList)malloc(sizeof(MPList));
P->hp->tp->tag = 1;
P->hp->tp->exp = 2;
P->hp->tp->hp = A;
P->hp->tp->tp = (MPList)malloc(sizeof(MPList));
P->hp->tp->tp->tag = 1;
P->hp->tp->tp->exp = 1;
P->hp->tp->tp->hp = B;
P->hp->tp->tp->tp = (MPList)malloc(sizeof(MPList));
P->hp->tp->tp->tp->tag = 0;
P->hp->tp->tp->tp->exp = 0;
P->hp->tp->tp->tp->coef = 15;
P->hp->tp->tp->tp->tp = NULL; // P=A*z2+B*z1+15
return P;
}
来源:https://www.cnblogs.com/ciyeer/p/9040516.html