再议动态二维数组,通过一句表达式完成矩阵的转置

先来回顾一下通常动态二维数组的创建过程,这里以 m×n int数组为例

	int **pp=new int*[m];
	for(int i=0;i<m;++i)
		*(pp+i)=new int[n];

	//通过*(*(pp+i)+j)操作数组元素(i,j)

	for(i=0;i<m;++i)
		delete [] *(pp+i);
	delete [] pp;

这样的方式称为离散动态数组,主要存在两个缺点:

1. 数组储存区不连续;

2. 堆上空间释放比较麻烦。

图中以m=4,n=3为例。


所以我们寻求更好的代码:

	int *p=new int[m*n];
	int **pp=new int*[m];
	for(int i=0;i<m;++i)
		*(pp+i)=p+i*n;

	delete [] pp;
	delete [] p;

同样通过 *(*(pp+i)+j) 访问数组成员(i,j),先申请一段连续的空间,然后让指针数组保存它们的地址。

图中,m=4,n=3,这样做有两个好处:

1. 空间的释放更方便了;

2. 可以重新操作这段空间组成新数组。相较于第一种方式,其额外的开销仅是一个int*变量。


比如要把m×n个int所组成的空间段重分配为k×j的数组:

	delete [] pp;
	pp=new int*[k];
	for(int i=0;i<k;++i)
		*(pp+i)=p+i*j;

图中,以k=2,j=6为例。


通过观察代码,不难发现对于任意的i,都有

		*(pp+i)=p+i*n;

那么此时对于二维数组的操作事实上不需要二级指针的参与,只需一句表达式即可以用元素(i,j):

	int *p=new int[m*n];

	//*(p+i*n+j)——(i,j)

	delete [] p;

其实矩阵这个概念本来就是抽象的,把一个串拆分下并列着放就是矩阵了。对于这样的存储方式,可以很轻松的完成其转置,只要换一种引用方式:

                 *(p+i+j*n)

即可完成矩阵的“转置”操作。事实上根本没有矩阵,存在的只是在内存中的一块连续空间而已,不同的访问方式显示了这块内存段在我们大脑中不同的映射。

这里并不是按常规的思维方式,先形成一个二维数组,如A(m,n),然后填充,而是创建一个串,按某种规则写入数据,按某种规则读取数据。对于普通的矩阵操作,其读写规则为同一种。

而对于一个矩阵转置问题,其本质是,按某种规则写入数据,按另一种规则读取数据,而这两种规则的不同点反映出矩阵转置的概念。内存段没变,变的是它在我们大脑中映射的矩阵,或者更准确的说是映射的规则变了。


原文地址:https://www.cnblogs.com/silyvin/p/9106915.html