18、数据结构笔记之十八链表实现稀疏矩阵

来源:互联网 发布:ubuntu pxe boot 编辑:程序博客网 时间:2024/06/16 01:04

18、数据结构笔记之十八链表实现稀疏矩阵

           “必须如蜜蜂一样,采过许多花,才能酿出蜜来。

            上篇中实现了栈在多项式实现中的例子,再来看下稀疏矩阵通过链表方式实现。

           关键字:十字链表存储

1.  十字链表存储

           十字链表(OrthogonalList)是有向图的另一种链式存储结构。该结构可以看成是将有向图的邻接表和逆邻接表结合起来得到的。用十字链表来存储有向图,可以达到高效的存取效果。同时,代码的可读性也会得到提升。

为便于理解后续代码,从网上摘了如下内容:图1 ,用十字链表表示稀疏矩阵。


用十字链表表示稀疏矩阵的基本思想是:对每个非零元素存储为一个结点,结点由5个域组成,其结构如2 表示,其中:row 域存储非零元素的行号,col 域存储非零元素的列号,v 域存储本元素的值,right,down 是两个指针域。


稀疏矩阵中每一行的非零元素结点按其列号从小到大顺序由right 域链成一个带表头结点的循环行链表,同样每一列中的非零元素按其行号从小到大顺序由down 域也链成一个带表头结点的循环列链表。即每个非零元素aij 既是第i 行循环链表中的一个结点,又是第j 列循环链表中的一个结点。行链表、列链表的头结点的row 域和col 域置0。每一列链表的表头结点的down 域指向该列链表的第一个元素结点,每一行链表的表头结点的right域指向该行表的第一个元素结点。由于各行、列链表头结点的row域、col域和v 域均为零行链表头结点只用right指针域,列链表头结点只用right 指针域,故这两组表头结点可以合用,也就是说对于第i 行的链表和第i 列的链表可以共用同一个头结点。为了方便地找到每一行或每一列,将每行(列)的这些头结点们链接起来,因为头结点的值域空闲,所以用头结点的值域作为连接各头结点的链域,即第i 行(列)的头结点的值域指向第i+1行(列)的头结点,… ,形成一个循环表。这个循环表又有一个头结点,这就是最后的总头结点,指针HA 指向它。总头结点的row 和col 域存储原矩阵的行数和列数。
    因为非零元素结点的值域是datatype 类型,在表头结点中需要一个指针类型,为了使整个结构的结点一致,我们规定表头结点和其它结点有同样的结构,因此该域用一个联合来表示;改进后的结点结构如3 所示。

 

 

2.  定义结构体

定义两个结构体OLNode和CrossList.

一个是节点,一个是头节点。

头结点中有两个指针分别是行链表头,列链表头。

 

typedefstructOLNode

{

           inti,j;   // 该非零元的行和列下标

           ElemTypee;   // 非零元素值

           structOLNode*right,*down;// 该非零元所在行表和列表的后继链域

}OLNode, *OLink;

typedefstruct//行和列链表头指针向量基址,CreatSMatrix_OL()分配

{

           OLink*rhead, *chead;

           intmu, nu, tu;       //稀疏矩阵的行数、列数和非零元个数,手动输入

}CrossList;

 

3.  InitSMatrix

初始化CrossList变量

// 初始化M(CrossList类型的变量必须初始化,否则创建、复制矩阵将出错)

int InitSMatrix(CrossList *M)

{

           (*M).rhead=(*M).chead=NULL;

           (*M).mu=(*M).nu=(*M).tu=0;

           return1;

}

 

4.  CreateSMatrix

采用十字链表存储稀疏矩阵M。

如果该参数不为空,则先删除,调用DestorySMatrix函数。

输入矩阵的行数m、列数n和非零元个数t。

然后分配(m+1)行链表头,n+1个列标链表头。

初始化之。

然后输入t个元素,元素需要输入行列 值。

然后分配元素空间,创建一个OLNode节点。

接着将该点接入到对应行链表,列链表上。

// 创建稀疏矩阵M,采用十字链表存储表示。

int CreateSMatrix(CrossList *M)

{

           inti,j,k,m,n,t;

           ElemTypee;

           OLNode*p,*q;

           if((*M).rhead)

                     DestroySMatrix(M);

           printf("请输入稀疏矩阵的行数列数非零元个数:(space) ");

           scanf("%d%d%d",&m,&n,&t);

           (*M).mu=m;

           (*M).nu=n;

           (*M).tu=t;

           //初始化行链表头

           (*M).rhead=(OLink*)malloc((m+1)*sizeof(OLink));

           if(!(*M).rhead)

                     exit(0);

           //初始化列链表头

           (*M).chead=(OLink*)malloc((n+1)*sizeof(OLink));

           if(!(*M).chead)

                     exit(0);

           for(k=1;k<=m;k++)//初始化行头指针向量;各行链表为空链表

                     (*M).rhead[k]=NULL;

           for(k=1;k<=n;k++)//初始化列头指针向量;各列链表为空链表

                     (*M).chead[k]=NULL;

           printf("请按任意次序输入%d个非零元的行元素值:(空格)\n",(*M).tu);

           for(k=0;k<t;k++)

           {

                     scanf("%d%d%d",&i,&j,&e);

                     p=(OLNode*)malloc(sizeof(OLNode));

                     if(!p)

                                exit(0);

                     p->i=i;//生成结点

                     p->j=j;

                     p->e=e;

                     if((*M).rhead[i]==NULL||(*M).rhead[i]->j>j)   

                     {

                                //p插在该行的第一个结点处

                                p->right=(*M).rhead[i];

                                (*M).rhead[i]=p;

                     }

                     else//寻查在行表中的插入位置

                     {

                                //从该行的行链表头开始,直到找到

                                for(q=(*M).rhead[i];q->right && q->right->j < j;q = q->right)

                                          ;

                                p->right=q->right;//完成行插入

                                q->right=p;

                     }

                     if((*M).chead[j]==NULL || (*M).chead[j]->i> i)

                     {

                                //p插在该列的第一个结点处

                                p->down= (*M).chead[j];

                                (*M).chead[j]= p;

                     }

                     else//寻查在列表中的插入位置

                     {

                                for(q= (*M).chead[j];q->down &&q->down->i < i;q = q->down)

                                          ;

                                p->down=q->down;//完成列插入

                                q->down=p;

                     }

           }

           return1;

}

 

 

