5.3矩阵乘积(三元组存储结构)
行邏輯鏈表的順序表
為了便于隨機存取任意一行的非零元,則需要知道每一行的第一個非零元在三元組表中的位置。為此,可將上節快速轉置矩陣中的算法創建的,指示“行”信息的輔助數組cpot固定在稀疏矩陣的存儲結構中。稱這種"帶行鏈接信息"的三元組表為行邏輯鏈接的順序表。
描述如下:
typedef struct{Triple data[MAXSIZE + 1]; //非零元三元組表int rpos[MAXRC + 1]; //各行第一個非零元的位置表int mu, nu, tu; //矩陣的行數、列數和非零元個數 }RLSMatrix;P·S
這里的MAXSIZE在上一節有交代。這個data[MAXSIZE+1]為什么要加一呢,因為data[0]未用,同樣rpos[MAXRC+1]也是這個道理。
如下圖所示:
P·S:本人字丑,大家將就看吧。
另外大家要知道矩陣相乘的條件:矩陣只有當左邊矩陣的列數等于右邊矩陣的行數時,它們才可以相乘,乘積矩陣的行數等于左邊矩陣的行數,乘積矩陣的列數等于右邊矩陣的列數。
這樣我們就知道,當一個不用三元組表示的矩陣M(m1行n1列)和一個矩陣n(m2行n2列)相乘時,有一個經典算法,就和上面那數學運算一模一樣。
代碼如下:
for (i = 1; i <= m1; i++) {for (j = 1; j <= n2; j++){Q[i][j] = 0;for (k = 1; k <= n1; k++){Q[i][j] += M[i][k] * N[K][j];}} }分析下:
因為產生的矩陣是m1行n2列的矩陣,所以第一個for里面限定條件是m1,第二個for限定條件是n2,第三個for就是把第一個矩陣里面的行和第二個矩陣的列相乘并且加起來。這個Q[i][j]的作用就是先把存儲到那一塊的內存初始化,免得有其他數據影響。
也就是說當M和N是稀疏矩陣并用三元組表作存儲結構時,不能用上面那個算法。
如下面這個例子:
那么,他們的三元組M.data、N.data和Q.data分別為:
在此補充下rpos
矩陣N的rpos值(代碼中會用到)
| row | 1 | 2 | 3 | 4 |
| rpos[row] | 1 | 2 | 3 | 5 |
矩陣M的rpos值
| row | 1 | 2 | 3 |
| rpos[row] | 1 | 3 | 4 |
rpos[row]指:第row行中第一個非零元在N.data中的序號。不難理解。大家對照上面的表就能填出來。
下面給出書中的偽代碼:
2017年版的嚴蔚敏版數據結構
Status MultSMatrix(RLSMatrix M, RLSMatrix N, RLSMatrix &Q) {// 求矩陣乘積Q=M*N,采用行邏輯鏈接存儲表示。int arow, brow, p, q, t, ctemp[30], l, ccol, tp;if (M.nu != N.mu) return ERROR;Q.mu = M.mu; Q.nu = N.nu; Q.tu = 0; // Q初始化if (M.tu*N.tu != 0) { // Q是非零矩陣for (arow = 1; arow <= M.mu; ++arow) { // 處理M的每一行for (l = 1; l <= M.nu; ++l) ctemp[l] = 0; // 當前行各元素累加器清零Q.rpos[arow] = Q.tu + 1;if (arow < M.mu) tp = M.rpos[arow + 1];else tp = M.tu + 1;for (p = M.rpos[arow]; p < tp; ++p) { // 對當前行中每一個非零元 brow = M.data[p].j; // 找到對應元在N中的行號if (brow < N.mu) t = N.rpos[brow + 1];else t = N.tu + 1;for (q = N.rpos[brow]; q< t; ++q) {ccol = N.data[q].j; // 乘積元素在Q中列號ctemp[ccol] += M.data[p].e * N.data[q].e;} // for q} // 求得Q中第crow( =arow)行的非零元for (ccol = 1; ccol <= Q.nu; ++ccol) // 壓縮存儲該行非零元if (ctemp[ccol]) {if (++Q.tu > MAXSIZE) return ERROR;Q.data[Q.tu].i = arow;Q.data[Q.tu].j = ccol;Q.data[Q.tu].e = ctemp[ccol];} // if} // for arow} // if return OK; } // MultSMatrix分析下:
這里,我們要有一個思路:在經典算法里面,無論M(i,k)和N(k,j)的值是否為0,都要進行一次乘法運算,而實際上,這兩者有一個值不為0時,其乘積也是0.所以,在稀疏矩陣進行運算時,要避免這種無效果操作,只需要在M.data和N.data中找到相應的各對元素(即M.data中的j值和N.data中的i值相等的各元素)乘積即可。
此函數一開始的M.nu!=N.mu就返回ERROR,這就是我剛剛說的矩陣要相乘應該滿足的條件。
在if語句M.tu*N.tu!=0,這是為了判斷他是不是非0矩陣,如果是非0矩陣,就直接返回。
在這個for(l=1;l<=M.nu;++l)里面這個是把nu是列。這時可能有人會問,為什么nu是列,而注釋里面是把當前行各元素累加器清0,原因是他把當前行的元素清0,當前行到底有多少個元素,只能靠列來算。
隨后的Q.rpos[arow]=Q.tu+1;這里有網友可能會問兩個問題,一個是這個這個Q.rpos[arow]有什么用把后面那個賦值給他有什么含義,第二個就是為什么要Q.tu+1(為什么要總元素+1)。Q.rpos[arow]這個東西就是Q中各行第一個非零元的位置表。Q.tu+1是因為第一個就是1,這里面不可能從0開始。
下面這個if(aow<M.mu)else這個,這個tp是得到了下一行的第一個元素的位置。所以拿他當下面那個for循環的限制條件。
剩下的代碼和上面的有很多相似之處,在此不再說明了。
總結
以上是生活随笔為你收集整理的5.3矩阵乘积(三元组存储结构)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 5.3稀疏矩阵的十字链表存储
- 下一篇: 5.1数组的定义5.2数组的顺序表示和实