数据结构27:矩阵加法(基于十字链表)

本文介绍了如何使用十字链表法解决稀疏矩阵相加问题。通过详细阐述十字链表的结构和节点操作,展示了如何在矩阵相加过程中判断和处理元素位置,以及提供了完整的代码演示。十字链表法在处理非0元素较少的矩阵时能有效节省存储空间,并且在算法时间复杂度上具有优势。
摘要由CSDN通过智能技术生成

矩阵之间能够进行加法运算的前提条件是:各矩阵的行数和列数必须相等。

在行数和列数都相等的情况下,矩阵相加的结果就是矩阵中对应位置的值相加所组成的矩阵,例如:

图1 矩阵相加

十字链表法

之前所介绍的都是采用顺序存储结构存储三元组,在类似于矩阵的加法运算中,矩阵中的数据元素变化较大(这里的变化主要为:非0元素变为0,0变为非0元素),就需要考虑采用另一种结构——链式存储结构来存储三元组。

采用链式存储结构存储稀疏矩阵三元组的方法,称为“十字链表法”。

十字链表法表示矩阵

例如,用十字链表法表示矩阵 A ,为:  
图2 矩阵用十字链表法表示
 
由此可见,采用十字链表表示矩阵时,矩阵的每一行和每一个列都可以看作是一个单独的链表,而之所以能够表示矩阵,是因为行链表和列链表都分别存储在各自的数组中
图 2 中:存储行链表的数组称为 rhead 数组;存储列链表的数组称为 chead 数组。

十字链表中的结点

从图2中的十字链表表示矩阵的例子可以看到,十字链表中的结点由 5 部分组成:
图3 十字链表中的结点
指针域A存储的是矩阵中结点所在列的下一个结点的地址(称为 “down域”);
指针域B存储的是矩阵中该结点所在行的下一个结点的地址(称为 “right域”);

用结构体自定义表示为:
typedef struct OLNode
{
  int i, j, e;   //矩阵三元组 i 代表行 j 代表列 e 代表当前位置的数据
  struct OLNode *right, *down; //指针域 右指针 下指针
}OLNode, *OLink;

 

十字链表的结构

使用十字链表表示一个完整的矩阵,在了解矩阵中各结点的结构外,还需要存储矩阵的行数、列数以及非 0 元素的个数,另外,还需要将各结点链接成的链表存储在数组中。

所以,采用结构体自定义十字链表的结构,为:
typedef struct
{
  OLink *rhead, *chead;   //存放各行和列链表头指针的数组
  int mu, nu, tu;       //矩阵的行数,列数和非零元的个数
}CrossList;

十字链表存储矩阵三元组

由于三元组存储的是该数据元素的行标、列标和数值,所以,通过行标和列标,就能在十字链表中唯一确定一个位置。

判断方法为:在同一行中通过列标来判断位置;在同一列中通过行标来判断位置。

首先判断该数据元素 A(例如三元组为:(i,j,k))所在行的具体位置:
  • 如果 A 的列标 j 值比该行第一个非 0 元素 B 的 j 值小,说明该数据元素在元素 B 的左侧,这时 A 就成为了该行第一个非0元素(也适用于当该行没有非 0 元素的情况,可以一并讨论)
  • 如果 A 的列标 j 比该行第一个非 0 元素 B 的 j 值大,说明 A 在 B 的右侧,这时,就需要遍历该行链表,找到插入位置的前一个结点,进行插入。

对应行链表的位置确定之后,判断数据元素 A 在对应列的位置:
  • 如果 A 的行标比该列第一个非 0 元素 B 的行标 i 值还小,说明 A 在 B 的上边,这时 A 就成了该列第一个非 0 元素。(也适用于该列没有非 0 元素的情况)
  • 反之,说明 A 在 B 的下边,这时就需要遍历该列链表,找到要插入位置的上一个数据元素,进行插入。

实现代码:
//创建系数矩阵M,采用十字链表存储表示
CrossList CreateMatrix_OL(CrossList M)
{
  int m,n,t;
  int i,j,e;
  OLNode *p,*q;//定义辅助变量
  scanf("%d%d%d",&m,&n,&t); //输入矩阵的行列及非零元的数量
  //初始化矩阵的行列及非零元的数量
  M.mu=m;
  M.nu=n;
  M.tu=t;
  if(!(M.rhead=(OLink*)malloc((m+1)*sizeof(OLink)))||!(M.chead=(OLink*)malloc((n+1)*sizeof(OLink))))
  {
    printf("初始化矩阵失败");
    exit(0); //初始化矩阵的行列链表
  }
  for(i=1;i<=m;i++)
  {
    M.rhead[i]=NULL; //初始化行
  }
  for(j=1;j<=n;j++)
  {
    M.chead[j]=NULL; //初始化列
  }
  for(scanf("%d%d%d",&i,&j,&e);0!=i;scanf("%d%d%d",&i,&j,&e)) 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值