分析:
矩阵转置操作:就是将原来矩阵的行变成列。
如: A矩阵的转置为:
该数组在内存中的存放为A[8]={1,2,3,4,5,6,7,8}. 其实如果是方阵的话,就会很简单,因为转置只会是两两元素交换位置就可以实现,因为是对称的。但是针对非方阵的矩阵。问题就要复杂一些。以上面的矩阵为例。
1转置后还是原来位置, 下标0->0
2转置后到了原来5的位置,因为不能用额外空间,所以5的位置不能直接被覆盖,我们需要寻找5需要交换的位置,5交换到原来3的位置。同样来跟踪下标得到:
1->4->2->1.同理可以推出其它元素的交换过程。
A[0]->[0]
A[1]->A[4]->A[2]->A[1]
A[3]->A[5]->A[6]->A[3]
A[7]->A[7]
这样的话, 就整个矩阵就完成了转置,可以有for循环来遍历数组进行交换。如果编程来实现的话,就会发现如果确定某个元素已经被交换过,是实现的关键。需要找出这其中的规律。发现有两点规律如下:
(1)发现每一次交换过程,都形成了循环链。
(2)如果元素在某一次交换过程中,已经交换过了,那么一定是可以找到比他下标要小的后继。换句话理解就是第一次防问需要交换的元素下标,一定是这个交换链中最小的下标。
证明这两点规律才能保证算法的正确性:
(1)因为没有额外的空间,在原来的数组上进行交换,所以元素交换一定会形成循环链。这是显而易见的,假设A[X]->A[Y]->A[Z].....->A.[K] ,A[K] 一定是会回到A[X]。因为没有其它空间存放。
(2)因为遍历数组,是从下标0开始扫描, 且元素都只需交换一次。所以每次遇到的第一个需要交换的元素,交换到任何位置,其下标都会是最小的。
求交换后继下标:
MXN 的矩阵,转置后变成NXM矩阵。下标为i的元素转换成原始矩阵的表示则为row= i / N; line=i%N; 然后转置后的行变列,列变行。A[row][line]->A[line][row] ,转置矩阵为NxM ,再转换成一维数组的下标:(i / N) + (i % N)*M;
源代码如下:
#include<iostream>
using namespace std;
/*
*function: 取得当前元素需要交换元素的下标
*parameter: currentIndex:当前元素下标
* row:原始矩阵的行
* line:原始矩阵的列
*/
int getNextCursor(int currentIndex ,int row,int line)
{
return (currentIndex % line) * row + ( currentIndex / line ) ;
}
/*
*function: 从当前没有被交换的元素开始执行交换,完成整个环上的交换
*parameter: a:数组名
* row:原始矩阵的行
* line:原始矩阵的列
* i:开始元素下标
*/
void exchange(int a[],int row,int line,int i)
{
int nextCursor = getNextCursor(i,row,line);
while(nextCursor != i)
{
a[i] = a[i]^a[nextCursor];
a[nextCursor] = a[i]^a[nextCursor];
a[i] = a[i]^a[nextCursor];
nextCursor = getNextCursor(nextCursor,row,line);
}
}
void showMatrix(int a[],int row,int line)
{
for(int i = 1 ; i <= row*line;i++)
{
cout<<a[i-1]<<" ";
if(i % line == 0)
cout<<endl;
}
}
void matriTransport(int a[],int row,int line)
{
int nextCursor;
for(int i=0; i< row*line;i++)
{
nextCursor = getNextCursor(i,row,line);
while( i < nextCursor )
{
nextCursor = getNextCursor(nextCursor,row,line);
}
if( i == nextCursor)
exchange(a,row,line,i);
}
}
int main()
{
int a[8]={1,2,3,4,5,6,7,8};
showMatrix(a,4,2);
matriTransport(a,4,2);
cout<<"after matrix transport:"<<endl;
showMatrix(a,2,4);
while(1);
return 0;
}