矩陣我個人理解就是一堆數據放在一塊兒排列整齊,當然正規一點說就是m行n列的數據構成。在編程中一般采用數組對其進行存儲,但矩陣中的某些特殊矩陣里,有時會出現很多數據相等或者存有很多0只有某幾個位置為別的數據,那么這類矩陣我們在用數組存儲的時候就會感覺比較的浪費空間,那么會對一些特殊矩陣進行壓縮存儲。
常見的能夠壓縮存儲的矩陣有對稱矩陣和稀疏矩陣,今天主要說說對稱矩陣的壓縮存儲。先來說說什么是對稱矩陣,相信大家都很熟悉,對於一個矩陣如果它的行和列相等並且矩陣中的數據是關於對角線對稱的,那么我們稱這樣的矩陣為對稱矩陣,拿公式來說就是:A[i][j] = A[j][i](0<=i<=N-1&&0<=j<=N-1)。
那么對於這樣的對稱矩陣我就只需要存儲它的一個上三角或者下三角就足夠,沒必要對另一部分重復的數據存儲。
一維數組開辟多大:
觀察上面的對稱矩陣,如果我要存儲下三角,那么在類中給一位數組開辟的大小是多少呢?可以看到下三角第一行為一個元素,往下依次遞增,直到最后一行N個元素,可以發現就是等差數列求和的問題,那么來計算:(1+5)*5/2=15,因此用來存儲矩陣的一位數組開辟上15個空間的大小,這樣相對於之前能夠節省接近一半的存儲空間。
對稱矩陣和壓縮存儲的對應關系:
因為是存儲下三角,所以是把矩陣中元素A[i][j](i>=j)存放到數組Array中。那么在這里看一下兩者的對應關系。
上圖給出了矩陣中部分元素在一位數組中的存儲位置也就是索引,那么怎么確定其在數組中的索引呢,其實這僅僅是一個數學問題也比較簡單,我們來看看在Array[13]位置存儲的那個元素2,它在矩陣中的位置為A[4][3],那么我們放眼到上圖中的那個下三角,這個2的上面正好有4行,那么上面的元素的個數又是一個等差求和(1+4)*4/2=10,在加上它的列數3結果就是13.所以可以列出公式為:SymmetricMatrix[i][j] == Array[i*(i+1)/2+j],SymmetricMatrix代表我們的對稱矩陣。
看代碼說話:
構造這樣的一個對稱矩陣類時,需要兩個成員變量,一個是用來存放矩陣的一位數組_arr,一個是一位數組的大小_size.下面是構造函數:
SymmetricMatrix(T *arr, int N) :_size(N*(N + 1) / 2) { assert(arr); arr = new T[_size]; int idex = 0; for (int i = 0; i < N; ++i) { for (int j = 0; j < N; ++j) { if (i >= j && idex<_size) { _arr[idex++] = arr[i*N + j]; } } } }
其實整體代碼還是比較簡單的,在類中還要重載它的輸出操作符,思路就是根據矩陣的i和j計算出一位數組中的索引然后輸出就可以了,當然下三角的是i>=j的,所以如果循環中如果i<j的時候需要進行一次交換。
以下為整體代碼:
template<typename T> class SymmetricMatrix { public: SymmetricMatrix(T *arr, int N) :_size(N*(N + 1) / 2) { assert(arr); arr = new T[_size]; int idex = 0; for (int i = 0; i < N; ++i) { for (int j = 0; j < N; ++j) { if (i >= j && idex<_size) { _arr[idex++] = arr[i*N + j]; } } } } T Access(size_t _row,size_t _col)const { if (_row < _col) { swap(_row, _col); } return _arr[_row*(_row + 1) + _col]; } template<typename T> friend ostream& operator<<(ostream& _cout, const SymmetricMatrix<T> sm) { size_t N = sqrt((long double)sm._size * 2); for (size_t i = 0; i < N; ++i) { for (size_t j = 0; j < N; ++j) { _cout << sm.Access(i, j) << " "; } _cout << endl; } return _cout; } private: T *_arr; int _size; };
文章作者:Mr_listening,博客地址:http://www.cnblogs.com/MrListening/