JavaScript数据结构与算法(七) 双向链表的实现

TypeScript方式实现源码

// 双向链表和普通链表的区别在于, 在链表中,
// 一个节点只有链向下一个节点的链接,而在双向链表中,链接是双向的:一个链向下一个元素,
// 另一个链向前一个元素,如下图所示:
// 
// Node类里有prev属性(一个新指针) ,在DoublyLinkedList类里也有用来保存对列表最后一
// 项的引用的tail属性。 

// 双向链表提供了两种迭代列表的方法:从头到尾,或者反过来。我们也可以访问一个特定节
// 点的下一个或前一个元素。在单向链表中,如果迭代列表时错过了要找的元素,就需要回到列表
// 起点,重新开始迭代。这是双向链表的一个优点。
// 代码角度
//   每个节点设置两个指针,关联相邻的前后节点.提供逆向遍历,链表篇提到,链表是针对大量删除与添加场景下使用的.因此双向链表是针对普通链表的功能为基础,强化了遍历的功能
// 抽象
//   想了很久找不到现实中的场景,还是拿火车来理解吧.早期火车就像普通链表,具有重组车厢的功能.而随着科技的进步,双向列车出来了,优势便是不用再每次脱离车头,开到转盘进行掉头
//   然后再行驶.双向链表便是双向列车,它弱化了车头的概念,前后皆可是车头.
// 总结
//   单向链表优势在于可执行大量删除、增加操作并不用像数组那样需要重新排序.劣势则是每次便利必须从头开始,无端增加许多系统开销.假如有这种场景,知道某个节点,我需要找到
//   该节点的爷爷,再找他爷爷的儿子,再找他儿子的孙子.我们大脑瞬间可以计算出,这不就是要找当前节点的儿子吗?的确!我们就是要程序能够这样做,但是单向链表就是一根筋,不具备
//   这样的智商,这时双向链表优势则非常明显
  1 class Node {
  2     element;
  3     next;
  4     prev; // 新增的
  5     constructor(element) {
  6         this.element = element;
  7         this.next = null;
  8         this.prev = null;
  9     }
 10 }
 11 
 12 /**
 13  * 双向链表
 14  * @name DoublyLinkedList
 15  */
 16 class DoublyLinkedList {
 17     private length = 0;
 18     head = null;
 19     tail = null; // 新增的
 20 
 21     /**
 22      * 向列表尾部添加一个新的项
 23      * @param element 
 24      */
 25     public append(element) {
 26         let node = new Node(element), current;
 27 
 28         if (this.head === null) {
 29             this.head = node;
 30         } else {
 31             current = this.head;
 32 
 33             // 循环列表,知道找到最后一项
 34             while (current.next) {
 35                 current = current.next;
 36             }
 37 
 38             // 找到最后一项,将其next赋为node,建立链接
 39             current.next = node;
 40         }
 41         this.length++; // 更新列表长度    
 42     }
 43     /**
 44      * 向列表的特定位置插入一个新的项
 45      * @param position 
 46      * @param element 
 47      */
 48     public insert(position, element) {
 49         // 检查越界值
 50         if (position >= 0 && position <= this.length) {
 51             let node = new Node(element),
 52                 current = this.head,
 53                 previous,
 54                 index = 0;
 55 
 56             if (position === 0) { // 在第一个位置添加
 57                 if (!this.head) { // 新增的
 58                     this.head = node;
 59                     this.tail = node;
 60                 } else {
 61                     node.next = current;
 62                     current.prev = node; // 新增的
 63                     this.head = node;
 64                 }
 65             } else if (position === this.length) { // 最后一项 新增的
 66                 current = this.tail;
 67                 current.next = node;
 68                 node.prev = current;
 69                 this.tail = node;
 70             } else {
 71                 while (index++ < position) {
 72                     previous = current;
 73                     current = current.next;
 74                 }
 75                 node.next = current;
 76                 previous.next = node;
 77 
 78                 current.prev = node; // 新增的
 79                 node.prev = previous; // 新增的
 80             }
 81             this.length++; // 更新列表长度
 82             return true;
 83         } else {
 84             return false;
 85         }
 86     }
 87     /**
 88      * 从列表的特定位置移除一项
 89      * @param position 
 90      */
 91     public removeAt(position) {
 92         // 检查越界值
 93         if (position > -1 && position < this.length) {
 94             let current = this.head,
 95                 previous,
 96                 index = 0;
 97 
 98             // 移除第一项
 99             if (position === 0) {
100                 this.head = current.next;
101 
102                 // 如果只有一项,更新tail // 新增的
103                 if (this.length === 1) {
104                     this.tail = null;
105                 } else {
106                     this.head.prev = null;
107                 }
108             }
109             else if (position === this.length - 1) { // 新增的
110                 current = this.tail;
111                 this.tail = current.prev;
112                 this.tail.next = null;
113             }
114             else {
115                 while (index++ < position) {
116                     previous = current;
117                     current = current.next;
118                 }
119                 // 将previous与current的下一项链接起来:跳过current,从而移除它
120                 previous.next = current.next;
121                 current.next.prev = previous; // 新增的
122             }
123             this.length--;
124             return current.element;
125         } else {
126             return null;
127         }
128     }
129     /**
130      * 从列表中移除一项
131      * @param element 
132      */
133     public remove(element) {
134         let index = this.indexOf(element);
135         return this.removeAt(index);
136     }
137     /**
138      * :返回元素在列表中的索引。如果列表中没有该元素则返回-1
139      * @param element 
140      */
141     public indexOf(element) {
142         let current = this.head,
143             index = -1;
144 
145         while (current) {
146             if (element === current.element) {
147                 return index;
148             }
149             index++;
150             current = current.next;
151         }
152         return -1;
153     }
154     /**
155      * 如果链表中不包含任何元素, 返回true, 如果链表长度大于0则返回false
156      */
157     public isEmpty() {
158         return this.length === 0;
159     }
160     /**
161      * 返回链表包含的元素个数。与数组的length属性类似
162      */
163     public size() {
164         return this.length;
165     }
166     /**
167      * 由于列表项使用了Node类,就需要重写继承自JavaScript对象默认的toString方法,让其只输出元素的值
168      */
169     public toString() {
170         let current = this.head,
171             string = '';
172 
173         while (current) {
174             string += current.element;
175             current = current.next;
176         }
177         return string;
178     }
179     public getHead() {
180         return this.head;
181     }
182     public print() {
183         console.log(this.toString());
184     }
185 }
View Code
 
