【数据结构】——稀疏矩阵转置

转自http://www.cnblogs.com/ngnetboy/archive/2013/03/13/2949188.html

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

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

然后可以开始矩阵转置:

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

 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 juzhenb[MAX_TERM];

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

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

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

3 b[count_b].value = a[j].value; 

整个函数如下:

 1 void zhuanzhi_1(struct juzhen a[MAX_TERM],struct juzhen b[MAX_TERM])            //转置矩阵方法一
 2 {
 3     int i,j;
 4     int count_b = 1;        //b的当前元素下标
 5     b[0].row = a[0].col;  
 6     b[0].col = a[0].row;
 7     b[0].value = a[0].value;
 8     for(i = 0;i < a[0].col;i++)
 9     {
10         for(j = 1;j <= a[0].value;j++)
11         {
12             if(a[j].col == i)    //有种排序效果
13             {
14                 b[count_b].row = a[j].col;
15                 b[count_b].col = a[j].row;
16                 b[count_b].value = a[j].value;
17                 count_b++;
18             }
19         }
20     }
21 }

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

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

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

 1 int term[N],star[N];        //保存转置矩阵第i行元素的数量  保存第i行开始位置    
 2     int n = a[0].value;
 3     int i,j,k;
 4     int b_star;
 5 
 6     for(i = 0;i < N;i++)    
 7         term[i] = 0;
 8 
 9     for(j = 0;j <= n;j++)
10         term[a[j].col]++;
11     
12     star[0] = 1;
13     for(k = 1;k < N;k++)
14         star[k] = star[k - 1] + term[k - 1];

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

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

 1 b[0].col = a[0].col;
 2     b[0].row = a[0].row;
 3     b[0].value = a[0].value;
 4     for(i = 1;i <= n;i++)
 5     {
 6         b_star = star[a[i].col]++;
 7         b[b_star].col = a[i].row;
 8         b[b_star].row = a[i].col;
 9         b[b_star].value = a[i].value;
10     }

需要注意的是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]++。为下一个元素设置相应的位置;

完整函数:

 1 void zhuanhuan_2(struct juzhen a[MAX_TERM],struct juzhen b[MAX_TERM])
 2 {
 3     int term[N],star[N];        //保存转置矩阵第i行元素的数量  保存第i行开始位置    
 4     int n = a[0].value;
 5     int i,j,k;
 6     int b_star;
 7 
 8     for(i = 0;i < N;i++)    
 9         term[i] = 0;
10 
11     for(j = 1;j <= n;j++)
12         term[a[j].col]++;
13     
14     star[0] = 1;
15     for(k = 1;k < N;k++)
16         star[k] = star[k - 1] + term[k - 1];
17 
18     b[0].col = a[0].col;
19     b[0].row = a[0].row;
20     b[0].value = a[0].value;
21     for(i = 1;i <= n;i++)
22     {
23         b_star = star[a[i].col]++;
24         b[b_star].col = a[i].row;
25         b[b_star].row = a[i].col;
26         b[b_star].value = a[i].value;
27     }
28 
29 }

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

