8  多维数组

在实际应用的过程中,经常需要构造多于二维的数组,我们将多于二维的数组统称为多维数组。

对于二维数组,人们习惯于把数组的第1维称为“行”,把第2维称为“列”,我们将第3维称为“页”。

由于更多维的数组的显示并不直观,所以本节以三维数组为例来介绍多维数组的使用。

8.1  多维数组的创建

创建多维数组最常用的方法有以下4种。

(1)直接通过“全下标”元素赋值的方式创建多维数组。

(2)由若干同样尺寸的二维数组组合成多维数组。

(3)由函数ones、zeros、rand、randn等直接创建特殊多维数组。

(4)借助cat、repmat、reshape等函数构建多维数组。

【例2-26】  采用“全下标”元素赋值方式创建多维数组示例。

>> A(3,3,3)=1                %  创建3*3*3数组,未赋值元素默认设置为0

0     0    0

0     0    0

0     0    0

0    0     0

0     0    0

0     0    0

0     0    0

0     0    0

0     0    1

>> B(3,4,:)=1:4              % 创建3*4*4数组

0     0    0     0

0     0    0     0

0     0    0     1

0     0    0     0

0     0    0     0

0     0    0     2

0     0    0     0

0     0    0     0

0     0    0     3

0     0    0     0

0     0    0     0

0     0    0     4

【例2-27】  由二维数组合成多维数组示例。

>> clear

>> A(:,:,1)=magic(4);                %  创建数组A第1页的数据

>> A(:,:,2)=ones(4);                 %  创建数组A第2页的数据

>> A(:,:,3)=zeros(4)                 %  创建数组A第3页的数据

16     2    3    13

5    11   10     8

9    7     6    12

4    14   15     1

1     1    1     1

1     1    1     1

1     1    1     1

1     1    1     1

0     0    0     0

0     0    0     0

0     0    0     0

0     0    0     0

【例2-28】  由函数rand直接创建特殊多维数组示例。

>> rand('state', 0);        % 设置随机种子,便于读者验证

>> B=rand(3,4,3)

0.9501    0.4860    0.4565   0.4447

0.2311    0.8913    0.0185   0.6154

0.6068    0.7621    0.8214   0.7919

0.9218    0.4057   0.4103    0.3529

0.7382    0.9355    0.8936   0.8132

0.1763    0.9169    0.0579   0.0099

0.1389    0.6038    0.0153   0.9318

0.2028    0.2722    0.7468   0.4660

0.1987    0.1988    0.4451   0.4186

【例2-29】  借助cat函数构建多维数组示例。

>>B=cat(3,ones(2,3),ones(2,3)*2,ones(2,3)*3)

1     1    1

1     1    1

2     2    2

2     2    2

3     3    3

3     3    3

cat指令第1个输入变量填写的数字“表示扩展方向的维号”。本例第1个输入变量是3,表示“沿第3维方向扩展”。为了对比下面我们分别演示使用cat函数沿其他方向进行扩展的情况。

>>B=cat(2,ones(2,3),ones(2,3)*2,ones(2,3)*3)        % 沿第2维方向扩展

1    1     1     2    2     2     3    3     3

1    1     1     2    2     2     3    3     3

>>B=cat(1,ones(2,3),ones(2,3)*2,ones(2,3)*3)       % 沿第1维方向扩展

1    1     1

1    1     1

2    2     2

2    2     2

3    3     3

3    3     3

>>B=cat(4,ones(2,3),ones(2,3)*2,ones(2,3)*3)       % 沿第4维方向扩展

B(:,:,1,1) =

1    1     1

1    1     1

B(:,:,1,2) =

2    2     2

2    2     2

B(:,:,1,3) =

3    3     3

3    3     3

【例2-30】  借助repmat函数构建多维数组示例。

>> repmat([1,2;3,4;5,6],[1,2,3])

ans(:,:,1) =

1     2    1     2

3     4    3     4

5     6    5     6

ans(:,:,2) =

1     2    1     2

3     4    3     4

5     6    5     6

ans(:,:,3) =

1     2    1     2

3     4    3     4

5     6    5     6

repmat函数的第1个输入变量是构成多维数组的源数组。第2个输入变量是指定向各维方向上扩展的源数组个数。本例中输入变量[1,2,3]是指将源数组在行方向上扩展为1个,在列方向上扩展为2个,在页方向上扩展为3个。

【例2-31】  借助reshape函数构建多维数组示例。

>> A=reshape(1:60,5,4,3)

1     6   11    16

2     7   12    17

3     8   13    18

4     9   14    19

5    10   15    20

21    26   31    36

22    27   32    37

23    28   33    38

24    29   34    39

25    30   35    40

41    46   51    56

42    47   52    57

