在前端中,排开数组,我们最熟悉的数据结构莫过于链表。众所周知,考研也好,就业也罢,链表的地位都是不可动摇的。今天就让我们来搞定它!
本篇以基础为主,面向想要学习链表的小伙伴们,难度螺旋向上(当然也不会很难...
链表的删除
虽然比较简单,但还是想跟大伙唠唠。
给定要删除的目标节点 node(非头尾节点),头结点 head
删除一个给定的节点 node,就必须找到其前驱节点 pre。
而 pre.next = node,我们只需要让 pre.next = node.next 就能完成删除操作。
精髓部分已经完成,剩下的,只需要从 head 依次遍历寻找到 pre 前驱节点即可。
// 初始化节点
let pre = head
let cur = pre.next
// 一直往后移,直到找到目标节点
while (cur !== node) {
pre = cur
cur = cur.next
}
// 删除目标节点
pre.next = cur.next
1. 移除链表元素
题目地址:leetCode 203.移除链表元素
题目描述:
给你一个链表的头节点
head和一个整数val,请你删除链表中所有满足Node.val == val的节点,并返回 新的头节点 。
根据题意,依旧是找到指定节点,只不过这里的节点是根据 val 而定。
知识扩充:对于链表类题型,我们通常会创建一个锚节点 Dummy ,使其 next 指向头结点 head,便于对链表整体的把控。
// 初始化锚节点
let dummy = new ListNode()
dummy.next = head
由于第一个节点也可能会成为被删除节点,所以锚节点的创建是必然的。
细节请直接看代码。
var removeElements = function(head, val) {
// 如果头结点不存在,直接返回
if (!head) {
return null
}
// 初始化锚节点
let dummy = new ListNode()
dummy.next = head
// 初始化前驱节点
let pre = dummy
// 初始化当前节点
let cur = head
// 循环遍历链表
while (cur) {
// 如果找到需要删除的节点,直接删除
if (cur.val === val) {
// 使pre指向被删除节点的下一个节点,即删除cur节点
pre.next = cur.next
// 继续让cur成为pre的后继节点
cur = pre.next
}
// 如果没有找到,则换下一个节点
else {
pre = cur
cur = cur.next
}
}
return dummy.next
};
环形链表
这个环形链表,大伙应该都不陌生,如果陌生的话,也不要慌,只是还没人给你引上道。
当我们中国人第一次登月,在月球上插上我们的国旗时,小伙伴们的内心一定是激情澎湃的(跟我一样)。环形链表也如此,我们每到一个节点,就插入一面旗帜,表示我们已经来过了。如果一直遍历链表,又碰到了这面旗帜,那就说明,有环。反之,则无。
1. 环形链表
题目地址:leetCode 141.环形链表
给你一个链表的头节点
head,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪
next指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数pos来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos不作为参数进行传递。仅仅是为了标识链表的实际情况。
如果链表中存在环 ,则返回
true。 否则,返回false。
大伙应该已经顿悟!那我就不客气了,直接上代码,具体细节请看注释
var hasCycle = function (head) {
// 循环遍历链表
while (head) {
// 如果不存在flag
if (!head.flag) {
// 则插入这个属性到节点中
head.flag = 1
}
// 如果存在,说明有环
else {
return true
}
head = head.next
}
return false
};
快慢指针也可以实现,有兴趣的小伙伴们可以尝试一下
链表的排序与翻转
1. 排序链表
题目地址:leetCode 148.排序链表
题目描述:
给你链表的头结点
head,请将其按 升序 排列并返回 排序后的链表 。
小伙伴们:啊这...这题?可恶!怎么不是数组?!
注意了,拿起笔划重点啦,三剑客登场。
pre(前驱节点) cur(当前节点) next(后继节点)
处理这类排序翻转比较负责的问题时,就需要用到三剑客,小伙伴们需要察言观色啊(多做题...
实现翻转效果
cur.next = next.next
next.next = pre.next
pre.next = next
请看代码
var sortList = function (head) {
// 初始化锚节点
let dummy = new ListNode()
dummy.next = head
// 初始化前驱结点
let pre = dummy
// 初始化当前节点
let cur = head
// 循环遍历链表
while (cur) {
// 初始化后继节点
let next = cur.next
// 如果后继节点存在 且值要小于当前节点 则需要换位置
if (next && next.val < cur.val) {
// 遍历链表 找到比next.val要大的值
while (pre.next.val < next.val) {
pre = pre.next
}
// 翻转
cur.next = next.next
next.next = pre.next
pre.next = next
// 重置pre 从头开始
pre = dummy
} else {
// 回至原来的位置
cur = next
}
}
return dummy.next
};
小结:
未完待更...