如果矩陣中有很多數值相同的數據元素,在存儲時,可以考慮對其進行適當的壓縮存儲。
有必要壓縮存儲的矩陣大致分為兩大類:
- 矩陣中含有大量的相同數值,稱為特殊矩陣(例如對稱矩陣和上下三角矩陣)。
- 矩陣中只有極少量的元素是非 0 元素,稱為稀疏矩陣。
兩類矩陣壓縮存儲的方法:
- 特殊矩陣中,對於相同的數據元素,只存儲一個。
- 稀疏矩陣中,只需要存儲非 0 元素。
對稱矩陣
如果n階矩陣中的元素滿足: a ij = a ji ( i 為行標, j 為列標),就稱這個矩陣為對稱矩陣。
圖1 對稱矩陣
圖1 為 3 階對稱矩陣,圖中的虛線為矩陣的 “主對角線” ,主對角線上方區域稱為 “上三角” ;主對角線下方稱為 “下三角” ,沿主對角線對稱的數據元素一一相等,所以對於此矩陣來說,只需要存儲 6 個元素即可。
若將對稱矩陣壓縮存儲在一維數組 S[k] 中,矩陣中數據元素在數組中存儲的位置和所在的行標(用 i 表示)和列標(用 j 表示)有關。
對稱矩陣沿主對角線對稱的數據元素相等,任選一邊的數據元素進行存儲即可:
存儲下三角區域的數據元素:


上下三角矩陣
上下三角矩陣,和對稱矩陣類似,不同在於,上三角矩陣是指主對角線下方的元素(不包括主對角線上的)都是常數C(包括數值 0 );同理,下三角矩陣是指主對角線上方的元素都是常數C。例如:

圖2 下三角矩陣
存儲時,上(下)三角存儲上(下)三角的數據元素,除此之外,額外存儲一個下(上)三角含有的常數C(圖 2 中,C==0)。
稀疏矩陣
稀疏矩陣,簡單的說,就是矩陣中只含有少量的非 0 元素,相比於使用普通方式將矩陣中的所有數據元素一一存儲,不如只存儲非 0 元素更節省內存空間。例如:

圖 3 稀疏矩陣
矩陣壓縮存儲的方式
矩陣壓縮存儲的方式有 3 種,分別為:三元組順序表、行邏輯鏈接的順序表和十字鏈表。三元組順序表
在存儲稀疏矩陣時,除了要存儲非 0 元素的值之外,還需要存儲元素所在矩陣中的行標 i 和列標 j ,三個元素構成三元組(行標,列標,元素值)。所以,表示三元組結構需要使用結構體進行自定義:
//三元組結構體 typedef struct
{ int i, j; //行標i,列標j int data; //元素值 }triple;
每個稀疏矩陣的表示,需要存儲矩陣中所有非 0 元素的三元組,並且還需要記錄矩陣的行數和列數,這樣才能唯一確定一個稀疏矩陣。 所以,表示矩陣的結構也需要使用結構體實現: #define number 100 //矩陣的結構表示 typedef struct { triple data[number];//存儲該矩陣中所有非0元素的三元組 int n,m,num;//n和m分別記錄矩陣的行數和列數,num記錄矩陣中所有的非0元素的個數 }TSMatrix; 例如,對於圖 3 的稀疏矩陣來說,即將(2,2,3)、(2,3,4)、(3,2,5)存儲進 data 數組,並且存儲稀疏矩陣的行數3和列數3 ,該稀疏矩陣中非 0 元素有 3 個。
行邏輯鏈接的順序表
使用三元組順序表存儲矩陣后,當需要提取矩陣某一行的非 0 元素時,需要遍歷整個順序表。為了提高查找的效率,在三元組順序表的基礎上,增加一個數組用於記錄每一行第一個非 0 元素的存儲位置,這樣的存儲結構,稱為:行邏輯鏈接的順序表。
結構代碼:
#define number 100
typedef struct
{ int i, j; int data; }triple;
typedef struct
{ triple data[number]; int rpos[number]; //存儲各行第一個非0元素在三元組表中的位置 int n, m, num; }TSMatrix;
十字鏈表
以上兩種存儲稀疏矩陣的方法,說到底,還是操作數組,在進行矩陣運算過程中,如果有插入非 0 元素或者刪除某一個元素的操作,可能需要大量的移動數組中的三元組。這時,就要考慮使用鏈表的存儲結構。例如在進行“將矩陣 B 加到矩陣 A 上”的操作時,矩陣 A 中的數據元素會發生很大的變化,之前的 0 元素可能變成非 0 元素,非 0 元素也可能變成 0 (正負數相加為 0)。在這種情況下,就需要使用鏈表的存儲結構來存儲矩陣,這種存儲方式稱為:十字鏈表法。
例如,將下列矩陣以十字鏈表的方式存儲起來:

圖4 十字鏈表

圖5 十字鏈表中的結點
兩個指針域:一個指向所在列的下一個元素,一個指向所在行的下一個元素。
結構代碼:
typedef struct OLNode
{ int i, j; int data; struct OLNode *right, *down; }OLNode;
//此結構體表示一個矩陣,其中包含矩陣的行數,列數,非0元素的個數以及用於存儲各行以及各列元素頭指針的動態數組rhead和chead。 typedef struct
{ OLNode *rhead, *chead; int n, m, num; }CrossList;
總結
稀疏矩陣的三種不同的存儲方法,采用哪種方法要看程序具體要實現的功能: 如果想完成例如矩陣的轉置這樣的操作,宜采用三元組順序表; 如果想實現矩陣的乘法這樣的功能,宜采用行邏輯鏈接的順序表; 如果矩陣運算過程中(例如矩陣的加法),需要不斷地插入非 0 元素或刪除變為 0 的元素,宜采用十字鏈表法。 有關三種存儲方法的實例:矩陣轉置、矩陣的乘法和矩陣的加法各自利用一節來詳細介紹。