基于十字链表的稀疏矩阵加法

稀疏矩阵加法(十字链表)

问题描述

若将稀疏矩阵 \mathbf{A}A 的非零元素以行序为主序的顺序存于一维数组 VV 中,并用二维数组 BB 表示 AA 中的相应元素是否为零元素(以0和1分别表示零元素和非零元素)。例如,
矩阵A
可以使用一个数组和一个01矩阵表示在这里插入图片描述

试写一算法,实现在上述表示法中实现矩阵相加的运算。并分析你的算法时间复杂度(在代码注释中给出)。


输入

在这里插入图片描述

输出

在这里插入图片描述

输入输出样例

输入:

2 2
1 1
1 0
0 1
-2 -1
1 0
0 1

输出:

-1
1 0
0 0

代码

#include <stdio.h>
#include <stdlib.h>
//十字链表的结点
typedef struct olnode{
    //line
    int i;
    //row
    int j;
    //elemtype
    int e;
    //right
    struct olnode *right;
    //down
    struct olnode *down;
}ol;

//存储行和列的头
typedef struct {
    ol *rhead[100];
    ol *chead[100];
    //line
    int mu;
    //row
    int nu;
    //element
    int tu;
}crosslist;

//申请内存
ol *lalloc(void){
    return (ol *)malloc(sizeof(ol));
}

int main(){
    int m,n;
    //读入行数和列数
    scanf("%d %d\n",&m,&n);

    //获取输入并返回数组长度
    int getinput(int *p);
    //获取输入的矩阵
    crosslist getarray(crosslist p,int v[]);
    //初始化头链表
    crosslist initialhead(crosslist p);
    //相加
    crosslist addarray(crosslist a,crosslist b);
    void addnode(crosslist p,int ia,int ja,int k,int v[]);
    //打印v数组
    void printv(crosslist a);
    //打印01矩阵
    void printm(crosslist a);

    //根据行数和列数
    int va[m*n];
    int vb[m*n];
    int vc[m*n];

    //存储行和列的头
    crosslist listheada;
    crosslist listheadb;
    listheada.mu=m;
    listheada.nu=n;
    listheadb.mu=m;
    listheadb.nu=n;
    listheada=initialhead(listheada);
    listheadb=initialhead(listheadb);
    //读入va
    listheada.tu=getinput(va);
    int i,j;
    //读入数组a
    listheada=getarray(listheada,va);
    //读入vb
    listheadb.tu=getinput(vb);
    //读入数组b
    listheadb=getarray(listheadb,vb);
    //相加
    listheada=addarray(listheada,listheadb);

    //输出
    printv(listheada);
    printm(listheada);
    
    return 0;
}

//读入数组va,p为数组名
int getinput(int *p){
    int c;
    int i=0;
    //符号位
    int sig=1;
	c=getchar();
    if(c=='\n'){
        c=getchar();
    }
    while(c!='\n'){
        sig=1;
		//printf("read\n");
        if(c==' '){
            i++;
            c=getchar();
        }
        if(c=='-'){
            sig=-1;
            c=getchar();
        }
        p[i]=c-'0';
        while((c=getchar())!='\n'&&c!=' '){
            p[i]=p[i]*10+c-'0';
        }
        //符号位
        p[i]=p[i]*sig;
    }
    return i+1;
}

//读入二维数组作为矩阵,p为二维数组名
crosslist getarray(crosslist p,int v[]){
    int i,j;
    //表示获取的输入的值
    int c;
    //对v数组计数
    int k=0;
    ol *pwork;
    ol *ppoint;
    for(i=0;i<p.mu;i++){
        for(j=0;j<p.nu;j++){
            scanf("%d",&c);
            if(c==1){
                //addnode(p,i,j,k,v);
                ppoint=lalloc();
                ppoint->i=i;
                ppoint->j=j;
                ppoint->e=v[k];
                //此处应初始化为null不然扫描时可能会出错吧
                ppoint->down=NULL;
                ppoint->right=NULL;

                //先完成行插入
                pwork=p.rhead[i];
                while(pwork->right!=NULL){
                pwork=pwork->right;
            }
                pwork->right=ppoint;

                //完成列插入
                pwork=p.chead[j];
                while(pwork->down!=NULL){
                pwork=pwork->down;
            }
            pwork->down=ppoint;
    
                k++;
            }
        }
    }
    return p;
}

//在十字链表中增加结点,i,j为行,k为va中的位置

//行和列的头初始化
crosslist initialhead(crosslist p){
    int i;
    ol *pwork;
    //将行的头结点初始化
    for(i=0;i<p.mu;i++){
        pwork=lalloc();
        pwork->down=NULL;
        pwork->right=NULL;
        p.rhead[i]=pwork;
    }
    //将列的头结点初始化
    for(i=0;i<p.nu;i++){
        pwork=lalloc();
        pwork->down=NULL;
        pwork->right=NULL;
        p.chead[i]=pwork;
    }
    
    return p;
}

//O(ta+tb),
//因为输出只要打印所以输出破坏了链表,
//列并没有连接,只连接了行
crosslist addarray(crosslist a,crosslist b){
    int i,j;
    ol *pa;
    ol *pb;
    ol *pre;
    //记录pa和pb下一个要处理的结点
    ol *pbnext;
    //ol *panext;
    //逐行扫描
    
    for(i=0;i<a.mu;i++){
        //初始化行
        pa=a.rhead[i]->right;
        pre=a.rhead[i];
        pb=b.rhead[i]->right;
        //扫描pb并将其中行结点插入a中
        while(pb!=NULL){
            pbnext=pb->right;
            if(pa==NULL || pa->j>pb->j){
                //需要新增结点,pa不需要移动
                pb->right=pa;
                pre->right=pb;
                pre=pb;
                //处理完当前pb结点,移到下一个
                pb=pbnext;
                //多了一个数
                a.tu++;
            }else if(pa!=NULL && pa->j<pb->j){
                //pb没有对应结点,不操作,pa需要移动
                pre=pa;
                pa=pa->right;
                //未处理pb结点,不移动
            }else if(pa->j==pb->j){
                //pa,pb同时有,增加
                pa->e+=pb->e;
                //此处pa是否移动都可以吧
                //不可以!!!
                //pa=pa->right;
                //和为0,删除该结点
                if(pa->e==0){
                    pre->right=pa->right;
                    pa=pa->right;
                    //少了一个数
                    a.tu--;
                }
                //pa=pa->right;
                //处理了pb结点,移动
                pb=pbnext;
            }
        }
    }
    return a;
}

//怎么能不输出空格啊
//有了,记录有多少数
void printv(crosslist a){
    int i;
    ol *p;
    int count=0;
    if(a.tu==0)
		printf("\n");
    for(i=0;i<a.mu;i++){
        p=a.rhead[i]->right;
        while(p!=NULL){
            count++;
            if(count<a.tu){
                printf("%d ",p->e);
            }else if(count==a.tu){
                printf("%d\n",p->e);
            }else{
                printf("\n");
            }
            p=p->right;
        }
    }
}

void printm(crosslist a){
    int i,j;
    ol *p;

    for(i=0;i<a.mu;i++){
        p=a.rhead[i]->right;
        for(j=0;j<a.nu-1;j++){
            if(p!=NULL && j<p->j){
                printf("0 ");
            }else if(p!=NULL && j==p->j){
                printf("1 ");
                //打印当前结点,右移
                p=p->right;
            }else if(p!=NULL && j>p->j){
                printf("error:j>p->j\n");
            }else if(p==NULL){
                printf("0 ");
            }
        }
        //打印最后一个结点
        if(p==NULL){
            printf("0\n");
        }else{
            printf("1\n");
        }
        
    }
}

原本是将addnode单独写为一个函数,但是不知为何一直报错,所以就直接将代码加到getarray中了
备注写的很详细呀,如果有什么问题欢迎一起讨论~

  • 4
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
十字链表是一种用于表示稀疏矩阵的数据结构,它可以高效地存储和处理稀疏矩阵。 在进行十字链表稀疏矩阵加法时,我们需要进行以下步骤: 1. 创建两个稀疏矩阵十字链表表示。 2. 初始化一个新的十字链表来存储结果矩阵。 3. 遍历两个输入矩阵的十字链表,同时进行如下操作: a. 如果两个链表的行号和列号相等,说明有相同的元素可以相加,将它们的值相加,并将结果插入到结果链表中。 b. 如果链表1的行号小于链表2的行号,说明链表1中存在元素而链表2中不存在,直接将链表1的元素插入结果链表中。 c. 如果链表2的行号小于链表1的行号,说明链表2中存在元素而链表1中不存在,直接将链表2的元素插入结果链表中。 4. 返回结果链表作为结果矩阵。 这样,我们就可以实现两个稀疏矩阵的加法操作。 当进行稀疏矩阵加法时,可能会遇到以下问题: 1. 如何创建十字链表表示稀疏矩阵:可以使用一个结构体来表示每个元素,结构体包含行号、列号和值等信息。然后,使用链表来存储这些结构体,同时使用一维数组来存储每个行和列的头指针。 2. 如何处理两个链表的合并:可以使用双指针来遍历两个链表,根据行号和列号的大小关系来决定插入哪个元素到结果链表中,然后将指针移动到下一个节点。 3. 如何处理相同位置的元素相加:可以直接将两个元素的值相加,并将结果插入到结果链表中。 相关问题: 1. 如何实现稀疏矩阵的乘法? 2. 如何实现稀疏矩阵的转置? 3. 如何实现稀疏矩阵的压缩存储? 4. 如何实现稀疏矩阵的逆转?

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值