【问题描述】两个相同行数和列数的稀疏矩阵用十字链表实现加法运算
【数据描述】
typedef struct ele {/* 十字链表结点类型*/
int row, col;
double val;
struct ele *right, *down;
}eleNode;
【算法描述】
(1) 若q->j>v->j,则需要在C矩阵的链表中插入一个值为bij的结点,,修改v=v->right。
(2) 如q->j<v->j,则需要在C矩阵的链表中插入一个值为aij的结点,修改q=q->right。
(3) 若q->j = = v->j且q->e + v->e ! = 0,则需要在C矩阵的链表中插入一个值为aij+bij的结点,修改q=q->right,v=v->right。
重复(1)--(3)完成一行的操作。修改p=p->down,u=u->down后,再继续下一行。【C源程序】
#include <stdio.h>
#include <malloc.h>
typedef struct ele {/* 十字链表结点类型*/
int row,col;
int val;
struct ele *right,*down;
}eleNode;
/*建立一个元素全为零的稀疏矩阵的十字链表*/
eleNode *createNullMat(int m,int n) / * m行n列 */
{eleNode *h,*p;
int k;
h=(eleNode *)malloc(sizeof(eleNode)); /*十字链表头结点 */
h->row=m;h->col=n;h->val=0; / * 行数、列数和非零元素个数 */
h->right=(eleNode *)malloc(sizeof(eleNode)*n);
h->down=(eleNode *)malloc(sizeof(eleNode)*m);
for(p=h->down,k=0;k<m;k++,p++){
p->col=1000; / * 设矩阵不会超过1000列 */
p->right=p; / * 每个行链表是一个环 * /
p->down=k<m-1?p+1:h->down; / * 使全部行链表头结点构成环*/
}
for(p=h->right,k=0;k<n;k++,p++){
p->row=1000; / * 设矩阵不会超过1000行 * /
p->down = p; / * 每个列链表是一个环 * /
p->right = k<n-1 ? p+1 : h->right; / *使全部列链表头结点构成环 * /
}
return h;
}
//
int insertNode(eleNode *a ,int row,int col,double val){
/* 在十字链表中插入一个结点*/
eleNode *p,*q,*r,*u,*v;
if(row>=a->row||col>=a->col) return -2; / * 不合理的行列号 * /
r=(eleNode *)malloc(sizeof(eleNode));
r->row=row;r->col=col;r->val=val;
p=a->down+row;q=p->right;
while(q->col<col){p=q;q=q->right;}
if(q->col==col) return -1; / * 该行已有col列元素 * /
u=a->right+col;v=u->down;
while(v->row<row){u=v;v=v->down;}
if(v->row==row) return -1; / * 该列已有row行元素 * /
p->right = r; r->right = q; / * 插入到行链中 * /
u->down = r; r->down = v; / * 插入到列链中 * /
a->val=val;
return 0; / * 插入成功 * /
}
eleNode *readMat(){
/*输入数据建立十字链表*/
eleNode *h;
int i,j,m,n;
int v;
printf("输入稀疏矩阵的行数和列数");
scanf("%d%d",&m,&n);
h=createNullMat(m,n);
printf("输入有非零元素的行号");
scanf("%d",&i);
while(i>=0) / * 逐行输入非零元素 * /
{ printf("输入非零元素的列号");
scanf("%d",&j);
while(j>=0) / * 输入一行非零元素 * /
{ printf("输入非零元素的值");
scanf("%d",&v);
insertNode(h,i,j,v);
printf("输入当前行下一个非零元素的列号(-1表示当前行一组数据结束)");
scanf("%d",&j);
}
printf("输入下一行有非零元素的行号(-1表示输入结束)");
scanf("%d",&i);
}
return h;
}
void showMat(eleNode *a)
{int row,col,i,j;
eleNode *p;
row=a->row;
col=a->col;
for (i=0;i<row;i++)
{ p=a->down+i;
p=p->right;
for(j=0;j<col;j++)
{ if(p->row==i&&p->col==j) {printf("%d ",p->val);p=p->right;}
else
printf("0 ");
}
printf("/n");
}
}
eleNode *matAdd(eleNode *a,eleNode *b)
{eleNode *r,*p,*q,*u,*v;
r=createNullMat(a->row,a->col);
p=a->down;u=b->down;
do { / * 逐行相加 * /
q=p->right;v=u->right;
while(q!=p||v!=u) / * 两矩阵中有一个一行未结束循环 */
if(q->col==v->col){ / * 有相同列的元素 * /
if(q->val+v->val!=0) / * 和非零插入 * /
insertNode(r,q->row,q->col,q->val+v->val);
q=q->right;v=v->right;
}
else if(q->col<v->col){ / * 插入a的元素 * /
insertNode(r,q->row,q->col,q->val);
q=q->right;
}
else{ / * 插入b的元素 * /
insertNode(r,v->row,v->col,v->val);
v=v->right;
}
p=p->down;u=u->down;
}while(p!=a->down);
return r;
}
void main()
{ eleNode *a,*b,*c;
a=readMat();
printf("a/n");
showMat(a);
b=readMat();
printf("b/n");
showMat(b);
c= matAdd(a,b);
printf("c/n");
showMat(c);
}
【测试数据】
输入a 矩阵: 4 0 0 0 输入b矩阵: 0 1 0 1 输出:4 1 0 1
0 5 0 9 0 –5 0 0 0 0 0 9
0 0 1 0 1 0 9 0 1 0 10 0
输入数据注意事项:
(1)如上面a矩阵,应输入3行4列
(2)若某行有非零元素,则按下列格式(三元组格式)输入:
行号 列号 值 列号 值 … 列号 值 -1,如a矩阵的第0行,应输入0 0 4 -1,最后 的-1表示该行的一组数据输入结束。
(3)按以上格式逐行地输入数据,直到输入的行号的值为-1时,表示稀疏矩阵的全部数据输入结束。
【说明】
从一个结点来看,进行比较、修改指针所需的时间是一个常数;整个运算过程在于对A和B的十字链表逐行扫描,其循环次数主要取决于A和B矩阵中非零元素的个数ta和tb;由此算法的时间复杂度为O(ta+tb)。