1. Введение
\
Пусть матрица 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[n]=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]的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="<<endl;
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;
}
\
результат операции:
\
\
\