您的位置:首页 > 其它

特殊矩阵的压缩存储

2016-06-01 19:01 288 查看
对称矩阵及对称矩阵的压缩存储

设一个N*N的方阵A,A中任意元素Aij,当且仅当Aij == Aji(0 <= i <= N-1 && 0 <= j <= N-1),则矩阵A是对称矩阵。以矩阵的对角线为分隔,分为上三角和下三角。
压缩存储称矩阵存储时只需要存储上三角/下三角的数据,所以最多存储n(n+1)/2个数据。

对称矩阵和压缩存储的对应关系:下三角存储i>=j,SymmetricMatrix[i][j] == Array[i*(i+1)/2+j]。
650) this.width=650;" src="/e/u261/themes/default/images/spacer.gif" style="background:url("/e/u261/lang/zh-cn/images/localimage.png") no-repeat center;border:1px solid #ddd;" alt="spacer.gif" /> 实现代码如下:

)
,_size(size*(size + 1) / 2)
,_n(size)
{
size_t index = 0;
for (size_t i = 0; i < size; i++)
{
for (size_t j = 0; j < size; j++)
{
if (i >= j)
{
_a[index++] = a[size*i + j];//按照一维数组的方式存入数据
}
else
{
break;
}
}
}
}
~SymmetricMatrix()
{
if (_a)
{
delete[]_a;
_a = NULL;
_size = 0;
}
}
T& Access(size_t i, size_t j)
{
if (i < j)
{
swap(i, j);//当是上三角时,交换i和j
}
return _a[i*(i + 1) / 2 + j];
}
void display()
{
for (size_t i = 0; i < _n; i++)
{
for (size_t j = 0; j < _n; j++)
{
if (i >= j)
{
cout << _a[i*(i + 1) / 2 + j] << ]2.稀疏矩阵

M*N的矩阵,矩阵中有效值的个数远小于无效值的个数,且这些数据的分布没有规律。
比如下面这个矩阵:
650) this.width=650;" src="http://s2.51cto.com/wyfs02/M01/7F/1D/wKioL1cUekXTHIOVAAAJWXulRyo033.png" title="QQ截图20160418140641.png" alt="wKioL1cUekXTHIOVAAAJWXulRyo033.png" />
650) this.width=650;" src="/e/u261/themes/default/images/spacer.gif" style="background:url("/e/u261/lang/zh-cn/images/localimage.png") no-repeat center;border:1px solid #ddd;" alt="spacer.gif" /> (1)稀疏矩阵的压缩存储
压缩存储只存储极少数的有效数据。使用{row,col,value}三元组存储每一个有效数据,三元组按原矩阵中的位置,以行优先级先后顺序依次存放。
那么上面的矩阵压缩存储结果就是:
650) this.width=650;" src="http://s5.51cto.com/wyfs02/M00/7F/20/wKiom1cUefrgD4A3AAAEUJora9M325.png" title="QQ截图20160418140843.png" alt="wKiom1cUefrgD4A3AAAEUJora9M325.png" />
三元组的定义:

template<typename T>
struct Triple//三元组
{
Triple<T>::Triple()//无参的构造函数
{

}

Triple(size_t row, size_t col, T value)//构造函数
:_row(row)
,_col(col)
,_value(value)
{

}

size_t _row;//行
size_t _col;//列
T _value;//值

};
压缩存储的实现代码:
 != invalid)//不是无效数据
{
Triple<T> cur(i, j, a[i*n + j]);
_a.push_back(cur);
}
}
}
}
protected:
vector <Triple<T>> _a;
size_t _rowsize;
size_t _colsize;
T _invalid;
};
(2)稀疏矩阵的转置

[i][j]和[j][i]位置上的数据对换。
650) this.width=650;" src="http://s2.51cto.com/wyfs02/M00/7F/1D/wKioL1cUfJXBya7rAAAW17qk6v4073.png" title="QQ截图20160418141640.png" alt="wKioL1cUfJXBya7rAAAW17qk6v4073.png" />

普通转置(列转置)
按照原矩阵的列优先把vector中的三元组放入新的容器中,并且交换行和列的值
[code] SparseMatrix<T> Transport()
{
assert(_a.size() < 0);
//创建新的矩阵,交换行列的值
SparseMatrix<T> ret;
ret._rowsize = _colsize;
ret._colsize = _rowsize;
ret._invalid = _invalid;
//两次循环
for (size_t i = 0; i < _colsize; i++)//按原矩阵的列扫描
{
size_t index = 0;
while (index < _a.size())
{
if (_a[index]._col == i)
//如果三元组中的列值=i时
//交换行列的值,放入新的矩阵
{
Triple<T> tmp(_a[index]._col, _a[index]._row, _a[index]._value);
ret._a.push_back(tmp);
}
index++;
}
if (_a.size() == ret._a.size())
{
break;//两个容器的大小相同时,break
}
}
return ret;
}
用此方法可以有效的转置矩阵,我们来看一下此函数的时间复杂度:O(col * _a.size())——矩阵的列*矩阵的元素总和。 如果元素很多就会浪费很多的时间。有没有办法让两层循环变成一层循环呢?付出空间上的代价,换取时间效率。 快速转置
我们只用一层循环来遍历容器_a中所有元素,并把该元素放到指定的位置。这样我们就需要一个数组rowStar来存放第i个元素所在位置。在定义这个数组之前,我们还需要一个数组rowCount来实现统计矩阵第i行元素的数量。这样我们才能更方便的知道第i个元素应该存放的位置。
650) this.width=650;" src="http://s2.51cto.com/wyfs02/M00/7F/1E/wKioL1cUgh7xfJ6XAAAl71YfXUA333.png" title="QQ截图20160418144014.png" alt="wKioL1cUgh7xfJ6XAAAl71YfXUA333.png" />实现代码如下:
;
int * rowStart = new int[_colsize];
//初始化rowCount和rowStart为0
memset(rowCount, 0, sizeof(int)* _colsize);
memset(rowStart, 0, sizeof(int) * _colsize);
//初始化
size_t index = 0;
while (index < _a.size())
{
rowCount[_a[index]._col]++;
++index;
}
rowStart[0] = 0;
for (size_t i = 1; i < _colsize; i++)
{
rowStart[i] = rowStart[i - 1] + rowCount[i - 1];
}

