三元组十字链表下稀疏矩阵的加、转、乘实现

#include<stdio.h>
#include<stdlib.h>
#include<iostream.h>
#include<process.h>
#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef int ElemType;

//------------------------------------------------------------------------------------------------

struct OLNode
{
 int i,j;                                           //非零元所在行、列
 ElemType e;                                        //非零元值
 OLNode *right,*down;                               //定义向右域和向下域
};

typedef OLNode *OLink;

struct CrossList
{
 OLink *rhead,*chead;                               //行、列表头的头节点
 int mu,nu,tu;                                      //矩阵的行、列和非零元个数
};


//------------------------------------------------------------------------------------------------


void Create(CrossList &M)                             //矩阵的创建
{
 int i,j,k,m,n,t;
 ElemType e;                                       //用于存放非零元值
 OLNode *p,*q;
 printf("Please input the rows 、columns and the values of the matrix:");
 scanf("%d%d%d",&m,&n,&t);                         //输入稀疏矩阵的行、列、非零元
 M.mu=m;                                           //把矩阵的总行数存入M.mu
 M.nu=n;                                           //把矩阵的总列数存入M.nu
 M.tu=t;                                           //把矩阵的非零元个数存入M.tu
 M.rhead=(OLink*)malloc((m+1)*sizeof(OLink));      //给对象M的行分配m+1个结点大小的空间用行头指针M.rhead指向第一个行结点
 if(!M.rhead)                                      //假如头结点分配成功
  exit(OVERFLOW);                               //退出程序,程序返回给操作系统的返回码是OVERFLOW
 M.chead=(OLink*)malloc((n+1)*sizeof(OLink));      //给对象M的列分配n+1个结点大小的空间用列头指针M.chead指向第一个列结点
 if(!M.chead)                                      //假如头结点分配成功
  exit(OVERFLOW);                               //退出程序,程序返回给操作系统的返回码是OVERFLOW
 for(k=1;k<=m;k++)                                 //初始化行头指针
  M.rhead[k]=NULL;
 for(k=1;k<=n;k++)                                 //初始化列头指针
  M.chead[k]=NULL;
 printf("Please input %d data:/n",M.tu);
 for(k=0;k<t;k++)
 {
  scanf("%d%d%d",&i,&j,&e);                     //输入t个非零元的信息
  if(i>m||j>n)                                  //假如输入的元素不在矩阵中
  {
            printf("Please input again:/n");
   exit(OVERFLOW);                           //退出程序,程序返回给操作系统的返回码是OVERFLOW
  }
  else                                          //假如输入的元素在矩阵中
  {
   p=(OLNode*)malloc(sizeof(OLNode));        //为p分配一个结点大小的空间
   if(!p)                                    //假如p不存在
    exit(OVERFLOW);                       //退出程序,程序返回给操作系统的返回码是OVERFLOW
   p->i=i;                                   //把非零元的行值赋给p->i
   p->j=j;                                   //把非零元的列值赋给p->j
   p->e=e;                                   //把非零元的值赋给p->e
   if(M.rhead[i]==NULL||M.rhead[i]->j>j)     //如果第i行的第一个结点为空或者要插入的非零元的列值小于第i行的第一个结点的列值
   {
    //p插入该行第一节点处
    p->right=M.rhead[i];                  //p的向右域指向没有插入前的第i行的第一个结点
    M.rhead[i]=p;                         //p指向没有插入前的第i行的第一个结点
   }
   else
   {
    //否则寻找行表插入位置
    for(q=M.rhead[i];q->right&&q->right->j<j;q=q->right);//这里的;表示对这个循环不执行任何操作
    p->right=q->right;                    //p的右向域指向q的右向域
    q->right=p;                           //p指向q的右向域
   }                                         //完成行插入
   if(M.chead[j]==NULL||M.chead[j]->i>i)     //假如第一个列结点为空或者第j列的第一个结点的行值大于要插入的行值
   {
    //p插入该列第一节点处
    p->down=M.chead[j];                   //p的向下域指向没有插入前的第j列的第一个结点
    M.chead[j]=p;                         //p指向没有插入前的第j列的第一个结点
   }                                         //完成列插入
   else
   {
    //否则寻找列表插入位置
    for(q=M.chead[j];q->down&&q->down->i<i;q=q->down);//这里的;表示对这个循环不执行任何操作
    p->down=q->down;                      //p的向下域指向q的向下域
    q->down=p;                            //p指向q的向下域
   }                                         //完成列插入
  }
 }
}


//------------------------------------------------------------------------------------------------

void Print(CrossList M)                               //矩阵的输出
{
 int i,j,k;
 OLink p;                                          //定义结点指针p
 int array[100][100];                              //定义二元数组array[100][100]
 for(i=1;i<=M.mu;i++)                              //行循环
 {
  for(j=1;j<=M.nu;j++)                          //列循环
  {
   array[i][j]=0;                            //初始化数组所需部分
  }
 }
 for(k=1;k<=M.nu;k++)                              //将所有非零元的值存入对应的数组中
 {
  p=M.rhead[k];                                 //p指向第k行的第一个结点
  while(p)
  {
   //将第k行的非零元存入数组中
   array[p->i][p->j]=p->e;                   //将这个结点的非零元存入数组中
   p=p->right;                               //p指向下一个向右域
  }
 }
 for(i=1;i<=M.mu;i++)                              //行循环
 {
  for(j=1;j<=M.nu;j++)                          //列循环
  {
   if(j==M.nu)
    cout<<array[i][j]<<endl;              //如果是行的最后一个结点则换行
   else
    cout<<array[i][j]<<" ";               //以矩阵的显示方式显示稀疏矩阵
  }
 }
}


//------------------------------------------------------------------------------------------------


void Add(CrossList M,CrossList N,CrossList &Q)  //矩阵M和矩阵N相加并存入矩阵Q
{
 int i,k;
 OLink p,pq,pm,pn;
 OLink *col;
 if(M.mu!=N.mu||M.nu!=N.nu)                 //如果两个矩阵不是同类型的
 {
  printf("The two matrixes is not of the same type!/n");
  exit(OVERFLOW);                        //退出程序,程序返回给操作系统的返回码是OVERFLOW
 }
 //对Q进行初始化
 Q.mu=M.mu;                                 //矩阵Q的总行数和矩阵M的总数相同
 Q.nu=M.nu;                                 //矩阵Q的总列数和矩阵M的总数相同
 Q.tu=0;                                    //将矩阵Q的非零元个数初始化为零
 Q.rhead=(OLink*)malloc((Q.mu+1)*sizeof(OLink));  //给对象Q的行分配Q.mu+1个结点大小的空间用行头指针Q.rhead指向第一个行结点
 if(!Q.rhead)                               //如果行分配空间成功
  exit(OVERFLOW);                        //退出程序,程序返回给操作系统的返回码是OVERFLOW
 Q.chead=(OLink*)malloc((Q.nu+1)*sizeof(OLink));  //给对象Q的列分配Q.nu+1个结点大小的空间用列头指针Q.chead指向第一个列结点
 if(!Q.chead)                               //如果列分配空间成功
  exit(OVERFLOW);                        //退出程序,程序返回给操作系统的返回码是OVERFLOW
 for(k=1;k<=Q.mu;k++)                       //初始化行
  Q.rhead[k]=NULL;
 for(k=1;k<=Q.nu;k++)                       //初始化列
  Q.chead[k]=NULL;
 col=(OLink*)malloc((Q.nu+1)*sizeof(OLink));//生成指向列的起始节点的指针
 if(!col)                                   //如果分配空间成功
  exit(OVERFLOW);                        //退出程序,程序返回给操作系统的返回码是OVERFLOW
 for(k=1;k<=Q.nu;k++)                       //赋初始值
  col[k]=NULL;
 for(i=1;i<=M.mu;i++)                       //按行序相加
 {
  pm=M.rhead[i];                         //pm指向矩阵M的第i行的头结点
  pn=N.rhead[i];                         //pn指向矩阵N的第i行的头结点
  while(pm&&pn)                          //如果pm和pn都存在
  {
   if(pm->j<pn->j)                    //矩阵M当前结点的列小于矩阵N当前结点的列
   {
    //生成Q的结点
    p=(OLink)malloc(sizeof(OLNode));  //给p分配一个结点大小的空间
    if(!p)                         //如果分配空间不成功
     exit(OVERFLOW);            //退出程序,程序返回给操作系统的返回码是OVERFLOW
    Q.tu++;                        //矩阵Q的非零元个数加1
    p->i=i;                        //把非零元的行赋给p->i
    p->j=pm->j;                    //把矩阵M中当前结点列的值赋给p->j
    p->e=pm->e;                    //把矩阵M中当前结点的元素值赋给p->e
    p->right=NULL;                 //p的向右域为空
    pm=pm->right;                  //pm右移
   }
   else if(pm->j>pn->j)               //矩阵M当前结点的列大于矩阵N当前结点的列
   {
    p=(OLink)malloc(sizeof(OLNode));//给p分配一个结点大小的空间
    if(!p)                          //如果分配空间不成功
     exit(OVERFLOW);             //退出程序,程序返回给操作系统的返回码是OVERFLOW
    Q.tu++;                         //矩阵Q的非零元个数加1
    p->i=i;                         //把矩阵当前非零元的行赋给p->i
    p->j=pn->j;                     //把矩阵N中当前结点列的值赋给p->j
    p->e=pn->e;                     //把矩阵N中当前结点的元素值赋给p->e
    p->right=NULL;                  //p的向右域为空
    pn=pn->right;                   //pn右移
   }
   else if(pm->e+pn->e)                //M,N当前结点的列相同并且两元素之和非零
   {
    p=(OLink)malloc(sizeof(OLNode));//给p分配一个结点大小的空间
    if(!p)                          //如果分配空间不成功
     exit(OVERFLOW);             //退出程序,程序返回给操作系统的返回码是OVERFLOW
    Q.tu++;                         //矩阵Q的非零元个数加1
    p->i=i;                         //把矩阵当前非零元的行赋给p->i
    p->j=pn->j;                     //把矩阵当前非零元的列赋给p->j
    p->e=pm->e+pn->e;               //把矩阵M当前非零元的值和矩阵N当前非零元的值相加赋给p->e
    p->right=NULL;                  //p的向右域为空
    pm=pm->right;                   //pm右移
    pn=pn->right;                   //pn右移
   }
   else                                //两元素相加为零
   {
    pm=pm->right;                   //pm右移
    pn=pn->right;                   //pn右移
    continue;                       //不执行下面的程序,回到循环
   }
   if(Q.rhead[i]==NULL)                //如果当前行的头结点为空
    Q.rhead[i]=pq=p;                //把p结点中的数据赋给pq结点和结点Q.rhead[i],pq结点用来保存当前的位置
   else                                //如果当前的头结点不为空
   {
    pq->right=p;                    //pq的向右域指向p
    pq=pq->right;                   //pq指向pq的向右域
   }                                   //完成行插入
   if(Q.chead[p->j]==NULL)             //如果当前列的头结点为空
    Q.chead[p->j]=col[p->j]=p;      //把p结点中的数据赋给结点col[p->j]和当前列的头结点Q.chead[p->j]
   else
   {
    //如果当前结点不为空,则插入p结点
    col[p->j]->down=p;
    col[p->j]=col[p->j]->down;
   }
  }
  while(pm)                               //如果矩阵M中的结点还没有插完,将矩阵M该行的剩余元素插入矩阵Q
  {
   p=(OLink)malloc(sizeof(OLNode));    //给结点p分配空间
   if(!p)
    exit(OVERFLOW);
   Q.tu++;                             //矩阵非零元个数加1
   p->i=i;                             //把当前结点的行、列、和值插入p中
   p->j=pm->j;
   p->e=pm->e;
   p->right=NULL;                      //p的向右域为空
   pm=pm->right;                       //pm右移
            if(Q.rhead[i]==NULL)                //如果当前行头结点为空,直接插入p结点
    Q.rhead[i]=pq=p;
   else                                //如果当前行头结点不为空,插入p结点
   {
    pq->right=p;
    pq=pq->right;
   }
   if(Q.chead[p->j]==NULL)             //如果当前列头结点为空,直接插入p结点
    Q.chead[p->j]=col[p->j]=p;    
   else                                //如果当前列头结点不为空,插入p结点
   {
    col[p->j]->down=p;
    col[p->j]=col[p->j]->down;
   }
  }
  while(pn)                               //如果矩阵N中的结点还没有插完,将矩阵N该行的剩余元素插入矩阵Q
  {
   p=(OLink)malloc(sizeof(OLNode));    //给结点p分配空间
   if(!p)
    exit(OVERFLOW);
   Q.tu++;                             //矩阵非零元个数加1
   p->i=i;                             //把当前结点的行、列、和值插入p中
   p->j=pn->j;
   p->e=pn->e;
   p->right=NULL;                      //p的向右域为空
   pn=pn->right;                       //pn右移
            if(Q.rhead[i]==NULL)                //如果当前行头结点为空,直接插入p结点
    Q.rhead[i]=pq=p;
   else                                //如果当前行头结点不为空,插入p结点
   {
    pq->right=p;
    pq=pq->right;
   }
   if(Q.chead[p->j]==NULL)             //如果当前列头结点为空,直接插入p结点
    Q.chead[p->j]=col[p->j]=p;
   else                                //如果当前列头结点不为空,插入p结点
   {
    col[p->j]->down=p;
    col[p->j]=col[p->j]->down;
   }
  }
    }
 for(k=1;k<=Q.nu;k++)                        //使得每一列的最后一个结点的向下域为空
  if(col[k])
   col[k]->down=NULL;
  free(col);                              //释放col的空间
}

