稀疏矩陣轉置

發表於2016-11-23

矩陣是線性代數中的一個知識,剛開始學習的時候可能感覺不到它有什麼用處,最初的感覺就是對二維資料的操作。其實現實生活中矩陣的用處太大了,設計領域相當的廣泛。在此只討論稀疏矩陣的轉置問題;

可能看到矩陣就會想到二維陣列,比如這樣一個矩陣:

你可能會想到用二維陣列來存放此矩陣中的元素,就像這樣: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單元。這樣是不是有點太浪費了。如果我們只儲存這七個元素我想會節省一部分記憶體空間。但是如果我們只儲存矩陣中的元素還是不行的,因為只有元素我們就無法還原矩陣,我們還需要此元素的行列值。這樣就好辦了。我們宣告一個結構體來表示一個元素。就像這樣:

這樣儲存一個元素就會用到三個儲存單元,七個就是二十一個儲存單元,可能與二十五個沒多大差別,但是如果矩陣的行列是一個很大的值,而且又是稀疏矩陣,這樣做就可以節省很大的空間。這種儲存結構只限於稀疏矩陣。

解決了儲存結構,就開始矩陣的轉置吧!!!

首先我們需要一個矩陣,就按照上圖給的矩陣好了,按照此矩陣做一個二維陣列:

就像這樣;我們需要定義一個陣列來表示稀疏矩陣,並賦值;

在初始化矩陣陣列的時候為了方便轉置矩陣時的操作,我們把陣列的第一個元素設定為矩陣的列數,行數和元素總數;

矩陣有了,存放矩陣元素的陣列也有了。接下來就是轉置矩陣的函式了。

我們在轉置矩陣的時候會需要一個陣列來儲存轉置後的矩陣,定義為:

主要思想,兩層迴圈,第一層迴圈控制矩陣的行,第二層迴圈控制陣列a的行。由於轉置矩陣即把矩陣中元素的列行對換一下,並且按照行排序;所以我們在第二層迴圈中做一個判斷,if(a[j].col == i) 【i控制第一層迴圈,j控制第二層迴圈】 如果為真值則執行:

整個函式如下:

用此方法可以有效的轉置矩陣,我們來看一下此函式的時間複雜度:O(cols * elements)——矩陣的列*矩陣的元素總和;

如果元素很多就會浪費很多的時間。有沒有辦法讓兩層迴圈變成一層迴圈呢?付出空間上的代價,換取時間效率;

我們只用一層迴圈來遍歷陣列a中所有元素,並把該元素放到指定的位置。這樣我們就需要一個陣列star來存放第i個元素所在位置。在定義這個陣列之前,我們還需要一個陣列term來實現統計矩陣第i行元素的數量。這樣我們才能更方便的知道第i個元素應該存放的位置。

第一個迴圈初始化term,每個元素都為零。第二個迴圈是為了統計第i行元素的數量。第三個迴圈是設定第i個元素所在的位置。因為陣列a的第一個元素是存放行列和元素的總數,因此第三個迴圈要從k = 1開始。此時兩個陣列的元素為:

下一步就是遍歷a中的所有元素,然後根據a[i].col的值來把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]++。為下一個元素設定相應的位置;

完整函式:

此函式每個迴圈體的執行次數分別為cols cols elements elements 時間複雜度為O(cols + elements)和O(cols * elements)相差好多,尤其是clos 和 elements很大的時候;

完整的測試程式:

相關文章