廣義表,又稱為列表。記作:
廣義表可以看作是線性表的推廣。兩者區別是:線性表中的數據元素只能表示單個數據元素;廣義表中的單個數據元素 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; }