我第一下拿到这个题目,第一反应就是先定义好数据结构,然后构建好十字链表基础操作的函数,也就是“创插遍历”这些操作。下面是我的定义和函数操作。

typedef int ElemType;
typedef struct OLNode{
    int i,j;//行号和列号
    ElemType elem;
    struct OLNode *right;//右边元素 
    struct OLNode *down;//下边元素 
}OLNode,*OLink;

typedef struct CrossList{
    OLink* rHead;
    OLink* cHead;
    int mu,nu,tu;//行数、列数、非零元个数 
}CrossList;

CrossList* CreateOLSMatrix(int r,int c,int t){//创建目标十字链表的表头 
    CrossList* p=(CrossList*)malloc(sizeof(CrossList));
    if(p==NULL){
        printf("Out of space!");
    }
    p->mu=r;
    p->nu=c;
    p->tu=t;
    p->rHead=(OLink*)malloc((r+1)*sizeof(OLink));
    p->cHead=(OLink*)malloc((c+1)*sizeof(OLink));
    if(p->rHead==NULL||p->cHead==NULL) printf("Out of space!\n");
    for(int i=0;i<r+1;i++){
        p->rHead[i]=NULL;
    }//强迫症,初始化操作 
    for(int i=0;i<c+1;i++){
        p->cHead[i]=NULL;
    }//强迫症,初始化操作 
    return p;
}

void InsertMatrix(CrossList* p,int i,int j,int elem){//插入数据
    OLink p1=(OLink)malloc(sizeof(OLNode));
    if(p1==NULL) printf("Out of space!\n");
    p1->i=i;p1->j=j;p1->elem=elem;
    //创建并填充结点
    
    if(p->rHead[i]==NULL||p->rHead[i]->j>j){
        p1->right=p->rHead[i];
        p->rHead[i]=p1; 
    }else{
            OLink q=p->rHead[i];
            while(1){
                if(q->right==NULL||q->right->j>j) break;
                q=q->right;
            }//找到插入位置
            p1->right=q->right;
            q->right=p1;
        }//完成行插入
        
    if(p->cHead[j]==NULL||p->cHead[j]->i>i){
        p1->down=p->cHead[j];
        p->cHead[j]=p1;
    }else{
            OLink q=p->cHead[j];
            while(1){
                if(q->down==NULL||q->down->i>i) break;
                q=q->down;
            }//找到插入位置
            p1->down=q->down;
            q->down=p1; 
        }//完成列插入 
}

int BuildMatrix(CrossList* p){//完善表
    for(int k=1;k<=p->tu;k++){
        int i,j,elem;
        scanf("%d%d%d",&i,&j,&elem);
        InsertMatrix(p,i,j,elem);
    }
}

int OutputMatrix(CrossList* p){//输出表
    for(int i=1;i<=p->mu;i++){
        OLink q=p->rHead[i];
        for(int j=1;j<=p->nu;j++){
            if(q!=NULL&&j==q->j){
                printf("%d %d %d\n",q->i,q->j,q->elem);
                q=q->right;
            }
        }
    }//按照先行后列的顺序输出 
}

其中插入数据这个函数有点难。

我们在插入元素时,既要完成行插入,又要完成列插入。虽然这两个步骤基本类似,但我还是建议大家不要看行插入步骤,独立敲一遍列插入步骤。记住,不要着急,不要浮躁,静下心来,不要害怕说你同学就因此速度比你快,然后他就能做更多的练习,最后绩点比你高,拿了奖学金最后跟你炫耀,打击挖苦你,嘲讽你。大学里面最可恶的不是不学习的人,而是那些”欻欻欻写完作业,然后把你搞得浮躁,搞崩你的心态,最后嘲讽你不如他,还拿到了奖学金”的人。(就和考理综的时候,第一考场总有人来回翻卷子,就是为了搞崩你的心态)。不要慌,稳下来,因为你一慌,他们的目的就达到了。再回到这道题,如果你复制粘贴过来,很多东西你会忘记调整为列,而且Debug的时候,大家的第一反应都是先关注行,所以忽视了列,如果列插入上出了问题,是很难很难找出来错误的,不信大家看我下面的例子:

if(p->cHead[j]==NULL||p->cHead[j]->i>i){
        p1->down=p->rHead[j];//1
        p->rHead[j]=p1;//2
    }else{
            OLink q=p->rHead[j];//3
            while(1){
                if(q->down==NULL||q->down->i>i) break;
                q=q->down;
            }//找到插入位置
            p1->down=q->down;
            q->down=p1; 
        }//完成列插入

上面3处就是我复制过来以后,忘记调整过来的地方,如果只输出i=2这一行的第2个元素,结果是下面这样,根本就不正确。

3 3 3
1 0 2
2 1 2
2 2 3

--------------------------------
Process exited after 16.53 seconds with return value 3221225477
请按任意键继续. . .

正确的代码应该把这3处给改掉,像下面这样:

if(p->cHead[j]==NULL||p->cHead[j]->i>i){
        p1->down=p->cHead[j];//1
        p->cHead[j]=p1;//2
    }else{
            OLink q=p->cHead[j];//3
            while(1){
                if(q->down==NULL||q->down->i>i) break;
                q=q->down;
            }//找到插入位置
            p1->down=q->down;
            q->down=p1; 
        }//完成列插入

最后,也就是咱们程序的核心:“矩阵相加”了:

int AddMatrix(CrossList* p1,CrossList* p2,CrossList* p3){//矩阵相加得到新矩阵p3 
    for(int i=1;i<=p1->mu;i++){
        //先行后列,一点一点地来做 
        OLink temp1=p1->rHead[i];
        OLink temp2=p2->rHead[i];
        for(int j=1;j<=p1->nu;j++){
            int flag1=temp1!=NULL&&j==temp1->j;
            int flag2=temp2!=NULL&&j==temp2->j;
            //为什么我要用flag呢?因为都放在if后面的话,if会变的很长很长,超级麻烦 
            if(flag1==1&&flag2!=1){//如果这个位置上,p1有数据,p2没数据 
                InsertMatrix(p3,temp1->i,temp1->j,temp1->elem);
                temp1=temp1->right;
            }
            if(flag1!=1&&flag2==1){//如果这个位置上,p1没数据,p2有数据 
                InsertMatrix(p3,temp2->i,temp2->j,temp2->elem);
                temp2=temp2->right;
            }
            if(flag1==1&&flag2==1){//如果这个位置上,p1有数据,p2也有数据 
                int total=temp1->elem+temp2->elem;
                if(total==0){
                    p3->tu=p3->tu-2;
                    //如果p1的数据与p2的数据相加为0,那就不用插入
                    //别忘了p3中非零元素要减2
                }else if(total!=0){
                    InsertMatrix(p3,temp1->i,temp1->j,total);
                    p3->tu--;
                }//如果相加和不为0,那么把和total插入。
                 //别忘了p3中非零元素要自减 
                temp1=temp1->right;
                temp2=temp2->right;
            }
        }
    }
}

最后总结一下,有一些特别容易错的地方,而且不容易Debug出来:

1.插入元素时,既要完成行插入,又要完成列插入。虽然这两个步骤基本类似,但还是建议大家不要看行插入步骤,独立敲一遍列插入步骤。

2.注意三元组表的行数是从1开始,列数也是从1开始,所以在设置for循环时,要注意应该设置成:

for(int i=1;i<=...;i++)

不应该设置成:

for(int i=0;i<...;i++)

这也就是为什么,在对CrossList型变量的rHead动态分配空间时,要多分配1个的原因,就是因为下标为0的位置不可以使用。

p->rHead=(OLink*)malloc((r+1)*sizeof(OLink));

