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

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)    // pm和pn均不空

{

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

}

//矩阵M、N当前结点的列相等且两元素之和不为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 //矩阵M、N当前结点的列相等且两元素之和为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]指向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]指向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;

}

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)    // pm和pn均不空

{

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

}

//矩阵M、N当前结点的列相等且两元素之和不为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 //矩阵M、N当前结点的列相等且两元素之和为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]指向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]指向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 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)//pm和pn均不空

{

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)

{

//矩阵M、N当前结点的列相等且两元素之差不为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 //矩阵M、N当前结点的列相等且两元素之差为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]指向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]指向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;

}

时间: 2024-08-05 11:17:50

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

48. 蛤蟆的数据结构笔记之四十八的有向无环图的应用关键路径

48. 蛤蟆的数据结构笔记之四十八的有向无环图的应用关键路径 本篇名言:"富贵不淫贫贱乐 ,男儿到此是豪雄.-- 程颢" 这次来看下有向无环图的另一个应用关键路径. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47135061 1.  关键路径 与AOV-网相对应的是AOE-网(Activity On Edge)即边表示活动的网.AOE-网是一个带权的有向无环图,其中,顶点表示事件(Event),弧表示活动,权表

19、 蛤蟆的数据结构笔记之十九链表实现等价类寻找

19. 蛤蟆的数据结构笔记之十九链表实现等价类寻找 本篇名言:"人生有两出悲剧:一是万念俱灰,另一是踌躇满志." 继续来看下通过链表存储实现等价类寻找. 欢迎转载,转载请标明出处: 1.  等价类 等价类(Equivalenceclass)在数学中,给定一个集合 X 和在 X 上的一个等价关系 ~,则 X 中的一个元素 a 的等价类是在 X 中等价于 a 的所有元素构成的集合: a= { X ; X ~ a } 2.  实现 输入一个size,然后初始化out和seq数组. 然后输入数

15、蛤蟆的数据结构笔记之十五栈的应用之栈与递归之八皇后问题

15.蛤蟆的数据结构笔记之十五栈的应用之栈与递归之八皇后问题 本篇名言:"人的一生应当这样度过:当回忆往事的时候,他不致于因为虚度年华而痛悔,也不致于因为过去的碌碌无为而羞愧:在临死的时候,他能够说:"我的整个生命和全部精力,都已经献给世界上最壮丽的事业--为人类的解放而斗争." 继续递归问题,本次是经典的八皇后问题: 欢迎转载,转载请标明出处: 1.  八皇后问题 八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例.该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出

42. 蛤蟆的数据结构笔记之四十二图的遍历之广度优先

42. 蛤蟆的数据结构笔记之四十二图的遍历之广度优先 本篇名言:"生活真象这杯浓酒 ,不经三番五次的提炼呵 , 就不会这样一来可口 ! -- 郭小川" 继续看下广度优先的遍历,上篇我们看了深度遍历是每次一个节点的链表是走到底的. 欢迎转载,转载请标明出处:http://write.blog.csdn.net/postedit/47029275 1.  原理 首先,从图的某个顶点v0出发,访问了v0之后,依次访问与v0相邻的未被访问的顶点,然后分别从这些顶点出发,广度优先遍历,直至所有的

49. 蛤蟆的数据结构笔记之四十九图的连通性问题

49. 蛤蟆的数据结构笔记之四十九图的连通性问题 本篇名言:"我们不得不饮食.睡眠.游惰.恋爱,也就是说,我们不得不接触生活中最甜蜜的事情:不过我们必须不屈服于这些事物 .....--约里奥?居里"     此篇就作为数据结构入门笔记的最后一篇吧. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47135259 设图G=(V,E)是一个无向图,G的一个连通分支是一个最大的连通子图,即一个连通分支是不包含在任何更大的

46. 蛤蟆的数据结构笔记之四十六普里姆算法

46. 蛤蟆的数据结构笔记之四十六普里姆算法 本篇名言:"手莫伸 ,伸手必被捉.党与人民在监督 ,万目睽睽难逃脱.汝言惧捉手不伸 ,他道不伸能自觉 , 其实想伸不敢伸 ,人民咫尺手自缩.-- 陈毅" 连通图的生成树是一个极小的连通子图,它含有图中全部的顶点,但只有足以构成一棵树的n-1条边.所谓的最小成本,就是n个顶点,用n-1条边把一个连通图连接起来,并且使得权值的和最小.构造连通网的最小代价生成树,即最小生成树(Minimum Cost Spanning Tree). 找连通图的最

44. 蛤蟆的数据结构笔记之四十四弗洛伊德Floyd算法

44. 蛤蟆的数据结构笔记之四十四弗洛伊德Floyd算法 本篇名言:"希望是厄运的忠实的姐妹. --普希金" 我们继续来看下数据结构图中的一个算法,这个算法来自图灵奖得主. 1.  Floyd算法介绍 Floyd算法又称为插点法,是一种用于寻找给定的加权图中多源点之间最短路径的算法.该算法名称以创始人之一.1978年图灵奖获得者.斯坦福大学计算机科学系教授罗伯特·弗洛伊德命名.注意这个可不是心理学的那个弗洛伊德. 是解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权的最短路径

34. 蛤蟆的数据结构笔记之三十四树的概念

34. 蛤蟆的数据结构笔记之三十四树的概念 本篇名言:"过去属于死神,未来属于你自己.--雪莱" 本篇笔记开始我们要进入新的概念了,树!是不是有点小激动呢?让我们从概念开始吧 当然概念要理解,如果当前不能立刻理解,可以后续结合代码一起理解效果更佳. 1.  树型结构 之前我们学习的那么多,其实都是线性数据结构. 树 则不同,它是非线性结构. 树形结构指的是数据元素之间存在着"一对多"的树形关系的数据结构,是一类重要的非线性数据结构.在树形结构中,树根结点没有前驱结点

30. 蛤蟆的数据结构笔记之三十数组之厄拉多塞筛

30. 蛤蟆的数据结构笔记之三十数组之厄拉多塞筛 本篇名言:"勤劳远比黄金可贵. -- 萨迪" 欢迎转载,转载请标明出处: 1.  厄拉多塞 厄拉多塞是一位古希腊数学家,他在寻找素数时,采用了一种与众不同的方法:先将2-N的各数放入表中,然后在2的上面画一个圆圈,然后划去2的其他倍数:第一个既未画圈又没有被划去的数是3,将它画圈,再划去3的其他倍数:现在既未画圈又没有被划去的第一个数是5,将它画圈,并划去5的其他倍数--依次类推,一直到所有小于或等于N的各数都画了圈或划去为止.这时,表