前言
本节我们来说说C语言中的广义表。主要介绍广义表的概念定义,并说明其存储结构,算法中将使用到递归思想。
广义表是线性表的一种推广,在数据结构中有广泛应用。
一、广义表的概念
1.广义表的概念
(1)广义表:也称列表,是n(n>=0)个元素的有限序列
记作:LS=(a1,a2,…,an)ai(1<=i<=n)是数据元素或广义表
其中:
LS:广义表名
n:LS的长度
通常,大写字母表示广义表的名称,小写字母表示数据元素
(2)原子:当广义表LS的元素是一个数据元素时,称为原子
(3)广义表的子表:当广义表LS的元素不是一个数据元素时,称为广义表的子表
(4)LS的表头(head):广义表非空时,第一个元素a1称为LS的表头
(5)LS的表尾(tail):其余部分(a2,…,an)称为表尾
举例:
(1)A=(): A是一个空表,长度n=0
(2)B=(e),Head(B)=e ,Tail(B)=():表尾为空的广义表,长度为1
(3)C=(a,(b,c)) ,Head©=a为原子 ,Tail©=((b,c))为广义表,表尾长度为1
(4)D=((a,b),c) ,Head(D)=(a,b)为广义表 ,Tail(D)=©
(5)E=((a,b),c,(d,e)), Head(E)=(a,b)为E的子表 ,Tail(E)=(c,(d,e)) ,Head(Tail(E))=c , Tail(Tail(E))=((d,e))
结论1:广义表允许共享子表
结论2:广义表也允许d递归的定义
例:G=(a,G) 这里G是一个长度为2的广义表,第一个元素是原子a,第二个元素是广义表G自己
2.广义表的图型表示
二、广义表的存储结构
1.广义表的存储结构
(1)由于广义表中的元素既可以是原子,也可以是广义表,所以会有原子结点和链表结点
(2)每个元素元素所需的空间大小无法统一,所以很难用顺序存储结构表示,通常采用链式结构表示
原子结点:tag=0 atom(元素),只有2个域,标志域和值域
列表结点: tag=1 hp(表头) tp(表尾),有3个域,标志域、表头指针域与表尾指针域
注:这种链式存储结构中,为了统一管理这2类结点,采用了共同体(联合)来定义广义表的结点类型。
//相关定义
typedef struct GLNode
{
ElemTag tag;//标志域,用以区分原子结点和表结点
union
{
AtomType atom;//原子结点
struct
{
struct GLNode *hp,*tp;
}ptr;//表结点
}
}*GList;
2.广义表的基本操作(递归算法)
(1)求广义表的长度 :int GLisitLength(Glist L)
递归定义:
若L==NULL,长度0
若L!=NULL,长度:1 + GLisitLength(L->ptr.tp)
//求广义表的长度
int GLisitLength (Glist L)
{
if (!L)
return 0;
return 1+GLisitLength(L->ptr.tp);
}
(2)求广义表的深度:int GLisitDepth(Glist L)
广义表:LS=(a1,a2,…,an)
递归定义:
若L= =NULL,深度1
若L!=NULL,深度:1 + Max(ai)
L->tag==0,原子结点:深度0
//求广义表的深度
int GLisitDepth (Glist L)
{
if (!L)
return 1;
if (L->tag==0)
return 0;
for (max=0,p=L;p;p=p->ptr.tp)
{
dep = GLisitDepth(p->ptr.hp);
if (dep>max)
max = dep;
}
return max+1;
}
总结
以上简要介绍了一下广义表。广义表还有很多其他的基本操作,在此不一 一赘述。感兴趣的话可以再去看看其他的代码实现。
下一篇将开始介绍非线性结构——树。篇幅较长,将分为上下两篇。
ps:代码非原创。
如有错误,欢迎指正。