7矩阵

稀疏矩阵的顺序存储

 

在工程数学上学过矩阵,有多行多列,类似于多维数组。那么又如何将矩阵中的数值转换成数组的元素?

如图,左一是一个下三角矩阵,要将不为0的数值存放到一维数值中(右一)。

 

其中i是原矩阵的行标,j是原矩阵的列标,k是转换后数组的下标。

 

一般的非0元素极少可以用压缩法存储。。。

每个非0元素对应一个三元组(行号,列号,值)

     (row,col,val)

若稀疏矩阵Am×n共有t个非0元素

t个三元组构成长度为t的线性表

矩阵运算可通过线性表运算实现

 

存储结构的定义:

#define  m  100       //非0元素个数

typedef  struct  element

  {  float   val;   //值域

   int  row, col; 

  } elem;

elem  b[m];  // 定义存储数组

 

按行次序压缩顺序存储(按行顺序压缩存储)

 

 

稀疏矩阵的链式存储

 

链式存储有以下的几种方式:

(1)简单链式存储

(2)行链表组

结点只含列号域、元素域值和链域

适用于按行读取元素

 

(3)正交链表

 

 

 

正交链表,其实就是二维数组+链表。

可以把rh,ch当成二维数组,再在二维数组中存储对应的结点。(结点中定义矩阵的数值属性,如结点结构所示)

 

不解之处:

                图一                                                        图二

Val=35的行标row=0,列标col=2,但是在图二中的行标和列标却变成了1,3。为什么存储在结点的行、列标都+1,而不用原来的矩阵的行、列标。这是为什么?

 

矩阵的转置

 

 

矩阵的转置有以下三种方式:

1.简单复制:

算法:

for(i=0;i<t;i++)

  {

    c[i].row=b[i].col;

    c[i].col=b[i].row;

    c[i].val=b[i].val;

  }

从第一个元素开始,无论是否0都进行转置,效率有点低。

(2)逐行复制法

   先转A的第一列非0元素

   再转A的第二列非0元素

……

效率性:每转置一列,需要循环t次

A共n列,总共需要循环n*t次

转置共需O(nt)时间,效率也有点低

算法:

按行号j从0变到n-1,依次复制AT的各行非0元素 

    for(j=0;j<n;j++)  //n是A的列数

     for(i=0;i<t;i++)

       if(b[i].col==j)  //若列号是j

        {  c[k].row=b[i].col; //原行号变为列号

           c[k].col=b[i].row; //原列号变为行号

            c[k++].val=b[i].val;

        }

(3) 分段定位法(高效率)

该方法分为2个阶段:

1.预处理阶段

[1]统计A的各列非0元素个数,记录在数组num[n]中

[2]将数组c分成n段,使第j段含有num[j]个单元 ,用行定位指针数组pot[n]指示各段地址。

行定位指针的计算公式 :

 

2.转置阶段

 

 

算法跟踪示例

 

稀疏矩阵转置算法:

void transpose(elem b[ ],elem c[ ])

  {

int  i,j,k,num[n],pot[n];   

    for(j=0; j<n; j++)

num[j]=0; // 预处理阶段

        for(i=0; i<t; i++)

num[b[i].col]++;

for(pot[0]=0,j=1;j<n;j++)

pot[j]=pot[j-1]+num[j-1];

    for(i=0; i<t; i++) //转置阶段

    {

      j=b[i].col;      //取列号

      k=pot[j];    //取行定位指针值

      c[k].row=j, c[k].col=b[i].row, c[k].val=b[i].val;

      pot[j]++;    //修改定位指针

     }

   }

 

该算法效率分析:

 

 

空间复杂性

使用两个辅助数组(数组num和数组pot)

各占O(n)个单元,故S(n)=O(n)

 

时间复杂性

预处理阶段,用O(n+t)时间

转置阶段,用O(t)时间

共用O(n+t)时间 

 

 

稀疏矩阵相乘

本例采用逐步累加法

[1]先将Z的各元素存储单元c[i,j]清0

[2]顺序地扫描数a,每找到一个非元素xrk

在数组b中找出行号等于k的非0元素:

        yks1,yks2,…

让xrk依次与它们相乘

乘积分别累加到c[r-1][s1-1],c[r-1][s2-1],······

 

用行定位指针pot[k]指向Y第k+1行非0元素在数组b中的存储位置(如下图)。

 

 

稀疏矩阵相乘算法:

void  multiply(elem a[ ],elem b[ ],float c[ ][l])

  {

 int i,j,k,r,s,pot[n];  float  x,y;

    for(i=0; i<m; i++) 

{

         for(j=0; j<l; j++)

  c[i][j]=0; 

}  

for(i=0; i<n; i++)

 pot[i]=-1; 

for(i=t2-1; i>=0; i--) 

pot[b[i].row-1]=i;

    for(i=0; i<t1; i++)

    {

      k=a[i].col;    

      j=pot[k-1];   

      if(j<0)continue;

         r=a[i].row;    

         x=a[i].val;    

         while (b[j].row==k)

         {

          s=b[j].col;       

          y=b[j].val;    

          c[r-1][s-1]+=x*y;     

          j++;        

         }

       }

     }

该算法的效率分析:

空间复杂性

     不计原始数据及结果数据所占空间

行定位指针数组pot占用O(n)个单元

“纯”空间复杂性S(n)=O(n)

 

时间复杂性

句1用O(ml)时间

句2用O(n)时间,句3用O(t2)时间

故,预处理阶段共用O(ml+n+t2)时间

 

相乘阶段

外循环(句4)执行t1次

内循环(句10)最多执行min(t2,l)次

句4到句14所用时间总量不超过

O(t1)O(min(t2,l))

两阶段所用时间相加

 T(n)≤O(ml+n+t2+t1*min(t2,l))

posted @ 2018-01-09 18:09  gd_沐辰  阅读(240)  评论(0编辑  收藏  举报