數據結構25:矩陣轉置算法(三元組順序表)


矩陣的轉置實際上就是將數據元素的行標和列標互換,即 T(i,j) = M(j,i) 。例如:

 
圖1 矩陣的轉置
相應地,三元組表轉變為:
 
圖2 三元組表
矩陣的轉置,經歷了三個步驟:

  • 矩陣的行數 n 和列數 m 的值交換;
  • 將三元組中的i和j調換;
  • 轉換之后的表同樣按照行序(置換前的列序)為主序,進行排序;
實現三元組的轉換,重點在第三步,實現算法有兩種。
 

普通算法

普通算法的實現過程為:
  1. 將矩陣的行數和列數進行調換;
  2. 遍歷表 a 的 j 列(查找 j 的值,從 1 一直到未轉置之前的矩陣的列數 m ),遍歷的過程,就可以自動存儲為表 b 的形式。
因為在表 a 中 i 列的數值是從小到大的,在根據 j 列由上到下的遍歷時, i 列同樣也是有序的。
實現代碼:
TSMatrix transposeMatrix(TSMatrix M, TSMatrix T)
{   
//行和列置換   T.m = M.n;   T.n = M.m;   T.num = M.num;   if (T.num)
  {     
int q = 0;     //依次遍歷M矩陣的列(從1開始),的遍歷的過程中將行標和列標置換,得到置換后的三元表T     for (int col=1; col<=M.m; col++)
    {       
for (int p=0; p<M.num; 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].data = M.data[p].data;           q++;         }       }     }   }
  
return T; }

 

此算法的時間復雜度關鍵在於嵌套的兩個 for 循環,時間復雜度為 O(m*num),和矩陣的列數以及非 0 元素的個數的乘積成正比,如果稀疏矩陣的非 0 元素很多的情況,使用這個算法,雖然一定程度上節省了空間,但是時間復雜度會很高。

快速轉置算法

快速轉置算法在普通算法的基礎上,對遍歷存儲的過程做了改進。

首先將每一列中非 0 元素的個數對應地存儲在一個數組(數組名為array)中。在此基礎上,計算出每一列第一個元素存放在三元組表中的位置,存儲在數組(數組名為 cpot )中。
第一列第一個非 0 元素肯定存放在第一個位置,第二列第一個非 0 元素的位置 = 第一列存放的起始位置 + 第一列的非 0 元素個數,以此類推。

用圖 2 中置換之前的表舉例:

array 數組中的數據表示,第一列有一個非 0 元素,第二列中 3 個非0元素。
 

cpot 數組中的數據表示,第一列中第一個數據存儲的位置默認是 1 ,第二列第一個非 0 元素存放的位置是 2。

計算方法是:cpot[col] = cpot[col-1] + array[col-1],即后邊一列第一個非 0 元素存放的位置為前邊一列第一個非 0 元素存放的位置加上該列非 0 元素的個數的和。
在以上兩個數組的基礎上,當遍歷表 a 的 j 列時,根據每個元素 j 列的數值,就可以判斷出它在表 b 中的存放位置,整個三元組表只需要遍歷一次,就能實現矩陣的轉置。

