数组原地交换

例1 旋转图像

数组原地交换_第1张图片

分析:每四个数构成一个互相交换的环,对所有这些环交换即可。
1,外层循环控制一圈
2,内层循环遍历每个每个环的起点m[i][j],它的三个后继可以推导出来
3,一个环的交换,这里用其他元素分别和同一元素交换实现。(顺时针旋转:其他元素按顺时针顺序和同一元素交换,逆时针同理
数组原地交换_第2张图片

void rotate(vector>& matrix) {
        int n=matrix.size();
        if(n==0) return;
        if(n!=matrix[0].size()) return;

        for(int i=0;i<=n/2;i++){ //外围圈
            for(int j=i;j<=n-2-i;j++){ //每个环的起点
                //四个数交换
                swap(matrix[n-1-j][i],matrix[i][j]);
                swap(matrix[n-1-j][i],matrix[j][n-1-i]);
                swap(matrix[n-1-j][i],matrix[n-1-i][n-1-j]);
            }
        }
        return;
    }

例2 矩阵转置

将一个m*n的矩阵存储在一个一维数组中,原地实现矩阵的转置。
分析:以一个4x2的矩阵A={1,2,3,4,5,6,7,8}进行分析。
转置前:1,2,3,4,5,6,7,8
转置后:1,3,5,7,2,4,6,8

数组原地交换_第3张图片

可以看出有四个独立的交换环。

算法:遍历数组,判断该位置的环若未处理过,则对该环进行一次交换。
1,如何判断环是重复已处理过的?遍历数组时下标是从小到大的,所以如果是第一次遍历该环,则第一个下标肯定是这个环中最小的。如果一个环被处理过,那么总能找到一个它的后继是小于它的。
2,如何计算当前元素下标的前驱与后继?假设转置前某个元素的数组下标为i,则它所在行列为(i/N, i%N),转置后所在行列则为(i%N, i/N),可计算转置后数组下标为(i%N)M+i/N,此为i的后继。假设转置后某个元素的数组下标为i,则它所在行列为(i/M, i%M),则转置前所在行列为(i%M, i/M),可计算此时下标为(i%M)N+i/M,此为i的前驱。

int getnext(int i,int m,int n){
    return (i%n)*m + i/n;
}

void transpose(vector& a,int m,int n){
    for(int i=0;ii){
            next=getnext(next,m,n);
        }
        if(i==next){   //未处理过,对该环进行处理
            next=getnext(i,m,n);  
            while(next!=i){
                swap(a[i],a[next]);
                next=getnext(next,m,n);
            }
        }
    }
}

你可能感兴趣的:(数组原地交换)