首页 > 代码库 > javascript实现数据结构:稀疏矩阵的十字链表存储表示

javascript实现数据结构:稀疏矩阵的十字链表存储表示

当矩阵的非零个数和位置在操作过程中变化大时,就不宜采用顺序存储结构来表示三元组的线性表。例如,在作“将矩阵B加到矩阵A上”的操作时,由于非零元的插入或删除将会引起A.data中元素的移动。为此,对这种类型的矩阵,采用链式存储结构表示三元组的线性表更为恰当。

在链表中,每个非陵园可用一个含5个域的结点表示,其中i,j和e这3个域分别表示该非零元所在的行,列和非零元的值,向右域right用以链接同一行中下一个非零元,向下域down用以链接同一列中下一个非零元。同一行的非零元通过right域链接成一个线性表,同一列中的非零元通常down域链接成一个线性链表,每一个非零元既是某个行链表中的一个结点,又是某个列链表中的一个结点,整个矩阵构成了一个十字交叉的链表。

可用两个分别存储行链表的头指针和列链表的头指针的一维数组来表示。

 

代码:

  1 /**
  2  * 十字链表
  3  *
  4  * 当矩阵的非零个数和位置在操作过程中变化大时,就不宜采用顺序存储结构来表示三元组的线性表。例如,在作“将矩阵B加到矩阵A上”的操作时,由于非零元的插入或删除将会引起A.data中元素的移动。为此,对这种类型的矩阵,采用链式存储结构表示三元组的线性表更为恰当。
  5  *
  6  * 在链表中,每个非陵园可用一个含5个域的结点表示,其中i,j和e这3个域分别表示该非零元所在的行,列和非零元的值,向右域right用以链接同一行中下一个非零元,向下域down用以链接同一列中下一个非零元。同一行的非零元通过right域链接成一个线性表,同一列中的非零元通常down域链接成一个线性链表,每一个非零元既是某个行链表中的一个结点,又是某个列链表中的一个结点,整个矩阵构成了一个十字交叉的链表。
  7  *
  8  * 可用两个分别存储行链表的头指针和列链表的头指针的一维数组来表示。
  9  */
 10 
 11     // 稀疏矩阵的十字链表存储表示
 12 
 13 function OLNode(i, j, e) {
 14     // 该非零元的行和列下标
 15     this.i = i || 0;
 16     this.j = j || 0;
 17     this.e = e;
 18     // 该非零元所在行表和列表的后继链域
 19     this.right = null;  // type: OLNode
 20     this.down = null;   // type: OLNode
 21 }
 22 
 23 function CrossList() {
 24     // 行和列链表头指针向量基址由CreateSMatrix分配
 25     this.rhead = [];
 26     this.chead = [];
 27     // 稀疏矩阵的行数,列数
 28     this.mu = 0;
 29     this.nu = 0;
 30     this.tu = 0;
 31 }
 32 /**
 33  * 矩阵初始化
 34  * @param m
 35  * @param n
 36  * @param t
 37  * @param {Array} list 二维数组,每行的元素分别是[i, j, e]
 38  */
 39 CrossList.prototype.createSMatrix = function (m, n, t, list) {
 40     this.mu = m;
 41     this.nu = n;
 42     this.tu = t;
 43 
 44     for (var row = 0; row < list.length; row++) {
 45         var p = {};
 46         OLNode.apply(p, list[row]);
 47         var i = list[row][0];
 48         var j = list[row][1];
 49         var q;
 50 
 51         if (this.rhead[i] == null || this.rhead[i].j > j) {
 52             p.right = this.rhead[i];
 53             this.rhead[i] = p;
 54         } else {
 55             // 查询在行表中的插入位置
 56             for (q = this.rhead[i]; q.right && q.right.j < j; q = q.right);
 57             p.right = q.right;
 58             q.right = p;
 59         }
 60 
 61         if (this.chead[j] == null || this.chead[j].i > i) {
 62             p.down = this.chead[j];
 63             this.chead[j] = p;
 64         } else {
 65             for (q = this.chead[j]; q.down && q.down.i < i; q = q.down);
 66             p.down = q.down;
 67             q.down = p;
 68         }
 69     }
 70 };
 71 
 72 // 矩阵相加
 73 CrossList.prototype.addMatrix = function (crossList) {
 74     var hl = [];
 75     //hl初始化
 76     for (var j = 0; j <= this.nu; j++)
 77         hl[j] = this.chead[j];
 78 
 79     for (var i = 0; i <= this.mu; i++) {
 80         //pa和pb指向每一行的第一个非0元结点,直至最后一行
 81         var pa = this.rhead[i];
 82         var pb = crossList.rhead[i];
 83         var pre = null;
 84 
 85         //处理B的一行,直至本行中无非0元素的结点
 86         while (pb) {
 87             var p, q;
 88             // 新插入一个结点到pa的左侧
 89             if (!pa || pa.j > pb.j) {
 90                 p = new OLNode(pb.i, pb.j, pb.e);
 91 
 92                 //行表的指针变化
 93                 if (!pre) this.rhead[p.i] = p;
 94                 else pre.right = p;
 95 
 96                 p.right = pa;
 97                 pre = p;
 98 
 99                 //列表的指针变化
100                 if (hl[p.j]) {
101                     // 从hl[p.j]开始找到新结点在同一列中的前驱结点,并让hl[p.j]指向它
102                     for (q = hl[p.j]; q && q.i < p.i;q = q.down)
103                         hl[p.j] = q;
104                 }
105 
106                 //在列表中插入新结点,根据行数判断插入前面还是后面
107                 if (!this.chead[p.j] || this.chead[p.j].i > p.i) {
108                     p.down = this.chead[p.j];
109                     this.chead[p.j] = p;
110                 } else {
111                     p.down = hl[p.j].down;
112                     hl[p.j].down = p;
113                 }
114 
115                 hl[p.j] = p;
116                 pb = pb.right;
117             } else if (pa.j < pb.j) {
118                 pre = pa;
119                 pa = pa.right;
120             } else {
121                 //当pa.j === pb.j时,将B中当前结点的值加到A中当前结点上
122                 pa.e += pb.e;
123 
124                 //当pa.e === 0时,删除该结点
125                 if (pa.e === 0) {
126                     // 若无前驱结点,将第一个非0元结点置为当前结点的后继结点,
127                     // 否则前驱结点的后继结点为当前结点的后继结点
128                     if (!pre) this.rhead[pa.i] = pa.right;
129                     else pre.right = pa.right;
130 
131                     p = pa;
132                     pa = pa.right;
133 
134                     //列表的指针变化
135                     if (hl[p.j]) {
136                         //从hl[p.j]开始找到新结点在同一列中的前驱结点,并让hl[p.j]指向它
137                         for (q = hl[p.j]; q && q.i < p.i; q = q.down)
138                             hl[p.j] = q;
139                     }
140 
141                     if (this.chead[p.j] == p)
142                         this.chead[p.j] = hl[p.j] = p.down;
143                     else
144                         hl[p.j].down = p.down;
145                 }
146 
147                 pb = pb.right;
148             }
149         }
150     }
151 };
152 
153 var lists = [
154     [1, 4, 5],
155     [2, 2, -1],
156     [1, 1, 3],
157     [3, 1, 2]
158 ];
159 var a = new CrossList();
160 a.createSMatrix(4, 4, 4, lists);
161 console.log(a);
162 
163 var lists2 = [
164     [1, 4, -5],
165     [2, 3, 1],
166     [1, 1, 3],
167     [3, 2, 2]
168 ];
169 var b = new CrossList();
170 b.createSMatrix(4, 4, 4, lists2);
171 console.log(b);
172 
173 a.addMatrix(b);
174 console.log(a);