稀疏矩阵:一个m*n的矩阵,如果大多数元素都是0,则称为稀疏矩阵,一般规定稀疏矩阵的非0元素个数要小于n^2/3,有时还有小于n^2/5.
下面来实现一个稀疏矩阵的实例:
稀疏矩阵实现的思想是把无规则稀疏矩阵的非0元素映射到一个线性表中。为了重建矩阵结构,必须记录每个非0元素的行号和列号,因此数组元素需要三个域:row,col和value。为此定义结构maxtrixTerm。
template<class T>
struct matrixTerm
{
int row;
int col;
T value;
};
下面仅写类matrixTerm的部分定义:
template<class T>
class sparseMatrix
{
public:
void transpose(sparseMatrix<T> &b);
void add(sparseMatrix<T> &b,sparseMatrix<T>& c);
private:
int rows,cols;
arrayList<matrixTerm<T>> terms;
}
template<class T>
ostream& operator<<(ostream& out,sparseMatrix<T>& x)
{
out<<"rows="<<x.rows<<"columns="<<x.cols<<endl;
out<<"nonozero terms="<<x.terms.size()<<endl;
for(arrayList<matrixTerm<T>>::iterator i=x.terms.begin();
i!=x.terms.end();i++)
out<<"a("<<(*i).row<<','<<(*i).col<<")="<<(*i).value<<endl;
return out;
}
以上是输出函数,是个友元函数,但我并没有在里面进行声明,因为懒。
template<class T>
istream& operator>>(istream& in,sparseMatrix<T>& x)
{
int numberOfTerms;
cout<<"Enter number of rows,columns,and #terms"<<endl;
in>>x.rows>>x.cols>>numberOfTerms;
if(x.rows<1||x.cols<1||numberOfTerms<x.rows*x.cols)
throw illegalParameter();
x.terms.reSet(numberOfTerms);
matrixTerm<T>mTerm;
for(int i=0;i<numberOfTerms;i++)
{
cout<<"Enter row.columns,and value of term"<<(i+1)<<endl;
in>>mTerm.row>>mTerm.col>>merm.value;
if(x.rows<1||x.cols<1)
throw illegalParameter();
x.terms.set(i,mTerm);
}
return in;
}
输入采取的是行主模式输入,即先输入第一行,再输入第二行,再输入第三行……。
template<class T>
void sparseMatrix<T>::transpose(sparseMatrix<T> &b)
{
b.cols=rows;
b.rows=cols;
b.terms.reSet(terms.size());
int* colSize=new int[cols+1];
int* rowNext=new int[cols+1];
for (int i=1;i<=cols;i++)]
colSize[i]=0;
for(arrayList<matrixTerm<T>>::iterator i=term.begin();
i!=terms.end();i++)
colSize[(*i).col]++;//colSize用来记录原矩阵每列的非零个数,比如colSize[i]代表i列的非零元素个数
rowNext[1]=0;//转置矩阵第一行非零元素出现在b中第一个位子。其实第一行并没有非零元素,我们将其设置为0并不影响。
for(int i=2;i<=cols;i++)//转置矩阵中第一行的第一个非零元素一定在b中第一个。
rowNext[i]=rowNext[i-1]+colSize[i-1];//转置矩阵第二行的第一个非零元素在b中的位置
//等于第一行的第一个非零元素加上第一行
//的非零元素个数。
matrixTerm<T> mTerm;
for (arrayList<matrixTerm<T>>::iterator i=terms.begin();
i!=terms.end();i++)
{
int j=rowNext[(*i).col]++; //b中的位置,第一个col将出现在行中的首元素,注意这是后++,下一个同列将出现在它后面。
mTerm.row=rowNext[(*i).col]++;
mTerm.col=(*i).row;
mTerm.value=(*i).value;
b.terms.set(j,mTerm);
}
}
rowNext[i]里面装的是转置矩阵第i行首个非零元素在b数组里面的位置。
template<class T>
void sparseMatrix<T>::add(sparseMatrix<T> &b,sparseMatrix<T> &c)
{
if(rows!=b.rows||cols!=b.cols)
throw matrixSizeMismatch();
c.rows=rows;
c.cols=cols;
c.terms.clear;
int cSize=0;
arrayList<matrixTerm<T>>::iterator it=terms.begin();
arrayList<matrixTerm<T>>::iterator ib=b.terms.begin();
arrayList<matrixTerm<T>>::iterator itEnd=terms.end();
arrayList<matrixTerm<T>>::iterator ibEnd=b.terms.end();
while(it!=itEnd&&ib!=ibEnd)
{
int tIndex=(*it).row*cols+(*it).col;//列数乘以当前行数+当且列数等于当前位置,通过这个进行比较再适合不过了。
int bIndex=(*ib).row*cols+(*ib).col;
if(tIndex<bIndex)
{
c.terms.insert(cSize++,*it);
it++;
}
else
{
if(tIndex==bIndex)
{
if((*it).value+(*ib).value!=0)
{
matrixTerm<T>mTerm;
mTerm.row=(*it).row;
mTerm.col=(*it).col;
mTerm.value=(*it).value+(*ib).value;
c.terms.insert(cSize++,mTerm);
}
it++;
ib++;
}
else
{
c.terms.insert(cSize++,*ib);
ib++
}
}
}
for(;it!=itEnd;ib++)
c.terms.insert(cSize++,*it);
for(;ib!=ibEnd;ib++)
c.terms.insert(cSize++,*ib);
}
从头开始循环,只有当两个元素的位置相同时才进行相加,否则将在前的那个元素直接放到c数组里面,然后将其迭代器加一,再次进行比较。