对称矩阵
对称矩阵A:N*N,A(i,j)=A(j,i)(0<=i<=N&&0<=j<=N)
压缩存储:只存储对称矩阵的上三角或下三角的数据,所以最多存储N*(N+1)/2个数据
对称矩阵和压缩存储的对应关系:SymmetricMatrix[i][j]=array[i*(i+1)/2+j]
还原矩阵:首先判断指定位置的元素是上三角还是下三角的坐标,如果是上三角的坐标,值要将(x,y)的坐标交换就可以了,否则直接返回指定位置的下三角元素。
#include<iostream>
using namespace std;
template<class T>
class SymmetricMatrix
{
public:
SymmetricMatrix(T* arr, int n)
:_row(n)
, _col(n)
, _data(new T[n*(n+1)/2])
{
int index = 0;
//存储下三角的元素
for (int i = 0; i < n; ++i)//控制遍历的次数
{
for (int j = 0; j < n; ++j)//控制每行遍历的元素个数
{
if (i >= j)//控制读取原始数据的行数
{
//行数*每行的元素个数就是当前行的第一个元素,然后+j往后偏移
_data[index] = arr[i*n+j];
index++;
}
}
}
}
T getdata(int i, int j)
{
if (i <= j)
{
return _data[i*(i+1)/2 + j];
}
else
{
swap(i, j);
return _data[i*(i + 1) / 2 + j];
swap(j, i);
}
}
void print()
{
for (int i = 0; i < _row; ++i)
{
for (int j = 0; j < _col; ++j)
{
cout << getdata(i, j) << " ";
}
cout << endl;
}
}
private:
int _row;
int _col;
T* _data;
};
int main()
{
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}
};
SymmetricMatrix<int> array((int*)arr,5);
array.print();
system("pause");
return 0;
}
运行结果:
稀疏矩阵
稀疏矩阵:M*N的矩阵中有效值的个数远远小于无效值的个数,且这些数据的分布没有任何规律
压缩存储:使用三元组{row,col,value}存储原矩阵中每一个有效值及其所在的行和列(以行优先级顺序依次存放),然后将这些三元组放入vector中
还原矩阵:如果数值等于vector中三元组中的有效元素,则打印这个元素,然后vector向后偏移,否则打印无效
#include<iostream>
using namespace std;
#include<vector>
template<class T>
struct trituple
{
trituple(size_t row, size_t col, T data)
:_row(row)
, _col(col)
, _data(data)
{}
trituple()
{}
size_t _row;
size_t _col;
T _data;
};
template<class T>
class SpareseMatrix
{
public:
SpareseMatrix(T* arr, size_t row, size_t col,T value)
:_row(row)
,_col(col)
,_value(value)
{
for (size_t i = 0; i < row; ++i)
{
for (size_t j = 0; j < col; ++j)
{
if (arr[i*col + j] != _value)
{
_v.push_back(trituple<T>(i, j, arr[i*col + j]));
}
}
}
}
void print()
{
size_t index = 0;
for (size_t i = 0; i < _row; ++i)
{
for (size_t j = 0; j < _col; ++j)
{
if (index != _v.size() && i==_v[index]._row && _v[index]._col == j)
{
cout << _v[index]._data << " ";
index++;
}
else
{
cout << _value << " ";
}
}
cout << endl;
}
}
private:
vector<trituple<T>> _v;
int _row;
int _col;
T _value;
};
int main()
{
int arr[6][5] = {
{ 1,0,3,0,5},
{ 0,0,0,0,0},
{ 0,0,0,0,0},
{ 1,0,3,0,5},
{ 0,0,0,0,0},
{ 0,1,4,0,0}
};
SpareseMatrix<int> array((int*)arr, 6, 5, 0);
array.print();
system("pause");
return 0;
}
运行结果:
稀疏矩阵的逆置
1、普通的逆置
通过遍历原矩阵的三元组表得出逆置后的元素存储的三元组表,所以根据原矩阵的每个元素的y坐标作为判断依据,y=0就是逆置后的三元组表中的下标为0行的元素,y=1就是小标为1行的元素·········,根据优先的顺序遍历最后得到的就是逆置后的三元组表。
void Transpostion()
{
size_t n = _a.size();
vector<Triple<T>> _tmp;//定义转置后的Vector
size_t count = 0;
for (size_t i = 0; i < _col; i++)
{
for (size_t j = 0; j < n; j++)
{
if (_a[j].y == i)//如果列下标符合,则将其压入vector,i表示列
{
_tmp.push_back(_a[j]);
swap(_tmp[count].y, _tmp[count].x);//将压进去的元素的(x,y)互换
count++;//为了交换而设计的,不然的话没有办法交换
}
}
}
for (size_t i = 0; i < n; i++)//方便打印而写的代码
{
_a[i] = _tmp[i];
}
swap(_col, _row);//整体矩阵的行列互换
}
由于要遍历数次原矩阵的三元组表,故而效率太低。
2、快速逆置
这种方法只要遍历一遍原矩阵的三元组表,就可以得到转置后的三元组表。
准备两个数组,一个用来存储原矩阵中每列有效元素的个数
一个用来存储原三元组表中每列第一个有效元素在新三元组表中的位置
void Transpostion2()
{
vector<Triple<int>> _tmp2;//用来存储逆置后的顺序
//都是用来表示列的相关内容的
size_t n = _a.size();//原矩阵的三元组个数
_tmp2.resize(n);//开辟矩阵三元组的个数
size_t num[5] = { 0 };//表示每列中的有效元素的个数
size_t pos[5] = { 0 };//表示每列中第一个有效元素在_tmp2的位置
//填补num,遍历有效元素就可以了
for (size_t i = 0; i < n; i++)//因为是遍历远原来的vector所以用n
num[_a[i].y]++;//能表示到哪个y坐标几次则表示那个y列有几个元素
pos[0] = 0;//第一个列元素的位置在新表位置肯定是0,毋庸置疑
for (size_t j = 1; j < 5; j++)//填补pos,每个位置对应一列
{
pos[j] =pos[j - 1] + num[j - 1];//第二列的首元素位置必然等于第一列第一个元素位置+元素个数
}
for (size_t k = 0; k < n; k++)//遍历一遍建成逆置后的tmp2
{
_tmp2[pos[_a[k].y]] = _a[k];//左边直接表示新表的指定的位置
swap(_tmp2[pos[_a[k].y]].y, _tmp2[pos[_a[k].y]].x);
pos[_a[k].y]++;//当前位置存了元素往后走一个储存位置,因为下一次走到这个列的话必定在其后面储存
}
for (size_t i = 0; i < n; i++)
{
_a = _tmp2;
}
swap(_col, _row);
}
稀疏矩阵的加法
分别计算两个矩阵的有效元素在各自矩阵中的序列,然后遍历矩阵,如果序列相等则相加对应元素,否则把较小的插入到新的三元组表中,然后继续比较。
//稀疏矩阵的加法
void operator+(Trituple<T> &tri2)//第二个要运算的矩阵
{
if (tri2._col != _col&&tri2._row != _row)//判断矩阵是否相同
{
exit(0);
}
vector<Triple<T>> tmp;
size_t index1 = 0;
size_t index2 = 0;
size_t _aarr[6] = { 0 };//储存第一个的偏移量,注意这里可以去优化修改,我就不弄了
size_t _tarr2[6] = { 0 };//储存第二个的偏移量
for (size_t i = 0; i < _a.size(); i++)
{
_aarr[i] = ((_a[i].x * _col) + _a[i].y);
}
for (size_t j = 0; j < tri2._a.size(); j++)
{
_tarr2[j] = ((tri2._a[j].x *tri2._col) + tri2._a[j].y);
}
while (index1 < 6 && index2<6)//开始计算
{
while (_aarr[index1]>_tarr2[index2] && index1 < 6 && index2 < 6)
{
tmp.push_back(tri2._a[index2]);
index2++;
}
while (_aarr[index1] < _tarr2[index2] && index1 < 6 && index2 < 6)
{
tmp.push_back(_a[index1]);
index1++;
}
while (_aarr[index1] == _tarr2[index2] && index1 < 6 && index2 < 6)
{
_a[index1].data += tri2._a[index2].data;
tmp.push_back(_a[index1]);
index1++;
index2++;
}
_a.resize(tmp.size());
for (size_t i = 0; i < tmp.size(); i++)
{
_a[i] = tmp[i];
}
}
}