返回

初探 LeetCode 147:对链表进行插入排序的 Python 巧解

人工智能

导言

算法竞赛的殿堂里,LeetCode 147 是一道经典题,它考验着算法爱好者们对链表数据结构的理解和运用能力。这道题要求我们对一个无序链表进行插入排序,按照从小到大的顺序排列元素。本篇文章将带你领略 Python 语言下的优雅解法,为你打开算法思维的另一扇窗。

算法流程

插入排序算法的精髓在于将待排序的元素逐个插入到已排序序列中。对于链表结构,插入过程需要格外谨慎,以维护链表的连贯性。算法流程如下:

  1. 初始化 :设置头指针(Head)和当前指针(Current)。Head 指向链表头,Current 指向待排序元素。

  2. 循环遍历 :对于每一个待排序元素(Current),执行以下操作:

    • 将 Current 指向待插入元素。
    • 比较 Current 与其前驱元素(Current.prev),直到找到合适的位置。
    • 将 Current 插入到前驱元素之后。
  3. 更新指针 :将 Current 指向待插入元素的下一个元素。

  4. 循环结束 :当所有元素都已排序,算法终止,返回头指针。

Python 实现

def insertion_sort_list(head):
  """
  对链表进行插入排序。

  参数:
    head:链表头节点

  返回:
    排序后的链表头节点
  """

  if not head or not head.next:
    return head

  dummy = ListNode(0)
  dummy.next = head

  current = head

  while current and current.next:
    if current.val <= current.next.val:
      current = current.next
    else:
      prev = dummy

      while prev.next.val < current.next.val:
        prev = prev.next

      nxt = current.next
      current.next = nxt.next
      nxt.next = prev.next
      prev.next = nxt

  return dummy.next

代码解读

  1. 初始化 :创建哨兵节点 dummy,它指向链表头。这样,算法可以处理空链表和只有一个元素的链表。

  2. 遍历链表 :使用 current 指针遍历链表。

  3. 比较元素 :如果 current.val <= current.next.val,说明元素已经处于正确的位置,继续遍历。否则,需要插入排序。

  4. 查找插入点 :使用 prev 指针遍历已排序链表,找到插入点(即 prev.next.val < current.next.val)。

  5. 插入元素 :将 current.next 元素插入到 prev 和 prev.next 之间。

  6. 更新指针 :将 current 指向 current.next。

  7. 返回结果 :返回哨兵节点 dummy 的 next 指向的节点,即排序后的链表头。

优势和限制

优势

  • 简单易懂,代码清晰易读。
  • 时间复杂度为 O(n^2),适用于规模较小的链表。
  • 空间复杂度为 O(1),不需要额外的空间。

限制

  • 对于大型链表,时间复杂度较高。
  • 对于特殊情况(如链表为空或只有一个元素),需要特殊处理。

结语

LeetCode 147 是一道经典算法题,它考验着对链表结构和插入排序算法的理解。通过 Python 的简洁实现,我们可以领会算法的精髓和优势。希望这篇文章能够激发你的算法热情,助你踏上算法竞赛的征途。

参考