对于N*N的矩阵A,对于任意i和j(N-1>i>=0 && N-1>j>=0),如果Aij=Aji那么,就称矩阵A是对称矩阵。以矩阵对角线为分界线,矩阵A分为上三角和下三角。
如下图:
由对称矩阵的性质,存储对称矩阵时,只需要存储对称矩阵的上三角或下三角就可以了(压缩存储),最多存储N*(N+1)/2个数据。
对称矩阵和压缩存储的对应关系:下三角存储i>=j, SymmetricMatrix[i][j] == Array[i*(i+1)/2+j]
步骤分析:
(1)存储
定义一个一维数组_a,开辟N*(N+1)/2个空间,遍历矩阵,若i>=j,说明元素在矩阵的下三角位置,按顺序存入_a; 若i<j,则不存储,继续遍历矩阵的下一个元素。
(2)访问矩阵元素
要访问压缩存储的矩阵元素,我们可以根据对称矩阵和压缩存储的对应关系: SymmetricMatrix[i][j] == Array[i*(i+1)/2+j]
来访问矩阵元素。
实现方法:
#pragma once
#include<iostream>
using namespace std;
template<class T>
class SymmetricMatrix
{
public:
SymmetricMatrix(const T* a, size_t size, size_t n)//构造函数,压缩存储矩阵元素
:_a(new T[n*(n + 1) / 2])//开辟空间,下三角元素一共有(n*(n + 1) / 2)个
, _size(n*(n + 1) / 2)//设置一维数组大小
, _n(n)//矩阵大小(维数)
{
int index = 0;
for (size_t i = 0; i < n; i++)
{
for (size_t j = 0; j < n; j++)//遍历
{
if (i >= j) //若为下三角元素
_a[index++] = a[i*n + j];//存储
else; //若不是下三角元素
break //直接跳出循环(此步骤优化,若不是下三角元素,则该行剩余元素一定也不是下三角元素)
}
}
}
~SymmetricMatrix()//析构函数
{
if (_a)
delete[] _a;
}
T& Access(int i,int j)//访问元素
{
if (i < j)
swap(i, j);
return _a[i*(i + 1) / 2 + j];//根据对称矩阵和压缩存储的对应关系访问元素
}
void display()//还原打印矩阵
{
for (size_t i = 0; i < _n; i++)
{
for (size_t j = 0; j < _n; j++)
{
if (i >= j)//若要打印下三角元素,则直接根据对称矩阵和压缩存储的对应关系访问元素,打印
cout << _a[i*(i + 1) / 2 + j] << " ";
else //若打印上三角元素,则交换元素行列(根据对称矩阵性质),就可以看做该元素是下三角元素并打印
cout << _a[j*(j + 1) / 2 + i] << " ";
}
cout << endl;
}
}
protected:
T* _a;
size_t _size;
size_t _n;
};
测试代码:
#include "SymmetricMatrix.hpp"
void TestSymmetricMatrix()
{
int a[4][4] = {
{0,1,2,3},
{1,0,3,4},
{ 2, 3, 0, 5 },
{ 3, 4, 5, 0 }
};
size_t size = sizeof(a) / sizeof(a[0][0]);
SymmetricMatrix<int> matrix((int *)a, size, 4);
matrix.display();
cout << matrix.Access(2,3) << endl;
}
int main()
{
TestSymmetricMatrix();
getchar();
return 0;
}