第 5 章 数组和广义表

42
第5第 第第第第第第

description

第 5 章 数组和广义表. 2. 5.1 数组的逻辑结构. 数组 (array) 是最常用的数据结构之一。几乎所有的程序设计语言都把数组类型设定为固有类型。. 线性结构中的数据都是非结构的原子类型,元素的值是不再分解的。而数组可以看成是线性表在下述含义上的扩展:. 表中的数据元素本身也是一种数据结构。. 数组的定义. 数组的基本操作. 3. 5.1.1 数组的定义. 数组是由下标和值组成的序对集合。在数组中,一旦给定下标,都存在一个与其相对应的值,这个值就称为数组元素。. - PowerPoint PPT Presentation

Transcript of 第 5 章 数组和广义表

Page 1: 第 5 章  数组和广义表

第 5章 数组和广义表

Page 2: 第 5 章  数组和广义表

数组 数组 (array) (array) 是最常用的数据结构之一。几是最常用的数据结构之一。几乎所有的程序设计语言都把数组类型设定为固有类型。乎所有的程序设计语言都把数组类型设定为固有类型。

数组的定义数组的定义

线性结构中的数据都是非结构的原子类型,元线性结构中的数据都是非结构的原子类型,元素的值是不再分解的。而数组可以看成是线性表在下述素的值是不再分解的。而数组可以看成是线性表在下述含义上的扩展:含义上的扩展:

5.1 5.1 数组的逻辑结构数组的逻辑结构2

数组的基本操作数组的基本操作

表中的数据元素本身也是一种数据结构。表中的数据元素本身也是一种数据结构。

Page 3: 第 5 章  数组和广义表

数组是由下标和值组成的序对集合。在数组中,数组是由下标和值组成的序对集合。在数组中,一旦给定下标,都存在一个与其相对应的值,这个值就称一旦给定下标,都存在一个与其相对应的值,这个值就称为数组元素。为数组元素。

也可以说,数组中的每个数据元素都对应于一也可以说,数组中的每个数据元素都对应于一组下标( 组下标( jj11 , , jj22 , … , , … , jjnn ),每个下标取值范围是 ),每个下标取值范围是 1≤1≤jjii≤≤bbi i ,,

bbi i 称为第 称为第 ii 维的长度( 维的长度( ii = 1, 2, …, = 1, 2, …, nn )。显然,当 )。显然,当 nn

= 1 = 1 时,时, n n 维数组就退化为定长的线性表。反之,维数组就退化为定长的线性表。反之, nn 维维数组也可以看成是线性表的推广。数组也可以看成是线性表的推广。

3

5.1.1 5.1.1 数组的定义数组的定义

Page 4: 第 5 章  数组和广义表

可以把二维数组看成是这样一个定长线性表:可以把二维数组看成是这样一个定长线性表:它的每个数据元素也是一个定长线性表。它的每个数据元素也是一个定长线性表。

AAmm××n n ==

aa1111

aa2121

……

aamm11

aa1212

aa2222

……

aam2m2

aa1313

aa2323

……

aam3m3

……

……

……

……

aa 1.n 1.n

aa22, n, n

……

aam, nm, n

4

例如,下面是一个二维数组,且以 例如,下面是一个二维数组,且以 mm 行 行 nn

列的矩阵形式表示。列的矩阵形式表示。

Page 5: 第 5 章  数组和广义表

每个数据元素每个数据元素 aajj 是一个列向量形式的线性表是一个列向量形式的线性表

AAmm××n n == ……

aa1,1, n n

aa2,2, n n

……aam, nm, n

aa1313

aa2323

……aamm, 3, 3

aa1212

aa2222

……aamm, 2, 2

aa1111

aa2121

……aamm,1,1

二维数组 二维数组 AA 还可以看成是一个线性表:还可以看成是一个线性表: AA = ( = (αα11, , αα 22, … , , … , αα nn ) )

αα jj = ( = ( aa11jj , , aa22jj , … , , … , aamm, , j j )) 1 ≤ 1 ≤ jj ≤ ≤ nn

每个数据元素是一个行向量形式的线性表每个数据元素是一个行向量形式的线性表 B=(B=(ββ11ββ22ββ3 3 … ,… , ββmm))

AAmm××n n = = ( ( ( ( aa1111 aa1212 … … aa1, 1, nn ) , ) , … …, ( , ( aamm, 1, 1aamm, 2… , 2… aamm, , nn ) )) ) ( ( aa2121 aa2222 … … aa2, 2, nn ) , … ,) , … ,

ββii = ( = ( aai 1 i 1 , , aai 2 i 2 , … , , … , aai, n i, n )) 1 ≤ 1 ≤ ii ≤ ≤ mm

5

Page 6: 第 5 章  数组和广义表