3.在进行矩阵相加时,特殊情况优先考虑,即优先考虑“矩阵p1和p2在i行j列上都有元素”的情况,这个时候就要根据相加和来判断了。如果相加和为0,该怎么处理;如果相加和不为0,又该怎么处理,不管你怎么做,都要记住一点:"temp1=temp1->right;temp2=temp2->right;"

4.不要忘记考虑相加和为0的情况,这种情况不能插到新表里面去。(详见我的上一篇文章)(8条消息) 西工大NOJ数据结构实验——2.2稀疏矩阵加法,实现C=A+B_没耳朵的Rabbit的博客-CSDN博客

5.最后,提供一个测试用例,兴许对你有帮助(直接复制粘贴到exe黑框里面就行)

3 3 9 9
1 1 1
1 2 2
1 3 3
2 1 4
2 2 5
2 3 6
3 1 7
3 2 8
3 3 9
1 1 9
1 2 8
1 3 7
2 1 6
2 2 5
2 3 4
3 1 3
3 2 2
3 3 1

1 1 10
1 2 10
1 3 10
2 1 10
2 2 10
2 3 10
3 1 10
3 2 10
3 3 10

--------------------------------
Process exited after 13.05 seconds with return value 0
请按任意键继续. . .

最后,还是完整的代码:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
typedef int ElemType;
typedef struct OLNode{int i,j;//行号和列号ElemType elem;struct OLNode *right;//右边元素 struct OLNode *down;//下边元素
}OLNode,*OLink;typedef struct CrossList{OLink* rHead;OLink* cHead;int mu,nu,tu;//行数、列数、非零元个数
}CrossList;CrossList* CreateOLSMatrix(int r,int c,int t){//创建目标十字链表的表头 CrossList* p=(CrossList*)malloc(sizeof(CrossList));if(p==NULL){printf("Out of space!");}p->mu=r;p->nu=c;p->tu=t;p->rHead=(OLink*)malloc((r+1)*sizeof(OLink));p->cHead=(OLink*)malloc((c+1)*sizeof(OLink));if(p->rHead==NULL||p->cHead==NULL) printf("Out of space!\n");for(int i=0;i<r+1;i++){p->rHead[i]=NULL;}//强迫症,初始化操作 for(int i=0;i<c+1;i++){p->cHead[i]=NULL;}//强迫症,初始化操作 return p;
}void InsertMatrix(CrossList* p,int i,int j,int elem){//插入数据OLink p1=(OLink)malloc(sizeof(OLNode));if(p1==NULL) printf("Out of space!\n");p1->i=i;p1->j=j;p1->elem=elem;//创建并填充结点if(p->rHead[i]==NULL||p->rHead[i]->j>j){p1->right=p->rHead[i];p->rHead[i]=p1; }else{OLink q=p->rHead[i];while(1){if(q->right==NULL||q->right->j>j) break;q=q->right;}//找到插入位置p1->right=q->right;q->right=p1;}//完成行插入if(p->cHead[j]==NULL||p->cHead[j]->i>i){p1->down=p->cHead[j];p->cHead[j]=p1;}else{OLink q=p->cHead[j];while(1){if(q->down==NULL||q->down->i>i) break;q=q->down;}//找到插入位置p1->down=q->down;q->down=p1; }//完成列插入
}int BuildMatrix(CrossList* p){//完善表for(int k=1;k<=p->tu;k++){int i,j,elem;scanf("%d%d%d",&i,&j,&elem);InsertMatrix(p,i,j,elem);}
}int OutputMatrix(CrossList* p){//输出表for(int i=1;i<=p->mu;i++){OLink q=p->rHead[i];for(int j=1;j<=p->nu;j++){if(q!=NULL&&j==q->j){printf("%d %d %d\n",q->i,q->j,q->elem);q=q->right;}}}//按照先行后列的顺序输出
}int AddMatrix(CrossList* p1,CrossList* p2,CrossList* p3){//矩阵相加得到新矩阵p3 for(int i=1;i<=p1->mu;i++){//先行后列,一点一点地来做 OLink temp1=p1->rHead[i];OLink temp2=p2->rHead[i];for(int j=1;j<=p1->nu;j++){int flag1=temp1!=NULL&&j==temp1->j;int flag2=temp2!=NULL&&j==temp2->j;//为什么我要用flag呢?因为都放在if后面的话,if会变的很长很长,超级麻烦 if(flag1==1&&flag2!=1){//如果这个位置上,p1有数据,p2没数据 InsertMatrix(p3,temp1->i,temp1->j,temp1->elem);temp1=temp1->right;}if(flag1!=1&&flag2==1){//如果这个位置上,p1没数据,p2有数据 InsertMatrix(p3,temp2->i,temp2->j,temp2->elem);temp2=temp2->right;}if(flag1==1&&flag2==1){//如果这个位置上,p1有数据,p2也有数据 int total=temp1->elem+temp2->elem;if(total==0){p3->tu=p3->tu-2;//如果p1的数据与p2的数据相加为0,那就不用插入//别忘了p3中非零元素要减2}else if(total!=0){InsertMatrix(p3,temp1->i,temp1->j,total);p3->tu--;}//如果相加和不为0,那么把和total插入。//别忘了p3中非零元素要自减 temp1=temp1->right;temp2=temp2->right;}}}
}int main(){//int r,c,t1;//scanf("%d%d%d",&r,&c,&t1);int r,c,t1,t2;scanf("%d%d%d%d",&r,&c,&t1,&t2);//输入行数、列数、两个矩阵的非零元个数 CrossList* p1=CreateOLSMatrix(r,c,t1);CrossList* p2=CreateOLSMatrix(r,c,t2);CrossList* p3=CreateOLSMatrix(r,c,t1+t2);//创建三个十字链表的表头//其中p3表示最终相加得到的十字链表 //p1+p2时,可能会有元素合并,或者合并之后结果为0之类的情况出现,导致p3中非零元素小于t1+t2//但是方便起见,还是记非零元素个数为t1+t2//要是真有元素合并,以及合并之后结果为0,那“非零元素-1”这一步到时候再做也不迟 BuildMatrix(p1);BuildMatrix(p2);AddMatrix(p1,p2,p3);OutputMatrix(p3);return 0;
}

