稀疏矩陣是矩陣中非零元素的個數遠遠小於矩陣元素的總數,並且非零元素的分佈沒有規律,通常認爲非零元素比上矩陣所有元素的值小於等於0.05時,則稱該矩陣爲稀疏矩陣(sparse matrix);與之相區別的是,如果非零元素的分佈存在規律(如上三角矩陣、下三角矩陣、對角矩陣),則稱該矩陣爲特殊矩陣。
一個稀疏矩陣中有許多元素等於零,這便於矩陣的計算和保存.如果Matlab把一個矩陣當作稀疏矩陣,那麼只需在m×3的矩陣中存儲m個非零項.第1列是行下標,第2列是列下標,第3列是非零元素值,不必保存零元素.如果存儲一個浮點數要8個字節,存儲每個下標要4個字節,那麼整個矩陣在內存中存儲需要1 6×m個字節.
A = e y e ( 1 0 0 0 ) ;
得到一個1 0 0 0×1 0 0 0的單位矩陣,存儲它需要8 MB空間.如果使用命令:
B = s p e y e ( 1 0 0 0 ) ;
用一個1 0 0 0×3的矩陣來代表,每行包含有一個行下標,列下標和元素本身.只需1 6 K B的空間就可以存儲1 0 0 0×1 0 0 0的單位矩陣,它只需要滿單位矩陣的0 . 2 %存儲空間.對於許多的廣義矩陣也可這樣來作.
對於存稀疏矩陣我們首先定義一個三元組,壓縮存儲值存儲極少數的有效數據。使用{row,col,value}三元組存儲每一個有效數據,三元組按原矩陣中的位置,以行優先級先後順序依次存放。
struct Triple { int _row; //行 int _col; //列 T _value; //值 Triple(int row, int col, T& value) :_row(row) ,_col(col) ,_value(value) {} Triple() :_row(0) , _col(0) , _value(0) {} };
普通轉置:
SparseMatrix(T* a, int m, int n, const T& invalid)//非法值 :_rowsize(m) ,_colsize(n) ,_invaild(invalid) { for (int i=0; i < m; ++i) { for (int j = 0; j < n; j++) { if (a[i*n + j] != invalid) { Triple<T> tmp(i, j, a[i*n + j]); _a.push_back(tmp); } } } } SparseMatrix() {} SparseMatrix(size_t rowsize, size_t colsize, T invaild) :_rowsize(rowsize), _colsize(colsize), _invaild(invaild) {} // 轉置 SparseMatrix<T> Transport() { //務必保持行優先 SparseMatrix<T> sm(_colsize, _rowsize, _invaild); for (size_t i = 0; i < _colsize; i++) { size_t index = 0; while (index < _a.size()) { if (_a[index]._col == i) { Triple<T> mm; mm._col = _a[index]._row; mm._row = _a[index]._col; mm._value = _a[index]._value; sm._a.push_back(mm); } ++index; } } return sm; }
SparseMatrix<T> FastTransport() //快速轉置 { SparseMatrix<T> temp; temp._a.resize(_a.size()); int* rowcounts = new int[_col]; int* rowstarts = new int[_col]; memset(rowcounts, 0, sizeof((int)*_col)); memset(rowstarts, 0, sizeof((int)*_col)); size_t index = 0; while (index < _a.size()) { rowcounts[_a[index]._col]++; ++index; } rowstarts[0] = 0; for (size_t i = 0; i < _col; ++i) { rowstarts[i] = rowstarts[i - 1] + rowcounts[i - 1]; } while (index < _a.size()) { size_t& begin = rowstarts[_a[index]._col]; Triple<T> tp; tp._row = _a[index]._col; tp._col = _a[index]._row; tp._value = _a[index]._value; tmp._a[rowstarts++] = tp; ++index; } delete[] _a; return tmp; }
打印矩陣部分實現:
void display(T* a, int m, int n, const T& invalid) { int p = 0; for (int i = 0; i < m; ++i) { for (int j = 0; j < n; j++) { if (p < _a.size() && _a[p]._row == i&&_a[p]._col == j) { cout << _a[p]._value << " "; p++; } else { cout << invalid << " "; } } cout << endl; } }
完整實現代碼:
#pragma once #include<vector> #include<iostream> using namespace std; template<class T> struct Triple { int _row; int _col; T _value; Triple(int row, int col, T& value) :_row(row) ,_col(col) ,_value(value) {} Triple() :_row(0) , _col(0) , _value(0) {} }; template<class T> class SparseMatrix { public: SparseMatrix(T* a, int m, int n, const T& invalid)//非法值 :_rowsize(m) ,_colsize(n) ,_invaild(invalid) { for (int i=0; i < m; ++i) { for (int j = 0; j < n; j++) { if (a[i*n + j] != invalid) { Triple<T> tmp(i, j, a[i*n + j]); _a.push_back(tmp); } } } } SparseMatrix() {} SparseMatrix(size_t rowsize, size_t colsize, T invaild) :_rowsize(rowsize), _colsize(colsize), _invaild(invaild) {} void display(T* a, int m, int n, const T& invalid) { int p = 0; for (int i = 0; i < m; ++i) { for (int j = 0; j < n; j++) { if (p < _a.size() && _a[p]._row == i&&_a[p]._col == j) { cout << _a[p]._value << " "; p++; } else { cout << invalid << " "; } } cout << endl; } } SparseMatrix<T> Transport() { //務必保持行優先 SparseMatrix<T> sm(_colsize, _rowsize, _invaild); for (size_t i = 0; i < _colsize; i++) { size_t index = 0; while (index < _a.size()) { if (_a[index]._col == i) { Triple<T> mm; mm._col = _a[index]._row; mm._row = _a[index]._col; mm._value = _a[index]._value; sm._a.push_back(mm); } ++index; } } return sm; } SparseMatrix<T> FastTransport() //快速轉置 { SparseMatrix<T> temp; temp._a.resize(_a.size()); int* rowcounts = new int[_col]; int* rowstarts = new int[_col]; memset(rowcounts, 0, sizeof((int)*_col)); memset(rowstarts, 0, sizeof((int)*_col)); size_t index = 0; while (index < _a.size()) { rowcounts[_a[index]._col]++; ++index; } rowstarts[0] = 0; for (size_t i = 0; i < _col; ++i) { rowstarts[i] = rowstarts[i - 1] + rowcounts[i - 1]; } while (index < _a.size()) { size_t& begin = rowstarts[_a[index]._col]; Triple<T> tp; tp._row = _a[index]._col; tp._col = _a[index]._row; tp._value = _a[index]._value; tmp._a[rowstarts++] = tp; ++index; } delete[] _a; return tmp; } protected: size_t _rowsize; size_t _colsize; T _invaild; vector<Triple<T>> _a; }; void test() { int a[6][5] = { { 1, 0, 3, 0, 5 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 2, 0, 4, 0, 6 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 } }; SparseMatrix<int> d((int*)a,6,5,0); SparseMatrix<int> tmp=d.Transport(); cout << "轉置之前:" << endl; d.display((int*)a,6,5,0); cout << endl; cout << "轉置之後:" << endl; tmp.display((int*)a, 5, 6, 0); }
結果截圖