码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2015-06-28 09:54:07      阅读:218      评论:0      收藏:0      [点我收藏+]

标签:

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.

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

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

 

typedef struct OLNode

{

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

         ElemTypee;    // 非零元素值

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

}OLNode, *OLink;

typedef struct//行和列链表头指针向量基址,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(CrossList M)

{

         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;

}

 

7.  复制矩阵

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

 

int CopySMatrix(CrossList M,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(CrossList M,CrossList N,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指针向右移

                            }

                            else 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=pn->j;

                                     p->e=pn->e;

                                     p->right=NULL;

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

                            }

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

                            else if(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(CrossList M,CrossList N,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;//列指针后移

                                     else if(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(CrossList M,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"

typedef int ElemType;//稀疏矩阵的十字链表存储表示

 

typedef struct OLNode

{

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

         ElemTypee;    // 非零元素值

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

}OLNode, *OLink;

typedef struct//行和列链表头指针向量基址,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(CrossList M)

{

         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(CrossList M,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(CrossList M,CrossList N,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指针向右移

                            }

                            else 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=pn->j;

                                     p->e=pn->e;

                                     p->right=NULL;

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

                            }

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

                            else if(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(CrossList M,CrossList N,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当前结点的列

                            else if(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指针向右移

                            }

                            else if(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(CrossList M,CrossList N,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;//列指针后移

                                     else if(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(CrossList M,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;

}

 

 

 

 

 

 

 

 

 

 

 

 

 

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

标签:

原文地址:http://blog.csdn.net/notbaron/article/details/46664727

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!