课件下载

Download Report

Transcript 课件下载

第四章 数组、串和广义表
学习要点:
 数组(二维数组)基本概念与存储方式,基于某些特殊矩阵
的典型算法。
 串的基本概念和基本操作,串的存储方式和典型算法。
 广义表基本概念和相关概念,广义表的存储与基本操作实现。
§4.1 数组
数组(array)表示n(n>1)个具有相
同数据类型的数据元素的有序集合。
4.1.1二维数组
 数组中数据元素由一个数据值和一个(组)下标确定。下
标是数组中元素相互区分的标识。使用一个下标区分其中
元素的数组称为一维数组。使用两个以上下标的数组称为
多维数组。常用的多维数组是二维数组,通常称为矩阵。
 A3*4的阵列形式表示:
a 00
a
 10
a 20
a 01
a 02
a11
a 21
a12
a 22
a 03 
a13 
a 23 
4.1.2 矩阵的顺序表示与实现
 行序优先存储:
a00 a01 a02 a03 a10 a11 a12 a13 a20 a21 a22 a23
Loc(aij) = Loc(a00) +(i*n+j)* length
 列序优先存储:
a00 a10 a20 a01 a11 a21 a02 a12 a22 a03 a13 a23
Loc(aij) = Loc(a00) +(j*m+i)* length
4.1.3 特殊矩阵压缩存储
1.对称矩阵
 n阶方阵,沿主对角线对称位置上的元素相等,即aij=aji。
 主对角线:由元素aii组成的数列
如右图的对称矩阵按行序存储下三角
的元素,映射到一维数组中去,其对
应的一维数组下标如下图所示:
下标 k:
aij:
 a00
a
 10
a20

 a30
a01
a02
a11
a21
a12
a22
a31
a32
a03 
a13 
a23 

a33 
0
1
2
3
4
5
6
7
8
9
a00
a10
a11
a20
a21
a22
a30
a31
a32
a33
4.1.3 特殊矩阵压缩存储
1.对称矩阵2
 对称矩阵中任意元素与其对应的一维数组下标k的计算公式:
(i+1)*i/2+j
(i>=j)
k=
(j+1)*j/2+i
(i<j)
4.1.3 特殊矩阵压缩存储2
2.三角矩阵
 n阶方阵,沿主对角线以上的元素全为零。
 上三角矩阵、下三角矩阵
如右图为下三角矩阵。
按行序压缩存储下三角矩阵,映射到一维
数组中去,其对应的一维数组下标如下图
所示:
下标 k:
aij:
a 00
a
 10
a 20

 a30
0
0
a11
0
a 21
a 22
a31
a32
0
0 
0

a33 
0
1
2
3
4
5
6
7
8
9
a00
a10
a11
a20
a21
a22
a30
a31
a32
a33
4.1.3 特殊矩阵压缩存储2
2.三角矩阵2
 按行序压缩存储下三角矩阵,元素下标(i,j)与对应的一维数组下
标k映射公式为:
 k=(i+1)*i/2+j
(i>=j)
4.1.3 特殊矩阵压缩存储3
3.对角矩阵
 n阶方阵,沿主对角线上下若干对角线上有非零元素,其他全为零。
 带宽:主对角线上下各d条对角线上有非零元,则共有2d+1条对角线
有非零元,称为带宽。
a 00
a
如右图为3对角矩阵。
 10
按行序压缩存储3对角矩阵,映射到一维  0
数组中去,其对应的一维数组下标如下图  0

a 01
0
a11
a12
a 21
a 22
0
a32
0 
0 
a 23 

a33 
所示:
下标 k:
aij:
0
1
2
3
4
5
6
7
8
9
a00
a01
a10
a11
a12
a21
a22
a23
a32
a33
4.1.3 特殊矩阵压缩存储3
3.对角矩阵2
 按行序压缩存储三对角矩阵,元素下标(i,j)与对应的一维
数组下标k映射公式为:
 k=3*i-1+(j-i+1)=2*i+j
4.1.4 稀疏矩阵压缩存储
 稀疏矩阵是指矩阵中的非零元很少,大部分是零元素,且
非零元的分布没有规律。如下矩阵:
0
8

0

0
0
5
0
0
0
0
0
0
0
0
0 12 0
0 0 0
7
0 0
 9 0

0 0
4 0
0
4.1.4 稀疏矩阵压缩存储
1.三元组表表示法
 在存储稀疏矩阵中的非零元时,为了描述一个非零元素,需要
元素本身的值和行标、列标三方面的信息,这些信息的组合就
称为三元组。
row
col
value
下标
row
col
value
0
0
1
5
1
0
5
7
2
1
0
8
3
2
4
-9
4
3
2
12
5
4
4
4
1.三元组表表示法2
 用C语言定义三元组表的结构类型如下:
00
01
02
03
04
05
06
07
08
09
10
11
typedef int DataType; /* 假设稀疏矩阵的元素类型为整型 */
#define MAXSIZE 100 /* 非零元个数的最大值 */
typedef struct
/* 定义三元组结点类型 */
{
int row,col;
/* 非零元所在的行下标,列下标 */
DataType value;
/* 非零元素值 */
}Triple;
typedef struct
/* 定义三元组表结构类型SMatrix */
{
Triple data[MAXSIZE+1]; /* 非零元组成的三元组表 */
int mu,nu,tu;
/* 稀疏矩阵的行数、列数和非零元个数 */
}SMatrix;
1.三元组表表示法3
(1)建立稀疏矩阵的三元组表1
算法4-1 建立并输出稀疏矩阵的三元组表
00 SMatrix CreateSMatrix() /* 创建稀疏矩阵M */
01 {
02 SMatrix M;
03 int i;
04 printf("\n请输入矩阵的行数:");
05 scanf("%d",&M.mu);
06 printf("\n请输入矩阵的列数:");
07 scanf("%d",&M.nu);
08 printf("\n请输入矩阵的非零元素个数:");
09 scanf("%d",&M.tu);
10 for(i = 0; i < M.tu; i++)
11
{
12
printf("请按行序顺序输入第%d个非零元素所在的行(0~%d),"
"列(0~%d),元素值:(逗号分隔)\n", i,M.mu-1,M.nu-1);
13
scanf("%d,%d,%d",&M.data[i].row,&M.data[i].col,&M.data[i].value);
14
}
15 return M;
16 }
1.三元组表表示法3
(1)建立稀疏矩阵的三元组表2
算法分析:
 建立并输出稀疏矩阵的三元组表,首先要给出三元组表的类型定义,然
后编写建立函数和输出函数,最后在主程序中调用,见算法4-1。程序
第00-16行为建立函数,程序先定义了三元组变量M,再通过键盘输入
稀疏矩阵的信息:行数、列数、非零元个数,由程序第04-09行完成。
程序第10行的for语句循环M.tu次,输入每个非零元的信息,填入到相
应的三元组的对应域中,即完成三元组表的建立。
 输出函数(程序第17-24行)则按每行输出一个三元组的形式输出三元
组的信息。
 主程序(程序第25-30行)通过调用建立函数和输出函数完成三元组表
的建立于输出。
1.三元组表表示法4
(2)稀疏矩阵的转置
第一种方法:
假设稀疏矩阵M有n列,转置后的稀疏矩阵为T。需要对M的
三元组表进行n趟扫描,第i(0≤i≤n-1)趟扫描将M中所有col值
为i的三元组存放到T的三元组表中,具体方法是:取出该三元组,
交换row值和col值,连同value值,作为新的三元组存放到T的
三元组表中(程序第13-15行)。这样就将M中的第i列的非零元
转置到了T中的第i行,并且能保证T的三元组表是按行序存放。
算法4-2 稀疏矩阵的转置算法
00 SMatrix TransMatrix(SMatrix M) /* 稀疏矩阵M的转置算法 */
01 {
02 SMatrix T;
03 int i,j,k;
04 T.mu=M.nu;
/* 稀疏矩阵M的列数作为T的行数 */
05 T.nu=M.mu;
/* 稀疏矩阵M的行数作为T的列数 */
06 T.tu=M.tu;
/* 稀疏矩阵M的非零元个数作为T的非零元个数 */
07 if(T.tu>0)
08 {
09
k=0;
10
for(i=0;i<M.nu;i++)
/* M有nu列,要扫描nu趟 */
11
for(j=0;j<M.tu;j++)
/* 对M中的每个三元组扫描 */
12
if(M.data[j].col==i)
13
{
14
T.data[k].row=M.data[j].col;
15
T.data[k].col=M.data[j].row;
16
T.data[k].value=M.data[j].value;
17
k++;
18
}
19
}
20 return T;
21 }
1.三元组表表示法4
(2)稀疏矩阵的转置2
第二种方法:快速转置
引入两变量:一个变量存放转换后的稀疏矩阵T每行的非零元素个数,可
定义为rowsize[ ],变量长度为T的行数。
另外一个变量存放T中每行的第一个非零元在三元组表中的位置,可定义
为rowstart[ ],长度也为T的行数。具体公式为:
在两个辅助变量计算出来后,可对三元组表进行快速转置,进行一
趟扫描即可。具体做法是:逐个扫描M的三元组表中三元组的列值j(程
序第31行),以此列值为下标读取rowstart[j]中的元素值(程序第32
行),即为该三元组转置后在T的三元组表中的位置,将此三元组存放
到该位置后,rowstart[j]值加1(程序第36行),表示同一行的下一个
非零元素三元组的位置。
算法4-3 稀疏矩阵的快速转置算法1
00 SMatrix FastTransMatrix(SMatrix M) /* 稀疏矩阵M的快速转置算法 */
01 {
02 SMatrix T;
03 int rowsize[MAXSIZE];
04 int rowstart[MAXSIZE];
05 int i,j,k;
06 T.mu=M.nu;
/* 稀疏矩阵M的列数作为T的行数 */
07 T.nu=M.mu;
/* 稀疏矩阵M的行数作为T的列数 */
08 T.tu=M.tu;
/* 稀疏矩阵M的非零元个数作为T的非零元个数 */
09 if(T.tu>0)
10 {
11
for(j=0;j<M.nu;j++) /* 设rowsize的初值全为0 */
12
rowsize[j]=0;
13
for(i=0;i<M.tu;i++) /* 求M中每一列非零元素个数 */
14
{
15
j=M.data[i].col;
16
rowsize[j]=rowsize[j]+1;
17
}
18
printf("\nrowsize[]:");
19
for(i=0;i<M.nu;i++) /* 打印输出rowsize变量 */
20
printf("%d ",rowsize[i]);
21
printf("\n");
算法4-3 稀疏矩阵的快速转置算法2
22
rowstart[0]=0;
23
for(j=1;j<M.nu;j++) /* 求第j列中第一个非零元在T中的位置 */
24
rowstart[j]=rowstart[j-1]+rowsize[j-1];
25
printf("\nrowstart[]:");
26
for(i=0;i<M.nu;i++)
/* 打印输出rowstart变量 */
27
printf("%d ",rowstart[i]);
28
printf("\n");
29
for(i=0;i<M.tu;i++)
30
{
31
j=M.data[i].col; /* 取得三元组的列值 */
32
k=rowstart[j]; /* 取得三元组在T中的位置 */
33
T.data[k].row=M.data[i].col;
34
T.data[k].col=M.data[i].row;
35
T.data[k].value=M.data[i].value;
36
rowstart[j]=rowstart[j]+1;
37
}
38 }
39 return T;
40 }
4.1.4 稀疏矩阵压缩存储2
2.十字链表法
 当矩阵的非零元个数和位置在操作过程中变化较大时,就不宜采用三
元组表来表示,对此种类型矩阵,采用链式存储表示三元组的线性表
更为合适。
 为了使用链表存储稀疏矩阵,需要分别建立非零元素结点、行/列链表
