JS
实现单向链表
一、前言
单向链表(单链表)是链表的一种,其特点是链表的链接方向是单向的,对链表的访问要通过顺序读取从头部开始。链表是使用指针进行构造的列表,又称为节点列表,因为链表是由一个个节点组装起来的,其中每个节点都有指针成员变量指向列表中的下一个节点,head指针指向第一个成为表头节点,而终止于最后一个指向null
的指针,如下图所示:
一个单向链表至少具备以下基础功能:
-
append 往链表尾部添加节点
-
insert 指定位置插入节点
-
remove 根据内容移除某个节点
-
removeAt 根据索引移除某个节点
-
indexOf 返回某个节点的索引
-
isEmpty 链表是否为空
-
size 返回链表长度
下面开始使用
js
实现一个简单的单项链表
二、单向链表的实现
const LinkedList = (function() {
// 节点类
class Node {
constructor(element) {
// 保存当前节点的值
this.element = element
// 指向下一个节点的指针,初始为null
this.next = null
}
}
// 链表长度
let length = new WeakMap()
// 头节点
let head = new WeakMap()
return class {
constructor() {
// 初始长度为0
length.set(this, 0)
// 初始头节点为null
head.set(this, null)
}
// 往链表尾部添加节点
append(element) {
// 创建新节点
const node = new Node(element)
let current = null
// 头节点为null,说明链表此时为第一次添加节点
if (this.getHead() === null) {
head.set(this, node)
} else {
// 缓存头节点
current = this.getHead()
// 通过while循环找到尾节点,然后在尾节点添加新节点
while(current.next) {
current = current.next
}
// 将新节点添加到尾节点后面
current.next = node
}
// 链表长度加1
this._sizeAdd()
}
// 指定位置插入节点
insert(element, position) {
// position需在0-length之间
if (position >= 0 && position <= this.size()) {
// 创建新节点
const node = new Node(element)
let current = this.getHead(), // 缓存旧头节点
index = 0, // 查询下标
previous = null // 插入位置的前一个节点
// position等于0代表要插入到最前面
if (position === 0) {
// 新节点的指针指向旧头节点
node.next = current
// 将插入节点作为新的头节点
head.set(this, node)
} else {
while(index++ < position) {
previous = current
current = current.next
}
// 把节点插入到指定位置
node.next = current
previous.next = node
}
// 链表长度加一
this._sizeAdd()
return true
} else {
return false
}
}
// 根据索引移除节点
removeAt(position) {
if (position >= 0 && position < this.size()) {
let current = this.getHead(),
previous = null,
index = 0
// position为0代表删除头节点
if (position === 0) {
// 设置新头节点为旧头节点的下一个节点
head.set(this, current.next)
} else {
while(index++ < position) {
previous = current
current = current.next
}
// 将索引对应节点的上一个节点指针指向索引对应节点的下一个节点,即可完成节点的删除
previous.next = current.next
}
// 链表长度减1
this._sizeSub()
// 返回被删除节点
return current.element
} else {
return false
}
}
// 根据节点对应的值来删除节点
remove(element) {
// 找到对应下标
const index = this.indexOf(element)
return this.removeAt(index)
}
// 返回节点下标
indexOf(element) {
let current = this.getHead(),
index = 0
while(current) {
// 找到当前元素后,返回对应下标
if (element === current.element) {
return index
}
index++
current = current.next
}
return -1
}
// 链表是否为空
isEmpty() {
return this.getHead() === null
}
// 获取头节点
getHead() {
return head.get(this)
}
// 获取链表长度
size() {
return length.get(this)
}
// 链表长度加1
_sizeAdd() {
let len = this.size()
len++
length.set(this, len)
}
_sizeSub() {
let len = this.size()
len--
length.set(this, len)
}
}
})()
const link = new LinkedList()
console.log(link.isEmpty()) // true
link.append(0)
link.append(1)
link.append(2)
link.append(3)
console.log(link.indexOf(3)) // 3
link.insert(1.5, 2)
console.log(link.size()) // 5
console.log(link.removeAt(2)) // 1.5
console.log(link.indexOf(1.5)) // -1
console.log(link.remove(3)) // 3
console.log(link.size()) // 3
console.log(link.isEmpty()) // false