1.广义表基本概念
广义表是n个数据元素(d1,d2,d3,…,dn)的有限序列,di 既可以是单个元素,也可以是一个广义表。通常记作GL =(d1,d2,d3,…,dn),n是广义表长度。
若其中 di 是一个广义表,则称 di 是广义表GL的子表。在广义表GL中,d1是广义表表头,其余部分组成的表称为广义表表尾。
例如:
D=():空表,长度为0。
A=(a,(b,c)):表长度为2的广义表,第一个元素是单个数据a,第二个元素是一个子表(b,c)。
B=(A,A,D):长度为3的广义表,前两个元素为表A,第三个元素为空表D。
C=(a,C):长度为2递归定义的广义表,C相当于无穷表C=(a,(a,(a,(…))))。
由定义和例子可以得出以下三个结论:
① 广义表的元素可以是子表,而子表还可以是子表,因此广义表是一个多层的结构。
② 广义表可以被其它广义表共享。如广义表B共享表A,在表B中不必列出表A的内容,只要通过子表的名称就可以引用该表。
③ 广义表具有递归性,如广义表C。
2.广义表的存储结构
由于广义表中的元素具有不同的结构(原子或者列表),通常采用链式存储结构。
采用两种结构的结点:①表结点,表示列表 ②原子结点,表示原子
2.1头尾链表存储结构
任何一个非空的广义表都可以将其分解成表头和表尾两部分,反之,一对确定的表头和表尾可以唯一地确定一个广义表。因此,一个表结点可由三个域构成:标志域、指向表头的指针域和指向表尾的指针域,而元素结点只需要两个域:标志域和值域。
/*广义表的头尾链表存储结构*/
typedef enum { ATOM, LIST }ElemTag; //ATOM=0,表示原子;LIST=1,表示子表
typedef struct GLNode {
ElemTag tag; //标志位tag用来区分原子结点和表结点
union {
int atom; //原子结点的值域
struct {
struct GLNode* hp, * tp //表结点的指针域htp,包括表头指针域hp和表尾指针域tp
}htp;
}atom_htp; //atom_htp是原子结点的值域atom和表结点的指针域htp的联合体域
}GLNode, * GList;
2.2 同层结点链存储结构
原子结点和表结点均由三个域构成。
/*广义表的同层结点链存储结构*/
typedef enum { ATOM, LIST }ElemTag; //ATOM=0,表示原子;LIST=1,表示子表
typedef struct GLNode {
ElemTag tag; //标志位tag用来区分原子结点和表结点
union {
int atom; //原子结点的值域
struct GLNode* hp; //表头指针域
}atom_hp; //atom_hp是原子结点的值域atom和表结点的表头指针域hp的联合体域
struct GLNode* tp; //同层下一个结点的指针域
}GLNode, * GList;
3.广义表的典型实例--m元多项式的表示
由下述图片可以看出,用广义表表示m元多项式是超级合适的。
用第二种存储结构来定义表示m元多项式的广义表的存储结构
typedef struct MPNode {
ElemTag tag; //标志位tag用来区分原子结点和表结点
int exp; //指数域
union {
float coef; //系数域
struct MPNode* hp; //表头指针域
};
struct MPNode* tp; //同层下一个结点的指针域
} *MPList;
4.广义表的一些基本运算
4.1求广义表的深度
广义表的深度定义为广义表中括弧的重数,是广义表的一种量度。
采用递归算法:
//采用头尾链表存储结构,求广义表L的深度
int GListDepth(GList L) {
int dep, max;
GLNode* s;
if (L == NULL)
return 1; //空表深度为1
if (L->tag == ATOM)
return 0; //原子深度为0
for(max=0,pp=L;pp;pp=pp->ptr.tp)
{
dep=GListDepth(pp->ptr.tp);//求以pp->ptr.tp为头指针的子表的深度
if(dep>max) max=dep;
}
return max + 1; //表的深度等于最深子表的深度+1
}
4.2 复制广义表
一对确定的表头和表尾可以位移确定一个广义表。由此,复制一个广义表只要分别复制其表头和表尾。由此还是采用递归算法。
Status CopyGList(GList &T,GList L){
if(!L) T=NULL;
else
{
if(!(T=(GList)malloc(sizeof(GLNode)))) exit (OVERFLOW);//建立表结点
T->tag=L->tag;
if(L->tag==ATOM) T->atom=L->atom;//复制单原子
else
{
CopyGList(T->ptr.hp,L->ptr.hp);//复制广义表L->ptr.hp的一个副本T->ptr.hp
CopyGList(T->ptr.tp,L->ptr.tp);//复制广义表L->ptr.tp的一个副本T->ptr.tp
}
}
return OK;
}
4.3 建立广义表的存储结构
Status CreateGList(GList &L,SString S)
{
if(StrCompare(S,emp)) L=NUL;//创建空表
else{
if(!(L=(GList)malloc(sizeof(GLNode)))) ext(OVERFLOW);/建表结点
if(StrLength(S)==1)
{
L->tag=ATOM;
L->atom=S;
}//创建单原子广义表
else{
L->tag=LIST;
p=L;
SubString(sub,S,2,StrLength(s)-2);
do{ // 重复建n个字串
sever(sub,hsub);//从sub中分离出表头串hsub
CreateGList(p->ptr.hp,hsub);
q = p;
if (!StrEmpty(sub)){
if(!(p= (GLNode *) malloc (sizeof(GLNode))))
exit(OVERFLOW);
p->tag=LIST;
q->ptr.tp=p;
}
}while(!StrEmpty(sun));
q->ptr.tp=NULL;
}
}
return OK;
}
//将非空串str分割成两部分hsub为第一前的子串,str为之后的子串
Status sever(SString &str,SString &hstr){
n=StrLength(str);
i=0;
k=0;//k记尚未配对的左括号个数
do{//搜索最外层的第一个逗号
++i;
SubString(ch,str,i,1);
if(ch=='(') ++k;
else if(ch==')') --k;
}while(i<n&&(ch!=','||k!=0));
if(i<n)
{
SubString(hstr,str,1,i-1);
SubString(str,str,i+1,n-i);
}
else
{
(StrCopy(hstr,str);
ClearString(str);
}
}
4.4 统计原子的数目
/*统计广义表中原子结点数目*/
int CountAtom(GList L) {
int n1, n2;
if (L == NULL)
return 0; //空表中没有原子
if (L->tag == ATOM)
return 1; //L指向单个原子
n1 = CountAtom(L->atom_htp.htp.hp); //统计表头中的原子数目
n2 = CountAtom(L->atom_htp.htp.tp); //统计表尾中的原子数目
return (n1 + n2);
}
4.4 求广义表的长度和深度
/*求广义表长度*/
int Length(GList L) {
int k = 0;
GLNode* s;
if (L == NULL)
return 0; //空表长度为0
if (L->tag == ATOM) //原子不是表
exit(0);
s = L;
while (s != NULL) { //统计最上层表的长度
k++;
s = s->atom_htp.htp.tp;
}
return k;
}
/*求广义表的深度*/
int Depth(GList L) {
int d, max;
GLNode* s;
if (L == NULL)
return 1; //空表深度为1
if (L->tag == ATOM)
return 0; //原子深度为0
s = L;
while (s != NULL) { //求每个子表的深度的最大值
d = Depth(s->atom_htp.htp.hp);
if (d > max)
max = d;
s = s->atom_htp.htp.tp;
}
return (max + 1); //表的深度等于最深子表的深度+1
}
5.参考
《数据结构》严蔚敏