头结点和整个链表头结点。
row
col
i
j
down
value
row
col
next
aij
right
(a)非零元素结点
row
m
down
col
next
n
right
(b)行/列链表头结点
(c)十字链表链表头结
点
2.十字链表法2
非零元素结点C语言定义如下:
00 typedef int DataType; /* 假设稀疏矩阵的元素类型为整型 */
01 struct node
/* 定义十字链表结点结构 */
02 {
03 int row,col;
/* 非零元所在的行下标,列下标 */
04 DataType value;
/* 非零元素值 */
05 struct node *down;
/* 定义down域指向同一列中下一个非零元地址 */
06 struct node *right;
/* 定义right域指向同一行中下一个非零元地址 */
07 };
08 typedef struct node TripleNode; /* 定义十字链表结点类型 */
2.十字链表法3
十字链表头结点C语言定义如下:
00
01
02
03
04
05
struct node1
/* 定义十字链表结点结构 */
{
int mu,nu,tu;
/* 稀疏矩阵的行数、列数和非零元个数 */
TripleNode *head;
/* 定义head域指向行列表头结点向量 */
};
typedef struct node1 Triple; /* 定义十字链表类型 */
建立稀疏矩阵的十字链表程序见4.1.3节算法4-4
2.十字链表法4
一个十字链表实例:
head
3
h1
h1
h2
3
1
1
1
h2
3
h3
h3
1
4
1
3
1
2
3
2
§4.2 串
4.2.1 串及相关概念
串(string):是由零个或多个字符组成的有限序列。
S=‘a0a1a2…an-1’ (n≥ 0)
串名:大写字母S为串名
串值:引号引起来的字符序列
长度:n表示串值中的字符个数,称为长度
空串:当n=0时,称为空串
空格串:由一个或多个空格组成的串
子串与主串:串中任意连续的字符组成的子序列称为该串
的子串。包含子串的串相应地称为主串。
位置:字符在字符串中首次出现的位置
相等:两个串的长度相等且对应位置上的字符都一一相等
4.2.2 串的基本操作
 串的抽象数据类型定义如下:
ADT String is
{数据对象:D={ai|ai∈CharacterSet,i=0,1,2,…,n-1,n≥0}
数据关系:R={<ai-1,ai>|ai-1,ai∈D,i=1,2,…,n-1}
基本操作:
(1)StrAssign(String T, String chars)
把chars赋为T的值,chars是字符串常量。
(2)StrCopy(String T, String S) 将串S复制到串T中。
(3)StrEmpty(String S)
判断串S是否为空串,并返回TRUE或FALSE的标志。
(4)StrCompare(String S, String T)
判断两个字符串是否相等,若S>T,则返回值>0;若S=T,则返回值=0;若S<
T,则返回值<0。
(5)int StrLength(String S)
返回字符串S的元素个数,称为串的长度。
……
} ADT String
4.2.3 串的存储结构
1.串的定长顺序存储结构
 串的定长顺序存储表示,也称为静态存储分配的顺序串。它是用一组地址连续
的存储单元存储串值的字符序列。所谓定长顺序存储结构,是直接使用定长的
字符数组来定义。
 用C语言定义串的结构类型如下:
typedef struct
{char data[MAXSTRLEN]; /* 定义data域为定长的顺序存储结构 */
int len;
/* 定义len域为串的长度 */
} String;
/* 定义串的结构类型为String */
 串的定长顺序存储结构,优点是可以实现直接存取,定位方便,可以
很方便地求取子串;缺点是插入、删除、置换等操作困难,需要移动
大量的字符。
4.2.3 串的存储结构2
2.串的链式存储结构
 串的单链表存储表示
head
D
A
T
A
S
…
 结点大小为4的块链存储表示
