一、實驗內容
1.實驗目的
三元組是數據結構里的一個重要概念,主要是用來存儲稀疏矩陣的一種壓縮方式,也叫三元組表。采用順序存儲結構來表示的三元組稱為三元組順序表。本實驗使用高級編程C語言來構建一個三元組順序表存儲的稀疏n階方陣,求解該方陣中兩條對角線上的元素之和並實現該方陣的快速轉置。體會並掌握數據結構中通過三元組存儲結構實現矩陣壓縮的方法和實踐過程。
2.實驗內容
1) 構建一個三元組順序存儲結構的抽象數據類型,通常應包含如下步驟:
a.定義用來描述三元組的結構體變量類型Triple,成員包括i,j,value分別對應矩陣元素的行標、列標和值;
b.編寫一個矩陣壓縮算法,記為zipMatrix操作(函數),將稀疏矩陣轉化成三元組順序表;
c.編寫一個矩陣對角線求和算法,記為sumMatrix操作(函數);
d. 編寫一個快速轉置算法,記為SwapMatrix操作(函數);
2)基於上述三元組順序表存儲的基本操作實現矩陣壓縮和快速轉置:
a.在main函數內部聲明一個包含少量非零值的二維數組和一個三元組結構體數組,分別表示稀疏矩陣和三元組順序表;
b.調用zipMatrix函數,將稀疏矩陣轉化成三元組順序表,實現矩陣壓縮;
c.調用swapMatrix函數,實現矩陣的快速轉置;
d.編譯運行程序,評估實驗結果.
3)完成實驗報告的填寫
3.實驗原理
(1)稀疏矩陣:在矩陣中,若數值為0的元素數目遠遠多於非0元素的數目,並且非0元素分布沒有規律時,則稱該矩陣為稀疏矩陣.
(2)三元組順序表存儲的邏輯結構原理(即矩陣壓縮原理)如下:
矩陣的轉置實際上就是將數據元素的行標和列標互換,即 T(i,j) = M(j,i) 。
三元組相應地轉變為:
二、實驗過程
1.Triple結構體定義
首先用C/C++開發環境新建源文件,首先鍵入如下預定義命令行:
#include <stdio.h> #define MAXSIZE 30 #define n 6
使用C語言里的宏定義聲明兩個常量MAXSIZE和n,MAXSIZE表示三元組順序表的初始化大小,n表示矩陣的階數。
接着,根據三元組順序表的邏輯結構原理圖,定義用來描述三元組數據對象的結構體變量類型Triple,代碼如下:
typedef int ElemType; /* 定義三元組 */ typedef struct{ int i, j; ElemType value; }Triple;
這里用i、j和value分別表示數據元素在稀疏矩陣的行標、列標和值(int型)。
2. zipMatrix函數
編寫矩陣壓縮算法,在參數列表中接受一個n階int型矩陣arr和一個三元組指針t。聲明一個int變量index來統計矩陣壓縮后獲得的三元組順序表的數據元素個數。row和col是用來遍歷矩陣行和列的循環變量。遍歷過程中,遇到非零元素,將其在稀疏矩陣中的行標(第一行記為1)、列標(第一列記為1)和元素值分別賦給當前指針t所指向的三元組順序表元素的i、j和value。然后指針t自增指向下一個三元組順序表元素。最終返回三元組順序表的有效長度。
代碼如下:
/* 矩陣壓縮 */ int zipMatrix(int arr[n][n], Triple *t){ int index=0; int row,col; for(row=0;row<n;row++) for(col=0;col<n;col++){ if(arr[row][col]!=0){ t->i=row+1,t->j=col+1; t->value=arr[row][col]; t++; index++; } } return index; }
3. sumMatrix函數
編寫sumMatrix函數計算稀疏矩陣對角線上數據元素之和,對角線元素對應滿足成員i等於成員j(主對角線元素)或者成員i與j之和為n+1的三元組順序表元素。將符合條件的三元組的value值累加求和。
/* 對角線求和 */ int sumMatrix(Triple t[], int size){ int sum=0; for(int k=0;k<size;k++){ if(t[k].i==t[k].j||(t[k].i+t[k].j)==n+1){ sum=sum+(t[k].value); } } return sum; }
4. swapMatrix函數
算法思路
i |
j |
v |
1 |
2 |
4 |
1 |
3 |
7 |
2 |
1 |
6 |
2 |
2 |
5 |
3 |
7 |
8 |
4 |
3 |
3 |
5 |
6 |
2 |
j表示數據元素的列標,由於經轉置后以行標為主序(即原來的列標),所以首先統計出每一列的非零元素個數,上述為第一列1個元素、第二列2個元素、第三列2個元素、第四列0個元素、第五列0個元素、第六列1個元素和第七列1個元素。
用一個數組col來記錄每一列的個數(數組索引對應列數)
col[1] |
col[2] |
col[3] |
col[4] |
col[5] |
col[6] |
col[7] |
1 |
2 |
2 |
0 |
0 |
1 |
1 |
接着計算每一列首個非零元的位置次序:
用一個數組p來記錄,默認第一列的首個非零元位置次序為1,p[1]=1,列標與索引一致;
第二列首個非零元位置次序為1+col[1];
以此類推,p[i]=p[i-1]+col[i-1],i=2,3,…,n;
col[1~7] |
1 |
2 |
2 |
0 |
0 |
1 |
1 |
p[1~7] |
1 |
2 |
4 |
6 |
6 |
6 |
7 |
最后遍歷每個三元組表元素,由於i值遞增,所以不同j值首次出現則對應該列的首個非零元。如果再次出現相同的j值,該三元組向后依次插入數組。
上述三元組表經轉置得到
j |
i |
v |
1 |
2 |
6 |
2 |
1 |
4 |
2 |
2 |
5 |
3 |
1 |
7 |
3 |
4 |
3 |
6 |
5 |
2 |
7 |
3 |
8 |
其中(1,2,4)(2,1,4)(3,1,7)(6,5,2)(7,3,8)分別是現各行首個非零元,次序為1,2,4,6和7.與上述表一致。算法設計可行且正確。
具體操作
編寫swapMatrix函數實現矩陣的快速轉置(對應於三元組的轉置),代碼如下:
1. 參數列表接收一個三元組順序表(表現為Triple數組t)和一個int型變量size;
2. 初始化一個大小為size的三元組順序表T;
3. 初始化三個大小為n+1的int數組p、col和num;
4. 統計稀疏矩陣每一列的數據元素個數,並將第e列(e=1,2,…,n)的元素個數賦給col[e];
5. 計算每一列首個非零元的存儲位序,默認第一列首個非零元的存儲位序為1;
6. 遍歷三元組表t,實現快速轉置得到轉置后的三元組表T;
7. 打印三元組表T;
/* 快速轉置 */ void swapMatrix(Triple t[], int size){ Triple T[MAXSIZE]={}; int num[n+1]={}; int p[n+1]={}; int col[n+1]={}; int temp,k; for(k=0;k<size;k++){ col[t[k].j]++; } // 構造數組num,從num[1]開始表示每一列的非零元素的個數 for(k=1;k<=n;k++){ num[k]=col[k]; } p[1]=1; // 構造數組p,從p[1]開始定位每一列的第一個非零元素的位置 for(k=2;k<=n;k++){ p[k]=p[k-1]+num[k-1]; } // 快速轉置 for(k=0;k<size;k++){ temp=p[t[k].j]-1; while(T[temp++].value!=0); T[temp-1].i=t[k].j; T[temp-1].j=t[k].i; T[temp-1].value=t[k].value; } // 遍歷輸出三元組順序表T for(k=0;k<size;k++){ printf("(%d,",T[k].i); printf("%d,",T[k].j); printf("%d)",T[k].value); } }
5. main函數的實現
int main(){ // 定義一個矩陣(二維數組) int arr[n][n]={{0,0,6,4,0,9}, {7,3,8,0,0,0},{0,4,0,2,0,0}, {6,3,0,0,0,1},{4,0,9,0,1,0}, {3,0,0,0,7,0} }; // 初始化一個三元組 Triple t[MAXSIZE]={}; // 定義一個三元組指針 Triple *T=t; // 調用zipMatrix函數,返回int int size=zipMatrix(arr,T); // 調用sumMatrix函數,返回int int sum=sumMatrix(t,size); printf("對角線元素之和為%d\n",sum); printf("原三元組\n"); // 打印原三元組順序表 for(int k=0;k<size;k++){ printf("(%d,",t[k].i); printf("%d,",t[k].j); printf("%d)",t[k].value); } printf("\n"); printf("經轉置的三元組\n"); // 調用swapMatrix函數,實現快速轉置 swapMatrix(t,size); return 0; }
1. 聲明一個n階的int型稀疏方陣arr,並初始化;
2. 初始化一個大小為MAXSIZE的三元組數組t和一個初始值指向數組t基地址的指針T;
3. 調用zipMatrix函數並傳入參數arr和T,返回值賦給size;
4. 調用sumMatrix函數並傳入參數t和size,返回值賦給sum;
5. 打印原三元組順序表;
6. 調用swapMatrix函數並傳入參數t和size,實現快速轉置;
7. 編譯運行,測試代碼.
三、實驗結果
實驗結果與預期目標一致,能夠實現三元組順序表存儲稀疏矩陣、能夠正確計算出n階方陣對角線元素之和以及實現方陣的快速轉置(用三元組表來表示)。
四、實驗總結
通過“三元組順序表存儲的稀疏矩陣練習”這個實驗,利用三元組順序結構來實現對稀疏矩陣的壓縮存儲、計算對角線元素之和以及對n階方陣的快速轉置。
在實驗的過程中,體會到了采用三元組順序表存儲稀疏矩陣的優點,就本實驗而言,稀疏矩陣中的非零元遠少於零元,從存儲空間的意義來看,稀疏矩陣浪費了一定的存儲資源。而通過矩陣壓縮,使用三元組表來存儲稀疏矩陣會大大減少不必要的空間開銷。
三元組順序表結構對於實現n階方陣的快速轉置有着重要的作用。普通轉置需要從行和列兩個維度遍歷數據元素,時間復雜度為O(n^2)。而快速轉置利用每一列中首個非零元的具體位置來實現一次遍歷即可轉置。本實驗采用三元組轉置來表示方陣的轉置。
總的來說加深理解有關三元組順序表結構實現稀疏矩陣壓縮存儲和快速轉置,並體會和了解選擇不同的數據結構會影響算法的空間復雜度和時間復雜度。