【數據結構】——稀疏矩陣轉置


  矩陣是線性代數中的一個知識,剛開始學習的時候可能感覺不到它有什么用處,最初的感覺就是對二維數據的操作。其實現實生活中矩陣的用處太大了,設計領域相當的廣泛。在此只討論稀疏矩陣的轉置問題;

  可能看到矩陣就會想到二維數組,比如這樣一個矩陣:

  你可能會想到用二維數組來存放此矩陣中的元素,就像這樣:int text[][5] = {{0,5,6,0,4},{0,0,0,0,0},{1,0,0,0,0},{1,0,0,0,0},{0,2,0,0,1}};

這樣好像也沒有什么不好。我們再來看看這個矩陣,五行五列,可以包含二十五個元素,但是此矩陣只有七個元素。但是我們在存放數據的時候分配了二十五塊int單元。這樣是不是有點太浪費了。如果我們只存儲這七個元素我想會節省一部分內存空間。但是如果我們只存儲矩陣中的元素還是不行的,因為只有元素我們就無法還原矩陣,我們還需要此元素的行列值。這樣就好辦了。我們聲明一個結構體來表示一個元素。就像這樣:

1 typedef struct juzhen
2 {
3     int row;        //
4     int col;        //
5     int value;        //元素值
6 };

  這樣存儲一個元素就會用到三個存儲單元,七個就是二十一個存儲單元,可能與二十五個沒多大差別,但是如果矩陣的行列是一個很大的值,而且又是稀疏矩陣,這樣做就可以節省很大的空間。這種存儲結構只限於稀疏矩陣。

  解決了存儲結構,就開始矩陣的轉置吧!!!

  首先我們需要一個矩陣,就按照上圖給的矩陣好了,按照此矩陣做一個二維數組:

1 int text[][5] = {{0,5,6,0,4},{0,0,0,0,0},{1,0,0,0,0},{1,0,0,0,0},{0,2,0,0,1}};

  就像這樣;我們需要定義一個數組來表示稀疏矩陣,並賦值;

 1 #define MAX_TERM 15
 2 
 3 struct juzhen a[MAX_TERM];        //存放矩陣中元素數值不為零的元素
 4 
 5 int chushi(struct juzhen a[MAX_TERM])            //初始化稀疏矩陣
 6 {
 7     int count_value = 0;    //統計矩陣中元素數值不為零的元素的總和
 8     int i,j;
 9     int count_a = 1;
10     for(i = 0;i < N;i++)
11     {
12         for(j = 0;j < N;j++)
13         {
14             if(text[i][j] != 0)
15             {
16                 a[count_a].row = i;
17                 a[count_a].col = j;
18                 a[count_a].value = text[i][j];
19                 count_a++;
20             }
21         }
22     }
23     a[0].col = 5;            //矩陣的總列數
24     a[0].row = 5;            //矩陣的總行數
25     a[0].value = --count_a;    //矩陣中的元素個數
26 
27     return count_a;
28 }

  在初始化矩陣數組的時候為了方便轉置矩陣時的操作,我們把數組的第一個元素設置為矩陣的列數,行數和元素總數;

  矩陣有了,存放矩陣元素的數組也有了。接下來就是轉置矩陣的函數了。

  我們在轉置矩陣的時候會需要一個數組來保存轉置后的矩陣,定義為:

struct juzhen b[MAX_TERM];//轉置后的矩陣

  主要思想,兩層循環,第一層循環控制矩陣的行,第二層循環控制數組a的行。由於轉置矩陣即把矩陣中元素的列行對換一下,並且按照行排序;所以我們在第二層循環中做一個判斷,if(a[j].col == i) 【i控制第一層循環,j控制第二層循環】 如果為真值則執行:

                b[count_b].row = a[j].col;
                b[count_b].col = a[j].row;
                b[count_b].value = a[j].value;

整個函數如下:

