所謂壓縮儲存,是指對多個值相同的元素只分配一個空間,對零元素不分配空間。

一、特殊矩陣

特殊矩陣是指值相同的元素分佈具有一定規律的矩陣,如對角矩陣、三角矩陣,對稱矩陣等,對於此類矩陣,找到一個關係將其元素儲存到一維陣列中,通過這個關係可以對矩陣中的元素進行隨機存取。

二、稀疏矩陣

稀疏矩陣中也含有較多的零元素,但是非零元素的分佈沒有任何規律,因此在儲存非零元素的同時,還必須儲存適當的輔助資訊,才能迅速確定一個非零元素是矩陣中的哪一個元素。稀疏矩陣的表示有很多種方法,下面僅分析用三元組表示稀疏矩陣儲存的方法。
矩陣中非零元素的行號、列號及元素值組成了三元組,三元組按行優先(或列優先)的順序排列得到一個其結點均是三元組的線性表,此外,要唯一的確定一個稀疏矩陣,還必須確定矩陣的行數和列數,為了方便,還要將非零元素個數儲存起來,於是得到稀疏矩陣的一種型別如下:

#define MAX 12
typedef int datatype;
typedef struct 
{
    int i, j;          //行號、列號
    datatype  v;       //元素值
} node;
typedef struct
{
    int m, n, t;  //行數,列數,非零元素個數
    node data[MAX];     //三元組表
}spmatrix;

三、演算法分析舉例

下面以矩陣的轉置簡單說明一下如何用稀疏矩陣進行矩陣運算:
將矩陣A轉置為B,即B[i][j] = A[j][i],這樣看來,其實只需將三元組中的i與j 數值交換即可,但是這樣做,轉置後的矩陣就不會按照行優先或列優先的順序線上性表中排列了。由於A的列是B的行,因此按A的列順序進行轉置,得到的轉置矩陣B必然是按行排列的,具體演算法描述如下:

spmatrix *TransMat(spmatrix *a)     //稀疏矩陣的轉置
{
    int p, q, bno = 0;
    spmatrix *b;
    b = (spmatrix *)malloc(sizeof(spmatrix)); //為矩陣b分配記憶體空間
    b->m = a->n;
    b->n = a->m;
    b->t = 0;
    if (a->t == 0)    //若b中元素全為零,則將b返回
        return b;
    for (p = 0; p < a->n; p++)
        for (q = 0; q < a->t; q++)
            if (a->data[q].j == p)
            {
                b->data[bno].i = a->data[q].j;
                b->data[bno].j = a->data[q].i;
                b->data[bno].v = a->data[q].v;
                bno++;
            }
    b->t = bno;
    return b;
}

上述演算法有雙重迴圈,若A有n列t個非零元素,則演算法複雜度為O(n x t),若用二維矩陣儲存,A有m行n列,則演算法複雜度為O(n x m),一般t遠大於m,因此在此例中,稀疏矩陣轉置演算法執行時間更長一些。

四、完整程式舉例

下面寫一個完成的C程式來測試稀疏矩陣三元組結構及轉置演算法,程式輸入為一個3行4列的整數矩陣,輸出轉置矩陣。

/*  稀疏矩陣的型別說明及轉置演算法  */
#include<stdio.h>
#include<stdlib.h>
#define MAX 12
typedef int datatype;
typedef struct 
{
    int i, j;          //行號、列號
    datatype  v;       //元素值
} node;
typedef struct
{
    int m, n, t;  //行數,列數,非零元素個數
    node data[MAX];     //三元組表
}spmatrix;

spmatrix *Create();     //建立一個3行4列的稀疏矩陣
spmatrix *TransMat(spmatrix *a);     //稀疏矩陣的轉置
void Output(spmatrix *a);      //在螢幕上以行列的形式輸出矩陣

int main()
{
    spmatrix *a = Create();
    spmatrix *b = TransMat(a);
    printf("原矩陣:\n");
    Output(a);
    printf("轉置矩陣:\n");
    Output(b);
    return 0;
}

spmatrix *Create()     //建立一個3行4列的稀疏矩陣
{
    int m = 3, n = 4, k = 0, t = 0;
    datatype element;
    spmatrix *matrix;
    matrix = (spmatrix *)malloc(sizeof(spmatrix));   //建立一個稀疏矩陣a
    matrix->m = m;
    matrix->n = n;
    printf("輸入12個整數:\n");
    while (k < m*n)
    {
        scanf_s("%d", &element);
        if (element != 0)
        {
            matrix->data[t].i = k / n;
            matrix->data[t].j = k % n;
            matrix->data[t].v = element;
            t++;
        }
        k++;
    }
    matrix->t = t;
    return matrix;
}

spmatrix *TransMat(spmatrix *a)     //稀疏矩陣的轉置
{
    int p, q, bno = 0;
    spmatrix *b;
    b = (spmatrix *)malloc(sizeof(spmatrix));   //為矩陣b分配記憶體空間
    b->m = a->n;
    b->n = a->m;
    b->t = 0;
    if (a->t == 0)    //若b中元素全為零,則將b返回
        return b;
    for (p = 0; p < a->n; p++)
        for (q = 0; q < a->t; q++)
            if (a->data[q].j == p)
            {
                b->data[bno].i = a->data[q].j;
                b->data[bno].j = a->data[q].i;
                b->data[bno].v = a->data[q].v;
                bno++;
            }
    b->t = bno;
    return b;
}

void Output(spmatrix *a)
//輸入:稀疏矩陣、行數,列數
//輸出:在螢幕上以行列的形式輸出矩陣
{
    int i = 0, j = 0, k = 0;
    for (i = 0; i < a->m; i++)
    {
        for (j = 0; j < a->n; j++)
        {
            if (i == a->data[k].i && j == a->data[k].j)
            {
                printf("%d ", a->data[k].v);
                k++;
            }
            else
                printf("%d ", 0);
        }
        printf("\n");
    }
}
.