稀疏矩阵的创建--十字链表

一:概念

    既然要用链表节点来模拟矩阵中的非零元素,肯定需要如下5个元素(row,col,val,down,right),其中:

row:矩阵中的行。

col:矩阵中的列。

val:矩阵中的值。

right:指向右侧的一个非零元素。

down:指向下侧的一个非零元素。


      现在我们知道单个节点该如何表示了,那么矩阵中同行的非零元素的表示不就是一个单链表吗?比如如下:



       那么进一步来说一个多行的非零元素的表示不就是多个单链表吗,是的,这里我把单链表做成循环链表,我们来看看如何用十字链表来表示稀疏矩阵。



从上面的十字链表中要注意两个问题:

第一:这里有一个填充色的节点,是十字链表中的总结点,它是记录该矩阵中的(row,col,value)和一个指向下一个头节点的next指针。

第二:每个链表都有一个头指针,总结点用next指针将它们贯穿起来。

二、稀疏矩阵的创建过程

1、稀疏矩阵节点的定义

typedef struct OLNode {    
     int  i, j;          //行号与列号     
     ElemType e;        //值     
     struct OLNode *right, *down;  //指针域     
}OLNode, *OList; 
2、为了创建稀疏矩阵,除了需要知道行数、列数和非零个数以外,还需要创建行头指针和列头指针,定义如下:

typedef struct {    
    OLink   *Rhead, *Chead;     
    int mu, nu, tu;       // 稀疏矩阵的行数、列数和非零元个数      
}CrossList;    
3、稀疏矩阵的代码

int CreateSMatrix(CrossList *M)    
{     
 int i, j, m, n, t;    
 int k, flag;    
 ElemType e;    
 OLNode *p, *q;    
  //输入稀疏矩阵的基本信息   
 if (M->Rhead)    
  DestroySMatrix(M); do {    
  flag = 1;    
  printf("输入需要创建的矩阵的行数、列数以及非零元的个数");    
  scanf("%d%d%d", &m, &n, &t);    
  if (m<0 || n<0 || t<0 || t>m*n)    
   flag = 0;    
 }while (!flag);    
 M->mu = m;    
 M->nu = n;    
 M->tu = t;    
     
 //创建行链表头数组     
 M->Rhead = (OLink *)malloc((m+1) * sizeof(OLink));    
 if(!M->Rhead)    
  exit(-1);    
 //创建列链表头数组     
 M->Chead = (OLink *)malloc((n+1) * sizeof(OLink));    
 if(!(M->Chead))    
  exit(-1);  

 for(k=1;k<=m;k++) // 初始化行头指针向量;各行链表为空链表      
  M->Rhead[k]=NULL;    
 for(k=1;k<=n;k++) // 初始化列头指针向量;各列链表为空链表      
  M->Chead[k]=NULL; 
   
 //输入各个结点     
 for (k=1; k<=t; ++k)    
 {    
  do {    
   flag = 1;    
   printf("输入第%d个结点行号、列号以及值", k);    
   scanf("%d%d%d", &i, &j, &e);    
   if (i<=0 || j<=0)    
    flag = 0;    
  }while (!flag);  p = (OLink) malloc (sizeof(OLNode));    
  if (NULL == p)    
   exit(-1);    
  p->i = i;    
  p->j = j;    
  p->e = e;    
//节点的行插入
  if(NULL==M->Rhead[i] || M->Rhead[i]->j>j)        //-----(1)
  {    
   // p插在该行的第一个结点处     
   // M->Rhead[i]始终指向它的下一个结点     
    
   p->right = M->Rhead[i];    
   M->Rhead[i] = p;    
  }    
  else // 寻查在行表中的插入位置     
  {    
   //从该行的行链表头开始,直到找到     
   for(q=M->Rhead[i]; q->right && q->right->j < j; q=q->right) ; //----(2) 
      
   p->right=q->right; // 完成行插入      
   q->right=p;    
  } 
//节点的列插入
 if(NULL==M->Chead[j] || M->Chead[j]->i>i)     
  {    
   p->down = M->Chead[j];    
   M->Chead[j] = p;    
  }    
  else // 寻查在列表中的插入位置     
  {    
   //从该列的列链表头开始,直到找到     
   for(q=M->Chead[j]; q->down && q->down->i < i; q=q->down)     
    ;    
   p->down=q->down; // 完成行插入      
   q->down=p;    
  }    
 } return 1;    
}  
4、代码的部分解释

(1)怎么去找到要插入的正确位置。当行中有结点的时候我们无非就是插入到某个结点之前或者之后。那么我们再回到前面,在我们定义Rhead的时候就说过,某一行的表头指针指向的就是该行中第一个结点的地址。我们假设该行中已经有了一个结点我们称它为A结点,如果要插在A结点之前那么A结点的列号必定是大于我们输入的结点(我们称它为P结点)的列号的。我们的插入操作就要修改头指针与p结点的right域。就像链表中的插入。那么当该行中没有结点的时候我们怎么去插入?同样是修改头指针让它指向我们的P结点,同样要修改P结点的right域。看,我们可以利用if语句来实现这两种条件的判断。

(2)重点关注:for循环后紧跟" ; ",

         现在我们再想一下怎么去插入到某一个结点的后面? 我们新创建的P结点要插入到现有的A结点的后面,那么P的列号必定是大于A的列号,那么我们只要找到第一个大于比P的列号大的结点B,然后插入到B结点之前!如果现有的结点没有一个结点列号是大于P结点的列号的,那么我们就应该插入到最后一个结点之后!所以我们首先要寻找符合条件的位置进行插入  。

         





  • 10
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值