zoukankan      html  css  js  c++  java
  • 【数据结构】——稀疏矩阵转置

      矩阵是线性代数中的一个知识,刚开始学习的时候可能感觉不到它有什么用处,最初的感觉就是对二维数据的操作。其实现实生活中矩阵的用处太大了,设计领域相当的广泛。在此只讨论稀疏矩阵的转置问题;

      可能看到矩阵就会想到二维数组,比如这样一个矩阵:

      你可能会想到用二维数组来存放此矩阵中的元素,就像这样:int text[][5] = {{0,5,6,0,4},{0,0,0,0,0},{1,0,0,0,0},{1,0,0,0,0},{0,2,0,0,1}};

    这样好像也没有什么不好。我们再来看看这个矩阵,五行五列,可以包含二十五个元素,但是此矩阵只有七个元素。但是我们在存放数据的时候分配了二十五块int单元。这样是不是有点太浪费了。如果我们只存储这七个元素我想会节省一部分内存空间。但是如果我们只存储矩阵中的元素还是不行的,因为只有元素我们就无法还原矩阵,我们还需要此元素的行列值。这样就好办了。我们声明一个结构体来表示一个元素。就像这样:

    1 typedef struct juzhen
    2 {
    3     int row;        //
    4     int col;        //
    5     int value;        //元素值
    6 };

      这样存储一个元素就会用到三个存储单元,七个就是二十一个存储单元,可能与二十五个没多大差别,但是如果矩阵的行列是一个很大的值,而且又是稀疏矩阵,这样做就可以节省很大的空间。这种存储结构只限于稀疏矩阵。

      解决了存储结构,就开始矩阵的转置吧!!!

      首先我们需要一个矩阵,就按照上图给的矩阵好了,按照此矩阵做一个二维数组:

    1 int text[][5] = {{0,5,6,0,4},{0,0,0,0,0},{1,0,0,0,0},{1,0,0,0,0},{0,2,0,0,1}};

      就像这样;我们需要定义一个数组来表示稀疏矩阵,并赋值;

     1 #define MAX_TERM 15
     2 
     3 struct juzhen a[MAX_TERM];        //存放矩阵中元素数值不为零的元素
     4 
     5 int chushi(struct juzhen a[MAX_TERM])            //初始化稀疏矩阵
     6 {
     7     int count_value = 0;    //统计矩阵中元素数值不为零的元素的总和
     8     int i,j;
     9     int count_a = 1;
    10     for(i = 0;i < N;i++)
    11     {
    12         for(j = 0;j < N;j++)
    13         {
    14             if(text[i][j] != 0)
    15             {
    16                 a[count_a].row = i;
    17                 a[count_a].col = j;
    18                 a[count_a].value = text[i][j];
    19                 count_a++;
    20             }
    21         }
    22     }
    23     a[0].col = 5;            //矩阵的总列数
    24     a[0].row = 5;            //矩阵的总行数
    25     a[0].value = --count_a;    //矩阵中的元素个数
    26 
    27     return count_a;
    28 }

      在初始化矩阵数组的时候为了方便转置矩阵时的操作,我们把数组的第一个元素设置为矩阵的列数,行数和元素总数;

      矩阵有了,存放矩阵元素的数组也有了。接下来就是转置矩阵的函数了。

      我们在转置矩阵的时候会需要一个数组来保存转置后的矩阵,定义为:

    struct juzhen b[MAX_TERM];//转置后的矩阵

      主要思想,两层循环,第一层循环控制矩阵的行,第二层循环控制数组a的行。由于转置矩阵即把矩阵中元素的列行对换一下,并且按照行排序;所以我们在第二层循环中做一个判断,if(a[j].col == i) 【i控制第一层循环,j控制第二层循环】 如果为真值则执行:

                    b[count_b].row = a[j].col;
                    b[count_b].col = a[j].row;
                    b[count_b].value = a[j].value;

    整个函数如下:

    void zhuanzhi_1(struct juzhen a[MAX_TERM],struct juzhen b[MAX_TERM])            //转置矩阵方法一
    {
        int i,j;
        int count_b = 1;        //b的当前元素下标
        b[0].row = a[0].col;  
        b[0].col = a[0].row;
        b[0].value = a[0].value;
        for(i = 0;i < a[0].col;i++)
        {
            for(j = 1;j <= a[0].value;j++)
            {
                if(a[j].col == i)    //有种排序效果
                {
                    b[count_b].row = a[j].col;
                    b[count_b].col = a[j].row;
                    b[count_b].value = a[j].value;
                    count_b++;
                }
            }
        }
    }

      用此方法可以有效的转置矩阵,我们来看一下此函数的时间复杂度:O(cols * elements)——矩阵的列*矩阵的元素总和;

      如果元素很多就会浪费很多的时间。有没有办法让两层循环变成一层循环呢?付出空间上的代价,换取时间效率;

      我们只用一层循环来遍历数组a中所有元素,并把该元素放到指定的位置。这样我们就需要一个数组star来存放第i个元素所在位置。在定义这个数组之前,我们还需要一个数组term来实现统计矩阵第i行元素的数量。这样我们才能更方便的知道第i个元素应该存放的位置。

        int term[N],star[N];        //保存转置矩阵第i行元素的数量  保存第i行开始位置    
        int n = a[0].value;
        int i,j,k;
        int b_star;
    
        for(i = 0;i < N;i++)    
            term[i] = 0;
    
        for(j = 0;j <= n;j++)
            term[a[j].col]++;
        
        star[0] = 1;
        for(k = 1;k < N;k++)
            star[k] = star[k - 1] + term[k - 1];

    第一个循环初始化term,每个元素都为零。第二个循环是为了统计第i行元素的数量。第三个循环是设置第i个元素所在的位置。因为数组a的第一个元素是存放行列和元素的总数,因此第三个循环要从k = 1开始。此时两个数组的元素为:

    下一步就是遍历a中的所有元素,然后根据a[i].col的值来把a[i].value放到指定的位置。

        b[0].col = a[0].col;
        b[0].row = a[0].row;
        b[0].value = a[0].value;
        for(i = 1;i <= n;i++)
        {
            b_star = star[a[i].col]++;
            b[b_star].col = a[i].row;
            b[b_star].row = a[i].col;
            b[b_star].value = a[i].value;
        }

    需要注意的是b的第一个元素与a中的第一个元素是同样的。b_star = star[a[i].col]++;因为当term[1] = 2;而star[1] = 3;就是a[i].col = 1时有两个元素,第一个元素的位置是star[a[i].col];而第二个元素的位置就是star[a[i].col] + 1所以在此用star[a[i].col]++。为下一个元素设置相应的位置;

    完整函数:

    void zhuanhuan_2(struct juzhen a[MAX_TERM],struct juzhen b[MAX_TERM])
    {
        int term[N],star[N];        //保存转置矩阵第i行元素的数量  保存第i行开始位置    
        int n = a[0].value;
        int i,j,k;
        int b_star;
    
        for(i = 0;i < N;i++)    
            term[i] = 0;
    
        for(j = 1;j <= n;j++)
            term[a[j].col]++;
        
        star[0] = 1;
        for(k = 1;k < N;k++)
            star[k] = star[k - 1] + term[k - 1];
    
        b[0].col = a[0].col;
        b[0].row = a[0].row;
        b[0].value = a[0].value;
        for(i = 1;i <= n;i++)
        {
            b_star = star[a[i].col]++;
            b[b_star].col = a[i].row;
            b[b_star].row = a[i].col;
            b[b_star].value = a[i].value;
        }
    
    }

    此函数每个循环体的执行次数分别为cols cols elements elements 时间复杂度为O(cols + elements)和O(cols * elements)相差好多,尤其是clos 和 elements很大的时候;

    完整的测试程序:

    完整代码
      1 #include<stdio.h>
      2 #define N 5
      3 #define MAX_TERM 15
      4 
      5 typedef struct juzhen
      6 {
      7     int row;        //
      8     int col;        //
      9     int value;        //元素值
     10 };
     11 
     12 int text[][5] = {{0,5,6,0,4},{0,0,0,0,0},{1,0,0,0,0},{1,0,0,0,0},{0,2,0,0,1}};
     13 struct juzhen a[MAX_TERM];        //存放矩阵中元素数值不为零的元素
     14 struct juzhen b[MAX_TERM];        //转置后的矩阵
     15 
     16 int chushi(struct juzhen a[MAX_TERM])            //初始化稀疏矩阵
     17 {
     18     int count_value = 0;    //统计矩阵中元素数值不为零的元素的总和
     19     int i,j;
     20     int count_a = 1;
     21     for(i = 0;i < N;i++)
     22     {
     23         for(j = 0;j < N;j++)
     24         {
     25             if(text[i][j] != 0)
     26             {
     27                 a[count_a].row = i;
     28                 a[count_a].col = j;
     29                 a[count_a].value = text[i][j];
     30                 count_a++;
     31             }
     32         }
     33     }
     34     a[0].col = 5;            //矩阵的总列数
     35     a[0].row = 5;            //矩阵的总行数
     36     a[0].value = --count_a;    //矩阵中的元素个数
     37 
     38     return count_a;
     39 }
     40 
     41 void showjuzhen(struct juzhen a[MAX_TERM],int count_a)        //显示稀疏矩阵
     42 {
     43     int i,j;
     44     int text = 1;
     45     for(i = 0;i < N;i++)
     46     {
     47         for(j = 0;j < N;j++)
     48         {
     49             if(a[text].row == i && a[text].col == j)
     50             {
     51                 printf(" %d ",a[text].value);
     52                 text++;
     53             }
     54             else
     55                 printf(" 0 ");
     56         }
     57         printf("\n");
     58     }
     59 
     60 }
     61 
     62 void showjuzhen_2(struct juzhen a[MAX_TERM],int count_a)            //显示稀疏矩阵方法二
     63 {
     64     int i;
     65     printf(" i row col val\n");
     66     for(i = 0;i < count_a + 1;i++)
     67     {
     68         printf(" %d|  %d   %d   %d\n",i,a[i].row,a[i].col,a[i].value);
     69     }
     70 }
     71 
     72 
     73 void zhuanzhi_1(struct juzhen a[MAX_TERM],struct juzhen b[MAX_TERM])            //转置矩阵方法一
     74 {
     75     int i,j;
     76     int count_b = 1;        //b的当前元素下标
     77     b[0].row = a[0].col;
     78     b[0].col = a[0].row;
     79     b[0].value = a[0].value;
     80     for(i = 0;i < a[0].col;i++)
     81     {
     82         for(j = 1;j <= a[0].value;j++)
     83         {
     84             if(a[j].col == i)
     85             {
     86                 b[count_b].row = a[j].col;
     87                 b[count_b].col = a[j].row;
     88                 b[count_b].value = a[j].value;
     89                 count_b++;
     90             }
     91         }
     92     }
     93 }
     94 
     95 
     96 void zhuanhuan_2(struct juzhen a[MAX_TERM],struct juzhen b[MAX_TERM])
     97 {
     98     int term[N],star[N];        
     99     int n = a[0].value;
    100     int i,j,k;
    101     int b_star;
    102 
    103     for(i = 0;i < N;i++)    
    104         term[i] = 0;
    105 
    106     for(j = 0;j <= a[0].value;j++)
    107         term[a[j].col]++;
    108     
    109     star[0] = 1;
    110     for(k = 1;k < N;k++)
    111         star[k] = star[k - 1] + term[k - 1];
    112 
    113     b[0].col = a[0].col;
    114     b[0].row = a[0].row;
    115     b[0].value = a[0].value;
    116     for(i = 1;i <= n;i++)
    117     {
    118         b_star = star[a[i].col]++;
    119         b[b_star].col = a[i].row;
    120         b[b_star].row = a[i].col;
    121         b[b_star].value = a[i].value;
    122     }
    123 
    124 
    125     for(i = 0;i < a[0].value + 1;i++)
    126         printf(" %d|  %d   %d   %d\n",i,b[i].row,b[i].col,b[i].value);
    127 
    128 }
    129 
    130 int main(void)
    131 {
    132     int count_a;
    133     count_a = chushi(a);
    134     showjuzhen(a,count_a);
    135     showjuzhen_2(a,count_a);
    136     printf("\n");
    137     zhuanhuan_2(a,b);
    138     //zhuanzhi_1(a,b);
    139     //showjuzhen(b,count_a);
    140     //showjuzhen_2(b,count_a);
    141     //return 0;
    142 }
  • 相关阅读:
    移动页面HTML5自适应手机屏幕宽度
    “流式”前端构建工具——gulp.js 简介
    HDU2602-Bone Collector
    HDU3535-AreYouBusy
    HDU1712-ACboy needs your help
    HDU3496-Watch The Movie
    HDU1171-Big Event in HDU
    POJ2533-Longest Ordered Subsequence
    HDU2084-数塔
    HDU2023-求平均成绩
  • 原文地址:https://www.cnblogs.com/ngnetboy/p/2949188.html
Copyright © 2011-2022 走看看