head
D ATA
S T R
…
U E # # ^
最后结点不满可以用“#”号补上;
也可设置尾指针,方便联接操作,注意“#”号的处理。
E
^
2、串的链式存储结构2
重点:设定结点的大小,小则操作方便,但系统
开销大;大节省空间,操作不方便。
存储密度 =
串值所占存储空间
实际分配的存储空间
4.2.4 串的模式匹配
串的模式匹配是一种重要的串运算,即子串定位操作,具体含义是:若
主串S中存在和串T值相同的子串, 则返回它在主串S中第一次出现首字母的位
置; 否则函数值为-1。
1. BF算法
 基本思想:
假设主串S=’s0s1s2…sn-1’,模式串T=’t0t1t2…tm-1’,n为S的长
度,m为T的长度。从主串S的第一个字符开始和模式串T的第一个字符
进行比较,若相等,则继续比较两者的后续字符;否则,从主串S的第
二个字符开始和模式T的第一个字符进行匹配。重复上述过程,若T中
的字符全部匹配完毕,则说明本趟匹配成功,返回本趟匹配S的起始位
置;否则,匹配失败,返回-1。
设主串S=’abacababaabcacadcaa’,模式串T=’abaabcac’,
BF算法匹配过程如下图所示:
k=3
第 1 趟匹配
abacababaabcacadcaa
abaabcac
失败,回溯:
k = i=k-j+1= 1
j=0
j= 3
k=1
第 2 趟匹配
abacababaabcacadcaa
abaabcac
失败,回溯:
k = i=k-j+1= 2
j=0
j= 0
k=3
第 3 趟匹配
abacababaabcacadcaa
abaabcac
失败,回溯:
k = i=k-j+1= 3
j=0
j= 1
k=3
第 4 趟匹配
abacababaabcacadcaa
abaabcac
j= 0
失败,回溯:
k = i=k-j+1= 4
j=0
匹配过程图(续):
k=7
第 5 趟匹配
abacababaabcacadcaa
abaabcac
失败,回溯:
k = i=k-j+1= 5
j=0
j= 3
k=5
第 6 趟匹配
abacababaabcacadcaa
abaabcac
失败,回溯:
k = i=k-j+1= 6
j=0
j= 0
k
第 7 趟匹配
=
a b a c a b a b a a b c a c a d14c a a
abaabcac
j= 8
成功!返回 k = i = k -j = 6
1. BF算法2
BF算法虽然简单但是效率较低,时间复杂度为O(n×m)。
造成BF算法效率低的原因是回溯,即在某趟匹配i个字符失败
后,对于主串S要回溯到本趟匹配开始字符的下一个字符,模
式串T要回溯到第一个字符,没有利用前i-1个字符时的部分匹
配结果。
BF算法详见教材4.2.4节的算法4-5。
4.2.4 串的模式匹配2
2. KMP算法
 基本思想:
该算法主要消除了主串指针(i指针)的回溯,利用已经得到的部分
匹配结果将模式串右滑尽可能远的一段距离再继续比较,从而使算法
效率有某种程度的提高,可使效率提高到O(n+m)的水平。
KMP算法当某趟匹配不成功时,即Si≠Tj时,主串S下标i不回溯,
模式串T下标j也不回到0位置,而是回到一个恰当的位置,所以在主
串下标i不回溯的前提下,下标j回到哪个位置是问题的关键。
假设回到位置j,代表的意思是在主串S位置i之前(j-1)位必定
与模式串T的前(j-1)位一一匹配。
设主串S=’abacababaabcacadcaa’,模式串
T=’abaabcac’,T中next函数值如下表所示:
下标
0
1
2
3
4
5
6
7
T
a
b
a
a
b
c
a
c
next[]
-1
0
0
1
1
2
0
1
KMP算法匹配过程如下图:
i=0
i=3
abacababaabcacadcaa
第 1 趟匹配
abaabcac
j= 0
失败:
i=3
j = next[3 ]= 1
j= 3
i=3
第 2 趟匹配
abacababaabcacadcaa
abaabcac
失败:
i=3
j = next[1 ]= 0
j= 1
i=3
第 3 趟匹配
abacababaabcacadcaa
abaabcac
失败:
i=4
i=3
j=
next[0]= - 1
j= 0
i=4
第 4 趟匹配
k=7
abacababaabcacadcaa
abaabcac
j= 0
i=7
j = next[ 3]= 1
j= 3
k=7
第 5 趟匹配
失败:
k
=
a b a c a b a b a a b c a c a d14c a a
abaabcac
j= 1
j= 8
成功!返回 i = i -j = 6
j=0
2. KMP算法2
 next函数的值完全只与模式串有关而与主串的值没有任何关系,
