您的位置:首页 > 其它

特殊矩阵的压缩存储

2016-12-10 15:46 204 查看

矩阵的压缩存储

这两天我们学的一直是数据结构,今天我们来说说矩阵的这个数据结构 之前在大一的时候我们就学习线性代数是就了解了矩阵的使用 ,但是我们主要讲的是 矩阵的计算方法。。。。。
但是我们现在学习了编程语言 ,之后就要学会将矩阵存储起来 ,但是 有一些特殊的矩阵,如果我们将他们全部都存储起来的话之后,就会浪费很多的空间。。。。。
就比如说

对称矩阵的压缩存储

所谓对称矩阵,就是上三角 与下三角的数据都是相等的 , ,, ,如果我们将上三角与下三角都存储起来的话就显得有点多余了。。》》》》
下面用图来说明一下吧!!!!!



上图表示就是一个对称矩阵,其中上三角与下三角的数据值一模一样的,
所以我们可以将这个矩阵压缩存储一下,只需要保存下三角的数据就可以了。。。
我们可以将这数据保存在数组里,,,,
压缩存储称矩阵存储时只需要存储上三角/下三角的数据,所以最多存储n(n+1)/2个数据。

对称矩阵和压缩存储的对应关系:下三角存储i>=j, SymmetricMatrix[i][j] ==Array[i*(i+1)/2+j]
写出代码是
//对称矩阵的压缩存储
template<class T>
class SymmetricMatrix
{
public:
SymmetricMatrix(T * a,size_t  n)
:_a(new T[n*(n+1)/2])
,_n(n)
{
for(size_t i = 0 ;i < n; ++i )
{
for(size_t j = 0 ;j < n;++j)
{
if(i >= j)
{
_a[i*(i+1)/2 +j]  = a[i*n + j];//将下三角的值都放到数组里去;;
}
else
{
break;
}
}
}
}
T& Access(size_t i ,size_t j)//得到每个位置的值
{
if(i < j)
{
std::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)
{
cout<<Access(i,j)<<" ";
}
cout<<endl;
}
}
protected:
T * _a;//存储的下三角的数组指针
size_t _n;//矩阵的大小
};


//测试代码
void TestSymmetricMatrix()
{
int a [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> s1((int*)a,5);
s1.Display();
}
矩阵中 的特殊矩阵除了对称矩阵之外还有的是稀疏矩阵 。。。。

稀疏矩阵的压缩存储

稀疏矩阵也是矩阵,只不过它里面保存的值大多数都是无效的的,只有少数是有效的, 所以对于这类的
矩阵 ,, ,, ,压缩存储是十分有必要的,为什么呢????
如果有有一个文件大约有 32G ,如果存到硬盘上就会很费空间,但是它里面有效的数据仅仅只有 100M的话
在这种情况下,使用压缩存储是十分有必要的。。。
关于这类矩阵我们要怎么来压缩存储呢????
我们可以只保存有效数据的坐标与有效值 。。。。。
我们保存的数据叫做是一个三元组 (实际上就是个结构体)
压缩存储值存储极少数的有效数据。使用{row,col,value}三元组存储每一个有效

数据,三元组按原矩阵中的位置,以行优先级先后顺序依次存放。
另外除了这个 ,, , ,我们还需要实现一个矩阵转置 , ,, ,得到转置矩阵的压缩存储
实现转置的方法总有很多种:::
在这里我来说两种 ,,, 一个是普通的转置 ,,,, 还有就是快速转置。》》》》
就用下面这个矩阵来说说吧!!!!



通过上图我们可以看出来 ,,,上面的图中转置之后只是之前的列换成是的转置后的行
因此我们可以将按照列优先遍历一遍转置前的存储 !!!!
按照列的先后顺序 插入到新的压缩存储中!!!!
这就是所谓的普通转置法》》》》》
上面的转置法 ,,,将原来生成的压缩数组 ,遍历了不只一遍
所谓的快速转置法也就是说 只需要遍历一次, 就可以得到转置后的存储。。。。
但是要怎么做 呢????
我们知道所谓转置 ,就是将之前的行换成了现在的列 。。。。。
所以我们只需要记录下之前的每列有多少个有效值 ,,,,
再用 一个数组记录下每列的数的该插入的其实坐标。。。。
只要知道这俩个我们就可以直接 , ,, , ,,遍历一次数组 ,就可以将 全部完成转置。。。。
实现代码
//稀疏矩阵的存储的三元组
template<class T>
struct Triple
{
size_t _row;//保存元素的行
size_t _col;//保存元素的列
T _value;//保存元素的有效值
Triple(size_t row = 0,size_t col  = 0 ,const T& value = T())
:_row(row)
,_col(col)
,_value(value)
{}
};

template<class T>
class SparseMatrix
{
public:
SparseMatrix(T* a,size_t m,
size_t n,const T& invalid)
:_a(vector<Triple<T>>())
,_countrow(m)
,_countcol(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<T>(i,j,a[i*n+j]));
}
}
}
}
SparseMatrix()
{}

//转置
SparseMatrix  Transport()
{
SparseMatrix<T> s;
s._a = vector<Triple<T>>();
s._a.reserve(_a.size());
s._countrow =_countcol;
s._countcol =_countrow;
s._invalid  =_invalid;
for(size_t i = 0 ;i < s._countrow;++i)//从第0列开始,向后
{
for(size_t j  = 0 ;j <_a.size();++j)
{
if(_a[j]._col  ==  i)//如果是存储的当前列的数就插入
{
s._a.push_back(Triple<T>(_a[j]._col,_a[j]._row,_a[j]._value));
}
}
}
return s;
}
//快速转置
SparseMatrix  FastTransport()
{
SparseMatrix<T> s;
s._a = vector<Triple<T>>();
s._a.resize(_a.size());
s._countrow =_countcol;
s._countcol =_countrow;
s._invalid  =_invalid;
int* count = new int[s._countrow];//创建数组 count保存每一列的有效值个数
for(size_t i = 0; i < s._countrow;++i)
{
int m= 0 ;
for(size_t j = 0 ;j <_a.size();++j)
{
if(_a[j]._col == i)
{
m++;
}
}
count[i] = m;
}
int * start = new int[s._countrow];//创建数组start 保存每一列位置的起始值
*start  = 0;//第一列位置的起始值为0
for(size_t i = 1;i < s._countrow;++i)
{
start[i]  =start[i-1] + count[i-1];
}
for(size_t i = 0 ;i < _a.size();++i)
{
s._a[start[_a[i]._col]]  =Triple<T>(_a[i]._col,_a[i]._row,_a[i]._value);
start[_a[i]._col]++;//每一列插入一个元素之后 ,,,其实位置向后移一位
}
delete[] count;//释放开辟的这两段空间
delete[] start;
return s;
}
void Dsiplay()
{
size_t idex = 0;
for(size_t i = 0;i <_countrow;++i)
{
for(size_t j =  0;j < _countcol;++j)
{
if( idex < _a.size()
&& _a[idex]._row == i
&& _a[idex]._col == j)
{
cout<<_a[idex]._value<<" ";
idex++;

}
else
{
cout<<_invalid<<" ";
}
}
cout<<endl;
}
cout<<endl;
}

protected:
vector<Triple<T>> _a;//保存压缩后的数据
size_t _countrow;//矩阵的行
size_t _countcol;//矩阵的列
T _invalid;//保存的是无效值

};

void TestSparseMatrix()
{
int array [6][5] = {{1, 0, 3, 0, 5},
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0},
{2, 0, 4, 0, 6},
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0}};
SparseMatrix<int> s((int*)array,6,5,0);
s.Dsiplay();
SparseMatrix<int> s1 =s.Transport();
s1.Dsiplay();
SparseMatrix<int> s2 =s.FastTransport();
s2.Dsiplay();

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  矩阵的压缩存储