一、双向链表
(1)概念:
单向链表
-
只能从头遍历到尾或者从尾遍历到头(一般从头到尾) 即链表相连的过程是单向的
-
单向链表有一个比较明显的缺点:
双向链表
(2)双向链表的优缺点
优点:
缺点:
-
每次在插入或删除某个节点时, 需要处理四个节点的引用, 而不是两个. 也就是实现起来要困难一些
-
并且相当于单向链表, 必然占用内存空间更大一些
(3)双向列表的结构:
二、程序封装双向链表
1.创建链表类
//节点的结构
class Dnode {
constructor(data) {
this.prev = null;
this.data = data;
this.next = null;
}
}
//链表的结构
class DoubleLinkList {
constructor() {
this.head = null;
this.tail = null;
this.length = 0
}
}
2.双向链表的操作
方法:
1)在尾部添加节点
append(ele) {
let newnode = new Dnode(ele);
// console.log(newnode);
if (this.length == 0) { //空链表
this.head = newnode;
this.tail = newnode;
} else {
newnode.prev = this.tail; //新节点.prev = 尾节点
this.tail.next = newnode; //尾节点.next指向新节点
this.tail = newnode; //将尾节点指向新节点
}
this.length++;
}
2)向指定位置插入元素
insert(position, ele) {
// 位置是否合法
if (position < 0 || position > this.length || !Number.isInteger(position)) {
return false
}
let newnode = new Dnode(ele);
if (position == 0) {
if (this.length == 0) { //空链表
this.head = newnode;
this.tail = newnode;
} else {
newnode.next = this.head; //新节点.next指向头节点
this.head.prev = newnode; //头节点.prev指向新节点
this.head = newnode; //头节点指向新节点
}
this.length++
} else if (position == this.length) {
this.append(ele)
} else {
let current = this.head,
index = 0;
while (index < position - 1) {
current = current.next;
index++;
}
// 1.将新节点练上去
newnode.prev = current;
newnode.next = current.next;
// 2.
current.next = newnode;
newnode.next.prev = newnode;
this.length++;
}
}
3)移除指定位置的节点
removeAt(position) {
//判断位置的合法性(越界判断)
if (position < 0 || position > this.length - 1 || !Number.isInteger(position)) {
return false
}
if (this.length == 0) {
//空链表
return
} else {
if (position == 0) {
//移除头节点
if (this.length == 1) {
this.head = null
this.tail = null
} else {
this.head = this.head.next
this.head.prev = null
}
} else if (position == this.length - 1) {
//移除尾结点
this.tail = this.tail.prev
this.tail.next = null
} else {
//移除中间任意位置的节点
let current = this.head,
index = 0
while (index < position - 1) {
current = current.next
index++
}
current.next = current.next.next
current.next.prev = current
}
this.length--
}
}
4)查找指定元素的位置
indexOf(ele) {
let current = this.head,
index = 0
while (index < this.length) {
if (current.data == ele) {
return index
} else {
current = current.next
index++
}
}
return -1
}
5)移除指定元素
remove(ele) {
let index = this.indexOf(ele)
this.removeAt(index)
}
6)正向遍历
forwardString() {
let current = this.head,
index = 0,
str = "";
while (index < this.length) {
str += "-" + current.data
current = current.next
index++
}
return str.slice(1)
}
7)反向遍历
reverseString() {
let current = this.tail,
index = this.length - 1,
str = "";
while (index >= 0) {
str += "-" + current.data
current = current.prev
index--
}
return str.slice(1)
}
8)判断是否为空
isEmpty () {
return this.length == 0
}
9)获取链表长度
size () {
return this.length
}