稀疏矩阵

在矩阵中,如果很多元素都是零,这种矩阵称为稀疏矩阵,在对稀疏矩阵存储中,常常不存储零元素来节省空间的,矩阵常用操作有转置,加法,乘法等操作,其中转置和乘法最常用。
假设有a和b两个矩阵,其中b是a的转置矩阵,a和b矩阵表示如图:
矩阵
矩阵结构体

typedef struct
{
   //矩阵对应的列值
   int col;
   //矩阵对应的行值
   int row;
   //矩阵行和列对应的数值
   int value;
} term;

其稀疏矩阵转置快速算法的实现:
核心代码:

//转置稀疏矩阵的核心代码,时间复杂度为(colums+elements)
void fast_transpose(term a[],term b[])
{
   //统计转置矩阵中,每一行的元素个数,以及第几行在转置矩阵中的起始位置
   int row_terms[MAX_COL],starting_pos[MAX_COL];
   int i,j,num_cols=a[0].col,num_items=a[0].value;
   b[0].row=num_cols;b[0].col=a[0].row;
   b[0].value=num_items;
   for(i=0;i<num_cols;i++)
   {
      row_terms[i]=0;
   }
    //统计转置矩阵中,每一行的元素个数
   for(i=1;i<=num_items;i++)
   {
      row_terms[a[i].col]++;
   }
   starting_pos[0]=1;
   //第几行在转置矩阵中的起始位置
   for(i=1;i<num_cols;i++)
   {
      starting_pos[i]=starting_pos[i-1]+row_terms[i-1];
   }
   for(i=1;i<=num_items;i++)
   {
      j=starting_pos[a[i].col]++;
      b[j].row=a[i].col;
      b[j].col=a[i].row;
      b[j].value=a[i].value;
   }
}

时间复杂度为O(columns+elements),对于二维数组矩阵转置的时间复杂度O(columns.elements)快多了。
稀疏矩阵乘法核心算法:

//d是存储a和b两个矩阵相乘的结果的矩阵
void mmult(term a[],term b[],term d[])
{
   //totalb,totald,totala分别代表b,d,a的非零元素个数
   //row是当前与B的列相乘的A的行号,column是当前与A的行相乘的B的列号
   int i,j,column,totalb=b[0].value,totald=0;
   int row_a=a[0].row,cols_a=a[0].col;
   int totala=a[0].value,cols_b=b[0].col;
   //row_begin代表a当前行第一个元素的位置,sum代表两个矩阵对应行和列相乘的结果
   int row_begin=1,sum=0,row=a[1].row;
   //存放b转置矩阵
   term new_b[MAX_TERMS];
   if(cols_a!=b[0].row)
   {
      fprintf(stderr,"Incompatible matrices\n");
      exit(1);
   }
   //转置b矩阵
   fast_transpose(b,new_b);
   a[totala+1].row=row_a;
   new_b[totalb+1].row=cols_b;
   new_b[totalb+1].col=0;
   for(i=1;i<totala;i++)
   {
      //记录当前与A的行相乘的B的列号
      column=new_b[i].row;
      for(j=1;j<totalb;j++)
      {
         //如果当前行与a[i]的行不相等,说明已得出一行与一列相乘的值,故要进入下一列与当前行相乘
         if(a[i].row!=row)
         {
            storesum(d,&totala,row,column,&sum);
            i=row_begin;
            for(;new_b[j].row==column;j++);
            column=new_b[j].row;
         }
          //如果当前列与b[j]的列不相等,说明已得出一行与一列相乘的值,故要进入下一列与当前行相乘
         else if(b[j].row!=column)
         {
            storesum(d,&totald,row,column,&sum);
            i=row_begin;
            column=new_b[j].row;
         }
         else switch(compare(a[i].col,b[j].col))
         {
            case -1:
               i++;
               break;
            case 0:
               sum+=(a[i++].value+b[j++].value);
               break;
            case 1:
               j++;
               break;
         }
      }
      //进入下一行
      for(;a[i].row==row;i++);
      row=a[i].row;
      row_begin=i;
   }
   d[0].row=a[0].row;
   d[0].col=b[0].col;
   d[0].value=totald;
}
//将相乘结果存储到d矩阵中
void storesum(term d[],int *totald,int row,int column,int *sum)
{
   if(*sum)
   {
      if(*totald<MAX_TERMS)
      {
          d[++*totald].row=row;
          d[*totald].col=column;
          d[*totald].value=*sum;
      }
      else
      {
         fprintf(stderr,"Numbers of terms in product exceeds %d\n",MAX_TERMS);
         exit(1);
      }
   }
}
int compare(int a,int b)
{
   if(a>b)
      return 1;
   else if(a==b)
      return 0;
   else
      return -1;
}

**时间复杂度O(n0(colsb.termsrow+totalb),nϵ[0,rowa]=O(cols_b.total_a+rows_a.totalb),而标准数组的矩阵相乘复杂度为O(rows_a.cols_a.cols_b),注意:如果在最坏情况下,当totala=cols_a.rows_a或totalb=cols_a.cols_b时,复杂度要比其标准数组的复杂度慢常数因子倍,如果,totala和totalb远小于其最大值时,其复杂度就优于经典算法。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值