[データ構造の原理]スパース行列-スパース行列

コンテンツ

スパース行列(THE SPARSE MATRIX)

0x00 ADT

 0x01ADT-スパース行列

0x02スパース行列の表現

0x03行列の転置-行列の転置

0x04行列の乗算


スパース行列(THE SPARSE MATRIX)

0x00 ADT

スパース行列:行列A 内の非ゼロ要素の数がゼロ要素の数よりもはるかに少ない場合、それをスパース行列A と呼びます

2D配列を使用してスパース行列を表す場合、同じ値(0)を格納するために多くのスペースを使用するだけでなく、行列が大きい場合、ほとんどのコンパイラが機能するため、この実装は機能しません配列のサイズには制限がありません。

 0x01ADT-スパース行列

0x02スパース行列の表現

行列内の任意の要素を一意に表すことができ、row、col、valueを使用して、スパース行列内のゼロ以外の要素を格納および検索できます。スパース行列を格納するこの方法は、トリプルと呼ばれます。

by a triple <row, col, value>.

行インデックスが昇順になるようにトリプルを編成し、同じ行インデックスを持つトリプル内では、列インデックスの昇順になるように編成します。

操作を確実に停止するには、行と列の数、および行列内のゼロ以外の要素の数を知る必要があります。

// Sparse_Matrix Create(max_row, max_col) ::=

#define Max_TERMS 101 /* maximum number of terms +1*/
typedef struct {
    int col;
    int row;
    int value;
} term;
term a[MAX_TERMS];

0x03行列の転置-行列の転置

<単純なアルゴリズム>

各行に対して 私

        要素 <i、j、value> を取り、それを保存します

        転置された要素として <j、i、value> 

以前のすべての要素を処理するまで、どの要素が転置されているかは正確にはわかりません。 <j、i、value>

次のように、どこに配置されますか。

 連続して挿入する必要があります。順序を正しく保つために要素を移動する必要があります。

列のインデックスを使用してマトリックス内の要素の位置を決定することにより、このデータの移動を回避できます。

j 列のすべての要素 について 、要素<i、j、value> を要素に 配置します<j、i、value>

【プログラム2.8】

時間計算量:  O(列\ cdot要素)

の場合  要素=O(行\ cdot列)、にO(列\ cdot要素) なり O(rows \ cdot columns ^ 2)ます。

 密な表現を使用した転置アルゴリズム

for (j = 0; j < columns; j++)
    for (i = 0; i < rows; i++)
        b[j][i] = a[i][j];

時間計算量:O(行\ cdot列)

もう少しストレージスペースを使用することによるより良いアルゴリズム

fast_transpose

アルゴリズムは、最初に元の行列の各列の要素数を決定します。

この数は、転置された行列の各行の要素の数を示します。

時間計算量:O(行\ cdot要素)

の場合 要素=O(行\ cdot列) 、

その後に O(列+要素) なります O(行\ cdot列)

追加の配列row_termsとstarting_posが使用されます。

row_termsで使用されるスペースに開始位置を配置すると、スペースを配列に減らすことができます。

0x04行列の乗算

与えられた2つの行列の合計 A 、 Bここで A is m * n とB is n * p

製品マトリックス D は m * pであり、その <i、j> 要素は次のとおりです。

d_ {i、j} = \ sum_ {k = 0} ^ {n-1} \、\、a_ {ik} \、\、b_ {kj}        0 \ geq i <m、\、\、0 \ leq j <p

<密な表記法を使用した行列乗算アルゴリズム>

for (i = 0; i < rows_a; i++) {
    for (j = 0; j < cols_b; j++) {
        sum = 0;
        for (k = 0; k < cols_a; k++)
            sum += a[i][k]*b[k][j];
        d[i][j] = sum;
    }
}

時間計算量: O(rows \、\ cdot cols \、a \ cdot cols \、b)

2つのスパース行列の積がスパースではなくなる可能性があることに注意してください。例えば:

【プログラム2.10】

行列 ABD は配列 abd に個別に格納B され、転置はnew_bに格納されます。

変数変数を使用します。

row - 目前正在与B的列相乘的A的行
row_begin - 当前行的第一个元素在a中的位置
column - 目前正在与A的某一行相乘的B的列
totald - 乘积矩阵D的当前元素数
i, j - 用于连续检查A行和B列中的元素的指针
void mmult(term a[], term b[], term d[])
/* multiply two sparse matrices */
{
    int i, j, column, totalb = b[0].value, totald = 0;
    int rows_a = a[0].row, cols_a = a[0].col, totala = a[0].value;
    int cols_b = b[0].col;
    int row_begin = 1, row = a[1].row, sum = 0;

    term new_b[MAX_TERMS];
    if (col_a != b[0].row) {
        fprintf(stderr, “Incompatible matrices\n”);
        exit(1);
    }
    fast_transpose(b, new_b);
    /* set boundary condition */
    a[totala+1].row = rows_a;
    new_b[totalb+1].row = cols_b; new_b[totalb+1].col = -1;
   
    for (i = 1; i <= totala; ) {
        column = new_b[1].row;
        for (j = 1; j <= totalb+1; ) {
        /* multiply row of a by column of b */
            if (a[i].row != row) {
                storesum(d, &totald, row, column, &sum);
                i = row_begin;
                for ( ; new_b[j].row == column; j++)
                                ;
                column = new_b[j].row;
            }
            else if (new_b[j].row != column) {
                storesum(d, &totald, row, column, &sum);
                i = row_begin;
                column = new_b[j].row;
            }
            else switch (COMPARE(a[i].col, new_b[j].col)) {
                case –1 : /* go to next term in a */
                    i++; break;
                case 0 : /* add terms, go to next term in a and b */
                    sum += (a[i++].value * new_b[j++].value);
                    break;
                case 1 : /* go to next term in b */
                    j++;
            }
        } /* end of for j <= totalb+1 */
        for ( ; a[i].row == row; i++)
                ;
        row_begin = i; row = a[i].row;
    } /* end of for i <= totala */
    d[0].row = row_a; d[0].col = cols_b;
    d[0].value = totald;
}

aとnew_bの両方に追加のアイテムを導入することに注意してください。

a[totala+1].row = rows_a;
new_b[totalb+1].row = cols_b;
new_b[totalb+1].col = -1;

時間計算量

forループの前:

fast transpose - O(cols_b + totalb) time.

外側のforループはrows_a回繰り返されます。

各反復で、積行列Dの1つの行が内側のforループによって計算され、各反復でiまたはjのいずれかが両方とも1ずつインクリメントされるか、iがrow_beginにリセットされます。

jの最大合計増分はtotalb+1です。次に、k番目の行が処理されると、iは最大で数回インクリメントでき、iは最大でrow_beginのcols_b倍にリセットされます。したがって、iの最大合計増分はcols_b-です。内部のforループにはO(cols_b- + totalb) 時間がかかり、列がリセットされます。したがって、外側のforループは

\ sum_ {k = 0} ^ {rows_a-1} O(cols_b \ cdot r_k + totalb)

= O(cols_b \ cdot \ sum_ {k = 0} ^ {rows_a-1} r_k + rows_a \ cdot totalb)

= O(cols_b \ cdot totala + rows_a \ cdot totalb)

totala = O(rows_a \ cdot cols_a) と の場合 totalb = O(rows_b \ cdot cols_b) 、彼の時間計算量はになり O(rows_a \ cdot cols_a \ cdot cols_b) ます。

おすすめ

転載: blog.csdn.net/weixin_50502862/article/details/123682726