矩陣(Matrix)是一個按照長方陣列排列的複數或實數集合.
稀疏矩陣:有效數據遠少於無效數據。
eg:規定無效數據爲 0
1 0 0 0 0
0 0 0 0 2
0 3 0 0 0
4 0 0 0 0
上述矩陣則可稱爲一個稀疏矩陣
我們在學習C語言的時候已經見過並使用過矩陣,其實它在我們的編程語言裏可以翻譯成二維數組,由於稀疏矩陣的有效數據十分的少,完全存儲十分耗費我們的空間,所以我們選擇只存儲它的有效數據位,所以我們可以直接使用一維數組將其存儲起來,但是我們必須讓別人在看它時還能知道它是一個矩陣,於是我們必須將其所在的位置使用一個三元組存儲起來!
三元組的定義如下:
template<class T> struct Triple { T _value;//有效值 int _row;//該值所在行 int _col;//該值所在列 Triple(const T& data = T(), int m = 0, int n = 0) :_value(data),_row(m), _col(n) {} };
矩陣的定義如下:
class SpaMatrix { public: SpaMatrix(T* arr = NULL, int m = 0, int n = 0, int inva = 0) :_Row(m), _Col(n), _invalid(inva) { int index = 0; for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { if (arr[i*n + j] != _invalid) { _a.push_back(Triple<T>(arr[i*n + j], i, j)); _n ++; } } } } private: vector< Triple<T> > _a;//存儲三元組 int _invalid;//規定的無效值 int _Row;//矩陣的行數 int _Col;//矩陣的列數 };
在矩陣裏,我們經常能夠看見一個運算,就是矩陣的轉置,即使得a[i][j] = a[j][i],我們之前在存儲矩陣時選擇了行優先的存儲方式,但是,轉置之後,我們的矩陣是以原來的行爲它的列,我們該如何做呢?
方法一:普通轉置
**我們遍歷矩陣,將第一列數據先放入新的矩陣,再放第二列,第三列,以此類推,這樣,我們就能夠得到新的矩陣
下面是代碼的實例(截取重要部分代碼):
//普通轉置 SpaMatrix<T>::SpaMatrix<T> OrdinaryTrans() { int count = 0; int index = 0; SpaMatrix<T> sp;//使用一個臨時變量存儲轉置後的矩陣 for (int j = 0; j < _Col; j++) { for (int index = 0; index < _a.size(); index++) { if (_a[index]._col == j) { //每次只push需要的列 sp._a.push_back(_a[index]); sp._a[index]._row = _a[index]._col; sp._a[index]._col = _a[index]._row; } } } //更新轉置後的矩陣行列信息 sp._Row = _Col; sp._Col = _Row; return sp; }
方法二:快速轉置
**我們將原來的矩陣的每一列有效數據的起始位和每一列有效數據的個數保存起來,作爲新矩陣的每一行有效數據的起始位置和有效數據個數,當我們想要的得到某個數據時,使用 上一行的起始位置+有效數據的個數即可得到我們新的矩陣。
我們來看看代碼的實例:
//快速轉置 SpaMatrix<T>::SpaMatrix<T> FastTrans() { //統計有效數據的開始位置 int *RowStart = new int[_Col]; //統計轉置之後的矩陣裏每行的有效數據的個數 int *RowCount = new int[_Col]; memset(RowCount, 0, sizeof(int)*_Col); memset(RowStart, 0, sizeof(int)*_Col); size_t index = 0; //Set RowCount while (index < _a.size()) { RowCount[_a[index]._col]++; index++; } //Set RowStart RowStart[0] = 0; for (int i = 1; i < _Col; i++) { RowStart[i] = RowStart[i - 1] + RowCount[i - 1]; } //構造轉置之後的矩陣 SpaMatrix<T> sptrans; sptrans._Row = _Col; sptrans._Col = _Row; sptrans._n = _n; //index 值已經改變了,必須重新讓其等於0 index = 0; //此處使用下標訪問必須開闢空間,但如果使用push_back()可以不用開闢~ sptrans._a.resize(_a.size()); while(index < _a.size()) { int Rowindex = _a[index]._col; //此處注意引用 int& RowSt = RowStart[Rowindex]; sptrans._a[RowSt]._value = _a[index]._value; sptrans._a[RowSt]._col = _a[index]._row; sptrans._a[RowSt]._row = _a[index]._col; index++; //每次必須更新該位置,否則錯誤 RowSt++; } return sptrans; }