【数据结构】NOJ013 以十字链表为存储结构实现矩阵相加(1.0)

本文介绍了使用十字链表作为存储结构来实现矩阵相加的过程。作者分享了编写Add函数时遇到的困难,以及Delete函数中忽视删除首节点的情况。此外,还提到测试与调试中的经验教训,包括内存分配检测的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

//【数据结构】NOJ013 以十字链表为存储结构实现矩阵相加
#include <stdio.h>
#include <stdlib.h>


//十字链表
typedef int ElemType;   //元素类型


typedef struct LNode{
    int Row,Col;    //行数、列数
    ElemType Elem;  //元素
    struct LNode *Right,*Down; //右侧、下侧
}LNode,*PLNode;


typedef struct CrossList{
    int mu,nu,tu;   //总行数、总列数、总个数
    PLNode *rHead,*cHead;    //存放指向首结点的指针的数组
}*CList;


CList Init(int m,int n,int t);  //初始化并插入初始元素
void Add(CList L1,CList L2);    //矩阵相加存入L1
int Insert(CList L, PLNode N);   //插入一个元素
void Delete(CList L,PLNode p);  //删除一个元素
void Output(CList L);           //按行输出


CList Init(int m,int n,int t)
{//初始化,插入初始元素
    //初始化
    CList L=(CList)malloc(sizeof(struct CrossList));
    L->mu=m;    L->nu=n;    L->tu=t;
    L->rHead=(PLNode*)malloc((m+1)*sizeof(LNode));
    L->cHead=(PLNode*)malloc((n+1)*sizeof(LNode));
    int i;
    for(i=0;i<m;i++)    L->rHead[i+1]=NULL;
    for(i=0;i<n;i++)    L->cHead[i+1]=NULL;


    //插入t个元素
    for(i=0;i<t;i++){
        //新建结点
        PLNode N=(PLNode)malloc(sizeof(struct LNode));
        N->Right=N->Down=NULL;
        scanf("%d %d %d",&N->Row,&N->Col,&N->Elem);
        //插入结点
        Insert(L,N);
    }
    return L;
}//Init


void Add(CList L1,CList L2)
{//相加结果存在L1中
    if(!L1->tu) L1=L2;  //L1为空
    else if(L2->tu){    //L1、L2均不为空
        PLNode P;   //遍历L2中结点
        int i;
        for(i=1;i<L2->mu+1;i++){
            P=L2->rHead[i];
            while(P){
                PLNode Q=(PLNode)malloc(sizeof(struct LNode));
                Q->Col=P->Col;
                Q->Row=P->Row;
                Q->Elem=P->Elem;
                Q->Down=Q->Right=NULL;
                Insert(L1,Q);
                P=P->Right;
            }
        }
    }
}//Add


int Insert(CList L,PLNode N)
{//插入一个元素,若L中已有就将元素值相加,若相加为0就删除
    int col=N->Col,row=N->Row;
    PLNode q;    //结点N应插入到q之后


    //查找相同位置的元素
    for(q=L->rHead[row];(q)&&((q->Col) < N->Col);q=q->Right)
        ;
    if(q&&(q->Col==N->Col)){          //将对应元素相加
        q->Elem+=N->Elem;
        if(q->Elem==0)Delete(L,q);    //如果相加为0,则删除该结点
        return 0;
    }


    //若L中没有相同位置的元素则插入该元素
    //插入行中
    if(!L->rHead[row]||((L->rHead[row]->Col)>N->Col)){  //此行为空或首节点的列数大于待插入结点列数
        N->Right=L->rHead[row];L->rHead[row]=N;     //作为首节点插入该行
    }
    else{   //寻找待插入位置q
        for(q=L->rHead[row];(q->Right)&&((q->Right->Col) < N->Col);q=q->Right)
            ;
        N->Right=q->Right;q->Right=N;   //将N插入到q之后
    }//行插入完成


    //插入列中
    if(!L->cHead[col]||((L->cHead[col]->Row)> N->Row)){   //此列为空或首节点的行数大于待插入结点行数
        N->Down=L->cHead[col];L->cHead[col]=N;          //作为首节点插入该列
    }
    else{   //寻找待插入位置q
        for(q=L->cHead[col];(q->Down)&&((q->Down->Row) < N->Row);q=q->Down)
            ;
        N->Down=q->Down;q->Down=N;  //将N插入到q之下
    }//列插入完成
    return 0;
}//Insert


void Delete(CList L,PLNode p)
{
    PLNode Del=p;    //记录待删除结点位置


    PLNode Tmp=L->rHead[Del->Row];
    if(Tmp==Del)L->rHead[Del->Row]=Del->Right;  //待删除结点为首节点
    else{
        while(Tmp->Right!=Del)Tmp=Tmp->Right; //寻找该结点在行中位置
        Tmp->Right=Del->Right;    //从行中删除
    }


    Tmp=L->cHead[Del->Col];
    if(Tmp==Del)L->cHead[Del->Col]=Del->Down;  //待删除结点为首节点
    else{
        while(Tmp->Down!=Del)Tmp=Tmp->Down; //寻找该结点在列中位置
        Tmp->Down=Del->Down;    //从列中删除
    }


    free(Del);  //终于删除掉了。。。
}//Delete


void Output(CList L)
{//按行输出
    if(L->tu){
        int i;
        PLNode P;
        for(i=1;i<L->mu+1;i++)
            for(P=L->rHead[i];P;P=P->Right)
                printf("%d %d %d\n",P->Row,P->Col,P->Elem);
    }
    else printf("Empty.");
}//Output


int main()
{
    int m,n,t1,t2;
    scanf("%d %d %d %d",&m,&n,&t1,&t2);
    CList L1=Init(m,n,t1);
    CList L2=Init(m,n,t2);
    //Insert(L1,1,1,-1);
    Add(L1,L2);
    Output(L1);
    //Output(L2);
    return 0;
}

【后记】

1.这段裹脚布代码写了将近六个小时才ac,期间Add函数“遍历L2中元素结点”的写法还偷窥了薛学长的博客才有思路。

2.最开始写的时候,是想把Insert函数的参数设为“待插入结点的行数、列数、元素值”,打算把Init和Insert统一起来,然而没成功,遂将其参数改为“待插入结点”

3.Delete函数最开始没有考虑到删除首节点的情况

4.昨晚写的时候测试了一些数据是对的,然而还是WA,以为是换行问题调了好久(也没调成功),结果发现不是这个问题

5.感觉自己不检测分配内存成功与否总有一天是要出事儿的,然而……

6.遗憾是Insert函数需要区别“已有元素”的情况,Delete函数需要从头遍历删除位置,看起来很难受……

7.出现的各种bug:没有初始化结点的指针Right、Down为NULL、插入位置的if-else分类条件搞不清……

8.ac了好开心哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值