对于数组A,一旦给定其维数n及各维长度bi(1≤i≤n),则该数组中元素的个数是固定的,不能对数组做插入和删除操作,不涉及移动数据元素操作,因此对于数组而言,采用顺序存储方式比较合适。
我们知道,计算机内存器的结构是一维的,因此对于一维数组按下标顺序分配即可,而对多维数组,就必须按照某种次序,将数据元素排成一个线性序列,然后将这个线性序列存放在存储器中。
数组的顺序存储结构有两种:一是以行为主序(或先行后列)的顺序存放,如BASIC、PASCAL、COBOL、C等程序设计语言中用的是以行为主的顺序分配,即一行分配完了接着分配下一行。另一种是以列为主序(先列后行)的顺序存放,如FORTRAN语言中,用的是以列为主序的分配顺序,即一列一列地分配。以行为主序的分配规律是:最右边的下标先变化,即最右下标从小到大,循环一遍后,右边第二个下标再变,…,从右向左,最后是左下标。以列为主序分配的规律恰好相反:最左边的下标先变化,即最左下标从小到大,循环一遍后,左边第二个下标再变,…,从左向右,最后是右下标。
例如,二维数组Am×n以行为主序的存储序列为:
a00 ,a01 ,… ,a0,n-1 ,a10 ,a11 ,…,a1,n-1 ,…am-1,0 ,am-1,1 ,…am-1,n-1
而以列为主序的存储序列为:
a00 ,a10 ,… ,am-1,0 ,a01 ,a11 ,…,am-11 ,…a0,n-1 ,a1,n-1 ,…am-1,n-1
例如一个2×3的二维数组,逻辑结构可以用图4-8(a)表示。以行为主序的内存映象如图4-8(b)所示。 分配顺序为:a00 ,a01 ,a02 ,a10 ,a11 ,a12 ; 以列为主序的分配顺序为:a00 ,a10 ,a01 ,a11 ,a02 ,a12 ;它的内存映象如图4-8(c)所示。
![数组的顺序存储和实现 1](https://i-blog.csdnimg.cn/blog_migrate/a4c26d1e5885305701be709a3d33442f.gif)
图4-8 2×3数组存储(a)逻辑状态(b)以行为主序(c)以列为主序
假设有一个3×4×2的三维数组A,共有24个元素,其逻辑结构如图4-9所示。
![数组的顺序存储和实现 2](https://i-blog.csdnimg.cn/blog_migrate/a4c26d1e5885305701be709a3d33442f.gif)
图4-9 三维数组的逻辑结构
三维数组元素得标号由三个数字表示。如果对A3×4×2采用以行为主序的方式存放,则顺序为:
a000 ,a001 ,a010 ,a011 ,… ,a220 ,a221 ,a230 ,a231
采用以列为主序的方式存放,则顺序为:
a000 ,a100 ,a200 ,a010 ,… ,a221 ,a031 ,a131 ,a231
以上的存放规则可推广到多维数组的情况。总之,知道了多维数组的维数,以及每维的上下界,就可以方便地将多维数组按顺序存储结构存放在计算机中了。同时,根据数组的下标,可以计算出其在存储器中的位置。因此,数组的顺序存储是一种随机存取的结构。
下面,以“以行为主序”的分配为例,讨论数组中数据元素存储位置的计算。
设有二维数组Am×n,,下标从0开始,假设每个数组元素占size个存储单元,首元素a00的存储地址为LOC[0,0],对任意元素aij来说,因为aij是排在第i行,第j列,前面的i行有n×i个元素,第i行第j列个元素前面还有j个元素,所以,可得aij的地址计算公式如下:
LOC[i,j] = LOC[0,0] + ( i×n + j ) × size
同理,对三维数组Ar×m×n,可以看成是r个m×n的二维数组,若首元素的存储地址为LOC[0,0,0],则元素ai11的存储地址为LOC[i,1,1] = LOC[0,0,0] + ( i×m×n ) × size,这是因为在该元素之前,有i个m×n的二维数组。由ai11的地址和二维数组的地址计算公式,不难得到三维数组任意元素aijk的地址计算公式:
LOC[i,j,k] = LOC[0,0,0] + ( i×m×n + j×n+k ) × size
其中0≤i≤r-1,0≤j≤m-1,0≤k≤n-1。
数组是各种高级语言中已经实现的数据结构。在高级语言的应用层上,一般不会涉及到数据元素的存储地址的计算,这一计算内存地址的任务是由高级语言的编译系统完成的。当我们使用数组进行程序设计时,只需给出数组的下标范围,编译系统将根据用户提供的必要参数进行地址分配,存取数据元素时,也只要给出下标,而不必考虑其内存情况。
例4-1 若矩阵Am×n 中存在某个元素aij满足:aij是第i行中最小值且是第j列中的最大值,则称该元素为矩阵A的一个鞍点。试编写一个算法,找出A中的所有鞍点。
基本思想:在矩阵A中求出每一行的最小值元素,然后判断该元素它是否是它所在列中的最大值,是则打印出,接着处理下一行。矩阵A用一个二维数组表示。
算法如下:
void saddle (int A[ ][ ],int m, int n) //m,n是矩阵A的行和列
{ int i,j,min;
for (i=0;i
{ min=A[i][0]
for (j=1; j
if (A[i][j]
for (j=0; j
if (A[I][j]==min )
{ k=j; p=0;
while (p
p++;
if ( p>=m) printf ("%d,%d,%d\n", i ,k,min);
}
}
}