43    48   53    58

44    49   54    59

45    50   55    60

>> B=reshape(A,4,5,3)

1     5    9    13    17

2     6   10    14    18

3     7   11    15    19

4     8   12    16    20

21    25   29    33    37

22    26   30    34    38

23    27   31    35    39

24    28   32    36    40

41    45   49    53    57

42    46   50    54    58

43    47   51    55    59

44    48   52    56    60

reshape的第1个输入变量是源数组,第2、3、4个输入变量是要生成的数组的行数、列数和页数。将要生成的数组必须和源数组的元素的个数相同。重组时,元素排列遵循“单下标”编号规则:第1页的第1列接该页的第2列,直至第1页最后一列。在第1页排列结束后,开始排列第2页的第1列,依次类推,直至所有的元素排列结束。

8.2 多维数组的寻访与重构

1.多维数组的寻访

多维数组的寻访和二维数组一样,可以使用“全下标”、“单下标”和“逻辑下标”来寻访。“全下标”和“逻辑下标”两种形式与二维数组相同,是以非常直观的形式来表现的,这里不再赘述。而多维数组的“单下标”就比较复杂一点。本小节对此进行介绍。

多维数组的“单下标”其实就是二维数组“单下标”的扩展,换句话说,二维数组的“单下标”编排方式是“单下标”的一种简单形式。用语言表示就是:将数组“全下标”格式中的各维按照出现的先后顺序依次循环,直至将所有的数据编排成为一列。

【例2-32】  多维数组“单下标”排列示例。

>> a=ones(2,2,2,2)             % 创建全为1的2*2*2*2四维数组a

a(:,:,1,1) =

1     1

1     1

a(:,:,2,1) =

1     1

1     1

a(:,:,1,2) =

1     1

1     1

a(:,:,2,2) =

1     1

1     1

>> a(1:16)=1:16                %  按照单下标形式为数组a赋值

a(:,:,1,1) =

1     3

2     4

a(:,:,2,1) =

5     7

6     8

a(:,:,1,2) =

9    11

10    12

a(:,:,2,2) =

13    15

14    16

从得到结果中的数组a被赋值以后的各元素分布,可以看出多维数组是如何按照“全下标”的各维顺序来存储数据的。

2.多维数组的重构

除了前面介绍的可以用来进行多维数组的重构函数cat、repmat和reshape之外,还有其他一些函数可用来进行多维数组的重构,详见表2-10。

表2-10     多维数组重构函数

函数形式

函数功能

函数形式

函数功能

广义非共轭转置

以指定维交换对称位置上的元素

广义反转置,permute的反操作

维移动函数

【例2-33】  多维数组元素对称交换函数flipdim使用示例。

>> A=reshape(1:18,2,3,3)            % 创建演示三维数组

1     3    5

2     4    6

7     9   11

8    10   12

13    15   17

14    16   18

>> B=flipdim(A,1)                    %  以第1维进行对称变换

2     4    6

1     3    5

8    10   12

7     9   11

14    16   18

13    15   17

>> C=flipdim(A,3)                    %  以第3维进行对称变换

13    15   17

14    16   18

7     9   11

8    10   12

1     3    5

2     4    6

从本例可以看出,函数flipdim(A,k)中的输入变量k就是指进行对称变换的维。另外flipdim(A,k)函数也可用于二维数组,读者可以自行验证。

【例2-34】  多维数组元素维移动函数shiftdim使用示例。

本例在上例所建立的三维数组A上进行演示。

>> D=shiftdim(A,1)      %  将各维向左移动1位,使2*3*3数组变成3*3*2数组

1     7   13

3     9   15

5    11   17

2     8   14

4    10   16

6    12   18

>> E=shiftdim(A,2)      %  将各维向左移动2位,使2*3*3数组变成3*2*3数组

1     2

7     8

13    14

3     4

9    10

15    16

5     6

11    12

17    18

运算D=shiftdim(A,1)实现以下操作:D(j,k,i)=A(i,j,k),i, j, k分别是指各维的下标。对于三维数组,D=shiftdim(A,3)的操作就等同于简单的D=A。

【例2-35】  多维数组元素广义非共轭函数permute使用示例。

本例在上例所建立的三维数组A上进行演示。

>> F=permute(A,[3 2 1])

1     3    5

7     9   11

13    15   17

2     4    6

8    10   12

14    16   18

>> G=permute(A,[3 1 2])

1     2

7     8

13    14

3     4

9    10

15    16

5     6

11    12

17    18

运算F=permute(A, [3 2 1])实现以下操作:F(k,j,i)=A(i,j,k),i, j, k分别是指各维的下标。函数permute就是函数shiftdim的特殊形式,它可以任意指定维的移动顺序。