我的老师问我们是否可以只使用一个" for循环转换矩阵"在C中,我们不应该使用额外的空间(比如将矩阵运送到另一个数组)。该算法应该与非平方矩阵一起使用。这可能吗?
编辑:使用"不应该使用额外的空间"我的意思是分配一个新矩阵并复制矩阵的某些部分。这些是不允许的。
答案 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 },列r
:c
。索引从零开始,因此i = r*cols + c
,0 <= i < rows*cols
和0 <= 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月未知。不是不可能,请注意;还不知道。