5.3矩阵的压缩存储(稀疏矩阵转置和快速转置)
在矩陣中有許多值相同的元素或者是零元素。有時為了節省存儲空間,可以對這類矩陣進行壓縮存儲。所謂的壓縮存儲是指:為多個值相同的元值分配一個存儲空間;對零元不分配空間。
5.32稀疏矩陣
在m*n的矩陣中,有t個元素不為零。零α=t/m*n,稱 α為矩陣的稀疏因子。通常認為α<=0.05時稱為稀疏矩陣。
對于稀疏矩陣的非零元我們有下面這個表示:
如:(,(1,2,12),(1,3,9),(3,1,-3),(3,6,14),(4,3,24),(5,2,18),(6,1,15),(6,4,-7))
如下圖所示:
下面我們來看下三元組的結構體:
下面是書中代碼(嚴蔚敏版的數據結構)
#define MAXSIZE 12500 //非零元素個數的最大值為12500 typedef struct{int i, j; //該非零元的行下標和列下標ElemType e; }Triple;typedef struct{Triple data[MAXSIZE + 1]; //非零元三元組表,data[0]未用int mu, nu, tu; //矩陣的行數、列數和非零元個數 }TSMatrix; 分析下:這里的思路和我們在鏈表上看到的有相似之處,結點變成了非零元素,線性表編程了非零元三元組的表。但多出了矩陣的行數,列數和非零元個數
對應一個m*n的矩陣M它的轉置矩陣是T,如下圖所示:
P·S:所謂的置換就是行和列進行交換,也就是關于主對角線對稱(矩陣左上角到右下角的線稱為主對角線)
而在程序里面,他將會是下面這張圖這樣:
這里的i對應行,j對應列,v表示值。
從分析a和b之間的差異可見只要做到:
1.將矩陣的行列值相互轉換。
2.將每個三元組中的i和j交換。
3.重排三元組之間的次序便可實現矩陣的轉置。
下面是書中給我們提供的偽代碼:
Status TransposeSMatrix(TSMatrix M, TSMatrix &T) { // 采用三元組順序表存儲表示,求稀疏矩陣M的轉置矩陣Tint p, q, col;T.mu = M.nu; T.nu = M.mu; T.tu = M.tu;if (T.tu) {q = 1;for (col = 1; col <= M.nu; ++col)for (p = 1; p <= M.tu; ++p)if (M.data[p].j == col){T.data[q].i = M.data[p].j; T.data[q].j = M.data[p].i;T.data[q].e = M.data[p].e; ++q;}}return Ok; } // TransposeSMatrix 下面來分析下:col表示列,從M矩陣的第一列開始。比如col=1時,他先檢索M的第一列,把非零元中第一列的換成T中的第一行,就這個思路。
原理是:如果能預先確定矩陣M中每一列(即T中每一行)的第一個非零元在b.data中(上面那圖是b.data)恰當位置。那么在對a.data中的三元組一次做轉置時,便可直接放到b.data中恰當的位置上去。
設兩個向量:num和cpot
num[col]表示矩陣M中第col列中的非零元素個數。
cpot[col]指M中第col列的第一個非零元在b.data中的恰當位置。
有下面兩個公式:
cpot[1]=1;
cpot[col]=copt[col-1]+num[col-1] 2<=col<=a.nu
圖如下:
下面來分析下這個表:
cpot[1]=1.
cpot[2]=num[1]+cpot[1]=1+2=3
cpot[3]=num[2]+cpot[2]=2+3=5
cpot[4]=num[3]+cpot[3]=2+5=7
cpot[5]=num[4]+cpot[4]=1+7=8
cpot[6]=num[5]+cpot[5]=0+8=8
cpot[7]=num[6]+cpot[6]=1+8=9
這個表就是這么填的,但是在代碼里面就不一樣了。我這里先提一下,代碼里面有覆蓋和范圍這種概念,這是什么意思,意思就是,大家看cpot[5]和cpot[6]都是8,那么在最后,他只會保留cpot[6],而cpot[7]他這里是9,但本身就只有8個元素,哪來第九個呢?所以這個cpot[9]在程序里面是沒有用的。
這個程序的關鍵就是他只用了一個for循環,而上面那個程序用了兩個for循環,這使得時間復雜度降低了。這個for(p=1;p<M.tu;++p).這個就是我剛剛在上表說的那個意思。這里有個++cpot[col]這是個關鍵
現在來解釋下++cpot[col]:
我們可以看到上表中cpot[col]只有1,3,5,7,8而2,4,5沒有,所以用了這個++cpot[col]后他就把每一列的第一個元素移到了第二個。
不懂的同學單步調試下。
#include <stdio.h> #include <windows.h> #define MAXSIZE 1250 #define OK 1 #define ERROR 0 #define TRUE 1 #define FLASE 0 typedef int Status; typedef int ElemType;typedef struct{int i, j; //該非零元的行下標和列下標 ElemType e; //非零元對應的值 }Triple;typedef struct{Triple data[MAXSIZE + 1]; //非零元三元組表,data[0]未用 int mu, nu, tu; //矩陣的行數,列數,非零元個數 }TSMatrix;Status FastTransposeSMatrix(TSMatrix M, TSMatrix &T) //快速轉置 { //采用三元組順序表存儲表示,求稀疏矩陣M的轉置矩陣T T.mu = M.nu;T.nu = M.mu;T.tu = M.tu;if (T.tu){int col;int num[100], cpot[100];for (col = 1; col <= M.nu; ++col)num[col] = 0; //num數組的初始化 for (int t = 1; t <= M.tu; ++t)++num[M.data[t].j]; //求M中每一列含有的非零元個數 cpot[1] = 1;for (col = 2; col <= M.nu; ++col)cpot[col] = cpot[col - 1] + num[col - 1]; //求cpot向量 int q;for (int p = 1; p <= M.tu; ++p){col = M.data[p].j;q = cpot[col];T.data[q].i = M.data[p].j;T.data[q].j = M.data[p].i;T.data[q].e = M.data[p].e;++cpot[col];}//for }//if return OK; }//FastTransposeSMatrix Status main() {TSMatrix M;TSMatrix T;printf("請輸入原矩陣:\n");printf("行數、列數: ");scanf_s("%d%d", &M.mu, &M.nu);printf("元素總數: ");scanf_s("%d", &M.tu);printf("輸入各個對應壓縮值:\n");for (int i = 1; i <= M.tu; ++i)scanf_s("%d%d%d", &M.data[i].i, &M.data[i].j, &M.data[i].e);FastTransposeSMatrix(M, T);printf("轉置后行數、列數、元素總數非別為:\n%d %d %d\n\n", T.mu, T.nu, T.tu);printf("值為:\n");for (int t = 1; t <= T.tu; ++t)printf("%d %d %d\n", T.data[t].i, T.data[t].j, T.data[t].e);system("pause");return OK; }運行結果如下:
和下面這圖是不是一模一樣
總結
以上是生活随笔為你收集整理的5.3矩阵的压缩存储(稀疏矩阵转置和快速转置)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: delay在java中有什么用_java
- 下一篇: Qt creator5.7 OpenCV