稀疏矩阵表示 |第 3 组(企业社会责任)
如果矩阵中的大多数元素为零,则该矩阵称为稀疏矩阵。将零元素存储在矩阵中是一种浪费,因为它们不会影响我们的计算结果。这就是为什么我们以比标准二维数组更有效的表示来实现这些矩阵。使用更有效的表示,我们可以显着降低操作的空间和时间复杂性。
我们在以下文章中讨论了 4 种不同的表示:
- 稀疏矩阵表示 |设置 1
- 稀疏矩阵表示 |设置 2 。
在本文中,我们将讨论稀疏矩阵的另一种表示形式,通常称为耶鲁格式。
CSR(压缩稀疏行)或耶鲁格式类似于稀疏矩阵的数组表示(在 Set 1 中讨论)。我们用三个称为 A、IA、JA 的一维数组或向量来表示矩阵 M (m * n)。让NNZ表示 M 中非零元素的数量,并注意使用基于 0 的索引。
- A 向量的大小为 NNZ,它存储矩阵的非零元素的值。值按逐行遍历矩阵的顺序出现
- IA 向量的大小为 m+1,存储非零元素的累积数量,直到(不包括)第 i 行。它由递归关系定义:
- IA[0] = 0
- IA[i] = IA[i-1] + 矩阵第 (i-1) 行中非零元素的数量
- JA 向量存储了 A 向量中每个元素的列索引。因此它的大小也是 NNZ。
为了找到第 i 行中非零元素的数量,我们执行 IA[i+1] – IA[i]。请注意,这种表示与基于数组的实现有何不同,其中第二个向量存储非零元素的行索引。
以下示例显示了这些矩阵的表示方式。
例子:
Input : 0 0 0 0
5 8 0 0
0 0 3 0
0 6 0 0
Solution: When the matrix is read row by
row, the A vector is [ 5 8 3 6]
The JA vector stores column indices
of elements in A hence, JA = [ 0 1 2
1]. IA[0] = 0. IA[1] = IA[0] + no
of non-zero elements in row 0
i.e 0 + 0 = 0.
Similarly,
IA[2] = IA[1] + 2 = 2
IA[3] = IA[2] + 1 = 3
IA[4] = IA[3]+1 = 4
Therefore IA = [0 0 2 3 4]
The trick is remember that IA[i]
stores NNZ upto and not-including
i row.
Input : 10 20 0 0 0 0
0 30 0 4 0 0
0 0 50 60 70 0
0 0 0 0 0 80
Output : A = [10 20 30 4 50 60 70 80],
IA = [0 2 4 7 8]
JA = [0 1 1 3 2 3 4 5]
算法
SPARSIFY (MATRIX)
Step 1: Set M to number of rows in MATRIX
Step 2: Set N to number of columns in MATRIX
Step 3: I = 0, NNZ = 0. Declare A, JA, and IA.
Set IA[0] to 0
Step 4: for I = 0 ... N-1
Step 5: for J = 0 ... N-1
Step 5: If MATRIX [I][J] is not zero
Add MATRIX[I][J] to A
Add J to JA
NNZ = NNZ + 1
[End of IF]
Step 6: [ End of J loop ]
Add NNZ to IA
[ End of I loop ]
Step 7: Print vectors A, IA, JA
Step 8: END
CPP
// CPP program to find sparse matrix rep-
// resentation using CSR
#include
#include
#include
using namespace std;
typedef std::vector vi;
typedef vector > matrix;
// Utility Function to print a Matrix
void printMatrix(const matrix& M)
{
int m = M.size();
int n = M[0].size();
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++)
cout << M[i][j] << " ";
cout << endl;
}
}
// Utility Function to print A, IA, JA vectors
// with some decoration.
void printVector(const vi& V, char* msg)
{
cout << msg << "[ ";
for_each(V.begin(), V.end(), [](int a) {
cout << a << " ";
});
cout << "]" << endl;
}
// Generate the three vectors A, IA, JA
void sparesify(const matrix& M)
{
int m = M.size();
int n = M[0].size(), i, j;
vi A;
vi IA = { 0 }; // IA matrix has N+1 rows
vi JA;
int NNZ = 0;
for (i = 0; i < m; i++) {
for (j = 0; j < n; j++) {
if (M[i][j] != 0) {
A.push_back(M[i][j]);
JA.push_back(j);
// Count Number of Non Zero
// Elements in row i
NNZ++;
}
}
IA.push_back(NNZ);
}
printMatrix(M);
printVector(A, (char*)"A = ");
printVector(IA, (char*)"IA = ");
printVector(JA, (char*)"JA = ");
}
// Driver code
int main()
{
matrix M = {
{ 0, 0, 0, 0, 1 },
{ 5, 8, 0, 0, 0 },
{ 0, 0, 3, 0, 0 },
{ 0, 6, 0, 0, 1 },
};
sparesify(M);
return 0;
}
输出:
0 0 0 0 1
5 8 0 0 0
0 0 3 0 0
0 6 0 0 1
A = [ 1 5 8 3 6 1 ]
IA = [ 0 1 3 4 6 ]
JA = [ 4 0 1 2 1 4 ]
笔记
- 矩阵的稀疏性 = ( 元素总数 – 非零元素数) / ( 元素总数) 或 (1 – NNZ/mn) 或 (1 – size(A)/mn)。
- 基于直接数组的表示需要内存 3 * NNZ,而 CSR 需要 (2*NNZ + m + 1) 内存。
- CSR 矩阵是内存高效的,只要 .
- 与 CSR 类似,存在 CSC,它代表压缩稀疏列。它是 CSR 的列类似物。
- 'New' Yale 格式进一步将 A 和 JA 向量压缩为 1 个向量。
参考
https://en.wikipedia.org/wiki/Sparse_matrix