廣義表

廣義表（Generalized List）是一種非線性的數據結構。但如果廣義表的每個元素都是原子，它就變成了線性表。廣義表廣泛地用於人工智能等領域的LISP語言。
廣義表一般記作 LS = (a1, a2, ···, an), n是它的長度，ai可以是單個元素(原子)，也可以是廣義表(子表)，當廣義表非空時，稱第一個元素a1為LS的表頭，稱其餘元素組成的表為LS的表尾。注意：表頭是元素(可以是原子，也可以是廣表)，表尾一定是廣義表。E=(a, E)是一個遞歸的表。D=(( ),(e),(a,(b,c,d)))是多層次的廣義表，長度為3，深度為3。例：((a),a)的表頭是(a)，表尾是(a)，((a))的表頭是(a)，表尾是( )。

**頭尾鏈表存儲表示**

**存儲結構**
// 廣義表的頭尾鏈表存儲表示
typedef enum {ATOM, LIST} ElemTag;
// ATOM==0：原子，LIST==1：子表
typedef struct GLNode {
ElemTag tag;
// 公共部分，用於區分原子結點和表結點
union {
// 原子結點和表結點的聯合部分
AtomType atom;
// atom是原子結點的值域，AtomType由用戶定義
struct {
struct GLNode *hp, *tp;
} ptr;
// ptr是表結點的指針域，prt.hp和ptr.tp分別指向表頭和表尾
} a;
} *GList, GLNode; // 廣義表類型

**基本操作**
// 廣義表的頭尾鏈表存儲的基本操作(11個)
#include"func5-1.c"
void InitGList(GList *L) {
// 創建空的廣義表L
*L = NULL;
}
void CreateGList(GList *L, SString S) {
// 採用頭尾鏈表存儲結構，由廣義表的書寫形式串S創建廣義表L。設emp="()"
SString sub, hsub, emp;
GList p, q;
StrAssign(emp, "()"); // 空串emp="()"
if (!StrCompare(S, emp)) // S="()"
*L = NULL; // 創建空表
else { // S不是空串
*L = (GList)malloc(sizeof(GLNode));
if (!*L) // 建表結點
exit(OVERFLOW);
if (StrLength(S) == 1) {
// S為單原子，只會出現在遞歸調用中
(*L)->tag = ATOM;
(*L)->a.atom = S1; // 創建單原子廣義表
} else { // S為表
(*L)->tag = LIST;
p = *L;
SubString(sub, S, 2, StrLength(S) - 2);
// 脫外層括號(去掉第1個字符和最後1個字符)給串sub
do {
// 重複建n個子表
sever(sub, hsub); // 從sub中分離出表頭串hsub
CreateGList(&p->a.ptr.hp, hsub);
q = p;
if (!StrEmpty(sub)) { // 表尾不空
p = (GLNode *)malloc(sizeof(GLNode));
if (!p)
exit(OVERFLOW);
p->tag = LIST;
q->a.ptr.tp = p;
}
} while (!StrEmpty(sub));
q->a.ptr.tp = NULL;
}
}
}
void DestroyGList(GList *L) {
// 銷燬廣義表L
GList q1, q2;
if (*L) {
if ((*L)->tag == LIST) { // 刪除表結點
q1 = (*L)->a.ptr.hp; // q1指向表頭
q2 = (*L)->a.ptr.tp; // q2指向表尾
DestroyGList(&q1); // 銷燬表頭
DestroyGList(&q2); // 銷燬表尾
}
free(*L);
*L = NULL;
}
}
void CopyGList(GList *T, GList L) {
// 採用頭尾鏈表存儲結構，由廣義表L複製得到廣義表T
if (!L) // 複製空表
*T = NULL;
else {
*T = (GList)malloc(sizeof(GLNode));
// 建表結點
if (!*T)
exit(OVERFLOW);
(*T)->tag = L->tag;
if (L->tag == ATOM)
(*T)->a.atom = L->a.atom; // 複製單原子
else {
CopyGList(&((*T)->a.ptr.hp), L->a.ptr.hp);
// 遞歸複製子表
CopyGList(&((*T)->a.ptr.tp), L->a.ptr.tp);
}
}
}
int GListLength(GList L) {
/* 返回廣義表的長度，即元素個數 */
int len = 0;
while (L) {
L = L->a.ptr.tp;
len++;
}
return len;
}
int GListDepth(GList L) {
/* 採用頭尾鏈表存儲結構，求廣義表L的深度。*/
int max, dep;
GList pp;
if (!L)
return 1; /* 空表深度為1 */
if (L->tag == ATOM)
return 0; /* 原子深度為0，只會出現在遞歸調用中 */
for (max = 0, pp = L; pp; pp = pp->a.ptr.tp) {
dep = GListDepth(pp->a.ptr.hp); /* 遞歸求以pp->a.ptr.hp為頭指針的子表深度 */
if (dep > max)
max = dep;
}
return max + 1; /* 非空表的深度是各元素的深度的最大值加1 */
}
Status GListEmpty(GList L) {
/* 判定廣義表是否為空 */
if (!L)
return TRUE;
else
return FALSE;
}
GList GetHead(GList L) {
/* 生成廣義表L的表頭元素，返回指向這個元素的指針 */
GList h, p;
if (!L) /* 空表無表頭 */
return NULL;
p = L->a.ptr.hp; /* p指向L的表頭元素 */
CopyGList(&h, p); /* 將表頭元素複製給h */
return h;
}
GList GetTail(GList L) {
/* 將廣義表L的表尾生成為廣義表，返回指向這個新廣義表的指針 */
GList t;
if (!L) /* 空表無表尾 */
return NULL;
CopyGList(&t, L->a.ptr.tp); /* 將L的表尾拷給t */
return t;
}
void InsertFirst_GL(GList *L, GList e) {
/* 初始條件：廣義表存在。操作結果：插入元素e(也可能是子表)作為廣義表L的第1元素(表頭) */
GList p = (GList)malloc(sizeof(GLNode)); /* 生成新結點 */
if (!p)
exit(OVERFLOW);
p->tag = LIST; /* 結點的類型是表 */
p->a.ptr.hp = e; /* 表頭指向e */
p->a.ptr.tp = *L; /* 表尾指向原表L */
*L = p; /* L指向新結點 */
}
void DeleteFirst_GL(GList *L, GList *e) {
// 初始條件：廣義表L存在。操作結果：刪除廣義表L的第一元素，並用e返回其值
GList p = *L; // p指向第1個結點
*e = (*L)->a.ptr.hp; // e指向L的表頭
*L = (*L)->a.ptr.tp; // L指向原L的表尾
free(p); // 釋放第1個結點
}
void Traverse_GL(GList L, void(*v)(AtomType)) {
// 利用遞歸算法遍歷廣義表L
if (L) // L不空
if (L->tag == ATOM) // L為單原子
v(L->a.atom);
else { // L為廣義表
Traverse_GL(L->a.ptr.hp, v);
// 遞歸遍歷L的表頭
Traverse_GL(L->a.ptr.tp, v);
// 遞歸遍歷L的表尾
}
}

