广义表

一、广义表的定义
广义表简称表,它是线性表的推广。一个广义表是n(n≥0)个元素的一个序列,若n=0时则称为空表。

设ai为广义表的第i个元素,则广义表GL的一般表示与线性表相同:

            GL=(a1,a2,…,ai,…,an)
其中n表示广义表的长度,即广义表中所含元素的个数,n≥0。如果ai是单个数据元素,则ai是广义表GL的原子;如果ai是一个广义表,则ai是广义表GL的子表。 

广义表具有如下重要的特性:
(1)广义表中的数据元素有相对次序;
(2)广义表的长度定义为最外层包含元素个数;
(3)广义表的深度定义为所含括弧的重数。其中原子的深度为0,空表的深度为1;
(4)广义表可以共享;一个广义表可以为其他广义表共享;这种共享广义表称为再入表;
(5)广义表可以是一个递归的表。一个广义表可以是自已的子表。这种广义表称为递归表。递归表的深度是无穷值,长度是有限值;

(6)任何一个非空广义表GL均可分解为表头head(GL) = a1和表尾tail(GL) = ( a2,…,an) 两部分。 

为了简单起见,下面讨论的广义表不包括前面定义的再入表和递归表,即只讨论一般的广义表。

另外,我们规定用小写字母表示原子,用大写字母表示广义表的表名。例如:

    A=()
    B=(e)
    C=(a,(b,c,d))
    D=(A,B,C)=((),(e),(a,(b,c,d)))
    E=((a,(a,b),((a,b),c)))

其中A是一个空表,其长度为0;

B是只含有单个原子e的表,其长度为1;

C有两个元素,一个是原子a,另一个是子表,其长度为2;

D有三个元素,每个元素都是一个表,其长度为3;

E中只含有一个元素,是一个表,它的长度为1;

二、广义表的存储结构

      广义表是一种递归的数据结构,因此很难为每个广义表分配固定大小的存储空间,所以其存储结构只好采用动态链式结构。

为了使得子表和原子两类节点能在形式上保持一致,又能进行区别,所以采用如下结构。

其中tag域为标志字段;sublist/data由tag决定,为0时表示该节点是原子节点,则第二个域为data,存放原子元素的信息,为1时,表示该节点是表节点,存放sublist,即存放子表第一个元素对应节点的地址。

link域存放与本元素同一层的下一个元素所在节点的地址,当本元素是所在层的最后一个元素时,link域为NULL。

 typedef struct lnode
{ int tag;        //节点类型标识
   union 
  {   ElemType data;
       struct lnode *sublist;
   }  val;
   struct lnode *link;    //指向下一个元素
} GLNode;    //广义表节点类型定义       

三、广义表的运算

(1)求广义表的长度

 在广义表中,同一层次的每个节点是通过link域链接起来的,所以可把它看做是由link域链接起来的单链表。这样,求广义表的长度就是求单链表的长度,可以采用以前介绍过的求单链表长度的方法求其长度。

求广义表长度的非递归算法如下:
 int GLLength(GLNode *g)  
 //g为一个广义表头节点的指针
 {  int n=0;
    g=g->val.sublist; //g指向广义表的第一个元素
    while (g!=NULL) 
    {  n++;
       g=g->link;
    }

    return n;

}

(2)求广义表的深度

对于带头节点的广义表g,广义表深度的递归定义是它等于所有子表中表的最大深度加1。若g为原子,其深度为0。

求广义表深度的递归模型f()如下:

int GLDepth(GLNode *g) //求带头节点的广义表g的深度
{  int max=0,dep;
   if (g->tag==0) return 0;  //为原子时返回0
   g=g->val.sublist;          //g指向第一个元素
   if  (g==NULL) return  1;   //为空表时返回1
   while (g!=NULL) //遍历表中的每一个元素
   {  if (g->tag==1)        //元素为子表的情况
      {  dep=GLDepth(g); //递归调用求出子表的深度
         if (dep>max) max=dep;   
            //max为同一层所求过的子表中深度的最大值
      }
      g=g->link;  //使g指向下一个元素
   }
   return(max+1); //返回表的深度
}

(3)输出广义表

 以g作为头节点的广义表的表头指针,打印输出该广义表时,需要对子表进行递归调用。

void DispGL(GLNode *g)  //g为一个广义表的头节点指针
{  if (g!=NULL)           //表不为空判断
   {  if (g->tag==1)    //为表节点时
{  printf("(");  //输出'('
         if (g->val.sublist==NULL) printf("");
             //输出空子表
         else  DispGL(g->val.sublist);
             //递归输出子表
      }
      else printf("%c", g->val.data); 
          //为原子时输出元素值
      if (g->tag==1)printf(")");//表节点时输出')'
         if (g->link!=NULL) 
         {  printf(",");
            DispGL(g->link);//递归输出后续表的内容
         }
    }

(4)建立广义表

假定广义表中元素类型为ElemType为char类型,每个原子的值被限定为单个英文字母。并假设广义表是一个正确的表达式,其格式为:元素之间用一个逗号分隔,表元素的起止符号为左、右括号,空表在元括号内包含#。

算法如下:

GLNode *CreateGL(char *&s)

{

    GLNode *g;

    char ch=*s++;//取一个字符

    if(ch!='\0') //读取串

    {        g=(GLNode *)malloc(sizeof(GLNode));

            if(ch=='(')//左括号

                { g->tag=1;

                    g->val.sublist=CreateGL(s);//构造子表并链接到表头

                 }

              else if(ch==')')//右括号

                    g=NULL;

              else if(ch=='#')//空表

                    g=NULL;

               else

             {    g->tag=0;//原子字符

                  g->val.data=ch;

               }

        }

else 

       g=NULL;//串结束

ch=*s++;//下一个字符

if(g!=NULL)//如果串未结束,继续构造兄弟节点

    if(ch==',')

            g->link=CreateGL(s);

    else

           g->link=NULL;

return 0;

}
--------------------- 
作者:kong_xz 
来源:CSDN 
原文:https://blog.csdn.net/kong_xz/article/details/79484843 
版权声明:本文为博主原创文章,转载请附上博文链接!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值