javascript實現數據結構: 稀疏矩陣之三元組線性表表示

稀疏矩陣(Sparse Matrix):對於稀疏矩陣,目前尚未一個確切的定義。設矩陣A是一個n*m的矩陣中有s個非零元素,設  δ=s/(n*m),稱δ爲稀疏因子,算法

若是某一矩陣的稀疏因子δ知足δ≦0.05時稱爲稀疏矩陣,數組

 

 

稀疏矩陣的壓縮存儲app

對於稀疏矩陣,採用壓縮存儲方法時,只存儲非0元素。必須存儲非0元素的行下標值、列下標值、元素值。所以,一個三元組(i, j, aij)惟一肯定稀疏矩陣的一個非零元素。ide

上圖的稀疏矩陣A的三元組線性表爲: ( (1,2,12), (1,3,9), (3,1,-3), (3,8,4), (4,3,24), (5,2,18), (6,7,-7), (7,4,-6) )ui

 

1  三元組順序表this

若以行序爲主序,稀疏矩陣中全部非0元素的三元組,就能夠得構成該稀疏矩陣的一個三元組順序表。spa

 

 1 function Triple(i, j, elem) {
 2     // 該非零元的行下標和列下標
 3     this.i = i || 0;
 4     this.j = j || 0;
 5     this.e = elem || null;
 6 }
 7 
 8 function TSMatrix(mu, nu) {
 9     // 非零元三元組表
10     this.data = [];
11     // 矩陣的行數,列數
12     this.mu = mu || 0;
13     this.nu = nu || 0;
14 }

 

下圖所示的稀疏矩陣及其相應的轉置矩陣所對應的三元組順序表:prototype

 

 

一個m*n的矩陣A,它的轉置B是一個n*m的矩陣,且b[i][j]=a[j][i],0≦i≦n,0≦j≦m,即B的行是A的列,B的列是A的行。code

設稀疏矩陣A是按行優先順序壓縮存儲在三元組表a.data中,若僅僅是簡單地交換a.data中i和j的內容,獲得三元組表b.data,blog

b.data將是一個按列優先順序存儲的稀疏矩陣B,要獲得按行優先順序存儲的b.data,就必須從新排列三元組表b.data中元素的順序。

 

求轉置矩陣的基本算法思想是:

① 將矩陣的行、列下標值交換。即將三元組表中的行、列位置值i 、j相互交換;

② 重排三元組表中元素的順序。即交換後仍然是按行優先順序排序的。

 

方法一: 算法思想:按稀疏矩陣A的三元組表a.data中的列次序依次找到相應的三元組存入b.data中。

每找轉置後矩陣的一個三元組,需從頭到尾掃描整個三元組表a.data 。找到以後天然就成爲按行優先的轉置矩陣的壓縮存儲表示

TSMatrix.prototype = {
    constructor: TSMatrix,
    addTriple: function (triple) {
        if (triple instanceof Triple) {
            if(triple.i >= this.mu)
                this.mu = triple.i + 1;
            if(triple.j >= this.nu)
                this.nu = triple.j + 1;

            this.data.push(triple);
            return true;
        }
        return false;
    },
    // 採用三元組表存儲表示,求稀疏矩陣的轉置矩陣t
    // 按照b.data中三元組的次序依次在a.data中找到相應的三元組進行轉置
    transposeSMatrix: function () {
        var t = new TSMatrix();
        t.mu = this.nu;
        t.nu = this.mu;

        if (this.data.length) {
            var q = 0;
            for (var col = 0; col < this.nu; col++) {
                for (var p = 0; p < this.data.length; p++) {
                    if (this.data[p].j === col)
                        t.data[q++] = new Triple(this.data[p].j, this.data[p].i, this.data[p].e);
                }
            }
        }

        return t;
    }
};

 

算法分析:本算法主要的工做是在p和col的兩個循環中完成的,故算法的時間複雜度爲O(nu * data.length),即矩陣的列數和非0元素的個數的乘積成正比。

 

方法二(快速轉置的算法) 算法思想:

直接按照稀疏矩陣A的三元組表a.data的次序依次順序轉換,並將轉換後的三元組放置於三元組表b.data的恰當位置。

前提:若能預先肯定原矩陣A中每一列的(即B中每一行)第一個非0元素在b.data中應有的位置,則在做轉置時就可直接放在b.data中恰當的位置。

所以,應先求得A中每一列的非0元素個數。 附設兩個輔助向量num[ ]和cpot[ ] 。

◆ num[col]:統計A中第col列中非0元素的個數;

◆ cpot[col] :指示A中第一個非0元素在b.data中的恰當位置。

顯然有位置對應關係:

快速轉置算法以下:

 1 // 採用三元組表存儲表示,求稀疏矩陣的轉置矩陣t
 2 /*
 3  按照a.data中三元組的次序進行轉置,並將轉置後的三元組置入b中恰當的位置。
 4  若是能預先肯定矩陣M中每一列(即T中每一行)的第一個非零元在b.data中應有的位置,
 5  那麼在對a.data中的三元組依次作轉置時,即可直接放到b.data中恰當的位置上去。
 6  爲了其額定這些位置,在轉置前,應先求得M的每一列中非零元的個數,進而求得每一列的第一個非零元在b.data中應有的位置。
 7  在此,須要設num和cpot兩個變量。num[col]表示矩陣M中第col列中非零元的個數,
 8  cpot[col]指示M中第col列的第一個非零元在b.data中的恰當位置。顯然有:
 9  cpot[0] = 1;
10  cpot[col] = cpot[col - 1] + num[col - 1]    2 <= col <= a.nu
11  */
12 TSMatrix.prototype.fastTransposeSMatrix = function(){
13     var t = new TSMatrix();
14     t.mu = this.nu;
15     t.nu = this.mu;
16 
17     if(this.data.length){
18         var num = [];
19         for(var col = 0; col < this.nu; col++)
20             num[col] = 0;
21         for(var i = 0; i < this.data.length; i++)
22             ++num[this.data[i].j];  // 求矩陣中每一列含非零元個數
23         // 求第col列中第一個非零元在b.data中的序號
24         var cpot = [0];
25         for(col = 1; col < this.nu; col++)
26             // 上一列以前的序號+上一列的非零元個數 = 該列的序號
27             cpot[col] = cpot[col - 1] + num[col - 1];
28         for(var p = 0; p < this.data.length; p++){
29             col = this.data[p].j;
30             var q = cpot[col];
31             t.data[q] = new Triple(this.data[p].j, this.data[p].i, this.data[p].e);
32             // 給該列的序號+1,用做相同列數的狀況
33             ++cpot[col];
34         }
35     }
36 
37     return t;
38 }

三元組順序表又稱有序的雙下標法,它的特色是,非零元在表中按行序有序存儲,所以便於進行依行順序處理的矩陣運算
然而,若需按行號存取某一行的非零元,則從頭開始進行查找

 

 

行邏輯連接的順序表

爲了便於隨機存取任意一行的非零元,則需知道每一行的第一個非零元在三元組表中的位置。

爲此可將快速轉置矩陣的算法中建立的,指示「行」信息的輔助數組cpot固定在稀疏矩陣的存儲結構中。

稱這種「帶行連接信息」的三元組表爲行邏輯連接的順序表

 

設有兩個稀疏矩陣A=(aij)m*n ,B=(bij)n*p ,其存儲結構採用行邏輯連接的三元組順序表。求稀疏矩陣的乘法:

 1 function RLSMatrix(mu, nu){
 2     TSMatrix.apply(this, arguments);
 3     this.rpos = [0];
 4 }
 5 RLSMatrix.MAXSIZE = 100;
 6 RLSMatrix.prototype = {
 7     constructor: RLSMatrix,
 8     __proto__: TSMatrix.prototype,
 9     // todo
10     /**
11      * 求矩陣乘積Q = M * N,採用行邏輯連接存儲表示
12      * @param nMatrix
13      * @returns {RLSMatrix}
14      */
15     multSMatrix: function(nMatrix){
16         if(this.nu !== nMatrix.mu) throw Error('nu is not equivalent to mu');
17 
18         // 初始化Q
19         var qMatrix = new RLSMatrix(this.mu, nMatrix.nu);
20         // Q是非零矩陣
21         if(this.data.length * nMatrix.data.length !== 0){
22             // 處理M的每一行
23             for(var arow = 0; arow < this.mu; arow++){
24                 // 當前行各元素累加器清零
25                 var ctemp = [];
26                 qMatrix.rpos[arow] = qMatrix.data.length + 1;
27                 var tp, ccol;
28 
29                 if(arow < this.mu)
30                     tp = this.rpos[arow + 1];
31                  else
32                     tp = this.data.length + 1;
33 
34                 //對當前行中每個非零元找到對應元在N中的行號
35                 for(var p = this.rpos[arow]; p < tp; p++){
36                     var brow = this.data[p].j;
37                     var t;
38                     if(brow < nMatrix.mu)
39                         t = nMatrix.rpos[brow + 1];
40                     else
41                         t = nMatrix.data.length + 1;
42 
43                     for(var q = nMatrix.rpos[brow]; q < t; q++){
44                         // 乘積元素在Q中的序號
45                         ccol = nMatrix.data[q].j;
46                         ctemp[ccol] = (ctemp[ccol] || 0) + this.data[p].e * nMatrix.data[q].e;
47                     }
48                 }
49 
50                 // 壓縮存儲該行非零元
51                 for(ccol = 1; ccol < qMatrix.nu; ccol++){
52                     if(ctemp[ccol]){
53                         if(++qMatrix.data.length > RLSMatrix.MAXSIZE) throw Error('overflow');
54                         qMatrix.data[qMatrix.data.length - 1] = new Triple(arow, ccol, ctemp[ccol]);
55                     }
56                 }
57             }
58         }
59 
60         return qMatrix;
61     },
62     _calcPos: function clcPos(){
63         var num = [];
64         for(var col = 0; col < this.nu; col++)
65             num[col] = 0;
66         for(var i = 0; i < this.data.length; i++)
67             ++num[this.data[i].j];  // 求矩陣中每一列含非零元個數
68         // 求第col列中第一個非零元在b.data中的序號
69         for(col = 1; col < this.nu; col++)
70             // 上一列以前的序號+上一列的非零元個數 = 該列的序號
71             this.rpos[col] = this.rpos[col - 1] + num[col - 1];
72     }
73 };

 

全部代碼:

  1 /**
  2  * 係數矩陣的三元組順序表存儲表示
  3  */
  4 
  5 
  6 function Triple(i, j, elem) {
  7     // 該非零元的行下標和列下標
  8     this.i = i || 0;
  9     this.j = j || 0;
 10     this.e = elem || null;
 11 }
 12 
 13 function TSMatrix(mu, nu) {
 14     // 非零元三元組表
 15     this.data = [];
 16     // 矩陣的行數,列數
 17     this.mu = mu || 0;
 18     this.nu = nu || 0;
 19 }
 20 TSMatrix.prototype = {
 21     constructor: TSMatrix,
 22     addTriple: function (triple) {
 23         if (triple instanceof Triple) {
 24             if(triple.i >= this.mu)
 25                 this.mu = triple.i + 1;
 26             if(triple.j >= this.nu)
 27                 this.nu = triple.j + 1;
 28 
 29             this.data.push(triple);
 30             return true;
 31         }
 32         return false;
 33     },
 34     // 採用三元組表存儲表示,求稀疏矩陣的轉置矩陣t
 35     // 按照b.data中三元組的次序依次在a.data中找到相應的三元組進行轉置
 36     transposeSMatrix: function () {
 37         var t = new TSMatrix();
 38         t.mu = this.nu;
 39         t.nu = this.mu;
 40 
 41         if (this.data.length) {
 42             var q = 0;
 43             for (var col = 0; col < this.nu; col++) {
 44                 for (var p = 0; p < this.data.length; p++) {
 45                     if (this.data[p].j === col)
 46                         t.data[q++] = new Triple(this.data[p].j, this.data[p].i, this.data[p].e);
 47                 }
 48             }
 49         }
 50 
 51         return t;
 52     },
 53     // 採用三元組表存儲表示,求稀疏矩陣的轉置矩陣t
 54     /*
 55     按照a.data中三元組的次序進行轉置,並將轉置後的三元組置入b中恰當的位置。
 56     若是能預先肯定矩陣M中每一列(即T中每一行)的第一個非零元在b.data中應有的位置,
 57     那麼在對a.data中的三元組依次作轉置時,即可直接放到b.data中恰當的位置上去。
 58     爲了其額定這些位置,在轉置前,應先求得M的每一列中非零元的個數,進而求得每一列的第一個非零元在b.data中應有的位置。
 59     在此,須要設num和cpot兩個變量。num[col]表示矩陣M中第col列中非零元的個數,
 60     cpot[col]指示M中第col列的第一個非零元在b.data中的恰當位置。顯然有:
 61     cpot[0] = 1;
 62     cpot[col] = cpot[col - 1] + num[col - 1]    2 <= col <= a.nu
 63      */
 64     fastTransposeSMatrix: function(){
 65         var t = new TSMatrix();
 66         t.mu = this.nu;
 67         t.nu = this.mu;
 68 
 69         if(this.data.length){
 70             var num = [];
 71             for(var col = 0; col < this.nu; col++)
 72                 num[col] = 0;
 73             for(var i = 0; i < this.data.length; i++)
 74                 ++num[this.data[i].j];  // 求矩陣中每一列含非零元個數
 75             // 求第col列中第一個非零元在b.data中的序號
 76             var cpot = [0];
 77             for(col = 1; col < this.nu; col++)
 78                 // 上一列以前的序號+上一列的非零元個數 = 該列的序號
 79                 cpot[col] = cpot[col - 1] + num[col - 1];
 80             for(var p = 0; p < this.data.length; p++){
 81                 col = this.data[p].j;
 82                 var q = cpot[col];
 83                 t.data[q] = new Triple(this.data[p].j, this.data[p].i, this.data[p].e);
 84                 // 給該列的序號+1,用做相同列數的狀況
 85                 ++cpot[col];
 86             }
 87         }
 88 
 89         return t;
 90     }
 91 };
 92 
 93 var a1 = new Triple(1, 2, 12);
 94 var a2 = new Triple(1, 3, 9);
 95 var a3 = new Triple(3, 1, -3);
 96 var a4 = new Triple(3, 6, 14);
 97 var a5 = new Triple(4, 3, 24);
 98 var a6 = new Triple(5, 2, 18);
 99 var a7 = new Triple(6, 1, 15);