**擴展線性鏈表存儲表示**

**存儲結構**
// 廣義表的擴展線性鏈表存儲表示
typedef enum {ATOM, LIST} ElemTag;
// ATOM==0：原子，LIST==1：子表
typedef struct GLNode1 {
ElemTag tag;
// 公共部分，用於區分原子結點和表結點
union {
// 原子結點和表結點的聯合部分
AtomType atom; // 原子結點的值域
struct GLNode1 *hp; // 表結點的表頭指針
} a;
struct GLNode1 *tp;
// 相當於線性鏈表的next，指向下一個元素結點
} *GList1, GLNode1;
// 廣義表類型GList1是一種擴展的線性鏈表

**基本操作**
// 廣義表的擴展線性鏈表存儲(的基本操作(13個)
#include"func5-1.c"
void InitGList(GList1 *L) {
// 創建空的廣義表L
*L = NULL;
}
void CreateGList(GList1 *L, SString S) {
// 採用擴展線性鏈表存儲結構，由廣義表的書寫形式串S創建廣義表L。設emp="()"
SString emp, sub, hsub;
GList1 p;
StrAssign(emp, "()"); /* 設emp="()" */
*L = (GList1)malloc(sizeof(GLNode1));
if (!*L) /* 建表結點不成功 */
exit(OVERFLOW);
if (!StrCompare(S, emp)) { /* 創建空表 */
(*L)->tag = LIST;
(*L)->a.hp = (*L)->tp = NULL;
} else if (StrLength(S) == 1) { /* 創建單原子廣義表 */
(*L)->tag = ATOM;
(*L)->a.atom = S1;
(*L)->tp = NULL;
} else { /* 創建一般表 */
(*L)->tag = LIST;
(*L)->tp = NULL;
SubString(sub, S, 2, StrLength(S) - 2);
// 脫外層括號(去掉第1個字符和最後1個字符)給串sub
sever(sub, hsub); // 從sub中分離出表頭串hsub
CreateGList(&(*L)->a.hp, hsub);
p = (*L)->a.hp;
while (!StrEmpty(sub)) { // 表尾不空，則重複建n個子表
sever(sub, hsub); // 從sub中分離出表頭串hsub
CreateGList(&p->tp, hsub);
p = p->tp;
};
}
}
void DestroyGList(GList1 *L) {
/* 初始條件：廣義表L存在。操作結果：銷燬廣義表L */
GList1 ph, pt;
if (*L) { /* L不為空表 */
/* 由ph和pt接替L的兩個指針 */
if ((*L)->tag) /* 是子表 */
ph = (*L)->a.hp;
else /* 是原子 */
ph = NULL;
pt = (*L)->tp;
DestroyGList(&ph); /* 遞歸銷燬表ph */
DestroyGList(&pt); /* 遞歸銷燬表pt */
free(*L); /* 釋放L所指結點 */
*L = NULL; /* 令L為空 */
}
}
void CopyGList(GList1 *T, GList1 L) {
/* 初始條件：廣義表L存在。操作結果：由廣義表L複製得到廣義表T */
*T = NULL;
if (L) { /* L不空 */
*T = (GList1)malloc(sizeof(GLNode1));
if (!*T)
exit(OVERFLOW);
(*T)->tag = L->tag; /* 複製枚舉變量 */
if (L->tag == ATOM) /* 複製共用體部分 */
(*T)->a.atom = L->a.atom; /* 複製單原子 */
else
CopyGList(&(*T)->a.hp, L->a.hp); /* 複製子表 */
if (L->tp == NULL) /* 到表尾 */
(*T)->tp = L->tp;
else
CopyGList(&(*T)->tp, L->tp); /* 複製子表 */
}
}
int GListLength(GList1 L) {
/* 初始條件：廣義表L存在。操作結果：求廣義表L的長度，即元素個數 */
int len = 0;
GList1 p = L->a.hp; /* p指向第1個元素 */
while (p) {
len++;
p = p->tp;
};
return len;
}
int GListDepth(GList1 L) {
/* 初始條件：廣義表L存在。操作結果：求廣義表L的深度 */
int max, dep;
GList1 pp;
if (L == NULL 
L->tag == LIST && !L->a.hp)
return 1; /* 空表深度為1 */
else if (L->tag == ATOM)
return 0; /* 單原子表深度為0，只會出現在遞歸調用中 */
else /* 求一般表的深度 */
for (max = 0, pp = L->a.hp; pp; pp = pp->tp) {
dep = GListDepth(pp); /* 求以pp為頭指針的子表深度 */
if (dep > max)
max = dep;
}
return max + 1; /* 非空表的深度是各元素的深度的最大值加1 */
}
Status GListEmpty(GList1 L) {
/* 初始條件：廣義表L存在。操作結果：判定廣義表L是否為空 */
if (!L 
L->tag == LIST && !L->a.hp)
return OK;
else
return ERROR;
}
GList1 GetHead(GList1 L) {
/* 生成廣義表L的表頭元素，返回指向這個元素的指針 */
GList1 h, p;
if (!L 
L->tag == LIST && !L->a.hp) /* 空表無表頭 */
return NULL;
p = L->a.hp->tp; /* p指向L的表尾 */
L->a.hp->tp = NULL; /* 截去L的表尾部分 */
CopyGList(&h, L->a.hp); /* 將表頭元素複製給h */
L->a.hp->tp = p; /* 恢復L的表尾(保持原L不變) */
return h;
}
GList1 GetTail(GList1 L) {
// 將廣義表L的表尾生成為廣義表，返回指向這個新廣義表的指針
GList1 t, p;
if (!L 
L->tag == LIST && !L->a.hp) // 空表無表尾
return NULL;
p = L->a.hp; // p指向表頭
L->a.hp = p->tp; // 在L中刪去表頭
CopyGList(&t, L); // 將L的表尾拷給t
L->a.hp = p; // 恢復L的表頭(保持原L不變)
return t;
}
void InsertFirst_GL(GList1 *L, GList1 e) {
// 初始條件：廣義表存在。操作結果：插入元素e(也可能是子表)作為廣義表L的第1元素(表頭)
GList1 p = (*L)->a.hp;
(*L)->a.hp = e;
e->tp = p;
}
void DeleteFirst_GL(GList1 *L, GList1 *e) {
// 初始條件：廣義表L存在。操作結果：刪除廣義表L的第一元素，並用e返回其值
if (*L && (*L)->a.hp) {
*e = (*L)->a.hp;
(*L)->a.hp = (*e)->tp;
(*e)->tp = NULL;
} else
*e = *L;
}
void Traverse_GL(GList1 L, void(*v)(AtomType)) {
// 利用遞歸算法遍歷廣義表L
GList1 hp;
if (L) { // L不空
if (L->tag == ATOM) { // L為單原子
v(L->a.atom);
hp = NULL;
} else // L為子表
hp = L->a.hp;
Traverse_GL(hp, v);
Traverse_GL(L->tp, v);
}
}

**參考資料 ==