マトリックス-C++

線形テーブルの 2 次元表現である行列。2 次元配列を使用して行列を表すことができ、疎行列や準対角行列などの広く使用されている特殊な形式の行列を圧縮して保存できます。

対称行列と三角行列

行と列の数が同じ場合、行列は正方形であると言われます。正方行列には、対称行列と三角行列という 2 つの特別なタイプがあります。対称行列には繰り返し要素が多数あるため、スペースを節約するために対称行列の非繰り返し部分を予約できます。このように、行列の要素情報の一部だけを保持し、元の行列に戻すことができる表現方法を行列の圧縮保存といいます。

対称行列の圧縮保存方法は、行列の下三角要素のみを保持することです。三角行列の圧縮削減は、対称行列の圧縮削減と同様です。

//矩阵的类型定义
constexpr auto M = 100; //矩阵行数的上限
constexpr auto N = 100; //矩阵列数的上限
typedef int datatype;
struct matrix {
	datatype a[M][N];
	int row; //矩阵的行数
	int col; //矩阵的列数
	matrix(int r = 0, int c = 0) :row(r), col(c) {
		memset(a, 0, sizeof(a));
	}
	matrix(datatype b[M][N], int r, int c) :row(r), col(c) { //用数组b初始化当前矩阵
		for (int i = 0; i < r; i++)
			for (int j = 0; j < c; j++)
				a[i][j] = b[i][j];
	}
};

//两个矩阵相乘,mat1*mat2,相乘结果作为返回值
matrix mat(matrix mat1, matrix mat2) {
	if (mat1.col != mat2.col) {
		cout << "矩阵不能相乘!" << endl;
		return NULL;
	}
	matrix mat(mat1.row, mat2.col); //mat的行数和列数分别mat1的行数和mat2的列数
	for (int i = 0; i < mat1.row; i++) {
		for (int j = 0; j < mat1.col; j++) {
			mat.a[i][j] = 0;
			for (int k = 0; k < mat1.col; k++) {
				mat.a[i][j] += mat1.a[i][k] * mat2.a[k][j];
			}
		}
	}
	return mat;
}

//特殊矩阵的表示与操作
//对称矩阵的压缩和还原

//将对称矩阵mat压缩为一维向量,结果作为返回值
vector<int> convert(matrix mat) {
	vector<int>ret;
	for (int i = 0; i < mat.row; i++) {
		for (int j = 0; j <= i; j++) {
			ret.push_back(mat.a[i][j]);
		}
	}
	return ret;
}

//将压缩的对称矩阵ve还原成二维表示方法,结果作为返回值
matrix convert(vector<int>ve) {
	matrix mat;
	int i = 0,j = 0;
	for (int k = 0; k < ve.size(); k++) {
		j = k - i * (i + 1) / 2; //数学计算,判断列数
		mat.a[i][j] = mat.a[j][i] = ve[k];
		if (i * (i + 2) / 2 < k) i++; //判断是否进入下一行
	}
	mat.row = mat.col = i;
	return mat;
}

スパース行列

行列内の非ゼロ要素の数と行列要素の総数の比率は行列の密度と呼ばれます。つまり、m*n 行列に t 個の非ゼロ要素がある場合、その密度は行列の密度と呼ばれます。行列はy=t/(mn)です。y が特定のしきい値 (0.05 など) より小さく、非ゼロ要素の分布が不規則な場合、行列は疎行列と呼ばれ、それ以外の場合は密行列呼ばれます

記憶領域を節約するために、スパース行列を保存するときに、ゼロ以外の要素のみを保存する圧縮保存方法を使用できます。圧縮して保存された行列を元の行列に復元するには、非ゼロ要素を保存するときに、要素の値だけでなく、その位置、つまり各非ゼロ要素の保存情報も保存する必要があります。トリプレット (i、j、aij) である必要があります。i と j はそれぞれ要素 aij の行と列の位置です。

通常、圧縮されたスパース行列の要素数は元の行列の要素数よりもはるかに小さいため、圧縮係数行列の演算効率は元の行列よりも高くなります。以下では、圧縮されたスパース行列に対する転置演算を説明する例として取り上げます。