void zhuanzhi_1(struct juzhen a[MAX_TERM],struct juzhen b[MAX_TERM])            //轉置矩陣方法一
{
    int i,j;
    int count_b = 1;        //b的當前元素下標
    b[0].row = a[0].col;  
    b[0].col = a[0].row;
    b[0].value = a[0].value;
    for(i = 0;i < a[0].col;i++)
    {
        for(j = 1;j <= a[0].value;j++)
        {
            if(a[j].col == i)    //有種排序效果
            {
                b[count_b].row = a[j].col;
                b[count_b].col = a[j].row;
                b[count_b].value = a[j].value;
                count_b++;
            }
        }
    }
}

  用此方法可以有效的轉置矩陣,我們來看一下此函數的時間復雜度:O(cols * elements)——矩陣的列*矩陣的元素總和;

  如果元素很多就會浪費很多的時間。有沒有辦法讓兩層循環變成一層循環呢?付出空間上的代價,換取時間效率;

  我們只用一層循環來遍歷數組a中所有元素,並把該元素放到指定的位置。這樣我們就需要一個數組star來存放第i個元素所在位置。在定義這個數組之前,我們還需要一個數組term來實現統計矩陣第i行元素的數量。這樣我們才能更方便的知道第i個元素應該存放的位置。

    int term[N],star[N];        //保存轉置矩陣第i行元素的數量  保存第i行開始位置    
    int n = a[0].value;
    int i,j,k;
    int b_star;

    for(i = 0;i < N;i++)    
        term[i] = 0;

    for(j = 0;j <= n;j++)
        term[a[j].col]++;
    
    star[0] = 1;
    for(k = 1;k < N;k++)
        star[k] = star[k - 1] + term[k - 1];

第一個循環初始化term,每個元素都為零。第二個循環是為了統計第i行元素的數量。第三個循環是設置第i個元素所在的位置。因為數組a的第一個元素是存放行列和元素的總數,因此第三個循環要從k = 1開始。此時兩個數組的元素為:

下一步就是遍歷a中的所有元素,然后根據a[i].col的值來把a[i].value放到指定的位置。

    b[0].col = a[0].col;
    b[0].row = a[0].row;
    b[0].value = a[0].value;
    for(i = 1;i <= n;i++)
    {
        b_star = star[a[i].col]++;
        b[b_star].col = a[i].row;
        b[b_star].row = a[i].col;
        b[b_star].value = a[i].value;
    }

需要注意的是b的第一個元素與a中的第一個元素是同樣的。b_star = star[a[i].col]++;因為當term[1] = 2;而star[1] = 3;就是a[i].col = 1時有兩個元素,第一個元素的位置是star[a[i].col];而第二個元素的位置就是star[a[i].col] + 1所以在此用star[a[i].col]++。為下一個元素設置相應的位置;

完整函數:

void zhuanhuan_2(struct juzhen a[MAX_TERM],struct juzhen b[MAX_TERM])
{
    int term[N],star[N];        //保存轉置矩陣第i行元素的數量  保存第i行開始位置    
    int n = a[0].value;
    int i,j,k;
    int b_star;

    for(i = 0;i < N;i++)    
        term[i] = 0;

    for(j = 1;j <= n;j++)
        term[a[j].col]++;
    
    star[0] = 1;
    for(k = 1;k < N;k++)
        star[k] = star[k - 1] + term[k - 1];

    b[0].col = a[0].col;
    b[0].row = a[0].row;
    b[0].value = a[0].value;
    for(i = 1;i <= n;i++)
    {
        b_star = star[a[i].col]++;
        b[b_star].col = a[i].row;
        b[b_star].row = a[i].col;
        b[b_star].value = a[i].value;
    }

}

此函數每個循環體的執行次數分別為cols cols elements elements 時間復雜度為O(cols + elements)和O(cols * elements)相差好多,尤其是clos 和 elements很大的時候;

完整的測試程序:

