广义表(Lists,又称列表)是线性表的推广。线性表定义为n>=0个元素a1,a2,a3,…,an的有限序列。线性表的元素仅限于原子项,原子是作为结构上不可分割的成分,它可以是一个数或一个结构,若放松对表元素的这种限制,容许它们具有其自身结构,这样就产生了广义表的概念。
广义表是n (n>=0)个元素a1,a2,a3,…,an的有限序列,其中ai或者是原子项,或者是一个广义表。通常记作LS=(a1,a2,a3,…,an)。LS是广义表的名字,n为它的长度。若ai是广义表,则称它为LS的子表。
抽象数据类型广义表的定义如下:
ADT Glist
{
数据对象: D={ei | i=1,2,..,n;n>=0 ; eiÎAtomSet或eiÎGlist,
AtomSet为某个数据对象}
数据关系:R1={< ei-1, ei > | ei-1 , eiÎD,2<=i<=n}
基本操作:
InitGList( &L);
操作结果:创建空的广义表L。
CreateGList(&L,S);
初始条件:S是广义表的书写形式串。
操作结果:由S创建广义表L。
DestroyGList(&L);
初始条件:广义表L存在。
操作结果:销毁广义表L。
CopyGList( &T,L);
初始条件:广义表L存在。
操作结果:由广义表L复制得到广义表T。
GListLength(L);
初始条件:广义表L存在。
操作结果:求广义表L的长度,即元素个数。
GListDepth(L);
初始条件:广义表L存在。
操作结果:求广义表L的深度。
GListEmpty (L);
初始条件:广义表L存在。
操作结果:判定广义表L是否为空。
GetHead(L);
初始条件:广义表L存在。
操作结果:取广义表L的头。
GetTail( &T,L);
初始条件:广义表L存在。
操作结果:取广义表L的尾。
InsertFirst_GL(&L,e);
初始条件:广义表L存在。
操作结果:插入元素e作为广义表L的第一元素。
DeleteFirst_GL(&L,&e);
初始条件:广义表L存在。
操作结果:删除广义表L的第一元素,并用e返回其值。
Traverse_GL (L,visit());
初始条件:广义表L存在。
操作结果:遍历广义表L,用函数visit处理每个元素。
}
通常用圆括号将广义表括起来,用逗号分隔其中的元素。为了区别原子和广义表,书写时用大写字母表示广义表,用小写字母表示原子。若广义表LS(n>=1)非空,则a1是LS的表头,其余元素组成的表(a2,…an)称为LS的表尾。
显然广义表是递归定义的,这是因为在定义广义表时又用到了广义表的概念。广义表的例子如下:
(1)A=()——A是一个空表,其长度为零。
(2)B=(e)——表B只有一个原子e,B的长度为1。
(3)C=(a,(b,c,d))——表C的长度为2,两个元素分别
为原子a和子表(b,c,d)。
(4)D=(A,B,C)——表D的长度为3,三个元素
都是广义表。显然,将子表的值代入后,
则有D=(( ),(e),(a,(b,c,d)))。
(5)E=(E)——这是一个递归的表,它的长度为2,E相当于一个无限的广义表E=(a,(a,(a,(a,…)))).
从上述定义和例子可推出广义表的三个重要结论:
(1)广义表的元素可以是子表,而子表的元素还可以是子表,。由此,广义表是一个多层次的结构,可以用图形象地表示。P108
(2)广义表可为其它表所共享。例如在上述例(4)中,广义表A,B,C为D的子表,则在D中可以不必列出子表的值,而是通过子表的名称来引用。
(3)广义表的递归性。
综上所述,广义表不仅是线性表的推广,也是树的推广。
由表头、表尾的定义可知:任何一个非空广义表其表头可能是原子,也可能是列表,而其表尾必定是列表。
gethead(B)=e gettail(B)=( )
gethead(D)=A gettail(D)=(B,C)
由于(B,C)为非空广义表,则可继续分解得到:
gethead(B,C)=B gettail(B,C)=(C)
注意广义表()和( ( ) )不同。前者是长度为0的空表,
对其不能做求表头的和表尾的运算;而后者是长度为1的非空表(只不过该表中唯一的一个元素是空表)。对其可进行分解,得到表头和表尾均为空表()。
广义表的存储结构
由于广义表(a1,a2,a3,…an)中的数据元素可以具有不同的结构,(或是原子,或是广义表),因此,难以用顺序存储结构表示,通常采用链式存储结构,每个数据元素可用一个结点表示。
由于广义表中有两种数据元素,原子或广义表,因此,需要两种结构的结点:一种是表结点,用以表示列表;一种是原子结点,用以表示原子。
若列表不空,则可分解成表头和表尾;反之,一对确定的表头和表尾可唯一确定列表。由此,一个表结点可由三个域组成:标志域、指示表头的指针域和指示表尾的指针域;而原子结点只需两个域:标志域和值域。
1、仅有表结点由三个域组成:
标志域、指示表头的指针域和指示表尾的指针域;而原子域只需两个域:标志域和值域。
头尾链表存储表示
示例如图:
这种存储结构的三个特点:
1。除空表的表头指针为空外,对任何非空列表,其表头指针均指向一个表结点,且该结点中的hp域指示列表表头,tp域指向列表表尾(除非表尾为空,则指针为空,否则必为表结点);
2。容易分清列表中原子和子表所在层次。如在列表D中,原子e和a在同一层次上,而b、c和d在同一层次且比e和a低一层,B和C是同一层的子表;
3。最高层的表结点个数即为列表的长度。
2、表结点和原子结点均由三个域组成:标志域、指示表头的指针域和指示表尾的指针域;原子结点的三个域为:标志域、值域和指示表尾的指针域。
其类型定义如下:
扩展线性链表存储表示
示例如图:
/* 广义表的头尾链表存储表示 */
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; /* 广义表类型 */
#include
#include
#include
#include
#include
using namespace std;
#define MAXSTRLEN 40 /* 用户可在255以内定义最大串长(1个字节) */
typedef char SString[MAXSTRLEN+1]; /* 0号单元存放串的长度 */
/* 函数结果状态代码 */
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2 //因为在math.h中已定义OVERFLOW的值为3,故去掉此行
typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */
typedef char AtomType; /* 定义原子类型为字符型 */
/* c5-5.h 广义表的头尾链表存储表示 */
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; /* 广义表类型 */
Status StrAssign(SString T,char *chars)
{ /* 生成一个其值等于chars的串T */
int i;
if(strlen(chars)>MAXSTRLEN)
return ERROR;
else
{
T[0]=strlen(chars);
for(i=1;i<=T[0];i++)
T[i]=*(chars+i-1);
return OK;
}
}
Status StrCopy(SString T,SString S)
{ /* 由串S复制得串T */
int i;
for(i=0;i<=S[0];i++)
T[i]=S[i];
return OK;
}
Status StrEmpty(SString S)
{ /* 若S为空串,则返回TRUE,否则返回FALSE */
if(S[0]==0)
return TRUE;
else
return FALSE;
}
int StrCompare(SString S,SString T)
{ /* 初始条件: 串S和T存在 */
/* 操作结果: 若S>T,则返回值>0;若S=T,则返回值=0;若SS[0]||len<0||len>S[0]-pos+1)
return ERROR;
for(i=1;i<=len;i++)
Sub[i]=S[pos+i-1];
Sub[0]=len;
return OK;
}
int Index(SString S,SString T,int pos)
{ /* 返回子串T在主串S中第pos个字符之后的位置。若不存在,则函数值为0。 */
/* 其中,T非空,1≤pos≤StrLength(S)。算法4.5 */
int i,j;
if(1<=pos&&pos<=S[0])
{
i=pos;
j=1;
while(i<=S[0]&&j<=T[0])
if(S[i]==T[j]) /* 继续比较后继字符 */
{
++i;
++j;
}
else /* 指针后退重新开始匹配 */
{
i=i-j+2;
j=1;
}
if(j>T[0])
return i-T[0];
else
return 0;
}
else
return 0;
}
Status StrInsert(SString S,int pos,SString T)
{ /* 初始条件: 串S和T存在,1≤pos≤StrLength(S)+1 */
/* 操作结果: 在串S的第pos个字符之前插入串T。完全插入返回TRUE,部分插入返回FALSE */
int i;
if(pos<1||pos>S[0]+1)
return ERROR;
if(S[0]+T[0]<=MAXSTRLEN)
{ /* 完全插入 */
for(i=S[0];i>=pos;i--)
S[i+T[0]]=S[i];
for(i=pos;iS[0]-len+1||len<0)
return ERROR;
for(i=pos+len;i<=S[0];i++)
S[i-len]=S[i];
S[0]-=len;
return OK;
}
Status Replace(SString S,SString T,SString V)
{ /* 初始条件: 串S,T和V存在,T是非空串(此函数与串的存储结构无关) */
/* 操作结果: 用V替换主串S中出现的所有与T相等的不重叠的子串 */
int i=1; /* 从串S的第一个字符起查找串T */
if(StrEmpty(T)) /* T是空串 */
return ERROR;
do
{
i=Index(S,T,i); /* 结果i为从上一个i之后找到的子串T的位置 */
if(i) /* 串S中存在串T */
{
StrDelete(S,i,StrLength(T)); /* 删除该串T */
StrInsert(S,i,V); /* 在原串T的位置插入串V */
i+=StrLength(V); /* 在插入的串V后面继续查找串T */
}
}while(i);
return OK;
}
void DestroyString()
{ /* 由于SString是定长类型,无法销毁 */
}
void StrPrint(SString T)
{ /* 输出字符串T。另加 */
int i;
for(i=1;i<=T[0];i++)
printf("%c",T[i]);
printf("\n");
}
void sever(SString str,SString hstr) /* 算法5.8 SString是数组,不需引用类型 */
{ /* 将非空串str分割成两部分:hsub为第一个','之前的子串,str为之后的子串 */
int n,k,i; /* k记尚未配对的左括号个数 */
SString ch,c1,c2,c3;
n=StrLength(str);
StrAssign(c1,",");
StrAssign(c2,"(");
StrAssign(c3,")");
SubString(ch,str,1,1);
for(i=1,k=0;i<=n&&StrCompare(ch,c1)||k!=0;++i)
{ /* 搜索最外层的第一个逗号 */
SubString(ch,str,i,1);
if(!StrCompare(ch,c2))
++k;
else if(!StrCompare(ch,c3))
--k;
}
if(i<=n)
{
SubString(hstr,str,1,i-2);
SubString(str,str,i,n-i+1);
}
else
{
StrCopy(hstr,str);
ClearString(str);
}
}
Status InitGList(GList *L)
{ /* 创建空的广义表L */
*L=NULL;
return OK;
}
Status CreateGList(GList *L,SString S) /* 算法5.7 */
{ /* 采用头尾链表存储结构,由广义表的书写形式串S创建广义表L。设emp="()" */
SString sub,hsub,emp;
GList p,q;
StrAssign(emp,"()");
if(!StrCompare(S,emp))
*L=NULL; /* 创建空表 */
else
{
*L=(GList)malloc(sizeof(GLNode));
if(!*L) /* 建表结点 */
exit(OVERFLOW);
if(StrLength(S)==1) /* S为单原子 */
{
(*L)->tag=ATOM;
(*L)->a.atom=S[1]; /* 创建单原子广义表 */
}
else
{
(*L)->tag=LIST;
p=*L;
SubString(sub,S,2,StrLength(S)-2); /* 脱外层括号 */
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;
}
}
return OK;
}
void DestroyGList(GList *L) /* 广义表的头尾链表存储的销毁操作 */
{ /* 销毁广义表L */
GList q1,q2;
if(*L)
{
if((*L)->tag==ATOM)
{
free(*L); /* 删除原子结点 */
*L=NULL;
}
else /* 删除表结点 */
{
q1=(*L)->a.ptr.hp;
q2=(*L)->a.ptr.tp;
free(*L);
*L=NULL;
DestroyGList(&q1);
DestroyGList(&q2);
}
}
}
Status CopyGList(GList *T,GList L)
{ /* 采用头尾链表存储结构,由广义表L复制得到广义表T。算法5.6 */
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);
/* 复制广义表L->ptr.hp的一个副本T->ptr.hp */
CopyGList(&((*T)->a.ptr.tp),L->a.ptr.tp);
/* 复制广义表L->ptr.tp的一个副本T->ptr.tp */
}
}
return OK;
}
int GListLength(GList L)
{ /* 返回广义表的长度,即元素个数 */
int len=0;
if(!L)
return 0;
if(L->tag==ATOM)
return 1;
while(L)
{
L=L->a.ptr.tp;
len++;
}
return len;
}
int GListDepth(GList L)
{ /* 采用头尾链表存储结构,求广义表L的深度。算法5.5 */
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)
{
printf("空表无表头!\n");
exit(0);
}
p=L->a.ptr.tp;
L->a.ptr.tp=NULL;
CopyGList(&h,L);
L->a.ptr.tp=p;
return h;
}
GList GetTail(GList L)
{ /* 取广义表L的尾 */
GList t;
if(!L)
{
printf("空表无表尾!\n");
exit(0);
}
CopyGList(&t,L->a.ptr.tp);
return t;
}
Status InsertFirst_GL(GList *L,GList e)
{ /* 初始条件: 广义表存在 */
/* 操作结果: 插入元素e作为广义表L的第一元素(表头,也可能是子表) */
GList p=(GList)malloc(sizeof(GLNode));
if(!p)
exit(OVERFLOW);
p->tag=LIST;
p->a.ptr.hp=e;
p->a.ptr.tp=*L;
*L=p;
return OK;
}
Status DeleteFirst_GL(GList *L,GList *e)
{ /* 初始条件: 广义表L存在 */
/* 操作结果: 删除广义表L的第一元素,并用e返回其值 */
GList p;
*e=(*L)->a.ptr.hp;
p=*L;
*L=(*L)->a.ptr.tp;
free(p);
return OK;
}
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);
Traverse_GL(L->a.ptr.tp,v);
}
}
void visit(AtomType e)
{
printf("%c ", e);
}
int main()
{
char p[80];
SString t;
GList l,m;
InitGList(&l);
InitGList(&m);
printf("空广义表l的深度=%d l是否空?%d(1:是 0:否)\n",GListDepth(l),GListEmpty(l));
printf("请输入广义表l(书写形式:空表:(),单原子:a,其它:(a,(b),b)):\n");
gets(p);
StrAssign(t,p);
CreateGList(&l,t);
printf("广义表l的长度=%d\n",GListLength(l));
printf("广义表l的深度=%d l是否空?%d(1:是 0:否)\n",GListDepth(l),GListEmpty(l));
printf("遍历广义表l:\n");
Traverse_GL(l,visit);
return 0;
}
/* 广义表的扩展线性链表存储表示 */
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=S[1];
(*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);
}
}