5.  删除矩阵

销毁稀疏矩阵,传输参数是CrossList *M.

按行进行释放节点。然后释放头结点,分别释放头结点。

// 销毁稀疏矩阵M

int DestroySMatrix(CrossList *M)

{

           inti;

           OLNode*p,*q;

 

           for(i=1;i<=(*M).mu;i++)//按行释放结点

           {

                     p=*((*M).rhead+i);

                     while(p)

                     {

                                q=p;

                                p=p->right;

                                free(q);

                     }

           }

           free((*M).rhead);

           free((*M).chead);

           (*M).rhead=(*M).chead=NULL;

           (*M).mu=(*M).nu=(*M).tu=0;

           return1;

}

 

6.  输出矩阵PrintSMatrix

分别按行输出和按列输出,按行输出,就是一行一行遍历,反正每行都是串起来的,对不对?

按列输出同理。

 

// 按行或按列输出稀疏矩阵M

int PrintSMatrix(CrossListM)

{

           inti,j;

           OLinkp;

           printf("%d%d%d个非零元素\n",M.mu,M.nu,M.tu);

           printf("请输入选择(1.按行输出2.按列输出):");

           scanf("%d",&i);

           switch(i)

           {

           case1:

                     for(j=1;j<=M.mu;j++)

                     {

                                p=M.rhead[j];

                                while(p)

                                {

                                          printf("%d%d列值为%d\n",p->i,p->j,p->e);

                                          p=p->right;

                                }

                     }

                     break;

           case 2:

                     for(j=1;j<=M.nu;j++)

                     {

                                p=M.chead[j];

                                while(p)

                                {

                                          printf("%d%d列值为%d\n",p->i,p->j,p->e);

                                          p=p->down;

                                }

                     }

           }

           return1;

}

 

7.  复制矩阵

复制矩阵,从矩阵M复制到矩阵T。

 

int CopySMatrix(CrossListM,CrossList *T)

{

           inti;

           OLinkp,q,q1,q2;

 

           if((*T).rhead)

                     DestroySMatrix(T);

           (*T).mu=M.mu;

           (*T).nu=M.nu;

           (*T).tu=M.tu;

           (*T).rhead=(OLink*)malloc((M.mu+1)*sizeof(OLink));

           if(!(*T).rhead)

                     exit(0);

           (*T).chead=(OLink*)malloc((M.nu+1)*sizeof(OLink));

           if(!(*T).chead)

                     exit(0);

           for(i=1;i<=M.mu;i++)//初始化矩阵T的行头指针向量;各行链表为空链表

                     (*T).rhead[i]=NULL;

           for(i=1;i<=M.nu;i++)//初始化矩阵T的列头指针向量;各列链表为空链表

                     (*T).chead[i]=NULL;

           for(i=1;i<=M.mu;i++)//按行复制

           {

                     p=M.rhead[i];

                     while(p)//没到行尾

                     {

                                q=(OLNode*)malloc(sizeof(OLNode));//生成结点

                                if(!q)

                                          exit(0);

                                q->i=p->i;//给结点赋值

                                q->j=p->j;

                                q->e=p->e;

                                if(!(*T).rhead[i])//插在行表头

                                          (*T).rhead[i]=q1=q;

                                else//插在行表尾

                                          q1=q1->right=q;

                                if(!(*T).chead[q->j])//插在列表头

                                {

                                          (*T).chead[q->j]=q;

                                          q->down=NULL;

                                }

                                else//插在列表尾

                                {

                                          q2=(*T).chead[q->j];

                                         while(q2->down)

                                                     q2=q2->down;

                                          q2->down=q;

                                          q->down=NULL;

                                }

                                p=p->right;

                     }

                     q->right=NULL;

           }

           return1;

}

 

 

8.  矩阵加法

将矩阵M和N相加,得到矩阵Q。

如果行、列不相等则不能相加,直接退出。

按行的顺序相加。

如果对比两个列的大小,相等则进行相加,相加后要判断是否为0.

不为零则创建一个新的OLNode.

然后将这些节点插入到行链表,列链表中。

最后如果M或者N在行的数量上多,则都插入到矩阵Q中。

最后将指向列的最后的指针down设置为NULL。

 

int AddSMatrix(CrossListM,CrossListN,CrossList *Q)

{

           inti,k;

           OLinkp,pq,pm,pn;

           OLink*col;

 

           if(M.mu!=N.mu||M.nu!=N.nu)

           {

                     printf("两个矩阵不是同类型的,不能相加\n");

                     exit(0);

           }

           (*Q).mu=M.mu;//初始化Q矩阵

           (*Q).nu=M.nu;

           (*Q).tu=0;//元素个数的初值

           (*Q).rhead=(OLink*)malloc(((*Q).mu+1)*sizeof(OLink));

           if(!(*Q).rhead)

                     exit(0);

           (*Q).chead=(OLink*)malloc(((*Q).nu+1)*sizeof(OLink));

           if(!(*Q).chead)

                     exit(0);

           for(k=1;k<=(*Q).mu;k++)//初始化Q的行头指针向量;各行链表为空链表

                     (*Q).rhead[k]=NULL;

           for(k=1;k<=(*Q).nu;k++)//初始化Q的列头指针向量;各列链表为空链表

                     (*Q).chead[k]=NULL;

           //生成指向列的最后结点的数组

           col=(OLink*)malloc(((*Q).nu+1)*sizeof(OLink));

           if(!col)

                     exit(0);

           for(k=1;k<=(*Q).nu;k++)//赋初值

                     col[k]=NULL;

           for(i=1;i<=M.mu;i++)//按行的顺序相加

           {

                     pm=M.rhead[i];   // pm指向矩阵M的第i行的第1个结点

                     pn=N.rhead[i];   // pn指向矩阵N的第i行的第1个结点

                     while(pm&&pn)   // pmpn均不空

                     {

                                if(pm->j<pn->j)//矩阵M当前结点的列小于矩阵N当前结点的列

                                {

                                          p=(OLink)malloc(sizeof(OLNode));//生成矩阵Q的结点

                                         if(!p)

                                                     exit(0);

                                          (*Q).tu++;   // 非零元素数加1

                                          p->i=i;       // 给结点赋值

                                          p->j=pm->j;

                                          p->e=pm->e;

                                          p->right=NULL;

                                          pm=pm->right;//pm指针向右移

                                }

                                elseif(pm->j>pn->j)//矩阵M当前结点的列大于矩阵N当前结点的列

                                {

                                          p=(OLink)malloc(sizeof(OLNode));//生成矩阵Q的结点

                                         if(!p)

                                                     exit(0);

                                          (*Q).tu++;   // 非零元素数加1

                                          p->i=i;       // 给结点赋值

                                          p->j=pn->j;

                                          p->e=pn->e;

                                          p->right=NULL;

                                          pn=pn->right;//pn指针向右移

                                }

                                //矩阵MN当前结点的列相等且两元素之和不为0

                                elseif(pm->e+pn->e)

                                {

                                          p=(OLink)malloc(sizeof(OLNode));//生成矩阵Q的结点

                                         if(!p)

                                                     exit(0);

                                          (*Q).tu++;//非零元素数加1

                                          p->i=i;//给结点赋值

                                          p->j=pn->j;

                                          p->e=pm->e+pn->e;

                                          p->right=NULL;

                                          pm=pm->right;//pm指针向右移

                                          pn=pn->right;//pn指针向右移

                                }

                                else//矩阵MN当前结点的列相等且两元素之和为0

                                {

                                          pm=pm->right;//pm指针向右移

                                          pn=pn->right;//pn指针向右移

                                         continue;

                                }

                                if((*Q).rhead[i]==NULL)//p为该行的第1个结点

                                         //p插在该行的表头且pq指向p(该行的最后一个结点)

                                                     (*Q).rhead[i]=pq=p;

                                else//插在pq所指结点之后

                                {

                                          pq->right=p;//完成行插入

                                          pq=pq->right;//pq指向该行的最后一个结点

                                }

                                if((*Q).chead[p->j]==NULL)//p为该列的第1个结点

                                         //p插在该列的表头且col[p->j]指向

                                                     (*Q).chead[p->j]=col[p->j]=p;

                                else//插在col[p->]所指结点之后

                                {

                                          col[p->j]->down=p;//完成列插入

                                         //col[p->j]指向该列的最后一个结点

                                          col[p->j]=col[p->j]->down;

                                }

                     }

                     while(pm)//将矩阵M该行的剩余元素插入矩阵Q

                     {

                                p=(OLink)malloc(sizeof(OLNode));//生成矩阵Q的结点

                                if(!p)

                                          exit(0);

                                (*Q).tu++;//非零元素数加1

                                p->i=i;//给结点赋值

                                p->j=pm->j;

                                p->e=pm->e;

                                p->right=NULL;

                                pm=pm->right;//pm指针向右移

                                if((*Q).rhead[i]==NULL)// p为该行的第1个结点

                                         //p插在该行的表头且pq指向p(该行的最后一个结点)

                                                     (*Q).rhead[i]= pq = p; 

                                else//插在pq所指结点之后

                                {

                                          pq->right=p;//完成行插入

                                          pq=pq->right;//pq指向该行的最后一个结点

                                }

                                if((*Q).chead[p->j]==NULL)// p为该列的第1个结点

                                         //p插在该列的表头且col[p->j]指向p

                                                     (*Q).chead[p->j]= col[p->j] = p;

                                else//插在col[p->j]所指结点之后

                                {

                                          col[p->j]->down=p;//完成列插入

                                         //col[p->j]指向该列的最后一个结点

                                          col[p->j]=col[p->j]->down; 

                                }

                     }

                     while(pn)//将矩阵N该行的剩余元素插入矩阵Q

                     {

                                p=(OLink)malloc(sizeof(OLNode));//生成矩阵Q的结点

                                if(!p)

                                          exit(0);

                                (*Q).tu++;//非零元素数加1

                                p->i=i;//给结点赋值

                                p->j=pn->j;

                                p->e=pn->e;

                                p->right=NULL;

                                pn=pn->right;//pm指针向右移

                                if((*Q).rhead[i]==NULL)//p为该行的第1个结点

                                         //p插在该行的表头且pq指向p(该行的最后一个结点)

                                                     (*Q).rhead[i]=pq=p; 

                                else//插在pq所指结点之后

                                {

                                          pq->right=p;//完成行插入

                                          pq=pq->right;//pq指向该行的最后一个结点

                                }

                                if((*Q).chead[p->j]==NULL)//p为该列的第1个结点

                                         //p插在该列的表头且col[p->j]指向

                                                     (*Q).chead[p->j]=col[p->j]=p;

                                else//插在col[p->j]所指结点之后

                                {

                                          col[p->j]->down=p;//完成列插入

                                         //col[p->j]指向该列的最后一个结点

                                          col[p->j]=col[p->j]->down; 

                                }

                     }

           }

           for(k=1;k<=(*Q).nu;k++)

                     if(col[k])//k列有结点

                                col[k]->down=NULL;//  令该列最后一个结点的down指针为空

           free(col);

           return1;

}

 

9.  矩阵减法

基本同加法。

10.      矩阵乘法

只有当矩阵A的列数与矩阵B的行数相等时A×B才有意义。一个m×n的矩阵a(m,n)左乘一个n×p的矩阵b(n,p),会得到一个m×p的矩阵c(m,p)。左乘:又称前乘,就是乘在左边(即乘号前),比如说,A左乘E即AE。

先根据MXN,确定了Q的行列数量。

然后M的行与N的列,每项相乘后进行相加累计,如果不为零。则插入到Q矩阵中。

 

int MultSMatrix(CrossListM,CrossListN,CrossList *Q)

{

           inti,j,e;

           OLinkq,p0,q0,q1,q2;

 

           InitSMatrix(Q);

           (*Q).mu=M.mu;

           (*Q).nu=N.nu;

           (*Q).tu=0;

           (*Q).rhead=(OLink*)malloc(((*Q).mu+1)*sizeof(OLink));

           if(!(*Q).rhead)

                     exit(0);

           (*Q).chead=(OLink*)malloc(((*Q).nu+1)*sizeof(OLink));

           if(!(*Q).chead)

                     exit(0);

           for(i=1;i<=(*Q).mu;i++)//初始化矩阵Q的行头指针向量;各行链表为空链表

                     (*Q).rhead[i]=NULL;

           for(i=1;i<=(*Q).nu;i++)//初始化矩阵Q的列头指针向量;各列链表为空链表

                     (*Q).chead[i]=NULL;

           for(i=1;i<=(*Q).mu;i++)

                     for(j=1;j<=(*Q).nu;j++)

                     {

                                p0=M.rhead[i];

                                q0=N.chead[j];

                                e=0;

                                while(p0&&q0)

                                {

                                         if(q0->i<p0->j)

                                                     q0=q0->down;//列指针后移

                                         elseif(q0->i>p0->j)

                                                     p0=p0->right;//行指针后移

                                         else//q0->i==p0->j

                                          {

                                                     e+=p0->e*q0->e;//乘积累加

                                                     q0=q0->down;//行列指针均后移

                                                     p0=p0->right;

                                          }

                                }

                                if(e)//值不为0

                                {

                                          (*Q).tu++;//非零元素数加1

                                          q=(OLink)malloc(sizeof(OLNode));//生成结点

                                         if(!q)//生成结点失败

                                                     exit(0);

                                          q->i=i;//给结点赋值

                                          q->j=j;

                                          q->e=e;

                                          q->right=NULL;

                                          q->down=NULL;

                                         if(!(*Q).rhead[i])//行表空时插在行表头

                                                     (*Q).rhead[i]=q1=q;

                                         else//否则插在行表尾

                                                     q1=q1->right=q;

                                         if(!(*Q).chead[j])//列表空时插在列表头

                                                     (*Q).chead[j]=q;

                                         else//否则插在列表尾

                                          {

                                                     q2=(*Q).chead[j];//q2指向j行第1个结点

                                                    while(q2->down)

                                                               q2=q2->down;//q2指向j行最后1个结点

                                                     q2->down=q;

                                          }

                                }

                     }

                     return1;

}

11.      转置矩阵

矩阵转置是一个数学概念,于19世纪由英国数学家凯利首先提出。在数学上,矩阵指纵横排列的二维数据表格,来自于方程组的系数及常数所构成的方阵;矩阵概念在生产实践中也有许多应用,比如矩阵图法以及保护个人帐号的矩阵卡系统(由深圳网域提出)等。

定义A的转置为这样一个n×m阶矩阵B,满足B=a(j,i),即 b (i,j)=a(j,i)(B的第i行第j列元素是A的第j行第i列元素),记A'=B。(有些书记为AT=B,这里T为A的上标)

 

int TransposeSMatrix(CrossListM,CrossList *T)

{

           intu,i;

           OLink*head,p,q,r;

           if((*T).rhead)

                     DestroySMatrix(T);

           CopySMatrix(M,T);//T=M

           u=(*T).mu;//交换(*T).mu(*T).nu

           (*T).mu=(*T).nu;

           (*T).nu=u;

           head=(*T).rhead;//交换(*T).rhead(*T).chead

           (*T).rhead=(*T).chead;

           (*T).chead=head;

           for(u=1;u<=(*T).mu;u++)//T的每一行

           {

                     p=(*T).rhead[u];//p为行表头

                     while(p)//没到表尾,T的每一结点

                     {

                                q=p->down;//q指向下一个结点

                                i=p->i;//交换.i.j

                                p->i=p->j;

                                p->j=i;

                                r=p->down;//交换.down.right

                                p->down=p->right;

                                p->right=r;

                                p=q;//p指向下一个结点

                     }

           }

           return1;

}

 

 

 

12.      Main函数

得到如下4

 

13.      源码

源码如下:

#include<stdio.h>

#include<malloc.h>

#include"stdlib.h"

typedefintElemType;//稀疏矩阵的十字链表存储表示

 

typedefstructOLNode

{

           inti,j;   // 该非零元的行和列下标

           ElemTypee;   // 非零元素值

           structOLNode*right,*down;// 该非零元所在行表和列表的后继链域

}OLNode, *OLink;

typedefstruct//行和列链表头指针向量基址,CreatSMatrix_OL()分配

{

           OLink*rhead, *chead;

           intmu, nu, tu;       //稀疏矩阵的行数、列数和非零元个数

}CrossList;

// 初始化M(CrossList类型的变量必须初始化,否则创建、复制矩阵将出错)

int InitSMatrix(CrossList *M)

{

           (*M).rhead=(*M).chead=NULL;

           (*M).mu=(*M).nu=(*M).tu=0;

           return1;

}

// 销毁稀疏矩阵M

int DestroySMatrix(CrossList *M)

{

           inti;

           OLNode*p,*q;

 

           for(i=1;i<=(*M).mu;i++)//按行释放结点

           {

                     p=*((*M).rhead+i);

                     while(p)

                     {

                                q=p;

                                p=p->right;

                                free(q);

                     }

           }

           free((*M).rhead);

           free((*M).chead);

           (*M).rhead=(*M).chead=NULL;

           (*M).mu=(*M).nu=(*M).tu=0;

           return1;

}

// 创建稀疏矩阵M,采用十字链表存储表示。

int CreateSMatrix(CrossList *M)

