《数据结构(C语言版)》学习笔记04 数组和矩阵、广义表

目录

一、普通矩阵存储

1.1 一维数组

1.2 二维数组

二、特殊矩阵存储

2.1 对称矩阵

2.2 三角矩阵

2.3 三对角矩阵

2.4 稀疏矩阵

三、广义表@20221030


一、普通矩阵存储

1.1 一维数组

前面介绍线性表时,顺序表的最大特性就是随机存取,而那正是通过数组来实现的,随机存取是数组本身的性质。

原因在于,一维数组在内存中的地址是顺序排列的,即有数组下标为 i 的元素的地址 LOC(i) = 首地址 + i * sizeof(数据类型)。比如,int a[3],其中 a[0] = a,a[1] = a + 1*4,a[2] = a + 2*4,a[3] = a + 3*4。

1.2 二维数组

二维数组和一维数组本质上是类似的,虽然看起来逻辑上有行优劣,但是实际上它们所占用的内存空间也是连续的。根据排列的不同,又分为行优先存储和列优先存储:

行优先存储,即按照行的顺序进行存储,例如 a[2][3] 的存储顺序为 a[0][0],a[0][1],a[0][2],a[1][0],a[1][1],a[1][2]。即一行一行存储。此时 a[i][j] 的地址 LOC(i,j) = a + (i*总列数 + j)*数据类型大小。(因为一行的元素等于总列数,一共 i 行又 j 个)。

列优先存储,即按照列的顺序进行存储,例如 a[2][3] 的存储顺序为 a[0][0],a[1][0],a[0][1],a[1][1],a[2][0],a[2][3]。即一列一列存储。此时 a[i][j] 的地址 LOC(i,j) = a + (j*总行数 + i)*数据类型大小。(因为一列的元素等于总行数,一共 j 列又 i 个)。

二、特殊矩阵存储

2.1 对称矩阵

学过线性代数的话,应该对对称矩阵很了解,即矩阵转置等于矩阵本身,所描述的特征为 aij = aji,即矩阵内所有元素关于主对角线对称。此时就不再需要一个二维数组存储矩阵的 n*n 个元素,只需要存储主对角线加半个三角区的元素即可。再者因为二维数组只用约一半的空间,会造成空间浪费,所以采用一维数组压缩存储。

每种存储方式对应的下标映射方式已经在思维导图里了,这里仅用行优先存下三角举个例子。

如果按照行优先存储只存下三角矩阵,那么矩阵的第一行需要存一个元素,第二行需要存两个元素,第 x 行需要存 x 个元素。也因此,一共要存 n(n+1)/2 个,即数组容量。aij 在 i 行 j 个位置,在第 i 行之前的元素个数为 1+2+3+...+(i-1) = i(i-1)/2个,另外还需包括第 i 行的 j 个,即 aij 在数组中的位置是 i(i-1)/2+j,对应的数组下标再减一即可。

2.2 三角矩阵

刚才探讨只存三角区的时候,其实思路和这部分是一样的。三角矩阵所不同的是,在上三角或下三角的所有元素都相同,即要存储的数据只有主对角线+上三角或下三角+1个其他元素。所以数组容量为 n(n+1)/2+1。其他的都和前面相同了。

2.3 三对角矩阵

从概念上来说,三对角矩阵并不太好想象,所以这里放个图。 

可以发现,除了第一行和最后一行为两个元素之外,其他每行都在主对角线及其两侧分布了三个元素,其他位置全为0。

也因此,总元素个数为 3*n-2。aij 在第 i 行 j 列,前 i-1 行共有 3(i-1)-1 个元素,第 i 行还存了 j-i+2 个元素(第三行有一个零是不存的,第四行有两个零是不存的,第 x 行有 x-2 个零是不存的,所以第 i 行有 i-2 个零是不存的),所以 aij 在数组中的第 3(i-1)-1+j-i+2 = 2i+j-2 个位置,对应数组下标再减一。

由此衍生的问题为,下标为 k 的元素在矩阵中的哪行哪列?

下标为 k 的元素是第 k+1 个元素,假设它在第 i 行 第 j 列,根据上面的公式我们知道下标 k = 2i+j-3,所以只要知道 i,j 就能直接算了。

那么在第 i 行前有 3(i-1)-1 个元素,第 k+1 个元素肯定不在这个范围里,k+1>3(i-1)-1;

加上第 i 行的元素一共有 3i-1 个,第 k+1 个元素肯定在这里面,k+1<=3i-1;

由此解出 (k+2)/3 <= i < (k+5)/3,可以发现左右区间刚好差 1。当左区间为整数的时候,i 就等于左区间,而当左区间不为整数的时候,i 等于大于左区间的最小整数。这正是向上取整所描述的功能。

即 i = ceil( (k+2)/3 )。

其他的计算方法请参考思维导图。

2.4 稀疏矩阵

稀疏矩阵就是比较稀疏的矩阵,但是“稀疏”毕竟只是主观印象,教材中这样描述,仅供参考:

假设在mxn的矩阵中,有t个元素不为零。令δ=t/(mxn),称δ为矩阵的稀疏因子。通常认为δ<=0.05时称为稀疏矩阵。 

 要存储一个稀疏矩阵,通常有两种办法:

第一,用一个三元组的数组来存,即创建一个结构体包含非零元的行号、列号、数值,再用这个结构体创建一个数组。这样一来,便会失去矩阵随机存取的特性,同时在进行矩阵操作时带来较大的时间开销(例如转置、相加相乘等,都需要对数组进行增删改查操作)。

第二,用十字链表来存,所谓十字链表就是一个行链表和一个列链表。每个结点包含五个域,分别为行号、列号、数值、指向同行下一个非零元的指针 *right、指向同列下一个非零元的指针 *down。这里就不做展开描述了(好像不怎么考,先不管了)。

三、广义表@20221030

广义表是线性表的推广,其一般形式为 LS=( a1, a2, ..., an)

其中,LS 是广义表的名称,n 是其长度。a1 可以是单个元素,也可以是广义表,分别成为广义表的原子和子表。当 LS 非空时,称第一个元素 a1 为 LS 的表头,称其余所有元素组成的表 ( a2, ..., an) 为 LS 的表尾。当表空时,长度为 0。

广义表的深度定义为广义表中括号的重数,例如 A=(a, (b, c, d)) 的深度为 2。

关于广义表的操作,主要有取头(Head)和取尾(Tail)。

对于一个非空广义表 L 来说,

Head(L) 将会取出表中第一个元素(原子或者子表);

Tail(L) 将会取出表中除第一个元素外的所有元素,组成一个广义表并返回。

如 L= ( 1, 2, 3, (4) ),Head(L) = 1,Tail(L) = ( 2, 3, (4) )。

又如 L= ((), ()),Head(L) = (),Tail(L) = (())。

==总结==

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值