为了节省空间,对于稀疏矩阵我们通常要压缩存储。具体方法是用一个三元数组按照行优先的方式保存每一个有效值的行、列、值。
三原数组的类型:
template<typename T>
struct ThirdArray
{
size_t _x; //行
size_t _y; //列
T _value;
ThirdArray(const size_t& row=0, const size_t& col=0, const T& value=T())
:_x(row)
, _y(col)
, _value(value)
{}
};
稀疏矩阵的压缩存储:
template<typename T>
class SpareMatric
{
typedef ThirdArray<T> ThirdArray;
public:
SpareMatric(T* array,const size_t& row,const size_t& col,const T& invalid)
:_row(row)
, _col(col)
, _invalid(invalid)
{
for (size_t i = 0; i < row; i++)
{
for (size_t j = 0; j < col; j++)
{
if (array[i*col + j] != invalid)
{
_array.push_back(ThirdArray(i, j, array[i*col + j]));
}
}
}
}
void Display()
{
size_t index = 0;
for (size_t i = 0; i < _row; i++)
{
for (size_t j = 0; j < _col; j++)
{
if (index < _array.size() && _array[index]._x==i&&_array[index]._y==j)
{
cout << _array[index]._value << " ";
index++;
}
else
{
cout << _invalid<< " ";
}
}
cout << endl;
}
}
vector<ThirdArray> _array;
size_t _row;
size_t _col;
T _invalid;
};
稀疏矩阵的转置:
假设现在有一个三元数组,里面保存了一个稀疏矩阵。我们要对这个稀疏矩阵进行转置的话需要进行三步操作(假设转置之前的三元数组是a,转置之后的三元数组是b)。
1、交换稀疏矩阵的行和列。
2、交换三元数组中每个元素的行和列。
3、将三元数组中的元素重新进行排序。(因为转置后的稀疏矩阵要按照行优先存储,b就相当于没转置之前的稀疏矩阵按照列优先存储)
如上图:对第1,2步操作非常简单。主要是第三部排序,现在我们有两种方式对a进行排序:
第一种:
1、先按照行从小到大进行排序
第二种:
1、先用一个数组num统计出来未转置之前的稀疏矩阵的每一列的有效值的个数
2、再用一个数组cpot统计出来为转置之前的稀疏矩阵的每一列的第一个有效值在相应b中的位置
接下来只要再遍历一遍a,遇到每列的第一个有效值的时候则直接将其放到b中相对应的位置,然后再将cpot中的值加加(cpot里面就保存了同一列的下一个元素在b中的位置)。
完整代码:
#pragma once
#include<iostream>
#include<vector>
using namespace std;
template<typename T>
struct ThirdArray
{
size_t _x;
size_t _y;
T _value;
ThirdArray(const size_t& row=0, const size_t& col=0, const T& value=T())
:_x(row)
, _y(col)
, _value(value)
{}
};
template<typename T>
class SpareMatric
{
typedef ThirdArray<T> ThirdArray;
public:
SpareMatric(T* array,const size_t& row,const size_t& col,const T& invalid)
:_row(row)
, _col(col)
, _invalid(invalid)
{
for (size_t i = 0; i < row; i++)
{
for (size_t j = 0; j < col; j++)
{
if (array[i*col + j] != invalid)
{
_array.push_back(ThirdArray(i, j, array[i*col + j]));
}
}
}
}
void Display()
{
size_t index = 0;
for (size_t i = 0; i < _row; i++)
{
for (size_t j = 0; j < _col; j++)
{
if (index < _array.size() && _array[index]._x==i&&_array[index]._y==j)
{
cout << _array[index]._value << " ";
index++;
}
else
{
cout << _invalid<< " ";
}
}
cout << endl;
}
}
vector<ThirdArray> _array;
size_t _row;
size_t _col;
T _invalid;
};
template<typename T>
class TransposeMatric
{
typedef ThirdArray<T> ThirdArray;
public:
TransposeMatric(SpareMatric<T>& Matric)
:_row(Matric._col)
, _col(Matric._row)
, _invalid(Matric._invalid)
{
_Trans.resize(Matric._array.size());
vector<size_t> num;
vector<size_t> cpot;
num.resize(Matric._col);
cpot.resize(Matric._col);
for (size_t i = 0; i < Matric._array.size(); i++)
{
num[Matric._array[i]._y]++;
}
cpot[0] =0;
for (size_t i = 1; i < Matric._col; i++)
{
cpot[i] = cpot[i - 1] + num[i-1];
}
for (size_t i = 0; i<_Trans.size(); i++)
{
size_t col = Matric._array[i]._y;
size_t pos = cpot[col];
_Trans[pos]._x= Matric._array[i]._y;
_Trans[pos]._y= Matric._array[i]._x;
_Trans[pos]._value= Matric._array[i]._value;
++cpot[col];
}
}
void Display()
{
size_t index = 0;
for (size_t i = 0; i < _row; i++)
{
for (size_t j = 0; j < _col; j++)
{
if (index < _Trans.size() && _Trans[index]._x == i&&_Trans[index]._y == j)
{
cout << _Trans[index]._value << " ";
index++;
}
else
{
cout << _invalid << " ";
}
}
cout << endl;
}
}
protected:
vector<ThirdArray> _Trans;
size_t _row;
size_t _col;
T _invalid;
};