归并排序 - 排序链表

LeetCode 排序链表(归并排序) 在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。 示例 1: 输入: 4->2->1->3 输出: 1->2->3->4 示例 2: 输入: -1->5->3->4->0 输出: -1->0->3->4->5 思路分析:由于题目特意要求 O(n log n) 时间复杂度和常数级空间复杂 阅读详情

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

要求:在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。

  1. 由于时间复杂度要在o(n log n)内 所以冒泡排序就不在选择范围内了 这里采用归并排序。
  2. 归并排序分为 迭代法 和 递归法 下面俩种方法的代码都将展示。
  3. 递归的核心思路就是:二分法
    从中间切割 然后左右俩边的一路按中切割到最小单位 然后排序返回
    举例 42507163
    42507163
    4250 7163
    42 50 71 63 切割到最小单位排序
    24 05 17 36 再合并排序
    0245 1376
    01234567
  4. 迭代法是在链表长度内进行切割
    先 2 2比较完后排序 再 4 4比较 再8 8…
    举例: 42507163
    先按42 50 71 63切割后排序得 24 05 17 36
    再按2405 1736切割后排序 得 0245 1367
    最后再按02451367比较排序 得 01234567
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode {
    int val;
    struct ListNode *next;
};

struct ListNode* FindLinkMid(struct ListNode* head) // 快慢指针法寻中点
{
    if (head == NULL) {
        return head;
    }

    struct ListNode* fast = head->next; // 快指针, 从第二个指针开始每次走俩步
    struct ListNode* slow = head;       // 慢指针, 从头开始每次走一步

    while (fast != NULL && fast->next != NULL) {
        fast = fast->next->next;
        slow = slow->next;
    }

    return slow;
}

struct ListNode* Merger(struct ListNode* left, struct ListNode* right) // 有序链表归并排序
{
    struct ListNode* head = (struct ListNode *)malloc(sizeof(struct ListNode));
    struct ListNode* temp = head;

    head->next = NULL;

    while (left != NULL && right != NULL) { //左右有序链表比较后, 较小值归入新建链表
    
        if (left->val <= right->val) {
            temp->next = left;
            left = left->next;
        } else {
            temp->next = right;
            right = right->next;
        }

        temp = temp->next;
    }

    if (left != NULL) { // 由于是有序, 可把剩余内容归入新链表
        temp->next = left;
    }

    if (right != NULL) { // 同上
        temp->next = right;
    }

    return head->next;
}


//递归的核心思路就是:二分法
//从中间切割 然后左右俩边的一路按中切割到最小单位 然后排序返回
//举例 42507163
//      42507163
//  4250        7163
//  42  50  71  63  切割到最小单位排序
//  24  05  17  36   再合并排序
//  0245 1376
//  01234567

struct ListNode* MergerSort_Recursion(struct ListNode* head) //归并排序-递归
{
    if (head == NULL || head->next == NULL) {//当链表被分割的只剩一个时 无需排序直接返回
        return head;
    }

    struct ListNode* mid = FindLinkMid(head); //找到中节点
    struct ListNode* next = mid->next; // 存储右边节点

    mid->next = NULL; // 把链表从中间分割开
    struct ListNode* left  = MergerSort_Recursion(head); // 左排序
    struct ListNode* right = MergerSort_Recursion(next); // 右排序 

    return Merger(left, right); // 合并
}

struct ListNode* Cut_List(struct ListNode* head, int cut) // 切割掉链表head 前cut个
{
    while (head!=NULL && --cut) {
        head = head->next;
    }

    if (head == NULL) {
        return NULL;
    }

    struct ListNode*temp = head->next;
    head->next = NULL;

    return temp;
}

// 迭代法是在链表长度内进行切割 
// 先 2 2比较完后排序 再 4 4比较 再8 8...
// 举例: 42507163
// 先按42 50 71 63切割后排序得 24 05 17 36
// 再按2405 1736切割后排序 得 0245 1367
// 最后再按02451367比较排序 得 01234567

struct ListNode* MergerSort_Iteration(struct ListNode* head) //归并排序-迭代
{
    if (head == NULL || head->next == NULL) {//当链表长度小于等于1 直接返回
        return head;
    }

    int len = 1;
    struct ListNode* temp = head;
    while(temp->next != NULL) { //计算链表长度
        len++;
        temp = temp->next;
    }
    
    struct ListNode* dummy = (struct ListNode *)malloc(sizeof(struct ListNode)); //排序后的链表头
    dummy->next = head;
    
    for (int cut = 1; cut < len; cut<<=1) {     //循环遍历链表 log2(len)次
        struct ListNode* curr = dummy->next;    // 当前链表头
        struct ListNode* tail = dummy;          // 临时链表 用于拼接排序合并后的链表
        while (curr != NULL) {                  //遍历当前链表
            struct ListNode* left = curr;
            struct ListNode* right = Cut_List(left, cut);   //把左边切割出去 获取右边首地址
            curr = Cut_List(right, cut);        //把右边切割出去 留下剩下未排序的链表下轮继续切割排序
            tail->next = Merger(left, right);   //合并排序
            while(tail->next != NULL) {         //尾插法 把合并排序后的链表插入新链表temp
                tail = tail->next;
            }
            
        }
    }

    return dummy->next;
    
}

链表排序——归并排序、快速排序 目录 1 归并排序 1.1 实现思路 1.2 代码实现 2 快速排序 2.1 实现思路 2.2 代码实现 1 归并排序 归并排序基本原理https://blog.csdn.net/qq_28114615/article/details/86345717 1.1 实现思路        与数组归并排序相同,主要分为以下三个步骤:       ①找到链表中点。最常用的方法是双指针... 阅读详情

相关推荐

C++链表实现归并排序

C++ 链表实现的归并排序 首先是定义和创建两个链表用来排序 typedef int ElemType; typedef struct LNode { ElemType data; struct LNode * next; }LinkNode; void CreateListF(LinkNode * &L, ElemType a[], int n) { LinkNode...

看起来喜欢做枯燥事情的人或许只是更清楚自己想要什么罢了 733

归并排序及其优化(数组归并/链表归并,自顶向下/自底向上等)

  归并排序时一种使用分治思想实现的高效的排序算法,它的最好/最坏/平均时间复杂度都是O(nlogn),而且是一种稳定的排序算法。然而归并排序并没有得到广泛的应用,今天我们来看看归并排序的特点、优化和应用。 1. 算法简介 归并排序的原理   归并排序(Merge Sort)的核心思想就是一个典型的分治算法。如果要排序一个数组,我们先把数组从中间分成前后两部分,然后对前后两部分分别排序,再将排好序的两部分合并在一起,这样整个数组就都有序了。算法示意图如下:   代码实现如下: class Solution

bitkevin的博客 2167

单向链表排序-归并排序

链表排序中使用归并排序:归并排序不仅保持了它的 O( nlog(n) ) 的时间复杂度,而且它在数组排序中广受诟病的空间复杂度,在链表排序中从 O(n) 降低到 O( log(n) )。    对于单向链表的二路归并排序,首先是要找到链表的中间节点,将链表等分。我们可以使用快慢指针的方式找到链表的中间节点,即一个指针以一个步长移动,另一个指针使用两个步长移动,当快指针到结尾位置时,慢指针正好在中

luckyone的专栏 1507

归并排序链表的实现——学习笔记

归并排序是效率非常高的一种排序方式,和快速排序一样用了分治的思想。分治法的精髓在于将一个复杂问题分割成为多个简单的子问题,然后将子问题逐个解决,最终合并在一起以后就是复杂问题的解了。 这篇文章主要讲归并排序链表的实现方式,如果想了解数组的归并排序,可移步这里。 归并排序的思想其实挺简单的,简而言之就是将数列分割成子序列,先对子序列进行排序,再将排好序的子序列合并成一个完整的数列。具体例子...

jjwwwww的博客 5802

保姆级教程:用NX机电概念设计与RobotStudio实现ModbusTCP联合仿真(附完整代码)

本文提供了一份详细的NX机电概念设计与RobotStudio联合仿真实战教程。通过ModbusTCP协议构建数据桥梁,实现机械行为与机器人控制逻辑的双向实时同步。文章从环境搭建、信号配置、RAPID代码编写到联合调试,逐步拆解了实现数字孪生核心链路的关键步骤,并分享了常见问题排查方法,助力工程师在虚拟环境中提前验证产线协同。

sat99的博客 1087

IEEE PHM 2012轴承数据实战:用LSTM预测剩余寿命的完整流程与调参心得

本文详细解析了如何利用IEEE PHM 2012轴承数据集和LSTM模型进行轴承剩余寿命预测。从数据预处理、特征工程到LSTM模型架构设计和调参技巧,提供了完整的实战流程。特别分享了FEMTO-ST数据集的处理方法、RUL标签构建策略以及提升预测精度的关键技巧,帮助工程师实现更准确的预测性维护。

weixin_31100517的博客 360

LeetCode 148. 排序链表(归并排序、快速排序)

1. 题目 在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。 示例 1: 输入: 4->2->1->3 输出: 1->2->3->4 示例 2: 输入: -1->5->3->4->0 输出: -1->0->3->4->5 来源:力扣(LeetCode) 链接:https://leet...

Michael是个半路程序员 1469

HUMAnN 3.0 (alpha)安装及使用

文章目录简介安装数据库下载运行参考 简介 安装 conda install humann humann_test (~1 minute) 数据库下载 humann_databases --download chocophlan full /path/to/databases --update-config yes humann_databases --download uniref uniref90_diamond /path/to/databases --update-config yes humann_

dys的博客 9491

对链表进行归并排序

题干:对一个链表进行归并排序。 对于数组,归并排序的思想是先将数据分成两部份,分别排序。然后再对已经排好序的两个数组归并。其中在对两部份数组排序时进行递归,最后得到的即是排好序的数组。 对于链表,归并的思想也是如此。需要解决的问题有两个,第一个是如何将链表平均分成两部份。 第二个是将两个有序链表合并成一个有序链表。 解决了这两个问题,归并排序链表就迎仞而解了。 对于第一个问题,可以采用快慢指针的方...

wh义华的专栏 1522

基于Transformer的CFD代理模型:AeroTransformer原理、实现与优化

计算流体动力学(CFD)仿真是航空航天、汽车工程等领域的关键技术,但其高计算成本限制了设计优化效率。代理模型通过机器学习方法学习输入参数与流场输出间的映射关系,能实现秒级预测,大幅加速仿真流程。Transformer架构凭借其全局注意力机制,能有效建模流场中的长程物理关联,克服了传统卷积神经网络在捕捉全局依赖上的局限。通过预训练与微调策略,模型能先在大规模多样化数据集上学习通用流体规律,再针对特定任务快速适配,显著提升了小样本下的泛化能力与工程实用价值。AeroTransformer项目正是这一技术路线的典

weixin_33509203的博客 353

WRF和WPS安装和编译时遇到的问题

检查是否自己netcdf和Fortran编译器一致。解决办法:修改configure.wps里的路径。如果没问题且wrf已成功编译,考虑重新。path修改为jasper在的路径。

m0_54898744的博客 1834

链表的归并排序

链表的归并排序是一种高效、稳定的排序算法,非常适合链表这种数据结构。通过分治思想,将链表不断分割并合并,实现了对链表的排序。

2401_86909484的博客 1171

TP4056锂电池充电电路设计原理与工程实践

锂离子电池充电管理是嵌入式电源系统的核心基础技术,其本质是通过恒流恒压(CC/CV)控制策略,匹配电池电化学特性以实现安全、高效、长寿命充放电。TP4056作为典型线性充电IC,以精简外围实现预充、恒流、恒压及自动截止全周期管理,但受限于线性拓扑的热耗散特性,必须协同散热设计、电阻精度选型与PCB布局进行系统级优化。该方案广泛应用于STM32智能小车、便携传感器节点等3.7V单节锂电供电场景,兼顾成本、可靠性与工程可实施性,是入门嵌入式硬件电源设计的关键实践范例。

weixin_36064575的博客 216

链表的归并排序与链表数组的归并排序

链表的归并排序 就是排序找中点,然后中点位置后一个为null,切断链表,也就是分而治之每次分割一半,一直往后分割,直到只剩下一个节点,或者没有节点停止。 public class ListNode{ int val; ListNode next; public ListNode(int x){ this.val = x; ...

AaronCao 341

Vulkan入门系列0- Vulkan与OpenGL的区别

虽然Vulkan和OpenGL都是对GPU的抽象,都能达到相同的功能,但它们的设计理念不同,可以说设计差异是非常之大,由于OpenGL从1992年到现在,已经有30多年的历史,GPU功能日新月异,与当年不可同日而语,在OpenGL保持向下兼容情况下,还要在OpenGL基础上设计一套编程接口显然是不可能的,所以推出了新编程规范Vulkan。另外在一些无窗口的应用中,Vulkan可以有选择的不创建帧缓冲区,比如在数学运算,物理模拟,处理视频流的应用中并不需要窗口,所以Vulkan支持更灵活的应用场景。

GPU全栈博主 4060

重复点击提交、产生多笔数据、保持数据只操作一次---->接口幂等性校验

幂等校验一、工作真实场景 + 常出现场景二、工作解决方案 + 百度解决方案 一、工作真实场景 + 常出现场景 真实场景:在一次工作中进行成品出库创建成品出库单时,手抖了一下,重复点击了两次确定(提交表单)。结果很神奇的发现居然产生了两笔一模一样的数据(流水号都一样),当时就很懵逼,稍作思考,想想应该是在同一时刻创建了两个出库单。感觉很有意思(因为之前没有遇到过,写代码的时候也没有考虑到这个问题的发生),后面换了一种方式复现场景:提交表单时多次点击Enter按钮,还是会产生多笔重复数据。 常见场景: 订单接

私聊前往站内信:https://i.csdn.net/#/msg/chat/weixin_44976692 6万+

单链表归并排序

单链表归并排序需要掌握的知识点。 1.归并排序的思想 2.如何合并两个有序的单链表 3.如何找到一个链表的中间节点,这里是为了断链。将链表一分为二。 (1)合并两个有序的链表,主要有两种思路。递归和迭代 递归方法的代码: struct node { int val; node *next; }; //注意此时链表a和链表b均为递增有序的单链表 node *merge(node *a, node...

乐行僧的博客 1271

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

链表的快排和归并排序

链表快排 对一个单链表用快排的方式排序 快排的关键在于partition函数,因为单链表是不能倒序遍历的,因此不能通过头尾双指针向内夹的partition函数,而是用都是从头开始的双指针方式,具体的两种partition函数可以参考:快排的两种partition函数 这里链表快排和数组快排partition函数中关键的不同点在于:partition函数中遍历结束的方式,和递归结束的方式 # 链表快...

海晨威 1176

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

C++链表的归并排序

void sort(node* plst,int low,iny high,int *parray)//low与high是闭区间[low,high]{ if(low { int mid=(low+high)/2;//取出数组的中间值 sort(plst,low,mid,parray);//递归调用左半边链表进行排序 sort(plst,mid+1,high,parray);//递归调用右半边

安子健的专栏 1584

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

C++链表归并排序

说在前面: 你需要先会写数组的归并排序。 除此之外,你还要对递归的过程有很清晰的认识。 你需要会用熟练的使用指针,这是C++玩家必备技能。 代码里的List,可能命名成Node更加合适,我也不知道我当时这么想的,命了个这鼠名字,看着挺别扭的。 掌握归并排序的核心思想就行了,将大区间分解成两个小区间之后呢,双指针,把小的数值一个一个的压入新的容器(这里自然是指链表了)里面,等待两个子区间其中有一个全部压入了之后,把另外一个区间剩余的全部压入,返回。这就完成归并的基本逻辑

Hayakawa123的博客 2465

排序链表 归并排序

给你链表的头结点head,请将其按升序排列并返回排序后的链表。 示例 1: 输入:head = [4,2,1,3]输出:[1,2,3,4] 示例 2: 输入:head = [-1,5,3,4,0]输出:[-1,0,3,4,5] 示例 3: 输入:head = []输出:[] 思路: 这个题乍一看是将链表进行排序。以前好像从来没有接触过如何排序链表,可以用像排序普通数组那样的排序方法来排序吗?是可以的。 这里我们可以使用归并排序的思路来解决。归...

TranSad的博客 352

链表归并排序

#include using namespace std; /** * 对链表进行原地排序 * 回忆数组归并最重要的就是:找到数组中点,以及归并两个有序数组。 * 类似地这里有两个关键点: * (1)找到链表的中间节点,用一快一慢两个指针往前走; * (2)归并两个已经排好序的链表,指向归并结果的指针总是变化的,所以需要返回一个指向归并好的链表的头指针; * (3)最后注意,将

jiq•钦's technical Blog 1070

对链表进行排序(归并排序)

归并排序(算法交换链表节点,时间复杂度O(nlogn),不考虑递归栈空间的话空间复杂度是O(1))                        本文地址 首先用快慢指针的方法找到链表中间节点,然后递归的对两个子链表排序,把两个排好序的子链表合并成一条有序的链表。归并排序应该算是链表排序最佳的选择了,保证了最好和最坏时间复杂度都是nlogn,而且它在数组排序中广受诟病的空间复杂度在链表排序中

iamxiaoguizi的博客 1148
上一篇: MFI认证
下一篇: 15765-2 协议解读
四夕、
博客等级 码龄8年 19粉丝 39原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值