溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

稀疏矩陣的壓縮

發(fā)布時(shí)間:2020-08-06 11:06:02 來源:網(wǎng)絡(luò) 閱讀:1089 作者:羌笛夜 欄目:編程語言

稀疏矩陣的特點(diǎn)

M*N矩陣,矩陣中有效值的個(gè)數(shù)遠(yuǎn)遠(yuǎn)小于無效值的個(gè)數(shù),并且這些數(shù)據(jù)的分布沒有規(guī)律。

例如下面的矩陣

稀疏矩陣的壓縮

稀疏矩陣的壓縮存儲(chǔ)

壓縮矩陣值存儲(chǔ)極少數(shù)的有效數(shù)據(jù)。使用三元組來存儲(chǔ)每一個(gè)數(shù)據(jù),三元組數(shù)據(jù)按照矩陣中的位置,以行優(yōu)先順序依次存放。

則上述矩陣的存儲(chǔ)結(jié)構(gòu)為

稀疏矩陣的壓縮

三元組結(jié)構(gòu)

//三元組的定義
template<class T>
struct  Triple
{
public:
	//默認(rèn)無參構(gòu)造函數(shù)
	Triple()
	{}

	//構(gòu)造函數(shù)
	Triple(const T& d,size_t row=0,size_t col=0)
		:_value(d)
		,_row(row)
		,_col(col)
	{}
public:
	T _value;//數(shù)據(jù)域
	size_t _row;//行
	size_t _col;//列
};

稀疏矩陣的壓縮

template<class T>
class SparseMatrix
{
public:
	//無參構(gòu)造函數(shù)
	SparseMatrix()
	{}
	SparseMatrix(const T* a, size_t row, size_t col, const T& invalid);
	void Display();//打印
	SparseMatrix<T> Transport();//列轉(zhuǎn)置
	SparseMatrix<T> FastTransport();//快速轉(zhuǎn)置
	
private:
	vector<Triple<T>> _a;//三元組類型的順序表
	size_t _rowSize;//行數(shù)
	size_t _colSize;//列數(shù)
	T _invalid;//非法值
};

//矩陣的壓縮
template<class T>
SparseMatrix<T>::SparseMatrix(const T* a, size_t row, size_t col, const T& invalid)
	:_rowSize(row)
	, _colSize(col)
	, _invalid(invalid)
{
	//行遍歷
	for (size_t i = 0; i < row; i++)
	{
		//列遍歷
		for (size_t j = 0; j < col; j++)
		{
			if (a[i*col + j] != invalid)
			{
				_a.push_back(Triple<T>(a[i*col + j], i, j));
				//不能通過數(shù)組創(chuàng)建,但是可以通過數(shù)組形式訪問
			}
		}
	}
}


轉(zhuǎn)置

將原矩陣的行、列互換,也就是將[row][col]和[col][row]位置上的數(shù)據(jù)對(duì)換。

稀疏矩陣的壓縮

列轉(zhuǎn)置

算法思想:

采用按照被轉(zhuǎn)置矩陣三元組表A的序列(即轉(zhuǎn)置后三元組表B的行序)遞增的順序進(jìn)行轉(zhuǎn)置,并以此送入轉(zhuǎn)置后矩陣的算遠(yuǎn)足表B中,這樣一來,轉(zhuǎn)置后矩陣的三元組表B恰好是以“行序?yàn)橹餍虻摹?

實(shí)現(xiàn)代碼

//列轉(zhuǎn)置
template<class T>
SparseMatrix<T> SparseMatrix<T>::Transport()
{
	SparseMatrix<T> result;
	//行列size互換
	result._rowSize = _colSize;
	result._colSize = _rowSize;
	result._invalid = _invalid;

	//按照列掃描
	for (size_t j = 0; j < _colSize; j++)
	{
		//在三元組數(shù)組中找到相同列的元素
		for (size_t index = 0; index < _a.size(); index++)
		{
			if (_a[index]._col == j)
			{
				result._a.push_back(Triple<T>(_a[index]._value, _a[index]._col, _a[index]._row));
				//按照列優(yōu)先的順序存到壓縮數(shù)組中
			}
		}
	}
	return result;
}

算法分析:

算法的時(shí)間主要消耗在雙重循環(huán)中,其時(shí)間復(fù)雜度為O(_colSize*_a.size)。


一次定位快速轉(zhuǎn)置

算法思想:

在列轉(zhuǎn)置中算法的時(shí)間浪費(fèi)主要在雙重循環(huán)中,要改善算法的性能,必須去掉雙重循環(huán),使得整個(gè)轉(zhuǎn)置過程通過一次循環(huán)來完成。

為了能使得被轉(zhuǎn)置的三元組表A中元素一次定位到三元組表B中,需要預(yù)先計(jì)算一下數(shù)據(jù):

1)rowCounts,三元組表A中每一列有效值的個(gè)數(shù),即轉(zhuǎn)置后矩陣三元組表B中每一行有效值的個(gè)數(shù)。

2)rowStart,三元組表B中每一行有效值的起始位置。


rowStart[col]=rowStart[col-1]+rowCounts[col-1]

上述矩陣的兩個(gè)數(shù)組為:

稀疏矩陣的壓縮

代碼實(shí)現(xiàn):

//快速轉(zhuǎn)置
template<class T>
SparseMatrix<T> SparseMatrix<T>::FastTransport()
{
	assert(_a.size() < 0);
	SparseMatrix<T> result;
	//行列size互換
	result._rowSize = _colSize;
	result._colSize = _rowSize;
	result._invalid = _invalid;

	//建立rowCounts和rowStart
	int* rowCounts = new int[_colSize];
	int* rowStart = new int[_colSize];
	memset(rowCounts, 0, sizeof(int)*_colSize);//初始化為0
	memset(rowStart, 0, sizeof(int)*_colSize);//初始化為0

	result._a.resize(_a.size());//復(fù)制順序表_a,容量相同,但是數(shù)據(jù)不同。
	//初始化
	for (size_t i = 0; i < _colSize; i++)
	{
		rowCounts[_a[i]._col]++;
	}
	rowStart[0] = 0;
	for (size_t i = 1; i < _colSize; i++)
	{
		rowStart[i] = rowCounts[i - 1] + rowStart[i - 1];
	}

	//快速轉(zhuǎn)置
	size_t index = 0;
	Triple<T> tmp;
	while (index < _a.size())
	{
		int row = _a[index]._col;//行數(shù)
		int rowIndex = rowStart[row];//當(dāng)前行的起始位置

									 //交換行和列
		tmp._value = _a[index]._value;
		tmp._row = _a[index]._col;
		tmp._col = _a[index]._row;

		result._a[rowIndex] = tmp;
		rowStart[row]++;
		index++;
	}
	delete[] rowCounts;
	delete[] rowStart;
	return result;

}

算法分析:

一次定位快速轉(zhuǎn)置算法時(shí)間主要浪費(fèi)在3個(gè)并列的循環(huán)中,分別執(zhí)行了_colSize,_col_Size,_a.size()次,總的時(shí)間復(fù)雜度為O(_colSize+_a.size())。遠(yuǎn)遠(yuǎn)小于O(_colSize*_a.size)。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI