欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

数据结构与算法分析课程设计:稀疏矩阵的应用

最编程 2024-05-22 14:09:02
...

1.设计题目与功能需求分析

1.1设计题目

稀疏矩阵应用

要求:实现三元组,十字链表下的稀疏矩阵的加、转、乘的实现。

1.2功能需求分析

1)设计函数建立稀疏矩阵,初始化值。

2)设计函数输出稀疏矩阵的值。

3)构造函数进行两个稀疏矩阵相加,输出最终的稀疏矩阵。

4)构造函数进行两个稀疏矩阵的相乘,输出最终的稀疏矩阵。

5)构造函数进行稀疏矩阵的转置,并输出结果。

6)退出系统。

2.概要设计

2.1功能模块设计

从系统的功能需求分析,得到系统主要包括以下几大功能模块,分别是建立主函数、创建三元组表、创建矩阵、矩阵相加减、矩阵转置等。其功能模块图如下图所示:

   

      图系统功能模块图

2.2模块简介

依据程序的功能模块划分,各模块定义如下:

1)定义稀疏矩阵框架

模块名:struct OLNode

模块描述:通过此模块可以定义矩阵内部元素类型及指针类型

2)创建稀疏矩阵信息

模块名:void Create(CrossList &M)

模块描述:根据文字提示,输入稀疏矩阵的行、列、非零元的全部信息。

(3)输出符合上述步骤中信息的稀疏矩阵

模块名:void Print(CrossList M)

模块描述:以矩阵的显示方式显示稀疏矩阵。

4)进行稀疏矩阵的加运算

模块名:void Add(CrossList M,CrossList N,CrossList &Q)

模块描述:根据文字提示,如果两个矩阵不是同类型的,程序返回给操作系统的返回码是OVERFLOW;如果两个矩阵是同类型的,相加程序运行

5)进行稀疏矩阵的转置运算

模块名:void Trans(CrossList M,CrossList &N)

模块描述:定义结点,扫描矩阵,进行矩阵的转置运算

6)进行稀疏矩阵的乘运算

模块名:void Mult(CrossList M,CrossList N,CrossList &Q)

模块描述:判断矩阵M的总列数是否等于矩阵N的总行数若是,程序运行,否则,提示出错

3.详细设计

3.1数据结构

本程序采用结构体数组,对稀疏矩阵中非零元素的行、列、值以及指针。

 1 struct OLNode
 2 {
 3  int i,j;                                           
 4  ElemType e;                                      
 5  OLNode *right,*down;                              
 6 };
 7 typedef OLNode *OLink;
 8 struct CrossList
 9 {
10  OLink *rhead,*chead;                               
11  int mu,nu,tu;                                     
12  };

3.2主函数的算法设计

首先显示菜单及运用菜单选择实现相应功能,输入稀疏矩阵行、列以及非零元,系统菜单调用采用while循环,在循环体中用switch语句调用各个功能函数,最后退出程序。

主函数的程序流程图如下图所示:

           

函数流程图

3.3程序代码实现

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<iostream.h>
  4 #include<process.h>
  5 #define OK 1
  6 #define ERROR 0
  7 #define OVERFLOW -2
  8 typedef int ElemType;
  9 
 10 //------------------------------------------------------------------------------------------------
 11 
 12 struct OLNode
 13 {
 14  int i,j;                                           //非零元所在行、列
 15  ElemType e;                                        //非零元值
 16  OLNode *right,*down;                               //定义向右域和向下域
 17 };
 18 
 19 typedef OLNode *OLink;
 20 
 21 struct CrossList
 22 {
 23  OLink *rhead,*chead;                               //行、列表头的头节点
 24  int mu,nu,tu;                                      //矩阵的行、列和非零元个数
 25 };
 26 
 27 
 28 //------------------------------------------------------------------------------------------------
 29 
 30 
 31 void Create(CrossList &M)                             //矩阵的创建
 32 {
 33  int i,j,k,m,n,t;
 34  ElemType e;                                       //用于存放非零元值
 35  OLNode *p,*q;
 36  printf("Please input the rows 、columns and the values of the matrix:");
 37  scanf("%d%d%d",&m,&n,&t);                         //输入稀疏矩阵的行、列、非零元个数
 38  M.mu=m;                                           //把矩阵的总行数存入M.mu
 39  M.nu=n;                                           //把矩阵的总列数存入M.nu
 40  M.tu=t;                                           //把矩阵的非零元个数存入M.tu
 41  M.rhead=(OLink*)malloc((m+1)*sizeof(OLink));      //给对象M的行分配m+1个结点大小的空间用行头指针M.rhead指向第一个行结点
 42  if(!M.rhead)                                      //假如头结点分配成功
 43   exit(OVERFLOW);                               //退出程序,程序返回给操作系统的返回码是OVERFLOW
 44  M.chead=(OLink*)malloc((n+1)*sizeof(OLink));      //给对象M的列分配n+1个结点大小的空间用列头指针M.chead指向第一个列结点
 45  if(!M.chead)                                      //假如头结点分配成功
 46   exit(OVERFLOW);                               //退出程序,程序返回给操作系统的返回码是OVERFLOW
 47  for(k=1;k<=m;k++)                                 //初始化行头指针
 48   M.rhead[k]=NULL;
 49  for(k=1;k<=n;k++)                                 //初始化列头指针
 50   M.chead[k]=NULL;
 51  printf("Please input %d data:\n",M.tu);
 52  for(k=0;k<t;k++)
 53  {
 54   scanf("%d%d%d",&i,&j,&e);                     //输入t个非零元的信息
 55   if(i>m||j>n)                                  //假如输入的元素不在矩阵中
 56   {
 57             printf("Please input again:\n");
 58    exit(OVERFLOW);                           //退出程序,程序返回给操作系统的返回码是OVERFLOW
 59   }
 60   else                                          //假如输入的元素在矩阵中
 61   {
 62    p=(OLNode*)malloc(sizeof(OLNode));        //为p分配一个结点大小的空间
 63    if(!p)                                    //假如p不存在
 64     exit(OVERFLOW);                       //退出程序,程序返回给操作系统的返回码是OVERFLOW
 65    p->i=i;                                   //把非零元的行值赋给p->i
 66    p->j=j;                                   //把非零元的列值赋给p->j
 67    p->e=e;                                   //把非零元的值赋给p->e
 68    if(M.rhead[i]==NULL||M.rhead[i]->j>j)     //如果第i行的第一个结点为空或者要插入的非零元的列值小于第i行的第一个结点的列值
 69    {
 70     //p插入该行第一节点处
 71     p->right=M.rhead[i];                  //p的向右域指向没有插入前的第i行的第一个结点
 72     M.rhead[i]=p;                         //p指向没有插入前的第i行的第一个结点
 73    }
 74    else
 75    {
 76     //否则寻找行表插入位置
 77     for(q=M.rhead[i];q->right&&q->right->j<j;q=q->right);//这里的;表示对这个循环不执行任何操作
 78     p->right=q->right;                    //p的右向域指向q的右向域
 79     q->right=p;                           //p指向q的右向域
 80    }                                         //完成行插入
 81    if(M.chead[j]==NULL||M.chead[j]->i>i)     //假如第一个列结点为空或者第j列的第一个结点的行值大于要插入的行值
 82    {
 83     //p插入该列第一节点处
 84     p->down=M.chead[j];                   //p的向下域指向没有插入前的第j列的第一个结点
 85     M.chead[j]=p;                         //p指向没有插入前的第j列的第一个结点
 86    }                                         //完成列插入
 87    else
 88    {
 89     //否则寻找列表插入位置
 90     for(q=M.chead[j];q->down&&q->down->i<i;q=q->down);//这里的;表示对这个循环不执行任何操作
 91     p->down=q->down;                      //p的向下域指向q的向下域
 92     q->down=p;                            //p指向q的向下域
 93    }                                         //完成列插入
 94   }
 95  }
 96 }
 97 
 98 
 99 //------------------------------------------------------------------------------------------------
100 
101 void Print(CrossList M)                               //矩阵的输出
102 {
103  int i,j,k;
104  OLink p;                                          //定义结点指针p
105  int array[100][100];                              //定义二元数组array[100][100]
106  for(i=1;i<=M.mu;i++)                              //行循环
107  {
108   for(j=1;j<=M.nu;j++)                          //列循环
109   {
110    array[i][j]=0;                            //初始化数组所需部分
111   }
112  }
113  for(k=1;k<=M.nu;k++)                              //将所有非零元的值存入对应的数组中
114  {
115   p=M.rhead[k];                                 //p指向第k行的第一个结点
116   while(p)
117   {
118    //将第k行的非零元存入数组中
119    array[p->i][p->j]=p->e;                   //将这个结点的非零元存入数组中
120    p=p->right;                               //p指向下一个向右域
121   }
122  }
123  for(i=1;i<=M.mu;i++)                              //行循环
124  {
125   for(j=1;j<=M.nu;j++)                          //列循环
126   {
127    if(j==M.nu)
128     cout<<array[i][j]<<endl;              //如果是行的最后一个结点则换行
129    else
130     cout<<array[i][j]<<" ";               //以矩阵的显示方式显示稀疏矩阵
131   }
132  }
133 }
134 
135 
136 //------------------------------------------------------------------------------------------------
137 
138 
139 void Add(CrossList M,CrossList N,CrossList &Q)  //矩阵M和矩阵N相加并存入矩阵Q
140 {
141  int i,k;
142  OLink p,pq,pm,pn;
143  OLink *col;
144  if(M.mu!=N.mu||M.nu!=N.nu)                 //如果两个矩阵不是同类型的
145  {
146   printf("The two matrixes is not of the same type!/n");
147   exit(OVERFLOW);                        //退出程序,程序返回给操作系统的返回码是OVERFLOW
148  }
149  //对Q进行初始化
150  Q.mu=M.mu;                                 //矩阵Q的总行数和矩阵M的总数相同
151  Q.nu=M.nu;                                 //矩阵Q的总列数和矩阵M的总数相同
152  Q.tu=0;                                    //将矩阵Q的非零元个数初始化为零
153  Q.rhead=(OLink*)malloc((Q.mu+1)*sizeof(OLink));  //给对象Q的行分配Q.mu+1个结点大小的空间用行头指针Q.rhead指向第一个行结点
154  if(!Q.rhead)                               //如果行分配空间成功
155   exit(OVERFLOW);                        //退出程序,程序返回给操作系统的返回码是OVERFLOW
156  Q.chead=(OLink*)malloc((Q.nu+1)*sizeof(OLink));  //给对象Q的列分配Q.nu+1个结点大小的空间用列头指针Q.chead指向第一个列结点
157  if(!Q.chead)                               //如果列分配空间成功
158   exit(OVERFLOW);                        //退出程序,程序返回给操作系统的返回码是OVERFLOW
159  for(k=1;k<=Q.mu;k++)                       //初始化行
160   Q.rhead[k]=NULL;
161  for(k=1;k<=Q.nu;k++)                       //初始化列
162   Q.chead[k]=NULL;
163  col=(OLink*)malloc((Q.nu+1)*sizeof(OLink));//生成指向列的起始节点的指针
164  if(!col)                                   //如果分配空间成功
165   exit(OVERFLOW);                        //退出程序,程序返回给操作系统的返回码是OVERFLOW
166  for(k=1;k<=Q.nu;k++)                       //赋初始值
167   col[k]=NULL;
168  for(i=1;i<=M.mu;i++)                       //按行序相加
169  {
170   pm=M.rhead[i];                         //pm指向矩阵M的第i行的头结点
171   pn=N.rhead[i];                         //pn指向矩阵N的第i行的头结点
172   while(pm&&pn)                          //如果pm和pn都存在
173   {
174    if(pm->j<pn->j)                    //矩阵M当前结点的列小于矩阵N当前结点的列
175    {
176     //生成Q的结点
177     p=(OLink)malloc(sizeof(OLNode));  //给p分配一个结点大小的空间
178     if(!p)                         //如果分配空间不成功
179      exit(OVERFLOW);            //退出程序,程序返回给操作系统的返回码是OVERFLOW
180     Q.tu++;                        //矩阵Q的非零元个数加1
181     p->i=i;                        //把非零元的行赋给p->i
182     p->j=pm->j;                    //把矩阵M中当前结点列的值赋给p->j
183     p->e=pm->e;                    //把矩阵M中当前结点的元素值赋给p->e
184     p->right=NULL;                 //p的向右域为空
185     pm=pm->right;                  //pm右移
186    }
187    else if(pm->j>pn->j)               //矩阵M当前结点的列大于矩阵N当前结点的列
188    {
189     p=(OLink)malloc(sizeof(OLNode));//给p分配一个结点大小的空间
190     if(!p)                          //如果分配空间不成功
191      exit(OVERFLOW);             //退出程序,程序返回给操作系统的返回码是OVERFLOW
192     Q.tu++;                         //矩阵Q的非零元个数加1
193     p->i=i;                         //把矩阵当前非零元的行赋给p->i
194     p->j=pn->j;                     //把矩阵N中当前结点列的值赋给p->j
195     p->e=pn->e;                     //把矩阵N中当前结点的元素值赋给p->e
196     p->right=NULL;                  //p的向右域为空
197     pn=pn->right;                   //pn右移
198    }
199    else if(pm->e+pn->e)                //M,N当前结点的列相同并且两元素之和非零
200    {
201     p=(OLink)malloc(sizeof(OLNode));//给p分配一个结点大小的空间
202     if(!p)                          //如果分配空间不成功
203      exit(OVERFLOW);             //退出程序,程序返回给操作系统的返回码是OVERFLOW
204     Q.tu++;                         //矩阵Q的非零元个数加1
205     p->i=i;                         //把矩阵当前非零元的行赋给p->i
206     p->j=pn->j;                     //把矩阵当前非零元的列赋给p->j
207     p->e=pm->e+pn->e;               //把矩阵M当前非零元的值和矩阵N当前非零元的值相加赋给p->e
208     p->right=NULL;                  //p的向右域为空
209     pm=pm->right;                   //pm右移
210     pn=pn->right;                   //pn右移
211    }
212    else                                //两元素相加为零
213    {
214     pm=pm->right;                   //pm右移
215     pn=pn->right;                   //pn右移
216     continue;                       //不执行下面的程序,回到循环
217    }
218    if(Q.rhead[i]==NULL)                //如果当前行的头结点为空
219     Q.rhead[i]=pq=p;                //把p结点中的数据赋给pq结点和结点Q.rhead[i],pq结点用来保存当前的位置
220    else                                //如果当前的头结点不为空
221    {
222     pq->right=p;                    //pq的向右域指向p
223     pq=pq->right;                   //pq指向pq的向右域
224    }                                   //完成行插入
225    if(Q.chead[p->j]==NULL)             //如果当前列的头结点为空
226     Q.chead[p->j]=col[p->j]=p;      //把p结点中的数据赋给结点col[p->j]和当前列的头结点Q.chead[p->j]
227    else
228    {
229     //如果当前结点不为空,则插入p结点
230     col[p->j]->down=p;
231     col[p->j]=col[p->j]->down;
232    }
233   }
234   while(pm)    //如果矩阵M中的结点还没有插完,将矩阵M该行的剩余元素插入矩阵Q
235   {
236    p=(OLink)malloc(sizeof(OLNode));    //给结点p分配空间
237    if(!p)
238     exit(OVERFLOW);
239    Q.tu++;                             //矩阵非零元个数加1
240    p->i=i;                             //把当前结点的行、列、和值插入p中
241    p->j=pm->j;
242    p->e=pm->e;
243    p->right=NULL;                      //p的向右域为空
244    pm=pm->right;                       //pm右移
245             if(Q.rhead[i]==NULL)                //如果当前行头结点为空,直接插入p结点
246     Q.rhead[i]=pq=p;
247    else                                //如果当前行头结点不为空,插入p结点
248    {
249     pq->right=p;
250     pq=pq->right;
251    }
252    if(Q.chead[p->j]==NULL)             //如果当前列头结点为空,直接插入p结点
253     Q.chead[p->j]=col[p->j]=p;    
254    else                                //如果当前列头结点不为空,插入p结点
255    {
256     col[p->j]->down=p;
257     col[p->j]=col[p->j]->down;
258    }
259   }
260   while(pn)                               //如果矩阵N中的结点还没有插完,将矩阵N该行的剩余元素插入矩阵Q
261   {
262    p=(OLink)malloc(sizeof(OLNode));    //给结点p分配空间
263    if(!p)
264     exit(OVERFLOW);
265    Q.tu++;                             //矩阵非零元个数加1
266    p->i=i;                             //把当前结点的行、列、和值插入p中
267    p->j=pn->j;
268    p->e=pn->e;
269    p->right=NULL;                      //p的向右域为空
270    pn=pn->right;                       //pn右移
271             if(Q.rhead[i]==NULL)                //如果当前行头结点为空,直接插入p结点
272     Q.rhead[i]=pq=p;
273    else                                //如果当前行头结点不为空,插入p结点
274    {
275     pq->right=p;
276     pq=pq->right;
277    }
278    if(Q.chead[p->j]==NULL)             //如果当前列头结点为空,直接插入p结点
279     Q.chead[p->j]=col[p->j]=p;
280    else                                //如果当前列头结点不为空,插入p结点
281    {
282     col[p->j]->down=p;
283     col[p->j]=col[p->j]->down;
284    }
285   }
286     }
287  for(k=1;k<=Q.nu;k++)                    //使得每一列的最后一个结点的向下域为空
288   if(col[k])
289    col[k]->down=NULL;
290   free(col);                              //释放col的空间
291 }
292 
293 //------------------------------------------------------------------------------------------------
294 
295 

						

上一篇: 乘风破浪的 WebGL 系列 - 仿射变换的数学基础

下一篇: 一起学习 matlab - 字符串操作 10_4 MATLAB 中的字符串表示法

推荐阅读