设计要求
稀疏矩阵是指那些多数元素为零的矩阵。利用“稀疏”特点进行存储和计算可以大大节省存储空间,提高计算准备效率。实现一个能进行稀疏矩阵基本运算的运算器,具体功能有:
- 以“带行逻辑链接信息”的三元组顺序表示稀疏矩阵,实现两个稀疏矩阵相加、相减、相乘的功能。
- 稀疏矩阵的输入形式采用三元组表示,而运算结果的矩阵则以通常的阵列形式列出。
- 稀疏矩阵采用带行逻辑链接信息的三元组顺序存储。
需求分析
- 设计函数建立稀疏矩阵,初始化值。
- 设计函数输出稀疏矩阵的值。
- 构造函数进行两个稀疏矩阵相加,输出最终的稀疏矩阵。
- 构造函数进行两个稀疏矩阵相减,输出最终的稀疏矩阵。
- 构造函数进行两个稀疏矩阵的相乘,输出最终的稀疏矩阵。
- 构造函数进行稀疏矩阵的转置,并输出结果。
- 退出系统。
概要设计
(1)主界面设计为了实现对稀疏矩阵的多种算法功能的管理,首先设计一个含有多个菜单项的主控菜单子程序以系统的各项子功能,方便用户交互式使用本系统。本系统主控菜单运行界面如图:
(2)存储结构设计本系统采用单链表结构存储稀疏矩阵的具体信息。其中:全部结点的信息用头结点为指针数组的单链表存储。
(3)系统功能设计本系统除了要完成稀疏矩阵的初始化功能外还设置了4个子功能菜单。建立稀疏矩阵用void Creat()实现,依据读入的行数和列数以及非零元素的个数,分别设定每个非零元素的信息。4个子功能的设计描述如下:
- 稀疏矩阵的加法:此功能由函数void add( )实现,当用户选择该功能,系统即提示用户初始化要进行加法的两个矩阵的信息。然后进行加法,最后输出结果。
- 稀疏矩阵的减法:此功能由函数void sub( )实现。当用户选择该功能,系统提示输入要进行相减的两个矩阵的详细信息。然后进行相减,最后得到结果。
- 稀疏矩阵的乘法:此功能由函数void mult( )实现。当用户选择该功能,系统提示输入要进行相乘的两个矩阵的详细信息。然后进行相乘,最后得到结果。
- 系统程序的退出:即退出稀疏矩阵的应用系统。用户选择此功能时,系统会提示计算器已关闭,按任意键退出。
模块设计
- void creat(TSMatrix *T) /由用户输入创建稀疏矩阵/
- void print(TSMatrix A) /输出稀疏矩阵/
- void add(TSMatrix A,TSMatrix B) /加法运算/
- void sub(TSMatrix A,TSMatrix B) /减法运算/
- void mult(TSMatrix A,TSMatrix B,TSMatrix *c) /乘法运算/
- char menu() /计算器主界面(菜单)/
- int main() /功能主函数/
C语言源程序——建议使用Devc ++ 运行
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#include<conio.h>
#include<malloc.h>
#include<string.h>
#define MAXSIZE 100 /*假设非零元个数的最大值为100*/
#define MAXMU 20 /*稀疏矩阵最大行列值为20*/
int count = 1;
typedef struct
{
int i,j; /*该非零元的行下标和列下标*/
int v;
}Triple;
typedef struct /*稀疏矩阵是由三元组的顺序存储*/
{ int rpos[MAXMU+1]; /*各行第一个非零元素的位置表*/
Triple data[MAXSIZE+1]; /*非零元三元组顺序表,data[0]未使用*/
int mu,nu,tu; /*矩阵的行数,列数和非零元个数*/
}TSMatrix;
void creat(TSMatrix *T) /*由用户输入创建稀疏矩阵*/
{
int row,num,k;
do
{
system("cls");
printf("\n 请输入第%d个矩阵!\n",count);
count = count + 1;
printf("*********************************\n");
printf(" 请输入稀疏矩阵行数: " );
scanf("%d", &T->mu);
if (T->mu<0 || T->mu>MAXMU)
printf("\n 行数超出定义范围,请重新输入!\n");
} while (T->mu<0 || T->mu>MAXMU);
do
{
printf(" 请输入稀疏矩阵列数: ");
scanf("%d", &T->nu);
if (T->nu<0 || T->nu>MAXMU)
printf("\n 列数超出定义范围,请重新输入!\n");
} while (T->nu<0 || T->nu>MAXMU);
do
{
printf(" 请输入稀疏矩阵的非零元素个数: ");
scanf("%d", &T->tu);
if (T->tu>MAXSIZE || (T->tu>T->mu*T->nu))
printf("\n 非零元素个数超出定义范围,请重新输入!\n");
} while (T->tu>MAXSIZE || (T->tu>T->mu*T->nu));
printf("**********************************\n");
printf(" 请按行从小到大依次输入结点信息!\n");
for (k=1; k<=T->tu; k++)
{
do
{
printf(" 请按三元组存储输入第%d个非零元素的行数i:", k);
scanf("%d", &T->data[k].i);
if (!T->data[k].i || T->data[k].i>T->mu)
printf("\n 输入有误,请重新输入!\n");
} while ((!T->data[k].i || T->data[k].i>T->mu));
do
{
printf(" 请按三元组存储输入第%d个非零元素的列数j:", k);
scanf("%d", &T->data[k].j);
if (!T->data[k].j || T->data[k].j>T->nu)
printf("\n 输入有误,请重新输入!\n");
} while ((!T->data[k].j || T->data[k].j>T->nu));
do
{
printf(" 请按三元组存储输入第%d个非零元素的值v:", k);
scanf("%d", &T->data[k].v);
if (T->data[k].v==0)
printf("\n 输入有误,请重新输入!\n");
} while (T->data[k].v==0);
printf("***********************************\n");
}
for(row=1,num=1;row<=T->mu;row++) /*行逻辑链接信息存储*/
{
T->rpos[row]=num;
while(T->data[num].i==row)
num++;
}
return;
}
void print(TSMatrix A) /*输出稀疏矩阵*/
{
int q,n,k,a=0;
system("cls");
printf("\n\n经过稀疏矩阵运算器运算,所得结果为:\n");
printf("***********************************\n");
printf("***********************************\n");
for(n=1;n<=A.mu;n++)
{
for(k=1;k<=A.nu;k++)
{
for(q=1;q<=A.tu;q++)
if(A.data[q].i==n && A.data[q].j==k)
{
printf("\t%-3d",A.data[q].v);break;
}
if(q>A.tu)
printf("\t%-3d",a);
}
printf("\n");
}
printf("***********************************\n");
printf("***********************************\n");
}
void add(TSMatrix A,TSMatrix B) /*加法运算*/
{
int n,k;
if(A.mu!=B.mu || A.nu!=B.nu)
{
printf("\n 不满足矩阵相加条件!");
printf("\n 需满足两矩阵的行数、列数均对应相等方可进行加法运算!!");
}
else
{
for(n=1;n<=A.tu;n++)
for(k=1;k<=B.tu;k++) /*将矩阵A的非零元接至B中*/
if(A.data[n].i==B.data[k].i && A.data[n].j==B.data[k].j)
{
A.data[n].v+=B.data[k].v;
B.data[k].v=0;
}
for(k=1;k<=B.tu;k++)
if(B.data[k].v!=0)
{
A.data[A.tu+1].i=B.data[k].i;
A.data[A.tu+1].j=B.data[k].j;
A.data[A.tu+1].v=B.data[k].v;
A.tu++;
}
print(A);
}
}
void sub(TSMatrix A,TSMatrix B) /*减法运算*/
{
int n,k;
if(A.mu!=B.mu || A.nu!=B.nu)
{
printf("\n 不满足矩阵相减条件!");
printf("\n 需要满足两矩阵的行数、列数均对应相等方可进行减法运算!!");
}
else
{
for(n=1;n<=A.tu;n++)
for(k=1;k<=B.tu;k++) /*将矩阵A的非零元接至B中*/
if(A.data[n].i==B.data[k].i && A.data[n].j==B.data[k].j)
{
A.data[n].v-=B.data[k].v;
B.data[k].v=0;
}
for(k=1;k<=B.tu;k++)
if(B.data[k].v!=0)
{
A.data[A.tu+1].i=B.data[k].i;
A.data[A.tu+1].j=B.data[k].j;
A.data[A.tu+1].v=-B.data[k].v;
A.tu++;
}
print(A);
}
}
void mult(TSMatrix A,TSMatrix B,TSMatrix *c) /*乘法运算*/
{
int arow,tp,i,t;
int ccol,p,brow,q;
int ctemp[MAXMU+1];
if(A.nu!=B.mu)
{
printf(" 矩阵不满足相乘条件!");
return ;
}
c->mu=A.mu;
c->nu=B.nu;
c->tu=0;
if(A.tu==0||B.tu==0)
{
printf(" 结果矩阵为零!");
return ;
}
else
{
for(arow=1;arow<=A.mu;arow++)
{
for(i=0;i<MAXMU;i++) /*存储器清零*/
ctemp[i]=0;
c->rpos[arow]=c->tu+1;
if(arow<A.mu)
tp=A.rpos[arow+1];
else
tp=A.tu+1;
for(p=A.rpos[arow];p<tp;p++)
{
brow=A.data[p].j;
if(brow<B.mu)
t=B.rpos[brow+1];
else
t=B.tu+1;
for(q=B.rpos[brow];q<t;q++)
{
ccol=B.data[q].j;
ctemp[ccol]+=A.data[p].v*B.data[q].v;
}
}
for(ccol=1;ccol<=c->nu;ccol++)
if(ctemp[ccol])
{
if(++(c->tu)>MAXSIZE)
{
printf("超出范围!");
return ;
}
c->data[c->tu].v=ctemp[ccol];
c->data[c->tu].i=arow;
c->data[c->tu].j=ccol;
}
}
}
print(*c);
}
char menu() /*计算器主界面(菜单)*/
{
char n;
system("title 稀疏矩阵运算器");
system("cls");
system("mode con cols=70 lines=30");
printf("\n");
printf("\n 课程设计-----*******班 \n\n\n\n");
printf(" **************************************** \n");
printf(" * * \n");
printf(" * 稀 疏 矩 阵 运 算 器 * \n");
printf(" * * \n");
printf(" * 实 现 运 算 * \n");
printf(" * * \n");
printf(" * 1:矩阵相加 * \n");
printf(" * 2:矩阵相減 * \n");
printf(" * 3:矩阵相乘 * \n");
printf(" * 4:选择退出 * \n");
printf(" * * \n");
printf(" **************************************** \n");
printf(" 请输入序号进行操作 : \n");
printf(" ");n=getchar();
return n;
}
int main() /*功能主函数*/
{
TSMatrix A,B,C;
for(;;)
switch(menu())
{case '1':creat(&A);
creat(&B);
add(A,B);
getch();
break;
case '2':creat(&A);
creat(&B);
sub(A,B);
getch();
break;
case '3':creat(&A);
creat(&B);
mult(A,B,&C);
getch();
break;
case '4':system("cls");
printf("计算器已关闭,按任意键退出 :)\n");
exit(0);
}
}
简要说明
- 输入第一个稀疏矩阵的行数,列数,非零个数
- 依次输入非零数所在的具体坐标
- 同理 输入第二个稀疏矩阵的行列非零个数
- 通常以回车作为输入结束
- 计算结果以矩阵的形式表现出来
总结
总通过本次实验,在我的学习理解上有很大的促进作用。单单对稀疏矩阵,我了解了由于矩阵在程序中常使用二维阵列表示,二维阵列的大小稀疏矩阵与使用的存储器空间成正比,如果多数的元素没有数据,则会造成存储器空间的浪费,为此,必须设计稀疏矩阵的阵列储存方式,利用较少的存储器空间储存完整的矩阵数据。二维数组Amn中有N个非零元素,若N<<m*n,则称A为稀疏矩阵。由于稀疏矩阵中含有很多的0元素,在计算机中存储会浪费很多的空间,因此我们通常采用压缩存储的方法。