{

           inti,j,k,m,n,t;

           ElemTypee;

           OLNode*p,*q;

           if((*M).rhead)

                     DestroySMatrix(M);

           printf("请输入稀疏矩阵的行数列数非零元个数:(space) ");

           scanf("%d%d%d",&m,&n,&t);

           (*M).mu=m;

           (*M).nu=n;

           (*M).tu=t;

           //初始化行链表头

           (*M).rhead=(OLink*)malloc((m+1)*sizeof(OLink));

           if(!(*M).rhead)

                     exit(0);

           //初始化列链表头

           (*M).chead=(OLink*)malloc((n+1)*sizeof(OLink));

           if(!(*M).chead)

                     exit(0);

           for(k=1;k<=m;k++)//初始化行头指针向量;各行链表为空链表

                     (*M).rhead[k]=NULL;

           for(k=1;k<=n;k++)//初始化列头指针向量;各列链表为空链表

                     (*M).chead[k]=NULL;

           printf("请按任意次序输入%d个非零元的行元素值:(空格)\n",(*M).tu);

           for(k=0;k<t;k++)

           {

                     scanf("%d%d%d",&i,&j,&e);

                     p=(OLNode*)malloc(sizeof(OLNode));

                     if(!p)

                                exit(0);

                     p->i=i;//生成结点

                     p->j=j;

                     p->e=e;

                     if((*M).rhead[i]==NULL||(*M).rhead[i]->j>j)   

                     {

                                //p插在该行的第一个结点处

                                p->right=(*M).rhead[i];

                                (*M).rhead[i]=p;

                     }

                     else//寻查在行表中的插入位置

                     {

                                //从该行的行链表头开始,直到找到

                                for(q=(*M).rhead[i];q->right && q->right->j < j;q = q->right)

                                          ;

                                p->right=q->right;//完成行插入

                                q->right=p;

                     }

                     if((*M).chead[j]==NULL || (*M).chead[j]->i> i)

                     {

                                //p插在该列的第一个结点处

                                p->down= (*M).chead[j];

                                (*M).chead[j]= p;

                     }

                     else//寻查在列表中的插入位置

                     {

                                for(q= (*M).chead[j];q->down &&q->down->i < i;q = q->down)

                                           ;

                                p->down=q->down;//完成列插入

                                q->down=p;

                     }

           }

           return1;

}

// 按行或按列输出稀疏矩阵M

int PrintSMatrix(CrossListM)

{

           inti,j;

           OLinkp;

           printf("%d%d%d个非零元素\n",M.mu,M.nu,M.tu);

           printf("请输入选择(1.按行输出2.按列输出):");

           scanf("%d",&i);

           switch(i)

           {

           case1:

                     for(j=1;j<=M.mu;j++)

                     {

                                p=M.rhead[j];

                                while(p)

                                {

                                          printf("%d%d列值为%d\n",p->i,p->j,p->e);

                                          p=p->right;

                                }

                     }

                     break;

           case2:

                     for(j=1;j<=M.nu;j++)

                     {

                                p=M.chead[j];

                                while(p)

                                {

                                          printf("%d%d列值为%d\n",p->i,p->j,p->e);

                                          p=p->down;

                                }

                     }

           }

           return1;

}

// 由稀疏矩阵M复制得到T

int CopySMatrix(CrossListM,CrossList *T)

{

           inti;

           OLinkp,q,q1,q2;

 

           if((*T).rhead)

                     DestroySMatrix(T);

           (*T).mu=M.mu;

           (*T).nu=M.nu;

           (*T).tu=M.tu;

           (*T).rhead=(OLink*)malloc((M.mu+1)*sizeof(OLink));

           if(!(*T).rhead)

                     exit(0);

           (*T).chead=(OLink*)malloc((M.nu+1)*sizeof(OLink));

           if(!(*T).chead)

                     exit(0);

           for(i=1;i<=M.mu;i++)//初始化矩阵T的行头指针向量;各行链表为空链表

                     (*T).rhead[i]=NULL;

           for(i=1;i<=M.nu;i++)//初始化矩阵T的列头指针向量;各列链表为空链表

                     (*T).chead[i]=NULL;

           for(i=1;i<=M.mu;i++)//按行复制

           {

                     p=M.rhead[i];

                     while(p)//没到行尾

                     {

                                q=(OLNode*)malloc(sizeof(OLNode));//生成结点

                                if(!q)

                                          exit(0);

                                q->i=p->i;//给结点赋值

                                q->j=p->j;

                                q->e=p->e;

                                if(!(*T).rhead[i])//插在行表头

                                          (*T).rhead[i]=q1=q;

                                else//插在行表尾

                                          q1=q1->right=q;

                                if(!(*T).chead[q->j])//插在列表头

                                {

                                          (*T).chead[q->j]=q;

                                          q->down=NULL;

                                }

                                else//插在列表尾

                                {

                                          q2=(*T).chead[q->j];

                                         while(q2->down)

                                                     q2=q2->down;

                                          q2->down=q;

                                          q->down=NULL;

                                }

                                p=p->right;

                     }

                     q->right=NULL;

           }

           return1;

}

// 求稀疏矩阵的和Q=M+N

int AddSMatrix(CrossListM,CrossListN,CrossList *Q)

