數據結構 對稱矩陣的壓縮存儲與稀疏矩陣的轉置

對稱矩陣的壓縮存儲與稀疏矩陣的轉置


一、對稱矩陣與對稱矩陣的壓縮存儲

對稱矩陣(Symmetric Matrix
       平時存儲一般矩陣我們都是用的二維數組,但我們可以看出對稱矩陣上三角與下三角的內容是一樣的。爲了節省空間我們採取壓縮存儲的方式,將對稱矩陣的上三角或者下三角的數據存儲在一個一維數組裏面。如果對稱矩陣爲n*n的矩陣,我們可以知道壓縮存儲的一維數組的大小爲n*(n+1)/2


現在我們用模板類來實現對稱矩陣的壓縮存儲(下面以存儲下三角爲例):


#include<iostream>
using namespace std;
using namespace std;

template<class T>
class SymmetricMatrix
{
public:
	SymmetricMatrix(T *a, size_t N)
		:_N(N)
	{
		_matrix = new T[N*(N + 1) / 2];
		size_t index = 0;

		for (size_t i = 0; i < N; i++)
		{
			for (size_t j = 0; j < N; j++)
			{
				if (i >= j)
				{
					_matrix[index++] = a[i*N+j];//依次將下三角的數據存入一位數組中
				}
			}
		}
	}

	void PrintCompressedMatrix()//打印一維數組
	{
		for (size_t i = 0; i < _N*(_N + 1) / 2; i++)
		{
			cout << _matrix[i] << " ";
		}
		cout << endl;
	}

	void PrintSymmetricMatrix()//根據存儲的一維數組打印原對稱矩陣
	{
		for (size_t i = 0; i < _N; i++)
		{
			for (size_t j = 0; j < _N; j++)
			{
				cout << _Access(i, j) << " ";
			}
			cout << endl;
		}
		cout << endl;
	}

	~SymmetricMatrix()
	{
		delete[] _matrix;
		_matrix = NULL;
	}

protected:
	T& _Access(size_t i, size_t j)
	{
		if (i < j)
		{
			swap(i, j);
		}
		return _matrix[i*(i + 1) / 2 + j];
	}
protected:
	T *_matrix;//對稱矩陣存儲的一維數組
	size_t _N;
};

void Test()
{
	int array[5][5] =
	{
		{ 0, 1, 2, 3, 4 },
		{ 1, 0, 1, 2, 3 },
		{ 2, 1, 0, 1, 2 },
		{ 3, 2, 1, 0, 1 },
		{ 4, 3, 2, 1, 0 },
	};

		SymmetricMatrix<int> SM((int*)array, 5);
		SM.PrintSymmetricMatrix();
		SM.PrintCompressedMatrix();
}


二、稀疏矩陣及稀疏矩陣的壓縮存儲(Sparse Matrix)


1、稀疏矩陣的壓縮存儲

稀疏矩陣中大多數據都爲0,而有效數據則很少。若是直接採用二維數組來存儲稀疏矩陣太浪費存儲空間,而且在運算中也會花費大量時間來計算無效數據0因此我們利用三元組(Triple)來記錄有效數據的座標及其值,然後將三元組存儲在一個一維數組中。



2、稀疏矩陣的普通轉置

根據稀疏矩陣壓縮存儲的一位數組進行轉置形成新的一維數組。將原稀疏矩陣按列遍歷,並按順序將有效數據放入轉置後新的一維數組中。如下圖中,先在_matrix中找到12,然後將其依次放入tmp._matrix中,以此類推。


3、稀疏矩陣的快速轉置

從普通轉置方法中我們可以發現稀疏矩陣中有多少有效數據,我們就需要遍歷多少次_matrix,這樣會比較浪費空間。那有沒有更快的方法呢?下面我們來介紹稀疏矩陣的快速轉置。

我們定義兩個新的一維數組rowcountrowpos,其中rowcount用來記錄新矩陣每一行(即原矩陣每一列)有效數據的個數,rowpos用來記錄轉置後新矩陣每一行第一個有效數據在新一維數組中的位置(下標),且每次將數據放入新數組之後,相應的rowpos1



代碼實現如下:
#include<iostream>
using namespace std;
#include<vector>

template<class T>
struct Triple//三元組結構,用來記錄有效數據的座標及其值
{
	size_t _row;
	size_t _col;
	T _value;

	Triple(size_t row, size_t col, const T& value)
		:_row(row)
		, _col(col)
		, _value(value)
	{}
};

template<class T>
class SparseMatrix
{
public:
	SparseMatrix(T *a, size_t M, size_t N, const T& invalid = T())//稀疏矩陣的壓縮存儲
		:_M(M)
		, _N(N)
		, _invalid(invalid)
	{
		for (size_t i = 0; i < M; i++)
		{
			for (size_t j = 0; j < N; j++)
			{
				if (a[i*N + j] != invalid)
				{
					Triple<T> t(i, j, a[i*N + j]);
					_matrix.push_back(t);
				}
			}
		}
	}

	void PrintCompressedMatrix()//打印一維數組
	{
		size_t index = 0;
		while (index<_matrix.size())
		{
			cout << _matrix[index++]._value << " ";
		}
		cout << endl;
	}

	void PrintSparseMatrix()//根據一維數組打印稀疏矩陣
	{
		size_t index = 0;
		for (size_t i = 0; i < _M; i++)
		{
			for (size_t j = 0; j < _N; j++)
			{
				if (index < _matrix.size()
					&& i == _matrix[index]._row
					&&j == _matrix[index]._col)
				{
					cout << _matrix[index++]._value << " ";
				}
				else
					cout << _invalid << " ";
			}
			cout << endl;
		}
		cout << endl;
	}

	SparseMatrix<T> TransposeMatrix(T *a)//稀疏矩陣的普通轉置
	{
		SparseMatrix<T> tmp(a, _M, _N, _invalid);//定義一個新數組存放轉置後矩陣的數據
		size_t count = 0;

		tmp._M = _N;
		tmp._N = _M;
		//將原一維數組中的數據放入新一維數組中相應的位置,並將行列互換
		for (size_t i = 0; i < _N; i++)
		{
			for (size_t index = 0; index < _matrix.size(); index++)
			{
				if (_matrix[index]._col == i)
				{
					tmp._matrix[count]._row = _matrix[index]._col;
					tmp._matrix[count]._col = _matrix[index]._row;
					tmp._matrix[count]._value = _matrix[index]._value;
					count++;
				}
			}
		}
		return tmp;
	}

	SparseMatrix<T> FastTransposeMatrix(T *a)//稀疏矩陣的快速轉置
	{
		SparseMatrix<T> tmp(a, _M, _N, _invalid);
		tmp._M = _N;
		tmp._N = _M;
		tmp._matrix.resize(_matrix.size());

		int *rowcount = new int[_N];//記錄轉置後的新矩陣每行有效數據的個數
		memset(rowcount, 0, sizeof(int)*_N);

		for (size_t i = 0; i < _matrix.size(); i++)
		{
			size_t col = _matrix[i]._col;
			++rowcount[col];
		}

		int *rowpos = new int[_N];//記錄轉置後新矩陣每一行第一個有效數據在三元組中的位置(下標)
		memset(rowpos, 0, sizeof(int)*_N);

		size_t i = 0;
		rowpos[i] = 0;
		for (i = 1; i < _N; i++)
		{
			rowpos[i] = rowcount[i - 1] + rowpos[i - 1];
		}

		for (size_t i = 0; i < _matrix.size(); i++)
		{
			size_t col = _matrix[i]._col;
			size_t index = rowpos[col];

			tmp._matrix[index]._col = _matrix[i]._row;
			tmp._matrix[index]._row = _matrix[i]._col;
			tmp._matrix[index]._value = _matrix[i]._value;
			++rowpos[col];
		}

		delete[] rowcount;
		delete[] rowpos;

		return tmp;
	}

	~SparseMatrix()
	{}

protected:
	vector<Triple<T>> _matrix;//使用vector不用手動開闢空間
	size_t _M;
	size_t _N;
	T _invalid;//非法值,這裏指0
};


void Test()
{
	int array[5][6] =
	{
		{ 1, 0, 3, 0, 0, 5 },
		{ 0, 0, 0, 0, 0, 0 },
		{ 2, 0, 0, 4, 0, 0 },
		{ 0, 0, 0, 0, 0, 0 },
		{ 0, 0, 6, 0, 0, 0 },
	};

	SparseMatrix<int> sp((int*)array, 5, 6, 0);
	sp.PrintSparseMatrix();

	SparseMatrix<int> sm = sp.TransposeMatrix((int*)array);
	sm.PrintSparseMatrix();
	sm.PrintCompressedMatrix();

	SparseMatrix<int> SM = sp.FastTransposeMatrix((int*)array);
	SM.PrintSparseMatrix();
	SM.PrintCompressedMatrix();
}





發佈了38 篇原創文章 · 獲贊 21 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章