完整的测试程序:

  1 完整代码
  2 #include<stdio.h>
  3 #define N 5
  4 #define MAX_TERM 15
  5 
  6 typedef struct juzhen
  7 {
  8     int row;        //
  9     int col;        //
 10     int value;        //元素值
 11 };
 12 
 13 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}};
 14 struct juzhen a[MAX_TERM];        //存放矩阵中元素数值不为零的元素
 15 struct juzhen b[MAX_TERM];        //转置后的矩阵
 16 
 17 int chushi(struct juzhen a[MAX_TERM])            //初始化稀疏矩阵
 18 {
 19     int count_value = 0;    //统计矩阵中元素数值不为零的元素的总和
 20     int i,j;
 21     int count_a = 1;
 22     for(i = 0;i < N;i++)
 23     {
 24         for(j = 0;j < N;j++)
 25         {
 26             if(text[i][j] != 0)
 27             {
 28                 a[count_a].row = i;
 29                 a[count_a].col = j;
 30                 a[count_a].value = text[i][j];
 31                 count_a++;
 32             }
 33         }
 34     }
 35     a[0].col = 5;            //矩阵的总列数
 36     a[0].row = 5;            //矩阵的总行数
 37     a[0].value = --count_a;    //矩阵中的元素个数
 38 
 39     return count_a;
 40 }
 41 
 42 void showjuzhen(struct juzhen a[MAX_TERM],int count_a)        //显示稀疏矩阵
 43 {
 44     int i,j;
 45     int text = 1;
 46     for(i = 0;i < N;i++)
 47     {
 48         for(j = 0;j < N;j++)
 49         {
 50             if(a[text].row == i && a[text].col == j)
 51             {
 52                 printf(" %d ",a[text].value);
 53                 text++;
 54             }
 55             else
 56                 printf(" 0 ");
 57         }
 58         printf("\n");
 59     }
 60 
 61 }
 62 
 63 void showjuzhen_2(struct juzhen a[MAX_TERM],int count_a)            //显示稀疏矩阵方法二
 64 {
 65     int i;
 66     printf(" i row col val\n");
 67     for(i = 0;i < count_a + 1;i++)
 68     {
 69         printf(" %d|  %d   %d   %d\n",i,a[i].row,a[i].col,a[i].value);
 70     }
 71 }
 72 
 73 
 74 void zhuanzhi_1(struct juzhen a[MAX_TERM],struct juzhen b[MAX_TERM])            //转置矩阵方法一
 75 {
 76     int i,j;
 77     int count_b = 1;        //b的当前元素下标
 78     b[0].row = a[0].col;
 79     b[0].col = a[0].row;
 80     b[0].value = a[0].value;
 81     for(i = 0;i < a[0].col;i++)
 82     {
 83         for(j = 1;j <= a[0].value;j++)
 84         {
 85             if(a[j].col == i)
 86             {
 87                 b[count_b].row = a[j].col;
 88                 b[count_b].col = a[j].row;
 89                 b[count_b].value = a[j].value;
 90                 count_b++;
 91             }
 92         }
 93     }
 94 }
 95 
 96 
 97 void zhuanhuan_2(struct juzhen a[MAX_TERM],struct juzhen b[MAX_TERM])
 98 {
 99     int term[N],star[N];        
100     int n = a[0].value;
101     int i,j,k;
102     int b_star;
103 
104     for(i = 0;i < N;i++)    
105         term[i] = 0;
106 
107     for(j = 0;j <= a[0].value;j++)
108         term[a[j].col]++;
109     
110     star[0] = 1;
111     for(k = 1;k < N;k++)
112         star[k] = star[k - 1] + term[k - 1];
113 
114     b[0].col = a[0].col;
115     b[0].row = a[0].row;
116     b[0].value = a[0].value;
117     for(i = 1;i <= n;i++)
118     {
119         b_star = star[a[i].col]++;
120         b[b_star].col = a[i].row;
121         b[b_star].row = a[i].col;
122         b[b_star].value = a[i].value;
123     }
124 
125 
126     for(i = 0;i < a[0].value + 1;i++)
127         printf(" %d|  %d   %d   %d\n",i,b[i].row,b[i].col,b[i].value);
128 
129 }
130 
131 int main(void)
132 {
133     int count_a;
134     count_a = chushi(a);
135     showjuzhen(a,count_a);
136     showjuzhen_2(a,count_a);
137     printf("\n");
138     zhuanhuan_2(a,b);
139     //zhuanzhi_1(a,b);
140     //showjuzhen(b,count_a);
141     //showjuzhen_2(b,count_a);
142     //return 0;
143 }

 

posted @ 2014-10-31 15:51  PJQOOO  阅读(690)  评论(0编辑  收藏  举报