148. 排序链表(中)

题目

  • 给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。

python

法一、冒泡排序

  • 冒泡排序:两个for循环,i从头开始,j在i后一位开始,比较如果j小于i就交换,否则i往后移
class Solution:
    def sortList(self, head: Optional[ListNode]) -> Optional[ListNode]:
        i = head
        j = head.next
        if not head or head.next is None: # 如果链表为空或只有一个节点,直接返回链表本身
            return []
        p = ListNode(0)# 创建一个虚拟节点作为排序后链表的头节点
        while i and i.next:
            while j and j.next:
                if j.val < i.val:
                    p.next, j.next = i.next, i
                else:# 如果j大于等于i,则继续向后移动j节点
                    j = j.next
            i = i.next
        return p.next# 返回排序后链表的头节点
  • 超时 :时间复杂度:O(n2);空间复杂度:O(1)
  • 分析:

不适合的排序:基数排序(只适合非负数)、希尔排序(链表不支持随机访问,该排序涉及步长)、堆排序(树适合用顺序结构)
超时排序:冒泡排序、选择排序、插入排序、快速排序。
空间换时间:归并排序、计数排序、桶排序

法二、归并排序

class Solution:
    def merge(self, left, right):
        # 归并环节
        dummy_head = ListNode(-1)#构造一个头节点
        cur = dummy_head#用 cur 指向 dummy_head 用于遍历
        while left and right:#比较两个链表头节点 left 和 right 的值大小。将较小的头节点加入到合并后的链表中。并向后移动该链表的头节点指针。
            if left.val <= right.val:
                cur.next = left
                left = left.next
            else:
                cur.next = right
                right = right.next
            cur = cur.next        
        if left:
            cur.next = left
        elif right:
            cur.next = right            
        return dummy_head.next        
    def mergeSort(self, head: ListNode):
        # 分割环节
        if not head or not head.next:
            return head
        # 快慢指针找到中心链节点
        slow, fast = head, head.next
        while fast and fast.next:
            slow = slow.next 
            fast = fast.next.next 
        # 断开左右链节点
        left_head, right_head = head, slow.next 
        slow.next = None 
        # 归并操作
        return self.merge(self.mergeSort(left_head), self.mergeSort(right_head))
    def sortList(self, head: Optional[ListNode]) -> Optional[ListNode]:
        return self.mergeSort(head)

javascript

归并排序(分治)

// 876. 链表的中间结点(快慢指针)
function middleNode(head) {
    let slow = head, fast = head;
    // 先找到链表的中间结点的【前一个节点】
    while (fast.next && fast.next.next) {
        slow = slow.next;
        fast = fast.next.next;
    }
    const mid = slow.next; // 下一个节点就是链表的中间结点 mid
    slow.next = null; // 断开 mid 的前一个节点和 mid 的连接
    return mid;
}

// 21. 合并两个有序链表(双指针)
function mergeTwoLists(list1, list2) {
    const dummy = new ListNode(); // 用哨兵节点简化代码逻辑
    let cur = dummy; // cur 指向新链表的末尾
    while (list1 && list2) {
        if (list1.val < list2.val) {
            cur.next = list1; // 把 list1 加到新链表中
            list1 = list1.next;
        } else { // 注:相等的情况加哪个节点都是可以的
            cur.next = list2; // 把 list2 加到新链表中
            list2 = list2.next;
        }
        cur = cur.next;
    }
    cur.next = list1 ?? list2; // 拼接剩余链表
    return dummy.next;
}

var sortList = function(head) {
    // 如果链表为空或者只有一个节点,无需排序
    if (head === null || head.next === null) {
        return head;
    }
    // 找到中间节点,并断开 head2 与其前一个节点的连接
    // 比如 head=[4,2,1,3],那么 middleNode 调用结束后 head=[4,2] head2=[1,3]
    let head2 = middleNode(head);
    // 分治
    head = sortList(head);
    head2 = sortList(head2);
    // 合并
    return mergeTwoLists(head, head2);
};
posted @   Frommoon  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示