稀疏矩阵转置+快速转置

稀疏矩阵转置  

Description

稀疏矩阵的存储不宜用二维数组存储每个元素,那样的话会浪费很多的存储空间。所以可以使用一个一维数组存储其中的非零元素。这个一维数组的元素类型是一个三元组,由非零元素在该稀疏矩阵中的位置(行号和列号对)以及该元组的值构成。

矩阵转置就是将矩阵行和列上的元素对换。

现在就请你对一个稀疏矩阵进行转置。以下是稀疏矩阵转置的算法描述:

图:稀疏矩阵转置的算法描述

Input

输入的第一行是两个整数r和c(r*c <= 12500),分别表示一个包含很多0的稀疏矩阵的行数和列数。接下来有r行,每行有c个整数,表示这个稀疏矩阵的各个元素。

Output

输出c行,每行有r个整数,每个整数后跟一个空格。该结果为输入稀疏矩阵的转置矩阵。

Sample Input

6 7
0 12 9 0 0 0 0
0 0 0 0 0 0 0
-3 0 0 0 0 14 0
0 0 24 0 0 0 0
0 18 0 0 0 0 0
15 0 0 -7 0 0 0

Sample Output

0 0 -3 0 0 15 
12 0 0 0 18 0 
9 0 0 24 0 0 
0 0 0 0 0 -7 
0 0 0 0 0 0 
0 0 14 0 0 0 
0 0 0 0 0 0 

HINT

提示:

严老师纸质书中用union类型来表示稀疏矩阵类型,这是有问题的,应该使用struct来表示该类型。

注意理解为什么转置算法中,以列从小到大来进行转置。实际上只需一个循环就能够完成转置而不需将列从小到大来处理,转置后的矩阵虽然是正确的但却乱掉了,以至于在各种处理中会增加复杂。(其实就本题而言,如果不以列从小到大处理将导致输出困难,输出的复杂度增加)

总结:

矩阵是一个应用很广泛的工具和课题。看看《黑客帝国》就知道了。现在初步给大家介绍矩阵的操作,以后有机会还会详细讨论矩阵的。

  1 #include <stdio.h>  
  2 #include <string.h>  
  3 #include <iostream>  
  4 #include <string>  
  5 #include <math.h>  
  6 #include <algorithm>  
  7 #include <vector>  
  8 #include <stack>  
  9 #include <queue>  
 10 #include <set>  
 11 #include <map>  
 12 #include <math.h>  
 13 const int INF=0x3f3f3f3f;  
 14 typedef long long LL;  
 15 const int mod=1e9+7;  
 16 const int maxn=1e4+10;  
 17 using namespace std;  
 18     
 19 typedef struct
 20 {  
 21     int row;  
 22     int col;   
 23     int val;   
 24 }Triple;  
 25     
 26 typedef struct
 27 {  
 28     Triple date[maxn];  
 29     int rows;
 30     int cols;
 31     int nums;
 32 }TSMatrix;  
 33     
 34 void TransposeTSMatrix(TSMatrix *A,TSMatrix *B)  
 35 {  
 36     B->rows=A->cols;  
 37     B->cols=A->rows;  
 38     B->nums=A->nums;  
 39     if(B->nums > 0)  
 40     {  
 41         int cnt=0;  
 42         for(int i=1;i<=A->cols;i++)  
 43         {  
 44             for(int j=1;j<=A->nums;j++)  
 45             {  
 46                 if(A->date[j].col==i)  
 47                 {  
 48                     cnt++;  
 49                     B->date[cnt].row=A->date[j].col;  
 50                     B->date[cnt].col=A->date[j].row;  
 51                     B->date[cnt].val=A->date[j].val;  
 52                 }  
 53             }  
 54             if(cnt == B->nums)  
 55                 break;  
 56         }  
 57     }  
 58     return ;  
 59 }  
 60     
 61 int main()  
 62 {  
 63     TSMatrix A,B;  
 64     scanf("%d %d",&A.rows,&A.cols);  
 65     A.nums=0;  
 66     for(int i=1;i<=A.rows;i++)  
 67     {  
 68         for(int j=1;j<=A.cols;j++)  
 69         {  
 70             int x;  
 71             scanf("%d",&x);  
 72             if(x)  
 73             {  
 74                 A.nums++;  
 75                 A.date[A.nums].row=i;  
 76                 A.date[A.nums].col=j;  
 77                 A.date[A.nums].val=x;  
 78             }     
 79         }  
 80     }  
 81     TransposeTSMatrix(&A,&B);  
 82     int cnt=1;  
 83     for(int i=1;i<=B.rows;i++) 
 84     {  
 85         for(int j=1;j<=B.cols;j++)  
 86         {  
 87             int a,b;  
 88             a=B.date[cnt].row;  
 89             b=B.date[cnt].col;  
 90             if(a==i&&b==j)  
 91             {  
 92                 printf("%d ",B.date[cnt].val);  
 93                 cnt++;  
 94             }  
 95             else
 96                 printf("%d ",0);  
 97         }  
 98         printf("\n");  
 99     }  
100     return 0;  
101 } 