100 var a8 = new Triple(6, 4, -7);
101 
102 var matrix = new TSMatrix();
103 matrix.addTriple(a1);
104 matrix.addTriple(a2);
105 matrix.addTriple(a3);
106 matrix.addTriple(a4);
107 matrix.addTriple(a5);
108 matrix.addTriple(a6);
109 matrix.addTriple(a7);
110 matrix.addTriple(a8);
111 
112 console.log(matrix.transposeSMatrix());
113 console.log(matrix.fastTransposeSMatrix());
114 
115 /*
116 三元組順序表又稱有序的雙下標法,它的特色是,非零元在表中按行序有序存儲,所以便於進行依行順序處理的矩陣運算。
117 然而,若需按行號存取某一行的非零元,則從頭開始進行查找。
118  */
119 
120 /**
121  * 行邏輯連接的順序表
122  *
123  * 爲了便於隨機存取任意一行的非零元,則需知道每一行的第一個非零元在三元組表中的位置。
124  * 爲此可將快速轉置矩陣的算法中建立的,指示「行」信息的輔助數組cpot固定在稀疏矩陣的存儲結構中。
125  * 稱這種「帶行連接信息」的三元組表爲行邏輯連接的順序表
126  */
127 
128 function RLSMatrix(mu, nu){
129     TSMatrix.apply(this, arguments);
130     this.rpos = [0];
131 }
132 RLSMatrix.MAXSIZE = 100;
133 RLSMatrix.prototype = {
134     constructor: RLSMatrix,
135     __proto__: TSMatrix.prototype,
136     // todo
137     /**
138      * 求矩陣乘積Q = M * N,採用行邏輯連接存儲表示
139      * @param nMatrix
140      * @returns {RLSMatrix}
141      */
142     multSMatrix: function(nMatrix){
143         if(this.nu !== nMatrix.mu) throw Error('nu is not equivalent to mu');
144 
145         // 初始化Q
146         var qMatrix = new RLSMatrix(this.mu, nMatrix.nu);
147         // Q是非零矩陣
148         if(this.data.length * nMatrix.data.length !== 0){
149             // 處理M的每一行
150             for(var arow = 0; arow < this.mu; arow++){
151                 // 當前行各元素累加器清零
152                 var ctemp = [];
153                 qMatrix.rpos[arow] = qMatrix.data.length + 1;
154                 var tp, ccol;
155 
156                 if(arow < this.mu)
157                     tp = this.rpos[arow + 1];
158                  else
159                     tp = this.data.length + 1;
160 
161                 //對當前行中每個非零元找到對應元在N中的行號
162                 for(var p = this.rpos[arow]; p < tp; p++){
163                     var brow = this.data[p].j;
164                     var t;
165                     if(brow < nMatrix.mu)
166                         t = nMatrix.rpos[brow + 1];
167                     else
168                         t = nMatrix.data.length + 1;
169 
170                     for(var q = nMatrix.rpos[brow]; q < t; q++){
171                         // 乘積元素在Q中的序號
172                         ccol = nMatrix.data[q].j;
173                         ctemp[ccol] = (ctemp[ccol] || 0) + this.data[p].e * nMatrix.data[q].e;
174                     }
175                 }
176 
177                 // 壓縮存儲該行非零元
178                 for(ccol = 1; ccol < qMatrix.nu; ccol++){
179                     if(ctemp[ccol]){
180                         if(++qMatrix.data.length > RLSMatrix.MAXSIZE) throw Error('overflow');
181                         qMatrix.data[qMatrix.data.length - 1] = new Triple(arow, ccol, ctemp[ccol]);
182                     }
183                 }
184             }
185         }
186 
187         return qMatrix;
188     },
189     _calcPos: function clcPos(){
190         var num = [];
191         for(var col = 0; col < this.nu; col++)
192             num[col] = 0;
193         for(var i = 0; i < this.data.length; i++)
194             ++num[this.data[i].j];  // 求矩陣中每一列含非零元個數
195         // 求第col列中第一個非零元在b.data中的序號
196         for(col = 1; col < this.nu; col++)
197             // 上一列以前的序號+上一列的非零元個數 = 該列的序號
198             this.rpos[col] = this.rpos[col - 1] + num[col - 1];
199     }
200 };
201 
202 var b1 = new Triple(1, 1, 3);
203 var b2 = new Triple(1, 3, 5);
204 var b3 = new Triple(2, 2, -1);
205 var b4 = new Triple(3, 1, 2);
206 
207 var t1 = new RLSMatrix();
208 t1.addTriple(b1);
209 t1.addTriple(b2);
210 t1.addTriple(b3);
211 t1.addTriple(b4);
212 t1._calcPos();
213 
214 var c1 = new Triple(1, 2, 2);
215 var c2 = new Triple(2, 1, 1);
216 var c3 = new Triple(3, 1, -2);
217 var c4 = new Triple(3, 2, 4);
218 
219 var t2 = new RLSMatrix();
220 t2.addTriple(c1);
221 t2.addTriple(c2);
222 t2.addTriple(c3);
223 t2.addTriple(c4);
224 t2._calcPos();
225 
226 t1.multSMatrix(t2);
View Code
相關文章
相關標籤/搜索