广义表的定义

广义表(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、仅有表结点由三个域组成:

    标志域、指示表头的指针域和指示表尾的指针域;而原子域只需两个域:标志域和值域。

头尾链表存储表示

[cpp] view plaincopy
  1. typedef enum {ATOM,LIST } ElemTag;  //ATOM==0:表示原子,LIST==1:表示子表
  2. typedef struct GLNode {
  3. ElemTag  tag;  //公共部分,用以区分原子部分和表结点
  4. union {       //原子部分和表结点的联合部分
  5. AtomType  atom; //atom是原子结点的值域,AtomType由用户定义
  6. struct { struct GLNode *hp, *tp;} ptr;
  7. // ptr是表结点的指针域,ptr.hp 和ptr.tp分别指向表头和表尾
  8. };
  9. } *Glist;  //广义表类型

示例如图:

这种存储结构的三个特点:

1。除空表的表头指针为空外,对任何非空列表,其表头指针均指向一个表结点,且该结点中的hp域指示列表表头,tp域指向列表表尾(除非表尾为空,则指针为空,否则必为表结点);

2。容易分清列表中原子和子表所在层次。如在列表D中,原子e和a在同一层次上,而b、c和d在同一层次且比e和a低一层,B和C是同一层的子表;

3。最高层的表结点个数即为列表的长度。

 

2、表结点和原子结点均由三个域组成:标志域、指示表头的指针域和指示表尾的指针域;原子结点的三个域为:标志域、值域和指示表尾的指针域。

其类型定义如下:

扩展线性链表存储表示

[cpp] view plaincopy
  1. Typedef enum { ATOM,LIST} ElemTag;
  2. //ATOM==0:表示原子,LIST==1:表示子表
  3. Typedef struct GLNode {
  4. ElemTag    tag;  //公共部分,用以区分原子部分和表结点
  5. union {  //原子部分和表结点的联合部分
  6. AtomType    atom;  //原子结点的值域
  7. struct GLNode  *hp;  //表结点的表头指针
  8. };
  9. struct GLNode    *tp;
  10. //相当于线性链表的next,指向下一个元素结点
  11. } *Glist;  //广义表类型Glist 是一种扩展的线性链表

示例如图:

头尾链表存储表示

存储结构

/* 广义表的头尾链表存储表示 */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<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<iostream>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;elsereturn FALSE;}int StrCompare(SString S,SString T){ /* 初始条件: 串S和T存在 *//* 操作结果: 若S>T,则返回值>0;若S=T,则返回值=0;若S<T,则返回值<0 */int i;for(i=1;i<=S[0]&&i<=T[0];++i)if(S[i]!=T[i])return S[i]-T[i];return S[0]-T[0];}int StrLength(SString S){ /* 返回串的元素个数 */return S[0];}Status ClearString(SString S){ /* 初始条件:串S存在。操作结果:将S清为空串 */S[0]=0;/* 令串长为零 */return OK;}Status Concat(SString T,SString S1,SString S2) /* 算法4.2改 */{ /* 用T返回S1和S2联接而成的新串。若未截断,则返回TRUE,否则FALSE */int i;if(S1[0]+S2[0]<=MAXSTRLEN){ /* 未截断 */for(i=1;i<=S1[0];i++)T[i]=S1[i];for(i=1;i<=S2[0];i++)T[S1[0]+i]=S2[i];T[0]=S1[0]+S2[0];return TRUE;}else{ /* 截断S2 */for(i=1;i<=S1[0];i++)T[i]=S1[i];for(i=1;i<=MAXSTRLEN-S1[0];i++)T[S1[0]+i]=S2[i];T[0]=MAXSTRLEN;return FALSE;}}Status SubString(SString Sub,SString S,int pos,int len){ /* 用Sub返回串S的第pos个字符起长度为len的子串。算法4.3 */int i;if(pos<1||pos>S[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];elsereturn 0;}elsereturn 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;i<pos+T[0];i++)S[i]=T[i-pos+1];S[0]=S[0]+T[0];return TRUE;}else{ /* 部分插入 */for(i=MAXSTRLEN;i<=pos;i--)S[i]=S[i-T[0]];for(i=pos;i<pos+T[0];i++)S[i]=T[i-pos+1];S[0]=MAXSTRLEN;return FALSE;}}Status StrDelete(SString S,int pos,int len){ /* 初始条件: 串S存在,1≤pos≤StrLength(S)-len+1 *//* 操作结果: 从串S中删除第pos个字符起长度为len的子串 */int i;if(pos<1||pos>S[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;elsereturn 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; /* 复制单原子 */elseCopyGList(&(*T)->a.hp,L->a.hp); /* 复制子表 */if(L->tp==NULL) /* 到表尾 */(*T)->tp=L->tp;elseCopyGList(&(*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;elsereturn 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);}
}

广义表的链式定义和基础操作相关推荐

  1. 数据结构开发(5):线性表的链式存储结构

    0.目录 1.线性表的链式存储结构 2.单链表的具体实现 3.顺序表和单链表的对比分析 4.小结 1.线性表的链式存储结构 顺序存储结构线性表的最大问题是: 插入和删除需要移动大量的元素!如何解决? ...

  2. 线性表的链式存储结构以及单链表的插入和删除原理实现

    线性表的链式存储结构 线性表中的每个元素最多只有一个前驱元素和一个后继元素(其逻辑结构),因此可以采用链式存储结构存储. 链表 线性表的链式存储结构称为链表.在链表中每个结点不仅包含有元素本身的信息( ...

  3. 数据结构(四) -- C语言版 -- 线性表的链式存储 - 循环链表

    文章目录 零.读前说明 一.循环链表的概述 二.循环链表的模型 2.1.包含头节点模型 2.2.不包含头节点模型 三.工程结构及简单测试案例 3.1.测试工程的目录结构 3.2.循环链表示例源码 3. ...

  4. 用c语言线性表的链式表示实现,数据结构-使用C语言 朱战立第2章线性表的链式表示.ppt...

    数据结构-使用C语言 朱战立第2章线性表的链式表示 * 循环链表(circular linked list) 循环链表是表中最后一个结点的指针指向头结点,使链表构成环状 特点:从表中任一结点出发均可找 ...

  5. 数据结构和算法:(3)3.2线性表的链式存储结构

    线性表的链式存储结构的特点是用一组任意的存储单元存储线性表的数据元素也就是说你这个可以放在A地点,这个可以放在E地点,A地点和E地点中间可以隔开一个C地点和D地点,这样是允许的),这组存储单元可以存在 ...

  6. 链表list(链式存储结构实现)_5 线性表的链式存储结构

    系列文章参考资料为<大话数据结构>,源码为个人私有,未经允许不得转载 线性表的链式存储结构的特点是用一组任意的存储单元存储线性表的数据元素,可以使连续的,也可以不连续,也就意味这些元素可以 ...

  7. 线性表的链式表示——单链表

    单链表 定义 线性表的链式存储又称单链表,它是指通过一组任意的存储单元来存储线性表中的数据元素.每个链表的结点,除存放元素自身的信息之外,还需要存放一个指向其后继结点的指针.即单链表的结构分为两部分, ...

  8. c:线性表的链式表示

    和顺序表相比,链式存储结构在实现插入,删除的操作时,不需要移动大量数据元素.但不利于对第i个数据元素的操作. 线性表的单链表存储结构. struct LNode{ ElemType data; LNo ...

  9. 五、【线性表】线性表的链式表示和实现

    线性表的链式表示和实现 上节提到,由于顺序表的特点是逻辑关系上相邻的两个元素在物理位置上也相邻,因此可以随机存取表中任一元素.然而,这也导致了顺序表在执行插入或删除操作时,需要移动大量元素.本节来讨论 ...

最新文章

  1. Android WiFi开发教程(三)——WiFi热点数据传输
  2. L-SNET:从区域定位到尺度不变的医学图像分割
  3. Java局部变量final
  4. 难解?SAP云平台集成前路何方?
  5. Web框架之Django_01初识(三大主流web框架、Django安装、Django项目创建方式及其相关配置、Django基础三件套:HttpResponse、render、redirect)
  6. 设计桑基图_教你用pyecharts制作交互式桑基图,赶快学起来吧!
  7. 概述类的加载器及类加载过程
  8. PHP正则匹配到2个字符串之间的内容,匹配HTML便签内容
  9. java设计模式----代理模式
  10. 管理系统项目-简历描述篇
  11. json文件简介及借助于python解析json文件
  12. 2k 幻14_ROG幻14经典版2K屏14寸
  13. 淘宝补单怎么补才有效果?
  14. Mysql- --DQl语句(select数据查询语言,多表查询,View试图)linux常用(重点)
  15. 使用花生壳配置内网穿透
  16. Flutter 调用百度地图APP实现位置搜索、路线规划
  17. c#split方法拆分为数据_C# 根据分隔符拆分Excel单元格数据
  18. 个人文件转移工具 v1.9.0.2107 系统目录迁移工具
  19. centos怎么卸载mysql
  20. 神经网络的简介和特点,神经网络的简介和应用

热门文章

  1. 数据结构——哈夫曼树
  2. 65536 65535 65534
  3. fps透视基础-3分钟快速定位矩阵基址-附3D坐标转屏幕坐标算法
  4. Solaris下网卡绑定多个IP
  5. 鸿蒙车载智慧屏评测,荣耀智慧屏体验评测:鸿蒙系统的智慧
  6. 小米android通知栏图标不显示,MIUI开发版更新:已修复原生样式下部分通知图标不显示的问题...
  7. 微信小店不同类型店铺区别,以及开通资质要求是什么丨国仁网络资讯
  8. STM32在线烧录程序的开发
  9. 全国计算机信息高新技术和全国计算机等级考试区别
  10. 直播电商平台开发,点击让窗口抖动动画效果