稀疏矩阵快速转置 

Description

稀疏矩阵的存储不宜用二维数组存储每个元素,那样的话会浪费很多的存储空间。所以可以使用一个一维数组存储其中的非零元素。这个一维数组的元素类型是一个三元组,由非零元素在该稀疏矩阵中的位置(行号和列号对)以及该元组的值构成。
而矩阵转置就是将矩阵行和列上的元素对换。参考算法5.1中的具体做法,令mu和nu分别代表稀疏矩阵的行数和列数,不难发现其时间复杂度为O(mu×nu)。而当非零元的个数tu与mu×nu同数量级时,算法5.1的时间复杂度将上升至O(mu×nu 2)。因此,需要采用快速的稀疏矩阵转置算法。
现在就请你实现一个快速的对稀疏矩阵进行转置的算法。以下是稀疏矩阵快速转置的算法描述:

Input

输入的第一行是两个整数r和c(r<200, c<200, r*c <= 12500),分别表示一个包含很多0的稀疏矩阵的行数和列数。接下来有r行,每行有c个整数,用空格隔开,表示这个稀疏矩阵的各个元素。

Output

输出为读入的稀疏矩阵的转置矩阵。输出共有c行,每行有r个整数,每个整数后输出一个空格。请注意行尾输出换行。

Sample Input

6 7
0 12 9 0 0 0 0
0 0 0 0 0 0 0
-3 0 0 0 0 14 0
0 0 24 0 0 0 0
0 18 0 0 0 0 0
15 0 0 -7 0 0 0

Sample Output

0 0 -3 0 0 15 
12 0 0 0 18 0 
9 0 0 24 0 0 
0 0 0 0 0 -7 
0 0 0 0 0 0 
0 0 14 0 0 0 
0 0 0 0 0 0 

HINT

提示:

这个算法仅比算法5.1多用了两个辅助向量。对于这个算法的时间复杂度,不难发现算法中有4个并列的单循环,循环次数分别为nu和tu,因而总的时间复杂度为O(nu+tu)。而当稀疏矩阵的非零元个数tu和mu×nu的数量级相同时,其时间复杂度为O(mu×nu),与经典算法的时间复杂度相同。

请注意理解为什么转置算法中,以列从小到大来进行转置。实际上只需一个循环就能够完成转置而不需将列从小到大来处理,转置后的矩阵虽然内容正确,但元素的顺序却发生了变化,以至于在后续的各种处理操作中会增加复杂度。而在本题中,如果不按照列从小到大的顺序处理将导致输出困难,大大增加输出的复杂度。

总结:

稀疏矩阵是矩阵应用中很重要的一部分,由于其元素稀疏的特殊性质,我们可以得到比传统矩阵算法更快速的特殊算法。这也将会在本章后面的题目中得到体现。
  1 #include <stdio.h>  
  2 #include <string.h>  
  3 #include <iostream>  
  4 #include <string>  
  5 #include <math.h>  
  6 #include <algorithm>  
  7 #include <vector>  
  8 #include <stack>  
  9 #include <queue>  
 10 #include <set>  
 11 #include <map>  
 12 const int INF=0x3f3f3f3f;  
 13 typedef long long LL;  
 14 const int mod=1e9+7;  
 15 const int maxn=1e4+10;  
 16 using namespace std;  
 17   
 18 typedef struct  
 19 {  
 20     int row;//
 21     int col;//
 22     int val;//
 23 }Triple;  
 24   
 25 typedef struct  
 26 {  
 27     Triple data[maxn];//三元组
 28     int rows;//矩阵的总行数
 29     int cols;//矩阵的总列数
 30     int nums;//矩阵的非零元素个数
 31 }TSMatrix;
 32 
 33 //void TransposeTSMatrix(TSMatrix *A,TSMatrix *B)//矩阵的转置
 34 //{
 35 //    B->rows=A->cols;  
 36 //    B->cols=A->rows;  
 37 //    B->nums=A->nums;  
 38 //    if(B->nums > 0)  
 39 //    {  
 40 //        int cnt=0;  
 41 //        for(int i=1;i<=A->cols;i++)  
 42 //        {  
 43 //            for(int j=1;j<=A->nums;j++)  
 44 //            {  
 45 //                if(A->data[j].col==i)  
 46 //                {  
 47 //                    cnt++;  
 48 //                    B->data[cnt].row=A->data[j].col;  
 49 //                    B->data[cnt].col=A->data[j].row;  
 50 //                    B->data[cnt].val=A->data[j].val;  
 51 //                }  
 52 //            }  
 53 //            if(cnt == B->nums)  
 54 //                break;  
 55 //        }  
 56 //    }  
 57 //    return ;  
 58 //}  
 59 
 60 int num[maxn];
 61 int pos[maxn];//转置后第col行的开始位置
 62 
 63 void Fast_TransposeTSMatrix (TSMatrix *A,TSMatrix *B)
 64 {
 65     B->rows=A->cols;  
 66     B->cols=A->rows;  
 67     B->nums=A->nums;
 68     pos[1]=1;
 69     if(B->nums)
 70     {
 71         memset(num,0,sizeof(num));
 72         for(int i=1;i<=A->nums;i++)
 73             num[A->data[i].col]++;
 74         for(int col=2;col<=A->cols;col++)
 75             pos[col]=pos[col-1]+num[col-1];
 76         for(int i=1;i<=A->nums;i++)
 77         {
 78             int t=A->data[i].col;
 79             B->data[pos[t]].row=A->data[i].col;
 80             B->data[pos[t]].col=A->data[i].row;
 81             B->data[pos[t]].val=A->data[i].val;
 82             pos[t]++;
 83         }
 84     }
 85 }
 86 
 87 int main()  
 88 {  
 89     TSMatrix A,B;  
 90     scanf("%d %d",&A.rows,&A.cols);  
 91     A.nums=0;  
 92     for(int i=1;i<=A.rows;i++)  
 93     {  
 94         for(int j=1;j<=A.cols;j++)  
 95         {  
 96             int x;  
 97             scanf("%d",&x);  
 98             if(x)  
 99             {  
100                 A.nums++;  
101                 A.data[A.nums].row=i;  
102                 A.data[A.nums].col=j;  
103                 A.data[A.nums].val=x;  
104             }     
105         }  
106     }
107     Fast_TransposeTSMatrix(&A,&B); 
108     int cnt=1; 
109     for(int i=1;i<=B.rows;i++)//输出转置后的矩阵   
110     {  
111         for(int j=1;j<=B.cols;j++)  
112         {  
113             int a,b;  
114             a=B.data[cnt].row;  
115             b=B.data[cnt].col;  
116             if(a==i&&b==j)  
117             {  
118                 printf("%d ",B.data[cnt].val);  
119                 cnt++;  
120             }  
121             else  
122                 printf("%d ",0);  
123         }  
124         printf("\n");  
125     }  
126     return 0;
127 }

猜你喜欢

转载自www.cnblogs.com/jiamian/p/11669046.html