思路
首先分析思路,链表+排序等于归并排序
归并: 如果是正常学习的数组,就要考虑空间置换的问题,但是链表是指针的行为,可以直接通过操作指针就行了,不像数组一样操作对应的东西。
步骤:
1.从中间分割开两边,使用快慢指针去获取中间位数 2.分割前面的链表 3.分割后面的链表 4.最后合并起来
code
先准备每个步骤的测试代码,然后再拼接起来
func sliceToList(arr []int) *ListNode { if len(arr) == 0 { return nil } head := &ListNode{Val: arr[0]} current := head for _, v := range arr[1:] { current.Next = &ListNode{Val: v} current = current.Next } return head }
首先的先写最简单的通过快慢指针去找到中位数(好像有几道 leetcode 也是这样子做的)
func getMiddle(head *ListNode) *ListNode {
slow := head
fast := head
for fast != nil && fast.Next != nil {
slow = slow.Next //一个先走一步
fast = fast.Next.Next //这个就是直接走两步
}
return slow //最后获取到中间的
}
//开始测试
func TestGetMiddle(t *testing.T) {
tests := []struct {
input []int
expected int
}{
{[]int{1, 2, 3, 4, 5}, 3},
{[]int{1, 2, 3, 4}, 2},
{[]int{1}, 1},
{[]int{}, 0},
}
for _, tt := range tests {
t.Run("getMiddle", func(t *testing.T) {
input := sliceToList(tt.input)
mid := getMiddle(input)
if mid != nil && mid.Val != tt.expected {
t.Errorf("expected middle value %v, but got %v", tt.expected, mid.Val)
} else if mid == nil && tt.expected != 0 {
t.Errorf("expected middle value %v, but got nil", tt.expected)
}
})
}
}
然后做一个 合并两个排序的 方法,这个比较写用一个 for 然后去比较谁比较大,然后把剩下的加到另外一个链表即可
func merge(left, right *ListNode) *ListNode {
dummy := &ListNode{}
tail := dummy
for left != nil && right != nil {
if left.Val < right.Val {
tail.Next = left
left = left.Next
} else {
tail.Next = right
right = right.Next
}
tail = tail.Next
}
if left != nil {
tail.Next = left
}
if right != nil {
tail.Next = right
}
return dummy.Next
}
//这里还能优化一下 只用 l1 的空间
func merge(list1, list2 *ListNode) *ListNode {
// 如果 list1 为空,直接返回 list2
if list1 == nil {
return list2
}
// 如果 list2 为空,直接返回 list1
if list2 == nil {
return list1
}
// 比较头结点,确定哪个链表的头结点较小
if list1.Val < list2.Val {
list1.Next = merge(list1.Next, list2) // 递归合并剩余部分
return list1
} else {
list2.Next = merge(list1, list2.Next) // 递归合并剩余部分
return list2
}
}
最后合并起来
// mergeSort 实现链表的归并排序
func mergeSort(head *ListNode) *ListNode {
if head == nil || head.Next == nil {
return head
}
// 1. 找到链表的中间节点
mid := getMiddle(head)
left := head
right := mid.Next
mid.Next = nil // 切断中间节点与右侧部分的连接
// 2. 递归对左右部分进行归并排序
left = mergeSort(left)
right = mergeSort(right)
// 3. 合并排序后的两个链表
return merge(left, right)
}
然后成功发生死循环,断电打在
left = mergeSort(left)
为什么为什么?因为这里需要slow 指针无论如何也不会移动
// 获取链表的中间节点
func getMiddle(head *ListNode) *ListNode {
if head == nil || head.Next == nil {
return head
}
slow, fast := head, head
// 快慢指针,找到中间节点 ,这里有问题,slow 一直返回最后一个
for fast != nil && fast.Next != nil {
slow = slow.Next
fast = fast.Next.Next
}
//新增加代码
if fast == nil {
return head
}
return slow
}
最后ac