[toc]

# 链表基础

# 一、链表操作

# 1. 力扣上的链表构造函数

1
2
3
4
5
6
7
8
//注意这是力扣上的构造函数不是JavaScript内置函数
function ListNode(val, next) {
this.val = (val===undefined ? 0 : val)
this.next = (next===undefined ? null : next)
}
let node = new ListNode(0,head)
//通常用来给链表加上虚拟头结点方便对链表进行操作,第一个形参传值,第二形参传链表
//另外如果用const定义变量再赋予链表,这个变量就无法操作了,原因应该是在操作链表时,链表所储存的变量的地址发生变化。

# 2. 链表移动和删除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
let cur = head 
/*
将head赋给变量cur,如果直接操作head然后再return的话会是null,由于这是浅拷贝,在操作cur时head也会发生改变,所以操作完cur再return head就行。
*/

cur = cur.next //让将cur下一位赋给cur就完成了一次移动。

while(cur){
... //对cur操作
cur = cur.next
} //这就完成了一次遍历,这时cur是null,head已操作

cur.netx = cur.next.next //想删除那个节点需找到那个节点的前面一个节点,将前面那个节点的指针指向删除节点后面那个节点。



//力扣上203. 移除链表元素

//方法一,增加虚拟节点
var removeElements = function(head, val) {
const cur = new ListNode(0,head)
let a = cur
while(a.next){
if(a.next.val==val){
a.next = a.next.next
}else{
a = a.next
}
}
return cur.next
};//增加虚拟头节点的好处在于,处理原链表的头节点与其他节点的方式一致,无需在额外考虑头节点如何处理,最后只要return cur.next就行。

//方法二,在不增加虚拟头节点的情况下删除指定节点
var removeElements = function(head, val) {
let cur = head
/*先用while将头节点中值等于val删除,之后就和方法一差不多,需要注意的是,删除后有可能是null或者传来的链表就是null,这是需要if条件判断一下,方法一无需判断是因为加了头节点所以不可能是null*/
while(cur&&cur.val==val){
cur = cur.next
}
if(!cur) return cur
head = cur //将处理好的cur赋值给head,如果不赋值,前面的操作就没有用了。
while(cur.next){
if(cur.next.val==val){
cur.next = cur.next.next
}else{
cur = cur.next
}
}
return head
};

# 3. 链表的插入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
//假设需要往链表head中的第n个节点插入val值,注意链表与数组一样下标从0开始
//首先声明一个变量并将head赋值给这个变量
let cur = head

方法一:不使用虚拟节点

//如果不使用虚拟节点的话,得分两种情况,第一种删除头节点,第二种删除后面的节点

//插入头节点
if(n==0){
head = new ListNode(val,head)
}else{
//移动到第n-1个节点前
while(n>1){ //从n减到1,这时cur到n-1节点前,如果加了虚拟头节点,这时的判断条件为0
cur = cur.next
n --
}
let node = new ListNode(val)
/*注意这里先把cur.next先赋给node.next,如果反过来先让cur.next变成node.next,再让cur.next赋给node.next,这时cur.next已经是node,相当于自己指向自己。这里有点像两个变量交换。假设有a,b两个变量,交换a,b两个变量的值,不用解构赋值的话
let c = a
a = b
b = c
*/
node.next = cur.next
cur.next = node
}

方法二:使用虚拟头节点
let cur = new ListNode(0,head)
let head = cur
while(n){
cur = cur.next
n--
}
let node = new ListNode(val)
node.next = cur.next
cur.next = node
head = head.next //最后注意去除虚拟头节点