矩阵(Matrix)是一个按照长方阵列排列的复数或实数集合.
稀疏矩阵:有效数据远少于无效数据。
eg:规定无效数据为 0
1 0 0 0 0
0 0 0 0 2
0 3 0 0 0
4 0 0 0 0
上述矩阵则可称为一个稀疏矩阵
我们在学习C语言的时候已经见过并使用过矩阵,其实它在我们的编程语言里可以翻译成二维数组,由于稀疏矩阵的有效数据十分的少,完全存储十分耗费我们的空间,所以我们选择只存储它的有效数据位,所以我们可以直接使用一维数组将其存储起来,但是我们必须让别人在看它时还能知道它是一个矩阵,于是我们必须将其所在的位置使用一个三元组存储起来!
三元组的定义如下:
template<class T>
struct Triple
{
T _value;//有效值
int _row;//该值所在行
int _col;//该值所在列
Triple(const T& data = T(), int m = 0, int n = 0)
:_value(data),_row(m), _col(n)
{}
};
矩阵的定义如下:
class SpaMatrix
{
public:
SpaMatrix(T* arr = NULL, int m = 0, int n = 0, int inva = 0)
:_Row(m), _Col(n), _invalid(inva)
{
int index = 0;
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
if (arr[i*n + j] != _invalid)
{
_a.push_back(Triple<T>(arr[i*n + j], i, j));
_n ++;
}
}
}
}
private:
vector< Triple<T> > _a;//存储三元组
int _invalid;//规定的无效值
int _Row;//矩阵的行数
int _Col;//矩阵的列数
};
在矩阵里,我们经常能够看见一个运算,就是矩阵的转置,即使得a[i][j] = a[j][i],我们之前在存储矩阵时选择了行优先的存储方式,但是,转置之后,我们的矩阵是以原来的行为它的列,我们该如何做呢?
方法一:普通转置
**我们遍历矩阵,将第一列数据先放入新的矩阵,再放第二列,第三列,以此类推,这样,我们就能够得到新的矩阵
下面是代码的实例(截取重要部分代码):
//普通转置
SpaMatrix<T>::SpaMatrix<T> OrdinaryTrans()
{
int count = 0;
int index = 0;
SpaMatrix<T> sp;//使用一个临时变量存储转置后的矩阵
for (int j = 0; j < _Col; j++)
{
for (int index = 0; index < _a.size(); index++)
{
if (_a[index]._col == j)
{
//每次只push需要的列
sp._a.push_back(_a[index]);
sp._a[index]._row = _a[index]._col;
sp._a[index]._col = _a[index]._row;
}
}
}
//更新转置后的矩阵行列信息
sp._Row = _Col;
sp._Col = _Row;
return sp;
}
方法二:快速转置
**我们将原来的矩阵的每一列有效数据的起始位和每一列有效数据的个数保存起来,作为新矩阵的每一行有效数据的起始位置和有效数据个数,当我们想要的得到某个数据时,使用 上一行的起始位置+有效数据的个数即可得到我们新的矩阵。
我们来看看代码的实例:
//快速转置
SpaMatrix<T>::SpaMatrix<T> FastTrans()
{
//统计有效数据的开始位置
int *RowStart = new int[_Col];
//统计转置之后的矩阵里每行的有效数据的个数
int *RowCount = new int[_Col];
memset(RowCount, 0, sizeof(int)*_Col);
memset(RowStart, 0, sizeof(int)*_Col);
size_t index = 0;
//Set RowCount
while (index < _a.size())
{
RowCount[_a[index]._col]++;
index++;
}
//Set RowStart
RowStart[0] = 0;
for (int i = 1; i < _Col; i++)
{
RowStart[i] = RowStart[i - 1] + RowCount[i - 1];
}
//构造转置之后的矩阵
SpaMatrix<T> sptrans;
sptrans._Row = _Col;
sptrans._Col = _Row;
sptrans._n = _n;
//index 值已经改变了,必须重新让其等于0
index = 0;
//此处使用下标访问必须开辟空间,但如果使用push_back()可以不用开辟~
sptrans._a.resize(_a.size());
while(index < _a.size())
{
int Rowindex = _a[index]._col;
//此处注意引用
int& RowSt = RowStart[Rowindex];
sptrans._a[RowSt]._value = _a[index]._value;
sptrans._a[RowSt]._col = _a[index]._row;
sptrans._a[RowSt]._row = _a[index]._col;
index++;
//每次必须更新该位置,否则错误
RowSt++;
}
return sptrans;
}
以上是我自己实现的转置代码,虽然代码渣,但是就是有迷之自信敢给你们看,我就问你们怕不怕
本文出自 “Zimomo” 博客,请务必保留此出处http://zimomo.blog.51cto.com/10799874/1764814