广义表(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] 网络资源: