广义表的定义(精)
合集下载
3.4 广义表

((b,c,d)) C → 1 a 0 a 1
((b,c,d)) C → 1 a 0 a 1 (b,c,d)
((b,c,d)) C → 1 a 0 a 1 () (b,c,d)
((b,c,d)) C → 1 a 0 a 1 ^ () (b,c,d)
((b,c,d)) C → 1 a 0 a 1 1 ^ () (b,c,d)
3.4.2 广义表的存储结构
1. 头尾表示法
表结点 tag=1 hp tp
指向表尾的指针
原子结点 tag=0 data
指向表头的指针
class GLNode{ private: int tag; tag=0 data union { ptr tag=1 DataType data; hp tp struct { GLNode *hp,*tp; }ptr; }; };//GLNode
2. 孩子兄弟表示法 有孩子结点 tag=1 hp tp
指向第一个孩子的指针 指向兄弟的指针
无孩子结点 tag=0 data tp
class GLNode{ private: int tag; union { DataType data; GLNode *hp; }; GLNode * tp; };//GLNode
例1
参赛队清单的表示。 参赛队清单的表示。
参赛队清单=(俄罗斯,巴西,东道主,古巴,美国,韩国,日本 参赛队清单 俄罗斯,巴西,东道主,古巴,美国,韩国,日本) 俄罗斯 东道主= 国家队 香港队,澳门队) 国家队, 东道主 (国家队,香港队,澳门队 韩国= 韩国 ( ) (俄罗斯,巴西,(国家队,香港队,澳门队 ,古巴,美国,( ),日本 俄罗斯,巴西, 国家队 香港队,澳门队),古巴,美国, ,日本) 国家队, 俄罗斯
广义表

一、基本概念 广义表是线性表的推广。线性表中的元素仅限于原子项 单 广义表是线性表的推广。线性表中的元素仅限于原子项(单 原子项 个数据元素),即不可以再分,而广义表中的元素既可以是 个数据元素 ,即不可以再分,而广义表中的元素既可以是 原子项,也可以是子表(另一个线性表 另一个线性表)。 如果 如果a 原子项,也可以是子表 另一个线性表 。 (如果 i是单个数 据元素,则称 则称a 据元素 则称 i为广义表的原子 ) 1.广义表的定义 . 广义表是n≥0个元素a …, 的有限序列, 广义表是 n≥0个元素a0, a1, …,an-1的有限序列, 其中每一 个元素 个 ai 或 者 是 原 子 , 或 者 是 一 个 子 表 。 广 义 表 通 常 记 为 GL=(a0,a1,…,an-1), 其中 为广义表的名字, 为广义表的 , 其中GL为广义表的名字 , n为广义表的 为广义表的名字 长度, 每一个a 为广义表的元素。但在习惯中, 长度, 每一个 i为广义表的元素。但在习惯中,一般用大写 字母表示广义表 小写字母表示原子。 表示广义表, 字母表示原子 字母表示广义表,小写字母表示原子。 称第一个元素a 为广义表GL的表头,其余部分 其余部分(a 称第一个元素 0为广义表 的表头 其余部分 1,...an-1)为GL 为 表尾,分别记作 的表尾 分别记作 head(GL)= a0 和 tail(GL)= (a1,...an-1)
tag=1
hp
tp
tag=0
atom
语言描述结点的类型如下: 用C语言描述结点的类型如下: 语言描述结点的类型如下 Typedef enum{Atom, LIST } Elemtag; typedef struct node { Elemtag tag; union{ AtomType atom; struct{struct node *hp,*tp;} ptr; }; }*GList;
第三章广义表

void Creat(GLNode *&GL) 输入:(#),a,((b,c),d); 输入: { char ch; 1: cin>>ch; Creat(GL) Creat(GL-> sublist) sublist 2:if(ch==‘#’) GL=NULL; 1:ch=‘(’ 1:ch=‘#’ 3:else if( ch==‘(‘) { if( 2,3, 4, 2:GL=^ 4:GL=new GLNode; GL->tag=true; GL5: ① 8:ch=‘)’ 5:Creat(GL5:Creat(GL->sublist);// ① } else { 8: ch=‘,’ 9: Creat(GL-> next next) 6: GL=new GLNode; GL->tag=false; GL9: 1:ch=‘a’ 7: GL->data=ch; } GL10: ② 8: cin>>ch; 2,3,6,7, 9:if(GL==NULL) 9:if(GL==NULL) ; 8:ch=‘,’ 10:else if(ch==‘,’) Creat(GL->next);//② if(ch==‘,’) Creat(GL->next);//② 10: ② 11: else if((ch==‘)’)||(ch==‘;’)) GL->next=NULL; GL0 a } 1 ^
1:max=0 2,3, ①
4:dep=1 5:max=1 6:GL=70 2,3,6:GL=^
7:return 2
3、建立广义表 如:(a,(#),b,c,(d,(e))); 建立广义表时,字符的情况: 建立广义表时,字符的情况: (1)当碰到左括号时 表明它是一个表元素的开始, (1)当碰到左括号时,表明它是一个表元素的开始,则应建立 一个由GL指向的表结点 并用它的sublist域作为子表的 指向的表结点, 一个由GL指向的表结点,并用它的sublist域作为子表的 表头指针进行递归调用,来建立子表的存储结构; 表头指针进行递归调用,来建立子表的存储结构; (2)当碰到一个英文字母时 表明它是一个单元素, (2)当碰到一个英文字母时,表明它是一个单元素,则应建立 一个由GL指向的单元素结点 指向的单元素结点; 一个由GL指向的单元素结点; (3)当碰到一个“#”字符 (3)当碰到一个“#”字符时,表明它是一个空表,则应置GL 字符时 表明它是一个空表,则应置GL 为空。 为空。 (4) 当建立了一个由GL指向的结点后, 当建立了一个由GL指向的结点后, 指向的结点后 接着碰到逗号字符时 表明存在后继结点, ①接着碰到逗号字符时,表明存在后继结点,需要建立当前 结点的后继表, 结点的后继表, 碰到右括号或分号字符时,表明当前所处理的表已结束, ②当碰到右括号或分号字符时,表明当前所处理的表已结束, 应置当前结点的next为空 为空。 应置当前结点的next为空。
数据结构 第5章广义表

if(i<n){ hstr=str.substr(1,i-2); str="("+str.substr(i,n-i); } else{ hstr=str.substr(1,n-2); str=""; } return hstr; }
何谓"递归函数 ? 何谓 递归函数"? 递归函数
一个含直接或间接调用本函数语句的函数被 称之为递归函数,它必须满足以下两个条件: 称之为递归函数,它必须满足以下两个条件: 在每一次调用自己时,必须是(在某种意义 ①在每一次调用自己时,必须是 在某种意义 更接近于解; 上)更接近于解; 更接近于解 函数中必须有一个终止处理或计算的准则。 ②函数中必须有一个终止处理或计算的准则。
的存储结构。 例:广义表 L=(a,(x,y),((z))) 的存储结构。
可由对L进行表头和表尾的分析得到 若列表不空 可由对 进行表头和表尾的分析得到--若列表不空, 进行表头和表尾的分析得到 若列表不空, 则可分解成表头和表尾(采用头尾链表存储结构)。 则可分解成表头和表尾(采用头尾链表存储结构)。 分析: 分析: ①L为一非空列表 为一非空列表
// 将非空串 分割成两部分: 将非空串str分割成两部分 分割成两部分: // hsub为最外层第一个 之前的子串,str为之后的子串 为最外层第一个','之前的子串 为最外层第一个 之前的子串, 为之后的子串 string sever(string& str) { int n,k,i; // k记录尚未配对的左括号个数 记录尚未配对的左括号个数 string ch,hstr; n=str.length(); for(i=0,k=-1; i<n&&(ch!=","||k!=0); ++i) { // 搜索最外层的第一个逗号 ch=str.substr(i,1); //从第 个位置起,取1个字符 从第i个位置起 从第 个位置起, 个字符 if(ch=="(") ++k; else if(ch==")") --k; }
数据结构广义表

结点结构是无论什么结点都有三个域:
第一个域是结点类型标志tag; 第二个域是指向一个列表的指针(当tag=1时) 或一个原子(当tag=0时); 第三个域是指向下一个结点的指针tp。
3 广义表的存储结构
形式描述为:
typedef enum{ ATOM, LIST }ElemTag typedef struct GLNode { //定义广义表结点 ElemTage tag; //公共部分,用以区分 原子结点和表结点 Unin{ //原子结点和表结点的联合部分 AtomType atom;//原子类型结点域, // AtomType由用户定义 struct GLNode *hp,; //表结点的表头指针域 }; struct GLNode *tp; //指向下一个结点的指针 }*Glist; //广义表类型
5. E=(a,E)
这是一个递归列表,其元素中有自己。
广义表也可以用图形表示,例如前述的广义表D和E可表示为:
广义表D
D
广义表E
E
C
A
B
a
e
a b c d
2 广义表的基本运算
广义表的基本运算 ⑴ 取表头 HEAD(LS); ⑵ 取表尾 TAIL(LS)。
3 广义表的存储结构
广义表中的数据元素可以是单元素,或是广义表, •很难用顺序存储结构表示,常采用链式存储结构。 1.表头表尾链存储结构 有两类结点:表结点和单元素结点。
P 1 3 1 1
A=y((c,3),(D,2)) C=x((1,10),(2,6))
^
1 2
A
z y 1 1 1 3
C
x 0 0 15 ^
B
1 2
1 2
^
数据结构(广义表)

3 广义表的存储结构
形式描述为: 形式描述为:
typedef enum{ ATOM, LIST }ElemTag typedef struct GLNode { //定义广义表结点 ElemTage tag; //公共部分,用以区分 原子结点和表结点 //原子结点和表结点的联合部分 Union{ atom;//原子类型结点域, AtomType atom; // AtomType AtomType由用户定义 Struct { struct GLNode *hp, *tp; }ptr; }; //表结点的指针域, //ptr.hp 与ptr.tp ptr.tp分别指向广义表的表头和表尾。 ptr.hp ptr.tp }*Glist; }*Glist; //广义表类型
应用: 元多项式的表示 应用:M元多项式的表示
对任何一个M元多项式P,先确定一个主变元,于是它可看成 对任何一个M元多项式P 先确定一个主变元, 主变元的一元多项式,但它的系数可能是一个多项式, 主变元的一元多项式,但它的系数可能是一个多项式,也可能是 一个常数。于是P 一个常数。于是P可表为一个线性表 ),…,( P=((α1 , expn1),(α2 ,expn2), ,( αn ,expnn)) 其中每个α 可能是一个常数,也可能又是一个多项式; 其中每个αi可能是一个常数,也可能又是一个多项式;对于每一 个多项式α 又可以确定一个主变元( 个多项式αj ,又可以确定一个主变元(可称为原多项式的第二变 ),从而 可表为下一级的一元多项式, 从而, 元),从而,可表为下一级的一元多项式,其系数又可能性是常 也可能是多项式; ;直到最后纯粹的一元多项式。 数,也可能是多项式;…;直到最后纯粹的一元多项式。 所以M元多项式,最好用广义表来表示。其元素结点如下图: 所以M元多项式,最好用广义表来表示。其元素结点如下图:
第4章数组与串第4节广义表

// 为原子时输出元素值
if (p->tag==1) cout << ")";
// 为表结点时输出')&)
{ cout << ",";
GLDisp (p->link);
// 递归输出后续表的内容
}
}
}
第4章 数组与串 第4节 广义表
3. 求广义表的长度 所谓广义表的长度是指在广义表中元素个
//p指向广义表的第一个元素
while (p!=NULL)
{ n++;
p=p->link;
}
return n;
}
第4章 数组与串 第4节 广义表
4.广义表的复制 复制一个广义表的算法思想:对于一个广义
表的头结点*p,若为空,则返回空指针;若为子 表,则递归复制子表;否则复制原子结点,然后 递归复制后续表。算法结束返回广义表链表指针。
用字符串变量 s 来表示一个广义表的括号表 达式,从头到尾扫描 s 的每一个符号:
(1)当遇到是左括号,说明是一个表的开始, 则建立一个由 h 指向的表的结点,并用它的dlink 域作为子表的表头指针,进行递归调用;
第4章 数组与串 第4节 广义表
(2)当扫描到一个字母,说明它是一个原子, 则建立一个由h指向的原子结点;
数,由于广义表在同一层次的每个结点是通过 link域链接起来的,所以可把它看做是由link域链 接起来的单链表。这样,求广义表的长度就变成 求单链表的长度了。
第4章 数组与串 第4节 广义表
int GLLength(GLNode *p)
//p为广义表附加头结点的指针
{
int n=0;
广义表

Union 结点的联合部分*/
/*表结点和原子
{ ElemType data; 点的数据域*/
/*data是原子结
struct
{ struct GLNode *hp,*tp; /*hp和tp分别指向表头和表尾*/
} ptr
}
} GList;
/*广义表类型*/
上一页 下一页 返回
6.2 广义表的存储结构
下一页 返回
6.2 广义表的存储结构
6.2.1 头尾表示法 若广义表不空,则可分解称表头和表尾;反之,一对确定的表头和表尾
可唯一地确定一个广义表。头尾表示法就是根据这一性质设计而成的一 种存储方式。图6-2 头尾表示法的结点形式 广义表的表尾一定还是广义表,但表头可能是表也可能是单元素(原 子)。在头尾表示法中,如果只使用一种表头结点,同样会遇到存储空 间浪费的问题。因此,表中应该有两类结点:表结点和单元素(原子) 结点,如图6-2所示。表结点包括3个域:标志个域:标志域和数据域。如果 标志域tag=1,则表示该结点为表结点。 如果标志域tag=0,则表示该结点为原子结点。
上一页
返回
6.2 广义表的存储结构
广义表的存储一般采用链式存储结构,这是因为广义表中的数据元素可 以是原子也可以是广义表,各元素类型不同,占用的存储空间大小相差 很大,如果采用顺序存储结构表示会造成很大的空间浪费,操作也不方 便。在链式存储方式下,每个表元素,不论是原子或是表,都可用一个 结点表示,不同的结点其存储空间大小不同。按结点形式的不同,广义 表的链式存储结构又可以分为两种存储方式。一种称为头尾表示法,另 一种称为孩子兄弟表示法。
上一页 下一页 返回
6.1 广义表的定义及基本操作
称表的第一个元素a1,为广义表GL的表头,其余部分(a2,…,ai,…,an)为 GL的表尾,分别记作head(GL)=a1和tail=(a2,…,ai,…,an)。显然,表头 可能是单元素也可能是广义表,表尾却一定是广义表,空表无表头表尾。 仍取上面示例:
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
0 若g为原子 若g为空表 其他情况,subg为g的子表
f(g)=
1 MAX{f(subg)}+1
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); /*递归调用求出子表的深度 */ /*max为同一层所求过的子表中深度的最大值*/ if (dep>max) max=dep; } g=g->link; /*使g指向下一个元素*/ } return(max+1); /*返回表的深度*/ }
C a b c d
C a b c d
广义表的存储结构
广义表的情况 :
g2 1
∧
g1
1
∧
∧
*
*
*
*
…
*
*
∧
第 1 个元素 (a)空表
第 2 个元素 (b)非空表
第 n 个元素
为原子的情况 :
g3 0 a
∧
typedef struct lnode { int tag; union { ElemType data; /*结点类型标识*/
A()
A B e a b c d C A e
B(e)
D B a b c d C
C(a,(b,c,d))
E
a a b a b c
D(A(),B(e),C(a,(b,c,d)))
E((a,(a,b),((a,b),c)))
8.2
广义表的存储结构
广义表是一种递归的数据结构 , 因此很难为每个 广义表分配固定大小的存储空间 ,所以其存储结构只 好采用动态链式结构。 有两类结点 ,一类为圆圈结点 ,在这里对应子表; 另一类为方形结点,在这里对应原子。
/*遇到')'字符,子表为空*/ /*新结点作为原子结点*/
/*串结束,子表为空*/ /*取下一个扫描字符*/ /*串指针后移一位*/ /*串未结束判断*/ /*当前字符为','*/ /*递归构造后续子表*/ /*串结束*/ /*处理表的最后一个元素*/ /*返回广义表指针*/
4. 输出广义表 以h作为带头结点的广义表的表头指针,打印输出 该广义表时,需要对子表进行递归调用。输出一个广 义表的算法如下:
如果把每个表的名字(若有的话)写在其表的前面, 则上面的5个广义表可相应地表示如下: A() B(e)
C(a,(Байду номын сангаас,c,d))
D(A(),B(e),C(a,(b,c,d)))
E((a,(a,b),((a,b),c)))
若用圆圈和方框分别表示表和单元素 ,并用线段把表 和它的元素 (元素结点应在其表结点的下方 )连接起来,则 可得到一个广义表的图形表示。例如,上面五个广义表的 图形表示如下图所示。
A=()
B=(e)
C=(a,(b,c,d))
D=(A,B,C)=((),(e),(a,(b,c,d))) E=((a,(a,b),((a,b),c))) F=(a,F)=(a,(a,(a,…)))
广义表具有如下重要的特性:
(1)广义表中的数据元素是有顺序的;
(2)广义表的长度定义为最外层包含元素个数;
3. 建立广义表的链式存储结构
假定广义表中的元素类型ElemType为char类型,每
个原子的值被限定为英文字母。
并假定广义表是一个表达式, 其格式为:元素之间用
一个逗号分隔, 表元素的起止符号分别为左、右圆括号, 空表在其圆括号内不包含任何字符。例如“(a,(b,c,d))” 就是一个符合上述规定的广义表格式。
if (ch=='(')
{ h->tag=1;
/*当前字符为左括号时*/
/*新结点作为表头结点*/
h->val.sublist=CreatGL(s); /*递归构造子表并链到表头结点*/ }
else if (ch==')') h=NULL; else { h->tag=0; h->val.data=ch; } } else h=NULL; ch=*s; s++; if (h!=NULL) if (ch==',') h->link=CreatGL(s); else h->link=NULL; return h; }
生成广义表链式存储结构的算法如下:
GLNode *CreatGL(char *&s)
{ GLNode *h;char ch; ch=*s; s++; if (ch!='\0') { /*取一个扫描字符*/
/*串指针后移一位*/ /*串未结束判断*/
h=(GLNode *)malloc(sizeof(GLNode));/*创建新结点*/
求广义表长度的非递归算法如下:
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()如下:
(3)广义表的深度定义为所含括弧的重数。其中,原 子的深度为0,空表的深度为1;
(4) 广义表可以共享;一个广义表可以为其他广义 表共享;这种共享广义表称为再入表; (5) 广义表可以是一个递归的表。一个广义表可以 是自已的子表。这种广义表称为递归表。 递归表的深度是无穷值,长度是有限值;
广义表具有如下重要的特性: (6) 任 何 一 个 非 空 广 义 表 GL 均 可 分 解 为 表 头 head(GL)和表尾tail(GL) 两部分。 表头是广义表的第一个元素: head(GL)= a1 表尾是广义表中除了表头之外的所有元素构成的 广义表 :tail(GL) = ( a2,…,an)
8.1
广义表的定义
广义表示一种递归定义的线性结构,广义表的 元素既可以是普通的数据元素,也可以是广义表。 对于GL=(a1,a2,…,ai,…,an)来说,如果ai是单个 数据元素,则ai是广义表GL的原子;如果ai是一个 广义表,则ai是广义表GL的子表。
我们规定用小写字母表示原子,用大写字母表示 广义表的表名。例如:
广义表的存储结构
广义表的两种存储结构: 1)子表分析法 2)表头、表尾分析法
本章小结
本章的基本学习要点如下:
(1)掌握广义表的定义。
(2)重点掌握广义表的链式存储结构。
(3)掌握广义表的基本运算 ,包括创建广义表、输出 广义表、求广义表的长度和深度。 (4)灵活运用广义表这种数据结构解决一些综合应 用问题。
练习
教材中p99习题1、2、3。
struct lnode *sublist;
} val; struct lnode *link; } GLNode; /*指向下一个元素*/ /*广义表结点类型定义*/
C a b
C 1
∧
C a c d b c d
0
a
1
∧
0
b
0
c
0
d
∧
广义表的存储结构
8.3
1. 求广义表的长度
广义表的运算
在广义表中 , 同一层次的每个结点是通过 link 域链 接起来的 , 所以可把它看做是由 link 域链接起来的单 链表。这样,求广义表的长度就是求单链表的长度,可 以采用以前介绍过的求单链表长度的方法求其长度。
第8章
8.1 8.2 8.3
广义表
广义表的定义 广义表的存储结构 广义表的运算
本章小结
8.1
广义表的定义
广义表简称表, 它是线性表的推广。一个广义 表是n(n≥0)个元素的一个序列: GL=(a1,a2,…,ai,…,an)
广义表的一般表示与线性表相同。
ai 为广义表的第 i 个元素, n 表示广义表的长 度 ,即广义表中所含元素的个数 ,n≥0。若 n=0时则 称为空表。
void DispGL(GLNode *g) /*g为一个广义表的头结点指针*/ { if (g!=NULL) /*表不为空判断*/ { if (g->tag==1) /*为表结点时*/ { printf("("); /*输出'('*/ if (g->val.sublist==NULL) printf(""); /*输出空子表*/ else DispGL(g->val.sublist); /*递归输出子表*/ printf(")"); /*为表结点时输出')'*/ } else printf("%c", g->val.data); /*为原子时输出元素值*/ if (g->link!=NULL) { printf(","); DispGL(g->link); /*递归输出后续表的内容*/ } } }
f(g)=
1 MAX{f(subg)}+1
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); /*递归调用求出子表的深度 */ /*max为同一层所求过的子表中深度的最大值*/ if (dep>max) max=dep; } g=g->link; /*使g指向下一个元素*/ } return(max+1); /*返回表的深度*/ }
C a b c d
C a b c d
广义表的存储结构
广义表的情况 :
g2 1
∧
g1
1
∧
∧
*
*
*
*
…
*
*
∧
第 1 个元素 (a)空表
第 2 个元素 (b)非空表
第 n 个元素
为原子的情况 :
g3 0 a
∧
typedef struct lnode { int tag; union { ElemType data; /*结点类型标识*/
A()
A B e a b c d C A e
B(e)
D B a b c d C
C(a,(b,c,d))
E
a a b a b c
D(A(),B(e),C(a,(b,c,d)))
E((a,(a,b),((a,b),c)))
8.2
广义表的存储结构
广义表是一种递归的数据结构 , 因此很难为每个 广义表分配固定大小的存储空间 ,所以其存储结构只 好采用动态链式结构。 有两类结点 ,一类为圆圈结点 ,在这里对应子表; 另一类为方形结点,在这里对应原子。
/*遇到')'字符,子表为空*/ /*新结点作为原子结点*/
/*串结束,子表为空*/ /*取下一个扫描字符*/ /*串指针后移一位*/ /*串未结束判断*/ /*当前字符为','*/ /*递归构造后续子表*/ /*串结束*/ /*处理表的最后一个元素*/ /*返回广义表指针*/
4. 输出广义表 以h作为带头结点的广义表的表头指针,打印输出 该广义表时,需要对子表进行递归调用。输出一个广 义表的算法如下:
如果把每个表的名字(若有的话)写在其表的前面, 则上面的5个广义表可相应地表示如下: A() B(e)
C(a,(Байду номын сангаас,c,d))
D(A(),B(e),C(a,(b,c,d)))
E((a,(a,b),((a,b),c)))
若用圆圈和方框分别表示表和单元素 ,并用线段把表 和它的元素 (元素结点应在其表结点的下方 )连接起来,则 可得到一个广义表的图形表示。例如,上面五个广义表的 图形表示如下图所示。
A=()
B=(e)
C=(a,(b,c,d))
D=(A,B,C)=((),(e),(a,(b,c,d))) E=((a,(a,b),((a,b),c))) F=(a,F)=(a,(a,(a,…)))
广义表具有如下重要的特性:
(1)广义表中的数据元素是有顺序的;
(2)广义表的长度定义为最外层包含元素个数;
3. 建立广义表的链式存储结构
假定广义表中的元素类型ElemType为char类型,每
个原子的值被限定为英文字母。
并假定广义表是一个表达式, 其格式为:元素之间用
一个逗号分隔, 表元素的起止符号分别为左、右圆括号, 空表在其圆括号内不包含任何字符。例如“(a,(b,c,d))” 就是一个符合上述规定的广义表格式。
if (ch=='(')
{ h->tag=1;
/*当前字符为左括号时*/
/*新结点作为表头结点*/
h->val.sublist=CreatGL(s); /*递归构造子表并链到表头结点*/ }
else if (ch==')') h=NULL; else { h->tag=0; h->val.data=ch; } } else h=NULL; ch=*s; s++; if (h!=NULL) if (ch==',') h->link=CreatGL(s); else h->link=NULL; return h; }
生成广义表链式存储结构的算法如下:
GLNode *CreatGL(char *&s)
{ GLNode *h;char ch; ch=*s; s++; if (ch!='\0') { /*取一个扫描字符*/
/*串指针后移一位*/ /*串未结束判断*/
h=(GLNode *)malloc(sizeof(GLNode));/*创建新结点*/
求广义表长度的非递归算法如下:
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()如下:
(3)广义表的深度定义为所含括弧的重数。其中,原 子的深度为0,空表的深度为1;
(4) 广义表可以共享;一个广义表可以为其他广义 表共享;这种共享广义表称为再入表; (5) 广义表可以是一个递归的表。一个广义表可以 是自已的子表。这种广义表称为递归表。 递归表的深度是无穷值,长度是有限值;
广义表具有如下重要的特性: (6) 任 何 一 个 非 空 广 义 表 GL 均 可 分 解 为 表 头 head(GL)和表尾tail(GL) 两部分。 表头是广义表的第一个元素: head(GL)= a1 表尾是广义表中除了表头之外的所有元素构成的 广义表 :tail(GL) = ( a2,…,an)
8.1
广义表的定义
广义表示一种递归定义的线性结构,广义表的 元素既可以是普通的数据元素,也可以是广义表。 对于GL=(a1,a2,…,ai,…,an)来说,如果ai是单个 数据元素,则ai是广义表GL的原子;如果ai是一个 广义表,则ai是广义表GL的子表。
我们规定用小写字母表示原子,用大写字母表示 广义表的表名。例如:
广义表的存储结构
广义表的两种存储结构: 1)子表分析法 2)表头、表尾分析法
本章小结
本章的基本学习要点如下:
(1)掌握广义表的定义。
(2)重点掌握广义表的链式存储结构。
(3)掌握广义表的基本运算 ,包括创建广义表、输出 广义表、求广义表的长度和深度。 (4)灵活运用广义表这种数据结构解决一些综合应 用问题。
练习
教材中p99习题1、2、3。
struct lnode *sublist;
} val; struct lnode *link; } GLNode; /*指向下一个元素*/ /*广义表结点类型定义*/
C a b
C 1
∧
C a c d b c d
0
a
1
∧
0
b
0
c
0
d
∧
广义表的存储结构
8.3
1. 求广义表的长度
广义表的运算
在广义表中 , 同一层次的每个结点是通过 link 域链 接起来的 , 所以可把它看做是由 link 域链接起来的单 链表。这样,求广义表的长度就是求单链表的长度,可 以采用以前介绍过的求单链表长度的方法求其长度。
第8章
8.1 8.2 8.3
广义表
广义表的定义 广义表的存储结构 广义表的运算
本章小结
8.1
广义表的定义
广义表简称表, 它是线性表的推广。一个广义 表是n(n≥0)个元素的一个序列: GL=(a1,a2,…,ai,…,an)
广义表的一般表示与线性表相同。
ai 为广义表的第 i 个元素, n 表示广义表的长 度 ,即广义表中所含元素的个数 ,n≥0。若 n=0时则 称为空表。
void DispGL(GLNode *g) /*g为一个广义表的头结点指针*/ { if (g!=NULL) /*表不为空判断*/ { if (g->tag==1) /*为表结点时*/ { printf("("); /*输出'('*/ if (g->val.sublist==NULL) printf(""); /*输出空子表*/ else DispGL(g->val.sublist); /*递归输出子表*/ printf(")"); /*为表结点时输出')'*/ } else printf("%c", g->val.data); /*为原子时输出元素值*/ if (g->link!=NULL) { printf(","); DispGL(g->link); /*递归输出后续表的内容*/ } } }