您的位置:首页 > 其它

矩阵原地转置算法

2015-12-19 11:05 281 查看
        这个面试题要求现场写程序。

        题目描述非常简单:给一个m*n的矩阵,要求实现矩阵的转置,不要额外开辟内存空间。

        题目分析:

        如果可以开辟额外内存空间,我们可以申请一个n*m的矩阵,然后挨个将矩阵元素放入转置之后的位置。但题目明确指出不能开辟额外内存空间,显然,最简单的实现就是,使用一个一维数组保存原来的矩阵(行优先,即一行一行的保存矩阵,其实在各个编译器中,这是最常见的保存方式),然后在这个一维数组上实现元素位置的变化。变化后,一行一行的读取一维数组时,读出的即是转置后的矩阵的行。下面举个栗子,看这个图,介绍了整个过程:

 初始矩阵如下



这个矩阵中,每个数字的下标表示这个数字在一维数组中的保存序号。经过转置后,矩阵应该如下:



        同样的,每个数字的下标表示这个数字在一维数组中保存的序号。虽然形象来看,转置后,矩阵应该这个样子,可是仍然按照一维数组保存和表示。大家脑海里应该都有这个影像。

        通过这个栗子,我们可以看到,实际上,我们只需要对这个一维数组中的元素进行交换,即可达到目的。可是该怎么变换呢?

        我们先来看看这些数字的位置是如何变化的。下面我们先把位置变化列举出来:

                                                                        0  to 0       5 to 1       10 to 2

                                                                        1  to 3       6 to 4        11 to 5

                                                                        2   to 6      7 to 7        12 to 8

                                                                        3   to 9      8 to 10      13 to 11

                                                                        4   to 12    9 to 13       14 to 14

        猛一看,这不是稍微有点规律吗!直接将0、1、2、3、4的数字分别移动到0、3、6、9、12,将5、6、7、8、9分别移动1、4、7、10、13,将10、11、12、13、14移动到2、5、8、11、14不就可以吗?但是存在一个问题,将1位置的数放入3位置,这样就会覆盖3位置原来的数字,3位置的数字是需要放到9的,而也不能提前将3位置的数放到9位置,因为9位置也有数,那个数需要放到13位置的。下面我们看看这是怎么样一个放置的过程:

        1 to 3, 3 to 9, 9 to 13, 13 to 11, 11 to 5, 5 to 1

        童鞋们,发现没有经过一个循环,最后又回到了1。这说明,其实变化的过程是个循环!如果按照这个顺序变化,肯定是不可以的了,因为要将1中的数组放到3,必须先将3中数字放入9,......,循环到最后,发现必须先将1中数字放入3才能解决5中数字的放置问题。

        看到这个问题想到了什么?对!我们应该反着来,反个顺序移动!先将1中的数字放入临时变量,然后将5中的数字放入1,再将11中数字放入5,......,最后将1放入3位置。这样不就可以完美解决了吗?是的,然后再分别将2、3、4这几个数也按照刚才的流程变化位置。这样这个矩阵就完成了转置!

        下面是我自己实现的一个简单实现的代码:

public class App {
public void rotateArray(int[] array, int rowNum, int columnNum) {
int maxValue = -1;
for (int i = 0; i < array.length; i++){
if (maxValue < array[i]){
maxValue = array[i];
}
}
maxValue += 1;

for (int i = 0; i < array.length; i++) {
if(array[i] >= maxValue){
continue;
}
int rowOri = i / columnNum, columnOri = i % rowNum;
if (rowOri == columnOri) {
array[i] += maxValue;
continue;
}

int startRow = columnOri, startColumn = rowOri;
int rowMoveTo = columnOri, columnMoveTo = rowOri;
int newColumnNum = rowNum;
int moveValue = array[i];

while(rowMoveTo != startColumn || columnMoveTo != startRow){
int offset = rowMoveTo * newColumnNum + columnMoveTo;
int tmpValue = array[offset];
array[offset] = moveValue;
array[offset] += maxValue;

rowOri = offset / columnNum;
columnOri = offset % columnNum;
rowMoveTo = columnOri;
columnMoveTo = rowOri;
moveValue = tmpValue;
}
array[i] = moveValue + maxValue;
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: