数据结构(C/C++)课程阶段总结(九)

写在前面

课程采用教材《数据结构(C语言版)》严蔚敏,吴伟民,清华大学出版社。
本系列博文用于自我学习总结和期末复习使用,同时也希望能够帮助到有需要的同学。如果有知识性的错误,麻烦评论指出。
本次实验实现稀疏矩阵的加法运算。
至此,数据结构课程的学习也告一段落,因为专业的原因,与科班的课程相比,做了不少简化,主要是面对测绘专业的学习。相关的课程资源,以及程序源文件都放在链接资源中了,需者自取。
相关资源

基本操作的实现方法

仍然采用头文件TSMatrixH.h,具体构造方法不再赘述。
目标:求取矩阵M和T的加和结果N。
具体过程:
基本的想法是,按照行主序,求M和T的元素在矩阵中的先后顺序,在前先插到N表尾,位置相同时,先求和,若和非零,插入到N表尾。最后将剩余的元素插入到N表尾。
具体编程实现时,需要用到二维数组的映像函数,以行主序计算M和T表当前位置的元素在矩阵中相对LOC(0,0)的位置。计算公式为:off=col×i+j。再定义三个表循环位置,初始位置均为0。然后开始遍历M和T表,此次遍历完全遍历了表尾元素在矩阵中位置靠前的表,另一表要么也遍历完全,要么还有剩余。在遍历中,判断两表当前位置元素在矩阵中的位置前后关系。如果,位置相同,则两表当前位置元素做加和运算,若和非零,则插入到N表尾,三表的位置后移一位,N表长加1;若为零,则对N表不操作,M和T表位置后移一位。如果,某一表位置在前,则先插入该表当前位置的元素,该表和N表位置后移一位,N表长加1。最后,将剩余的元素逐个插入到N表尾。

具体实现

//1、用到的头文件、命名空间和函数执行结果状态代码
#include <iostream>
#include "TSMatrixH.h"
using namespace std;

//2、基本操作侧函数原型说明及实现
//-----基本操作的函数原型说明-----
Status TSMatrixAdd(TSMatrix M, TSMatrix T, TSMatrix& N);
// 初始条件:采用三元组表存储表示,T,M为同维度稀疏矩阵。
// 操作结果:求M和T的加和矩阵,并用N传出。
Status TSMatrixAdd(TSMatrix M, TSMatrix T, TSMatrix& N) {
	// 求M和T的加和矩阵,并用N传出。
	if (!(M.col == T.col && M.row == T.row)) { cout << "矩阵维度不一致!!\n"; return ERROR; }
	N.col = M.col; N.row = M.row; N.num = 0;// 获取矩阵行列数,非零元个数置零
	int locM = 0, locT = 0, locN = 0;// 三个三元表的位置,初始为0,都从表头开始
	while (locT < T.num && locM < M.num)// 遍历表尾元素在矩阵中位置靠前的表
	{// off为loc位置相对矩阵中LOC(0,0)位置行主序的偏移量
		int offM = M.data[locM].i * M.col + M.data[locM].j;
		int offT = T.data[locT].i * T.col + T.data[locT].j;
		if (offM == offT)// 如果当前两三元组中的元素在矩阵中位于同一位置
		{// 则求两元素的和,存放在e中
			int e = T.data[locT].e + M.data[locM].e;
			if (e)// 如果e非零
			{// 则将该元素插入N表中
				N.data[locN] = T.data[locT];// 获取该元素的行列
				N.data[locN].e = e;// 获取该元素的值
				locN++; locT++; locM++; N.num++;// 三个loc均后移一位,N表长加1
			}
			else// 如果e为0
			{// 则跳过该元素,对N表无操作
				locT++; locM++;// M和T表位置后移一位
			}
		}
		else if (offM < offT)// 如果当前两三元组中的元素在矩阵中M的位置较前
		{// 则先将M表当前位置的三元组插入到N表中
			N.data[locN] = M.data[locM];// 插入到N表尾
			locN++; locM++; N.num++;// N和M表的位置后移一位,N表长加1
		}
		else if (offM > offT)// 如果当前两三元组中的元素在矩阵中T的位置较前
		{// 则先将T表当前位置的三元组插入到N表中
			N.data[locN] = T.data[locT];// 插入到N表尾
			locN++; locT++; N.num++;// N和T表的位置后移一位,N表长加1
		}
	}// 至此,表尾元素在矩阵中位置靠前的表,还需要将剩余的元素插入到N表中
	if (locT < T.num)// 如果T表位置未到表尾
	{// 则T表中有剩余元素
		int surplus = T.num - locT;// 剩余元素个数
		for (N.num; N.num < locN + surplus; N.num++)// 从N的表尾逐个插入T表剩余的元素
			N.data[N.num] = T.data[locT++];
	}
	else if (locM < M.num)
	{
		int surplus = M.num - locM;// 剩余元素个数
		for (N.num; N.num < locN + surplus; N.num++)// 从N的表尾逐个插入M表剩余的元素
			N.data[N.num] = M.data[locM++];
	}
	return OK;
}// TSMatrixAdd