JavaScript 方式实现源码
  1 var Node = (function () {
  2     function Node(element) {
  3         this.element = element;
  4         this.next = null;
  5         this.prev = null;
  6     }
  7     return Node;
  8 }());
  9 /**
 10  * 双向链表
 11  * @name DoublyLinkedList
 12  */
 13 var DoublyLinkedList = (function () {
 14     function DoublyLinkedList() {
 15         this.length = 0;
 16         this.head = null;
 17         this.tail = null; // 新增的
 18     }
 19     /**
 20      * 向列表尾部添加一个新的项
 21      * @param element
 22      */
 23     DoublyLinkedList.prototype.append = function (element) {
 24         var node = new Node(element), current;
 25         if (this.head === null) {
 26             this.head = node;
 27         }
 28         else {
 29             current = this.head;
 30             // 循环列表,知道找到最后一项
 31             while (current.next) {
 32                 current = current.next;
 33             }
 34             // 找到最后一项,将其next赋为node,建立链接
 35             current.next = node;
 36         }
 37         this.length++; // 更新列表长度    
 38     };
 39     /**
 40      * 向列表的特定位置插入一个新的项
 41      * @param position
 42      * @param element
 43      */
 44     DoublyLinkedList.prototype.insert = function (position, element) {
 45         // 检查越界值
 46         if (position >= 0 && position <= this.length) {
 47             var node = new Node(element), current = this.head, previous = void 0, index = 0;
 48             if (position === 0) {
 49                 if (!this.head) {
 50                     this.head = node;
 51                     this.tail = node;
 52                 }
 53                 else {
 54                     node.next = current;
 55                     current.prev = node; // 新增的
 56                     this.head = node;
 57                 }
 58             }
 59             else if (position === this.length) {
 60                 current = this.tail;
 61                 current.next = node;
 62                 node.prev = current;
 63                 this.tail = node;
 64             }
 65             else {
 66                 while (index++ < position) {
 67                     previous = current;
 68                     current = current.next;
 69                 }
 70                 node.next = current;
 71                 previous.next = node;
 72                 current.prev = node; // 新增的
 73                 node.prev = previous; // 新增的
 74             }
 75             this.length++; // 更新列表长度
 76             return true;
 77         }
 78         else {
 79             return false;
 80         }
 81     };
 82     /**
 83      * 从列表的特定位置移除一项
 84      * @param position
 85      */
 86     DoublyLinkedList.prototype.removeAt = function (position) {
 87         // 检查越界值
 88         if (position > -1 && position < this.length) {
 89             var current = this.head, previous = void 0, index = 0;
 90             // 移除第一项
 91             if (position === 0) {
 92                 this.head = current.next;
 93                 // 如果只有一项,更新tail // 新增的
 94                 if (this.length === 1) {
 95                     this.tail = null;
 96                 }
 97                 else {
 98                     this.head.prev = null;
 99                 }
100             }
101             else if (position === this.length - 1) {
102                 current = this.tail;
103                 this.tail = current.prev;
104                 this.tail.next = null;
105             }
106             else {
107                 while (index++ < position) {
108                     previous = current;
109                     current = current.next;
110                 }
111                 // 将previous与current的下一项链接起来:跳过current,从而移除它
112                 previous.next = current.next;
113                 current.next.prev = previous; // 新增的
114             }
115             this.length--;
116             return current.element;
117         }
118         else {
119             return null;
120         }
121     };
122     /**
123      * 从列表中移除一项
124      * @param element
125      */
126     DoublyLinkedList.prototype.remove = function (element) {
127         var index = this.indexOf(element);
128         return this.removeAt(index);
129     };
130     /**
131      * :返回元素在列表中的索引。如果列表中没有该元素则返回-1
132      * @param element
133      */
134     DoublyLinkedList.prototype.indexOf = function (element) {
135         var current = this.head, index = -1;
136         while (current) {
137             if (element === current.element) {
138                 return index;
139             }
140             index++;
141             current = current.next;
142         }
143         return -1;
144     };
145     /**
146      * 如果链表中不包含任何元素, 返回true, 如果链表长度大于0则返回false
147      */
148     DoublyLinkedList.prototype.isEmpty = function () {
149         return this.length === 0;
150     };
151     /**
152      * 返回链表包含的元素个数。与数组的length属性类似
153      */
154     DoublyLinkedList.prototype.size = function () {
155         return this.length;
156     };
157     /**
158      * 由于列表项使用了Node类,就需要重写继承自JavaScript对象默认的toString方法,让其只输出元素的值
159      */
160     DoublyLinkedList.prototype.toString = function () {
161         var current = this.head, string = '';
162         while (current) {
163             string += current.element;
164             current = current.next;
165         }
166         return string;
167     };
168     DoublyLinkedList.prototype.getHead = function () {
169         return this.head;
170     };
171     DoublyLinkedList.prototype.print = function () {
172         console.log(this.toString());
173     };
174     return DoublyLinkedList;
175 }());
View Code
原文地址:https://www.cnblogs.com/menu/p/6971946.html