数据结构课程设计:稀疏矩阵运算器

第一部分:设计目的

1.进一步理解和掌握课堂上所学各种基本抽象数据类型的逻辑结构、存储结构和操作实现算法,以及它们在程序中的使用方法。

2.掌握软件设计的基本内容和设计方法,并培养学生进行规范化软件设计的能力。

3.掌握使用各种计算机资料和有关参考资料,提高学生进行程序设计的基本能力。为学生提供了一个既动手又动脑,独立实践的机会,将课本上的理论知识和实际有机的结合起来,锻炼学生的分析解决实际问题的能力。提高学生适应实际,实践编程的能力。

第二部分:设计准备(包含设备及器材)

1、提前复习C语言相关知识,安装好C语言程序编辑器。

2、画出相应功能的流程图。

3、Dev-C++不仅仅是是一个C++编译器,而是一个基于Windows操作系统的可视化集成开发环境IDE,这种环境开发出来的软件稳定性好、可移植性强,可以编制各种各样的Windows应用程序。

第三部分:设计要求

1、功能要求

基本功能:

(1)稀疏矩阵相乘

(2)稀疏矩阵相加

(3)稀疏矩阵相减

(4)退出稀疏矩阵运算器

(5)对用户输入的矩阵进行判别是否符合矩阵运算的要求。

(6)运算结果的矩阵则以通常的阵列形式列出。

规定:输入的稀疏矩阵的非零元素以三元组的形式输入(即输入非零元素的行标、列标和值),无需输入值为零的元素。

输出形式:有中文提示,清晰易懂。

界面要求:有合理的提示,每个功能可以设立菜单,根据提示,可以完成相关的功能要求。

2、存储结构

非零元素的存储利用了稀疏矩阵表示法,三个整型变量分别存储了稀疏矩阵的行数、列数和非零元素个数,一个一位数组存储稀疏矩阵每一行第一个非零元素在三元组表的起始位置。tupletype是自定义的类型,其用来创建的一维数组用作非零三元组表,其内的两个整型变量分别存储非零元素的行标与下标,以及一个自定义类型ElemType的变量存储非零元素值。

3、测试数据

要求使用:

(1)合法数据;

(2)非法数据。

第四部分:设计内容(步骤及程序)

1.需求分析

(1)系统流程图如下图1所示

图1系统流程图

(2)该系统的六个模块

①先导入系统所需要的库函数,让程序可以正常运行。

# include <stdio.h>

# include <stdlib.h>

# include<math.h>

②定义稀疏矩阵的存储结构,通过在结构体里嵌套一个结构体的方式存储矩阵中的非

零元素,达到节省存储空间的目的。

③创建稀疏矩阵void creatltable(ltable *lt),通过do-while语句让用户输入稀疏矩阵的相关信息,并判断输入的信息是否合法,否则提醒用户重新输入信息。接着通过三个for循环计算出每行首个非零元素在三元组表的位置。

④以行列的形式输出稀疏矩阵void list(ltable *q),主要是通过嵌套for循环一次输出元素,如果不是非零元素则用0代替该矩阵的相应位置输出。

⑤矩阵相乘、相加和相减

void matrimul(ltable *m, ltable *t, ltable *q)//矩阵相乘

void matriadd(ltable *m, ltable *t, ltable *q, ltable *p)//矩阵相加

void matrisub(ltable *m, ltable *t, ltable *q, ltable *p)//矩阵相减

⑥主函数的设计:先让用户以三元组的形式输入两个矩阵,然后在永真while循环里放置菜单,菜单有4个选项:1.矩阵相乘。2.矩阵相加。3.矩阵相减。4.退出稀疏矩阵运算器。通过switch语句决定执行哪个功能。

2.概要设计

(1)系统结构体的设计,如下图2,3所示。

图2 稀疏矩阵流程图

typedef struct

{

int rownum;

int colnum;

int nznum;

int rpos[RC+1];

tupletype data[MAXSIZE];

}ltable;

图3 三元组表流程图

(2)创建稀疏矩阵的流程图如下图4所示

图4 创建稀疏矩阵流程图

先是让用户输入矩阵的行数、列数以及非零元的个数,判断数据是否合理,否则