行列の転置演算は実際には行列の全要素の行番号と列番号を呼び出すことになるので、圧縮された疎行列 sm の場合は、各要素の行番号と列番号を入れ替えるだけで済みます。 sm.nz、ただし交換 sm.nz の要素の並べ替えは、最初に行、置換後の列という要件を満たしていません。最も簡単な解決策は、sm.nz を並べ替えること、つまり、構造内ですでに定義されている並べ替え規則に従って並べ替えることです。 smNode、STL でアルゴリズムを呼び出すだけです。ソートするだけです。

//矩阵的类型定义
constexpr auto M = 100; //矩阵行数的上限
constexpr auto N = 100; //矩阵列数的上限
typedef int datatype;
struct matrix {
	datatype a[M][N];
	int row; //矩阵的行数
	int col; //矩阵的列数
	matrix(int r = 0, int c = 0) :row(r), col(c) {
		memset(a, 0, sizeof(a));
	}
	matrix(datatype b[M][N], int r, int c) :row(r), col(c) { //用数组b初始化当前矩阵
		for (int i = 0; i < r; i++)
			for (int j = 0; j < c; j++)
				a[i][j] = b[i][j];
	}
};

//两个矩阵相乘,mat1*mat2,相乘结果作为返回值
matrix mat(matrix mat1, matrix mat2) {
	if (mat1.col != mat2.col) {
		cout << "矩阵不能相乘!" << endl;
		return NULL;
	}
	matrix mat(mat1.row, mat2.col); //mat的行数和列数分别mat1的行数和mat2的列数
	for (int i = 0; i < mat1.row; i++) {
		for (int j = 0; j < mat1.col; j++) {
			mat.a[i][j] = 0;
			for (int k = 0; k < mat1.col; k++) {
				mat.a[i][j] += mat1.a[i][k] * mat2.a[k][j];
			}
		}
	}
	return mat;
}


//稀疏矩阵压缩存储的类型定义
struct smNode
{
	int r, c;  //非零元素所在的行号和列号
	datatype data; //非零元素的值
	bool operator<(smNode sm)const { //排序规则:行先列后,从小到大依次排列。
		if (r == sm.r) return c < sm.c;
		return r < sm.r;
	}
};

struct sMatrix {
	smNode nz[N]; //存放所有非零元素
	int n, row, col; //n:非零元素的数量;row:原矩阵的行数;col:原矩阵的列数
	sMatrix() :n(0), row(0), col(0) {
	}
};

//稀疏矩阵的压缩与还原
//将稀疏矩阵mat压缩存储,结果作为返回值
sMatrix sm_convert(matrix mat) {
	sMatrix sm;
	sm.row = mat.row = mat.col;
	for (int i = 0; i < mat.row; i++) {
		for (int j = 0; j < mat.col; j++) {
			if (mat.a[i][j] != 0) { //非零元素加入结果
				int& idx = sm.n; //idx为引用类型
				sm.nz[idx++] = { i,j,mat.a[i][j] };
			}
		}
	}
}

//将压缩存储的稀疏矩阵sm还原为原矩阵
matrix sm_convert(sMatrix sm) {
	matrix mat(sm.row, sm.col);
	for (int i = 0; i < sm.n; i++) {
		smNode tmp = sm.nz[i]; //第i个非零元素
		mat.a[tmp.r][tmp.c] = tmp.data;
	}
	return mat;
}

//压缩稀疏矩阵的转置
//求压缩稀疏矩阵的转置,结果也为压缩稀疏矩阵并作为返回值
sMatrix sm_tr(sMatrix sm) {
	sMatrix ret;
	ret.row = sm.col, ret.col = sm.row, ret.n = sm.n;//转置后的函数和列数与原矩阵交换,非零元素的数量不变
	for (int i = 0; i < sm.n; i++) { //考虑每一个非零元素
		smNode tmp = sm.nz[i];
		ret.nz[i] = { tmp.c,tmp.r,tmp.data }; //颠换行列
	}
	sort(ret.nz, ret.nz + ret.n); //将元素按指定的顺序排列
	return ret;
}

おすすめ

転載: blog.csdn.net/qq_62687015/article/details/128588675