前言
链表中的数据通过指针连接,添加、插入或删除节点只需要修改指针指向
实现思路
实现一个链表需要具备以下方法
- 在链表尾部添加节点
- 获取链表所有节点的数据
- 链表指定位置插入元素
- 获取链表指定位置的节点数据
- 获取节点在链表中的位置
- 更新链表指定位置的数据
- 移除链表指定位置的节点
- 移除链表中的指定节点
- 判断链表是否为空
- 获取链表长度
链表内部需要定义head指针和链表长度
实现代码
- 定义head指针和length存储链表长度
- 定义节点类
function LinkedList() {
this.head = null
this.length = 0
function Node(data) {
this.data = data
this.next = null
}
}
- 在链表尾部添加节点
append(data) {
//创建新节点
let node = new Node(data)
//是否是第一个节点
if(this.length === 0) {
//head指向新节点
this.head = node
} else {
//获取第一个节点
let current = this.head
//获取链表最后一个节点
while(current.next) {
current = current.next
}
//最后一个节点指向新节点
current.next = node
}
//链表长度加一
this.length += 1
}
- 获取链表所有节点的数据
toString() {
//声明空字符串存储链表节点数据
let listString = ''
//获取第一个节点
let current = this.head
//遍历所有节点
while(current) {
listString += current.data + ' '
current = current.next
}
return listString
}
- 链表指定位置插入元素
insert(position, data) {
//判断位置是否有效
if(position < 0 || position > this.length) return false
//创建新节点
let node = new Node(data)
//是否插入到第一
if(position === 0) {
node.next = this.head
this.head = node
} else {
//定义索引
let index = 0
//当前节点
let current = this.head
//上一个节点
let previous = null
//获取指定位置和上一个节点
while(index++ < position) {
previous = current
current = current.next
}
//上一个节点的指针指向新节点
previous.next = node
//新节点的指针指向当前节点
node.next = current
}
//链表长度加一
this.length += 1
return true
}
- 获取链表指定位置的节点数据
get(position) {
//判断位置是否有效
if(position < 0 || position >= this.length) return null
let index = 0
//获取第一个节点
let current = this.head
//获取指定位置的节点
while(index++ < position) {
current = current.next
}
//返回指定位置的节点数据
return current.data
}
- 获取节点在链表中的位置
indexOf(data) {
//获取第一个节点
let current = this.head
let index = 0
while(current) {
//判断当前节点数据是否和传入数据相等
if(current.data === data) {
//返回位置
return index
}
//获取下一个节点
current = current.next
index += 1
}
//没有找到节点
return -1
}
- 更新链表指定位置的数据
update(position, data) {
//判断位置是否有效
if(position < 0 || position >= this.length) return false
let index = 0
let current = this.head
//获取指定位置节点
while(index++ < position) {
current = current.next
}
current.data = data
}
- 移除链表指定位置的节点
removeAt(position) {
//判断位置是否有效
if(position < 0 || position >= this.length) return false
let current = this.head
//是否移除第一个节点
if(position === 0) {
this.head = this.head.next
} else {
let index = 0
let previous = null
while(index++ < position) {
previous = current
current = current.next
}
//指定位置上一节点指向指定位置的下一节点
previous.next = current.next
}
//长度减一
this.length -= 1
//返回移除节点
return current
}
- 移除链表中的指定节点
- 判断链表是否为空
- 获取链表长度
remove(data) {
this.removeAt(this.indexOf(data))
}
isEmpty() {
return this.length === 0
}
size() {
return this.length
}
测试代码
//实例化链表
let linkedList = new LinkedList()
//链表尾部添加节点
linkedList.append('swt')
linkedList.append('mff')
linkedList.append('pty')
//获取链表节点数据
console.log(linkedList.toString())
//指定位置插入
linkedList.insert(1, 'cyw')
console.log(linkedList.toString())
//获取指定位置节点数据
console.log(linkedList.get(1))
//获取节点数据在链表中的位置
console.log(linkedList.indexOf('lbw'))
console.log(linkedList.indexOf('mff'))
//更新指定位置的数据
linkedList.update(0, 'wo')
//移除指定位置的节点
linkedList.removeAt(0)
console.log(linkedList.toString())
//移除指定数据的节点
linkedList.remove('mff')
console.log(linkedList.toString())
//判断链表是否为空
console.log(linkedList.isEmpty())
//获取链表长度
console.log(linkedList.size())
双向链表
双向链表的指针是双向的,前指针指向上一个节点,后指针指向下一个节点
head指向第一个节点,tail指向最后一个节点
双向链表实现思路
需要具备以下方法
- 尾部插入元素
- 任意位置插入元素
- 获取所有节点数据
- 正向遍历链表获取节点数据
- 反向遍历链表获取节点数据
- 获取指定位置的节点数据
- 获取指定数据在链表中的位置
- 更新指定位置的节点数据
- 移除指定位置的节点
- 移除指定数据的节点
- 判断链表是否为空
- 获取链表长度
定义head和tail分别指向第一个节点和最后一个节点
代码实现
/**
* 双向链表
*/
function DoublyLinkedList() {
//指向第一个节点
this.head = null
//指向最后一个节点
this.tail = null
//链表长度
this.length = 0
//创建节点类
function Node(data) {
this.data = data
this.prev = null
this.next = null
}
}
- 尾部插入元素
append(data) {
//创建新节点
let node = new Node(data)
//判断链表是否为空
if(this.length === 0) { //链表为空
this.head = node
this.tail = node
} esle { //链表不为空
//新节点的前指针指向最后一个节点
node.prev = this.tail
//最后一个节点的后指针指向新节点
this.tail.next = node
//尾指针指向新节点
this.tail = node
}
//链表长度加一
this.length += 1
}
- 向前遍历链表获取节点数据
forwardString() {
//用于存储节点数据
let string = ''
//获取最后一个节点
let current = this.tail
//只要当前节点存在就将节点存储到字符串中并让当前节点等于上一个节点
while(current) {
string += current.data + ' '
current = current.prev
}
return string
}
- 向后遍历链表获取节点数据
backwardString() {
//用于存储节点数据
let string = ''
//获取第一个节点
let current = this.head
//只要当前节点存在就将节点数据存储到字符串中并让当前节点等于下一节点
while(current) {
string += current.data
current = current.next
}
return string
}
- 获取所有节点数据
toString() {
return this.backwardString()
}
- 任意位置插入元素
insert(position, data) {
//判断插入位置是否有效
if(position < 0 || position > this.length) return false
//创建新节点
let node = new Node(data)
//判断链表是否为空
if(this.length === 0) { //链表为空
this.head = node
thi.tail = node
} else { //链表不为空 判断插入位置
if(position === 0) { //插入到第一个节点位置
//新节点的后指针指向第一个节点
node.next = this.head
//第一个节点的前指针指向新节点
this.head.prev = node
//head指向新节点
this.head = node
} else if(position === this.length) { //插入到最后一个节点
//最后一个节点的后指针指向新节点
this.tail.next = node
//新节点的前指针指向最后一个节点
node.prev = this.tail
//tail指向新节点
this.tail = node
} else { //插入到中间位置
let index = 0
let current = this.head
//获取插入位置的节点
while(index++ < position) {
current = current.next
}
//新节点后指针指向当前节点
node.next = current
//新节点前指针指向上一个节点
node.prev = current.prev
//上一节点后指针指向新节点
current.prev.next = node
//当前节点前指针指向新节点
current.prev = node
}
}
this.length += 1
return true
}
- 获取指定位置的节点数据
get(position) {
//判断位置是否有效
if(position < 0 || position >= this.length ) return false
//判断是向后遍历查找还是向前遍历查找
if(this.length / 2 >= position) { //向后遍历
let index = 0
let current = this.head
while(index++ < position) {
current = current.next
}
return current.data
} else { //向前遍历
let index = this.length - 1
let current = this.tail
while(index-- > position) {
current = current.prev
}
return current.data
}
}
- 获取指定数据在链表中的位置
indexOf(data) {
let index = 0
let current = this.head
while(current) {
if(current.data === data) {
return index
}
current = current.next
index += 1
}
//没有找到
return -1
}
- 更新指定位置的节点数据
update(position, data) {
//判断位置是否有效
if(position < 0 || position >= this.length) return false
//判断向后遍历还是向前遍历
if( this.length / 2 > position) { // 向后遍历
let index = 0
let current = this.head
//获取指定位置节点
while(index++ < position) {
current = current.next
}
current.data = data
return true
} else { //向前遍历
let index = this.length - 1
let current = this.tail
//获取指定位置节点
while(index-- > position) {
current = current.prev
}
current.data = data
return true
}
}
- 移除指定位置的节点
removeAt(position) {
//判断位置是否有效
if(position < 0 || position >= this.length) return false
let current = this.head
//判断链表长度
if(this.length === 1) { //链表长度为1
this.head = null
this.tail = null
} else {
if(position === 0) { //移除第一个节点
//第二个节点的前指针指向null
this.head.next.prev = null
//head指向第二个节点
this.head = this.head.next
} else if(position === this.length - 1) { //移除最后一个节点
//当前节点为最后一个节点
current = this.tail
//倒数第二个节点的后指针指向nul
this.tail.prev.next = null
//tail指向倒数第二个节点
this.tail = this.tail.prev
} else { //移除中间节点
if(this.length / 2 >= position) { //向后遍历
let index = 0
//获取指定位置的节点
while(index++ < position) {
current = current.next
}
//指定位置节点的下一个节点前指针指向指定位置的上一个节点
current.next.prev = current.prev
//指定位置节点的上一个节点后指针指向指定位置的
current.prev.next = current.next
} else { //向前遍历
let index = this.length - 1
current = this.tail
//获取指定位置的节点
while(index-- > position) {
current = current.prev
}
//指定位置节点的下一个节点前指针指向指定位置的上一个节点
current.next.prev = current.prev
//指定位置节点的上一个节点后指针指向指定位置的
current.prev.next = current.next
}
}
}
this.length -= 1
return current.data
}
- 移除指定数据的节点
remove(data) {
return this.removeAt(this.indexOf(data))
}
- 判断链表是否为空
- 获取链表长度
isEmpty() {
return this.length === 0
}
sieze() {
return this.length
}
代码测试
let doublyLinkedList = new DoublyLinkedList()
doublyLinkedList .append('swt')
doublyLinkedList .append('mff')
console.log(doublyLinkedList .forwardString())
console.log(doublyLinkedList .backwardString())
doublyLinkedList .insert(0,'cyw')
console.log(doublyLinkedList .toString())
console.log(doublyLinkedList .get(0))
console.log(doublyLinkedList .get(2))
console.log(doublyLinkedList .indexOf('mff'))
console.log(doublyLinkedList .update(2, '巢怡雯'))
console.log(doublyLinkedList .toString())
console.log(doublyLinkedList .removeAt(2))
console.log(doublyLinkedList .remove('swt'))
console.log(doublyLinkedList .isEmpty())
console.log(doublyLinkedList .size())