稀疏矩阵的压缩存储及其两种转置算法

1  什么是稀疏矩阵

       有较多值相同元素或较多零元素,且值相同元素或者零元素分布没有一定规律的矩阵称为稀疏矩阵。

假设在mXn的矩阵中,有t个元素不为零,令c=t/mXn则称为矩阵的稀疏因子,通常认为c<0.05时称为稀疏矩阵。

2 稀疏矩阵的压缩存储(只讨论有较多零元素矩阵的压缩存储);
如何进行稀疏矩阵的压缩存储?稀疏矩阵的压缩存储有多种方法,本文主要介绍三元组顺序表这种存储方式。

1)三元组表

       按照压缩存储的概念,只须存储稀疏矩阵的非零元素。但稀疏矩阵零元素分布没有一定规律,因此,除了存储非零元素的值之外,还必须同时记下它所在行和列号;反之,一个三元组(i,j,e),能唯一确定矩阵的一个非零元。由此,稀疏矩阵可由非零元的三元组表及其行数、列数唯一确定。

 例如,下列三元组表

A=( (1,2,12), (1,3,9), (3,1,-3), (3,6,14), (4,3,24), (5,2,18), (6,1,15), (6,4,-7) )

加上行、列数6,7便可作为矩阵M的另一种表示方式。

       上述三元组表的不同存储方法可引出稀疏矩阵不同的压缩存储方法

2)三元组顺序表
        假设以顺序存储结构来表示三元组表,则可得稀疏矩阵的一种压缩存储方式——我们称之为三元组顺序表。

稀疏矩阵的三元组顺序表的类型定义

  1. #define MAXSIZE 12500            //假设非零元个数的最大值为12500  
  2.   
  3. Typrdef struct {  
  4.   
  5.               int      i,j;               //非零元的行下标和列下标  
  6.   
  7.               ElemType  e;                 //非零元  
  8.   
  9. }Triple;  
  10.   
  11. Typedef union {  
  12.   
  13.          Triple    data[MAXSIZE+1];  //用于存储非零元三元组表, data[0]未用  
  14.   
  15.          int          mu,nu,tu;                 //矩阵的行数、列数和非零元个数  
  16.   
  17. }TSMatrix;

Triple:是包含三个域的结构类型,其变量用于存储矩阵的非零元三元组

   i, j:两个整数域,用于存储非零元的行下标和列下标

      e:用于存储非零元的值

TSMatrix:是包含四个域的结构类型,

 data:       一维数组,用于存储矩阵的非零元三元组表

mu,nu,tu:三个整数域,分别存储矩阵的行数、列数和非零元个数

 

设M是TSMatrix 类型的结构变量,则M有四个域,其中M.data用于存储矩阵M的三元组表,在此我们约定,M.data域中非零元三元组是以行序为主序顺序存储的。

 

设M是TSMatrix类型的结构变量,则M有四个域,其中M.data用于存储矩阵M的三元组表,如下图所示

 

3  转置运算算法

       下面以矩阵的转置运算为例,讨论在三元组顺序表存储方式下,如何实现矩阵的运算。本文介绍两种转置运算算法。

      转置运算是一种最简单的矩阵运算。对于一个m行 n列的矩阵M,它的转置矩阵T是一个n行m列的矩阵。例如,下图中的矩阵M和T互为转置矩阵。

1)  转置运算算法TransposeSMatrix(TSMatrix M, TSMatrix &T)

基本思想

  对M.data从头至尾扫描:

  第一次扫描时,将M.data中列号为1的三元组赋值到T.data中,

  第二次扫描时,将M.data中列号为2的三元组赋值到T.data中,

  依此类推,直至将M.data所有三元组赋值到T.data中

转置运算算法

 

  1. Status TransposeSMatrix(TSMatrix M, TSMatrix &T)  {  
  2. //采用三元组表存储表示,求稀疏矩阵M的转置矩阵T  
  3.      T.mu=M.nu;  T.nu=M.mu;  T.tu=M.tu;  
  4.      if (T.tu)  {  
  5.           q=1;               // q为当前三元组在T.data[ ]存储位置(下标)  
  6.           for (col=1; col<=M.nu;  ++col)  
  7.                 for (p=1;  p<=M.tu;  ++p)      //p为扫描M.data[ ]的“指示器”  
  8.                                                                //p“指向”三元组称为当前三元组  
  9.                       if (M.data[p].j= =col){  
  10.                              T.data[q].i =M.data[p].j; T.data[q].j=M.data[p].i;  
  11.                              T.data[q].e=M.data[p].e; ++q;}  
  12.     }  
  13.     return OK;  
  14. }//  TransposeSMtrix      

