javascript实现数据结构与算法系列:功能完整的线性链表

由于链表在空间的合理利用上和插入,删除时不需要移动等的有点,因此在很多场合下,它是线性表的首选存储结构。然而,它也存在着实现某些基本操作,如求线性表长度时不如顺序存储结构的缺点;另一方面,由于在链表中,结点之间的关系使用指针来表示,则数据元素在线性表中的“位序”的概念已淡化,而被数据元素在线性链表中的“位置”所代替。为此,从实际出发重新定义线性链表及其基本操作

 

结构图:

 

  1 (function(module){
  2   function List() {
  3     this.head = null;
  4     this.tail = null;
  5   }
  6   module.exports = List;
  7 
  8   List.mergeList = function (a, b, compare) {
  9     var ha = a.head;
 10     var hb = b.head;
 11     var pa = ha;
 12     var pb = hb;
 13     var c = new List();
 14     var q;
 15     compare = compare || function (data1, data2) {
 16       return data1 <= data2;
 17     };
 18 
 19     while (pa && pb) {
 20       var data1 = pa.data;
 21       var data2 = pb.data;
 22 
 23       if (!compare(data1, data2)) {
 24         // delete head node
 25         q = a.delFirst();
 26         // append the node to c linkedList
 27         c.append(q);
 28         pa = a.head;
 29       } else {
 30         q = b.delFirst();
 31         c.append(q);
 32         pb = b.head;
 33       }
 34     }
 35 
 36     if (pa) {
 37       c.append(pa);
 38     } else {
 39       c.append(pb);
 40     }
 41 
 42     return c;
 43   };
 44 
 45   List.prototype = {
 46     makeNode: function(data, next){
 47       return {
 48         data: data != null ?  data : null,
 49         next: next || null
 50       };
 51     },
 52     delFirst: function () {
 53       var head = this.head;
 54       this.head = this.head.next;
 55       head.next = null;
 56 
 57       if(this.head === null) this.tail = null;
 58       return head;
 59     },
 60     append: function (node) {
 61       if (this.head !== null) {
 62         this.tail.next = node;
 63         this.tail = this.tail.next;
 64       } else {
 65         this.head = node;
 66         this.tail = node;
 67       }
 68     },
 69     add: function (data) {
 70       if (this.head === null) {
 71         this.head = this.makeNode(data);
 72         this.tail = this.head;
 73       } else {
 74         this.tail.next = this.makeNode(data);
 75         this.tail = this.tail.next;
 76       }
 77 
 78       this.tail.data = data;
 79     },
 80     'delete': function (data) {
 81       var current = this.head;
 82       var previous = this.head;
 83       var elem;
 84 
 85       while (current !== null) {
 86         if (data === current.data) {
 87           if (current === this.head) {
 88             this.head = current.next;
 89             elem =  current.data;
 90             break;
 91           }
 92 
 93           if (current === this.tail) this.tail = previous;
 94 
 95           previous.next = current.next;
 96           elem =  current.data;
 97           break;
 98         }
 99 
100         previous = current;
101         current = current.next;
102       }
103 
104       if(this.head === null) this.tail = null;
105 
106       return elem ? elem : false;
107     },
108     insertAsFirst: function (data) {
109       var temp = this.makeNode(data);
110       temp.next = this.head;
111       this.head = temp;
112     },
113     insertAfter: function (target, data) {
114       var current = this.head;
115       while (current !== null) {
116         if (current.data === target) {
117           var temp = this.makeNode(data);
118           temp.next = current.next;
119 
120           if (current === this.tail) this.tail = temp;
121 
122           current.next = temp;
123           return;
124         }
125 
126         current = current.next;
127       }
128     },
129     item: function (index) {
130       var current = this.head;
131 
132       while (current !== null) {
133         if (--index === 0) return current;
134 
135         current = current.next;
136       }
137 
138       return null;
139     },
140     each: function (callback) {
141       var current = this.head;
142 
143       while (current !== null) {
144         callback(current);
145         current = current.next;
146       }
147     },
148     orderInsert: function(data, cmp){
149       cmp = typeof cmp === 'function' ? cmp : function (a, b){
150         if(a > b)
151           return 1;
152         else if(a === b)
153           return 0;
154         else
155           return -1;
156       };
157       var previous = this.head;
158       var current = this.head;
159 
160       if(current === null){
161         this.head = this.tail = this.makeNode(data);
162         return;
163       }
164 
165       var me = this;
166       while(current){
167         var ret = cmp(data, current.data);
168         // 如果插入元素大于当前元素,准备下次遍历
169         if(ret > 0){
170           previous = current;
171           current = current.next;
172 
173           // 如果等于,直接插入到后面
174         } else if(ret === 0){
175           return insertBetween(data, previous, current);
176 
177           // 如果小于则插入到前节点和当前节点中
178           // 因为已经是排序了,所以不需要多余判断了
179         } else {
180           if(this.head === previous && previous === current){
181             return this.insertAsFirst(data);
182           } else {
183             return insertBetween(data, previous, current);
184           }
185         }
186       }
187 
188       // 插入到最后一个结点
189       previous.next = this.makeNode(data);
190       this.tail = previous.next;
191 
192       function insertBetween(data, a, b){
193         var temp = me.makeNode(data);
194         temp.next = b;
195         a.next = temp;
196         return true;
197       }
198     }
199   };
200   /*
201   var list = new List();
202   list.add('b');
203   list.insertAsFirst('a');
204   list.insertAfter('b', 'c');
205   console.log(list.item(2));
206   console.log(JSON.stringify(list));
207   list.each(function (node) {
208     if (node.data === 'b') {
209       console.log('get b in each');
210     }
211   });
212   list['delete']('c');
213   list['delete']('a');
214   console.log(list);
215 
216   var list2 = new List();
217   list2.add('c');
218   list2.insertAsFirst('d');
219   list2.insertAfter('d', 'b');
220   console.log(JSON.stringify(list2));
221 
222   var list3 = List.mergeList(list, list2);
223   console.log(list3);
224   */
225   /*
226   var list = new List();
227 
228   list.orderInsert('e');
229   list.orderInsert('b');
230   list.orderInsert('c');
231   list.orderInsert('a');
232   list.orderInsert('d');
233   list.orderInsert('f');
234   */
235 }(this.module || this));

 

