归并排序详解

简介: 归并排序详解

 



归并排序

基本思想

归并思想:

将两个有序数组归并到一起,使其有序;

两个数组中取小尾插到新数组;

归并排序的基本思想:

1.一组数据想要有序,可以先使其左半部分有序,右半部分有序,再利用归并的思想使其整体有序;

2.在将左边的数据变为有序时,又可以分为两部分,先使其左边有序,右边有序,再利用归并想使其整体有序;

3.利用上述思想,将待排数据分为两部分,直到分到每组数据只有一个时,再边排序边返回;

4.这里归并时,需要用到另一个数组,将原数组的数据归并到该数组使其有序,再将数据拷贝回原数组;

图解

代码实现(代码中含分析)

递归实现:

void _MergeSort(int* a, int* tmp ,int begin, int end)
{
  if (begin >= end)
    return;
  int mid = (begin + end) / 2;
    //[begin,mid][mid+1,end]
  _MergeSort(a, tmp, begin, mid);
  _MergeSort(a, tmp, mid+1,end);
  //递归到tmp数组
  //[begin1,end1][begin2,end2]
  int begin1 = begin, end1 = mid;
  int begin2 = mid+1, end2 = end;
  int i = begin;
  while (begin1<=end1 && begin2<=end2)
  {
        //取小的尾插到tmp数组
    if (a[begin1] <= a[begin2])
      tmp[i++] = a[begin1++];
    else
      tmp[i++] = a[begin2++];
  }
    //退出循环,有一个区间的元素还未取完
    //因为两区间的数据都在本区间已经有序,所以剩余数据直接插入
  while (begin2 <= end2)
  {
    tmp[i++] = a[begin2++];
  }
  while (begin1 <= end1)
  {
    tmp[i++] = a[begin1++];
  }
    //递归完一次后将tmp中数据拷贝回原数组
    //注意拷贝回去时,注意拷贝回原位置
  memcpy(a+begin, tmp+begin, sizeof(int)*(end-begin+1));
}
void  MergeSort(int* a ,int begin, int end)
{
    //开辟一个与待排数组同大小的tmp数组,用于归并
  int* tmp = (int* )malloc(sizeof(int) * (end - begin + 1));
  if (tmp == NULL)
  {
    perror("malloc fail");
    return;
  }
  _MergeSort(a,tmp, begin, end);
   
  free(tmp);
}

 

非递归实现:

void  MergeSortNonR(int* a, int n)
{
  int* tmp = (int*)malloc(sizeof(int) * n);
  if (tmp == NULL)
  {
    perror("malloc fail");
    return;
  }
    //gap等于几就是几个和几个进行归并,不一定是均分
  int gap = 1;
  while (gap < n)
  {
        //用i控制区间边界,i+=2*gap时,就进行同层的后组归并
    for (int i = 0; i <n; i += 2*gap)
    {
      int begin1 = i, end1 = i + gap-1;
      int begin2 = i + gap, end2 =i + 2*gap-1;
            //越界处理,如果end1越界,或则begin2越界,那么第二个区间不存在,就不需要归并
      if (end1 > n || begin2 >= n)
      {
        return;
      }
            //如果只是end2越界了,只需要修改边界
      if (end2 > n)
      {
        end2 = n-1;
      }
            //tmp数组的下标
            //开始归并
      int cur = i;
      while (begin1 <= end1 && begin2 <= end2)
      {
        if (a[begin1] < a[begin2])
          tmp[cur++] = a[begin1++];
        else
          tmp[cur++] = a[begin2++];
      }
      while (begin2 <= end2)
      {
        tmp[cur++] = a[begin2++];
      }
      while (begin1 <= end1)
      {
        tmp[cur++] = a[begin1++];
      }
            //拷贝回原数组
      memcpy(a + i, tmp + i, sizeof(int)*(end2-i+1));
    }
        //一一归完两两归,两两归完四四归……
    gap *= 2;
  }
  free(tmp);
}

性能分析

时间复杂度:O(N*logN)

空间复杂度:O(N)

稳定性:稳定


 

目录
相关文章
|
13天前
|
存储 人工智能 负载均衡
阿里云OpenClaw多Agent实战宝典:从极速部署到AI团队搭建,一个人=一支高效军团
在AI自动化时代,单一Agent的“全能模式”早已无法满足复杂任务需求——记忆臃肿导致响应迟缓、上下文污染引发逻辑冲突、无关信息加载造成Token浪费,这些痛点让OpenClaw的潜力大打折扣。而多Agent架构的出现,彻底改变了这一现状:通过“单Gateway+多分身”模式,让一个Bot在不同场景下切换独立“大脑”,如同组建一支分工明确的AI团队,实现创意、写作、编码、数据分析等任务的高效协同。
6177 31
|
前端开发 API Python
使用 tkintertools 模块显示简单的 3D 效果
如何使用 Python 快速又简单地显示 3D 效果呢?使用 tkintertools 模块,轻松地做到这一点!(本文适用于 tkintertools-v2.6.6)
885 1
|
15天前
|
人工智能 自然语言处理 监控
2026年零基础部署OpenClaw(Clawdbot)教程及OpenClaw必装Skill+实战案例分享
2026年初,一款名为OpenClaw(原Clawdbot、Moltbot)的AI工具以现象级速度席卷全球科技圈,凭借72小时狂揽60000+GitHub Stars的成绩,如今星标数已突破180000+,不仅让Mac Mini全球卖断货,更带动Cloudflare股价上涨20%。这款被网友亲切称为Molty“小龙虾”的工具,并非普通的聊天机器人,而是真正“长了手的AI助理”——它能通过Telegram、飞书等10+渠道主动执行任务,从网站重建、买车砍价到深夜Bug修复,真正实现“聊天框里办大事”。
723 3
|
存储 算法 调度
操作系统实验二-虚拟存储器/内存管理(一)
操作系统实验二-虚拟存储器/内存管理
1167 0
操作系统实验二-虚拟存储器/内存管理(一)
|
Java Maven
idea引入外部maven项目(非压缩)方式
idea引入外部maven项目(非压缩)方式
379 0
|
安全 关系型数据库 MySQL
CentOS8 安装 MySQL8.0(RPM)
环境:Linux centos8 4.18.0-80.el8.x86_64、Mysql8.0.18
9058 0
|
14天前
|
人工智能 运维 自然语言处理
OpenClaw是什么?OpenClaw能做什么?OpenClaw详细介绍及保姆级部署教程
在AI自动化办公全面落地的2026年,一款名为OpenClaw的低门槛AI自动化代理工具迅速崛起,成为个人与轻量团队的效率利器。其前身为Clawdbot、Moltbot,经过版本迭代与品牌整合后,2026年正式统一为“OpenClaw”,核心定位是通过自然语言指令替代人工完成流程化、重复性工作,无需编程技能即可适配多场景自动化需求。作为GitHub上星标量超18.6万的开源项目,OpenClaw以“能动手做事的AI助手”为核心理念,打破了传统AI工具“只说不做”的局限,构建起“需求解析-任务规划-工具调用-结果反馈”的完整闭环系统,为办公协同、开发辅助等场景带来革命性效率提升。
3172 12
|
11月前
|
存储 算法 数据可视化
【二叉树遍历入门:从中序遍历到层序与右视图】【LeetCode 热题100】94:二叉树的中序遍历、102:二叉树的层序遍历、199:二叉树的右视图(详细解析)(Go语言版)
本文详细解析了二叉树的三种经典遍历方式:中序遍历(94题)、层序遍历(102题)和右视图(199题)。通过递归与迭代实现中序遍历,深入理解深度优先搜索(DFS);借助队列完成层序遍历和右视图,掌握广度优先搜索(BFS)。文章对比DFS与BFS的思维方式,总结不同遍历的应用场景,为后续构造树结构奠定基础。
517 10
|
Kubernetes Cloud Native 云计算
云原生入门:从Docker到Kubernetes的旅程
【10月更文挑战第2天】本文将带你走进云原生的世界,从基础的Docker容器技术开始,逐步深入到Kubernetes集群管理。我们将通过实际代码示例,探索如何利用这些工具构建、部署和管理现代云应用。无论你是初学者还是有经验的开发者,这篇文章都将为你提供宝贵的知识和技能,让你在云原生领域迈出坚实的一步。
379 5
|
C语言
【C语言基础考研向】05 scanf读取标准输入超详解
本文详细解析了C语言中`scanf`函数的工作原理及常见问题。首先介绍了`scanf`如何处理标准输入,并通过示例说明了为何有时会出现阻塞现象及其解决办法。接着探讨了当输入包含多种数据类型时,特别是字符型数据的处理方式,强调了格式控制的重要性,并给出了正确的输入格式示例。通过正确配置,可以避免因空格和换行符导致的问题,确保数据准确读取。
732 10