Реализация шаблона класса C++ разреженной матрицы Triplet Packed Storage

глубокое обучение

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;
}


\

результат операции:

\

\

\