广义表(Generalized List)
1. 广义表的概念
1.1 广义表的定义
- 广义表(Generalized List,又称列表,或表)是一种非线性的数据结构,是线性表的一种推广。
- 广义表中放松对表元素的原子限制,容许它们具有其自身结构。即广义表的定义是递归的,因为在表的描述中又用到了表,允许表中有表,这种递归的定义能够很简洁地描述庞大而复杂的结构。
- 一个广义表LS定义为n(n≥0)个元素 a0,a1,a2,...an−1 组成的有限序列,记作LS=( a0,a1,a2,...an−1 ),其中,LS为表名; ai (0≤i≤n-1)是表中元素,它或者是数据元素(称为原子),或者是子表;n是表的长度,即表中元素的个数;表的长度不包括作为分界符的左括号“(”和右括号“)”和表元素之间的分隔符“,”;长度为0的表为空表。
- 一个广义表如果长度n≥1,则称其第一个表元素 a0 为广义表的表头(head),而由表中除 a0 外其他元素组成的表( a1,a2,...an−1 )称为广义表的表尾(tail)。
广义表的一些例子及其对应的示例图:
(1)A = (),A是一个空表,表的长度为0,没有表头和表尾。 (2)B = (a,b),B是一个只包括原子的表,称为线性表,表的长度为2,表头是a,表尾是(b)(表尾还是一个表,其表头是b,表尾是空表())。 (3)C = (c,(d,e,f)),C是一个包括一个原子和一个子表的表,表的长度为2,表头是c,表尾是((d,e,f))(表尾还是一个表,其表头是(d,e,f),表尾是空表())。 (4)D = (B,C,A) = ((a,b),(c,(d,e,f)),()),D是一个包括三个子表的表,表的长度为3,表头是B,表尾是(C,A)。 (5)E = (B,D) = ((a,b),(B,C,A)) = ((a,b),((a,b),(c,(d,e,f)),())),E是一个包括两个子表的表,表的长度为2,表头是B,表尾是(D)。 (6)F = (g,F) = (g,(g,(g,(…)))),F是一个包括一个原子和一个子表的表,表的长度为2,表头是g,表尾是(F)(表尾还是一个表,其表头是(F),表尾是空表()),对于表头来说出现了递归。
- 注:广义表()和(())不同,前者是长度为0的空表,对其不能做求表头和表尾的运算;而后者是长度为1的非空表(只不过该表中惟一的一个元素是空表),对其可进行分解,得到的表头和表尾均是空表()。
1.2 广义表的特性
- 有次序性:各表元素在表中以线性序列排列,每个表元素至多一个直接前驱,一个直接后继,这个次序不能交换(ps:这句话我也不是很懂,为什么不是可以有多个直接后继。)
- 有长度:表元素个数一定,不能是无限的,可以是空表。
- 有深度:表元素可以是原表的子表,子表的表元素还可以是子表,……,因此广义表是多层次结构。
- 可递归:广义表本身可以是自己的子表,一般称具有这种性质的表为递归表。
- 可共享:广义表可以为其他广义表共享,一般称具有这种性质的表为共享表或再入表。
1.3 广义表的存储表示及结点结构
- 广义表的存储表示:用链表结构作为广义表的存储表示。
- 广义表的的结点包括3个部分:标志域(utype),信息域(info),尾指针域(tlink)。
(1)标志域(utype):用来标明该结点是什么类型的结点。
当utype=0时,表示该结点是广义表专用的附加头结点;
当utype=1时,表示该结点是原子节点;
当utype=2时,表示该结点是子表结点。
(2)信息域(info):不同类型的结点在这个域中存放的内容不同。
当utype=0时,该信息域存放引用计数(ref);
当utype=1时,该信息域存放数据值(value);
当utype=2时,该信息域存放指向子表表头的指针(hlink)。
(3)尾指针域(tlink):用于存放一个指针,该指针指向下一个结点的开始存储地址。
当utype=0时,该指针域存放指向该表表头元素结点的指针;
当utype≠0时,该指针域存放同一层下一个表结点的地址。 - 广义表的结点结构示意图:
2. 广义表的实现
2.1 广义表的结点结构定义
文件:GenListNode.h
#ifndef GEN_LIST_NODE_H_ #define GEN_LIST_NODE_H_ #include <iostream> #include <string> #include <strstream> using namespace std; template <class T> struct GenListNode //广义表结点类定义 { int utype; //标志域,utype={0,1,2} GenListNode<T> *tlink; //尾指针域,tlink union //信息域,info { int ref; //当utype=0时,该信息域存放引用计数(ref) T value; //当utype=1时,该信息域存放数据值(value) GenListNode<T> *hlink; //当utype=2时,该信息域存放指向子表表头的指针(hlink) }info; //构造函数 GenListNode():utype(0),tlink(NULL),info.ref(0) { } //拷贝构造函数 GenListNode(GenListNode<T>& RL) { utype = RL.utype; tlink = RL.tlink; info = RL.info; } }; #endif /* GEN_LIST_NODE_H_ */
2.2 广义表的类定义及其操作的实现
文件:GenList.h
#ifndef GEN_LIST_H_ #define GEN_LIST_H_ #include "GenListNode.h" template<class T> class GenList { public: GenList(); //构造函数 ~GenList(); //析构函数 public: GenListNode<T>* Head(); //返回表头元素 GenListNode<T>* First(); //返回第一个元素 GenListNode<T>* Next(GenListNode<T>* elem); //返回表元素elem的直接后继元素 GenList<T>* Tail(); //返回表尾元素 void Copy(const GenList<T>& R); //广义表的复制 int Length(); //计算广义表的长度 int Depth(); //计算一个非递归广义表的深度 public: template<class T> friend istream& operator >> (istream& in, GenList<T>& L); //输入广义表元素的重载操作>> private: GenListNode<T>* Copy(GenListNode<T>* ls); //复制一个ls指示的无共享非递归表 int Length(GenListNode<T>* ls); //求由ls指示的广义表的长度 int Depth(GenListNode<T>* ls); //计算由ls指示的非递归表的深度 bool Equal(GenListNode<T>* s, GenListNode<T>* t); //判以s和t为表头的两个表是否相等 void Remove(GenListNode<T> *ls); //释放以ls为附加头结点的广义表 void GreateList(istream& in, GenListNode<T> *& ls); //从输入流对象输入广义表的字符串描述,建立一个带附加头结点的广义表结构 private: GenListNode<T> *first; //广义表头指针 }; //构造函数 template<class T> GenList<T>::GenList() : first(new GenListNode<T>) { cout << "$ 执行构造函数" << endl; } //析构函数 template<class T> GenList<T>::~GenList() { cout << "$ 执行析构函数" << endl; Remove(first); } //返回表头元素 template<class T> GenListNode<T>* GenList<T>::Head() { return first; } //返回第一个元素 template<class T> GenListNode<T>* GenList<T>::First() { return first->tlink; } //返回表元素elem的直接后继元素 template<class T> GenListNode<T>* GenList<T>::Next(GenListNode<T>* elem) { return elem->tlink; } //返回表尾元素 template<class T> GenList<T>* GenList<T>::Tail() { if (first->tlink == NULL) { return NULL; } GenList<T>* lt; lt->first->tlink = Copy(first->tlink->tlink); return lt; } //广义表的复制 template<class T> void GenList<T>::Copy(const GenList<T>& R) { first = Copy(R.first); } //计算广义表的长度 template<class T> int GenList<T>::Length() { return Length(first); } //计算一个非递归广义表的深度 template<class T> int GenList<T>::Depth() { return Depth(first); } //输入广义表元素的重载操作>> template<class T> istream& operator >> (istream& in, GenList<T>& L) { return in; } //复制一个ls指示的无共享非递归表 template<class T> GenListNode<T>* GenList<T>::Copy(GenListNode<T>* ls) { GenListNode<T> *q = NULL; if (ls != NULL) { q = new GenListNode<T>; //处理当前的结点q q->utype = ls->utype; //复制结点类型 switch (ls->utype) //根据utype传送信息 { case 0: { q->info.ref = ls->info.ref; //附加头结点 break; } case 1: { q->info.value = ls->info.value; //原子结点 break; } case 2: { q->info.hlink = Copy(ls->info.hlink); //表结点 break; } default: { break; } } q->tlink = Copy(ls->tlink); //处理同一层下一结点为头的表 } return q; } //求由ls指示的广义表的长度 template<class T> int GenList<T>::Length(GenListNode<T>* ls) { if (ls != NULL) { return 1 + Length(ls->tlink); } else { return 0; } } //计算由ls指示的非递归表的深度 template<class T> int GenList<T>::Depth(GenListNode<T>* ls) { if (ls->tlink == NULL) { return 1; } GenListNode<T> *temp = ls->tlink; int m = 0; int n = 0; while (temp != NULL) { if (temp->utype == 2) { n = Depth(temp->info.hlink); if (m < n) { m = n; } } temp = temp->tlink; } return m + 1; } //判以s和t为表头的两个表是否相等 template<class T> bool GenList<T>::Equal(GenListNode<T>* s, GenListNode<T>* t) { int x = 0; if ((s->tlink == NULL) && (t->tlink == NULL)) { return true; } if ((s->tlink != NULL) && (t->tlink != NULL) && (s->tlink->utype == t->tlink->utype)) { if (s->tlink->utype == 1) { x = (s->tlink->info.value == t->tlink->info.value) ? 1 : 0; } else { x = Equal(s->tlink->info.hlink, t->tlink->info.hlink); } if (x == 1) { return Equal(s->tlink, t->tlink); } } return false; } //释放以ls为附加头结点的广义表 template<class T> void GenList<T>::Remove(GenListNode<T> *ls) { ls->info.ref--; //附加头结点的引用计数减1 if (ls->info.ref >= 0) //如果减到0 { GenListNode<T> *q; while (ls->tlink != NULL) //横扫表顶层 { q = ls->tlink; //到第一个结点 if (q->utype == 2) //递归删除子表 { Remove(q->info.hlink); if (q->info.hlink->info.ref <= 0) { delete q->info.hlink; //删除子表附加头结点 } } ls->tlink = q->tlink; delete q; } } } //从输入流对象输入广义表的字符串描述,建立一个带附加头结点的广义表结构 template<class T> void GenList<T>::GreateList(istream& in, GenListNode<T> *& ls) { } #endif /* GEN_LIST_H_ */
2.3 主函数(main函数)的实现
文件:main.cpp
#include "GenList.h" int main() { system("pause"); return 0; }
参考文献:
[1]《数据结构(用面向对象方法与C++语言描述)(第2版)》殷人昆——第四章
[2] 百度搜索关键字:广义表
[3] 网络资源:http://blog.csdn.net/pi9nc/article/details/9228581