介紹
廣義表是線性表的補充。廣義表是遞歸定義的,廣義表的元素既可以是單個元素,也可以是一個廣義表。
廣義表的第一個元素是表頭,其余部分是表尾
例如:
D=() :空表,長度為0
A=(a, (b, c) :長度為2的廣義表,第一個元素為單個元素,第二個元素為子表(b, c)
B=(A,A,D): 長度為3的廣義表,千聊個元素為表A,第三個元素為表D
C=(a,C): 長度為2的遞歸定義的廣義表,相當於無窮表(a,(a,(a,(...))))
廣義表被廣泛用於lisp中,因此可能會有一些非常恐怖的代碼,如:
((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ((lambda () (quote ( ))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) ))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) )))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
(cpp的模板元編程也可以得到上述效果)
結構定義
廣義表中有兩種結點:
1.單元素結點:即原子結點
2.子表結點:即表結點
使用代碼描述如下(頭尾鏈表):
struct Node { NodeType tag; //區別原子結點與表結點 union atom_htp //原子結點的值域與atom與表結點的指針與htp的聯合體域 { struct htp //表結點 { Node *hp; Node *tp; }; int atom; //原子結點 }; };
廣義表的同層結點鏈存儲結構
在廣義表的同層結點存儲結構中,無論原子結點還是表結點都有三個域組成,如圖:
之前提過的A, B, C, D的存儲結構如圖
以下是廣義表同層結點的結構類型定義:
struct Node { NodeType tag; //區別原子結點與表結點 union atom_htp { AtomType atom; Node* hp; //表頭指針域 }; Node* tp; //下一結點的指針域 };
廣義表的操作
廣義表的創建
我其實非常震驚,課本居然沒有講到這一部分,那我也只好百度+自己想了
但是這東西可真難搞啊。
創建也是用遞歸創建的,比較抽象,目前只做出來了字符串形式
也就是說我的這個創建方法無法處理上面列出來的B表和C表。
Node *createGeneralizedList(char *s) { int length = strlen(s); if (*s == '\0') { return nullptr; } int i = 0; Node *newNode; if (*s == '(') { //先去除括號 s++; s[strlen(s) - 1] = '\0'; //分子表 int k = 0; //與左邊括號匹配情況 char *temp = s; while (temp[i] != '\0') //將輸入的按","分割(僅分割表頭和表尾) { if (temp[i] == '(') { k++; } if (temp[i] == ')') { k--; } if (temp[i] == ',' && k == 0) { temp[i] = '\0'; break; } i++; } newNode = new Node; newNode->tag = LIST; newNode->atom_htp.hp = createGeneralizedList(s); if (i != length - 2) //判斷傳入的是不是(a)這種,如果不是則繼續創建tp結點 { newNode->atom_htp.hp->tp = new Node; newNode->atom_htp.hp->tp->tag = LIST; newNode->atom_htp.hp->tp->atom_htp.hp = createGeneralizedList(&s[i + 1]); } } else { newNode = new Node; newNode->tag = ATOM; newNode->atom_htp.atom = *s; if (strlen(s) == 1) //判斷傳入的是不是單個原子元素,如a, 若不是,如傳入a,b,則b又是一個表 { newNode->tp = nullptr; } else { newNode->tp = new Node; newNode->tp->tag = LIST; newNode->tp->atom_htp.hp = createGeneralizedList(&s[2]); } } return newNode; }
求廣義表長度
int length(Node* L) { int k = 0; Node* s; s = L; while (s != NULL) { k++; s = s->atom_htp.hp->tp; } return k; }
廣義表表頭
Node* getHead(Node* L) { if (L == NULL) { return NULL; } if (L->tag == ATOM) { exit(0); } else return L->atom_htp.hp; }
廣義表表尾
Node* getTail(Node* L) { if (L == NULL) { return NULL; } if (L->tag == ATOM) { exit(0); } else return L->atom_htp.hp->tp; }
廣義表深度
int depth(Node *L) { //廣義表深度 int d = 0, max = 0; if (L->tag == ATOM) { return 0; //原子結點深度為0 } if (L == NULL) { return 1; //空表深度為1 } Node *s = L->atom_htp.hp; while (s != NULL) { d = depth(s); if (d > max) { max = d; } s = s->tp; } return max + 1; }
廣義表原子結點數
int countATOM(Node* L) { int n1, n2; if (L == NULL) //空表無結點 { return 0; } if (L->tag == ATOM) { return 1; } n1 = countATOM(L->atom_htp.hp); n2 = countATOM(L->atom_htp.hp->tp); return n1 + n2; }
完整測試代碼
#include <iostream> #include <cstring> enum NodeType //結點類型:0為原子結點, 1為表結點 { ATOM, LIST }; struct Node { NodeType tag; //區別原子結點與表結點 union { char atom; Node *hp = nullptr; //表頭指針域 } atom_htp; Node *tp = nullptr; //下一結點的指針域 }; Node *createGeneralizedList(char *s) { int length = strlen(s); if (*s == '\0') { return nullptr; } int i = 0; Node *newNode; if (*s == '(') { //先去除括號 s++; s[strlen(s) - 1] = '\0'; //分子表 int k = 0; //與左邊括號匹配情況 char *temp = s; while (temp[i] != '\0') //將輸入的按","分割(僅分割表頭和表尾) { if (temp[i] == '(') { k++; } if (temp[i] == ')') { k--; } if (temp[i] == ',' && k == 0) { temp[i] = '\0'; break; } i++; } newNode = new Node; newNode->tag = LIST; newNode->atom_htp.hp = createGeneralizedList(s); if (i != length - 2) { newNode->atom_htp.hp->tp = new Node; newNode->atom_htp.hp->tp->tag = LIST; newNode->atom_htp.hp->tp->atom_htp.hp = createGeneralizedList(&s[i + 1]); } } else { newNode = new Node; newNode->tag = ATOM; newNode->atom_htp.atom = *s; if (strlen(s) == 1) { newNode->tp = nullptr; } else { newNode->tp = new Node; newNode->tp->tag = LIST; newNode->tp->atom_htp.hp = createGeneralizedList(&s[2]); } } return newNode; } int depth(Node *L) { int d = 0, max = 0; Node *s; if (L->tag == ATOM) { return 0; } s = L; while (s != NULL) { d = depth(s->atom_htp.hp); if (d > max) { max = d; } s = s->atom_htp.hp->tp; } return max + 1; } int length(Node* L) { int k = 0; Node* s; s = L; while (s != NULL) { k++; s = s->atom_htp.hp->tp; } return k; } int countATOM(Node* L) { int n1, n2; if (L == NULL) //空表無結點 { return 0; } if (L->tag == ATOM) { return 1; } n1 = countATOM(L->atom_htp.hp); n2 = countATOM(L->atom_htp.hp->tp); return n1 + n2; } int main() { char s[100]; std::cin >> s; Node *aCL = createGeneralizedList(s); std::cout << depth(aCL) << std::endl; std::cout << length(aCL) << std::endl; std::cout << countATOM(aCL) << std::endl; }
該代碼稍作修改可以通過NOJ數據結構理論第14題。