因此对于每个模式串来说都有一个唯一的next数组值。
 next数组的计算公式为:
-1
next[j]=
当 j=0 时
Max{ k|0<k<j-1,且‘t0 … tk-1’=‘tj-k+1 … tj-1’ }
0
当此集合不空时
其他情况
 Index_KMP函数中,求next数组的GetNext函数时间复杂度为
O(m)接下来不回溯的匹配过程时间复杂度为O(n),所以,
KMP算法总的时间复杂度为O(m+n)。
KMP算法详见教材4.2.4节的算法4-6。
§4.3 广义表
4.3.1 广义表基本概念
1.广义表及相关概念
广义表(Generalized Lists)是由n(n≥0)个数据元素组成的
有序序列,一般记为:
Lists=(a0,a1,a2,……,an-1)
长度:广义表中包含数据元素(直接数据元素)个数称为该广义表的长度
深度:包含括弧的最大嵌套层数称为该广义表的深度
子表:广义表的递归性使得广义表中数据元素为子广义表
表头:广义表中第一个元素a0为广义表的表头
表尾:广义表中除了表头之外的其它元素组成的广义表称为表尾
再入表:广义表L中存在某个原子或子表成员出现多次
纯表:广义表L中不存在相同数据元素出现两次以上
1.广义表及相关概念2
 一些广义表的例子:
① A=()。A是一个广义表,而且是一个空表,长度为0。表头为空,表尾为
()。
② B=(())。注意B与A的区别,B的长度为1,子表是()。表头head(A)
=(),表尾tail(B)=()。
③ C=(a,b,c)。C是一个长度为3的广义表,它的数据元素都是原子元素。
表头head(C)=a,表尾tail(C)=(b,c)。此时,C是一个纯表。
④ D=(a,(a,b),(a,(a,b)))。D是一个长度为3,深度为3的广义
表,它的数据元素有原子元素,也有广义表。表头head(D)=a,表尾tail
(D)=((a,b),(a,(a,b)))。此时,D是一个再入表
⑤ E=(A,C,d)=((),(a,b,c),d)长度为3,深度为2。此时,广
义表中的子表可以用广义表的名称来代替。
⑥ F=(f,F)。广义表F是一个递归表述的表,意义为F=(f,(f,(f,
(…)))),F的长度为2。此时,F是一个递归表
广义表能够实现共享!
4.3.1 广义表基本概念2
2.广义表ADT描述
ADT Generalized Lists is
{数据对象:D={ai| ai∈AtomSet或者ai∈Generalized,i=0,1,2,…,n-1,n≥0,
AtomSet为某种数据元素类型}
数据关系:R={<ai-1,ai>|ai-1,ai∈D,i=1,2,…,n-1}
基本操作:
(1)InitGList(Generalized Ls)
创建一个空的广义表Ls。
(2)GetHead(Generalized Ls)
返回取广义表Ls的表头。
(3)GetTail(Generalized Ls)
返回广义表Ls的表尾。
(4)GListDepth(Generalized Ls)
返回广义表Ls的深度。
(5)GListEmpty(Generalized Ls) 判断广义表Ls是否为空广义表。
(6)DestroyGList(Generalized Ls)
……
} ADT Generalized
销毁广义表Ls释放空间。
4.3.2 广义表存储结构
 广义表中的元素有原子元素和广义表,在存储结构设计上也需要使用
