系列文章目录
文章目录
数组
定义
- 定义:数组是一组偶对(下标值,数据元素值)的集合,由n(n>1)个具有相同数据类型的数据元素a1,a2...,an组成的有序序列
- 类型:数组的数据元素具有相同的数据类型
- 下标:在数组中,对一组具有意义的下标,都存在一个与其对应的值
- 一维数组对应着一个下标值,二维数组对应两个下标值,如此类推
- 访问:数组是一种随机存储结构,给定一组下标,就可以访问与其对应的数据元素
- 数组中的数据元素的个数是固定的
数组的存储和寻址
存储方式
- 一般采用顺序存储的方法来表示数组
- 数组一般不做插入和删除操作数,数组一旦建立,结构中的元素个数和元素间的关系就不再发生变化
一维数组和高维数组
- 一维数组:A[n],每个数组元素占一个存储单元(不妨设为C个连续字节)。数组元素A[0]的首地址Loc(A[0]),则对于0≤i≤n-1,有:
Loc(A[i])=Loc(A[0])+i*C
- 高维数组:可转化为一维数组计算元素地址
- 高维数组有两种存放次序:按行优先顺序和按列优先顺序存储
行优先和列优先
- 按行优先顺序:将数组元素按行向量的顺序存储
- 第i+1个行向量存储在第i个行向量后
- BASIC、PASCAL、C/C++等程序设计语言中,数组按行优先顺序存放
- 按列优先顺序:将数组元素按列向量的顺序存储
- 第i+1个列向量存储在第i列向量后
- FORTRAN、Matlab中,数组按列优先顺序存放
示例 int x[2][3]
- 有 2×3个数组元素
x[0][0] x[0][1] x[0][2]
x[1][0] x[1][1] x[1][2]
- 按行优先顺序存放,存储分配顺序为:
x[0][0]→x[0][1]→x[0][2]→x[1][0]→x[1][1]→x[1][2]
- 按列优先顺序存放,存储分配顺序为:
x[0][0]→x[1][0]→x[0][1]→x[1][1]→x[0][2]→x[1][2]
二维数组
- 二维数组可以看作是一种特殊的一维数组。如 float a[3][4]
- 二维数组(m×n)中元素a[i][j]的地址:(假设一个元素占C个存储空间)
Loc(a[i][j])= Loc(b[i])+ j*C
Loc(b[i]) = Loc(b[0])+ i*C
Loc(a[i][j])= Loc(a[0][0]) + i*n*C + j*C = Loc(a[0][0])+ (i*n + j)*C
多维数据
- 多维数组元素在内存排列顺序为:第一维的下标变化最慢,最右边的维的下标变化最快
示例:float a[2][3][4]
- a[i1][i2]......[in]的存储地址(行优先,每一行的数量分别是mp,p={1,2,.....,n})
- a[i1][i2]....[in]的存储地址,行优先
- a[i1][i2]....[in]的存储地址,列优先
自定义数组
- 直接创建数组的局限
- 无法对数组执行一些简单的运算,如数组加法和数组剑法等操作
- 没有越界索引保护,不检查数组的下标索引值是否在0到arraysize-1范围内。例如一些高级程序设计语言对越界访问并不一定产生异常。没有越界保护会直接给程序调试带来难以预料的困难
- 数组类型时高级程序设计语言所提供的基本数据类型之一,可定义一组相同类型的元素
- 重载一些必要的运算符
- 重载对下标符号“[ ]”
- 提供越界保护
矩阵
- 矩阵时许多物理问题中出现的数学对象,是一种常用的数据组织方式。计算机工作者关心的是矩阵在计算机中如何储存,以及如何实现矩阵的基本操作
- 二维数组与矩阵相比
- 数组的基本操作是数组加减,而矩阵的基本操作还有矩阵相乘、矩阵转置等
- 数组的下标从0开始,而矩阵的下标一般从1开始
- 数组元素用a[i][j]表示,而矩阵元素一般用a(i,j)表示
矩阵相乘
- 对于矩阵和矩阵的乘积,其i行j列元素cij的计算公式为
- 有两种方法:
- Multi-1:矩阵和直接相乘
- Multi-2:矩阵和转化为一维数组再乘
算法Multi-1
for i = 0 TO m DO
for j = 1 TO n DO
cij = 0
for k = 1 TO p DO
cij += Aij * Bkj
算法Multi-2
- 将矩阵转化为一维数组,按行优先
- 用一维数组s 存放
- 用一维数组t存放
- 求存放A与B的乘积的一维数组w
- 定位
- cs为A中i行k列元素的下标,则A中i行k+1列的元素下标为cs+1
- ct为B中k行j列元素的下标,则B中k+1行j列元素的下标为ct+n
cw = 0
for i = 1 TO m Do
cs = (i-1)*p
for j = 1 TO n DO
ct = j - 1
w[cw] = 0
for k = 1 TO p DO
w[cw] += s[cs]*t[ct]
cs += 1
c t += n
cw += 1
两种算法都包含了三层for循环,所以其时间复杂性为O(m*n*p)
矩阵压缩
- 矩阵存储:可以存在一维数组中
- 局限:特殊的矩阵可能浪费存储空间
- 对称矩阵
- 三角矩阵
- 对角矩阵
- 稀疏矩阵
- 解决办法:矩阵压缩
对角矩阵
- 定义:对n*n的对角矩阵M所有的 i ≠ j (1 ≤ i,j ≤ n)都有M(i,j)= 0,即非对角线上元素均为0
- 对于一个n*n的对角矩阵,至多只有n个非零元素,因此只需存储n个对角元素的信息。采用一维数组d[n]来压缩存储对角矩阵,其中d[I]存储M[i,i]的值
三角矩阵
- 三角矩阵分为上三角矩阵和下三角矩阵
- 方阵M是上三角矩阵,当且仅当 i >j是有M(i,j)= 0
- 方阵M是下三角矩阵,当且仅当 i <j是有M(i,j)= 0
- 分析(以下三角矩阵为例)
- 将下三角矩阵映射为一个一维数组d需要n(n+1)/2个元素
- 解决思路
- 设元素M(i,j)前面有k个元素,可以计算出
- k = 1+2+...+(i-1)+(j-1) = i(i-1)/2 + (j-1)
- 设一维数组d的下标是从0开始,则M(i,j)映射到d中所对应的元素是a[k]
- 有了k的计算公式,可以很容易实现下三角矩阵的压缩存储
- 设元素M(i,j)前面有k个元素,可以计算出
对称矩阵
- 分析
- 对称矩阵映射为一个一维数组需要n(n+1)/2
- 解决思路
- 下三角矩阵, i ≥ j,映射到d[k],k = i(i-1)/2 + (j-1)
- 上三角矩阵, i<j,映射到d[q],q = i(2n-i+1)/2+ j-i
稀疏矩阵
- 定义:设矩阵中非零元素个数远远小于令其元素的个数,则称A为稀疏矩阵
- 特点:零元素的分布一般没有规律,无法简单利用一维数组和映射公式来实现其压缩存储
- 作用:仅存储非零元素,节省空间
- 稀疏矩阵压缩存储方法:
- 存储行号和具体值
- 示例对aij其存储形式为
对aij其存储由三元组结点(i,j,aij)组成
- 在三元组结点的基础上实现对整个稀疏矩阵的存储
- 顺序存储方法实现的三元组表
- 链接存储方式实现的十字链表
三元组表
示例:稀疏矩阵A及其对应的三元组B
算法Transpose(a,b)
j = 0
if aount <=0 return;
for k = 1 TO n DO
for i = 0 TO count-1 DO
if col(a[i]) = k
row(b[j]) = k
col(b[j]) = row(a[i])
val(b[j]) = value(a[i])
j + = 1
对于一个用三元组表存储的稀疏矩阵 ,若矩阵非零元素个数为t,则转置为一维数组的时间复杂度为O(nt)
- 分析:矩阵的算法描述较为简单,但对于非零元的位置或个数经常发生变化的矩阵运算就显得不太合适
- 示例:执行将矩阵B相加到矩阵A上的运算时,某位置上的结果可能会由非零元变为零元,但也可能由零元变为非零元,这就会引起在A的三元组表中进行删除和插入操作,从而导致大量的结点移动
十字链表
- 十字链表对稀疏矩阵的元素结构表示:分别表示该元素的左邻非零元素、上邻非零元素、所在的行、所在的列和它的值
- 矩阵的每一行、每一列都设置为由一个表头结点引导的循环链表,并且各行各列的表头结点有如下特点:
-1 = COL(loc(Baserow[i]))<0
-1 = ROW(loc(Basecol[i])) <0
- 若某行没有非零元素,则Left(Baserow[i]) = Baserow[i],若某一列没有非零元素,则UP(BASECOL[i]) = BASECOL[i]
- 分析:假设A和B都采用十字链表存储,A=A+B的结果有三种:
- aij+bij ≠ 0:改变结点的VAL阈值
- aij+bij = 0:删除一个结点
- aij(bij=0):不变
- bij(aij=0):插入一个结点