矩陣是線性代數中的一個知識,剛開始學習的時候可能感覺不到它有什么用處,最初的感覺就是對二維數據的操作。其實現實生活中矩陣的用處太大了,設計領域相當的廣泛。在此只討論稀疏矩陣的轉置問題;
可能看到矩陣就會想到二維數組,比如這樣一個矩陣:
你可能會想到用二維數組來存放此矩陣中的元素,就像這樣: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 }