稀疏矩阵-----矩阵中有效元素的个数远远小于总元素的个数。所以,要是我们把矩阵中
的所有元素都存储起来的话,这样子对空间就是造成极大的浪费。所以,我们采用压缩
存储,即就是,将有效元素存储在一个三元组中(包括元素所在行,列,值),这样就
减少了空间的浪费。
三元组定义如下:
template<typename T>
struct Triple
{
T _value;
size_t _row;
size_t _col;
Triple(T value = 0,size_t row = 0,size_t col = 0)
:_value(value)
,_row(row)
,_col(col)
{}
};
我们知道,矩阵的转置就是交换元素的行和列。下边图解:
由于上述的转置方法效率比较低下,所以,我们采用另一种方法:见图
下边给出实现代码:
//声明:代码中的几处注释,仅仅是个人心得
#pragma once
#include<iostream>
using namespace std;
#include<vector>
template<typename T>
struct Triple
{
T _value;
size_t _row;
size_t _col;
Triple(T value = 0,size_t row = 0,size_t col = 0)
:_value(value)
,_row(row)
,_col(col)
{}
};
template<typename T>
class SparseMatrix
{
public:
typedef Triple<T> Triple;
SparseMatrix()
{}
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)
{
_a.push_back(Triple(a[i * n + j], i, j));
}
else
{
continue;
}
}
}
}
void Display()
{
size_t index = 0;
for (size_t i = 0; i < _rowSize; ++i)
{
for (size_t j = 0; j < _colSize; ++j)
{
size_t size = _a.size();
/*if ((_a[index]._row == i)
&& (_a[index]._col == j)//注意:三个条件顺序不同,下边的实现则不同
&& (index < size))*/ //如果这样写,下边的加一操作必须进行条件判断
if ((index < size)
&&(_a[index]._row == i)
&& (_a[index]._col == j))//最好写成这样
{
cout << _a[index]._value << " ";
//if (index != size - 1)
++index;
}
else
{
cout << _invalid << " ";
}
}
cout << endl;
}
cout << endl;
}
SparseMatrix<T> Transport()
{
SparseMatrix<T> sm;
sm._colSize = _rowSize;
sm._rowSize = _colSize;
sm._invalid = _invalid;
sm._a.reserve(_a.size());
for (size_t i = 0; i < _colSize; ++i)
{
size_t index = 0;
while (index < _a.size())
{
if (_a[index]._col == i)
{
sm._a.push_back(Triple(_a[index]._value, _a[index]._col, _a[index]._row));
}
++index;
}
}
return sm;
}
SparseMatrix<T> FastTransport()
{
SparseMatrix<T> sm;
sm._colSize = _rowSize;
sm._rowSize = _colSize;
sm._invalid = _invalid;
sm._a.resize(_a.size());
//nums数组的初始化
int* nums = new int[_colSize];
memset(nums,0,sizeof(int)*_colSize);
for (size_t index = 0; index < _a.size(); ++index)
{
int col = _a[index]._col;
++nums[col];
}
//start数组初始化
int* start = new int[_colSize];
start[0] = 0;
for (size_t i = 1; i < _colSize; ++i)
{
start[i] = start[i - 1] + nums[i - 1];
}
//转置
for (size_t i = 0; i < _a.size(); ++i)
{
int col = _a[i]._col;
int begin = start[col];
sm._a[begin]._row = _a[i]._col;
sm._a[begin]._col = _a[i]._row;
sm._a[begin]._value = _a[i]._value;
++ start[col];
}
delete[] nums;
delete[] start;
return sm;
}
private:
vector<Triple> _a;//存放结构体的容器
size_t _rowSize;
size_t _colSize;
T _invalid;
};
void TestSparseMatrix()
{
int a[5][6] = {
{0,1,0,3,0,5},
{0,0,0,0,0,0},
{0,2,0,4,0,6},
{0,0,0,0,0,0},
{ 0,0,0,0,0,0 }
};
SparseMatrix<int> sp((int*)a,5,6,0);
sp.Display();
SparseMatrix<int> tsm = sp.Transport();
tsm.Display();
SparseMatrix<int> ftsm = sp.FastTransport();
ftsm.Display();
}
上边这段程序的完成过程中,也是遇到了各种各样的问题,原因还是对STL容器使用不
熟练,比如resize()和reserve()的区别;
resize()改变size为指定的值,而reserve()改变容量(size并没有改变)。
在Transport函数中我们用的是reserve(),(其实sm._a.reserve(_a.size())不要也行),
毕竟我们是向容器中push数据。如果使用resize(),后有什么后果。resize()不仅仅是改
变大小,还会将这块空间置为随机值,所以之后push(可以push进去,vector
自动改变容量),新的内容会被写入resize那段空间之后,在display时,输出的矩阵
的元素全是0(无效值)。
FastTransport函数中,我们必须使用resize,因为我们后边使用的是[]操作([pos]必须
保证pos要小于当前size)。但是也有人说,不使用resize,然后后边使用push_back,
其实,我尝试过这样的办法,快速转置是将原矩阵的有效元素放到新矩阵的对应位置,
push_back只能做到放到新矩阵,但是不能保证放到正确的位置。所以,我们必须使用
resize().
以上说法如有问题,请回复~~不甚感激