当前位置: 首页 > news >正文

LeetCode 148.排序链表

Algorithm

      • 🎯 问题描述
      • 🛠️ 思路与方法
      • 🧩 归并排序的原理
      • 📚 解决方法:归并排序
      • 💻 C++ 实现
      • 🧠 逐步解释
      • ✅ 复杂度分析
      • 🧩 小结
      • 💡 其他解法(简单介绍)

🎯 问题描述

给定一个链表的头节点 head,要求将链表按升序排序,并返回排序后的链表。

🛠️ 思路与方法

这个问题本质上是一个链表排序问题,和常见的数组排序问题类似。常见的排序算法有很多种,最直接的方法是使用 归并排序(Merge Sort)。因为归并排序具有 O(n log n) 的时间复杂度,而且对于链表来说,归并排序非常适用,它不需要像快速排序那样随机访问数据。

归并排序的优点

  • 时间复杂度:O(n log n)
  • 空间复杂度:O(1),对于链表排序,我们可以使用递归实现归并排序,这样不需要额外的空间开销。

🧩 归并排序的原理

  1. 分割:递归地将链表分成两半,直到每个子链表只有一个节点为止。
  2. 合并:逐层合并这些子链表,使得每个子链表都是排序的。

📚 解决方法:归并排序

  1. 链表分割:我们可以使用快慢指针来找到链表的中点,将链表分为两半。
  2. 归并操作:递归地对两半链表进行排序,然后合并两部分。

💻 C++ 实现

#include <iostream>
using namespace std;// Definition for singly-linked list.
struct ListNode {int val;ListNode* next;ListNode(int x) : val(x), next(nullptr) {}
};class Solution {
public:// 归并排序主函数ListNode* sortList(ListNode* head) {if (!head || !head->next) return head;  // 递归终止条件:空链表或只有一个节点// 步骤1: 分割链表ListNode* mid = getMiddle(head);ListNode* right = mid->next;mid->next = nullptr;  // 将左半部分断开// 步骤2: 递归排序左半部分和右半部分ListNode* left = sortList(head);right = sortList(right);// 步骤3: 合并两个有序链表return merge(left, right);}private:// 获取链表的中间节点ListNode* getMiddle(ListNode* head) {if (!head) return nullptr;ListNode* slow = head;ListNode* fast = head;// 快慢指针:fast 每次移动 2 步,slow 每次移动 1 步while (fast->next && fast->next->next) {slow = slow->next;fast = fast->next->next;}return slow;}// 合并两个有序链表ListNode* merge(ListNode* left, ListNode* right) {ListNode dummy(0);ListNode* curr = &dummy;// 合并过程while (left && right) {if (left->val <= right->val) {curr->next = left;left = left->next;} else {curr->next = right;right = right->next;}curr = curr->next;}// 连接剩余部分if (left) curr->next = left;if (right) curr->next = right;return dummy.next;}
};int main() {// 示例:创建一个链表ListNode* head = new ListNode(4);head->next = new ListNode(2);head->next->next = new ListNode(1);head->next->next->next = new ListNode(3);Solution solution;ListNode* sortedList = solution.sortList(head);// 打印排序后的链表ListNode* p = sortedList;while (p) {cout << p->val << " ";p = p->next;}return 0;
}

🧠 逐步解释

  1. sortList 函数

    • 递归地分割链表。
    • 如果链表为空或者只有一个节点,则直接返回该链表。
    • 通过调用 getMiddle 找到链表的中间节点,并将链表分成左右两部分。
    • 分别对左半部分和右半部分进行排序。
    • 合并左右两个已经排序的链表,并返回结果。
  2. getMiddle 函数

    • 使用快慢指针来找到链表的中点。slow 每次走一步,fast 每次走两步,直到 fastfast->nextnullptr,此时 slow 就指向链表的中点。
  3. merge 函数

    • 将两个已经排序的链表合并成一个排序好的链表。
    • 使用一个虚拟头节点 dummy 来简化合并过程,最终返回合并后的链表。

✅ 复杂度分析

  • 时间复杂度:O(n log n),因为每次分割都将链表分成两部分,递归深度为 log n,而合并两个链表的时间是线性的 O(n),因此总的时间复杂度是 O(n log n)
  • 空间复杂度:O(log n),由于递归调用栈的空间使用,空间复杂度为 O(log n)。如果使用迭代方式来替代递归,空间复杂度可以进一步优化为 O(1)

🧩 小结

  • 归并排序非常适合链表排序,尤其是当链表非常长时,归并排序能够提供一个稳定的 O(n log n) 时间复杂度。
  • 通过链表的分割和合并操作,我们可以非常高效地完成链表的排序。

💡 其他解法(简单介绍)

除了归并排序,还可以使用快速排序或堆排序等方法,但对于链表来说,归并排序是最常见的选择,因为它适合链表的结构,不需要随机访问。

http://www.dtcms.com/a/435594.html

相关文章:

  • 做美食网站的特点怎么添加网站权重
  • 服装软件管理系统是什么?主要有哪几种类型?
  • ⚡ WSL2 搭建 s5p6818 Linux 嵌入式开发平台(Part 2):系统构建与系统部署
  • 网站别人备案怎么办赚钱网
  • wordpress网站接入qqwordpress怎么修改导航栏
  • 中山网站建设文化机构电商网站怎么做的
  • 福州市 2025 国庆集训 Day2 前三题题解
  • Java中的优先队列PriorityQueue
  • 宁波网站关键词做网站赚钱还是做应用赚钱
  • 重庆网站推广营销h5页面制作工具 软件
  • AI让产品越来越用户中心化
  • 襄阳做淘宝网站推广建设银行个人登录网站
  • 网站建设思维1级a做爰免费网站
  • 网站设计报告总结淘客免费网站建设
  • 又一个 wordpress 站点php网站建设填空题
  • 那个网站做图片好看wordpress 导入数据库结构
  • Bean后处理器
  • 一款可视化的自动复盘系统分享
  • 郑州正云网站建设慈溪网站建设慈溪
  • 我爱学算法之—— 分治-快排
  • asp网站后台上传不了图片wordpress无法加载图片
  • 什么软件 做短视频网站长尾关键词有哪些
  • 江苏建设部官方网站外贸网站有必要吗
  • 企业网站规划案例长沙seo全网营销
  • 郑州营销网站公司地址天台县建设局官方网站
  • 函数调用约定
  • 迪杰斯特拉算法
  • 网站租用服务器价格个人主页网页设计模板
  • 【开题答辩实录分享】以《基于协调过滤算法的插画分享与社交网络平台的设计与实现》为例进行答辩实录分享
  • c语言定义数组