一、链表节点
class ListNode {
var val: Int
var node: ListNode
init(_ val: Int){
self.val = val
self.node = nil
}
}
二、通过节点实现链表
class List {
var head: ListNode?
var tail: ListNode?
// 尾插法
func appendToTail(_ val: Int) {
if tail == nil { // 确定头部节点
tail = ListNode(val)
head = tail
} else {
// 如下方式保证了尾部节点始终为传入的最新节点
tail?.next = ListNode(val)
tail = tail?.next
}
}
// 头插法
/*
头插法就是从后往前寻找节点,当前传入的节点在链表中位于head节点之前
*/
func appendToHead(_ val: Int) {
if head == nil {
head = ListNode(val)
tail = head
} else {
let temp = ListNode(val)
temp.next = head
head = temp
}
}
}
三、Dummy节点和尾插法
Dummy节点的作用是作为一个虚拟的头前节点。在不知道要返回的新链表的头结点是哪一个,它可能是原链表的第一个节点,可能在原链表的中间,也可能在最后,甚至不存在(nil)。引入Dummy节点可以涵盖所有情况,并且可以使用dummy.next返回最终需要的头结点。
四、算法实例
给出一个链表和一个值x,要求将链表中所有小于x得值放在左边,左右大于或者等于x的值放到右边,并且原链表的节点顺序不能变。例如:1 -> 5 -> 3 -> 2 -> 4 -> 2,给定x = 3,则要返回 1 -> 2 -> 2 -> 5 -> 3 -> 4。
思路:将链表分为小于x节点与大于x节点进行处理,最后进行左右连接。同时采用尾插法,遍历链表。
func partiton(_ head: ListNode?, _ target: Int) {
// 引入Dummy节点
var preDummy = ListNode(0), postDummy = ListNode(0)
var pre = preDummy, post = postDummy, node = head
while node != nil {
if node!.val < target {
pre.next = node
pre = node!
} else {
post.next = node
post = node!
}
node = node!.next
}
preDummy.next = postDummy.next
post.next = nil // 防止构成环
return preDummy.next
}
测试代码:
let firstNode = ListNode(1)
let secondNode = ListNode(5)
let thirdNode = ListNode(3)
let fourthNode = ListNode(2)
let fifthNode = ListNode(4)
let sixthNode = ListNode(2)
firstNode.next = secondNode
secondNode.next = thirdNode
thirdNode.next = fourthNode
fourthNode.next = fifthNode
fifthNode.next = sixthNode
var result = self.getLeftList(firstNode, 3)
while result != nil {
print("node val: \(String(describing: result?.val))")
result = result?.next
}
注意点:post.next = nil,是为了防止链表循环指向构成环,这是必需的但是容易忽略的一步。
本文介绍了链表节点的概念,讲解了如何通过节点实现链表,重点探讨了Dummy节点在链表操作中的作用,特别是在尾插法中的应用。此外,还提供了一个具体的算法实例——根据给定值x重新排列链表,将小于x的节点放在左边,大于或等于x的节点放在右边,保持原顺序。文中提到的解决方案是将链表分为两部分并采用尾插法,最后将两部分连接起来,确保正确性和避免环形链表的形成。
721

被折叠的 条评论
为什么被折叠?