以下是对应的单元测试代码:

 1 describe('linkedList tests', function(){
 2 
 3   var list = new List();
 4 
 5   it('should find the second item', function(){
 6     list.add('b');
 7     expect(list.head.data).toBe('b');
 8     expect(list.tail.next).toBe(null);
 9 
10     list.insertAsFirst('a');
11     expect(list.head.data).toBe('a');
12     expect(list.head.next.data).toBe('b');
13 
14     list.insertAfter('b', 'c');
15     expect(list.item(2).data).toBe('b');
16     expect(list.tail.data).toBe('c');
17   });
18 
19   it('should remove one item', function(){
20     expect(list['delete']('c')).toBe(true);
21     list['delete']('a');
22     expect(list.head.data).toBe('b');
23   });
24 
25   var list2 = new List();
26 
27   it('should match the json', function(){
28     list2.add('c');
29     list2.insertAsFirst('d');
30     list2.insertAfter('d', 'b');
31     expect(JSON.stringify(list2)).toBe('{"head":{"data":"d","next":{"data":"b","next":{"data":"c","next":null}}},"tail":{"data":"c","next":null}}');
32   });
33 
34   it('should merge the lists', function(){
35     var list3 = List.mergeList(list, list2);
36     expect(list3.head.data).toBe('d');
37     expect(list3.head.next.data).toBe('b');
38     expect(list3.head.next.next.data).toBe('c');
39     expect(list3.tail.data).toBe('b');
40   });
41 });

 

posted @ 2014-04-16 11:19  LukeLin  阅读(307)  评论(0编辑  收藏  举报