一、单向链表
链表和数组一样,可以用于存储一系列的元素,但是链表和数组的实现机制完全不同。链表的每个元素由一个存储元素本身的节点和一个指向下一个元素的引用(有的语言称为指针或连接)组成。类似于火车头,一节车厢载着乘客(数据),通过节点连接另一节车厢。
重点:单向链表由一个头组成
链表的优势:
链表中的元素在内存中不必是连续的空间,可以充分利用计算机的内存,实现灵活的内存动态管理。
链表不必在创建时就确定大小,并且大小可以无限地延伸下去。
链表在插入和删除数据时,时间复杂度可以达到O(1),相对数组效率高很多。
链表的缺点:
链表访问任何一个位置的元素时,都需要从头开始访问(无法跳过第一个元素访问任何一个元素)。无法通过下标值直接访问元素,需要从头开始一个个访问,直到找到对应的元素。虽然可以轻松地到达下一个节点,但是回到前一个节点是很难的。
1.1 链表的实现
class CreateNode {
constructor(data) {
this.data = data
this.next = null
}
}
class LinkedList {
constructor() {
this.heade = null
this.length = 0
}
append(data) {
let newNode = new CreateNode(data)
if (this.length == 0) {
this.heade = newNode
} else {
let current = this.heade
while (current.next) {
current = current.next
}
current.next = newNode
}
this.length++
}
toString() {
let current = this.heade,
stringLsit = '';
while (current) {
stringLsit += current.data + ' '
current = current.next
}
return stringLsit
}
insert(index, data) {
if (index < 0 || index > this.length) return false
let node = new CreateNode(data);
if (index == 0) {
node.next = this.heade
this.heade = node
} else {
let idx = 0,
previous = null,
current = this.heade;
while (idx++ < index) {
previous = current
current = current.next
}
node.next = current
previous.next = node
}
this.length++
}
get(index) {
if (index < 0 || index >= this.length) return null
let current = this.head,
idx = 0;
while (idx++ < index) {
current = current.next
}
return current.data
}
indexOf(data) {
let current = this.head,
idx = 0;
while (current) {
if (current.data == data) {
return idx
}
current = current.next
idx += 1
}
return null
}
update(index, newData) {
if (index < 0 || index >= this.length) return false
let current = this.head,
idx = 0;
while (idx++ < index) {
current = current.next
}
current.data = newData
return true
}
removeAt(index) {
if (index < 0 || index >= this.length) return false
let current = this.head
if (position == 0) {
this.head = this.head.next
} else {
let idx = 0,
previous = null;
while (idx++ < position) {
previous = current
current = current.next
}
previous.next = current.next
}
this.length -= 1
return current.data
}
}
二、双向链表
双向链表:既可以从头遍历到尾,又可以从尾遍历到头。也就是说链表连接的过程是双向的,它的实现原理是:一个节点既有向前连接的引用,也有一个向后连接的引用。
双向链表的缺点:
每次在插入或删除某个节点时,都需要处理四个引用,而不是两个,实现起来会困难些;相对于单向链表,所占内存空间更大一些;但是,相对于双向链表的便利性而言,这些缺点微不足道。
2.1 双向链表实现
class Node {
constructor(data) {
this.data = data
this.next = null
this.prev = null
}
}
class DoubleLinklist {
constructor() {
this.length = 0
this.head = null
this.tail = null
}
append(data) {
let node = new Node(data)
if (this.length == 0) {
this.head = node
this.tail = node
} else {
node.prev = this.tail
this.tail.next = node
this.tail = node
}
this.length++
}
}