ret._a.resize(_a.size());//复制顺序表_a,容量相同
index = 0;
Triple<T> tmp;
while (index < _a.size())
{
size_t rowIndex = _a[index]._col;//行数
size_t row = rowStart[rowIndex];//当前行的起始位置

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

ret._a[row] = tmp;//将tmp放入ret计算好的位置
rowStart[row]++;
index++;
}
delete[] rowCount;
delete[] rowStart;
return ret;
}
此函数的时间复杂度为O(col + _a.size());和普通转置相比,效率提高了很多。
最后,附上完整代码(稀疏矩阵):
#pragma once

#include <iostream>
#include <vector>
#include <assert.h>
using namespace std;

template<typename T>
struct Triple//三元组
{
Triple<T>::Triple()//无参的构造函数
{

}

Triple(size_t row, size_t col, T value)
:_row(row)
,_col(col)
,_value(value)
{

}

size_t _row;//行
size_t _col;//列
T _value;//值

};

template<typename T>
class SparseMatrix
{
public:

SparseMatrix()//无参的构造函数
{

}
//用vector顺序表来存储三元组的信息
SparseMatrix(T * a, size_t m, size_t n, const T & invalid)
:_rowsize(m)
,_colsize(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> cur(i, j, a[i*n + j]);
_a.push_back(cur);
}
}
}
}

void Display()//打印矩阵
{
size_t index = 0;
for (size_t i = 0; i < _rowsize; i++)
{
for (size_t j = 0; j < _colsize; j++)
{
if ((index < _a.size()) && _a[index]._row == i&&_a[index]._col == j)
{
cout << _a[index]._value << " ";
index++;
}
else
{
cout << _invalid << " ";
}
}
cout << endl;
}
cout << endl;
}

//普通转置
SparseMatrix<T> Transport()
{
assert(_a.size() 》 0);
//创建新的矩阵,交换行列的值
SparseMatrix<T> ret;
ret._rowsize = _colsize;
ret._colsize = _rowsize;
ret._invalid = _invalid;
//两次循环
for (size_t i = 0; i < _colsize; i++)//按原矩阵的列扫描
{
size_t index = 0;
while (index < _a.size())
{
if (_a[index]._col == i)
//如果三元组中的列值=i时
//交换行列的值,放入新的矩阵
{
Triple<T> tmp(_a[index]._col, _a[index]._row, _a[index]._value);
ret._a.push_back(tmp);
}
index++;
}
if (_a.size() == ret._a.size())
{
break;//两个容器的大小相同时,break
}
}
return ret;
}

//快速转置
SparseMatrix<T> FastTransport()
{
assert(_a.size() > 0);
SparseMatrix<T> ret;

ret._rowsize = _colsize;//行列值互换
ret._colsize = _rowsize;
ret._invalid = _invalid;

int * rowCount = new int[_colsize];
int * rowStart = new int[_colsize];
//初始化rowCount和rowStart为0
memset(rowCount, 0, sizeof(int)* _colsize);
memset(rowStart, 0, sizeof(int) * _colsize);
//初始化
size_t index = 0;
while (index < _a.size())
{
rowCount[_a[index]._col]++;
++index;
}
rowStart[0] = 0;
for (size_t i = 1; i < _colsize; i++)
{
rowStart[i] = rowStart[i - 1] + rowCount[i - 1];
}

ret._a.resize(_a.size());//复制顺序表_a,容量相同
index = 0;
Triple<T> tmp;
while (index < _a.size())
{
size_t rowIndex = _a[index]._col;//行数
size_t row = rowStart[rowIndex];//当前行的起始位置

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

ret._a[row] = tmp;//将tmp放入ret计算好的位置
rowStart[row]++;
index++;
}
delete[] rowCount;
delete[] rowStart;
return ret;
}

protected:
vector <Triple<T>> _a;//容器
size_t _rowsize;//行
size_t _colsize;//列
T _invalid;//非法值
};

void Test()
{
int array[5][4] =
{
{ 1, 0, 3, 0, },
{ 0, 0, 0, 0, },
{ 0, 0, 0, 0, },
{ 1, 0, 3, 0, },
{ 0, 0, 0, 0, },
};
SparseMatrix<int> sm((int*)array, 5, 4, 0);
sm.Display();

SparseMatrix<int> sm1;
sm1 = sm.FastTransport();
cout << "转置后的矩阵为: " << endl << endl;
sm1.Display();
}[/code]650) this.width=650;" src="http://s4.51cto.com/wyfs02/M00/7F/1E/wKioL1cUhT3hX2QwAAALrbRRIoc772.png" title="QQ截图20160418145336.png" alt="wKioL1cUhT3hX2QwAAALrbRRIoc772.png" />
本文出自 “不断进步的空间” 博客,请务必保留此出处http://10824050.blog.51cto.com/10814050/1765046
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: