题目:用O(1)的空间实现矩阵的转置

为了方便,使用一维数组来分析。所谓矩阵转置,行变列,列变行。在转置的过程中,有的元素位置是不变的;对于变化位置的元素,要求O(1)空间完成,那么这些位置的变化一定是有着规律的。

举例,2×5的矩阵,A={0,1,2,3,4,5,6,7,8,9};转置后为AT={0,5,1,6,2,7,3,8,4,9},探索下标变化:

0->0

1->2->4->8->7->5->1

3->6->3

9->9

这些下标的变化是一些环,如果我们能找到这个环,对环做移动处理,就可以O(1)完成了。

现在的问题是,我们如何知道一个环是已经处理过的,仔细观察,如果一个环被处理过,那么总能找到一个它的后继是小于它的。例如,处理了前三个环的时候,当尝试找下标4打头的环时,一直找4的后继下标,会发现后继1是小于4的,我们就知道4是存在于一条已经处理过的环,跳过。

接下来的问题是如何找到当前元素下标的前驱和后继。先求下标i转置前的下标,即i的前驱,对于m×n的矩阵,转置后为n×m,则一维数组的第i个元素表示的行列为(i/m, i%m),根据转置原理,那么这个元素在转置前的m×n矩阵中所表示的行列为(i%m, i/m),那么i在转置前一维数组中的位置为j=(i%m)×n+(i/m)。同理,下标i转置后的位置j=(i%n)×m+(i/n)。

这样,前驱后继都可以求得,找到环就移动环的元素,如果已处理过则跳过,代码如下:

评论:个人觉得每条环总能找到一个它的后继是小于它的原因在于,每条环开始的第一个位置下标总是整条环中最小的,所以只有第一次能遍历权环并回到开始的点。而之所以每条环开始的第一个位置下标最小,是因为整个数组的遍历过程是从小到大,可以保证比每条环开始的位置小的位置都被遍历过了。

int Pre(int index, int m, int n) // 求前驱
{
    return (index % m) * n + (index / m);
}
 
int Next(int index, int m, int n) // 求后继
{
    return (index % n) * m + (index / n);
}
 
void  move(int * a, int i, int m, int n) // 处理环
{
    int curVal =  a[i];
    int cur = i;
    int pre = Pre(i,m,n);
    while(i != pre)
    {
        a[cur] = a[pre];
        cur = pre;
        pre = Pre(cur,m,n);
    }
    a[cur] = curVal;
}
 
void transpose(int *a, int m, int n)  // 转置
{
    for(int i = 0; i < m*n; ++i)
    {
        int next = Next(i,m,n);
        while(i < next)  // 若大于说明已处理过
        {
            next = Next(next,m,n);
        }
        if(next == i)
        {
            move(a,i,m,n);
        }
    }
}
int main()
{
    int a[10] = {0,1,2,3,4,5,6,7,8,9};
    for(int i = 0; i < 10; ++i)
    {
        printf("%d ",a[i]);
    }
    printf("\n");
    transpose(a,2,5);
    for(int i = 0; i < 10; ++i)
    {
        printf("%d ",a[i]);
    }
    printf("\n");
    return 0;
}

转自:http://www.ahathinking.com/archives/217.html

更多:http://zhiqiang.org/blog/science/computer-science/another-perfect-shuffle-algorithm.html

http://space.itpub.net/67063/viewspace-169250

