数据结构广义表
数据结构第五章 数组与广义表

压缩存储方法:只需要存储下三角 (含对角线)上的元素。可节省一 半空间。
可以使用一维数组Sa[n(n+1)/2]作为n阶对称矩阵A的存 储结构,且约定以行序为主序存储各个元素,则在Sa[k]和矩
阵元素aij之间存在一一对应关系: (下标变换公式)
i(i+1)/2 + j 当i≥j k = j(j+1)/2 + i 当i<j
q = cpot[col];
T.data[q].i = M.data[p].j; T.data[q].j = M.data[p].i; T.data[q].e = M.data[p].e; ++cpot[col]; }
分析算法FastTransposeSMatrix的时间 复杂度:
for (col=1; col<=M.nu; ++col) … … for (t=1; t<=M.tu; ++t) … … for (col=2; col<=M.nu; ++col) … … for (p=1; p<=M.tu; ++p) … …
//对当前行中每一个非零元
处
brow=M.data[p].j;
理
if (brow < N.nu ) t = N.rpos[brow+1];
M
else { t = N.tu+1 }
的
for (q=N.rpos[brow]; q< t; ++q) { ccol = N.data[q].j; // 乘积元素在Q中列号
一、三元组顺序表
对于稀疏矩阵,非零元可以用三元组表示, 整个稀疏矩阵可以表示为所有非零元的三元组所 构成的线性表。例如:
数据结构-广义线性表广义表

清华大学出版社
数据结构( 数据结构(C++版) 版
广义线性表——广义表 广义线性表——广义表 ——
广义表的示例 AБайду номын сангаас=( ) B =(e) C =(a, (b,c,d)) , , D =(A, B, C) E =(a, E) F =(( ))
长度?深度?表头?表尾? 长度?深度?表头?表尾?
清华大学出版社
数据结构( 数据结构(C++版) 版
广 义 表 类 的 声 明
清华大学出版社
广义线性表——广义表 广义线性表——广义表 ——
数据结构( 数据结构(C++版) 版
广义表的操作——建立广义表 建立广义表 广义表的操作 template <class T> Lists::Lists(Lists ls1,Lists ls2) { ls = new GLNode ls->tag = 1; ls->ptr.hp = ls1; ls->ptr.tp = ls2; }
∧
C
1 0 a
1 1 0 b
1 0 c
1
∧
0 d
清华大学出版社
广义线性表——广义表 广义线性表——广义表 ——
《数据结构与算法》第五章-数组和广义表学习指导材料

《数据结构与算法》第五章数组和广义表本章介绍的数组与广义表可视为线性表的推广,其特点是数据元素仍然是一个表。
本章讨论多维数组的逻辑结构和存储结构、特殊矩阵、矩阵的压缩存储、广义表的逻辑结构和存储结构等。
5.1 多维数组5.1.1 数组的逻辑结构数组是我们很熟悉的一种数据结构,它可以看作线性表的推广。
数组作为一种数据结构其特点是结构中的元素本身可以是具有某种结构的数据,但属于同一数据类型,比如:一维数组可以看作一个线性表,二维数组可以看作“数据元素是一维数组”的一维数组,三维数组可以看作“数据元素是二维数组”的一维数组,依此类推。
图5.1是一个m行n列的二维数组。
5.1.2 数组的内存映象现在来讨论数组在计算机中的存储表示。
通常,数组在内存被映象为向量,即用向量作为数组的一种存储结构,这是因为内存的地址空间是一维的,数组的行列固定后,通过一个映象函数,则可根据数组元素的下标得到它的存储地址。
对于一维数组按下标顺序分配即可。
对多维数组分配时,要把它的元素映象存储在一维存储器中,一般有两种存储方式:一是以行为主序(或先行后列)的顺序存放,如BASIC、PASCAL、COBOL、C等程序设计语言中用的是以行为主的顺序分配,即一行分配完了接着分配下一行。
另一种是以列为主序(先列后行)的顺序存放,如FORTRAN语言中,用的是以列为主序的分配顺序,即一列一列地分配。
以行为主序的分配规律是:最右边的下标先变化,即最右下标从小到大,循环一遍后,右边第二个下标再变,…,从右向左,最后是左下标。
以列为主序分配的规律恰好相反:最左边的下标先变化,即最左下标从小到大,循环一遍后,左边第二个下标再变,…,从左向右,最后是右下标。
例如一个2×3二维数组,逻辑结构可以用图5.2表示。
以行为主序的内存映象如图5.3(a)所示。
分配顺序为:a11 ,a12 ,a13 ,a21 ,a22,a23 ; 以列为主序的分配顺序为:a11 ,a21 ,a12 ,a22,a13 ,a23 ; 它的内存映象如图5.3(b)所示。
数据结构广义表

结点结构是无论什么结点都有三个域:
第一个域是结点类型标志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
^
数据结构广义表

数据结构广义表介绍广义表是一种扩展了线性表的数据结构,可以存储不仅仅是数据元素,还可以存储子表,从而形成多级结构。
在广义表中,元素可以是基本类型(如整数、字符等),也可以是广义表。
广义表由一组元素组成,每个元素可以是一个基本元素或者是一个子表。
广义表可以为空,称为空表。
广义表中的元素的个数称为广义表的长度。
广义表的表示广义表可以通过两种方式进行表示:括号表示和逗号表示。
1.括号表示:使用括号将广义表括起来,每个元素之间使用逗号分隔。
例如,(1,2,3)表示一个包含3个元素的广义表,分别为1、2和3。
2.逗号表示:用逗号将广义表的元素分隔开,如果元素是基本元素,则直接写在逗号之间,如果元素是子表,则将子表表示为广义表的形式。
例如,1,2,3表示一个包含3个元素的广义表,分别为1、2和3。
广义表的操作广义表支持多种操作,包括获取广义表的长度、判断广义表是否为空、获取广义表的头、获取广义表的尾、判断两个广义表是否相等、复制广义表等。
获取广义表的长度获取广义表的长度即求广义表中元素的个数。
可以使用递归的方式来实现这个操作。
如果广义表为空,则长度为0;否则,长度等于广义表头的长度加上广义表尾的长度。
判断广义表是否为空判断广义表是否为空即判断广义表中是否没有元素。
如果广义表长度为0,则为空;否则,不为空。
获取广义表的头获取广义表的头即获取广义表中第一个元素。
如果广义表为空,则没有头;否则,头等于广义表中的第一个元素。
获取广义表的尾获取广义表的尾即获取广义表中除了第一个元素以外的所有元素。
如果广义表为空,则没有尾;否则,尾等于广义表中除了第一个元素以外的所有元素所组成的广义表。
判断两个广义表是否相等判断两个广义表是否相等即判断两个广义表中的元素是否完全相同。
如果两个广义表都为空,则相等;如果两个广义表的长度不相等,则不相等;否则,判断广义表的头是否相等,如果相等则判断广义表的尾是否相等。
复制广义表复制广义表即创建一个与原广义表相同的新广义表。
《数据结构(Python语言描述)》第5章 广义表

广义表是由n个类型相同的数据元素(a1、a2、……、an)组成的有限序列。广义表的元素可以是单个 元素,也可以是一个广义表。通常广义表记作:
GL=(a1,a2,…,an) 广义表有两种数据元素,分别是原子和子表,因此需要两种结构的节点,一种是表节点,用来表 示子表,如图5-1所示;一种是原子节点,用来表示原子,如图5-2所示。
OPTION
在广义表GL中,如果ai也是一个 广义表表,则称ai为广义表GL的 子表。
03 表头
OPTION
在广义表中GL中,a1如果不为空, 则称a1为广义表的表头。
04 表尾
OPTION
在广义表GL中,除了表头a1的其余 元素组成的表称为表尾。
05 深度
OPTION
广义表GL中括号嵌套的最大层数。
图5-3 广义表表节点
表节点由三个域组成:标志域tag,指向表头节点的指针域ph,指向表尾节 点的指针域pt。表节点的标志域tag=1。
5.3 存储结构
7
图5-4 广义表原子节点
原子节点由两个域组成:标志域tag,值域atom。原子节点的标志域tag=0。
节点的定义:
class Node:
def __init__(self, ph, pt, tag, atom):
表节点由三个域组成,即标志域tag、指向表头节点的指针域ph、指向表尾节点的指针域pt。表节点 的标志域tag=1。
原子节点由两个域组成,即标志域tag、值域atom。原子节点的标志域tag=0。
5.2 基本用语
4
01 原子
OPTION
在广义表GL中,如果ai为单个元 素,则称ai称为原子
02 子表
数据结构广义表

{ printf("("); /*输出'('*/
if (g->val.sublist==NULL) printf(""); /*输出空子表*/
else DispGL(g->val.sublist); /*递归输出子表*/
}
else printf("%c", g->val.data); /*为原子时输出元素值*/
假如把每个表旳名字(若有旳话)写在其表旳前面,则 上面旳5个广义表可相应地体现如下:
A()
B(e)
C(a,(b,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(e),C(a,(b,c,d))) E((a,(a,b),((a,b),c)))
AB e
C A
a b cd
D BC
ea b cd
E
a
ab
c
ab
8.2 广义表旳存储构造
广义表是一种递归旳数据构造,所以极 难为每个广义表分配固定大小旳存储空间,所
GLNode *CreatGL(char *&s)
{ GLNode *h;char ch=*s++; /*取一种扫描字符*/
if (ch!='\0')
/*串未结束判断*/
{ h=(GLNode *)malloc(sizeof(GLNode));/*创建新结点*/
数据结构第06章广义表

第6章广义表z6.1 广义表的基本概念z6.2 广义表的存储结构z6.3 广义表的操作算法16.1 广义表的基本概念广义表(列表)的概念-n( ≥0 )个表元素组成的有限序列,记作LS= ( a1, a1, a2, …, a n)LS是表名,a i是表元素,它可以是单个元素(称为原子) ,可以是表(称为子表) 。
n为表的长度。
n= 0 的广义表为空表。
n> 0时,表的第一个表元素称为广义表的表头(head),除此之外,其它表元素组成的表称为广义表的表尾(tail)。
2广义表举例:(1)A=()(2)B=(e)(3)C=(a, (b, c, d) )(4)D=(A,B,C)(5)E= (a , E)9任意一个非空广义表,均可分解为表头和表尾。
9对于一个非空广义表,其表头可能是原子,也可能是子表;而表尾一定是子表。
3广义表的基本操作:•结构的创建和销毁InitGList(&L); DestroyGList(&L); CreateGList(&L, S); CopyGList(&T, L);•状态函数GListLength(L); GListDepth(L);GListEmpty(L); GetHead(L); GetTail(L);•插入和删除操作InsertFirst_GL(&L, e);DeleteFirst_GL(&L, &e);•遍历Traverse_GL(L, Visit());66. 2 广义表的存储结构z由于广义表中的元素不是同一类型,因此难以用顺序结构表示,通常采用链接存储方法存储广义表,并称之为广义链表。
z由于广义表中有两种数据元素,原子或子表,因此,需要两种结构的结点:一种是表结点,一种是原子结点。
z下面介绍一种广义表的链式存储结构。
78扩展的线性链表表示法:-子表结点由三个域组成:标志域、表头指针域和指向下一个元素的指针域;-原子结点的三个域为:标志域、值域和指向下一个元素的指针域。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
/*遇到')'字符,子表为空*/
/*新结点作为原子结点*/
/*串结束,子表为空*/ /*取下一个扫描字符*/ /*串未结束判断*/ /*当前字符为','*/ /*递归构造后续子表*/ /*串结束*/ /*处理表的最后一个元素*/ /*返回广义表指针*/
4. 输出广义表 以h作为带表头附加结点的广义表的表头指针,打印输
广义表的两种基本情况 :
g2 1
∧
g1
1
∧
∧
*
*
*
*
…
*
*
∧
第 1 个元素
第 2 个元素
第 n 个元素
( a) 空 表
( b) 非 空 表
为原子的情况 :
g3 0 a
∧
8.3
1. 求广义表的长度
广义表的运算
在广义表中,同一层次的每个结点是通过link域链
接起来的,所以可把它看做是由link域链接起来的单
A()
B(e)
C(a,(b,c,d))
D(A(),B(e),C(a,(b,c,d)))
E((a,(a,b),((a,b),c)))
A
B
C A a b c d
D B C a b c d a
E
e
e
a
b a b
c
8.2
广义表的存储结构
广义表是一种递归的数据结构,因此很难为每个 广义表分配固定大小的存储空间,所以其存储结构只 好采用动态链式结构。 我们将一个广义表看成一棵树,为了方便存储,将 其转换成一棵二叉树。其转换过程已在第6章中介绍 过,这里以示例中的广义表C说明其转换过程。如下 图所示,左边的图表示转换的中间状态,右边的图表示 转换的最终状态,即一棵二叉树。从二叉树中看到,有 两类结点,一类为圆圈结点,在这里对应子表;另一类 为方形结点,在这里对应原子。
while (g!=NULL)
{ n++; g=g->link;
}
return n; }
2. 求广义表的深度 对于带头结点的广义表g,广义表深度的递归定义 是它等于所有子表中表的最大深度加1。若g为原子, 其深度为0。 求广义表深度的递归模型f()如下:
0 若g为原子 若g为空表 其他情况,subg为g的子表
3. 建立广义表的链式存储结构
假定广义表中的元素类型ElemType为char类型,每
个原子的值被限定为英文字母。
并假定广义表是一个表达式,其格式为:元素之间用
一个逗号分隔,表元素的起止符号分别为左、右圆括号,
空表在其圆括号内不包含任何字符。例如“(a,(b,c,d))”
就是一个符合上述规定的广义表格式。
h->val.sublist=CreatGL(s); /*递归构造子表并链到表头结点*/ }
else if (ch==')') h=NULL; else { h->tag=0; h->val.data=ch; } } else h=NULL; ch=*s++; if (h!=NULL) if (ch==',') h->link=CreatGL(s); else h->link=NULL; return h; }
如果把每个表的名字(若有的话)写在其表的前面,则 上面的5个广义表可相应地表示如下:
A()
B(e)
C(a,(b,c,d))
D(A(),B(e),C(a,(b,c,d)))
E((a,(a,b),((a,b),c)))
若用圆圈和方框分别表示表和单元素,并用线段把表 和它的元素(元素结点应在其表结点的下方)连接起来,则 可得到一个广义表的图形表示。例如,上面五个广义表 的图形表示如下图所示。
生成广义表链式存储结构的算法如下:
GLNode *CreatGL(char *&s) { GLNode *h;char ch=*s++; /*取一个扫描字符*/
if (ch!='\0')
{
/*串未结束判断*/
h=(GLNode *)malloc(sizeof(GLNode));/*创建新结点*/ if (ch=='(') { h->tag=1; /*当前字符为左括号时*/ /*新结点作为表头结点*/
本章小结 本章的基本学习要点如下: (1)掌握广义表的定义。 (2)重点掌握广义表的链式存储结构。 (3)掌握广义表的基本运算,包括创建广义表、输出 广义表、求广义表的长度和深度。
(4)灵活运用广义表这种数据结构解决一些综合应 用问题。
练习
教材中p182习题1和2。
链表。这样,求广义表的长度就是求单链表的长度,可
以采用以前介绍过的求单链表长度的方法求其长度。
求广义表长度的非递归算法如下:
int GLLength(GLNode *g) /*g为一个广义表头结点的指针*/ { int n=0; g=g->val.sublist; /*g指向广义表的第一个元素*/
C
C
a
a
b
1
∧
c
d
b
c
d
C
0
a
1
∧
0
b
0
c
0
d
∧
广义表的存储结构
typedef struct lnode { int tag; union { ElemType data; /*结点类型标识*/
struct lnode *sublist;
} val; struct lnode *link; } GLNode; /*指向下一个元素*/ /*广义表结点类型定义*/
广义表具有如下重要的特性: (1)广义表中的数据元素有相对次序; (2)广义表的长度定义为最外层包含元素个数; (3)广义表的深度定义为所含括弧的重数。其中,原 子的深度为0,空表的深度为1; (4)广义表可以共享;一个广义表可以为其他广义 表共享;这种共享广义表称为再入表; (5)广义表可以是一个递归的表。一个广义表可以 是自已的子表。这种广义表称为递归表。递归表的 深度是无穷值,长度是有限值; (6)任何一个非空广义表GL均可分解为表头 head(GL) = a1和表尾tail(GL) = ( a2,…,an) 两部分。
第8章
8.1 8.2 8.3
广义表
广义表的定义 广义表的存储结构 广义表的运算
本章小结
8.1
广义表的定义
广义表简称表,它是线性表的推广。一个广义 表是n(n≥0)个元素的一个序列,若n=0时则称为空 表。设ai为广义表的第i个元素,则广义表GL的一 般表示与线性表相同:
GL=(a1,a2,…,ai,…,an) 其中n表示广义表的长度,即广义表中所含元 素的个数,n≥0。如果ai是单个数据元素,则ai是广 义表GL的原子;如果ai是一个广义表,则ai是广义 表GL的子表。
为了简单起见,下面讨论的广义表不包括前面定 义的再入表和递归表,即只讨论一般的广义表。另 外,我们规定用小写字母表示原子,用大写字母表示 广义表的表名。例如: A=()
B=(e)
C=(a,(b,c,d))
D=(A,B,C)=((),(e),(a,(b,c,d)))
E=((a,(a,b),((a,b),c)))
出该广义表时,需要对子表进行递归调用。输出一个广义
表的算法如下:
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); /*递归输出后续表的内容*/ } } }
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); /*递归调用求出子表的深度*/ if (dep>max) max=dep; /*max为同一层所求过的子表中深度的最大值*/ } g=g->link; /*使g指向下一个元素*/ } return(max+1); /*返回表的深度*/ }