双向链表
- 既可以从头遍历到尾, 又可以从尾遍历到头
- 也就是链表相连的过程是双向的. 那么它的实现原理, 你能猜到吗?
- 一个节点既有向前连接的引用, 也有一个向后连接的引用
双向链表缺点
- 每次在插入或删除某个节点时, 需要处理四个节点的引用, 而不是两个. 也就是实现起来要困难一些
- 并且相当于单向链表, 必然占用内存空间更大一些.
- 但是这些缺点和我们使用起来的方便程度相比, 是微不足道的
- 双向链表代码实现
class Lnode {
constructor(data) {
this.head = null
this.tail = null
this.data = data
}
}
class DoubleLinkList {
constructor() {
this.head = null
this.tail = null
this.length = 0
}
// 尾部添加节点
append(el) {
let newnode = new Lnode(el)
if (this.length == 0) {
this.head = newnode
this.tail = newnode
} else {
newnode.prev = this.tail
this.tail.next = newnode
this.tail = newnode;
}
this.length++
}
// 向指定位置插入元素
insert(position, el) {
// 判断位置是否合法
if (position < 0 || position > this.length || !Number.isInteger(position)) {
return false
}
let newnode = new Lnode(el)
if (position == 0) {
// 头部添加
if (this.length == 0) {
this.head = newnode
this.tail = newnode
} else {
newnode.next = this.head
this.head.prev = newnode
this.head = newnode;
}
this.length++;
} else if (position == this.length) {
// 尾部添加
this.append()
this.length++;
} else {
// 任意位置插入
let current = this.head;
var index = 0;
while (index < position - 1) {
current = current.next;
index++;
}
// 将新节点链接上去
newnode.prev = current
newnode.next = current.next;
current.next = newnode;
newnode.next.prev = newnode
this.length++
}
}
indexOf(el) {
let current = this.head,
index = 0;
while (index < this.length) {
if (current.data == el) {
return index
} else {
current = current.next;
index++;
}
}
return -1
}
remove(el) {
let index = this.indexOf(el)
this.removeAt(index)
}
// 正向遍历
toAfterString() {
let current = this.head,
index = 0,
res = "";
while (index < this.length) {
res += "-" + current.data;
current = current.next;
index++;
}
return res.slice(1)
}
// 反向遍历
toBeforeString() {
let current = this.tail,
index = this.length - 1,
res = "";
while (index >= 0) {
res += "-" + current.data;
current = current.prev;
index--;
}
return res.slice(1)
}
}