链表
数组<队列>是比较简单的线性存储,数组的大小初始化是固定,从起点和中间插入元素成本很高,因为需要不断的移动元素。 链表存储有序的数据集合,不同于数组的是,链表存储的数据在内存中并不要求是连续的,链表中每个节点存储了当前节点值,以及指向下一个节点的指针
链表可细分为
- 链表结构实现
- 添加、删除元素
- 插入元素
- 获取链表长度、输出链表文本
- 双向链表
- 循环链表
- 排序链表
- 通过链表实现栈
链表结构实现
实现一个链表类,包含删除、添加元素、链表长度等
class Node {
constructor(value) {
this.value = value
this.next = null
}
}
class LinkedList {
count = 0
head = null
push(element) {
const node = new Node(element)
if (this.isEmpty()) {
this.head = node
} else {
let current = this.head
while (current.next) {
current = current.next
}
current.next = node
}
this.count++
}
insert(element, index = 0) {
if (index < 0 || index > this.count) {
return false
}
let prious
let current = this.head
const node = new Node(element)
if (index === 0) {
if (!this.head) {
this.head = node
} else {
node.next = current
this.head = node
}
} else {
for (let i = 0; i < index; i++) {
prious = current
current = current.next
}
prious.next = node
node.next = current
}
this.count++
return true
}
removeElement(element) {
const index = this.getIndexBy(element)
return index > -1 ? this.removeElementBy(index) : false
}
removeElementBy(index) {
if (!this.head || index < 0 || index >= this.count) {
return false
}
if (index === 0) {
this.head = this.head.next
} else {
let previous
let current = this.head
for (let i = 0; i < index; i++) {
previous = current
current = current.next
}
previous.next = current.next
}
this.count--
return true
}
getIndexBy(element) {
if (!this.head || !element) {
return undefined
}
let current = this.head
for (let i = 0; current; i++) {
if (current.value === element) {
return i
}
current = current.next
}
// for 循环找到的直接退出函数体
return -1
}
getElementBy(index) {
if (!this.head || index < 0 || index >= this.count) {
return undefined
}
let current = this.head
// 控制次数
for (let i = 0; i < index; i++) {
current = current.next
}
return current
}
size() {
return this.count
}
isEmpty() {
return this.count === 0
}
print() {
if (!this.count === 0) {
console.log('')
return
}
let str = ''
let current = this.head
while (current) {
str = `${str}=>${current.value}`
current = current.next
}
}
}
双向链表
相比较单链表,当前元素只能指向下一个元素,双向链接区别在于,不仅可以指向下一个元素,还可以指向上一个元素
class Node {
constructor(value) {
this.value = value
this.next = null
this.prev = null
}
}
class DoubleLinkedList {
count = 0
head = null
tail = null // 记录尾指针,向后插入不用一次次遍历了
push(element) {
const node = new Node(element)
if (this.isEmpty()) {
this.head = node
this.tail = node
} else {
let current = this.tail;
current.next = node;
node.prev = current;
this.tail = node;
}
this.count++
}
insert(element, index = 0) {
if (index < 0 || index > this.count) {
return false
}
let current = this.head
const node = new Node(element)
if (index === 0) {
if (!this.head) {
this.head = node
this.tail = node
} else {
current.prev = node
node.next = current
this.head = node
}
} else if (index === this.count) {
this.tail.next = node
node.prev = this.tail
this.tail = node
} else {
const previous = this.getElementBy(index - 1)
node.prev = previous
node.next = previous.next
previous.next.prev = node
previous.next = node
}
this.count++
return true
}
removeElement(element) {
const index = this.getIndexBy(element)
return index > -1 ? this.removeElementBy(index) : false
}
removeElementBy(index) {
if (!this.head || index < 0 || index >= this.count) {
return false
}
let current = this.head
if (index === 0) {
this.head = current.next
if (this.count === 1) {
this.tail = null
} else {
this.head.prev = null
}
} else if (index === this.count - 1) {
current = this.tail.prev
this.tail = current
this.tail.next = null
} else {
const previous = this.getElementBy(index)
previous.prev.next = previous.next
previous.next.prev = previous.prev
}
this.count--
return true
}
getIndexBy(element) {
if (!this.head || !element) {
return undefined
}
let current = this.head
for (let i = 0; current; i++) {
if (current.value === element) {
return i
}
current = current.next
}
// for 循环找到的直接退出函数体
return -1
}
getElementBy(index) {
if (!this.head || index < 0 || index >= this.count) {
return undefined
}
let current = this.head
// 控制次数
for (let i = 0; i < index; i++) {
current = current.next
}
return current
}
size() {
return this.count
}
isEmpty() {
return this.count === 0
}
print() {
if (!this.count === 0) {
console.log('')
return
}
let str = ''
let current = this.head
while (current) {
str = `${str}=>(current: ${current.value}, prev: ${current.prev && current.prev.value}, next:${
current.next && current.next.value
})\n`
current = current.next
}
console.log(str)
return str
}
}
循环链表
循环链表和普通链表最大的区别是,循环链表最后的tail指针,指向了header
class CycleLinkedList {
count = 0
head = null
push(element) {
const node = new Node(element)
if (this.isEmpty()) {
this.head = node
node.next = this.head
} else {
const last = this.getElementBy(this.count - 1)
last.next = node
node.next = this.head
}
this.count++
}
insert(element, index = 0) {
if (index < 0 || index > this.count) {
return false
}
let current = this.head
const node = new Node(element)
if (index === 0) {
if (!this.head) {
this.head = node
node.next = this.head
} else {
const last = this.getElementBy(this.count - 1)
last.next = node
node.next = this.head
this.head = node
}
} else if (index === this.count) {
const last = this.getElementBy(this.count - 1)
last.next = node
node.next = current
} else {
const previous = this.getElementBy(index - 1)
node.next = previous.next
previous.next = node
}
this.count++
return true
}
removeElement(element) {
const index = this.getIndexBy(element)
return index > -1 ? this.removeElementBy(index) : false
}
removeElementBy(index) {
if (!this.head || index < 0 || index >= this.count) {
return false
}
let current = this.head
if (index === 0) {
if (this.count !== 1) {
const last = this.getElementBy(this.count - 1)
this.head = current.next
last.next = this.head
} else {
this.head = null
}
} else {
const previous = this.getElementBy(index - 1)
current = previous.next
previous.next = current.next
}
this.count--
return true
}
getIndexBy(element) {
if (!this.head || !element) {
return undefined
}
let current = this.head
for (let i = 0; current; i++) {
if (current.value === element) {
return i
}
current = current.next
}
// for 循环找到的直接退出函数体
return -1
}
getElementBy(index) {
if (!this.head || index < 0 || index >= this.count) {
return undefined
}
let current = this.head
// 控制次数
for (let i = 0; i < index; i++) {
current = current.next
}
return current
}
size() {
return this.count
}
isEmpty() {
return this.count === 0
}
print() {
if (!this.count === 0) {
console.log('')
return
}
let str = ''
let current = this.head
let i = 0
while (current && i < this.count) {
str = `${str}=>(current: ${current.value}, next:${current.next && current.next.value})\n`
current = current.next
i++
}
console.log(str)
return str
}
}
双向循环链表
链表尾元素指向链表的头部节点, 每个链表有next和prev指针,分别指向链表的下个节点和上个节点
有序链表
按照链表的元素大小排列依次排列
const compare = {
BIGGER: 1,
SMALL: -1,
EQUAL: 0,
}
class Node {
constructor(value) {
this.value = value
this.next = null
}
}
class OrderlyinkedList {
count = 0
head = null
push(element, index = 0) {
if ((index < 0 || index > this.count) && typeof element !== 'number') {
return false
}
let current = this.head
const node = new Node(element)
if (this.isEmpty()) {
return this.insert(element, 0)
} else {
// 不断移动索引, index 和 current每次循环开始前都一一对应了
for (var i = 0; i < this.count; i++) {
const result = element - current.value
if (result === compare.EQUAL || result === compare.SMALL) {
break
}
current = current.next
}
return this.insert(element, i)
}
}
insert(element, index = 0) {
if (index < 0 || index > this.count) {
return false
}
let prious
let current = this.head
const node = new Node(element)
if (index === 0) {
if (!this.head) {
this.head = node
} else {
node.next = current
this.head = node
}
} else {
for (let i = 0; i < index; i++) {
prious = current
current = current.next
}
prious.next = node
node.next = current
}
this.count++
return true
}
removeElement(element) {
const index = this.getIndexBy(element)
return index > -1 ? this.removeElementBy(index) : false
}
removeElementBy(index) {
if (!this.head || index < 0 || index >= this.count) {
return false
}
let current = this.head
if (index === 0) {
if (this.count !== 1) {
const last = this.getElementBy(this.count - 1)
this.head = current.next
last.next = this.head
} else {
this.head = null
}
} else {
const previous = this.getElementBy(index - 1)
current = previous.next
previous.next = current.next
}
this.count--
return true
}
getIndexBy(element) {
if (!this.head || !element) {
return undefined
}
let current = this.head
for (let i = 0; current; i++) {
if (current.value === element) {
return i
}
current = current.next
}
// for 循环找到的直接退出函数体
return -1
}
getElementBy(index) {
if (!this.head || index < 0 || index >= this.count) {
return undefined
}
let current = this.head
// 控制次数
for (let i = 0; i < index; i++) {
current = current.next
}
return current
}
size() {
return this.count
}
isEmpty() {
return this.count === 0
}
print() {
if (!this.count === 0) {
console.log('')
return
}
let str = ''
let current = this.head
while (current) {
str = `${str}=>${current.value}`
current = current.next
}
console.log(str)
return str
}
}