稀疏矩阵的顺序存储及基本操作

存储结构

typedef struct {
	int i, j;//存储元素下标
	ElemType v;
}Triple;
typedef struct {
	Triple data[MAXSIZE+1];//data[0]闲置;
	int mu, nu, tu;//矩阵行数,列数以及非零元素个数;
	int rpos[MAXSIZE];//记录每行非零元素存储位置;
}RLSMatrix;

基本操作

初始化矩阵

Status InitMatrix(RLSMatrix& M) {//创建三元表
	//输入数据
	for (int i = 0;i < MAXSIZE + 2;i++) {
		M.data[i].v = 0;
	}
	cout << "请输入稀疏矩阵的行数、列数以及非零元个数"<<endl;
	cin >> M.mu >> M.nu >> M.tu;cout ;
	cout << "请按行序输入" << M.tu << "个元素所在行、列以及元素值;" << endl;
	for (int col = 1;col < M.tu + 1;col++) {
		cin >> M.data[col].i >> M.data[col].j >> M.data[col].v;
	}
	//求rpos[]值
	int num[MAXSIZE];
	for (int col = 0;col < MAXSIZE;col++) num[col] = 0;
	for (int row = 1;row < M.tu + 1;row++) num[M.data[row].i]++;//求每行非零元素个数;
	M.rpos[1] = 1;
	for (int roc = 2;roc < M.mu +1;roc++) M.rpos[roc] = M.rpos[roc - 1] + num[roc - 1];
	if (num[M.mu] == 0) M.rpos[M.mu] = NULL;//这里是判断最后一个rpos值是否正常;
	                                        //当最后一行全是零元素,按照递推公式,最后一行有rpos值,实际上没有;
	return OK;
}

输出矩阵

Status Check(RLSMatrix M, int a, int b) {//检查是否非零元素
	for (int k = 1;k < M.tu + 1;k++) {
		if (M.data[k].i == a && M.data[k].j == b)
			return k;
	}
	return 0;
}

Status PrintMatrix(RLSMatrix M) {//打印稀疏矩阵
	int t = 0;
	for (int a = 1;a < M.mu + 1;a++) {
		for (int b = 1;b < M.nu + 1;b++) {
			if(t=Check(M,a,b)) 
				cout << M.data[t].v; 
			else cout << "0";
			cout << "   ";
		}//for b
		cout << endl;
	}//for a
	return OK;
}

矩阵转置

  1. 将矩阵行列值交换
  2. 将每个三元组下标交换
  3. 重排三元组之间次序

转置矩阵1

  • 按照N中三元组次序在M中找到相应的三元组进行转置;
  • 在M中找N的每一行,而M按行序存储,所以只要在M中找到对应行的列就是N的行;
  • 时间复杂度为O(nutu),适用于tu<<munu.
Status TransposeMatrix1(RLSMatrix M, RLSMatrix& N) {//转置矩阵方法1
	N.mu = M.nu;N.nu = M.mu;N.tu = M.tu;
	int q = 1;
	for (int a = 1;a < M.nu + 1;a++) {//在M中找N的每一行,而M按行序存储,所以只要在M中找到对应行的列就是N的行;
		for (int b = 1;b < M.tu + 1;b++) {//搜索M中的每一个元素,检查它的列下标是否满足条件;
			if (M.data[b].j == a) {
				N.data[q].i = M.data[b].j;
				N.data[q].j = M.data[b].i;
				N.data[q].v = M.data[b].v;
				q++;
			}
		}//for b
	}//for a
	return OK;
}

转置矩阵2

  • 按照M中三元组次序进行转置,并将转置后的三元组存入N中的恰当位置
  • 时间复杂度为O(mu*nu)
Status TransposeMatrix2(RLSMatrix M, RLSMatrix& N) {//矩阵转置方法二
	N.mu = M.nu;N.nu = M.mu;N.tu = M.tu;
	//求每列第一个非零元素在N.data中的位置;因为M按行序存储,把M按照列序存储在N中,就相当于转置后的M按行序存储
	int num2[MAXSIZE];//用于存储每列非零元素个数
	for (int col = 0;col <  MAXSIZE;col++) num2[col] = 0;//这里要记得初始化,应为下面直接开始运算。先赋值,再运算;
	for (int col = 1;col < M.tu + 1;col++) num2[M.data[col].j]++;
	int rpos1[MAXSIZE];//用于存储每列第一个非零元素在N.data中的位置;
	rpos1[1] = 1; //这里同理,先赋值再运算!下面运算会用到,而显然易知,第一行第一个非零元素存储在数组第一位;
	for (int row = 2;row < M.nu+1;row++) rpos1[row] = rpos1[row - 1] + num2[row - 1];//一定要注意,这里row从2开始
	//转置
	for (int col = 1;col < M.tu + 1;col++) {
		int q,p;
		q = M.data[col].j;p = rpos1[q];
		N.data[p].i = M.data[col].j;N.data[p].j = M.data[col].i;
		N.data[p].v = M.data[col].v;
		rpos1[q]++;//这里很关键,这就是求出了该列第二个非零元素在N.data中的位置;
	}
	return OK;
}

矩阵乘法

假设矩阵M*N=Q 如下

那么得到的矩阵Q有三行三列,第一行中的元素有这样的关系
在这里插入图片描述
所以我们可以这样,在遍历到M1行时,由于N11,N12,N13是在顺序表中连续排列的,所以我们可以创建一个3个累加器(int QElem[4]={0}),

  1. 遍历到M11时,先算Q11,Q12,Q13的第一项,累加到累加器中即
    在这里插入图片描述
  2. 然后遍历到M12时计算第二项,累加到累加器中即
    在这里插入图片描述
  3. 接着遍历到M13时计算第三项,累加到累加器中即
    在这里插入图片描述
    如此,Q的第一行我们就计算出来了。后面的第二、第三等等行同理。
    这样算,免除了无意义的零元素的相乘,提高了算法的效率;

原思路分析链接

Status MultSMatrix(RLSMatrix M, RLSMatrix N, RLSMatrix& Q) {//矩阵乘法
	Q.mu = M.mu;Q.nu = N.nu;Q.tu = 0;
	int tp,cp,a=1;
	int temp[MAXSIZE];//记录Q各行数据的累加器
	//处理Q的每一行
	for (int col = 1;col < M.mu + 1;col++) {
		for (int e = 0;e < MAXSIZE;e++) {
			temp[e] = 0;
		}
		if (col < M.mu) tp = M.rpos[col + 1];//这里的判断非常重要,是考虑矩阵最后一行为零元素行;
		else {                               //如果最后一行为零元素行,tp值应该为零;
			if (M.rpos[col] == 0)            //不将tp归零,后面继续计算会将Q最后一行的元素更改;也有可能发生内存访问权限冲突;
				tp = 0;
			else tp = M.tu+1; 
		}
		//处理当前行的每一个非零元素
		for (int row = M.rpos[col];row < tp ;row++) {
			int brow = M.data[row].j;
			if (brow < N.mu) cp = N.rpos[brow + 1];
			else {
				if (N.rpos[brow] == 0)
					cp = 0;
				else cp = N.tu + 1;
			}
			//对当前每个元素在N中找到相应的元素相乘
			for (int p = N.rpos[brow];p < cp ;p++) {
				int cool = N.data[p].j;
				temp[cool] += M.data[row].v * N.data[p].v;
			}
		}
		//将求的Q的当前行存入Q.data中
		for (int n = 1;n < N.nu+1;n++) {
			if (temp[n]) {
				Q.tu++;
				Q.data[Q.tu] = { col,n,temp[n] };
			}
		}
	}
	return OK;
}

矩阵加法

Status AddMatrix(RLSMatrix M, RLSMatrix N, RLSMatrix& Q) {//矩阵加法
	Q.mu = M.mu;Q.nu = M.nu;Q.tu = 1;
	int temp[MAXSIZE];
	int t;
	for (int col = 1;col < Q.mu + 1;col++) {
		for (int j = 0;j < MAXSIZE;j++) temp[j] = 0;
		for (int row = 1;row < Q.nu + 1;row++) {
			if (t = Check(M, col, row)) {
				if (t = Check(N, col, row)) {
					temp[row] = M.data[t].v + N.data[t].v;
				}
				else temp[row] = M.data[t].v;
			}
			else {
				if (t = Check(N, col, row)) {
					temp[row] = N.data[t].v;
				}
				else temp[row] = 0;
			}
		}
		for (int i = 1;i < Q.nu + 1;i++) {
			if (temp[i]) {
				Q.data[Q.tu].v = temp[i];
				Q.data[Q.tu].i = col;
				Q.data[Q.tu].j = i;
			}
			Q.tu++;
		}
	}
	return OK;
}

完整代码地址:https://github.com/jaziel126/text2.git

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值