时间复杂度分析

        算法的基本操作为将M.data中的三元组赋值到T.data,是在两个循环中完成的,故算法的时间复杂度为O(nu´tu)

        我们知道,若用二维数组存储矩阵,转置算法的时间复杂度为O(mu´nu)。当非零元的个数tu和矩阵元素个数mu´nu同数量级时,转置运算算法1的时间复杂度为O(mu´nu´ nu)。由此可见:在这种情况下,用三元组顺序表存储矩阵,虽然可能节省了存储空间,但时间复杂度提高了,因此算法仅适于tu << mu´nu的情况。

  该算法效率不高的原因是:对为实现M到T的转置,该算法对M.data进行了多次扫描。能否在对M.data一次扫描的过程中,完成M到T的转置?

快速转置算法

        下面介绍转置运算算法称为快速转置算法

分析

       在M.data中,M的各列非零元对应的三元组是以行为主序存储的,故M的各列非零元对应的三元组存储位置不是“连续”的。然而,M的各列非零元三元组的存储顺序却与各列非零元在M中的顺序一致。

     如:M的第一列非零元素是-3、15,它们对应的三元组在M.data中的存储顺序也是(3,1,-3)在前(6,1,15)后。

    如果能先求得M各列第一个非零元三元组在T.data中的位置,就能在对M.data一次扫描的过程中,完成M到T的转置:

    对M.data一次扫描时,首先遇到各列的第一个非零元三元组,可按先前求出的位置,将其放至T.data中,当再次遇到各列的非零元三元组时,只须顺序放到对应列元素的后面。

    

       为先求得M各列第一个非零元三元组在T.data中的位置。引入两个辅助向量num[ ] 、cpos[ ]:

    num[col]:存储第col列非零元个数

    cpos[col]:存储第col列第一个非零元三元组在T.data中的位置

cpos[col]的计算方法:

      cpos[1]=1

      cpos[col]=cpos[col-1]+num[col-1]        

 

例矩阵M

 

快速转置算法主要步骤:

 

1、 求M中各列非零元个数num[ ];

2、 求M中各列第一个非零元在T.data中的下标cpos[ ];

3、 对M.data进行一次扫描,遇到col列的第一个非零元三元组时,按cpos[col ]的位置,将其放至T.data中,当再次遇到col列的非零元三元组时,只须顺序放到col列元素的后面;

快速转置算法

  1. Status FastTransposeSMatrix(TSMatrix M, TSMatrix &T) {  
  2.    //采用三元组顺序表存储表示,求稀疏矩阵M的转置矩阵T。  
  3.    T.mu=M.nu; T.nu=M.mu; T.tu=M.tu;  
  4.   if (T.tu){  
  5.     for (col=1; col<=M.nu; ++col)   num[col]=0;  
  6.     for (t=1; t<=M.tu; ++t) ++num[M.data[t].j];       //求M中每一列非零元个数  
  7.     //求第 col列中第一个非零元在T.data中的序号  
  8.     cpot[1]=1;  
  9.     for(col=2; col<=M.tu;  ++col)  cpot[col]=cpot[col-1]+num[col-1];  
  10.     for(p=1; p<M.tu;  ++p) {    
  11.          col=M.data[p].j;   q=cpot[col];   
  12.          T.data[q].i=M.data[p].j;  T.data[q].j=M.data[p].i;   
  13.          T.data[q].e=M.data[p].e;     
  14.          ++cpot[col];  
  15.     }//for  
  16.  }//if   
  17.  return OK;  
  18. }//FastTransposeSMatrix   

时间复杂度分析

   该算法利用两个辅助向量num[ ]、cpos[ ],实现了对M.data一次扫描完成M到T的转置。

      从时间上看,算法中有四个并列的单循环,循环次数分别为mu、tu、t和tu,因而总的时间复杂度为O(mu+tu),在M的非零元个数tu和mu´nu同等数量级时,其时间复杂度为O( mu´nu),和转置算法5.1的时间复杂度相同。由此可见,只有当tu<< mu´nu时,使用快速转置算法才有意义。


原文:http://blog.csdn.net/fanzheng220112583/article/details/7715003

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值