您的位置:首页 > 编程语言 > C语言/C++

三元组压缩存储稀疏矩阵的C++类模板实现

2017-03-25 17:12 501 查看
一 简介

设m*n 矩阵中有t 个非零元素且t<<m*n,这样的矩阵称为稀疏矩阵。

遇到阶数很高的大型稀疏矩阵,按常规分配方法,顺序分配在计算机内,占用内存过大。

故有另一种存储方法,仅仅存放非零元素。

但对于这类矩阵,通常零元素分布没有规律,为能找到相应的元素,仅存储非零元素是不够的,还要记下它所在的行和列。

将三元组按行优先的顺序,同一行中列号从小到大的规律排列成一个线性表,称为三元组表,采用顺序存储方法存储该表。一张图举例说明问题:



二 编程实现

准备的测试文件有:







1. 先建立一个CPMatrix.h

#ifndef CPMatrix_H
#define CPMatrix_H
enum Sub_Or_Add{
Sub,Add//在下面成员函数选择加法或减法的标志
};
template <typename T>
struct Triple{//三元组类型结构体
int i,j;//行列下标
T e;//非零元素的值
};
const int MAX_SIZE=100;//非零元素的个数最大值
const int MAX_RC=20;//矩阵最大行数
template <typename T>
class CPMatrix{
private:
Triple<T> data[MAX_SIZE+1];//非零元三元组表,data[0]不用
int rpos[MAX_RC+1];//各行第一个非零值的位置表
int row,col,num;//行列数,非零元个数
public:
CPMatrix(){
row=col=num=1;
}
CPMatrix(char * FileName){
CreateSMatrixFromFile(FileName);
}
bool CreateSMatrixFromFile(char *FileName="test1.txt"){
int i,j;
ifstream fin(FileName);
fin>>row>>col>>num;
if(num>MAX_SIZE||row>MAX_RC)
return false;
data[0].i=0;
for(i=1;i<=num;i++){
fin>>data[i].i>>data[i].j>>data[i].e;
if(data[i].i<1||data[i].i>row||data[i].j<1
||data[i].j>col)
return false;
if(data[i].i<data[i-1].i||data[i].i==data[i-1].i
&&data[i].j<data[i-1].j)//行或者列输入顺序错误!!
return false;
}
fin.close();
for(i=1;i<=row;i++){
rpos[i]=1;//先初始化:每一行第一个非零值元素都挤在三元组第一个位置data[1],显然不可能
}
for(i=1;i<=num;i++)
for(j=data[i].i+1;j<=row;j++)//从非零元素所在行的下一行开始
rpos[j]++;//相当于每行第一个非零元素的位置后移一位
return true;

}
void CopySMatrix(const CPMatrix<T> &M){
int i;
row=M.row;
col=M.col;
num=M.num;
for(i=0;i<=M.num;i++)
data[i]=M.data[i];
for(i=0;i<M.row;i++)
rpos[i]=M.rpos[i];
}
void TransposeSMatrix(const CPMatrix<T> &M){
int i,j,k,colm[MAX_RC+1];//[0]不用!!
row=M.col;
col=M.row;
num=M.num;
if(num){//矩阵非空
for(i=1;i<=row;++i)//从矩阵第一列到最后一列
colm[i]=0;
for(i=1;i<=num;++i)
++colm[M.data[i].j];//统计每一列有多少个元素,最后colm
=m表示第n列有m个非零元素
rpos[1]=1;
for(i=2;i<=row;++i)
rpos[i]=rpos[i-1]+colm[i-1];//最后rpos[i]=a表示M转置后第i行第一个非零元素的位置data[a]
for(i=1;i<=row;++i)
colm[i]=rpos[i];//此时colm[]存放每一行第一个非零元素在M转置后应该存放的位置data[]
for(i=1;i<=num;++i){//对于每一个非零元素
j=M.data[i].j;//取得行号
k=colm[j]++;//k代表该行第n个非零元素的位置,colm[]自增准备下次该行后一个非零元素的读取
data[k].i=j;//开始对调
data[k].j=M.data[i].i;
data[k].e=M.data[i].e;
}
}

}
bool Sub_Add_SMatrix(const CPMatrix<T> &M,const CPMatrix<T> &N,Sub_Or_Add mod){
int p,q,up,uq;
if(M.row!=N.row||M.col!=N.col)
return false;
row=M.row;
col=M.col;
num=0;
for(int k=1;num<=MAX_SIZE&&k<=M.row;++k)//k指示行号
{
rpos[k]=num+1;//“和矩阵”的第K行的第一个元素的位置data[]
p=M.rpos[k];//p指示M第K行当前元素的位置
q=N.rpos[k];
if(k<M.row){//不是最后一行
up=M.rpos[k+1];//下一行的第一个元素位置data
的n是本行元素的上界最大
uq=N.rpos[k+1];
}
else{
up=M.num+1;//最后一行也设置上届
uq=N.num+1;
}
while(p<up&&q<uq)
if(M.data[p].j<N.data[q].j){//M当前元素的列 < N当前元素的列
data[++num] = M.data[p++];//不论加法减法都是把M赋给“和矩阵”

}

else
if(M.data[p].j>N.data[q].j){//M当前元素的列 > N当前元素的列,就是N在前面
data[++num]=N.data[q++];//加法直接赋值
if(mod==Sub)
data[num].e *= (-1);//减法还要乘-1,应为相当于用0减去!!!
}

else{
if(M.data[p].e-N.data[q].e!=0&&mod==Sub){
data[++num]=M.data[p];
data[num].e-=N.data[q].e;
}
if(M.data[p].e+N.data[q].e!=0&&mod==Add){
data[++num]=M.data[p];
data[num].e+=N.data[q].e;
}
p++;
q++;
}

while(p<M.rpos[k+1]&&p<=M.num)
data[++num]=M.data[p++];
while(q<N.rpos[k+1]&&q<=N.num){
data[++num] = N.data[q++];
if(mod==Sub)
data[num].e *= (-1);
}
}
if(num>MAX_SIZE) return false;
else return true;
}
bool MultSMatrix(const CPMatrix<T> &M,CPMatrix<T> &N){
int i,j,q,p,up,uq;
T temp;//暂时存放data[].e
CPMatrix<T> E;//存放N转置矩阵
if(M.col!=N.row) return false;
row=M.row;
col=N.col;
num=0;
E.TransposeSMatrix(N);
for(i=1;i<=row;i++)//对于乘积每一行
for(j=1;j<=col;j++){//对于乘积每一列
temp=0;
p=M.rpos[i];//p指示M在第i行的第一个非零元素位置
q=E.rpos[j];//q指示E在第j行(也就是N在第j列)的第一个非零元素位置
if(i<M.row)
up=M.rpos[i+1];
else
up=M.num+1;
if(j<E.row)
uq=E.rpos[j+1];
else uq=E.num+1;
while(p<up&&q<uq)
if(M.data[p].j<E.data[q].j)
p++;
else
if(M.data[p].j>E.data[q].j)
q++;
else
temp+=M.data[p++].e*E.data[q++].e;
if(temp){
if(++num>MAX_SIZE) return false;
data[num].i=i;
data[num].j=j;
data[num].e=temp;
}
}
return true;
}
void PrintSMatrix()const{
int k=1;
const Triple<T> *p=data+1;//p指向第一个非零元素
if(num==0) return ;
for(int i=1;i<=row;i++){
for(int j=1;j<=col;j++){
if(k<=num&&p->i==i&&p->j==j){
cout<<setw(3)<<(p++)->e;
k++;
}
else cout<<setw(3)<<0;
}
cout<<endl;
}
}
};
#endif