實現代碼:
TSMatrix fastTransposeMatrix(TSMatrix M, TSMatrix T)
{   
//行和列置換   T.m = M.n;   T.n = M.m;   T.num = M.num;   if (T.num)
  {     
//創建並初始化array數組     int array[number];     for (int col=1; col<=M.m; col++)
    {       array[col]
=0;     }     for (int t=0; t<M.num; t++)
    {       
int j = M.data[t].j;       array[j]++;     }
    
//創建並初始化cpot數組     int cpot[T.m+1];     cpot[1]=1;  //第一列中第一個非0元素的位置默認為1     for (int col=2; col<=M.m; col++)
    {       cpot[col]
= cpot[col-1]+array[col-1];     }
    
for (int p=0; p<M.num; p++)
    {       
//提取當前三元組的列數       int col = M.data[p].j;       //根據列數和cpot數組,找到當前元素需要存放的位置       int q = cpot[col];       //轉置矩陣的三元組默認從數組下標0開始,而得到的q值是單純的位置,所以要減1       T.data[q-1].i = M.data[p].j;       T.data[q-1].j = M.data[p].i;       T.data[q-1].data = M.data[p].data;       //存放完成后,cpot數組對應的位置要+1,以便下次該列存儲下一個三元組       cpot[col]++;     }   }
  
return T; }
這個算法中含有四個並列的單循環,時間復雜度為 O(m+num)(實際得到的是 O(2*m+2*num),當 m 和 num 足夠大時,可以省略常數參數),即使最壞情況下,矩陣中的元素都是非 0 元素,時間負責度為 O(m*n)。稱此算法為快速轉置算法。

兩種算法的完整代碼

 1 #include<stdio.h>
 2 #define number 10
3 typedef struct
  {
4   int i,j; 5   int data; 6 }triple;
7 typedef struct
  {
8   triple data[number]; 9   int rpos[number]; 10   int n,m,num; 11 }TSMatrix;
12 TSMatrix transposeMatrix(TSMatrix M,TSMatrix T)
  {
13   T.m = M.n; 14   T.n = M.m; 15   T.num = M.num;
16   if (T.num)
   {
17     int q = 0; 18     for (int col=1; col<=M.m; col++)
      {
19       for (int p=0; p<M.num; p++)
        {
20         if (M.data[p].j == col)
          {
21           T.data[q].i = M.data[p].j; 22           T.data[q].j = M.data[p].i; 23           T.data[q].data = M.data[p].data; 24           q++; 25         } 26       } 27     } 28   }
29   return T; 30 }
31 TSMatrix fastTransposeMatrix(TSMatrix M, TSMatrix T)
  {
32   T.m = M.n; 33   T.n = M.m; 34   T.num = M.num; 35   if (T.num)
    {
36     int array[number]; 37     for (int col=1; col<=M.m; col++)
      {
38       array[col] = 0; 39     } 40     for (int t=0; t<M.num; t++)
      {
41       int j = M.data[t].j; 42       array[j]++; 43     } 44     int cpot[T.m+1]; 45     cpot[1] = 1; 46     for (int col=2; col<=M.m; col++)
      {
47       cpot[col] = cpot[col-1]+array[col-1]; 48     } 49     for (int p=0; p<M.num; p++)
      {
50       int col = M.data[p].j; 51       int q = cpot[col]; 52       T.data[q-1].i = M.data[p].j; 53       T.data[q-1].j = M.data[p].i; 54       T.data[q-1].data = M.data[p].data; 55       cpot[col]++; 56     } 57   } 58
    return T; 59 }
60 int main()
  {
61   TSMatrix M; 62   M.m = 2; 63   M.n = 3; 64   M.num = 4; 65   M.data[0].i = 1; 66   M.data[0].j = 2; 67   M.data[0].data = 1; 68   M.data[1].i = 2; 69   M.data[1].j = 2; 70   M.data[1].data = 3; 71   M.data[2].i = 3; 72   M.data[2].j = 1; 73   M.data[2].data = 6; 74   M.data[3].i = 3; 75   M.data[3].j = 2; 76   M.data[3].data = 5; 77   TSMatrix T; 78   T=transposeMatrix(M, T); 79   printf("使用普通方法:\n"); 80   for (int i=0; i<T.num; i++)
    {
81     printf("(%d,%d,%d)", T.data[i].i, T.data[i].j, T.data[i].data); 82   } 83   printf("\n"); 84   TSMatrix T1; 85   T1 = fastTransposeMatrix(M, T1); 86   printf("使用改進方法:\n"); 87   for (int i=0; i<T.num; i++)
    {
88     printf("(%d,%d,%d)", T.data[i].i, T.data[i].j, T.data[i].data); 89   }
90   return 0; 91 }


輸出結果
使用普通方法:
(1,3,6)(2,1,1)(2,2,3)(2,3,5)
使用改進方法:
(1,3,6)(2,1,1)(2,2,3)(2,3,5)

 



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM