链表相对传统数组优点是:添加删除元素不会移动其它元素。链表相对传统数组缺点是:访问链表中间的元素,需要从头迭代,直到找到所需元素。上一篇文章讨论了链表,本章叙述双向链表。双向链表是双向的,一个链向上一个元素,一个链向上一个元素。 双向链表提供两种迭代方式:从头到尾和从尾到头,我们可以访问特定一个节点的上一个元素或者下一个元素。
简单链表和双向链表非常类似,上一章 juejin.cn/post/684490… 已经介绍了基本的操作方法和写法,这次介绍双向链表和简单链表不一样的一些算法。
在任意位置插入新元素
function DoublyLinkedList() {
let Node = function(element) {
this.element = element;
this.next = null;
this.prev = null;
};
let length = 0,
head = null,
tail = null;
// 在任意位置插入新元素
this.insert = function(position) {
if (position >= 0 && position <= length) {
let node = new Node(element),
current = head,
previous = null,
index = 0;
if (0 === position) {
if (!head) {
head = node;
tail = node;
} else {
node.next = current;
current.prev = node;
head = node;
}
} else if (length === position) {
current = tail;
current.next = node;
node.prev = current;
tail = node;
} else {
while (index++ < position) {
previous = current;
current = current.next;
}
previous.next = node;
node.prev = previous;
current.prev = node;
node.next = current;
}
length++;
return true;
} else {
return false;
}
};
}
插入大致分为三种场景:1、 在列表第一个位置插入元素,如果列表为空,head和tail都指向这个新节点。如果列表不为空,current将是对这个列表对一个元素的引用,node.next指向current,current.prev指向node。2、在列表最后插入一个元素,这是一种比较特殊的场景,因为最后还控制着tail指针,current指向最后一个指针的引用,然后建立里一个链接,current.next指向node,然后node.prev指向current,最后更新tail,指向node。3、在列表任意位置插入元素,首先遍历到指定位置,这里就需要在指定位置前后位新元素建立两两链接。这样才不会丢掉节点之间的关系。



从任意位置移除元素
function DoublyLinkedList() {
let Node = function(element) {
this.element = element;
this.next = null;
this.prev = null;
};
let length = 0,
head = null,
tail = null;
// 从任意位置移除元素
this.removeAt = function(position) {
if (position > -1 && position < length) {
let current = head,
previous = null,
index = 0;
if (0 === position) {
head = current.next;
if (1 === length) {
tail = null;
} else {
head.prev = null;
}
} else if (length - 1 === position) {
current = tail;
tail = current.prev;
tail.next = null;
} else {
while (index++ < position) {
previous = current;
current = current.next;
}
previous.next = current.next;
current.next.prev = previous;
}
length--;
return current.element;
} else {
return null;
}
};
}
删除也大致分为三种场景:1、 在列表第一个位置删除元素。2、删除列表最后一个元素,这是一种比较特殊的场景,因为最后还控制着tail指针。3、在列表任意位置删除元素。



双向链表的删除和插入操作最基本的思想一致,在操作元素时保证元素间前后链接不能断开。
下一章:循环链表