{

           inti,k;

           OLinkp,pq,pm,pn;

           OLink*col;

 

           if(M.mu!=N.mu||M.nu!=N.nu)

           {

                     printf("两个矩阵不是同类型的,不能相加\n");

                     exit(0);

           }

           (*Q).mu=M.mu;//初始化Q矩阵

           (*Q).nu=M.nu;

           (*Q).tu=0;//元素个数的初值

           (*Q).rhead=(OLink*)malloc(((*Q).mu+1)*sizeof(OLink));

           if(!(*Q).rhead)

                     exit(0);

           (*Q).chead=(OLink*)malloc(((*Q).nu+1)*sizeof(OLink));

           if(!(*Q).chead)

                     exit(0);

           for(k=1;k<=(*Q).mu;k++)//初始化Q的行头指针向量;各行链表为空链表

                     (*Q).rhead[k]=NULL;

           for(k=1;k<=(*Q).nu;k++)//初始化Q的列头指针向量;各列链表为空链表

                     (*Q).chead[k]=NULL;

           //生成指向列的最后结点的数组

           col=(OLink*)malloc(((*Q).nu+1)*sizeof(OLink));

           if(!col)

                     exit(0);

           for(k=1;k<=(*Q).nu;k++)//赋初值

                     col[k]=NULL;

           for(i=1;i<=M.mu;i++)//按行的顺序相加

           {

                     pm=M.rhead[i];   // pm指向矩阵M的第i行的第1个结点

                     pn=N.rhead[i];   // pn指向矩阵N的第i行的第1个结点

                     while(pm&&pn)   // pmpn均不空

                     {

                                if(pm->j<pn->j)//矩阵M当前结点的列小于矩阵N当前结点的列

                                {

                                          p=(OLink)malloc(sizeof(OLNode));//生成矩阵Q的结点

                                         if(!p)

                                                     exit(0);

                                          (*Q).tu++;   // 非零元素数加1

                                          p->i=i;       // 给结点赋值

                                          p->j=pm->j;

                                          p->e=pm->e;

                                          p->right=NULL;

                                          pm=pm->right;//pm指针向右移

                                }

                                elseif(pm->j>pn->j)//矩阵M当前结点的列大于矩阵N当前结点的列

                                {

                                          p=(OLink)malloc(sizeof(OLNode));//生成矩阵Q的结点

                                         if(!p)

                                                     exit(0);

                                          (*Q).tu++;   // 非零元素数加1

                                          p->i=i;       // 给结点赋值

                                          p->j=pn->j;

                                          p->e=pn->e;

                                          p->right=NULL;

                                          pn=pn->right;//pn指针向右移

                                }

                                //矩阵MN当前结点的列相等且两元素之和不为0

                                elseif(pm->e+pn->e)

                                {

                                          p=(OLink)malloc(sizeof(OLNode));//生成矩阵Q的结点

                                         if(!p)

                                                     exit(0);

                                          (*Q).tu++;//非零元素数加1

                                          p->i=i;//给结点赋值

                                          p->j=pn->j;

                                          p->e=pm->e+pn->e;

                                          p->right=NULL;

                                          pm=pm->right;//pm指针向右移

                                          pn=pn->right;//pn指针向右移

                                }

                                else//矩阵MN当前结点的列相等且两元素之和为0

                                {

                                          pm=pm->right;//pm指针向右移

                                          pn=pn->right;//pn指针向右移

                                         continue;

                                }

                                if((*Q).rhead[i]==NULL)//p为该行的第1个结点

                                         //p插在该行的表头且pq指向p(该行的最后一个结点)

                                                     (*Q).rhead[i]=pq=p;

                                else//插在pq所指结点之后

                                {

                                          pq->right=p;//完成行插入

                                          pq=pq->right;//pq指向该行的最后一个结点

                                }

                                if((*Q).chead[p->j]==NULL)//p为该列的第1个结点

                                         //p插在该列的表头且col[p->j]指向

                                                     (*Q).chead[p->j]=col[p->j]=p;

                                else//插在col[p->]所指结点之后

                                {

                                          col[p->j]->down=p;//完成列插入

                                         //col[p->j]指向该列的最后一个结点

                                          col[p->j]=col[p->j]->down;

                                }

                     }

                     while(pm)//将矩阵M该行的剩余元素插入矩阵Q

                     {

                                p=(OLink)malloc(sizeof(OLNode));//生成矩阵Q的结点

                                if(!p)

                                          exit(0);

                                (*Q).tu++;//非零元素数加1

                                p->i=i;//给结点赋值

                                p->j=pm->j;

                                p->e=pm->e;

                                p->right=NULL;

                                pm=pm->right;//pm指针向右移

                                if((*Q).rhead[i]==NULL)// p为该行的第1个结点

                                         //p插在该行的表头且pq指向p(该行的最后一个结点)

                                                     (*Q).rhead[i]= pq = p; 

                                else//插在pq所指结点之后

                                {

                                          pq->right=p;//完成行插入

                                          pq=pq->right;//pq指向该行的最后一个结点

                                }

                                if((*Q).chead[p->j]==NULL)// p为该列的第1个结点

                                         //p插在该列的表头且col[p->j]指向p

                                                     (*Q).chead[p->j]= col[p->j] = p;

                                else//插在col[p->j]所指结点之后

                                {

                                          col[p->j]->down=p;//完成列插入

                                         //col[p->j]指向该列的最后一个结点

                                          col[p->j]=col[p->j]->down; 

                                }

                     }

                     while(pn)//将矩阵N该行的剩余元素插入矩阵Q

                     {

                                p=(OLink)malloc(sizeof(OLNode));//生成矩阵Q的结点

                                if(!p)

                                          exit(0);

                                (*Q).tu++;//非零元素数加1

                                p->i=i;//给结点赋值

                                p->j=pn->j;

                                p->e=pn->e;

                                p->right=NULL;

                                pn=pn->right;//pm指针向右移

                                if((*Q).rhead[i]==NULL)//p为该行的第1个结点

                                         //p插在该行的表头且pq指向p(该行的最后一个结点)

                                                     (*Q).rhead[i]=pq=p; 

                                else//插在pq所指结点之后

                                {

                                          pq->right=p;//完成行插入

                                          pq=pq->right;//pq指向该行的最后一个结点

                                }

                                if((*Q).chead[p->j]==NULL)//p为该列的第1个结点

                                         //p插在该列的表头且col[p->j]指向

                                                     (*Q).chead[p->j]=col[p->j]=p;

                                else//插在col[p->j]所指结点之后

                                {

                                          col[p->j]->down=p;//完成列插入

                                         //col[p->j]指向该列的最后一个结点

                                          col[p->j]=col[p->j]->down; 

                                }

                     }

           }

           for(k=1;k<=(*Q).nu;k++)

                     if(col[k])//k列有结点

                                col[k]->down=NULL;//  令该列最后一个结点的down指针为空

           free(col);

           return1;

}

 

//  求稀疏矩阵的差Q=M-N

int SubtSMatrix(CrossListM,CrossListN,CrossList *Q)

