拓展阅读4——稀疏矩阵的十字链表

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

MLink CreatMLink( int m,int n,int t,int s)
/* 建立稀疏矩阵的十字链表*/

MLink H;
MNode *p,*q,*hd[s+1];
int i,j;
Datatype v;
H=(MNode*)malloc(sizeof(MNode));
/*申请总头结点*/
H->row=m; H->col=n;
q->down=pa->down;
free (pa);
pa=qa;
} /*if (x==0)*/
else /*第一种情况*/
{
pa->v_next.v=x;
qa=pa;
}
pa=pa->right;
pb=pb->right; } } /*while*/ ca=ca->v_next.next; cb=cb->v_next.next; } while (ca->row==0) return Ha; }
hd[0]=H;
for(i=1; i<=s; i++)
{
p=(MNode*)malloc(sizeof(MNode));
/*申请第 i 个头结点*/
Fra Baidu bibliotek
p->row=0; p->col=0;
p->right=p; p->down=p;
hd[i]=p;
hd[i-1]->v_next.next=p;
}
hd[s]->v_next.next=H;
{
if (pa->col < pb->col && pa->col !=0 )
/*第三种情况*/
{
qa=pa;
pa=pa->right;
}
else
if (pa->col > pb->col || pa->col ==0 )
/*第四种情况*/
{
p=(MNode *)malloc(sizeof(MNode));
上时,对 A 十字链表的当前结点来说,对应下列四种情况:或者改变结点的值(aij+bij≠0),
或者不变(bij=0),或者插入一个新结点(aij=0),还可能是删除一个结点(aij+bij=0)。
整个运算从矩阵的第一行起逐行进行。对每一行都从行表的头结点出发,分别找到 A
和 B 在该行中的第一个非零元素结点后开始比较,然后按4种不同情况分别处理。设 pa 和
第 i 个行链表中去,同时也按其行号的大小将该结点插入到第 j 个列链表中去。在算法中将
利用一个辅助数组 MNode *hd[s+1],其中 s=max(m , n) , hd [i]指向第 i 行(第 i 列)链表的头
结点。这样做可以在建立链表时随机的访问任何一行(列),为建表带来方便。
【算法 5-4】:
稀疏矩阵的十字链表
1.建立稀疏矩阵 A 的十字链表
首先输入的信息是:m(A 的行数),n(A 的列数),r(非零元的个数),紧跟着输入
的是 r 个形如(i,j,aij)的三元组。
算法的设计思想是:首先建立每行(每列)只有表头结点的空链表,并建立起这些头结
点拉成的循环链表;然后每输入一个三元组(i,j,aij),则将其结点按其列号的大小插入到
/*十字链表表示的稀疏矩阵的加法*/
{
MNode *p,*q,*pa,*pb,*ca,*cb,*qa;
if (Ha->row!=Hb->row || Ha->col!=Hb->col) return NULL;
ca=Ha->v_next.next;
/*ca 初始指向 A 矩阵中第一行表头结点*/
cb=Hb->v_next.next;
p-> down =q-> down; q-> down =p; }/*for k*/ return H; } /* CreatMLink */
/*按行号找位置*/ /*插入*/
上述算法中,建立头结点循环链表时间复杂度为 O(s),插入每个结点到相应的行表和 列表的时间复杂度是 O(t*s),这是因为每个结点插入时都要在链表中寻找插入位置,所以总 的时间复杂度为 O(t*s)。
/*ca 指向 A 中下一行的表头结点*/ /*cb 指向 B 中下一行的表头结点*/
/*当还有未处理完的行则继续*/
为 了 保 持 算 法 的 层 次 , 在 上 面 的 算 法 , 用 到 了 一 个 函 数 Find_JH 。 函 数 Mlink Find_JH(MLink H, int j)的功能是:返回十字链表 H 中第 j 列链表的头结点指针,读者可 自行写出。
if (x==0)
/*第二种情况*/
{
qa->right=pa->right;
./*从行链中删除*/
/*还要从列链中删除,找*pa 的列前驱结点*/
q= Find_JH (Ha,pa->col);
/*从列链表的头结点找起*/
while ( q->down->row < pa->row )
q=q->down;
p->row=pb->row; p->col=pb->col; p->v=pb->v;
p->right=pa;qa->right=p;
/* 新结点插入*pa 的前面*/
pa=p;
/*新结点还要插到列链表的合适位置,先找位置,再插入*/
q=Find_JH(Ha,p->col);
/*从列链表的头结点找起*/
while(q->down->row!=0 && q->down->row<p->row)
q=q->down;
p->down=q->down;
/*插在*q 的后面*/
q->down=p;
pb=pb->right;
} /* if */
else
/*第一、二种情况*/
{
x= pa->v_next.v+ pb->v_next.v;
/*将头结点们形成循环链表*/
for (k=1;k<=t;k++)
{
scanf (“%d,%d,%d”,&i,&j,&v);
/*输入一个三元组,设值为 int*/
p=(MNode*)malloc(sizeof(MNode));
p->row=i ; p->col=j; p->v_next.v=v;
/*以下是将*p 插入到第 i 行链表中去*/
q=hd[i];
while (q->right!=hd[i] && (q->right->col)<j )
/*按列号找位置*/
q=q->right;
p->right=q->right;
/*插入*/
q->right=p;
/*以下是将*p 插入到第 j 列链表中去,且按行号有序*/
q=hd[j];
while (q->down!=hd[j] && (q->down->row)<i ) q=q->down;
结点,此时需改变该行链表中前趋结点的 right 域,以及该列链表中前趋结点的 down 域。
(3)若 pa->col < pb->col 且 pa->col≠0(即不是表头结点),则只需要将 pa 指针向右
推进一步,并继续进行比较。
(4)若 pa->col > pb->col 或 pa->col=0(即是表头结点),则需要在矩阵 A 的十字链表
pb 分别指向 A 和 B 的十字链表中行号相同的两个结点,4种情况如下:
(1)若 pa->col=pb->col 且 pa->v+pb->v≠0,则只要用 aij+bij 的值改写 pa 所指结点的值
域即可。
(2)若 pa->col=pb->col 且 pa->v+pb->v=0,则需要在矩阵 A 的十字链表中删除 pa 所指
/*cb 初始指向 B 矩阵中第一行表头结点*/
do {
pa=ca->right;
/*pa 指向 A 矩阵当前行中第一个结点*/
qa=ca;
/*qa 是 pa 的前驱*/
pb=cb->right;
/*pb 指向 B 矩阵当前行中第一个结点*/
while (pb->col!=0)
/*当前行没有处理完*/
中插入一个 pb 所指结点。
由前面建立十字链表算法知,总表头结点的行列域存放的是矩阵的行和列,而各行(列)
链表的头结点其行列域值为零,当然各非零元素结点的行列域其值不会为零,下面分析的 4
种情况利用了这些信息来判断是否为表头结点。
【算法 5-5】:
MLink AddMat (MLink Ha, MLink Hb)
2.两个十字链表表示的稀疏矩阵的加法**
已知两个稀疏矩阵 A 和 B,分别采用十字链表存储,计算 C=A+B,C 也采用十字链表
方式存储,并且在 A 的基础上形成 C。
由矩阵的加法规则知,只有 A 和 B 行列对应相等,二者才能相加。C 中的非零元素 cij
只可能有3种情况:或者是 aij+bij,或者是 aij (bij=0),或者是 bij (aij=0),因此当 B 加到 A
相关文档
最新文档