5.1.2 数组的抽象类型定义ADT Array {ADT Array { D={aD={aj1j2j3…..jnj1j2j3…..jn|n>0,|n>0, 称为数组的维数称为数组的维数 , j, jii 是数组的第是数组的第 ii 维下标维下标 ,,

11≤ ≤ jjii ≤bi, bi 为数组第 i维的长度, aaj1j2j3…..jnj1j2j3…..jn∈∈ElementSet}ElementSet}

数据关系:R数据关系:R ={R={R11,,RR22, …….R, …….Rnn}}

RRii=<a=<aj1…ji….jnj1…ji….jn,a,aj1…ji+1…jnj1…ji+1…jn>| 1>| 1≤≤jjk k ≤≤bbkk, 1, 1≤≤kk≤≤n n 且 且 kk≠≠i, i,

11≤≤jjii ≤≤bbi-1i-1, a, aj1…j2….jnj1…j2….jn,a,aj1…ji+1…jnj1…ji+1…jn∈∈D,i=1,…n}D,i=1,…n}

基本操作基本操作 ::

InitArray (A, n, bound1, … , boundn );InitArray (A, n, bound1, … , boundn );

操作结果:如果维数 操作结果:如果维数 nn 和各维长度合法,则构造和各维长度合法,则构造 相应的数组 相应的数组 AA ,并且返回 ,并且返回 TRTR

UEUE 。。

Page 7: 第 5 章  数组和广义表

