定义了一个稀疏矩阵类,有转置和相乘,相加三个功能,主要是熟悉稀疏矩阵的三元组顺序表存储的一些操作,和一般的矩阵不同的地方,两个转置的算法,第一个是较容易想到的,书上管它叫“按需点菜”法,就是按一开始列的顺序,一个个转为新矩阵中行的顺序。第二个叫作“按位就坐”法,就是条件两个辅助数组,确定每一列中第一个非零元在稀疏矩阵中存储的位置,从而可以在操作时,更为容易地实现矩阵转置后可以按行递增的顺序排列整齐。
稀疏矩阵的乘法,我自己觉得确实有难度,研究了一天才研究清楚这个东西,如果按和一般矩阵那样去做的话,虽然会浪费多一点时间,但是代码量和思考量就相对少得多,但是这也是算法的特别之处吧。 下面是代码,有较为清楚的解释
文件"dingyi.h"
#define maxtemr 100
class SparseMatrix; //向前声明
class MatrixTerm//矩阵元素类
{
public:
int row;//行
int col;//列
int value;//值
friend SparseMatrix;
};
class SparseMatrix
{
private:
int Rows;//行数
int Cols;//列数
int Terms;//非零项个数
MatrixTerm smArray[maxtemr];//maxterm是常数,maxterm<<Rows*Cols
int cpot[20];
public:
void InitMatrix();
SparseMatrix Transpose1(); //矩阵转置算法1
SparseMatrix Transpose2();//矩阵转置算法2
bool Multiply(SparseMatrix b,SparseMatrix &q);//矩阵相乘
bool Add(SparseMatrix b,SparseMatrix &c);//矩阵相加
void print();
};
文件"shixian.cpp"
#include"dingyi.h"
#include<iostream>
using namespace std;
void SparseMatrix::InitMatrix()
{
Terms=0;
int r,c,s=0,val;
cout<<"输入要创建的矩阵的行数和列数:";
cin>>r>>c;
Rows=r;
Cols=c;
cout<<"请输入矩阵中各元素的值,请输入"<<r*c<<"个整数"<<endl;
for(int i=0;i<r;i++)
{
for(int j=0;j<c;j++)
{
cin>>val;
if(val!=0)
{
smArray[s].row=i;
smArray[s].col=j;
smArray[s].value=val;
s++;
}
}
}
Terms=s;
int *num=new int[r];
for(int m=0;m<Rows;m++)
num[m]=0;
for(m=0;m<Terms;m++)
++num[smArray[m].row];
cpot[0]=0;
for(m=1;m<Rows;m++)
cpot[m]=cpot[m-1]+num[m-1];
}
SparseMatrix SparseMatrix::Transpose1()
{
SparseMatrix b;
b.Rows=Cols;
b.Cols=Rows;
b.Terms=Terms;
if(b.Terms)
{
int currentB=0;
for(int c=0;c<Cols;c++)
for(int i=0;i<Terms;i++)
if(smArray[i].col==c)//找到c列中的元素
{
b.smArray[currentB].row=c;
b.smArray[currentB].col=smArray[i].row;
b.smArray[currentB].value=smArray[i].value;
currentB++;
}
}
return b;
}
SparseMatrix SparseMatrix::Transpose2()
{
SparseMatrix b;
b.Rows=Cols;
b.Cols=Rows;
b.Terms=Terms;
int *num;
int *cpot;
num=new int[Cols];
cpot=new int[Cols];
if(b.Terms)
{
for(int c=0;c<Cols;c++)
num[c]=0;
for(c=0;c<b.Terms;c++)
++num[smArray[c].col];
cpot[0]=0;
for(c=1;c<Cols;c++)
cpot[c]=cpot[c-1]+num[c-1];
for(int p=0;p<b.Terms;p++)
{
int j=smArray[p].col;
int q=cpot[j];
b.smArray[q].row=smArray[p].col;
b.smArray[q].col=smArray[p].row;
b.smArray[q].value=smArray[p].value;
++cpot[j];
}
}
return b;
}
bool SparseMatrix::Multiply(SparseMatrix b,SparseMatrix &q)
{
/*
返回两个矩阵的乘积,用C来装
采用与第二种转置的算法一样的做法,给每个矩阵增加一个数组,用来记录每一行第一个非零值在
在矩阵smArray[]中的位置,这个数组就是cpot[],有这样结构的稀疏矩阵叫做行逻辑连接顺序表
计算过程如下:
1. 由于矩阵a和Q的行数相等并且C语言以行为主序进行存储,所以以a进行逐行的扫描。
2. 使Q的此行逻辑表的序号等于其非零元个数Q.terms+1,以表示其行的首个元素的序号。
3. 从行中找到a的非零元,并以它的列值为b的行号,对b进行行的扫描,若存在,
则依次计算它们,并把其值累加到一个以b中这个对应非零元的列值为序号的临时数组q_sum[q_col]中。
4. 在a的当前行完成扫描后,将q_sum[q_col]不为0的值,压入到Q矩阵的三元组,累加Q.Terms
*/
int t1,t2,q_col;
int *q_sum;//用于存放结果的临时数组
if(this->Cols!=b.Rows)
return false;
q.Rows=this->Rows;
q.Cols=b.Cols;
q.Terms=0;
q_sum=new int[b.Cols];
if(this->Terms*b.Terms!=0)
{
for(int a_row=0;a_row<this->Rows;a_row++)//以a的每一行为标准,进行运算
{
for(int i=0;i<b.Cols;i++)
q_sum[i]=0;
q.cpot[a_row]=q.Terms;
if(a_row<this->Rows-1)
t1=this->cpot[a_row+1];
else
t1=this->Terms;
for(int p=this->cpot[a_row];p<t1;p++)
{
int b_row=this->smArray[p].col;
if(b_row<b.Rows-1)
t2=b.cpot[b_row+1];
else
t2=b.Terms;
for(int q=b.cpot[b_row];q<t2;q++)
{
q_col=b.smArray[q].col;
q_sum[q_col]+=this->smArray[p].value*b.smArray[q].value;
}
}
for(q_col=0;q_col<q.Cols;q_col++)
if(q_sum[q_col])
{
q.smArray[q.Terms].row=a_row;
q.smArray[q.Terms].col=q_col;
q.smArray[q.Terms].value=q_sum[q_col];
++q.Terms;
}
}
}
return true;
}
bool SparseMatrix::Add(SparseMatrix b,SparseMatrix &c)
{
/*
计算过程是这样的,一次扫描两个矩阵a,b的smArray[]中的每个数据,
比较两个数据,如果行号相同,则比较列号,若列号不想等则将列号小的存入矩阵c
的smArray[]中,若列号相等,则计算,计算完非零,再存入c中;
如果a的当前项行号小于b的当前项行号,那么就将a的项存入c,反之,存b
*/
if(this->Rows!=b.Rows||this->Cols!=b.Cols)
return false;
int sum=0;
int p=0;//指向a的当前项
int t=0;//指向b的当前项
int k=0;//指向c的当前项
while( p<this->Terms && t<b.Terms)
{
if(this->smArray[p].row==b.smArray[t].row)
{
if(this->smArray[p].col==b.smArray[t].col)
{
sum=this->smArray[p].value+b.smArray[t].value;
if(sum)
{
c.smArray[k].row=b.smArray[t].row;
c.smArray[k].col=b.smArray[t].col;
c.smArray[k].value=sum;
k++;p++;t++;
}
}
else if(this->smArray[p].col<b.smArray[t].col)
{
c.smArray[k].row=this->smArray[p].row;
c.smArray[k].col=this->smArray[p].col;
c.smArray[k].value=this->smArray[p].value;
k++;p++;
}
else
{
c.smArray[k].row=b.smArray[t].row;
c.smArray[k].col=b.smArray[t].col;
c.smArray[k].value=b.smArray[t].value;
k++;t++;
}
}
else if(this->smArray[p].row<b.smArray[t].row)
{
c.smArray[k].row=this->smArray[p].row;
c.smArray[k].col=this->smArray[p].col;
c.smArray[k].value=this->smArray[p].value;
k++;p++;
}
else
{
c.smArray[k].row=b.smArray[t].row;
c.smArray[k].col=b.smArray[t].col;
c.smArray[k].value=b.smArray[t].value;
k++;t++;
}
}
while(p<this->Terms)
{
c.smArray[k].row=this->smArray[p].row;
c.smArray[k].col=this->smArray[p].col;
c.smArray[k].value=this->smArray[p].value;
k++;p++;
}
while(t<b.Terms)
{
c.smArray[k].row=b.smArray[t].row;
c.smArray[k].col=b.smArray[t].col;
c.smArray[k].value=b.smArray[t].value;
k++;t++;
}
c.Rows=b.Rows;
c.Cols=b.Cols;
c.Terms=k;
return true;
}
void SparseMatrix::print()
{
int p=Terms;
for(int i=0;i<p;i++)
cout<<"smArray["<<smArray[i].row<<"]["<<smArray[i].col<<"]= "<<smArray[i].value<<endl;
cout<<endl;
}
测试函数"main.cpp"
#include"dingyi.h"
#include<iostream.h>
int main()
{
SparseMatrix sm,T,F;
sm.InitMatrix();
cout<<"矩阵sm 为:"<<endl;
sm.print();
T=sm.Transpose2();
//T=sm.Transpose1();
cout<<"矩阵sm的转置为: "<<endl;
T.print();
SparseMatrix M;
M.InitMatrix();
cout<<"矩阵M为:"<<endl;
M.print();
if(sm.Multiply(M,F))
{
cout<<"矩阵M与矩阵sm 相乘为:"<<endl;
F.print();
}
SparseMatrix N,P;
N.InitMatrix();
if(sm.Add(N,P))
{
cout<<"矩阵sm和N相加的矩阵为:"<<endl;
P.print();
}
return 0;
}