如果对你有帮助的话,就请麻烦点个赞叭

真心希望点赞加关注哦

你们的鼓励是我创作路上的不竭动力

谢谢大家!

西工大NOJ数据结构理论——013.以十字链表为存储结构实现矩阵相加(严5.27)相关推荐

  1. 西工大NOJ数据结构理论——021.逆波兰表达式(严7.38)

    这道题我参考的是(80条消息) 『西工大-数据结构-NOJ』 021-逆波兰表达式(耿7.38) 『西北工业大学』__LanXiu的博客-CSDN博客 (准确来说是快期末考试了,所以各科老师都在疯 狂 ...

  2. 西工大NOJ数据结构理论——017.输出以二叉树表示的算术表达式(严6.51)

    (17条消息) 『西工大-数据结构-NOJ』 017-输出以二叉树表示的算术表达式(耿6.51) 『西北工业大学』__LanXiu的博客-CSDN博客 上面是我参考的一位学长的博客. 先序建立二叉树, ...

  3. 西工大NOJ数据结构理论——007.表达式括号与匹配(严3.19)

    害怕提交次数过多,然后不再跑代码,影响成绩,所以又重新创建了两个号来测这道题. 结果全都正确,但就是一直"WA",然后Debug了近5个小时才把"WA"改成&q ...

  4. 西工大NOJ数据结构理论——015.建立二叉树的二叉链表存储结构(严6.70)

    我相信,大家都已经了解了这道题的背景,以及明白了我们需要做的事情. 对于这道题的背景,相信大家都熟悉,所以就不说了. 关于我们需要做的事情,大家也已经有了自己的思路.所以,我只在下面简短的写一写我的思 ...

  5. 西工大NOJ数据结构理论——018.建立二叉树的二叉链表(严6.65)

    刚点开这道题以后,我的反应是: 1.打开老师发的PPT:DS-Chap6,然后翻到第70页: 2.跟着图解,自己照着画了三四遍(其实是抄了三四遍: 3.然后自己出了一个比较简单的题: 先序:ABDCE ...

  6. 西工大NOJ数据结构理论——010.k阶斐波那契数列(严3.32)

    k阶斐波那契序列定义:第k和k+1项为1,前k - 1项为0,从k项之后每一项都是前k项的和 k=2时,斐波那契序列为:0,1,1,2,3,5,8,13... k=3时,斐波那契序列为:0,0,1,1 ...

  7. 西工大NOJ数据结构理论——001.顺序表的插入运算(耿2.4)

    #include<stdio.h> #include<string.h> #include<stdlib.h> typedef struct NODE {int n ...

  8. 西工大NOJ数据结构理论——016.计算二叉树叶子结点数目(耿6.14)

    一.初级思路 拿到题之后的好习惯--先在纸上写思路: 1.构建二叉树: char* BinTreeBuilding(PBinTreeNode ptr_node,char *ptr_str){//创建二 ...

  9. 西工大NOJ数据结构理论——019.基于图的深度优先搜索策略(耿7.10)

    临近期末考了,所以思路来不及整理了,但大家还是可以仿照我的上几篇文章,"先动笔,再代码"的思路还是不变的. #include<stdio.h> #include< ...

最新文章

  1. oracle查询不走索引全表扫描,使用索引快速全扫描(Index FFS)避免全表扫描的若干场景-Oracle...
  2. python 操作mysql 返回字典_Python查询Mysql时返回字典结构的代码
  3. oracle中同义词的用法,Oracle中使用同义词介绍
  4. access 导入 txt sql语句_从零开始学习 MySQL 系列索引、视图、导入和导出
  5. KUKA profesafe
  6. Ajax基本案例详解之$.get的实现
  7. date format 精辟讲解
  8. delphi listview1添加指定列_对表格的列进行批量处理的函数详解
  9. 动态规划——乘积为正数的最长子数组长度(Leetcode 1567)
  10. jsonp和ajax的区别,dataType jsonp和JSON之间的区别
  11. platform总线注册过程及platform_driver与platform_device的匹配
  12. 工行u盾显示316_工行U盾只显示金融@家怎么显密码
  13. python+qqbot实现qq聊天机器人
  14. java 微信图片上传_后台Java代码加前端微信小程序实现图片上传案例(学习)
  15. deny后加to do还是doing_还在为动词后面接不定式还是动名词而发愁?点开解惑
  16. 手风琴式折叠html,基于jQuery实现以手风琴方式展开和折叠导航菜单
  17. cpu第几代计算机,赛扬G系列有几代cpu分别是
  18. CAD-Cass小结(4)——Cass、CAD对图像校正与等高线矢量化
  19. ubuntu20.4安装谷歌
  20. iphoneX系列手机在页面滚动时隐藏底部的操作栏

热门文章

  1. matlab井函数,用MATLAB函数解承压含水层完整井非稳定流问题
  2. 响应式与自适应设计:设计师的最佳选择是什么?
  3. vue学习笔记--动画
  4. 寄存器(RAL)模型中的write方法
  5. 双幂数列(C++)M={2^x,3^y|x=0,y=0}
  6. 代码审计--13--源代码审计思路(下)
  7. css+js制作循环轮播图——可滑动
  8. python爬取豆瓣电影名称、评分
  9. ctrl+alt+t 函数注释快捷键失效KoroFileHeader
  10. Python数据处理DataFrame小记