1. 程式人生 > >稀疏矩陣的儲存方法(3種)及C語言程式碼實現

稀疏矩陣的儲存方法(3種)及C語言程式碼實現

稀疏矩陣,即含有少量非 0 元素的矩陣,如圖 1 所示:
 


圖 1 稀疏矩陣 
  該矩陣中非 0 元素的數量比較少,與其使用普通方式將矩陣中的所有資料元素一一儲存,不如只儲存非 0 元素更節省記憶體空間,拿圖 1 中矩陣來說,只需儲存元素 3、4、5 即可(此類儲存方式被稱為稀疏矩陣的壓縮儲存)。
  稀疏矩陣(壓縮)儲存的方式有 3 種,分別為:三元組順序表行邏輯連結的順序表十字連結串列

三元組順序表

儲存稀疏矩陣,需記錄矩陣中每個非 0 元素的 3 個要素:非 0 元素的值、所在行標(用 i 表示)以及所在列標(用 j 表示),每個非 0 元素的 3 要素都可以用一個三元組(行標、列標、元素值)來表示,矩陣中所有非 0 元素的三元組可以通過順序表來儲存。此方法也被稱為稀疏矩陣的三元組表示法


因此,每個非 0 元素的三元組需要使用結構體進行自定義:
//三元組結構體
typedef struct {
    int i,j;//行標i,列標j
    int data;//元素值
}triple;
稀疏矩陣的儲存,一方面要儲存矩陣中所有非 0 元素的三元組,同時還要記錄該稀疏矩陣的行數、列數以及矩陣中非 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 十字連結串列 採用十字連結串列法儲存矩陣的非 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;

總結

稀疏矩陣的三種不同的儲存方法,採用哪種方法要看程式具體要實現的功能:

  1. 如果想完成例如矩陣的轉置這樣的操作,宜採用三元組順序表;
  2. 如果想實現矩陣的乘法這樣的功能,宜採用行邏輯連結的順序表;
  3. 如果矩陣運算過程中(例如矩陣的加法),需要不斷地插入非 0 元素或刪除變為 0 的元素,宜採用十字連結串列法。

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