对称矩阵、稀疏矩阵的压缩存储
1)对称矩阵的压缩存储
对称矩阵顾名思义就是符合行和列的个数相同,并且矩阵中存储的数据上三角和下三角中对应位置上的元素值是相等的。为了能够减少存储的空间,我们可以只存储上三角矩阵、或者下三角矩阵中的元素,这样就能够极大地节省空间的浪费。下面是对称矩阵的示列:
假设对称矩阵为n*n,这里以行优先存储下三角矩阵,总共需要存储的元素有n*(n+1)/2个元素,从而将n*n个元素压缩到n*(n+1)/2大小的空间中。
下面是具体的程序实现:
——symmetric.h文件
//实现对称矩阵
#include <assert.h>
template <class T>
//稀疏矩阵的存储需要n*(n + 1) / 2 个空间,将对称矩阵的下三角矩阵存储在一个一维数组中
class Matrix
{
public:
Matrix(T* arr, size_t size) //构造函数
:_array(new T[size * (size + 1) / 2])
, _size(size * (size + 1) / 2)
{
assert(arr);
size_t num = 0;
for (size_t i = 0; i < size; i++)
{
for (size_t j = 0; j < size; j++)
{
if (i >= j)
{
_array[num++] = arr[i * size + j];
}
else
{
break; //减少循环遍历上三角矩阵中的元素
}
}
}
}
T& Access(size_t i, size_t j) //打印矩阵中某一元素
{
if (i < j)
{
swap(i, j);
}
return _array[i * (i + 1) / 2 + j];
}
void Display() //打印
{
for (size_t i = 0; i < _size; i++)
{
cout << _array[i] << " ";
}
cout << endl;
}
protected:
T* _array;
size_t _size;
};
void Test1()
{
int arr[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 }
};
Matrix<int> s1((int*)arr, 5);
int ret = s1.Access(2, 1);
s1.Display();
cout << ret << endl;
}
2)稀疏矩阵的压缩存储
稀疏矩阵是指矩阵中大多数元素为无效数据的矩阵,即就是矩阵中的有效元素远远少于无效元素。对于稀疏矩阵我们应该怎样对其进行存储?稀疏矩阵没有对称矩阵那样上三角矩阵与其下三角矩阵的元素是对应相等的特点,不能像对称矩阵一样只存储上三角或者下三角矩阵中的元素,但是稀疏矩阵最大的特点就是矩阵中所需要的数据远远少于无效的数据,所以我们可以采取只存储有效的数据,将有效数据的行、列和值同时进行存储。下面为存储的图示:
下面为三元组表的类型如下:
struct Point
{
int _row; //行
int _col; //列
T _value; //值
};
稀疏矩阵的存储问题解决了,那么矩阵的转置又应该怎么解决?
方法一:列序递增转置法
采用按照被转置矩阵三元组表_array的列序(即转置后三元组表的行序)递增的顺序进行转置,并依次送入转置后矩阵的三元组表中。具体的做法就是:将从开始以行进行遍历三元组表_array,找出其中所有列为1的元组,转置后进行存储。接着找出所有列为2的元组,转置后进行存储。依次类推...
方法二:一次定位快速算法
这个算法需要创建两个数组分别保存三元组表中第i列中非零元素的个数,存放转置前三元组表中第i列中第一个非零元素在三元组表B中的存储位置。下面为算法具体的图解:
下面是具体的程序实现:
——sparse.h文件
//实现稀疏矩阵的存储(存储点的位置信息(行、列、值))
#include <assert.h>
#include <vector> //容器
template <class T>
struct Point
{
int _row;
int _col;
T _value;
Point(int row = 0, int col = 0, const T& value = T()) //构造节点
:_row(row)
, _col(col)
, _value(value)
{ }
};
template <class T>
class Matrix
{
public:
Matrix()
:_array(NULL)
, _cols(0)
, _rows(0)
, _invalues(0)
{ }
Matrix(T* arr, int row, int col, const T& invalue) //构造函数,invalue为无效值
{
for (size_t i = 0; i < row; i++)
{
for (size_t j = 0; j < col; j++)
{
if (arr[i * col + j] != invalue)
{
_array.push_back(Point<T>(i, j, arr[i * col + j])); //将有效值压入容器中
}
}
}
_rows = row;
_cols = col;
_invalues = invalue;
}
void Display() //打印稀疏矩阵
{
size_t index = 0; //index记录——array中元素
for (int i = 0; i < _rows; i++)
{
for (int j = 0; j < _cols; j++)
{
//从坐标(0,0)位置开始以行遍历,若坐标的i,j与存储的有效数据的坐标相同,进行打印,
//若不同,此位置上输出非有效值。
if (index < _array.size()
&& _array[index]._row == i
&& _array[index]._col == j)
{
cout << _array[index]._value << " ";
index++;
}
else
{
cout << _invalues << " ";
}
}
cout << endl;
}
}
Matrix<T> Transport() //将稀疏矩阵进行转置
{
Matrix<T> tmp; //新建一个对象将行和列进行交换
tmp._invalues = _invalues;
tmp._cols = _rows;
tmp._rows = _cols;
/*
上面将矩阵中的元素进行行列互换,但是存在矩阵存储时有效元素的顺序不一致的问题,
通过对原来的矩阵进行以列进行遍历,当遇到与数组中存储的有效数据的列相同的,将其行列互换,进行存储。
*/
for (size_t i = 0; i < _cols; i++)
{
size_t index = 0;
while (index < _array.size())
{
if (_array[index]._col == i)
{
Point<T> ptr; //将有效数据的行和列进行交换存储
ptr._row = _array[index]._col;
ptr._col = _array[index]._row;
ptr._value = _array[index]._value;
tmp._array.push_back(ptr);
}
index++;
}
}
return tmp;
}
/*快速转置的思想是将原来矩阵中每行的有效数据和每行开始的位置相加,
能够直接确定有效数据在一维数组中的存储位置,然后直接进行行列交换*/
Matrix<T> FastTransport() //快速转置
{
Matrix<T> tmp; //新建一个对象将行列进行交换
tmp._invalues = _invalues;
tmp._cols = _rows;
tmp._rows = _cols;
tmp._array.resize(_array.size()); //resize进行申请空间
//_rowcount记录每列的有效数据个数,即就是原来矩阵每行的有效数据个数
int* _rowcount = new int[_cols];
int* _rowstart = new int[_cols]; //_rowstart记录每行开始的位置
memset(_rowcount, 0, sizeof(int)*_cols);
memset(_rowstart, 0, sizeof(int)*_cols);
size_t index = 0;
while (index < _array.size())
{
_rowcount[_array[index]._col]++;
index++;
}
_rowstart[0] = 0; //记录开始位置
for (size_t i = 1; i < _cols; i++)
{
_rowstart[i] = _rowstart[i - 1] + _rowcount[i - 1];
}
index = 0;
while (index < _array.size())
{
int& rowstarts = _rowstart[_array[index]._col];
Point<T> ptr;
ptr._col = _array[index]._row;
ptr._row = _array[index]._col;
ptr._value = _array[index]._value;
tmp._array[rowstarts++] = ptr;
index++;
}
delete[] _rowcount;
delete[] _rowstart;
return tmp;
}
protected:
vector<Point<T>> _array;
size_t _rows;
size_t _cols;
T _invalues;
};
void Test1()
{
int arr[4][5] = {
{ 0, 1, 2, 0, 0 },
{ 1, 0, 1, 2, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
};
Matrix<int> s1((int*)arr, 4, 5, 0);
s1.Display();
cout << endl << endl;
Matrix<int> tmp = s1.Transport();
tmp.Display();
cout << endl << endl;
Matrix<int> ptr = s1.FastTransport();
ptr.Display();
}
转载于:https://blog.51cto.com/10740590/1764243