//------------------------------------------------------------------------------------------------


void Trans(CrossList M,CrossList &N)            //将矩阵M转置到矩阵N中
{
 OLink p,q,s;                                //定义三个结点p、q、s
 int i,j;
 N.mu=M.mu;                                  //将矩阵M中的行、列和非零元值赋给矩阵N
 N.nu=M.nu;
 N.tu=M.tu;
 if(N.rhead==NULL)                           //如果矩阵N的行为空
  N.rhead=(OLink *)malloc((N.mu+1)*sizeof(OLink));//给矩阵N的行分配N.mu+1个结点大小的空间
 for(i=1;i<=N.mu;i++)                        //对矩阵N的行进行初始化
  N.rhead[i]=NULL;
 if(N.chead==NULL)                           //如果矩阵N的列为空
  N.chead=(OLink *)malloc((N.nu+1)*sizeof(OLink));//给矩阵N的列分配N.nu+1个结点大小的空间
 for(j=1;j<=N.nu;j++)                        //对矩阵N的列进行初始化
  N.chead[j]=NULL;
 for(i=1;i<=M.mu;i++)                       
 {
  for(s=M.rhead[i];s!=NULL;s=s->right)    //对矩阵M的第i行进行扫描
  {
   p=(OLink)malloc(sizeof(OLink));     //给p分配一个结点大小的空间
   p->i=s->j;                          //将扫描到的结点中的数据进行转置后存到结点p中
   p->j=s->i;
   p->e=s->e;
   if(N.rhead[p->i]==NULL || N.rhead[p->i]->j>p->j)//如果p结点所在行的头结点为空或者头结点的列大于p结点的列值将p结点插入到第一个结点
   {
    p->right=N.rhead[p->i];
    N.rhead[p->i]=p;
   }
   else
   {
    for(q=N.rhead[p->i];q->right && q->right->j<p->j;q=q->right);//扫描直到扫描到的列值大于要插入的结点的列值,则把p结点插入到这个结点的后面
    p->right=q->right;
    q->right=p;
   }
   if(N.chead[p->j]==NULL || N.chead[p->j]->i > p->i)//如果p结点所在列的头结点为空或者头结点的行值大于p结点的行值将p结点插入到第一个结点
   {
    p->down=N.chead[p->j];
    N.chead[p->j]=p;
   }
   else
   {
    for(q=N.chead[p->j];q->down && q->down->i < p->i; q=q->down);//扫描当前列,直到扫描到的结点的行值大于要插入的结点的行值,则把p结点插入到这个结点的后面
    p->down=q->down;
    q->down=p;
   }
  }
 }
}


