矩阵的压缩存储

一、矩阵的分类

1、特殊矩阵:其矩阵值在在矩阵中分布有规律

2、稀疏矩阵:矩阵的非零值在矩阵中占比小于0.05的矩阵,即零值占比在95%以上

3、一般矩阵:不属于上面的两种矩阵

快速求解大稀疏矩阵的零空间 python 大型稀疏矩阵分类_转置

二、矩阵的存储方式

1、特殊矩阵的存储方式

1、特殊矩阵包括三角矩阵,带状矩阵 都是使用顺序存储

快速求解大稀疏矩阵的零空间 python 大型稀疏矩阵分类_转置_02

2、稀疏矩阵的存储方式

稀疏矩阵的存储方式有两种,其一:三元组顺序表(顺序存储)其二:十字链表(链式存储)

1、稀疏矩阵的三元组顺序表存储

快速求解大稀疏矩阵的零空间 python 大型稀疏矩阵分类_三元组_03

3矩阵的转置

1、一般矩阵转置

快速求解大稀疏矩阵的零空间 python 大型稀疏矩阵分类_三元组_04

2、 稀疏矩阵的一般转置

快速求解大稀疏矩阵的零空间 python 大型稀疏矩阵分类_c语言_05

3、稀疏矩阵的快速排序

假如我们直接知道转置前的三元组数组的每个元素在转置后的三元组数组中位置,我们就可以直接转了

要想知道转置后的位置,我们必须要总结转置前的三元组数组的更详细信息。

由于转置后行列互换,所以转置后的三元组数组是按照行顺序记录的,所以我们要知道转置前矩阵的每列元素个数mun(j),另外我们还需要知道转置前的矩阵的每一列元素的第一个非0元素在转置后的三元组数组中的位置Pos(j)

那么我们就可以根据mun(j)和Pos(j)来确定转置前的三元组数组的每个元素在转置后的三元组数组中位置

快速求解大稀疏矩阵的零空间 python 大型稀疏矩阵分类_三元组_06

计算方法

快速求解大稀疏矩阵的零空间 python 大型稀疏矩阵分类_稀疏矩阵_07

代码

//稀疏矩阵的三元组顺序表存储表示.cpp 

#include<malloc.h> // malloc()等
#include<stdio.h> // EOF(=^Z或F6),NULL
#include<stdlib.h> // atoi()
// 函数结果状态代码
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1

// #define OVERFLOW -2 因为在math.h中已定义OVERFLOW的值为3,故去掉此行
typedef int Status; // Status是函数的类型,其值是函数结果状态代码,如OK等
typedef int Boolean; // Boolean是布尔类型,其值是TRUE或FALSE
typedef int ElemType;

#define MAX_SIZE 100 // 非零元个数的最大值
struct Triple 
{
	int i, j; // 行下标,列下标
	ElemType e; // 非零元素值
};
struct TSMatrix
{
	Triple data[MAX_SIZE + 1]; // 非零元三元组表,data[0]未用
	int mu, nu, tu; // 矩阵的行数、列数和非零元个数
};

// 1、创建稀疏矩阵M
Status CreateSMatrix(TSMatrix &M);
// 2、输出稀疏矩阵M
void PrintSMatrix(TSMatrix M);
//3、输出完整的矩阵
void display(TSMatrix M);
//4、输出完整的矩阵
void PrintSMatrix1(TSMatrix M);
//5、复制矩阵T = M
void CopySMatrix(TSMatrix M, TSMatrix &T);
//6、求稀疏矩阵的和Q=M+N
Status AddSMatrix(TSMatrix M, TSMatrix N, TSMatrix &Q);
//7、求稀疏矩阵的差Q=M-N
Status SubtSMatrix(TSMatrix M, TSMatrix N, TSMatrix &Q);
//8、 求稀疏矩阵M的转置矩阵T,普通方法
void TransposeSMatrix(TSMatrix M, TSMatrix &T);

int main() {	
	TSMatrix M;
	CreateSMatrix(M);
	PrintSMatrix(M);
	display(M);
}


//1、创建稀疏矩阵M
Status CreateSMatrix(TSMatrix &M)
{ 
	int i, m, n;
	ElemType e;
	Status k;
	printf("请输入矩阵的行数,列数,非零元素数:");
	scanf_s("%d, %d, %d", &M.mu, &M.nu, &M.tu);
	if (M.tu > MAX_SIZE)
		return ERROR;
	M.data[0].i = 0; // 为以下比较顺序做准备
	for (i = 1; i <= M.tu; i++)
	{
		do
		{
			printf("请按行序顺序输入第%d个非零元素所在的行(1~%d),列(1~%d),元素值:", i, M.mu, M.nu);
			scanf_s("%d,%d,%d", &m, &n, &e);
			k = 0;
			if (m<1 || m>M.mu || n<1 || n>M.nu) // 行或列超出范围
				k = 1;
			if (m < M.data[i - 1].i || m == M.data[i - 1].i&&n <= M.data[i - 1].j) // 行或列的顺序有错,M.data[i - 1].i当前输入数据的前一个数据的行坐标 M.data[i - 1].j当前输入数据的前一个数据的列坐标
				k = 1;
		} while (k);//输入值的行列不按顺序输入则重新输入
		M.data[i].i = m;
		M.data[i].j = n;
		M.data[i].e = e;
	}
	return OK;
}
//2、输出稀疏矩阵M的非0值
void PrintSMatrix(TSMatrix M)
{ 
	int i;
	printf("%d行%d列%d个非零元素。\n", M.mu, M.nu, M.tu);
	printf("行  列  元素值\n");
	for (i = 1; i <= M.tu; i++)//按顺序输出数组中的值
		printf("%2d%4d%8d\n", M.data[i].i, M.data[i].j, M.data[i].e);
}
//3、输出完整的矩阵
void display(TSMatrix M) 
{
	for (int i = 1; i <= M.mu; i++) {//循环行
		for (int j = 1; j <= M.nu; j++) {//循环列
			int value = 0;//标志变量
			for (int k = 0; k <= M.tu; k++) {//循环非0值
				if (i == M.data[k].i && j == M.data[k].j) {//行和列等于非0值的行和列时打印非0值不等则打印0值
					printf("%d ", M.data[k].e);
					value = 1;
					break;
				}
			}
			if (value == 0)
				printf("0 ");
		}
		printf("\n");
	}
}
//4、输出完整的矩阵
void PrintSMatrix1(TSMatrix M)
{ // 按矩阵形式输出M
	int i, j, k = 1;
	Triple *p = M.data;
	p++; // p指向第1个非零元素
	for (i = 1; i <= M.mu; i++)//循环行
	{
		for (j = 1; j <= M.nu; j++)//循环列
			if (k <= M.tu&&p->i == i && p->j == j) // p指向非零元,且p所指元素为当前处理元素
			{
				printf("%3d", p->e); // 输出p所指元素的值
				p++; // p指向下一个元素
				k++; // 计数器+1
			}
			else // p所指元素不是当前处理元素
				printf("%3d", 0); // 输出0
		printf("\n");
	}
}
//5、复制矩阵T = M
void CopySMatrix(TSMatrix M, TSMatrix &T)
{ // 由稀疏矩阵M复制得到T
	T = M;
}


int comp(int c1, int c2)
{ // AddSMatrix函数要用到,另加
	if (c1 < c2)
		return -1;
	if (c1 == c2)
		return 0;
	return 1;
}
//6、求稀疏矩阵的和Q=M+N
Status AddSMatrix(TSMatrix M, TSMatrix N, TSMatrix &Q)
{  
	int m = 1, n = 1, q = 0;
	if (M.mu != N.mu || M.nu != N.nu) // M、N两稀疏矩阵行或列数不同
		return ERROR;
	Q.mu = M.mu;
	Q.nu = M.nu;
	while (m <= M.tu&&n <= N.tu) // 矩阵M和N的元素都没处理完
	{
		switch (comp(M.data[m].i, N.data[n].i))
		{
		case -1: Q.data[++q] = M.data[m++]; // 将矩阵M的当前元素值赋给矩阵Q
			break;
		case  0: switch (comp(M.data[m].j, N.data[n].j)) // M、N矩阵当前元素的行相等,继续比较列
		{
		case -1: Q.data[++q] = M.data[m++];
			break;
		case  0: Q.data[++q] = M.data[m++]; // M、N矩阵当前非零元素的行列均相等
			Q.data[q].e += N.data[n++].e; // 矩阵M、N的当前元素值求和并赋给矩阵Q
			if (Q.data[q].e == 0) // 元素值为0,不存入压缩矩阵
				q--;
			break;
		case  1: Q.data[++q] = N.data[n++];
		}
				 break;
		case  1: Q.data[++q] = N.data[n++]; // 将矩阵N的当前元素值赋给矩阵Q
		}
	}
	while (m <= M.tu) // 矩阵N的元素全部处理完毕
		Q.data[++q] = M.data[m++];
	while (n <= N.tu) // 矩阵M的元素全部处理完毕
		Q.data[++q] = N.data[n++];
	Q.tu = q; // 矩阵Q的非零元素个数
	if (q > MAX_SIZE) // 非零元素个数太多
		return ERROR;
	return OK;
}
//7、求稀疏矩阵的差Q=M-N
Status SubtSMatrix(TSMatrix M, TSMatrix N, TSMatrix &Q)
{ 
	int i;
	for (i = 1; i <= N.tu; i++)
		N.data[i].e *= -1;
	return AddSMatrix(M, N, Q);
}
//8、 求稀疏矩阵M的转置矩阵T,普通方法
void TransposeSMatrix(TSMatrix M, TSMatrix &T)
{ 
	int p, q, col;
	T.mu = M.nu;
	T.nu = M.mu;
	T.tu = M.tu;
	if (T.tu)
	{
		q = 1;
		for (col = 1; col <= M.nu; ++col)//依次给出列标1-M.nu
			for (p = 1; p <= M.tu; ++p)//循环非0元素
				if (M.data[p].j == col)//如果M的第p个三元组的列元素和循环的列标相等,则转置非零元素
				{
					T.data[q].i = M.data[p].j;
					T.data[q].j = M.data[p].i;
					T.data[q].e = M.data[p].e;
					++q;//计数器+1
				}
	}
}