具有一个for循环的矩阵的就地转置

时间:2016-03-17 15:41:18

标签: c loops matrix transpose

我的老师问我们是否可以只使用一个" for循环转换矩阵"在C中,我们不应该使用额外的空间(比如将矩阵运送到另一个数组)。该算法应该与非平方矩阵一起使用。这可能吗?

编辑:使用"不应该使用额外的空间"我的意思是分配一个新矩阵并复制矩阵的某些部分。这些是不允许的。

2 个答案:

答案 0 :(得分:2)

要转换矩阵,您需要在矩阵内部交换迭代。可以使用基于exor操作的交换算法,允许交换而不使用附加存储。

void swap(int *a, int *b)
{
    *a = *a^*b;
    *b = *a^*b;
    *a = *a^*b;        
}

答案 1 :(得分:2)

因为两个矩阵的尺寸可能不同,所以矩阵的数据必须存储在一维数组中。

(在C中,数据通常按行主顺序排序,因此对于rows - 行,cols - 列矩阵,索引i对应于行{{1 },列rc。索引从零开始,因此i = r*cols + c0 <= i < rows*cols0 <= c < cols。相应地,索引0 <= r < rows是在行i,列i/cols,其中`%'是C模运算符。)

考虑如何转置矩阵,以及数据顺序在内存中的变化:

i % cols

对于所有方形矩阵,您只需要交换右上角三角形中的元素,左下角三角形中的对应元素。因此,对于 N × N 方阵,您只需要 N N -1)/ 2个交换

(单个for循环,2x2: A B = A B C D C D becomes A C = A C B D B D 3x3: A B C = A B C D E F G H I D E F G H I becomes A D G = A D G B E H G F I B E H C F I 就足够了。我在上面展示了当你知道索引i=0; i<cols*rows; i++时如何计算行r和列c;然后,您可以计算转置索引i,并且当且仅当j = c*rows + r时才进行交换。)

对于非平方矩阵,情况类似,但互换更为复杂。

i < j

如果我们假设我们有一个遍历数组的循环,并且没有交换,或者与更高索引处的元素交换,则这些交换偏移量(0表示无交换,1表示交换下一个元素, 2用于与下一个之后的元素交换,依此类推)形成整数序列。对于上述情况,这些序列是

2x3: A B C = A B C D E F
     D E F
   becomes
     A D   = A D B E C F
     B E
     C F

3x4: A B C D = A B C D E F G H I J K L
     E F G H
     I J K L
   becomes
     A E I   = A E I B F J C G K D H L
     B F J
     C G K
     D H L

换句话说,第一个元素没有被交换。对于2x3情况,[1]处的元素与[1 + 2]处的元素交换; [2]处的元素与[2 + 1]处的元素交换;并且[3]处的元素与[3 + 1]处的元素交换。对于3x4情况,[1]处的元素与[1 + 3]处的元素交换,[2]处的元素与[2 + 6]处的元素交换,[3]处的元素交换为[3 + 1]处的元素,依此类推。

这些交换序列相对于矩阵维度是对称的。也就是说,3x4和4x3矩阵的序列是相同的(这是有道理的,因为我们在这里进行转置)。

不幸的是,我不知道任何封闭的表格表达式或简单方法来生成一般 N × M 矩阵的序列。

(有一些方法可以以某种形式重新生成交换表,但它们都需要一个与矩阵大小相同的辅助数组,包含每个元素的索引,并在此过程中更新它。这就失去了避免目的一个单独的数组/矩阵。)

因此,in-place matrix transpose对矩阵的元素进行单次线性传递,每个元素最多一次交换,对于方形矩阵来说很容易。对于非平方矩阵,只有在矩阵维度恰好是您具有交换顺序的矩阵时才能进行;对于任何 N×M 矩阵,通用公式或生成它的方法在2016年3月未知。不是不可能,请注意;还不知道。