链表以及数组的缺点
链表和数组一样,可以用于存储一系列的元素,但是链表和数组的实现机制完全不同。
数组的缺点:
- 数组的创建通常需要申请一段连续的内存空间(一整块的内存),并且大小是固定的(大多数编程语言数组都是固定的),所以当 当前数组不能满足容量需求时,需要扩容。 (一般情况下是申请一个更大的数组,比如2倍。 然后将原数组中的元素复制过去)
- 在数组开头或中间位置插入数据的成本很高,需要进行大量元素的位移。
链表结构的封装
- 封装一个Node类,用于封装每一个节点上的信息(包括值和指向下一个节点的引用),它是一个泛型类。
- 封装一个LinkedList类,用于表示我们的链表结构。链表中我们保存两个属性,一个是链表的长度,一个是链表中第一个节点。
// 1.创建Node节点类
class Node<T> {
value: T
next: Node<T> | null = null
constructor(value: T) {
this.value = value
}
}
// 2.创建LinkedList的类
class LinkedList<T> {
head: Node<T> | null = null
private size: number = 0
get length() {
return this.size
}
}
append方法
向链表尾部追加数据可能有两种情况:\
- 链表本身为空,新添加的数据时唯一的节点。
- 链表不为空,需要向其他节点后面追加节点。
// 追加节点
append(value: T) {
// 1.根据value创建一个新节点
const newNode = new Node(value)
// 2.判断this.head是否为null
if (!this.head) {
this.head = newNode
} else {
let current = this.head
while (current.next) {
current = current.next
}
// current肯定是指向最后一个节点的
current.next = newNode
}
// 3.size++
this.size++
}
链表的遍历方法(traverse)
// 遍历链表的方法
traverse() {
const values: T[] = []
let current = this.head
while (current) {
values.push(current.value)
current = current.next
}
console.log(values.join("->"))
}
insert方法
-
添加到第一个位置:添加到第一个位置,表示新添加的节点是头, 就需要将原来的头节点,作为新节点的next,另外这个时候的head应该指向新节点。
-
添加到其他位置:如果是添加到其他位置,就需要先找到这个节点位置了。通过while循环,一点点向下找。 并且在这个过程中保存上一个节 点和下一个节点。找到正确的位置后,将新节点的next指向下一个节点,将上一个节点的 next指向新的节点。
// 插入方法: abc
insert(value: T, position: number): boolean {
// 1.越界的判断
if (position < 0 || position > this.size) return false
// 2.根据value创建新的节点
const newNode = new Node(value)
// 3.判断是否需要插入头部
if (position === 0) {
newNode.next = this.head
this.head = newNode
} else {
let current = this.head
let previous: Node<T> | null = null
let index = 0
while (index++ < position && current) {
previous = current
current = current.next
}
// index === position
newNode.next = current
previous!.next = newNode
}
this.size++
return true
}
removeAt方法
- 移除第一项的信息:直接让head指向第二项信息
- 其他项的信息:通过while循环,找到正确的位置,找到正确位置后,就可以直接将上一项的next指向current 项的next。
// 删除方法:
removeAt(position: number): T | null {
// 1.越界的判断
if (position < 0 || position >= this.size) return null
// 2.判断是否是删除第一个节点
let current = this.head
if (position === 0) {
this.head = current?.next ?? null
} else {
let previous: Node<T> | null = null
let index = 0
while (index++ < position && current) {
previous = current
current = current.next
}
// 找到需要的节点
previous!.next = current?.next ?? null
}
this.size--
return current?.value ?? null
}
get方法
// 获取方法:
get(position: number): T | null {
// 越界问题
if (position < 0 || position >= this.size) return null
// 2.查找元素, 并且范围元素
let index = 0
let current = this.head
while (index++ < position && current) {
current = current.next
}
// index === position
return current?.value ?? null
}