數據結構24:矩陣壓縮存儲(十字鏈表、三元組順序表、行邏輯鏈接的順序表)


如果矩陣中有很多數值相同的數據元素,在存儲時,可以考慮對其進行適當的壓縮存儲。


有必要壓縮存儲的矩陣大致分為兩大類:
  • 矩陣中含有大量的相同數值,稱為特殊矩陣(例如對稱矩陣和上下三角矩陣)。
  • 矩陣中只有極少量的元素是非 0 元素,稱為稀疏矩陣。

兩類矩陣壓縮存儲的方法:
  1. 特殊矩陣中,對於相同的數據元素,只存儲一個。
  2. 稀疏矩陣中,只需要存儲非 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 的稀疏矩陣來說,即將(223)、(234)、(325)存儲進 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 十字鏈表
采用十字鏈表法存儲矩陣的非 0 元素時,鏈表中的結點由 5 部分組成:

圖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 的元素,宜采用十字鏈表法。

有關三種存儲方法的實例:矩陣轉置、矩陣的乘法和矩陣的加法各自利用一節來詳細介紹。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM