单向链表
- 内存空间不是必须连续的,可以充分利用计算机的内存,实现灵活的内存动态管理。
- 链表不需要再创建的时候就确定大小,并且它的大小可以无限的延伸下去。
- 链表在插入和删除数据时,时间复杂度(即执行算法所需要的计算工作量)可以达到O(1),相对数组效率高许多。
链表相对于数组的缺点在于:
- 链表访问任何一个位置的元素时,都需要从头开始访问
- 无法像数组一样通过下标值访问元素,需要从头开始访问,直到找到对应的元素
主要实现一下方法:
- append 添加
- appendCha() 插入
- indexOf 返回索引
- remove 删除某一项
class Node {
constructor(element){
this.element = element
this.next = null
}
}
class LinkedList {
constructor(){
this.head = null
this.size = 0
}
append(element){
let node = new Node(element)
if(!this.head){
this.head = node
}else{
let current = this.getNode(this.size - 1)
current.next = node
}
this.size++
}
appendAt(position,element){
let node = new Node(element)
if(position === 0){
node.next = this.head
this.head = node
}else{
let pre = this.getNode(position - 1)
node.next = pre.next
pre.next = node
}
}
remove(position){
if(size < 0 || position >= this.size){
throw new Error('不合法')
}
let current = this.head
if(position === 0){
this.head = current.next
}else{
let pre = this.getNode(position - 1)
current = pre.next
pre.next = current.next
}
this.size--
}
indexOf(element){
let current = this.head
for(let i = 0; i<this.size; i++){
if(current.element === element){
return i
}
current = current.next
}
return -1
}
getNode(index){
if(index < 0 || index >= this.size){
throw new Error('不合法')
}
let current = this.head
for(let i = 0; i<index; i++){
current = current.next
}
return current
}
}
链表反转
- 第一种思路是每次复制一遍头部,然后追加到新的链表尾部,通过循环就能达到
reverse(){
let head = this.head
let newHead = null
while(head != null){
let temp = head.next
head.next = newHead
newHead = head
head = temp
}
this.head = newHead
return this.head
}
- 第二种思路 利用递归冒泡法 拿到上次的闭包钩住的值进行互换,说多了也听不懂,直接上代码
reverse(){
const reverse = (head) => {
if(head === null || head.next === null) return head
const current = reverse(head.next)
head.next.next = head
head.next = null
return current
}
this.head = reverse(this.head)
return this.head
}