{

           inti,k;

           OLinkp,pq,pm,pn;

           OLink*col;

 

           if(M.mu!=N.mu||M.nu!=N.nu)

           {

                     printf("两个矩阵不是同类型的,不能相加\n");

                     exit(0);

           }

           (*Q).mu=M.mu;//初始化Q矩阵

           (*Q).nu=M.nu;

           (*Q).tu=0;//元素个数的初值

           (*Q).rhead=(OLink*)malloc(((*Q).mu+1)*sizeof(OLink));

           if(!(*Q).rhead)

                     exit(0);

           (*Q).chead=(OLink*)malloc(((*Q).nu+1)*sizeof(OLink));

           if(!(*Q).chead)

                     exit(0);

           for(k=1;k<=(*Q).mu;k++)//初始化Q的行头指针向量;各行链表为空链表

                     (*Q).rhead[k]=NULL;

           for(k=1;k<=(*Q).nu;k++)//初始化Q的列头指针向量;各列链表为空链表

                     (*Q).chead[k]=NULL;

           //生成指向列的最后结点的数组

           col=(OLink*)malloc(((*Q).nu+1)*sizeof(OLink));

           if(!col)

                     exit(0);

           for(k=1;k<=(*Q).nu;k++)//赋初值

                     col[k]=NULL;

           for(i=1;i<=M.mu;i++)//按行的顺序相加

           {

                     pm=M.rhead[i];//pm指向矩阵M的第i行的第1个结点

                     pn=N.rhead[i];//pn指向矩阵N的第i行的第1个结点

                     while(pm&&pn)//pmpn均不空

                     {

                                if(pm->j<pn->j)//矩阵M当前结点的列小于矩阵N当前结点的列

                                {

                                          p=(OLink)malloc(sizeof(OLNode));//生成矩阵Q的结点

                                         if(!p)

                                                     exit(0);

                                          (*Q).tu++;//非零元素数加1

                                          p->i=i;//给结点赋值

                                          p->j=pm->j;

                                          p->e=pm->e;

                                          p->right=NULL;

                                          pm=pm->right;//pm指针向右移

                                }

                                //矩阵M当前结点的列大于矩阵N当前结点的列

                                elseif(pm->j>pn->j)

                                {

                                          p=(OLink)malloc(sizeof(OLNode));//生成矩阵Q的结点

                                         if(!p)

                                                     exit(0);

                                          (*Q).tu++;//非零元素数加1

                                          p->i=i;//给结点赋值

                                           p->j=pn->j;

                                          p->e=-pn->e;

                                          p->right=NULL;

                                          pn=pn->right;//pn指针向右移

                                }

                                elseif(pm->e-pn->e)

                                {

                                         //矩阵MN当前结点的列相等且两元素之差不为0

                                          p=(OLink)malloc(sizeof(OLNode));//生成矩阵Q的结点

                                         if(!p)

                                                     exit(0);

                                          (*Q).tu++;//非零元素数加1

                                          p->i=i;//给结点赋值

                                          p->j=pn->j;

                                          p->e=pm->e-pn->e;

                                          p->right=NULL;

                                          pm=pm->right;//pm指针向右移

                                          pn=pn->right;//pn指针向右移

                                }

                                else//矩阵MN当前结点的列相等且两元素之差为0

                                {

                                          pm=pm->right;//pm指针向右移

                                          pn=pn->right;//pn指针向右移

                                         continue;

                                }

                                if((*Q).rhead[i]==NULL)//p为该行的第1个结点

                                         //p插在该行的表头且pq指向p(该行的最后一个结点)

                                                     (*Q).rhead[i]=pq=p; 

                                else//插在pq所指结点之后

                                {

                                          pq->right=p;//完成行插入

                                          pq=pq->right;//pq指向该行的最后一个结点

                                }

                                if((*Q).chead[p->j]==NULL)//p为该列的第1个结点

                                         //p插在该列的表头且col[p->j]指向p

                                                     (*Q).chead[p->j]=col[p->j]=p; 

                                else//插在col[p->]所指结点之后

                                {

                                          col[p->j]->down=p;//完成列插入

                                         //col[p->j]指向该列的最后一个结点

                                          col[p->j]=col[p->j]->down; 

                                }

                     }

                     while(pm)//将矩阵M该行的剩余元素插入矩阵Q

                     {

                                p=(OLink)malloc(sizeof(OLNode));//生成矩阵Q的结点

                                if(!p)

                                          exit(0);

                                (*Q).tu++;//非零元素数加1

                                p->i=i;//给结点赋值

                                p->j=pm->j;

                                p->e=pm->e;

                                p->right=NULL;

                                pm=pm->right;//pm指针向右移

                                if((*Q).rhead[i]==NULL)//p为该行的第1个结点

                                         //p插在该行的表头且pq指向p(该行的最后一个结点)

                                                     (*Q).rhead[i]=pq=p; 

                                else//插在pq所指结点之后

                                {

                                          pq->right=p;//完成行插入

                                          pq=pq->right;//pq指向该行的最后一个结点

                                }

                                if((*Q).chead[p->j]==NULL)//p为该列的第1个结点

                                         //p插在该列的表头且col[p->j]指向

                                                     (*Q).chead[p->j]=col[p->j]=p;

                                else//插在col[p->j]所指结点之后

                                {

                                          col[p->j]->down=p;//完成列插入

                                         //col[p->j]指向该列的最后一个结点

                                          col[p->j]=col[p->j]->down; 

                                }

                     }

                     while(pn)//将矩阵N该行的剩余元素插入矩阵Q

                     {

                                p=(OLink)malloc(sizeof(OLNode));//生成矩阵Q的结点

                                if(!p)

                                          exit(0);

                                (*Q).tu++;//非零元素数加1

                                p->i=i;//给结点赋值

                                p->j=pn->j;

                                p->e=-pn->e;

                                p->right=NULL;

                                pn=pn->right;//pm指针向右移

                                if((*Q).rhead[i]==NULL)//p为该行的第1个结点

                                         //p插在该行的表头且pq指向p(该行的最后一个结点)

                                                     (*Q).rhead[i]=pq=p; 

                                else//插在pq所指结点之后

                                {

                                          pq->right=p;//完成行插入

                                          pq=pq->right;//pq指向该行的最后一个结点

                                }

                                if((*Q).chead[p->j]==NULL)//p为该列的第1个结点

                                         //p插在该列的表头且col[p->j]指向p

                                                     (*Q).chead[p->j]=col[p->j]=p; 

                                else//插在col[p->j]所指结点之后

                                {

                                          col[p->j]->down=p;//完成列插入

                                         //col[p->j]指向该列的最后一个结点 

                                          col[p->j]=col[p->j]->down;

                                }

                     }

           }

           for(k=1;k<=(*Q).nu;k++)

                     if(col[k])//k列有结点

                                col[k]->down=NULL;//令该列最后一个结点的down指针为空

           free(col);

           return1;

}

// 求稀疏矩阵乘积Q=M*N

int MultSMatrix(CrossListM,CrossListN,CrossList *Q)

{

           inti,j,e;

           OLinkq,p0,q0,q1,q2;

 

           InitSMatrix(Q);

           (*Q).mu=M.mu;

           (*Q).nu=N.nu;

           (*Q).tu=0;

           (*Q).rhead=(OLink*)malloc(((*Q).mu+1)*sizeof(OLink));

           if(!(*Q).rhead)

                     exit(0);

           (*Q).chead=(OLink*)malloc(((*Q).nu+1)*sizeof(OLink));

           if(!(*Q).chead)

                     exit(0);

           for(i=1;i<=(*Q).mu;i++)//初始化矩阵Q的行头指针向量;各行链表为空链表

                     (*Q).rhead[i]=NULL;

           for(i=1;i<=(*Q).nu;i++)//初始化矩阵Q的列头指针向量;各列链表为空链表

                     (*Q).chead[i]=NULL;

           for(i=1;i<=(*Q).mu;i++)

                     for(j=1;j<=(*Q).nu;j++)

                     {

                                p0=M.rhead[i];

                                q0=N.chead[j];

                                e=0;

                                while(p0&&q0)

                                {

                                         if(q0->i<p0->j)

                                                     q0=q0->down;//列指针后移

                                         elseif(q0->i>p0->j)

                                                     p0=p0->right;//行指针后移

                                         else//q0->i==p0->j

                                          {

                                                     e+=p0->e*q0->e;//乘积累加

                                                     q0=q0->down;//行列指针均后移

                                                     p0=p0->right;

                                          }

                                }

                                if(e)//值不为0

                                {

                                          (*Q).tu++;//非零元素数加1

                                           q=(OLink)malloc(sizeof(OLNode));//生成结点

                                         if(!q)//生成结点失败

                                                     exit(0);

                                          q->i=i;//给结点赋值

                                          q->j=j;

                                          q->e=e;

                                          q->right=NULL;

                                          q->down=NULL;

                                         if(!(*Q).rhead[i])//行表空时插在行表头

                                                     (*Q).rhead[i]=q1=q;

                                         else//否则插在行表尾

                                                     q1=q1->right=q;

                                         if(!(*Q).chead[j])//列表空时插在列表头

                                                     (*Q).chead[j]=q;

                                         else//否则插在列表尾

                                          {

                                                     q2=(*Q).chead[j];//q2指向j行第1个结点

                                                    while(q2->down)

                                                               q2=q2->down;//q2指向j行最后1个结点

                                                     q2->down=q;

                                          }

                                }

                     }

                     return1;

}

//  求稀疏矩阵M的转置矩阵T

int TransposeSMatrix(CrossListM,CrossList *T)

{

           intu,i;

           OLink*head,p,q,r;

 

           if((*T).rhead)

                     DestroySMatrix(T);

           CopySMatrix(M,T);//T=M

           u=(*T).mu;//交换(*T).mu(*T).nu

           (*T).mu=(*T).nu;

           (*T).nu=u;

           head=(*T).rhead;//交换(*T).rhead(*T).chead

           (*T).rhead=(*T).chead;

           (*T).chead=head;

           for(u=1;u<=(*T).mu;u++)//T的每一行

           {

                     p=(*T).rhead[u];//p为行表头

                     while(p)//没到表尾,T的每一结点

                     {

                                q=p->down;//q指向下一个结点

                                i=p->i;//交换.i.j

                                p->i=p->j;

                                p->j=i;

                                r=p->down;//交换.down.right

                                p->down=p->right;

                                p->right=r;

                                p=q;//p指向下一个结点

                     }

           }

           return1;

}

int main()

{

           CrossListA,B,C;

           InitSMatrix(&A);//CrossList类型的变量在初次使用之前必须初始化

           InitSMatrix(&B);

           printf("创建矩阵A: ");

           CreateSMatrix(&A);

           PrintSMatrix(A);

           printf("由矩阵A复制矩阵B:");

           CopySMatrix(A,&B);

           PrintSMatrix(B);

           DestroySMatrix(&B);//CrossList类型的变量在再次使用之前必须先销毁

           printf("销毁矩阵B:\n");

           PrintSMatrix(B);

           printf("创建矩阵B2:(与矩阵A的行、列数相同,行、列分别为%d,%d)\n",

                     A.mu,A.nu);

           CreateSMatrix(&B);

           PrintSMatrix(B);

           printf("矩阵C1(A+B): ");

           AddSMatrix(A,B,&C);

           PrintSMatrix(C);

           DestroySMatrix(&C);

           printf("矩阵C2(A-B): ");

           SubtSMatrix(A,B,&C);

           PrintSMatrix(C);

           DestroySMatrix(&C);

           printf("矩阵C3(A的转置): ");

           TransposeSMatrix(A,&C);

           PrintSMatrix(C);

           DestroySMatrix(&A);

           DestroySMatrix(&B);

           DestroySMatrix(&C);

           printf("创建矩阵A2: ");

           CreateSMatrix(&A);

           PrintSMatrix(A);

           printf("创建矩阵B3:(行数应与矩阵A2的列数相同=%d)\n",A.nu);

           CreateSMatrix(&B);

           PrintSMatrix(B);

           printf("矩阵C5(A*B): ");

           MultSMatrix(A,B,&C);

           PrintSMatrix(C);

           DestroySMatrix(&A);

           DestroySMatrix(&B);

           DestroySMatrix(&C);

           system("pause");

           return0;

}

 

 

 

 

 

 

 

 

 

 

 

 

 

阅读全文
0 0
原创粉丝点击