介绍
广义表是线性表的补充。广义表是递归定义的,广义表的元素既可以是单个元素,也可以是一个广义表。
广义表的第一个元素是表头,其余部分是表尾
例如:
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题。