基本操作 DestroyArray(A):DestroyArray(A): 销毁数组销毁数组 AA 。。 GetValue(A,e, index1, … , indexnGetValue(A,e, index1, … , indexn ): 初始条件:初始条件: AA 是 是 nn 维数组,维数组, ee 为元素变量,随后为元素变量,随后

是是 nn 个下标值。个下标值。操作结果:若各下标合法,则用操作结果:若各下标合法,则用 ee 返回数组A中由返回数组A中由由由 index1,… indexnindex1,… indexn 所指定的元素的值所指定的元素的值 ..

SetValue ( A, e, index1, … , indexn );SetValue ( A, e, index1, … , indexn );初始条件:初始条件: AA 是 是 nn 维数组,维数组, ee 为元素变量,随为元素变量,随后是后是 nn 个下标值。个下标值。操作结果:若各下标合法,则将数组操作结果:若各下标合法,则将数组 AA 中由中由 indexindex1,… indexn1,… indexn 所指定的元素的值置为所指定的元素的值置为 e.e.

Page 8: 第 5 章  数组和广义表

由于内存储器的结构是一维的。一维数组可直由于内存储器的结构是一维的。一维数组可直接采用顺序存储。用一维的内存存储表示多维数组时,接采用顺序存储。用一维的内存存储表示多维数组时,需按某种次序将数组中元素排成一线性序列,再将这个需按某种次序将数组中元素排成一线性序列,再将这个线性序列存放在一维的内存中,即数组的顺序存储结构线性序列存放在一维的内存中,即数组的顺序存储结构表示。表示。

顺序存储的定位公式顺序存储的定位公式

5.2 5.2 数组的顺序存储结构数组的顺序存储结构8

数组的顺序存储表示数组的顺序存储表示基本操作的算法描述基本操作的算法描述

Page 9: 第 5 章  数组和广义表

用顺序存储结构来存储数组中的元素,一定要用顺序存储结构来存储数组中的元素,一定要按照某种次序将元素排成一个线性序列。对二维数组可以按照某种次序将元素排成一个线性序列。对二维数组可以有两种存储方式:有两种存储方式:

(1) (1) 以列为主序 以列为主序 ( column major order ) ( column major order ) 的存储方的存储方式,即按列优先,逐列顺序存储。式,即按列优先,逐列顺序存储。

(2) (2) 以行为主序 以行为主序 ( row major order ) ( row major order ) 的存储方式,的存储方式,即按行优先,逐行顺序存储。即按行优先,逐行顺序存储。

9

5.2.1 5.2.1 顺序存储的定位公式顺序存储的定位公式

Page 10: 第 5 章  数组和广义表

⑵⑵ 二维数组的二维数组的地址计算地址计算

    假设每个数据元素占 假设每个数据元素占 CC 个存储单元,且以行序为主序的进行个存储单元,且以行序为主序的进行存储,则二维数组 存储,则二维数组 AA 中任一元素 中任一元素 aaijij 的存储位置可以由下面定位的存储位置可以由下面定位公式确定公式确定

LOCLOC (A[ (A[i]i],[ ,[ j]j]) = ) = LOCLOC (A[1], [1]) + (A[1], [1]) + ( ( n*(i-1)+(n*(i-1)+(j-1j-1)) )) **CC其中:其中:

LOCLOC (A[ (A[i[i[,[ ,[ j]j]) ) 是 是 aaijij 的存储位置; 的存储位置; LOCLOC (A[1], [1]) (A[1], [1]) 是 是 aa1111 的存储位置,即二维数组 的存储位置,即二维数组 AA

的起始存储位置,也称为基地址或基址;的起始存储位置,也称为基地址或基址; nn 是数组第二维的长度。是数组第二维的长度。

10

    一般地:一般地:

LOCLOC (A[ (A[i]i],[ ,[ j]j]) = ) = LOCLOC (A[s], [t]) + (A[s], [t]) + ( ( n*(i-s)+(n*(i-s)+(j-tj-t)) )) **CC

Page 11: 第 5 章  数组和广义表

⑶⑶ 三维数组的三维数组的地址计算地址计算    三维数组三维数组 A(1:r,1:m,1:n)A(1:r,1:m,1:n) 。。假设每个数据元素占假设每个数据元素占 sizesize

个存储单元,且以行序为主序的进行存储,首元素个存储单元,且以行序为主序的进行存储,首元素 aa111111 的的

地址为地址为 Loc(A[1][1][1]),Loc(A[1][1][1]), 求任意元素求任意元素 aaijkijk 的地址。的地址。

    显然,显然, aai11i11 地址为地址为 LL oc(A[i][1][1])=Lococ(A[i][1][1])=Loc(A[1][1][1])+(i-1)*m*n,(A[1][1][1])+(i-1)*m*n, 因为在该元因为在该元素之前有素之前有 i-1i-1 个个 m*nm*n 的二维数组。的二维数组。

11

 不难得到三维数组任意元素 不难得到三维数组任意元素 aaijkijk 的地址:的地址:Loc(A[i][j][k])=Loc(A[1][1][1])+((i-1)*m*n+(j-1)*n+(k-Loc(A[i][j][k])=Loc(A[1][1][1])+((i-1)*m*n+(j-1)*n+(k-

1))*size,1))*size, 其中:1其中:1≤≤ i≤r, i≤r, 1≤1≤ j≤m, j≤m, 1≤1≤ k≤nk≤n 。。

Page 12: 第 5 章  数组和广义表

矩阵 矩阵 (matrix) (matrix) 是很多科学与工程计算问题中是很多科学与工程计算问题中研究的数学对象。在数据结构中,我们感兴趣的不是矩研究的数学对象。在数据结构中,我们感兴趣的不是矩阵本身,而是如何存储矩阵的元素而使矩阵的各种运算阵本身,而是如何存储矩阵的元素而使矩阵的各种运算能够有效地进行。能够有效地进行。 在数值分析中经常出现有些阶数很高的矩阵,在数值分析中经常出现有些阶数很高的矩阵,同时在矩阵中有许多值相同的元素或者是零元素。有时同时在矩阵中有许多值相同的元素或者是零元素。有时为了节省存储空间,可以对这类矩阵进行为了节省存储空间,可以对这类矩阵进行压缩存储。压缩存储。

5.3 5.3 矩阵的压缩存储矩阵的压缩存储12

Page 13: 第 5 章  数组和广义表

特殊矩阵的压缩存储特殊矩阵的压缩存储

所谓压缩存储是指:为多个值相同的元只分配所谓压缩存储是指:为多个值相同的元只分配一个存储空间;对零元不分配空间。一个存储空间;对零元不分配空间。

13

稀疏矩阵的逻辑结构稀疏矩阵的逻辑结构

稀疏矩阵的存储结构稀疏矩阵的存储结构

Page 14: 第 5 章  数组和广义表

假若相同的元素或者零元素在矩阵中的分布有假若相同的元素或者零元素在矩阵中的分布有一定规律,则称特殊矩阵。特殊矩阵主要有 一定规律,则称特殊矩阵。特殊矩阵主要有 3 3 种:对种:对称矩阵、三角矩阵、带状矩阵。称矩阵、三角矩阵、带状矩阵。

在所有这些统称为 在所有这些统称为 “特殊矩阵” 的“特殊矩阵” 的矩阵中,矩阵中,非零元的分布都有一个明显的规律,从而都可以将其压非零元的分布都有一个明显的规律,从而都可以将其压缩存储到一维数组中,并且找到每个非零元在一维数组缩存储到一维数组中,并且找到每个非零元在一维数组中的对应关系。中的对应关系。

14

5.3.1 5.3.1 特殊矩阵的压缩存储特殊矩阵的压缩存储

Page 15: 第 5 章  数组和广义表

u t r o k ft s q n je r q p mi do n m l hc k ji h g bfe dc b a

若一个 若一个 nn 阶矩阵 阶矩阵 MM 中的元满足下述性质中的元满足下述性质 1. 1. 对称矩阵对称矩阵

aaijij = = aajiji 1 ≤ 1 ≤ ii ,, jj ≤ ≤ nn

则称为 则称为 nn 阶阶对称矩阵对称矩阵。。

15

Page 16: 第 5 章  数组和广义表

一个 一个 nn 阶方阵,若它的全部非零元素落在一阶方阵,若它的全部非零元素落在一个以对角线为中心的带状区域中,则称该矩阵为带状矩个以对角线为中心的带状区域中,则称该矩阵为带状矩阵,或对角矩阵。这个带状区域若包含主对角线上下各 阵,或对角矩阵。这个带状区域若包含主对角线上下各 bb 条对角线道上元素,那么,条对角线道上元素,那么, bb 称为该带状矩阵的半带称为该带状矩阵的半带宽,或称该带状矩阵的带宽为 宽,或称该带状矩阵的带宽为 (2(2bb+1)+1) 。。

3. 3. 带状矩阵带状矩阵

00

00

bb 条条

bb 条条

16

Page 17: 第 5 章  数组和广义表

带状矩阵中最常见的是三对角带状矩阵。带状矩阵中最常见的是三对角带状矩阵。

17

特点:特点:  当   当 i=1 j=1,2i=1 j=1,2

1<i<n,j=i-1,i,i+1 1<i<n,j=i-1,i,i+1

         i=n,j=n-1,n i=n,j=n-1,n        aijaij 非零,其它元素均为零非零,其它元素均为零

       

aa1111

AAnnnn= =

aa1212 00 00 00aa2121 aa2222 aa2323 00 0000 aa3232 aa3333 aa3434 0000 00 aa4343 aa4444 aa4545

00 00 …… …… ……

Page 18: 第 5 章  数组和广义表

1.1. 确定存储该矩阵所需的一维向量空间的大小确定存储该矩阵所需的一维向量空间的大小  除第一行和最后一行只有两个元素外,其余各行均  除第一行和最后一行只有两个元素外,其余各行均有有 33 个非零元素,由此得到一维向量所需的空间大小为:个非零元素,由此得到一维向量所需的空间大小为:33 n-2n-2   

2.2. 确定非零元素在一维数组空间中的位置确定非零元素在一维数组空间中的位置 L L oc(a[i][j])=Loc(a[1][1])+2(i-1)+j-1oc(a[i][j])=Loc(a[1][1])+2(i-1)+j-1

18

三对角带状矩阵的压缩存储,以行序为主序进三对角带状矩阵的压缩存储,以行序为主序进行存储,且只存储非零元素。其方法为行存储,且只存储非零元素。其方法为

Page 19: 第 5 章  数组和广义表

19

一般来说,当矩阵中非零元素的个数远远小于一般来说,当矩阵中非零元素的个数远远小于矩阵元素的总数时,称之为稀疏矩阵。假设在 矩阵元素的总数时,称之为稀疏矩阵。假设在 mm××nn 的的矩阵中,若有 矩阵中,若有 tt 个元素不为零,令 个元素不为零,令 = = t t / (/ (mm××nn)) ,则称 ,则称 为矩阵的稀疏因子。通常认为 为矩阵的稀疏因子。通常认为 ≤ ≤ 0.050.05 时称为时称为稀疏矩稀疏矩阵。阵。

5.3.2 5.3.2 稀疏矩阵的逻辑结构稀疏矩阵的逻辑结构

1. 1. 稀疏矩阵的定义稀疏矩阵的定义

Page 20: 第 5 章  数组和广义表

按照压缩存储的概念,只存储稀疏矩阵的非零按照压缩存储的概念,只存储稀疏矩阵的非零元素。因此,除了存储非零元素的值 元素。因此,除了存储非零元素的值 aaijij 之外,还必须之外,还必须同时记下它所在矩阵的行 同时记下它所在矩阵的行 ii 和列 和列 j j 的位置。反之,一的位置。反之,一个三元组 个三元组 ( ( ii, , jj,, a aij ij ) ) 唯一确定了矩阵的一个非零元素。唯一确定了矩阵的一个非零元素。因此,稀疏矩阵可以由表示非零元的三元组及其矩阵的因此,稀疏矩阵可以由表示非零元的三元组及其矩阵的总的行列数唯一确定。总的行列数唯一确定。 假设以顺序存储结构表示三元组表,则可以得假设以顺序存储结构表示三元组表,则可以得到稀疏矩阵的一种压缩存储方式,这种方式称之为三元到稀疏矩阵的一种压缩存储方式,这种方式称之为三元组顺序表。组顺序表。

20

5.3.3 5.3.3 稀疏矩阵的存储结构稀疏矩阵的存储结构 1. 1. 三元组顺序表三元组顺序表

Page 21: 第 5 章  数组和广义表

00

1212

99

00

00

00

00

00

00

00

00

00

00

00

-3-3

00

00

00

00

1414

00

00

00

2424

00

00

00

00

00

1818

00

00

00

00

00

1515

00

00

-7-7

00

00

00

MM = =

矩阵 矩阵 MM 可以由可以由三元组表三元组表 (1, 3, -3)(1, 3, -3) ,, (1, 6, 15)(1, 6, 15) ,, (2, 1, 12)(2, 1, 12) ,, (2, 5, 18)(2, 5, 18) ,,

(3, 1, 9)(3, 1, 9) ,, (3, 4, 24)(3, 4, 24) ,, (4, 6, -7)(4, 6, -7) ,, (6, 3, 14)(6, 3, 14)

再加上(再加上( 7, 67, 6 )这一对总的行列值来描述。)这一对总的行列值来描述。

21

Page 22: 第 5 章  数组和广义表

# define MAXSIZE# define MAXSIZE 1000 1000

// // 假设非零元个数的最大值为 假设非零元个数的最大值为 10001000

typedef struct {typedef struct { // // 三元组顺序表的元素结构定义三元组顺序表的元素结构定义

intint row, ;col row, ;col // // 该非零元的行下标和列下标该非零元的行下标和列下标

ElementType e;ElementType e; // // 该非零元的值该非零元的值

} // Triple;} // Triple;

typedef struct {typedef struct { // // 三元组顺序表存储结构定义三元组顺序表存储结构定义

Triple data[ MAXSIZE+1]; Triple data[ MAXSIZE+1]; // // 非零元三元组表,非零元三元组表, data[0] data[0] 未用未用

intint m, n, len; m, n, len; // // 矩阵的行数、列数和非零个数矩阵的行数、列数和非零个数

} // TSMatrix;} // TSMatrix; // // 三元组顺序表的类型名三元组顺序表的类型名

22

(1) (1) 三元组顺序存储表示三元组顺序存储表示

Page 23: 第 5 章  数组和广义表

(2) 利用三元组顺序表实现矩阵的转置运算

将矩阵的行列值相互交互;将矩阵的行列值相互交互;

在这 在这 3 3 点中,最关键的是第 点中,最关键的是第 3 3 条,即如何条,即如何使 使 bb.data .data 中的三元组以 T的行(M的列)为主序依次中的三元组以 T的行(M的列)为主序依次排列。排列。

23

显然,一个稀疏矩阵的转置矩阵仍是稀疏矩阵。假设 a 和 b 是 TSMatrix (三元组顺序表)类型变量,分别表示矩阵 M和其转置矩阵T。那么,只要做到下面 3 点就可以由 a 得到 b ,实现矩阵的转置。

将每三元组中的 将每三元组中的 rowrow 和 和 colcol 相互调换;相互调换; 重排三元组之间的次序。重排三元组之间的次序。

Page 24: 第 5 章  数组和广义表

24

原原始始的的三三元元组组表表

原原矩矩阵阵

0012129900000000

00000000000000

-3-300000000

141400

0000

242400000000

0018180000000000

15150000-7-7000000

MM ==

aa.data[1].data[1]aa.data[2].data[2]aa.data[3].data[3]aa.data[4].data[4]aa.data[5].data[5]aa.data[6].data[6]aa.data[7].data[7]aa.data[8].data[8]

aa.data.data

1 3 -31 3 -31 6 151 6 152 1 122 1 122 5 182 5 183 1 93 1 93 4 243 4 244 6 -74 6 -76 3 146 3 14

row col erow col e

转转置置矩矩阵阵

0000-3-30000

1515

1212000000

181800

990000

24240000

0000000000-7-7

000000000000

0000

1414000000

000000000000

TT ==

转转置置的的三三元元组组表表

bb.data[1].data[1]bb.data[2].data[2]bb.data[3].data[3]bb.data[4].data[4]bb.data[5].data[5]bb.data[6].data[6]bb.data[7].data[7]bb.data[8].data[8]

bb.data.data

1 2 121 2 121 3 91 3 93 1 -33 1 -33 6 143 6 144 3 244 3 245 2 185 2 186 1 156 1 156 4 -76 4 -7

row col erow col e

Page 25: 第 5 章  数组和广义表

使 使 bb.data .data 中的三元组以 中的三元组以 TT 的行(的行( MM 的的列)为主序依次排列的方法有如下两种:列)为主序依次排列的方法有如下两种:

25

方法一: 按照 方法一: 按照 bb.data .data 中三元组的次序,中三元组的次序,依次在 依次在 aa.data .data 中找到相应的三元组进行转置。中找到相应的三元组进行转置。

方法二: 按照 方法二: 按照 aa.data .data 中三元组的次序进中三元组的次序进行转置,并将转置后的三元组置入 行转置,并将转置后的三元组置入 bb.data .data 中恰当的中恰当的位置。位置。

Page 26: 第 5 章  数组和广义表

① ① 算法思算法思想想

在 在 AA 中按三元组的列域值 中按三元组的列域值 (col) (col) 开始扫描,开始扫描,依序将三元组 依序将三元组 aa.data .data 的列域值 的列域值 (col(col ) ) 与行域值 与行域值 (ro(ro

ww ) ) 进行对换,并且存入 进行对换,并且存入 BB 中。由于中。由于 AA 是以是以 MM 的行的行序为主序来存放每个非零元的,由此得到转置后矩阵序为主序来存放每个非零元的,由此得到转置后矩阵的三元组表的三元组表 BB恰是 以“行主为主序”。恰是 以“行主为主序”。

26

按照方法一,即按照按照方法一,即按照““被转置矩阵” 被转置矩阵” MM 的的三元组表三元组表 AA 的“列序”递增顺序进行转置。为了找到的“列序”递增顺序进行转置。为了找到矩阵 矩阵 MM 的每一列中所有的非零元素,需要对其三元的每一列中所有的非零元素,需要对其三元组 组 aa.data .data 从第一行起进行扫描,方法如下:从第一行起进行扫描,方法如下:

Page 27: 第 5 章  数组和广义表

转置的三元组表转置的三元组表

bb.data.data

原始的三元组表原始的三元组表

aa.data.data

ii

jj

vv

11

22

12 12

11

33

99

33

11

-3-3

33

66

1414

44

33

2424

55

22

1818

66

11

1515

66

44

-7-7

27

利用三元组顺序表存储实现矩阵的转置利用三元组顺序表存储实现矩阵的转置

jj

3 3

6 6

1 1

5 5

1 1

4 4

6 6

3 3

ii

1 1

1 1

2 2

2 2

3 3

3 3

4 4

6 6

vv

-3 -3

15 15

12 12

18 18

9 9

24 24

-7 -7

1414

Page 28: 第 5 章  数组和广义表

void TransposeTSMatrix ( TSMatrix A, TSMatrix *B ) void TransposeTSMatrix ( TSMatrix A, TSMatrix *B ) /*/* 采用三采用三元组表结构,求稀疏矩阵 元组表结构,求稀疏矩阵 AA 的转置矩阵 的转置矩阵 BB 。在程序中,。在程序中,

{{

int i,j,k;int i,j,k; // // jj 指示 指示 BB->data ->data 中三元组的序号, 中三元组的序号, ii 指示 指示 AA.data .data 中三元组的中三元组的序号,序号, // // kk 指示指示 A A 的列号(即的列号(即 B B 的行号)的行号) B->m = A.n;B->m = A.n;

// // 将稀疏矩阵 将稀疏矩阵 AA 的列数值作为其转置矩阵 的列数值作为其转置矩阵 BB 的行数值的行数值 B->n = A.m;B->n = A.m;

// // 将稀疏矩阵 将稀疏矩阵 AA 的行数值作为其转置矩阵 的行数值作为其转置矩阵 BB 的列数值的列数值

B->len = A.len;B->len = A.len;

// // 转置矩阵 转置矩阵 BB 与稀疏矩阵与稀疏矩阵 AA 的非零元个数相等的非零元个数相等

② ② 算法描述算法描述 (( 稀稀疏矩阵“列序”递增转置算疏矩阵“列序”递增转置算法)法)

if ( B->len>0 ) {if ( B->len>0 ) {

j = 1;j = 1;

28

Page 29: 第 5 章  数组和广义表

for (k = 1; k < = A.n; k++)for (k = 1; k < = A.n; k++)

for ( i = 1; i < = A.len; i++ )for ( i = 1; i < = A.len; i++ )

if ( A.data[i].col = = k ) {if ( A.data[i].col = = k ) { // // 进行转置进行转置

return OK;return OK;

}}/* TransposeSMatrix*//* TransposeSMatrix*/

B->data[j].row = A.data[i].col;B->data[j].row = A.data[i].col;

// // 稀疏矩阵稀疏矩阵 AA 的列域值成为其转置矩阵 的列域值成为其转置矩阵 BB 的行域值的行域值

B->data[j].col = A.data[i].row;B->data[j].col = A.data[i].row;

// // 稀疏矩阵 稀疏矩阵 AA 的行域值成为其转置矩阵 的行域值成为其转置矩阵 MM 的列域值的列域值

B->data[j].e = A.data[i].e;B->data[j].e = A.data[i].e;

// // 将稀疏矩阵 将稀疏矩阵 MM 的非零元值赋给其转置矩阵 的非零元值赋给其转置矩阵 TT

j++;j++;

// B->data // B->data 中三元组的序号加 中三元组的序号加 11

} } // if // if

}} // if // if

29

Page 30: 第 5 章  数组和广义表

③ ③ 算法分算法分析析

一般矩阵的转置算法(经典算法)为:一般矩阵的转置算法(经典算法)为:

30

for ( col = 1; col < = n; ++col )for ( col = 1; col < = n; ++col )

for ( row = 1; row < = m; ++row )for ( row = 1; row < = m; ++row )

B[col][row] = B[row][col];B[col][row] = B[row][col];

时间复杂度为 时间复杂度为 OO((mm××nn)) 。。

前面给出的求转置矩阵算法的主要工作是在 前面给出的求转置矩阵算法的主要工作是在 ii

和 和 k k 的两重循环中完成的,所以此算法的时间复杂度的两重循环中完成的,所以此算法的时间复杂度为 为 OO((A.nA.n××A.lenA.len) ) 即和矩阵 即和矩阵 AA 的列数和非零元的个数的列数和非零元的个数的乘积成正比。的乘积成正比。

Page 31: 第 5 章  数组和广义表

31

当矩阵 当矩阵 MM 中非零元个数几乎和中非零元个数几乎和矩阵元素个数相等时,即 矩阵元素个数相等时,即 lenlen 和 和 mm××nn 等等数量级时,算法时间复杂度就为 数量级时,算法时间复杂度就为 OO((mm××nn22)) ,虽然节省了存储空间,但时间复杂度,虽然节省了存储空间,但时间复杂度提高了。由此可见,上述求转置矩阵算法提高了。由此可见,上述求转置矩阵算法只适合于 只适合于 lenlen << << mm××nn 的情况。的情况。

Page 32: 第 5 章  数组和广义表

当矩阵非零元素的位置或个数经常变动时,当矩阵非零元素的位置或个数经常变动时,就不易采用顺序存储结构表示三元组的线性表。例如,就不易采用顺序存储结构表示三元组的线性表。例如,在在进行 “将矩阵进行 “将矩阵 BB 加到矩阵 加到矩阵 AA 上” 的上” 的操作时,由操作时,由于非零元素的插入或删除将会引起 于非零元素的插入或删除将会引起 AA.data .data 中元素的中元素的大量移动。为此,对这种类型的矩阵,采用链式存储大量移动。为此,对这种类型的矩阵,采用链式存储结构表示三元组的线性表更为恰当。结构表示三元组的线性表更为恰当。

32

2. 2. 十字链表十字链表

Page 33: 第 5 章  数组和广义表

(1) (1) 稀疏矩阵的十字链表存储表示稀疏矩阵的十字链表存储表示

矩阵中非零元的行号 矩阵中非零元的行号 rowrow ;; 矩阵中非零元的列号 矩阵中非零元的列号 colcol ;; 矩阵中非零元的值 矩阵中非零元的值 ee ;; 向右域 向右域 right ,用以链接同一行中下一个非,用以链接同一行中下一个非零元;零元; 向下域 向下域 downdown ,用以链接同一列中下一个非,用以链接同一列中下一个非零元。零元。

33

rowrow

downdowncolcol valuevalue

rightright非零元行号非零元行号

非零元列号非零元列号

非零元的值非零元的值向下域向下域 向右域向右域

在链表中,矩阵的非零元素可用如下结点表示:在链表中,矩阵的非零元素可用如下结点表示:

Page 34: 第 5 章  数组和广义表

typedef struct OLNode {typedef struct OLNode { // // 结点定义结点定义

intint row, col; row, col; // // 该非零元的行和列下标该非零元的行和列下标

ElementType value;ElementType value; // // 该非零元的值该非零元的值

struct OLNode struct OLNode **right, right, **down;down;

// // 该非零元所在的行表和列表的后继链域该非零元所在的行表和列表的后继链域

} OLNode; } OLNode; **Olink;Olink;

typedef struct {typedef struct { // // 十字链表定义十字链表定义

int int m, n, len;m, n, len; // // 稀疏矩阵行数、列数和非零元个数稀疏矩阵行数、列数和非零元个数

Olink Olink **row_head, row_head, **col_head;col_head;

// // 行和列链表头指针向量基址,由 行和列链表头指针向量基址,由 CreateSMatrix CreateSMatrix 分配分配

} CrossList;} CrossList; // // 十字链表存储结构的类型名十字链表存储结构的类型名

34

Page 35: 第 5 章  数组和广义表

广义表 广义表 (generalized list)(generalized list) 是线性表的推广,是线性表的推广,有时也称为列表(有时也称为列表( listslists ,用复数形式以示与统称的表 ,用复数形式以示与统称的表 list list 的区别)。广泛地应用于人工智能等领域的 的区别)。广泛地应用于人工智能等领域的 LISPLISP

(表处理语言),把广义表作为基本的数据结构,就(表处理语言),把广义表作为基本的数据结构,就连程序也表示为一系列的广义表。连程序也表示为一系列的广义表。

35

5.4 5.4 广义表广义表

Page 36: 第 5 章  数组和广义表

广义表的逻辑结构广义表的逻辑结构

和数组一样,广义表也可以看成是线性表在下和数组一样,广义表也可以看成是线性表在下述含义上的扩展:表中的数据元素本身也是一种数据结述含义上的扩展:表中的数据元素本身也是一种数据结构。构。

36

广义表的存储结构广义表的存储结构

Page 37: 第 5 章  数组和广义表

37

5.4.1 5.4.1 广义表的逻辑结构广义表的逻辑结构

广义表一般记作:广义表一般记作: GGLL = ( = ( aa1 1 , , aa2 2 , … , , … , aan n ))

其中:其中:

nn 是广义表 是广义表 GGLL 的长度;的长度; aaii 可以是单个元素,也可以是广义表,分别称可以是单个元素,也可以是广义表,分别称为广义表 为广义表 GGLL 的原子和子表,习惯上用大写字母表示的原子和子表,习惯上用大写字母表示广义表的名称,用小写字母表示原子的名称。广义表的名称,用小写字母表示原子的名称。

GGLL 是广义表 是广义表 ( ( aa1 1 , , aa2 2 , … , , … , aan n ) ) 的名称;的名称;

1. 1. 广义表的定义广义表的定义

Page 38: 第 5 章  数组和广义表

例例 5-15-1 AA = ( ) = ( ) ,, AA 是一个空表,它的长度为是一个空表,它的长度为零。零。 例例 5-25-2 BB = ( = (ee)) ,, BB 只有一个原子 只有一个原子 ee ,它的长,它的长度为 度为 11 。。 例例 5-35-3 CC = ( = (aa, (, (bb, , cc, , dd)))) ,, CC 的长度为 的长度为 22 ,两,两个元素分别为原子 个元素分别为原子 aa 和子表 和子表 ((bb, , cc, , dd)) 。。 例例 5-45-4 DD = ( = (AA, , BB, , CC)) ,, DD 的长度为 的长度为 33 ,三个,三个元素分别为 元素分别为 AA 、、 B B 和 和 CC ,都是广义表。显然,将上,都是广义表。显然,将上面所述三个子表的值代入以后,则有 面所述三个子表的值代入以后,则有 DD = (( ), ( = (( ), (ee), (), (aa, (, (bb, ,

cc, , dd)))))) 。。 例例 5-55-5 EE = ( = (aa, , EE)) ,这是一个递归表,它的长,这是一个递归表,它的长度为 度为 22 ,, E E 相当于一个无限的广义表 相当于一个无限的广义表 EE = ( = (aa, (, (aa, (, (aa, ,

…)))…))) 。。

38

2. 2. 广义表的三个重要结论广义表的三个重要结论

Page 39: 第 5 章  数组和广义表

从上述定义和例子推出如下广义表的三个重要结论从上述定义和例子推出如下广义表的三个重要结论

(1) (1) 广义表的元素可以是子表,而子表的元素还可广义表的元素可以是子表,而子表的元素还可以是子表,…。由此,广义表是一个多层次结构。以是子表,…。由此,广义表是一个多层次结构。

(2) (2) 广义表可以为其他广义表所共享。例如在上述广义表可以为其他广义表所共享。例如在上述例子中,广义表 例子中,广义表 AA、、 BB 和 和 CC 为 为 DD 的子表,则在 的子表,则在 DD

中可以不必列出广义表的值,而是通过子表的名称引用。中可以不必列出广义表的值,而是通过子表的名称引用。

(3) (3) 广义表可以是一个递归表,即广义表也可以是广义表可以是一个递归表,即广义表也可以是其本身的一个子表。例如广义表 其本身的一个子表。例如广义表 EE 就是一个递归的表。就是一个递归的表。

39

Page 40: 第 5 章  数组和广义表

和线性表相类似,可以对广义表进行的操作有和线性表相类似,可以对广义表进行的操作有查找、插入、删除和取表元素等。由于广义表在结构上查找、插入、删除和取表元素等。由于广义表在结构上较线性表复杂的多,因此,广义表操作的实现也不如线较线性表复杂的多,因此,广义表操作的实现也不如线性表简单。在这些操作中,最重要的两个基本操作是:性表简单。在这些操作中,最重要的两个基本操作是:

(1) (1) 取广义表表头 取广义表表头 GetHeadGetHead :表中的第一个元素:表中的第一个元素为此表的表头。为此表的表头。 (2) (2) 取广义表表尾 取广义表表尾 GetTailGetTail :表中除第一个元素外:表中除第一个元素外的其余元素组成的表为此表的表尾。的其余元素组成的表为此表的表尾。

40

3. 3. 广义表的两个基本操作广义表的两个基本操作

Page 41: 第 5 章  数组和广义表

(1) (1) AA = ( ) = ( ) (2) (2) BB = ( = (ee))

(3) (3) CC = ( = (aa, (, (bb, , cc, , dd)))) (4) (4) DD = ( = (AA, , BB, , CC))

(5) (5) EE = ( = (aa, , EE))

GetHead (GetHead (BB) = ) = ee GetTail (GetTail (BB) = ( )) = ( )

GetHead (GetHead (CC) = ) = aa GetTail (GetTail (CC) = (() = ((bb, , cc, , dd))))

GetHead (GetHead (DD) = ) = AA GetTail (GetTail (DD) = () = (BB, , CC))

由于 由于 ((BB, , CC) ) 为非空广义表,令为非空广义表,令 FF = ( = (BB, , CC)) ,,则可以继续分解得到:则可以继续分解得到: GetHead (GetHead (FF) = ) = BB GetTail (GetTail (FF) = () = (CC))

任何一个非空广义表的表头可能是原子,也可任何一个非空广义表的表头可能是原子,也可能是广义表;而其表尾必定是广义表。例如,广义表如能是广义表;而其表尾必定是广义表。例如,广义表如下:下:

对定义表 对定义表 BB ,, CC ,, DD 取表头和取表尾的操取表头和取表尾的操作结果:作结果:

41

Page 42: 第 5 章  数组和广义表

由于广义表(由于广义表( aa11, , aa22, … , , … , aann )中的数据元素)中的数据元素可以具有不同的结构(或是原子,或是广义表),因可以具有不同的结构(或是原子,或是广义表),因此很难用顺序结构表示,通常采用链式存储结构。在此很难用顺序结构表示,通常采用链式存储结构。在这种结构中,需要两种结构的结点。这种结构中,需要两种结构的结点。

42

5.4.2 5.4.2 广义表的存储结构广义表的存储结构