表结点和原子结点两种类型。
tag=1
next
sublist
标识域 表头指针域
下一元素指针域
(a)表结点
tag=0
atom
标识域
数据域
(b)原子结点
next
下一元素指针域
4.3.2 广义表存储结构2
 用C语言定义广义表的结点结构类型如下:
00 typedef struct GLnode
01 {
02 int tag;
/* 标识域,用于区分原子结点和表结点 */
03 union
04
{
05
DataType atom; /* 原子结点的值域,元素类型为DataType */
06
struct GLnode *sublist; /* 指向表头结点的指针域 */
07
} val;
/* 通过val.atom和val.sublist来引用值域或指针域 */
08 struct GLnode *next; /* 指向下一元素结点的指针域 */
09 } GLnode;
/* 定义广义表结点类型为GLnode */
4.3.2 广义表存储结构3
 广义表存储结构示例:
A
B
0
^
^
p
^
p
1
^
0
^
p
C
0
a
0
b
0
c
^
0
d
^
0
E
1
^
1
0
f
1
F
^
4.3.3 广义表基本操作
1.广义表创建
00 GLnode *creatglist(char *s) /* 创建广义表 */
01 {
02
GLnode *h;
03
char ch;
04
ch=*s;
05
s++;
06
if(ch!='\0')
07
{
08
h=(GLnode *)malloc(sizeof(GLnode));
09
if(!h)
10
printf("error!\n");
11
if(ch=='(')
12
{
13
h->tag=1;
14
h->val.sublist=creatglist(s); /* 递归创建广义表 */
15
}
16
else
17
if(ch==')')
18
h=NULL;
4.3.3 广义表基本操作
1.广义表创建2
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
else
{
h->tag=0;
h->val.atom=ch;
}
}
else
h=NULL;
ch=*s;
s++;
if(h!=NULL)
{
if(ch==',')
h->next=creatglist(s);
else
h->next=NULL;
}
return h;
}
4.3.3 广义表基本操作2
2.输出广义表
00 void output(GLnode *h)
01 {
02 if(h!=NULL)
03
{
04
if(h->tag==1)
05
{
06
printf("(");
07
if(h->val.sublist==NULL)
08
printf(" ");
09
else
10
output(h->val.sublist); /* 输出广义表表头结点 */
11
}
12
else
13
printf("%c",h->val.atom); /* 如该元素为原子结点,输出元素值 */
14
if(h->tag==1)
15
printf(")");
16
if(h->next!=NULL)
17
{
18
printf(",");
19
output(h->next); /* 继续输出广义表下一个元素 */
20
} } }
4.3.3 广义表基本操作3
3.插入元素到广义表表头
00 viod insert(GLnode *h,char e)
01 {
02
GLnode *p;
03
p=(GLnode *)malloc(sizeof(GLnode)); /* 申请新结点p并赋值 */
04
p->tag=0;
05
p->val.atom=e;
06
p->next=h->val.sublist;
07
h->val.sublist=p;
08 }
/* 将新结点p插入到广义表中 */
4.3.3 广义表基本操作4
4.求广义表深度
00 int depth(GLnode *h) /* 求广义表的深度 */
01 {
02 int max=0,dep;
03 while(h!=NULL)
04
{
05
if(h->tag==1) /* 如该元素为广义表,继续求其子表深度 */
06
{
07
dep=depth(h->val.sublist);
08
if(dep>max)
09
max=dep; /* 各子表深度最大值为子表的深度 */
10
}
11
h=h->next;
12
}
13 return max+1; /* 返回子表深度+1 */
14 }
本章小结
 本章基本内容:
数组存储
数组
特殊矩阵
二维数组
压缩存储
稀疏矩阵
串的存储
串
BF 算法
串的操作
模式匹配
KMP 算法
广义表存储
广义表
广义表操作
创建
插入
求深度
本章小结2
 基于线性表的数据结构:
(堆)栈
数据操作进行
数据格式进行
限制
限制
线性表
数据对象进行
队列
数据元素分出
结构,拓广
广义表
限制
数组
串