2. 当然习惯了C.h包含各种有用没用的头文件(可多不可少)

//C.h 几乎各程序都需要用到的文件包含宏命令和使用名空间
#ifndef C_H
#define C_H
#include <iostream>
#include <fstream>
#include <iomanip>
#include <cmath>
#include <string>
#include <vector>
#include <list>
#include <stack>
#include <queue>
#include <bitset>
#include <algorithm>
#include <ctime>
#include <cstdarg>
#include <assert.h>
using namespace std;
#endif


3. 最后是测试

#include "C.h"
#include "CPMatrix.h"
int main()
{
bool f;
CPMatrix<int> A("test2.txt"), B, C,D;
cout<<"test2.txt建矩阵A="<<endl;
A.PrintSMatrix();
f=B.CreateSMatrixFromFile();
if(f)
{
cout<<"默认test1.txt建矩阵B="<<e
a157
ndl;
B.PrintSMatrix();
}
C.CopySMatrix(A);
cout<<"A的拷贝C="<<endl;
C.PrintSMatrix();
f=C.CreateSMatrixFromFile("test3.txt");
if(f)
{
cout<<"由test3.txt重建C="<<endl;
C.PrintSMatrix();
}
f=B.Sub_Add_SMatrix(A, C,Add);
if(f)
{
cout<<"B=A+C="<<endl;
B.PrintSMatrix();
}
f=D.Sub_Add_SMatrix(B, A,Sub);
if(f)
{
cout<<"D=B-A="<<endl;
D.PrintSMatrix();
}
A.TransposeSMatrix(C);
cout<<"C的转置重建A:"<<endl;
A.PrintSMatrix();
f=B.MultSMatrix(C, A);
if(f)
{
cout<<"B=C×A="<<endl;
B.PrintSMatrix();
}
return 0;
}


运行结果:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