完整代碼
  1 #include<stdio.h>
  2 #define N 5
  3 #define MAX_TERM 15
  4 
  5 typedef struct juzhen
  6 {
  7     int row;        //
  8     int col;        //
  9     int value;        //元素值
 10 };
 11 
 12 int text[][5] = {{0,5,6,0,4},{0,0,0,0,0},{1,0,0,0,0},{1,0,0,0,0},{0,2,0,0,1}};
 13 struct juzhen a[MAX_TERM];        //存放矩陣中元素數值不為零的元素
 14 struct juzhen b[MAX_TERM];        //轉置后的矩陣
 15 
 16 int chushi(struct juzhen a[MAX_TERM])            //初始化稀疏矩陣
 17 {
 18     int count_value = 0;    //統計矩陣中元素數值不為零的元素的總和
 19     int i,j;
 20     int count_a = 1;
 21     for(i = 0;i < N;i++)
 22     {
 23         for(j = 0;j < N;j++)
 24         {
 25             if(text[i][j] != 0)
 26             {
 27                 a[count_a].row = i;
 28                 a[count_a].col = j;
 29                 a[count_a].value = text[i][j];
 30                 count_a++;
 31             }
 32         }
 33     }
 34     a[0].col = 5;            //矩陣的總列數
 35     a[0].row = 5;            //矩陣的總行數
 36     a[0].value = --count_a;    //矩陣中的元素個數
 37 
 38     return count_a;
 39 }
 40 
 41 void showjuzhen(struct juzhen a[MAX_TERM],int count_a)        //顯示稀疏矩陣
 42 {
 43     int i,j;
 44     int text = 1;
 45     for(i = 0;i < N;i++)
 46     {
 47         for(j = 0;j < N;j++)
 48         {
 49             if(a[text].row == i && a[text].col == j)
 50             {
 51                 printf(" %d ",a[text].value);
 52                 text++;
 53             }
 54             else
 55                 printf(" 0 ");
 56         }
 57         printf("\n");
 58     }
 59 
 60 }
 61 
 62 void showjuzhen_2(struct juzhen a[MAX_TERM],int count_a)            //顯示稀疏矩陣方法二
 63 {
 64     int i;
 65     printf(" i row col val\n");
 66     for(i = 0;i < count_a + 1;i++)
 67     {
 68         printf(" %d|  %d   %d   %d\n",i,a[i].row,a[i].col,a[i].value);
 69     }
 70 }
 71 
 72 
 73 void zhuanzhi_1(struct juzhen a[MAX_TERM],struct juzhen b[MAX_TERM])            //轉置矩陣方法一
 74 {
 75     int i,j;
 76     int count_b = 1;        //b的當前元素下標
 77     b[0].row = a[0].col;
 78     b[0].col = a[0].row;
 79     b[0].value = a[0].value;
 80     for(i = 0;i < a[0].col;i++)
 81     {
 82         for(j = 1;j <= a[0].value;j++)
 83         {
 84             if(a[j].col == i)
 85             {
 86                 b[count_b].row = a[j].col;
 87                 b[count_b].col = a[j].row;
 88                 b[count_b].value = a[j].value;
 89                 count_b++;
 90             }
 91         }
 92     }
 93 }
 94 
 95 
 96 void zhuanhuan_2(struct juzhen a[MAX_TERM],struct juzhen b[MAX_TERM])
 97 {
 98     int term[N],star[N];        
 99     int n = a[0].value;
100     int i,j,k;
101     int b_star;
102 
103     for(i = 0;i < N;i++)    
104         term[i] = 0;
105 
106     for(j = 0;j <= a[0].value;j++)
107         term[a[j].col]++;
108     
109     star[0] = 1;
110     for(k = 1;k < N;k++)
111         star[k] = star[k - 1] + term[k - 1];
112 
113     b[0].col = a[0].col;
114     b[0].row = a[0].row;
115     b[0].value = a[0].value;
116     for(i = 1;i <= n;i++)
117     {
118         b_star = star[a[i].col]++;
119         b[b_star].col = a[i].row;
120         b[b_star].row = a[i].col;
121         b[b_star].value = a[i].value;
122     }
123 
124 
125     for(i = 0;i < a[0].value + 1;i++)
126         printf(" %d|  %d   %d   %d\n",i,b[i].row,b[i].col,b[i].value);
127 
128 }
129 
130 int main(void)
131 {
132     int count_a;
133     count_a = chushi(a);
134     showjuzhen(a,count_a);
135     showjuzhen_2(a,count_a);
136     printf("\n");
137     zhuanhuan_2(a,b);
138     //zhuanzhi_1(a,b);
139     //showjuzhen(b,count_a);
140     //showjuzhen_2(b,count_a);
141     //return 0;
142 }

 


免責聲明!

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



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