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

链表实现排序(归并排序/快速排序) 一分为二时使用快慢指针找到中点区分。目的是使得左边的值都小于pivot,右边的值都不小于pivot 所以用一个索引记录左边的坐标,遍历过程中,每次碰到比pivot小的,都要交换一下,放到左边。题解1:https://leetcode.cn/problems/sort-list/solutions/9318/gui-bing-pai-xu-he-kuai-su-pai-xu-by-a380922457/自底向上的归并排序,先两个两个的 merge,完成一趟后,再 4 个4个的 merge,直到结束。 阅读详情

归并排序是效率非常高的一种排序方式,和快速排序一样用了分治的思想。分治法的精髓在于将一个复杂问题分割成为多个简单的子问题,然后将子问题逐个解决,最终合并在一起以后就是复杂问题的解了。

 

这篇文章主要讲归并排序链表的实现方式,如果想了解数组的归并排序,可移步这里。

归并排序的思想其实挺简单的,简而言之就是将数列分割成子序列,先对子序列进行排序,再将排好序的子序列合并成一个完整的数列。具体例子如下:

                       [3   7   6   4   8   9   2   1] 
                           /                  \
分割                 [3  7  6  4]          [8  9  2  1]
                     /          \          /        \
分割              [3   7]   [6   4]      [8   9]   [2   1]
                 /     \    /     \     /     \   /     \
分割            [3]    [7] [6]    [4]  [8]    [9] [2]    [1]
                 \     /   \     /     \     /    \     /
合并              [3   7]   [4   6]      [8   9]   [1   2]
                     \        /             \        /
合并                 [3  4  6  7]          [1  2  8  9]
                          \                     /
合并                   [1   2   3   4   6   7   8   9]

分割时从数列中间开始,将数列分成两部分,然后对分割后的序列继续进行分割直到分割不能再分为止。然后对已经排好序的子序列进行合并,重新产生一个排序好的数列。

 

用链表进行归并排序和数组排序略有不同,但是思想还是一样的。唯一的难点在于如何找到链表的中间点,这里就要运用到了一个额外的技巧——快慢指针。快慢指针常常用于判断链表中是否有环,简单来说就是有两个指针,快指针每次走两个节点,慢指针每次走一个节点,当快指针走到链表尽头时,慢指针才走到了链表的一半,此时就是我们想要的中间节点。

看代码:

//链表结构单位
struct Node{
    int val;
    Node* next;
};

//node -- 链表表头
Node* MergeSort(Node* node){
    //先判断链表长度是否大于1,小于1时无须排序
    if(node!=NULL&&node->next!=NULL){
        //运用快慢指针,找到链表的中间节点
        Node *fast=node->next;
        Node *slow=node;
        while(fast!=NULL&&fast->next!=NULL){
            fast=fast->next->next;
            slow=slow->next;
        }

        //将链表分成两部分进行分割
        Node *p1=MergeSort(slow->next);
        slow->next=NULL;                 //这儿很重要,仔细想想为什么
        Node *p2=MergeSort(node);

        //对两条子链进行归并
        Node *p0=(Node *)malloc(sizeof(Node));
        Node *p=p0;
        while(p1!=NULL&&p2!=NULL){
            if(p1->val<p2->val){
                p->next=p1;
                p1=p1->next;
            }else{
                p->next=p2;
                p2=p2->next;
            }
            p=p->next;
        }

        if(p1!=NULL){
            p->next=p1;
        }

        if(p2!=NULL){
            p->next=p2;
        }

        p=p0->next;
        free(p0);
        return p;
    }

    return node;
}

增加个C++版本的完整实现:

#include <iostream>

using namespace std;

//链表结构体
struct List{
    int val;
    List * next;
    
    List(int value = 0):
    val(value),
    next(nullptr)
    {
    }
};

//创建链表
List * createList(int length){
    List *root = new List(rand()%100);
    List *node = root;
    for(int i=0;i<length;++i){
        node->next = new List(rand()%100);
        node = node->next;
    }
    return root;
}

//打印链表
void printList(List * root){
    while(root!=nullptr){
        cout<<root->val<<" ";
        root = root->next;
    }
    cout<<endl;
}

//删除链表
void deletList(List * root){
    List * temp;
    while(root!=nullptr){
        temp = root->next;
        delete root;
        root = temp;
    }
}

//合并链表
List * merge(List * left,List * right){
    if(left == nullptr)
        return right;
    
    if(right == nullptr)
        return left;
    
    if(left->val < right->val){
        left->next = merge(left->next,right);
        return left;
    }else{
        right->next = merge(left,right->next);
        return right;
    }
}

//归并排序
List * mergeSort(List * root){
    //空链表或者长度为1的链表直接返回
    if(root == nullptr || root->next == nullptr)
        return root;
    
    //快慢指针寻找链表中间节点
    List *fast = root->next;
    List *slow = root;
    while(fast!=nullptr&&fast->next!=nullptr){
        slow = slow->next;
        fast = fast->next->next;
    }
    
    //将链表分成左右两段,分别进行归并排序
    List * right = mergeSort(slow->next);
    slow->next = nullptr;
    List * left = mergeSort(root);
    
    //合并左右链表
    return merge(left, right);
}

int main(){
    srand((unsigned)time(0));
    
    List * root = createList(10);
    
    printList(root);
    root = mergeSort(root);
    printList(root);
    
    deletList(root);
    return 0;
}

 

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

相关推荐

排序链表,用归并才够味!深入链表归并排序的原理与实现

摘要: 链表排序因非连续存储特性,传统排序算法效率较低。归并排序凭借分治策略与链表结构的天然契合,成为最优解——无需随机访问,仅需指针操作即可实现O(n log n)时间复杂度。核心步骤:快慢指针分割链表、递归排序子链表、合并有序链表。注意彻底断链和合并剩余节点,避免死循环。算法选择需结合数据结构特性,链表归并排序体现了“结构+算法”的深度配合,是面试中考察综合能力的经典题型。实际实现时需警惕指针操作陷阱,递归版本可能需优化为迭代以防栈溢出。

Echo_Wish 7769

链表的归并排序

链表的归并 主要有2种方法。 自顶向下的递归法 自底向上的非递归法 在讨论具体的归并排序前,必须清楚以下几个问题! 如何找到链表中点? ----------------------------->快慢指针法. public Link find_Mid(Link head) { Link fast = head; Link slow = he...

weixin_39657557的博客 1546

CyberChef本地搭建

CyberChef本地搭建

2301_80241182的博客 6017

九种排序算法

一:插入排序①直接插入排序//以从小到大排序为例 void InsertSort(int a[],int len) { int i; for(i=1;i<len;i++) { if(a[i]<a[i-1]) { int temp=a[i];//哨兵,保存将要插入的值 int j;

Gloria971111的博客 3603

Eureka自我保护机制

Eureka自我保护机制 默认情况下,当eureka server在一定时间内没有收到实例的心跳,便会把该实例从注册表中删除(默认是90秒),但是,如果短时间内丢失大量的实例心跳,便会触发eureka server的自我保护机制,比如在开发测试时,需要频繁地重启微服务实例,但是我们很少会把eureka server一起重启(因为在开发过程中不会修改eureka注册中心),当一分钟内收到的心跳数大量减少时,会触发该保护机制。可以在eureka管理界面看到Renews threshold和Renews(last

Soul_Ming的博客 537

ArcGIS插值可视化气象数据

前言 地图底图的制作和气象数据的预处理见我上两篇博客 ArcGIS精美中国地图制作(详解) python处理日值气象数据 在前面我们已经将日值的地温数据处理成了年均地温,添加了站点经纬度坐标并导出为excel格式。 得到如下数据: 导入数据 在Arcmap中 文件-添加XY数据 将年均地温和站点位置数据导入。 注意:excel表格的格式要另存为97-2003工作簿形式,否则会有"arcgi...

江北20190411的博客 2万+

用归并排序对链表进行排序

http://blog.csdn.net/lalor/article/details/7430624 当我们需要对链表进行排序时,由于不能对它的元素进行随机访问,所以更适合使用归并排序,大名鼎鼎的快速排序用到链表上,效率也很低,原因还是在于不能对链表中的元素进行随机访问,同理,采用堆排序更是不可能的事情。         算法具体实现时需要一个指向头节点(链表的第一个节点,链表中不包含额外

f81892461的专栏 956

UWB 多传感器通信的纳秒无线位置和时钟同步方法

利用UWB高精度的特点,实现多节点下的无线时钟同步和定位。通过优化硬件架构,减少不确定延迟的影响,系统可以提供纳秒级时钟同步消息

DT程序员的博客 1316

归并排序的链表实现

利用归并法可以对链表进行排序,而且不需要占用额外空间.对于一个无序链表,先利用循环找到链表的中值,再利用递归先将一个链表分成两个链表,逐步递归,递归停止的条件是链表中只有一个元素或是没有元素的情况,然后完成链表的有序. #include &lt;cstdio&gt; #include &lt;cstdlib&gt; #include &lt;algorithm&gt; #include &lt...

weixin_42480264的博客 2300

SolidWorks软件二次开发:使用C#进行SolidWorks二次开发

SolidWorks 提供的 API(应用程序编程接口)允许开发者使用多种编程语言(如 C#、VB.NET 等)来控制和扩展 SolidWorks 的功能。API 架构基于 COM(组件对象模型),这意味着开发者可以通过引用 SolidWorks 的类型库来访问其对象模型。SolidWorks 的对象模型包括了从文档、零件、装配体到特征、草图等所有 SolidWorks 中可操作的对象。

kkchenjj的博客 3208

【PINN物理信息网络】基于PINN物理信息网络求解泊松方程(python)

【PINN物理信息网络】基于PINN物理信息网络求解泊松方程(python)

k8291121的博客 2807

手把手教你实现链表的归并排序

参考资料:《数据结构与算法分析》(第三版英文版) 书本题目:7.20 (269页) 这个题目的意思很简单,就是实现链表的归并排序 先实现一个简单的节点Node结构 struct Node { int data; Node* next; Node(int val) { data = val; next = NULL; } Node() { data =

Crophone 8371

【工业级视觉实战】海康威视SDK + Python + YOLOv11:零延迟目标追踪系统落地指南

要在 Python 中调用海康 DLL,首先得把 C++ 的结构体 1:1 翻译过来。这是很多开发者踩坑最深的地方(指针错误、内存溢出)。import sys# 根据操作系统加载库else:# 定义设备信息结构体 (对应 C++ LPNET_DVR_DEVICEINFO_V30)("sSerialNumber", ctypes.c_byte * 48), # 序列号("byAlarmInPortNum", ctypes.c_byte), # 报警输入个数。

BUG猿的博客 217

基于链表结构实现二路归并排序详解(C++实现)

基于链表的二路归并排序和基于数组的二路归并排序的总体实现思想是一样的,同样是基于分治法。在递归算法结构下体现的是切分(相对比较常见的切分方法是对半切分),到分无可分时,切分函数调用逐个退栈继而进行合并函数调用,在进行合并的过程中进行一个类似于选择排序算法的思想实现。 其中在基于链表实现的算法下进行对半切分时,涉及到一个链表对切中点的寻找过程,在此采用两个不同的跳跃步长以寻找链表中间节点。代码如: ...

破晓的成长之路 2515

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

对链表进行归并排序

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

wh义华的专栏 1522

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

java中实现归并排序与链表的使用

【代码】java中实现归并排序。

nbbzi的博客 987

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

单链表归并排序

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

乐行僧的博客 1272

对单链表的归并排序的C++实现

前言 记录用C++实现基于单链表的归并排序 代码 一共三个文件SingleLinkedList.h, CNode.h以及main.cpp。 首先是CNode.h #ifndef _NODE_H__ #define _NODE_H__ class CNode{ private: int data; CNode *nextNode; public: CNode(); void setData...

Hikers、Wan的博客 892

用归并排序实现单链表的排序

今天做了百度的一套数据挖掘的笔试题,其中有一道对单链表进行归并排序,因为刚学归并排序的时候是针对数组来说,所以这道题着实费了一点心思。 考点:1归并算法2单双步求中点3链表指针的操作,以及边界空指针问题4内存分配与回收; 单链表与数组相比只能顺序访问每个元素,因此在使用二路归并排序时关键在于找到链表的中间结点将链表一分为二:可以利用快慢指针同时遍历单链表,当步长为2的指针 指向链表最后一个结

木东的博客 2021

排序链表(归并排序递归实现)

题目 给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。 示例 : 输入:head = [4,2,1,3] 输出:[1,2,3,4] 提示: 1、链表中节点的数目在范围 [0, 5 * 104] 内; 2、-105 <= Node.val <= 105。 注意点 1、归并排序其实就是使用分治(将问题分(divide)成一些小的问题然后递归求解)的思想来实现排序的,其主要的操作就是将两个已经有序的序列进行合并成一个有序的链表; 2、使用分治思想,所以需要寻找中间节点,链表

weixin_43857345的博客 1150

链表实现归并排序

通过链表实现归并排序 #include <iostream> using namespace std; struct ListNode{ int val; ListNode* next; ListNode(int x):val(x),next(NULL){ } }; ListNode* merge(ListNode *li...

atfa5720的博客 221

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

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

AaronCao 341

归并排序的实现(C语言链表)

/** * 名称: 归并算法的实现 * 作者: mz21g * 日期: 2019.8.29 * */ #include <stdio.h> #include <stdlib.h> typedef struct CELL *LIST; struct CELL{ int element; LIST next; }; LIST merge(LIST ...

MZ21G的博客 1672
上一篇: Java中实现正态随机分布
下一篇: C语言各类数值交换函数优缺点分析——学习笔记
jjwwwww
博客等级 码龄12年 251粉丝 65原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值