//------------------------------------------------------------------------------------------------

 

void Mult(CrossList M,CrossList N,CrossList &Q)//把矩阵M和矩阵N相乘并存入到矩阵Q中
{
 int i,j,e;
 OLink q,p0,q0,q1,q2;
 if(M.nu!=N.mu)                             //如果矩阵M的总列数不等于矩阵N的总行数,则不能矩阵相乘              
 {
  printf("The matrix what you input is error!/n");
  exit(OVERFLOW);
 }
 else                                       //如果矩阵M的总列数等于矩阵N的总行数
 {
  Q.mu=M.mu;                             //把矩阵M的总行数赋给Q.mu
  Q.nu=N.nu;                             //把矩阵N的总列数赋给Q.nu
  Q.tu=0;                                //矩阵Q的非零元个数置为零
  Q.rhead=(OLink*)malloc((Q.mu+1)*sizeof(OLink));  //给矩阵Q的行头指针分配Q.mu+1个结点大小的空间
  if(!Q.rhead)
   exit(OVERFLOW);
  Q.chead=(OLink*)malloc((Q.nu+1)*sizeof(OLink));  //给矩阵Q的列头指针分配Q.nu+1个结点大小的空间
  if(!Q.chead)
   exit(OVERFLOW);
  for(i=1;i<=Q.mu;i++)                   //初始化行
   Q.rhead[i]=NULL;
  for(i=1;i<=Q.nu;i++)                   //初始化列
   Q.chead[i]=NULL;
  for(i=1;i<=Q.mu;i++)
   for(j=1;j<=Q.nu;j++)
   {
    p0=M.rhead[i];                  //p0指向矩阵M第i行头结点
    q0=N.chead[j];                  //q0指向矩阵N第j列头结点
    e=0;                            //定义变量e的值为0
    while(p0&&q0)                   //当矩阵M和矩阵N的当前结点都存在时
    {
     if(q0->i<p0->j)             //如果q0当前所在行小于p0当前所在列,q0下移
      q0=q0->down;
     else if(q0->i>p0->j)        //如果q0当前所在行大于p0当前所在列,p0右移
      p0=p0->right;
     else
     {
      e=e+p0->e*q0->e;        //乘积累加
      q0=q0->down;            //行列后移
      p0=p0->right;
     }
    }
    if(e)                           //e不为零则插入Q
    {
     Q.tu++;                     //矩阵Q的非零元个数加1 
     q=(OLink)malloc(sizeof(OLNode));  //给q分配空间
     if(!q)
      exit(OVERFLOW);
     q->i=i;                     //把当前元素的行、列和值赋给结点q
     q->j=j;
     q->e=e;
     q->right=NULL;              //结点q的向右域为空
     q->down=NULL;               //结点q的向下域为空
     if(!Q.rhead[i])             //如果Q矩阵当前行的头结点为空,将结点q中的数据赋给Q.rhead和结点q1:用来存储当前位置
      Q.rhead[i]=q1=q;
     else                        //否则将q中的数据赋给q1的向右域,并将q1右移
      q1=q1->right=q;
     if(!Q.chead[j])             //如果Q矩阵当前列的头结点为空,将结点q中的数据赋给Q.chead
      Q.chead[j]=q;
     else
     {
      q2=Q.chead[j];          //将当前列的头结点数据赋给q2
      while(q2->down)         //如果q2的向下域存在
       q2=q2->down;        //q2下移
      q2->down=q;             //把当前要插入的结点q插入到结点q2的后面
     }
    }
   }
 }
}

