原址转置算法

原址转置算法使用环境:指针type* 指向的一维数据,指定矩阵宽度W,高度H。转置前的数据高度H,宽度W,转置之后的数据高度为W宽度为H。

以int* a=[1,2,3,4,5,6,7,8,9,10,11,12]为例,3行4列排放为

[ 1 2 3 4] [ 5 6 7 8] [ 9 10 11 12]

转置之后的数据为: [ 1 5 9] [ 2 6 10] [ 3 7 11] [ 4 8 12] 转置后的*a=[1,5,9,2,6,10,3,7,11,4,8,12]

序号 1 2 3 4 5 6 7 8 9 10 11 12
1 2 3 4 5 6 7 8 9 10 11 12
1 5 9 2 6 10 3 7 11 4 8 12
元素2的位置上被5占据了,5原来的位置被6占据了,6的位置被10占据了,10的位置被4占据了,4的位置被2占据了,也就是形成了2->5->6->10->4->2的环。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <iostream>
#include <vector>
using namespace std;

void trans_inplace(int *a, int h, int w){
    vector<int> tt;
    int num = 0;
    for (int i = 1; i != h*w - 1; ++i){
        tt.clear();
        tt.push_back(i);
        bool flag = true;//用来判断是不是重复转置
     int k = ( i % w ) * h + i / w;
        while (k != i){
            if (k<i){
                flag = false;
                break;
            }
            tt.push_back(k);
            k = (k%w)*h + k / w;
        }
        if (flag){
            int temp = a[tt[tt.size()-1]];
            for (int j = tt.size() - 1; j > 0; --j){
                a[tt[j]] = a[tt[j - 1]];
            }
            a[i] = temp;
            num += tt.size();
            if (num == h*w - 2)//首尾不需要转置
             break;
        }
    }
}

void print_matrix(int *a, int n, int m){
    for (int i = 0; i != n; ++i){
        cout<<"[ ";
        for (int j = 0; j != m; ++j){
            cout << a[j + i*m]<<" ";
        }
        cout << "]" << endl;
    }
}
int main()
{
    int a[12] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
    print_matrix(a, 3, 4);//转置前
 trans_inplace(a, 3, 4);
    print_matrix(a, 4, 3);//转置后
 getchar();
    return 0;
}