单链表的排序-力扣算法题

news2024/10/4 13:26:50

文章目录

    • 概要
    • 例题
    • 解题思路:
      • 1、递归分割
      • 2、递归排序实际的含义
      • 3、递归回溯与合并
    • case解析:
      • 1、初始链表:
      • 2、第一轮分割:
      • 3、继续分割:
      • 有序子链表合并:
      • 最终合并:
      • 结果:
    • 代码实现
    • 总结:

概要

对链表进行排序:按照从小到大的顺序或者从大到小的顺序进行完成排序

例题

在这里插入图片描述

解题思路:

1、递归分割

  • 当我们谈到“排序”链表时,指的是将链表递归地分割成越来越小的子链表,直到每个子链表只有一个节点或者没有节点。
    对于这样的链表,它们已经是有序的了,因为单个节点自然而然是有序的,而空链表也是有序的。
  • 这种分割发生在mergeSort函数中:如果链表头节点(head)不是null且下一个节点(head.next)不是null,则说明这个链表有两个以上的节点,需要被分割。

2、递归排序实际的含义

  • 在这个上下文中,“排序”实际上是一个递归过程,在这个过程中每次递归调用都会将链表分为两部分,并对这两部分做进一步的递归分割。
  • 当递归地对链表进行切分,直到无法继续切分(即每个子链表只有一个节点或者没有节点),就达到了递归的基本情况。这时候递归开始回溯,逐层向上。

3、递归回溯与合并

  • 在递归回溯的过程中,我们开始对这些只有一个节点的子链表进行合并,这其实就是在进行排序。
  • 每次递归返回时,我们会拿到两个有序的子链表,然后我们使用merge函数将这两个有序的子链表合并成一个更大的有序链表。这个合并的过程就是实际的排序操作,因为它将无序的链表组件重新组合成有序的形式。

如果你理解了分割和合并两个有序链表这两个步骤,那么“排序”这个词在这里其实是指归并排序中分割和合并的整个循环过程。实际上,链表从未真正被“排序”,而是被分割成单元件,那些单元件通过合并操作在递归回溯的过程中恢复成一个整体,形成最终的有序链表。

case解析:

case:节点6->4 -> 2->5->7-> 1 -> 3

让我们逐步通过归并排序对链表 6 -> 4 -> 2 -> 5 -> 7 -> 1 -> 3 进行排序。下面描述了排序过程的每个阶段。

1、初始链表:

6 -> 4 -> 2 -> 5 -> 7 -> 1 -> 3

2、第一轮分割:

将链表从中间分割成两半。
左边的子链表是 6 -> 4 -> 2 -> 5,右边的子链表是 7 -> 1 -> 3。

左子链表: 6 -> 4 -> 2 -> 5
右子链表: 7 -> 1 -> 3

3、继续分割:

左子链表 6 -> 4 -> 2 -> 5 再次分割为 6 -> 4 和 2 -> 5。

左子链表的左半部: 6 -> 4
左子链表的右半部: 2 -> 5

然后,6 -> 4 和 2 -> 5 分别再分割为单个节点。

右子链表 7 -> 1 -> 3 的分割稍微复杂因为它有奇数个节点。首先分割成 7 和 1 -> 3。

右子链表的左半部: 7
右子链表的右半部: 1 -> 3

然后,1 -> 3 分割成 1 和 3,单独的 7 已经是有序的。

有序子链表合并:

现在,开始合并这些子链表,每次合并都保证有序。

首先合并 6 -> 4 得到 4 -> 6,合并 2 -> 5 结果是已经有序的,然后合并 4 -> 6 和 2 -> 5 得到 2 -> 4 -> 5 -> 6。

接着,合并 7 和 1 -> 3,首先合并 1 和 3 得到 1 -> 3,然后与 7 合并得到 1 -> 3 -> 7。

最终合并:

现在,我们已经拥有两个有序的子链表 2 -> 4 -> 5 -> 6 和 1 -> 3 -> 7。

这两个有序子链表合并过程如下:

  1. 对比 2 和 1,因为 1 更小,所以选 1 作为新链表的第一个节点。
  2. 现在对比 2 和 3,选择 2。
  3. 然后对比 4 和 3,选择 3。
  4. 接下来对比 4 和 7,选择 4。
  5. 接着 5 比 7 小,选择 5。
  6. 再下来 6 比 7 小,选择 6。
  7. 最后只剩下 7,将其添加到新链表尾部。

结果:

1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7

这是最终排序后的链表。每一步的分割和合并操作是递归进行的,每次都有序地合并子链表,最终得到完整的排序链表。

代码实现

提示:这里可以添加总结
下面是一个典型的用于对单链表进行归并排序的Java代码示例。我将在代码中添加详细的注释以解释每一步的操作。


class ListNode {
    int val;
    ListNode next;
    ListNode(int x) { val = x; }
}

public class MergeSortLinkedList {

