矩阵转置,空间复杂度要求为O(1)

分析:

矩阵转置操作:就是将原来矩阵的行变成列。

如: 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;
}


 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值