算法小记 | 对稀疏矩阵的快速转置法的理解

233 阅读3分钟

算法小记 | 对稀疏矩阵的快速转置法的理解

“开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 3 天,点击查看活动详情

关于稀疏矩阵的快速转置法,首先得明白其是通过对三元表 进行转置,而不是对于矩阵本身进行转置,这一点要先理解。(!!!🍗)

一个三元顺序表有row(行),col(列),val(值),虽然直接交换row和col可以完成转置,但是得到的是一个混乱的矩阵。所以普通的转置是通过扫描(O(n2))的方法来完整矩阵转置的,比较慢我这里就直接放代码了。

 #define MaxSize  100    //矩阵中非零元素最多个数 
 typedef int ElemType;//矩阵元素数据类型 
 typedef struct { //三元组定义 
     int i, j; //非零元素行号、列号 
     ElemType e; //非零元素的值
 } Triple;
 typedef struct { //稀疏矩阵结构定义 
     int mu, nu, tu; //矩阵行、列、非零元素
     Triple data[MaxSize];    //三元组表
 } TSMatrix; 
 ​
 void TransposeSMatrix(TSMatrix M, TSMatrix &T) { 
     int p, q, col;
     T.mu = M.nu; 
     T.nu = M.mu;
     T.tu = M.tu;
     if(T.tu) { 
         q = 1;
         for(col = 1; col <= M.nu; ++col) 
             for(p = 1; p <= M.tu; ++p) 
                 if(M.data[p].j == col) { 
                 T.data[q].i = M.data[p].j; 
                 T.data[q].j = M.data[p].i;
                 T.data[q].e = M.data[p].e; 
                 ++q; 
                 } 
     } 

为了要实现快速转置,就要在扫描一遍的情况下找出转置后行(即转置前的列)所在的位置。

enter description here

col=0有1个,col=1有1个、col=2有1个、col=3有2个、col=5有2个、col=6有1个。

根据这些数据按照从小到大排列,col=0占据数组0位,col=1的项在新的三元表中应占据数组1位,col=2的项在新的三元表中应占据数组2位,col=3的项在新的三元表中应占据数组3、4位,col=4不占位,col=5应数组5、6位,col=6应数组第7位。

接下来就轻松多了,转置的时候直接从第一项读起,读取其col值,按照位置一个一个放就行。

为此,建立两个辅助数组 num[col] 和cpot[col]:

  • num[col] :记录转置前各列非零元素个数,即转置后就 是各行非零元素个数;
  • cpot[col] :记录转置后各行第一个非零元素开始的位置。

有了这个两个数组,就可以按照cpot[]找到转置后行每一个元素出现的位置,然后往后填写num[col]个元素,填着填着顺序就出来了。

  void FastTransposeSMatrix(TSMatrix M, TSMatrix &T) { 
     int p, q, t, col, num[MaxSize], cpot[MaxSize];
     T.mu = M.nu;         // 给T的行、列数与非零元素个数赋值 
     T.nu = M.mu; T.tu = M.tu;
     if(T.tu) {           // 是非零矩阵 
         for(col = 0; col < M.nu; ++col) 
             num[col] = 0;               // 计数器初值设为0 // 求M中每一列含非零元素个数 
         for(t = 0; t < M.tu; ++t) 
             ++num[M.data[t].j]; // T的第0行的第0个非零元在T.data中的下标为0 
         cpot[0] = 0; 
         for(col = 1; col < M.nu; ++col) 
             cpot[col] = cpot[col - 1] + num[col - 1];     
         for(p = 0; p < M.tu; ++p) {
             col = M.data[p].j;         // 求得在M中的列数 // q指示M当前的元素在T中的序号 
             q = cpot[col]; 
             T.data[q].i = M.data[p].j; 
             T.data[q].j = M.data[p].i; 
             T.data[q].e = M.data[p].e; // T第col行的下一个非零元在T.data中的序号 
             ++cpot[col];   
             }
     }
 }

本文只是个人理解,如有不理解的地方可以看下这篇文章