//------------------------------------------------------------------------------------------------


void main()
{
 CrossList A,B,C;                               //声明三个矩阵
 int Select;                                    //用来表示所要选择的序号
 cout<<"*****************************************************************************"<<endl;
 cout<<"******************************"<<"请选择你需要的操作"<<"*****************************"<<endl;
 printf("/t/t/t<1>.Press 1 to add the array;/n");
 printf("/t/t/t<2>.Press 2 to trans the array;/n");
 printf("/t/t/t<3>.Press 3 to multiply the array;/n");
 cout<<"*****************************************************************************"<<endl;
 while(printf("Please input the serial number:"),cin>>Select)
 {
  switch(Select)
  {
  case 1 :                                    //稀疏矩阵相加
   {
    Create(A);                          //创建矩阵A
    Create(B);                          //创建矩阵B
    cout<<"The array A is:"<<endl;
    Print(A);                           //输出矩阵A
    cout<<"To add array B:"<<endl;
    Print(B);                           //输出矩阵B
    Add(A,B,C);                         //把矩阵A和矩阵B相加存入到矩阵C中
    cout<<"The result is:"<<endl;
    Print(C);                           //输出矩阵C
    break;
   }
  case 2 ://稀疏矩阵转置
   {
    Create(A);                          //创建矩阵A
    Create(B);                          //创建矩阵B
    cout<<"The array A is:"<<endl;
    Print(A);                           //输出矩阵A
    cout<<"Trans to B:"<<endl;
    Trans(A,B);                         //将矩阵A转置到矩阵B中
    cout<<"The result is:"<<endl;
    Print(B);                           //输出矩阵B
    break;
   }
  case 3 :                                     //稀疏矩阵相乘
   {  
    Create(A);                           //创建矩阵A
    Create(B);                           //创建矩阵B
    cout<<"The array A is:"<<endl;
    Print(A);                            //输出矩阵A
    cout<<"To multiply array B:"<<endl;
    Print(B);                            //输出矩阵B
    Mult(A,B,C);                         //把矩阵A和矩阵B相乘所得的矩阵存入矩阵C中
    cout<<"The result is:"<<endl;
    Print(C);                            //输出矩阵C
    break;
   }
  }
 }
}
/*
2 2 3
1 1 1
1 2 4
2 2 3

 

2 2 2
1 1 2
2 2 33
*/

阅读更多
下一篇Web开发项目简单流程
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