int main()
{
	ElemType* S1[10], * S2[10];
	for (int i = 0; i < 10; i++)// 创建10*12的矩阵,由4个一维数组组成
	{// 申请空间
		S1[i] = new ElemType[12];
		S2[i] = new ElemType[12];
	}
	for (int i = 0; i < 10; i++)
		for (int j = 0; j < 12; j++)
		{// 全部赋0
			*(S1[i] + j) = 0;
			*(S2[i] + j) = 0;
		}
	S1[0][0] = 1;// 在(0,0)位置赋1
	S1[2][2] = 2;// 在(2,2)位置赋2
	S1[2][4] = 3;// 在(2,4)位置赋3
	S1[6][9] = 4;// 在(6,9)位置赋4
	S1[7][7] = -6;// 在(7,7)位置赋-6
	S1[9][11] = 8;// 在(9,11)位置赋8

	S2[0][0] = -1;// 在(0,0)位置赋1
	S2[2][0] = 2;// 在(2,0)位置赋2
	S2[3][4] = 3;// 在(3,4)位置赋3
	S2[2][4] = 4;// 在(2,4)位置赋4
	S2[7][7] = 6;// 在(6,11)位置赋6
	TSMatrix M, T, N;// 创建三元组顺序表
	M.CreateTSMatrix(M, S1, 10, 12);// 用三元组表存储稀疏矩阵
	M.DispTSMat(M);// 输出三元组表
	M.DispSMat(M);// 输出稀疏矩阵
	T.CreateTSMatrix(T, S2, 10, 12);// 用三元组表存储稀疏矩阵
	T.DispTSMat(T);// 输出三元组表
	T.DispSMat(T);// 输出稀疏矩阵

	TSMatrixAdd(M, T, N);// N=M+T
	N.DispTSMat(N);// 输出三元组表
	N.DispSMat(N);// 输出稀疏矩阵
	return 0;
}

运行结果

加法

总结

需要说明的是,为了演示方便,并没有满足稀疏矩阵的要求,但也可近似看做稀疏矩阵。值的一提的一点是,采用了偏移量来确定两表插入的顺序,更加直观,便于理解。避免直接比较行列出现逻辑错误。
简单分析不难发现,该算法的时间复杂度为O(max{M.num,T.num})。第一个遍历,把表尾元素在矩阵中位置靠前的表先遍历完了,不论表是否较长,另一个未完全遍历的表在处理剩余元素时,将未遍历的元素也遍历了一遍,故,循环语句执行次数为两表表长的较大值。
此前采取的方法是,把一表加到另一表上,这必然会引起双重循环语句,增加时间复杂度。因为,将一表的元素插入另一表,或将一表的元素删除,必然会涉及多个元素的移动,需要用循环语句来实现,加上外层遍历用的循环,所以至少需要两层循环。如果这种方法有其他比较好的处理方式,也愿闻其详。
当然,也可以参照快速转置的思想,通过一定的方法,预先获取各元素的位置,或许也是一种可行的方法。对此,我并没有深入研究了,但可以肯定的是,至少会用到多个单层的循环语句。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kFkPkDkN

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值