提醒用户重新输入数据。接着提醒用户按行优先输入三元组并判断数据是否合法,否则提醒用户重新输入。最后计算每一行首个非零元素在三元组表data[]的位置。

(3)按阵列式输出矩阵如下图5

图5 输出矩阵的流程图

通过三重循环依次遍历每一个非零元素的行标和列标,如果该行标和列标存在则

输出该非零元素,不存在则输出0。

(4)矩阵相加减思路大致一致,如下图6所示:

图6 矩阵相加减

(5)矩阵相乘的算法流程图如下图7所示:

图7 矩阵相乘算法流程图

(6)主函数模块的流程图如上图1所示,通过死循环实现让用户多次选择不同的功能,当用户输入了不在范围之内的编号时会提醒用户重新选择功能。

3.详细设计
(1)主函数设计

用函数int main()来实现

主要是用来显示主菜单,让用户选择操作。首先定义4个稀疏矩阵ltable m, t, q, p;然后让用户输入两个稀疏矩阵,在这里应用了do-while和switch-case语句来进行选择加减乘功能,最后若选择“4”则退出程序。

(2)各功能模块设计
①创建稀疏矩阵(输入)模块

用函数void creatltable(ltable *lt)来实现

在do-while语句中让用户输入矩阵的行数、列数与非零元的个数,接着利用if-else if语句对输入的数据进行判断,如果行数或列数小于等于0,则提示用户行数

或列数应该输入正整数并让用户重新输入,如果输入的非零元的个数大于矩阵的最大存储个数,同理提醒用户并重新输入。只有行数、列数和非零元的个数都输入无误后,才会让用户输入三元组,同理也是通过do-while循环判断输入的数据是否合理,如果有误则提醒用户重新输入。

do {

       printf("请输入矩阵的行数、列数以及非零元的个数:");
        scanf("%d %d %d", &r, &c, &n);
		if(r <= 0 || c <= 0)
			printf("行数或列数应为正整数!\n");
		else if(n > r*c)
			printf("非零元的个数大于矩阵的最大存储个数!\n");
	} while(r <= 0 || c <= 0 || n > r*c);
	lt->rownum = r;
	lt->colnum = c;
	lt->nznum = n;
	
	printf("请按行优先输入三元组\n");
	for(k = 1; k <= n; k++)				// 有多少个非零元就有多少个三元组
	{
		do {
			printf("请输入第%d个非零元素的三元组:", k);
			scanf("%d %d %d", &i, &j, &x);
			if(i < 0 || j < 0 || i > r || j > c || x == 0)
				printf("输入的参数有误!请重新输入:\n");
		}while(i < 0 || j < 0 || i > r || j > c || x == 0);
		lt->data[k].i = i;
		lt->data[k].j = j;
		lt->data[k].e = x;
	}

最后计算出每行首个非零元素在三元组表data[]的位置(下标):

先从下标1开始初始化数组,因为下标代表行标。然后统计每一行的非零元素个数,只要lt->data[e].i(行标)一样,那么nonzero[lt->data[e].i]就加1,然后从rpos[1]开始,存放各行首个非零元的位置(上一行首个非零元素的位置+上一行的非零元素个数)

int row, e;

int nonzero[RC+1];

for(row = 1; row <= lt->rownum; ++row)

    nonzero[row] = 0;             // 从下标1开始初始化数组,下标代表行标

for(e = 1; e <= lt->nznum; ++e)

    ++nonzero[lt->data[e].i];  // 统计每一行的非零元素个数,只要lt->data[e].i(行标)一样,那么nonzero[lt->data[e].i]就加1

lt->rpos[1] = 1;  // 第1行的首个非零元素肯定在rpos[1](从下标1开始存放)

for(row = 2; row <= lt->rownum; ++row)

    lt->rpos[row] = lt->rpos[row-1] + nonzero[row-1];    // 每一行首个非零元素在三元组表data[]的位置(下标)=上一行首个非零元素的位置+上一行的非零元素个数

该算法的时间性能最大的是在for循环里嵌套do-while,所以时间复杂度为:T(n)=O(n2);而算法的辅助空间有9个临时变量以及一个与问题规模无关的一维数组空间,共10个,所以空间复杂度为:S(n)=O(1)。

②以常规的阵列形式打印稀疏矩阵模块

用函数void list(ltable *q)来实现

