稀疏矩陣轉置
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

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 }