数据结构--广义表

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.参考

《数据结构》严蔚敏

【数据结构】广义表的存储结构及基本运算(C语言)_求广义表长度c语言_素锦流年つ的博客-CSD博客

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值