通过三层for循环将矩阵输出。在第一个for循环中依次遍历每一行,第二个for循环遍历每一行的每一个元素,如果该位置的行标和列标在三元组表内没有对应的非零元素值则用0代替,否则输出非零元素值。

for(i = 1; i <= q->rownum; i++)
	{
		for(j = 1; j <= q->colnum; j++)
		{
			e = 0;
			for(k = 1; k <= q->nznum; k++)
				if(i == q->data[k].i && j == q->data[k].j)
				{
					e = q->data[k].e;
					break;
				}
			printf("%4d", e);
		}
		printf("\n");
	}

该算法的三重循环部分语句的执行过程取决于矩阵的行数、列数以及非零元个数,与问题规模n无关,因此该算法的时间复杂度为:T(n)=O(1);算法的辅助空间只有4个临时变量的空间,因此S(n)=O(1)。

③矩阵相加模块设计

用函数void matriadd(ltable *m, ltable *t, ltable *q, ltable *p)来实现

首先将m,t两个矩阵复制给q,p,然后判断m的行数与列数是否与t的行数与列数相等,不相等则提示用户,相等则把m,t的三元组表依次分别赋值给p,q,接着如果p中非零元的行标与列标与q中非零元的行标与列标相等,则把p该位置的非零元加到q该位置的非零元,然后将p该位置的非零元置0,最后把p中的三元组表依次放到q中,如果有0,则跳过,继续添加下一个三元组。

if(m->rownum != t->rownum || m->colnum != t->colnum)
		printf("两个矩阵的行数与列数应对应相等!");
	else
	{
		for(i = 1; i <= t->nznum; i++)
		{
			q->data[i].i = t->data[i].i;
			q->data[i].j = t->data[i].j;
			q->data[i].e = t->data[i].e;
		}
		for(i = 1; i <= m->nznum; i++)
		{
			p->data[i].i = m->data[i].i;
p->data[i].j = m->data[i].j;
			p->data[i].e = m->data[i].e;
		}
		
		for(i = 1; i <= p->nznum; i++)
			for(j = 1; j <= t->nznum; j++)
				if(p->data[i].i == q->data[j].i && p->data[i].j == q->data[j].j)
				{
					q->data[j].e += p->data[i].e;
					p->data[j].e = 0;
				}
		for(i = 1; i <= p->nznum; i++)
			if(p->data[i].e != 0)
			{
				q->data[q->nznum+1].i = p->data[i].i;
				q->data[q->nznum+1].j = p->data[i].j;
				q->data[q->nznum+1].e = p->data[i].e;
				q->nznum++;
			}
		printf("矩阵相加的结果为:\n");
	}

该算法的循环部分取决于非零元的个数,而矩阵的非零元的最大个数是固定的(不大于400),因此该算法的时间复杂度为:T(n)=O(1);算法的辅助空间只有2个临时变量的空间,因此S(n)=O(1)。

④矩阵相减模块设计

用void matrisub(ltable *m, ltable *t, ltable *q, ltable *p)来实现

该模块与矩阵相加模块大同小异,在此只叙述不同的地方。如果p中非零元的行标与列标与q中非零元的行标与列标相等,则在p中,用p该位置的非零元减去q中该位置的非零元并且置0,然后用0减去q中其他的非零元后存放p中。

for(i = 1; i <= p->nznum; i++)
			for(j = 1; j <= q->nznum; j++)
				if(q->data[j].i == p->data[i].i && q->data[j].j == p->data[i].j)
				{
					p->data[i].e -= q->data[j].e;
					q->data[j].e = 0;
				}
	for(i = 1; i <= q->nznum; i++)
		if(q->data[i].e != 0)
		{
			p->data[p->nznum+1].i = q->data[i].i;
			p->data[p->nznum+1].j = q->data[i].j;
			p->data[p->nznum+1].e = 0 - q->data[i].e;
			p->nznum++;
        }
	printf("矩阵相减的结果为:\n");

该算法的循环部分取决于非零元的个数,而矩阵的非零元的最大个数是固定的(不大于400),因此该算法的时间复杂度为:T(n)=O(1);算法的辅助空间只有2个临时变量的空间,因此S(n)=O(1)。

⑤矩阵相乘模块设计

用函数void matrimul(ltable *m, ltable *t, ltable *q)来实现

