一、概念

单向链表
- 只能从头遍历到尾或者从尾遍历到头(一般从头到尾),也就是链表相连的过程是 单向 的。
- 实现的原理是上一个链表中有一个指向下一个的引用。
单链表的缺点:
我们可以轻松的到达下一个节点,但是回到前一个节点是很难的。
但是,在实际开发中,经常会遇到需要回到上一个节点的情况。
举个例子:
假设一个文本编辑用链表来存储文本。每一行用一个 String 对象存储在链表的一个节点中。
当编辑器用户向下移动光标时,链表直接操作到下一个节点即可。但是当用于将光标向上移动呢?
这个时候为了回到上一个节点,我们可能需要从first开始,依次走到想要的节点上。
双向链表
- 既可以从头遍历到尾,又可以从尾遍历到头。也就是链表的相连过程是双向的,
- 一个节点既有向前连接的引用,也有一个向后连接的引用。
优点:
- 每次在插入或删除某个节点时,需要处理四个引用,而不是两个。实现起来要困难一些。
- 相对于单向链表,占用的内存空间更大一些。
结构模型
head -> { prev, data, next } -> { prev, data, next } -> { prev, data, next(tail) } -> null;
head 指向头部节点;
tail 指向尾部节点;
prev 指向上一个节点;
next 指向下一个节点;
data 当前节点数据
第一个节点的 prev 是 null
最后一个节点的 next 是 null
二、属性和方法
链表的属性:
- head: 头部节点
- node: 节点
- data: 节点数据
- prev:指向下一个节点的
- next:指向下一个节点的
- tail: 尾部节点
- length: 链表长度
链表的方法(6个):
- append(data):向链表尾部添加一个新的项
- insert(position, data):向链表的特定位置 插入一个新的项
- get(position):获取对应位置的元素
- indexOf(data):返回元素在链表中的索引。如果链表中没有该元素,则返回-1
- update(position, data):修改某个位置的元素
- removeAt(position):从链表的特定位置删除一项
- remove(data):从列表中删除一项
- getHead():获取头部节点
- forwardString():返回向前遍历的节点字符串形式
- backwordString():返回向后遍历的节点字符串形式
- getTail():获取尾部节点
- isEmpty():如果链表中不包含任何元素,返回true;否则返回false
- size():返回链表中包含的元素个数
- toString():将链表中的内容,转换成字符串形式
具体实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
| function DoublyLinkedList() {
function Node(data) { this.data = data; this.prev = null; this.next = null; }
this.head = null; this.tail = null; this.length = 0;
DoublyLinkedList.prototype.append = function (data) {
const node = new Node(data);
if (this.length === 0) { this.head = node; this.tail = node;
} else {
node.prev = this.tail; this.tail.next = node; this.tail = node; }
this.length++; }
DoublyLinkedList.prototype.insert = function (position, data) {
if (position < 0 || position > this.length) { return false }
const node = new Node(data);
if (this.length === 0) { this.head = node; this.tail = node; } else {
if (position === 0) { this.head.prev = node; node.next = this.head; this.head = node;
} else if (position === this.length) { this.tail.next = node; node.prev = this.tail; this.tail = node;
} else {
let currentNode = this.head; let index = 0;
while (index++ < position) { currentNode = currentNode.next; }
node.next = currentNode; node.prev = currentNode.prev
currentNode.prev.next = node; currentNode.prev = node;
} }
this.length++; return true; }
DoublyLinkedList.prototype.get = function (position) { if (position < 0 || position >= this.length) { return null; }
let currentNode = this.head; let index = 0;
while(index++ < position) { currentNode = currentNode.next; }
return currentNode.data; }
DoublyLinkedList.prototype.indexOf = function (data) {
let curentNode = this.head; let index = 0;
while(index < this.length) { if (curentNode.data === data) { return index; } curentNode = curentNode.next; index++ }
return -1;
}
DoublyLinkedList.prototype.update = function (position, data) {
if(position < 0 || position >= this.length) { return false; }
let curentNode = this.head; let index = 0;
while(index++ < position) { curentNode = curentNode.next; } curentNode.data = data; return true; }
DoublyLinkedList.prototype.removeAt = function (position) { if(position < 0 || position >= this.length) { return null; }
let curentNode = this.head; if (this.length === 1) { this.head = null this.tail = null; } else {
if (position === 0) {
this.head.next.prev = null; this.head = this.head.next;
} else if (position === this.length - 1) {
curentNode = this.tail; this.tail.prev.next = null; this.tail = this.tail.prev;
} else {
let index = 0;
while(index++ < position) { curentNode = curentNode.next; }
curentNode.prev.next = curentNode.next; curentNode.next.prev = curentNode.prev; } }
this.length--;
return curentNode.data; }
DoublyLinkedList.prototype.remove = function (data) { const postion = this.indexOf(data);
return this.removeAt(postion); }
DoublyLinkedList.prototype.getHead = function () { return this.head.data; }
DoublyLinkedList.prototype.getTail = function () { return this.tail.data; }
DoublyLinkedList.prototype.isEmpty = function () { return this.length === 0; }
DoublyLinkedList.prototype.size = function () { return this.length }
DoublyLinkedList.prototype.toString = function () { return this.backwordString(); }
DoublyLinkedList.prototype.forwardString = function () { let current = this.tail; let listString = '';
while (current) { listString += current.data + ' '; current = current.prev; }
return listString; }
DoublyLinkedList.prototype.backwordString = function () { let current = this.head; let listString = '';
while (current) { listString += current.data + ' '; current = current.next; }
return listString; } }
|