稀疏矩阵十字链表的储存形式(十字链表的创建与相加)

矩阵十字链表的储存形式(十字链表的创建与相加)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct node
{
    int i,j;
    int elem;
    struct node *right,*down;
}cnode,*clink;
typedef struct
{
    clink *rhead,*chead;  //这个的确是指针的指针,一维只要一维指针,二维需要指针的指针来定位
    int m,n,len;
}clist;                   //clist 是二维平面的开始点,原点

// 创造十字链表是采用头插法的
/*
   行的创造
   如果该行的头结点后面为空,直接插在后面
   如果该行的头结点不为空,但后面节点的列值更大,新来的节点插在头结点后面
   新来的节点的列值跟大,则插在已存在节点的后面
   同理,列也是这样判断如何插
*/
void createcrosslist(clist *x,int m,int n,int t)
{
   int cnt;
   int x1,x2,x3;
   cnode* y;
   clink z;
   int i;
   x->m=m;
   x->n=n;
   x->len=t;
   if(!(x->rhead=(clink *)malloc((m+2)*sizeof(clink))))//三重平面理解,之前的链表是二重平面,在函数里,因为->的出现,所以三重变四重,二重变三重
   exit(0);                                            //节点指针的指针
   if(!(x->chead=(clink *)malloc((n+2)*sizeof(clink))))
   exit(0);
   for(cnt=0;cnt<=m;cnt++)//这样既处理了可能有0行0列的问题  chead[],rhead[]存的节点cnode的地址
   {
       x->rhead[cnt]=NULL;
   }
   for(cnt=0;cnt<=n;cnt++)
   {
      x->chead[cnt]=NULL;
   }
   for(i=0;i<t;i++)
   {
     scanf("%d%d%d",&x1,&x2,&x3);
     if(!(y=(cnode *)malloc(sizeof(cnode))))//因为->操作,指针变量和非指针变量都是要让其变成指针的
     exit(0);
     y->i=x1,y->j=x2,y->elem=x3;
     y->right=NULL;y->down=NULL;
     if(x->rhead[x1]==NULL||x->rhead[x1]->j>y->j)    //创建的时候只要考虑是否为空和rhead->j与y->j比,确定是否插入
     {
         y->right=x->rhead[x1];
         x->rhead[x1]=y;
     }
     else
     {                     //这步也是为了保护头结点。
          z=x->rhead[x1];//z是被赋值的,所以不必在设为指针变量,这里指指针的指针,也就是要用点的话就指针化,转成用->
          while((z->right!=NULL)&&(z->right->j<x2))
          z=z->right;
          y->right=z->right;
          z->right=y;
     }
      if(x->chead[x2]==NULL||x->chead[x2]->i>y->i)
      {
         y->down=x->chead[x2];
         x->chead[x2]=y;
      }
      else
      {
          z=x->chead[x2];
          while((z->down!=NULL)&&(z->down->i<x1))
          z=z->down;
          y->down=z->down;
          z->down=y;
      }
   }
   return;
}
clink isexist(clist* a,clink p)
{
    int x1,x2;
    clink q;
    x1=p->i;
    x2=p->j;
    q=a->rhead[x1];
    while(q)
    {
        if(x2==q->j)//这里当然是从第一个找
        return q;
        else
        q=q->right;
    }                                     //return  0就是没有找到
    return NULL;
}
void insert(clist* a,clink p)            //插入与删除都是要利用头结点的,只是这个头结点没有赋值而已
{
    int x1,x2;
    clink zz;
    clink q;
    x1=p->i;
    x2=p->j;
    q=a->rhead[x1];                     //不能该变头结点的数据
    zz=(clink)malloc(sizeof(cnode));
    zz->i=x1;
    zz->j=x2;
    zz->elem=p->elem;                  //插到第一个比他大的数前面,
    zz->right=NULL;                    //没有没数据的头结点,所以还要考虑插头的情况
    zz->down=NULL;                     //头插一个数 get
    if(q==NULL||q->j>x2)               //这行为空的情况,空就写==空更不会出错
    {
         zz->right=a->rhead[x1];
         a->rhead[x1]=zz;              // 因为是头指针的移动,所以不能用p,如果用p的话,a->head存的地址并不会改变
    }
    else
    {
            while(q->right)
            {
               if(q->right->j>x2)
               {
                   zz->right=q->right;
                   q->right=zz;
                   break;
               }
                q=q->right;
            }
            if(q->right==NULL)                      //尾接一个数
             q->right=zz;
                              //这里直接,不用判断q->j与zz->elem的大小关系,因为到这步,只有zz->elem大于q->j的情况。
    }
    q=a->chead[x2];                //关键
    if(q==NULL||q->i>x1)
    {
        zz->down=a->chead[x2];
        a->chead[x2]=zz;
    }
    else
    {                                //如果只有一个元素,直接跳出while,这是头结点的一个弊端
        while(q->down)              //进入这个else,第一个一定是小于x1的
        {
               if(q->down->i>x1)
              {
                zz->down=q->down;
                q->down=zz;
                break;
              }
                q=q->down;
        }
              if(q->down==NULL)  //如果到最后没有比他大的数,则插到最后
              q->down=zz;
    }
    return;
}
void Delete(clist* a,clink p)
{
    int x1,x2;
    clink q;
    x1=p->i;
    x2=p->j;
    q=a->rhead[x1];  //用q保留头结点 ,
    if(q->j==x2)
    {
        a->rhead[x1]=a->rhead[x1]->right;//删头结点,get.
        free(q);
    }
    else      //是从第二个开始
    {
        while(q->right->j!=x2)
        {
            q=q->right;
        }
        q->right=q->right->right;
    }
}
void print(clist* a)
{
    int k;
    clink p;
    for(k=0;k<=a->m;k++)
    {
        p=a->rhead[k];
        while(p)
        {
            printf("%d %d %d\n",p->i,p->j,p->elem);
            p=p->right;
        }
    }
    return;
}
void addcrosslist(clist* a,clist* b)//利用链表的插入与删除
//原理:链表的合并
{
   int k;
   clink p;
   clink pp=NULL;
   for(k=0;k<=b->m;k++)  //b->m是cnt类的,所以是小于号
   {
      p=b->rhead[k];
      while(p)          //每行用指针逐个后移
      {
          pp=isexist(a,p);
          if(!pp)        //如果不存在。
          insert(a,p);
          else
          {
              pp->elem+=p->elem;
              if(!pp->elem)
              Delete(a,pp);
          }
          p=p->right;
      }
   }
   return;
}
int main()
{
    int p,q;
    clist a,b;
    scanf("%d%d",&p,&q);
    int t1,t2;
    scanf("%d%d",&t1,&t2);
    createcrosslist(&a,p,q,t1);
    createcrosslist(&b,p,q,t2);
    addcrosslist(&a,&b);
    print(&a);
    return 0;
}

/*
 测试用例
 3 4 3 2
 1 1 1
 1 3 1
 2 2 2
 1 2 1
 2 2 3
*/

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值