首先初始化乘积结果矩阵,接着用if-else if语句先判断两个矩阵的非零元个数相乘是否等于0,然后判断第一个矩阵的列数是否与第二个矩阵的行数相等,若不相等则提醒用户,相等则开始处理矩阵相乘。先通过for循环处理m的每一行,将当前各行累加器清零然后判断m的行标是否小于其行数,再对当前行中的每一个非零元找到对应元在t中的行号,接着处理m的每一行的每一个元素,找到乘积元素在q中的列号并进行累加相乘。最后压缩存储该行非零元素。

	else if(m->colnum == t->rownum)
	{
		for(mrow = 1; mrow <= m->rownum; mrow++)		// 处理m的每一行 
		{
			for(k = 1; k <= q->colnum; k++)			// 当前各行累加器清零 
				qtemp[k] = 0;
			q->rpos[mrow] = q->nznum + 1;
			if(mrow < m->rownum)	
				mcurrownz = m->rpos[mrow+1];
			else
				mcurrownz = m->nznum + 1;
			for(row = m->rpos[mrow]; row < mcurrownz; row++)
			{
				trow = m->data[row].j;
				if(trow < t->rownum)
					tcurrownz = t->rpos[trow+1];
				else
					tcurrownz = t->nznum + 1;
				for(col = t->rpos[trow]; col < tcurrownz; col++)
				{
					qcol = t->data[col].j;			// 乘积元素在Q中的列号 
					qtemp[qcol] += m->data[row].e * t->data[col].e;
				}
			}
			for(qcol = 1; qcol <= q->colnum; qcol++)	// 压缩存储该行非零元素 
				if(qtemp[qcol] != 0)
				{
					q->data[q->nznum].i = mrow;
                    q->data[q->nznum].j = qcol;
					q->data[q->nznum].e = qtemp[qcol];
					q->nznum++;
				}
		}
		printf("矩阵乘积的结果为:\n");
		
	}

该算法的循环部分取决于行数、列数以及非零元个数,由于这些都已经定义好最大的数目,所以该算法的时间复杂度为:T(n)=O(1);算法的辅助空间只有2个临时变量的空间,因此该算法的时间复杂度为:T(n)=O(1);算法的辅助空间只有9个临时变量的空间,因此S(n)=O(1)。

第五部分:设计结果(结果分析)

①创建矩阵模块测试

输入合法数据测试后,如下图8所示:

图8 创建矩阵的合法数据测试

输入非法数据:行数或列数为负数或者非零元的个数大于矩阵的最大存储个数。如下图9所示:

图9 创建矩阵的非法数据测试

②矩阵相乘模块测试

输入合法数据测试后,如下图10所示:

图10 矩阵相乘的合法数据测试

输入非法数据:第一个矩阵的列数与第二个矩阵的行数不相等。如下图11所示:

图11 矩阵相乘的非法数据测试

③矩阵相加减模块测试

输入合法数据测试后,相加和相减分别如下图12,13所示:

图12 矩阵相加合法数据测试

图13 矩阵相减合法数据测试

输入非法数据:两个矩阵的行数与列数不对应相等。如下图14,15所示

图14 矩阵相加非法数据测试

图15 矩阵相减非法数据测试

④主函数模块测试

输入合法数据测试如下图16所示:

图16 主函数合法数据测试

输入非法数据:用户输入了不在范围内的功能编号。如下图17所示:

图17 主函数非法数据测试

第六部分:课程设计小结(心得及体会)

在本次的课程设计中,该系统实现了所有的要求,但是没有特别亮眼的关键技术。因为本人的数据结构的基础不是那么的扎实,所以在有关算法方面的设计可能会不太严谨,只是尽可能地把要求实现了,在实现乘法的功能时,除了增加一些判断参数合理性的语句外,其他的几乎是照搬课本的算法,所以今后我仍需回顾数据结构与算法,夯实本人的算法基础。另外,该系统值得说的地方就是可以通过if-else if判断语句对用户输入的矩阵行数、列数和非零元个数进行判断是否符合稀疏矩阵的特征,以及在用户选择加减乘的功能时,判断是否符合矩阵运算的要求。在设计矩阵相加减的算法时,我本来是计划直接将m复制到t中的,但是发现题目要求运算结果要另外生成,所以就另外搞了两个空矩阵,把m,t复制到这两个矩阵内进行操作。

通过本次的课程设计,我再次夯实了C语言和算法的基础知识。之前的学习大多停留在纸上谈兵,现在通过自己的设计调试后才深刻理解到算法对于一个程序的运行速度有多么大的影响。虽然在平时的上机实验中对一些知识点也是有了一定了解,但是通过这次的课程设计,对于之前搞不懂的困惑多多少少也有了全面的理解,哪怕只是一点点的进步,我也很高兴了,毕竟前进一小步总比原地踏步的好。

在这次的课程设计中,如果在调试代码时发现功能不完善或者出现了bug,可以先找到实现该功能的代码块,然后在该代码块中的各关键代码中放置标记(例如打印一行字符串),然后运行,查看哪个环节出现了问题,这样可以尽可能地快速找到问题所在,最后做出相应的修改。当然,最好在设计前对系统做出相应的流程图以及各模块的流程图,这样会大大减少代码编译出错的问题以及逻辑上的错误。另外,通过这次的论文设计,我学会了如何规范地撰写论文,学会了如何借鉴他人的方法与经验,这也为今后的论文写作打下了坚实的基础。虽然在编写这个程序时会出现很多的小错误,但正所谓“失败乃成功之母”,这些错误也会成为我不断前行的经验与动力。由于知识与经验的欠缺,这个程序还是不太完美,在今后的学习中还是需要努力学习的,不断提高自身的代码编写能力。

参考文献

[1] 秦玉平,马靖善 《数据结构(C语言版)》(第3版).清华大学出版社

[2] 数据中心扫地僧 c语言稀疏矩阵运算器,数据结构:稀疏矩阵运算器.CSDN

附录(程序代码)

# include <stdio.h>
# include <stdlib.h>
# include<math.h>
# define MAXSIZE 400	// 矩阵最多非零元个数 
# define RC 20			// 矩阵行数和列数最大均为20 

// 定义三元组表
typedef int ElemType;
typedef struct
{
	int i, j;				// 行标和列标 
	ElemType e;				// 非零元素值 
}tupletype;

typedef struct
{
	int rownum;					// 行数 
	int colnum;				 	// 列数 
	int nznum;				 	// 非零元数 
	int rpos[RC+1];		 	// 每一行第1个非零元素在三元组表中的起始位置 
	tupletype data[MAXSIZE];	// 非零三元组表 
}ltable;

// 输入三元组
void creatltable(ltable *lt)
{
	int r, c, n, i, j, k;
	ElemType x;
	do {
		printf("请输入矩阵的行数、列数以及非零元的个数:");
		scanf("%d %d %d", &r, &c, &n);
		if(r <= 0 || c <= 0)
			printf("行数或列数应为正整数!\n");
		else if(n > r*c)
			printf("非零元的个数大于矩阵的最大存储个数!\n");
	} while(r <= 0 || c <= 0 || n > r*c);
	lt->rownum = r;
	lt->colnum = c;
	lt->nznum = n;
	
	printf("请按行优先输入三元组\n");
	for(k = 1; k <= n; k++)				// 有多少个非零元就有多少个三元组
	{
		do {
			printf("请输入第%d个非零元素的三元组:", k);
			scanf("%d %d %d", &i, &j, &x);
			if(i < 0 || j < 0 || i > r || j > c || x == 0)
				printf("输入的参数有误!请重新输入:\n");
		}while(i < 0 || j < 0 || i > r || j > c || x == 0);
		lt->data[k].i = i;
		lt->data[k].j = j;
		lt->data[k].e = x;
	}
	
	int row, e;
	int nonzero[RC+1];
	for(row = 1; row <= lt->rownum; ++row)
		nonzero[row] = 0;						// 从下标1开始初始化数组,下标代表行标 
	for(e = 1; e <= lt->nznum; ++e)
		++nonzero[lt->data[e].i];				// 统计每一行的非零元素个数,只要lt->data[e].i(行标)一样,那么nonzero[lt->data[e].i]就加1
	lt->rpos[1] = 1;							// 第1行的首个非零元素肯定在rpos[1](从下标1开始存放)
	for(row = 2; row <= lt->rownum; ++row)
		lt->rpos[row] = lt->rpos[row-1] + nonzero[row-1];	// 每一行首个非零元素在三元组表data[]的位置(下标)=上一行首个非零元素的位置+上一行的非零元素个数			
}

// 输出
void list(ltable *q)
{
	int i, j, k, e;
	for(i = 1; i <= q->rownum; i++)
	{
		for(j = 1; j <= q->colnum; j++)
		{
			e = 0;
			for(k = 1; k <= q->nznum; k++)
				if(i == q->data[k].i && j == q->data[k].j)
				{
					e = q->data[k].e;
					break;
				}
			printf("%4d", e);
		}
		printf("\n");
	}
} 

// 矩阵相加 
void matriadd(ltable *m, ltable *t, ltable *q, ltable *p)
{	
	int i, j;
	q->rownum = t->rownum;
	q->colnum = t->colnum;
	q->nznum = t->nznum;
	p->rownum = m->rownum;
	p->colnum = m->colnum;
	p->nznum = m->nznum;
	if(m->rownum != t->rownum || m->colnum != t->colnum)
		printf("两个矩阵的行数与列数应对应相等!\n");
	else
	{
		for(i = 1; i <= t->nznum; i++)
		{
			q->data[i].i = t->data[i].i;
			q->data[i].j = t->data[i].j;
			q->data[i].e = t->data[i].e;
		}
		for(i = 1; i <= m->nznum; i++)
		{
			p->data[i].i = m->data[i].i;
			p->data[i].j = m->data[i].j;
			p->data[i].e = m->data[i].e;
		}
		
		for(i = 1; i <= p->nznum; i++)
			for(j = 1; j <= t->nznum; j++)
				if(p->data[i].i == q->data[j].i && p->data[i].j == q->data[j].j)
				{
					q->data[j].e += p->data[i].e;
					p->data[j].e = 0;
				}
		for(i = 1; i <= p->nznum; i++)
			if(p->data[i].e != 0)
			{
				q->data[q->nznum+1].i = p->data[i].i;
				q->data[q->nznum+1].j = p->data[i].j;
				q->data[q->nznum+1].e = p->data[i].e;
				q->nznum++;
			}
		printf("矩阵相加的结果为:\n");
	}
}

// 矩阵相减 
void matrisub(ltable *m, ltable *t, ltable *q, ltable *p)
{	
	int i, j;
	q->rownum = t->rownum;
	q->colnum = t->colnum;
	q->nznum = t->nznum;
	p->rownum = m->rownum;
	p->colnum = m->colnum;
	p->nznum = m->nznum;
	if(m->rownum != t->rownum || m->colnum != t->colnum)
		printf("两个矩阵的行数与列数应对应相等!\n");
	else
	{
		for(i = 1; i <= t->nznum; i++)
		{
			q->data[i].i = t->data[i].i;
			q->data[i].j = t->data[i].j;
			q->data[i].e = t->data[i].e;
		}
		for(i = 1; i <= m->nznum; i++)
		{
			p->data[i].i = m->data[i].i;
			p->data[i].j = m->data[i].j;
			p->data[i].e = m->data[i].e;
		}
		
		for(i = 1; i <= p->nznum; i++)
			for(j = 1; j <= q->nznum; j++)
				if(q->data[j].i == p->data[i].i && q->data[j].j == p->data[i].j)
				{
					p->data[i].e -= q->data[j].e;
					q->data[j].e = 0;
				}
		for(i = 1; i <= q->nznum; i++)
			if(q->data[i].e != 0)
			{
				p->data[p->nznum+1].i = q->data[i].i;
				p->data[p->nznum+1].j = q->data[i].j;
				p->data[p->nznum+1].e = 0 - q->data[i].e;
				p->nznum++;
			}
		printf("矩阵相减的结果为:\n");
		
	}
}

// 矩阵相乘
void matrimul(ltable *m, ltable *t, ltable *q)
{
	int row, mrow, trow, qcol, qtemp[MAXSIZE], col, mcurrownz, tcurrownz, k;
	q->rownum = m->rownum;
	q->colnum = t->colnum;
	q->nznum = 1;		// 乘积结果矩阵初始化 
	
	if(m->nznum * t->nznum == 0)
		printf("矩阵结果为零。\n");
	else if(m->colnum != t->rownum)
		printf("第一个矩阵的列数应与第二个矩阵的行数相等\n");
	else if(m->colnum == t->rownum)
	{
		for(mrow = 1; mrow <= m->rownum; mrow++)		// 处理m的每一行 
		{
			for(k = 1; k <= q->colnum; k++)			// 当前各行累加器清零 
				qtemp[k] = 0;
			q->rpos[mrow] = q->nznum + 1;
			if(mrow < m->rownum)	
				mcurrownz = m->rpos[mrow+1];
			else
				mcurrownz = m->nznum + 1;
			for(row = m->rpos[mrow]; row < mcurrownz; row++)
			{
				trow = m->data[row].j;
				if(trow < t->rownum)
					tcurrownz = t->rpos[trow+1];
				else
					tcurrownz = t->nznum + 1;
				for(col = t->rpos[trow]; col < tcurrownz; col++)
				{
					qcol = t->data[col].j;			// 乘积元素在Q中的列号 
					qtemp[qcol] += m->data[row].e * t->data[col].e;
				}
			}
			for(qcol = 1; qcol <= q->colnum; qcol++)	// 压缩存储该行非零元素 
				if(qtemp[qcol] != 0)
				{
					q->data[q->nznum].i = mrow;
					q->data[q->nznum].j = qcol;
					q->data[q->nznum].e = qtemp[qcol];
					q->nznum++;
				}
		}
		printf("矩阵乘积的结果为:\n");
		
	}
}



int main()
{
	ltable m, t, q, p;
	int i;
	printf("请输入第一个矩阵的三元组:\n");
	creatltable(&m);
	printf("生成的第一个稀疏矩阵为:\n");
	list(&m);
	printf("请输入第二个矩阵的三元组:\n");
	creatltable(&t);
	printf("生成的第二个稀疏矩阵为:\n");
	list(&t);
	
	while(1)
	{
		printf("\t菜单\t\n");
		printf("    1.矩阵相乘。\n");
		printf("    2.矩阵相加。\n");
		printf("    3.矩阵相减。\n");
		printf("    4.退出稀疏矩阵运算器。\n");
		printf("请输入你选择的功能的编号:");
		scanf("%d", &i);
		if(i > 4)
			printf("输入了无效编号,请重新输入\n");
		else
		switch(i)
		{
			case 1:
				matrimul(&m, &t, &q);
				list(&q);
				printf("\n");
				break;
			case 2:
				matriadd(&m, &t, &q, &p);
				list(&q);
				printf("\n");
				break;
			case 3:
				matrisub(&m, &t, &q, &p);
				list(&p);
				printf("\n");
				break;
			case 4:
				exit(0);	
		}
	}
}

  • 53
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
稀疏矩阵运算器是一种功能强大的计算工具,主要用于处理稀疏矩阵的各种运算。 在这门课程设计中,我们将学习稀疏矩阵的定义、表示以及运算方法。首先,我们将介绍稀疏矩阵的概念,即矩阵中绝大多数元素为0的矩阵稀疏矩阵在实际应用中有着广泛的应用,比如网络连接、图像处理等领域。 在稀疏矩阵的表示方面,我们将探讨几种不同的方法,如三元组表示法、十字链表表示法等。这些表示方法对于稀疏矩阵的存储和运算都有一定的影响,我们将详细比较它们的优缺点。 接下来,我们将学习稀疏矩阵的各种运算,包括矩阵的相加、相减、相乘等。我们将介绍相应的算法,并通过实例演示如何进行这些运算。同时,还需要考虑到矩阵的规模、存储结构等因素,以提高运算的效率。 除了基本稀疏矩阵运算外,我们还将涉及一些高级的运算,如矩阵的转置、求逆、求行列式等。这些运算对于某些科学计算和工程问题具有重要的意义,我们将讨论相应的算法和实现方法。 在课程设计中,我们将通过编程实现稀疏矩阵运算器。我们将使用C++等编程语言,实现各种矩阵运算算法,并通过实例测试算法的正确性和效率。同时,我们还将设计用户界面,使得用户可以方便地输入和操作稀疏矩阵。 通过这门课程设计,我们将深入了解稀疏矩阵的概念、表示和运算方法。我们将掌握稀疏矩阵运算器的设计与实现技巧,提升我们在计算机科学与工程领域的应用能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值