双向链表
也叫双链表,是链表的一种,它的每个数据节点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个节点开始,都可以很方便地访问它的前驱节点和后继节点。一般我们都构造双向循环链表
双向链表的特点
- 可以使用一个head和一个tail分别指向头部和尾部的节点
- 每个节点由三部分组成,前一个节点的指针(prev)、保存的元素(data)、后一个节点的指针(next)
- 双向链表的第一个节点的prev是null
- 双向链表的最后的节点的next是null
双向链表的封装
function doublyLinkList() {
function node(data) {
this.data = data;
this.prev = null;
this.next = null;
}
this.head = null;
this.tail = null;
this.length = 0;
}
向末尾添加节点
doublyLinkList.prototype.append = function(data) {
let newNode = new node(data);
// 如果链表是空
if (this.length === 0) {
this.head = newNode;
this.tail = newNode;
} else {
let tail = this.tail; // 旧的最后节点
newNode.prev = tail; // 新节点的前一个节点指向旧的最后节点
tail.next = newNode; // 旧的最后节点指向新的节点
this.tail = newNode; // 新加的最后节点
}
this.length += 1;
};
insert添加节点
向末尾添加节点时,链表为空添加节点和末尾添加节点已图解,不再画图
doublyLinkList.prototype.insert = function(index, data) {
if (index < 0 || index > this.length) return false;
let newNode = new node(data);
if (this.length === 0) {
this.head = newNode;
this.tail = newNode;
} else {
// 添加为第一个节点
if (index === 0) {
this.head.prev = newNode;
newNode.next = this.head;
this.head = newNode;
} else if (index === this.length) {
// 添加为末尾节点
newNode.prev = this.tail;
this.tail.next = newNode;
this.tail = newNode;
} else {
// 中间插入节点
let current = this.head;
let j = 0;
while (j++ < index) {
current = current.next; // 找点index下标的current节点
}
newNode.next = current; // 新增的节点指向current节点
newNode.prev = current.prev; // 新增的节点的前一个节点指向current前一个节点
current.prev.next = newNode; // current前一个节点next指向新增的节点
current.prev = newNode; // current前一个节点指向新增的节点
}
}
this.length += 1;
return true;
};
根据下标找到该节点
doublyLinkList.prototype.findNode = function(index) {
if (index < 0 || index >= this.length) return null;
/**
可以根据index的大小优化查找的顺序
1 this.length / 2 > index 从头向尾遍历
2 this.length / 2 < index 从尾向头遍历
*/
// 从头向尾遍历
let j = 0;
let current = this.head;
while (j++ < index) {
current = current.next;
}
return current.data;
// 从尾向头遍历
// let k = this.length - 1;
// let current = this.tail;
// while (k-- < index) {
// current = current.prev;
// }
// return current.data;
};
根基节点找到下标
doublyLinkList.prototype.indexOf = function(data) {
let index = 0;
let current = this.head;
while (current) {
if (current.data === data) {
return index;
}
current = current.next;
index += 1;
}
return -1;
};
修改某个节点
doublyLinkList.prototype.update = function(index, data) {
if (index < 0 || index >= this.length) return false;
let j = 0;
let current = this.head;
while (j++ < index) {
current = current.next;
}
current.data = data;
return true;
};
根据下标删除某个节点
doublyLinkList.prototype.removeAt = function(index) {
if (index < 0 || index >= this.length) return false;
// 如果链表只有一个节点
if (this.length === 1) {
this.head = null;
this.tail = null;
} else {
// 删除第一个节点
if (index === 0) {
this.head.next.prev = null; // this.head.next 第二个节点 this.head.next.prev 第一个节点
this.head = this.head.next; // head节点指向第二个节点
} else if (index === this.length - 1) {
// 删除末尾节点
this.tail.prev.next = null; // this.tail.prev 倒数第二个节点 this.tail.prev.next 尾部节点
this.tail = this.tail.prev; // tail节点指向倒数第二个节点
} else {
// 删除中间节点
let j = 0;
let current = this.head;
while (j++ < index) {
current = current.next;
}
current.prev.next = current.next; // current的前一个节点指向current的后一个节点
current.next.prev = current.prev; // current的后面的节点指向current的前一个节点
}
}
this.length -= 1;
return true;
};
根据节点删除
doublyLinkList.prototype.remove = function(data) {
let index = this.indexOf(data);
return this.removeAt(index);
};
从头到尾字符串排列
doublyLinkList.prototype.headToTailString = function() {
let current = this.head;
let res = "";
while (current) {
res += current.data + " ";
current = current.next;
}
return res;
};
从尾到头字符串排列
doublyLinkList.prototype.tailToHeadString = function() {
let current = this.tail;
let res = "";
while (current) {
res += current.data + " ";
current = current.prev;
}
return res;
};
let list = new doublyLinkList();
list.append(10);
list.append(200);
list.append(3000);
list.append(40000);
// let res = list.headToTailString();
// console.log(res) // 10 200 3000 40000
// let res1 = list.tailToHeadString();
// console.log(res1) // 40000 3000 200 10
// list.insert(2, "abc");
// let node = list.findNode(2);
// console.log(node, "node"); // abc
// let index = list.indexOf(400020);
// console.log("index", index); // -1
// list.removeAt(1);
// let res3 = list.headToTailString();
// console.log(res3); // 10 3000 40000
list.remove(40000);
let res4 = list.headToTailString();
console.log(res4); // 10 200 3000
console.dir(list, {
depth: 10
});