矩阵转置 O(1)空间的更多相关文章

  1. <矩阵的基本操作:矩阵相加,矩阵相乘,矩阵转置>

    //矩阵的基本操作:矩阵相加,矩阵相乘,矩阵转置 #include<stdio.h> #include<stdlib.h> #define M 2 #define N 3 #d ...

  2. 【异构计算】OpenCL矩阵转置

    介绍 矩阵转置,主要的技巧还是利用好local memory ,防止local memory,以及glabol memory的读取尽量是合并读写. 完整代码一: main.cpp代码 #include ...

  3. [转]Python中的矩阵转置

    Python中的矩阵转置 via 需求: 你需要转置一个二维数组,将行列互换. 讨论: 你需要确保该数组的行列数都是相同的.比如: arr = [[1, 2, 3], [4, 5, 6], [7, 8 ...

  4. [置顶] [MATLAB技术贴]漫谈MATLAB矩阵转置

    矩阵转置是matlab最基本的操作了,但这个基本操作,也是很多初学者容易出现问题的地方.本帖通过几个实例演示matlab矩阵转置的操作. 方法一:'  运算符与  .'  运算符 >>a ...

  5. POJ3268 Silver Cow Party(dijkstra+矩阵转置)

    Silver Cow Party Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 15156   Accepted: 6843 ...

  6. 基于visual Studio2013解决C语言竞赛题之0705矩阵转置

     题目 解决代码及点评 /* 5. 写一函数,将一个3×3的矩阵转置. */ #include <stdio.h> #include <stdlib.h> void mai ...

  7. Python小代码_5_二维矩阵转置

    使用列表推导式实现二维矩阵转置 matrix = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]] print(matrix) matrix_t = [[ro ...

  8. LHC大神问的矩阵转置问题

    数学中线性代数中提到的矩阵转置,其实在我们的业务场景中也有需要的地方,比如LHC大神问到的这个问题 那么如何进行行列转换呢? 代码如下: <?php $array=array( '部门1'=&g ...

  9. c++刷题(15/100)矩阵转置,最深子树

    题目一:矩阵转置 给定一个矩阵 A, 返回 A 的转置矩阵. 矩阵的转置是指将矩阵的主对角线翻转,交换矩阵的行索引与列索引. 示例 1: 输入:[[1,2,3],[4,5,6],[7,8,9]] 输出 ...

随机推荐

  1. Android动画的深入分析

    一.AnimationDrawable的使用 详见:Drawable类及XMLDrawable的使用 补充:通过Animation的setAnimationListener()可以给View动画添加监 ...

  2. maven+springmvc+easyui+fastjson+pagehelper

    1.maven配置 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www ...

  3. spark aggregate

    该函数官方的api,说的不是很明白: aggregate(zeroValue, seqOp, combOp) Aggregate the elements of each partition, and ...

  4. alternaiate terms

    操作系统就是能让您的计算机工作 的一系列基本程序和实用工具; 大多数的软件至少都要卖几百块钱,您们怎么愿意白白把它送给别人? 您真正应该问的问题是软件公司怎么可以要您花那么多钱买他们的软件.写软件和制 ...

  5. IOS设备设计完整指南(转载)

    http://blog.sina.com.cn/s/blog_6cc9af670102vq12.html

  6. linux中的strings命令简介2

    摘自:http://blog.csdn.net/stpeace/article/details/46641069 linux中的strings命令简介 之前我们聊过linux strings的用法和用 ...

  7. hdu 1010 Tempter of the Bone(dfs暴力)

    Problem Description The doggie found a bone in an ancient maze, which fascinated him a lot. However, ...

  8. C#委托的异步调用【转】

    本文将主要通过“同步调用”.“异步调用”.“异步回调”三个示例来讲解在用委托执行同一个“加法类”的时候的的区别和利弊. 首先,通过代码定义一个委托和下面三个示例将要调用的方法: ); //模拟该方法运 ...

  9. 热烈祝贺Polymer中文组织站点上线

    欢迎来到前端世界的明天 由于官网被墙, 所以 http://docs.polymerchina.org/ 其实是一件很有意义的事. 组件化和重用,一直是编程界几十年来前进的方向和目标,随着时间的推移和 ...

  10. 求链表的倒数第k个节点

    问题描述:给定一个链表的头节点,求出链表的倒数第k个节点. 分析:这是链表里的经典问题,存在多种解法,下面给大家分享下我的想法. 解法一:很直观的一种做法是从头到尾扫描链表,然后求倒数第k个,但是由于 ...