    public ListNode sortList(ListNode head) {
        // 基本情况:如果链表为空或只有一个元素,它已经是有序的
        if (head == null || head.next == null) {
            return head;
        }

        // 找到中间节点,将链表分成两半
        ListNode mid = getMid(head);
        ListNode left = head;         // 左半部分的头节点
        ListNode right = mid.next;    // 右半部分的头节点
        mid.next = null;              // 截断链表

        // 对左右两半递归进行排序
        left = sortList(left);
        right = sortList(right);

        // 合并两个已排序的子链表,并返回结果链表的头节点
        ListNode sortedList = merge(left, right);
        return sortedList;
    }

    private ListNode getMid(ListNode head) {
        // 快慢指针法找到中间节点
        ListNode slow = head;
        ListNode fast = head;
        ListNode prev = null; // 用于记录慢指针的前一个节点

        while (fast != null && fast.next != null) {
            prev = slow;
            slow = slow.next;
            fast = fast.next.next;
        }

        return prev != null ? prev : slow; // 返回慢指针的前一个节点作为中间节点
    }

    private ListNode merge(ListNode l1, ListNode l2) {
        // 使用虚拟头节点简化边界条件处理
        ListNode dummyHead = new ListNode(0);
        ListNode current = dummyHead;

        // 遍历两个链表,按顺序选择较小的节点进行合并
        while (l1 != null && l2 != null) {
            if (l1.val < l2.val) {
                current.next = l1;
                l1 = l1.next;
            } else {
                current.next = l2;
                l2 = l2.next;
            }
            current = current.next; // 移动到链表的下一个位置
        }

        // 如果有一个链表提前结束,将另一个链表的剩余部分连接到结果链表
        if (l1 != null) {
            current.next = l1;
        } else if (l2 != null) {
            current.next = l2;
        }

        return dummyHead.next; // 返回排序后的链表头节点,即虚拟头节点的下一个节点
    }
}


每一行代码都有相应的注释描述了其功能和作用。归并排序的链表版本有两个核心函数:

  1. sortList函数:用于对链表进行拆分并递归调用排序整个链表。
  2. getMid函数:使用快慢指针的方式找到链表的中间节点,从而拆分链表。
  3. merge函数:用于合并两个已排序的子链表。

整个归并排序是一个递归过程,在多数情况下,通过递归能够实现简洁而清晰的归并排序算法,对链表的每个部分都完成排序后的合并

总结:

长期主义就是坚持,任重而道远,当一件平凡的事情坚持下去就会有意想不到的结果,加油。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1488074.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JavaScript继承 寄生组合式继承 extends

JavaScript继承 1、JS 的继承到底有多少种实现方式呢? 2、ES6 的 extends 关键字是用哪种继承方式实现的呢? 继承种类 原型链继承 function Parent1() {this.name parentlthis.play [1, 2, 3] }function Child1() {this.type child2 }Child1.prototype new Parent1(…

(十)SpringCloud系列——openfeign的高级特性实战内容介绍

前言 本节内容主要介绍一下SpringCloud组件中微服务调用组件openfeign的一些高级特性的用法以及一些常用的开发配置&#xff0c;如openfeign的超时控制配置、openfeign的重试机制配置、openfeign集成高级的http客户端、openfeign的请求与响应压缩功能&#xff0c;以及如何开启…

bashplotlib,一个有趣的 Python 数据可视化图形库

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站AI学习网站。 目录 前言 什么是Bashplotlib库&#xff1f; 安装Bashplotlib库 使用Bashplotlib库 Bashplotlib库的功能特性 1. 绘…

Linux速览(1)——基础指令篇

在上一章对Linux有了一些基础了解之后&#xff0c;本章我们来学习一下Linux系统下一些基本操作的常用的基础指令。 目录 1. ls 指令 2. pwd&&whoami命令 3. cd 指令 4. touch指令 5.mkdir指令&#xff08;重要&#xff09;&#xff1a; 6.rmdir指令 && …

pandas行列求众数及按列去重

创建示例数据框如下&#xff1a; df2pd.DataFrame(data{A:[1,2,3,3,4,4,4,4],B:[a,b,c,c,d,d,d,d],C:[11,22,33,33,44,44,44,44],D:[11,22,33,33,44,44,44,44]}) print(df2.mode()) #求列众数 print(df2.loc[:,[A,C,D]].mode(axis1)) #求特定列的行众数 df2.drop_duplicates(s…

记一次:android学习笔记一(学习目录-不要看无内容)

学习目录如下 B站学习的名称--Android开发从入门到精通(项目案例版) 网址:https://www.bilibili.com/video/BV1jW411375J/ 第0章:安装 android stoid 参考地址https://blog.csdn.net/adminstate/article/details/130542368 第一章:第一个安卓应用 第二章:用户界面设…

类和对象基础知识

1. C和C语言最大的区别 以洗衣服为例&#xff0c; C语言是手洗&#xff0c;你需要对每一个过程非常的清楚&#xff0c;一步一步都需要自己亲自去完成&#xff0c; 而C更像是机洗&#xff0c;整个过程划分为人、衣服、洗衣粉、洗衣机四个对象的交互过程&#xff0c; 而人是不…

C语言指针的初步认识--学习笔记(2)

1.数组名的理解 我们在使⽤指针访问数组的内容时&#xff0c;有这样的代码&#xff1a; int arr[10]{1,2,3,4,5,6,7,8,9,10}; int* p&arr[0]; 这⾥我们使⽤ &arr[0] 的⽅式拿到了数组第⼀个元素的地址&#xff0c;但是其实数组名本来就是地址&#xff0c;⽽且 是数组…

React 事件机制原理

相关问题 React 合成事件与原生 DOM 事件的区别React 如何注册和触发事件React 事件如何解决浏览器兼容问题 回答关键点 React 的事件处理机制可以分为两个阶段&#xff1a;初始化渲染时在 root 节点上注册原生事件&#xff1b;原生事件触发时模拟捕获、目标和冒泡阶段派发合…

羊大师揭秘羊奶与健康,美味的保健佳品

羊大师揭秘羊奶与健康&#xff0c;美味的保健佳品 羊奶确实是一种美味且健康的保健佳品&#xff0c;其独特的营养成分和风味使其成为许多人的健康选择。以下是一些羊奶与健康的关系&#xff1a; 营养丰富&#xff1a;羊奶含有丰富的蛋白质、脂肪、矿物质和维生素&#xff0c;…

Go字符串实战操作大全!

目录 1. 引言文章结构概览 2. Go字符串基础字符串的定义与特性什么是字符串&#xff1f;Go字符串的不可变性原则 字符串的数据结构Go字符串的内部表达byte和rune的简介 3. 字符串操作与应用3.1 操作与应用字符串连接字符串切片字符串查找字符串比较字符串的替换字符串的大小写转…

【动态规划专栏】

动态规划基础知识 概念 动态规划&#xff08;Dynamic Programming&#xff0c;DP&#xff09;&#xff1a;用来解决最优化问题的算法思想。 动态规划是分治思想的延伸&#xff0c;通俗一点来说就是大事化小&#xff0c;小事化无的艺术。 一般来说&#xff0c;…

Android 开发环境搭建的步骤

本文将为您详细讲解 Android 开发环境搭建的步骤。搭建 Android 开发环境需要准备一些软件和工具&#xff0c;以下是一些基础步骤&#xff1a; 1. 安装 Java Development Kit (JDK) 首先&#xff0c;您需要安装 Java Development Kit (JDK)。JDK 是 Android 开发的基础&#xf…

教师的调动谁有决定权

当你身边的老师突然“消失”&#xff0c;在另一所学校出现&#xff0c;你是否好奇过&#xff0c;这背后的调动是如何发生的&#xff1f;谁又是这场“迁徙”背后的决定者&#xff1f; 很多人可能首先想到的是校长。毕竟&#xff0c;在学校里&#xff0c;校长似乎是那个“发号施令…

前端从普通登录到单点登录(SSO)

随着前端登录场景的日益复杂化和技术思想的不断演进&#xff0c;前端在登录方面的知识结构变得越来越复杂。对于前端开发者来说&#xff0c;在日常工作中根据不同的登录场景提供合适的解决方案是我们的职责所在&#xff0c;本文将梳理前端登录的演变过程。 1、无状态的HTTP H…

【论文阅读】TensoRF: Tensorial Radiance Fields 张量辐射场

发表于ECCV2022. 论文地址&#xff1a;https://arxiv.org/abs/2203.09517 源码地址&#xff1a;https://github.com/apchenstu/TensoRF 项目地址&#xff1a;https://apchenstu.github.io/TensoRF/ 摘要 本文提出了TensoRF&#xff0c;一种建模和重建辐射场的新方法。不同于Ne…

面试题HTML+CSS+网络+浏览器篇

文章目录 Css预处理sass less是什么&#xff1f;为什么使用他们怎么转换 less 为 css&#xff1f;重绘和回流是什么http 是什么&#xff1f;有什么特点HTTP 协议和 HTTPS 区别什么是 CSRF 攻击HTML5 新增的内容有哪些Css3 新增的特性flex VS grid清除浮动的方式有哪些&#xff…

嵌入式入门必经之路:C语言学习计划

1、学习计划 学习基本语法和语言特性&#xff1a; 了解C语言的基本语法结构&#xff0c;如变量、数据类型、运算符等。学习控制流程语句&#xff0c;如条件语句、循环语句等。熟悉函数的定义和使用&#xff0c;包括参数传递和返回值。掌握C语言的输入输出操作&#xff0c;如pri…

力扣hot100:1.两数之和

输入中可能存在重复值 。 分析&#xff1a; 本题需要返回的是数组下标&#xff0c;因此如果需要使用排序然后双指针的话&#xff0c;需要用到哈希表&#xff0c;但是由于输入中可能存在重复值&#xff0c;因此哈希表的value值必须是vector<int>。 使用双指针求目标值targ…

lv20 QT事件5

1 事件模型 2 事件处理 virtual void keyPressEvent(QKeyEvent *event) virtual void keyReleaseEvent(QKeyEvent *event) virtual void mouseDoubleClickEvent(QMouseEvent *event) virtual void mouseMoveEvent(QMouseEvent *event) virtual void mousePressEvent(QMou…