【数据结构】—超级详细的归并排序(含C语言实现)

简介: 【数据结构】—超级详细的归并排序(含C语言实现)

♉️一、前置知识—什么是归并排序

    归并排序是一种基于分治思想的排序算法。它将待排序的数组分成两个子数组,对每个子数组进行排序,最后将子数组合并成一个有序的数组。具体来说,归并排序采用递归的方式将数组不断二分,直到每个子数组只有一个元素,然后再将相邻的两个子数组归并成一个有序的数组,然后不断合并,直到最终得到原数组的有序排列当然你也可以采用非递归的方法,总体的思路都是一样的与快速排序不同的是,归并排序在每轮排序中都会将数组完全拆分成两个子数组。


♊️二、归并排序

       归并排序的思想

      归并排序是基于分治思想的一种排序算法,它可以将一个大问题分解成若干个小问题,再通过合并小问题的解来得到大问题的解。

      具体来说,归并排序的思想如下:

 1.将待排序的数组划分为两个子数组,对每个子数组进行递归排序;

 2.将排好序的子数组合并成一个有序的数组。

      这一过程可以不断重复,直到将整个数组划分为单个元素的子数组,然后再将其合并成一个有序数组,排序完成。

 一图理解~

1.png动图了解~

2.gif 

       归并排序的递归实现

     归并排序的递归实现步骤如下:

1.如果数组长度为1,直接返回该数组;

2.将数组按中间位置划分成两个子数组,分别对这两个子数组进行递归排序,得到排好序的两个子数组;

3.将排好序的两个子数组合并成一个有序数组,具体方法为创建一个辅助数组,同时遍历两个子数组,比较两个子数组中当前位置的元素,将较小的元素放入辅助数组中;

4.将辅助数组中的元素复制回原数组中。

代码实现:

void _Mergesort(int* a, int* temp,int begin, int end)
{
  if (end <= begin)//递归结束条件
    return;
  int mid = (begin + end) / 2;//开始二分
  _Mergesort(a, temp, begin, mid);//左半边
  _Mergesort(a, temp, mid + 1, end);//右半边
  //正式的归并操作
  //分出来的两个数组的下标
  int begin1 = begin;
  int end1 = mid;
  int begin2 = mid + 1;
  int end2 = end;
  int index = begin;
  while(begin1 <= end1 && begin2 <= end2)//归并
  {
    if (a[begin1] < a[begin2])
    {
      temp[index++] = a[begin1++];
    }
    else
    {
      temp[index++] = a[begin2++];
    }
  }
  //当其中有一个条件不符合时,跳出循环,但是可能还有数据每遍历完
  while (begin1 <= end1)
  {
    temp[index++] = a[begin1++];
  }
  while (begin2 <= end2)
  {
    temp[index++] = a[begin2++];
  }
  // 拷贝回原数组
  memcpy(a + begin, temp + begin, (end - begin + 1) * sizeof(int));//拷贝对应的数据到对应的位置
}
void Mergesort(int* a, int n)
{
  int* temp = (int*)malloc(sizeof(int) * n);
  if (temp == NULL)
  {
    perror("malloc fail");
    return;
  }
  _Mergesort(a, temp,0,n-1);
  free(temp);
}

♒️归并排序的非递归实现(难点)

      归并排序的非递归实现,也称为迭代实现,采用的是自底向上的方式,

       步骤如下:

      1.将原数组按照长度为1的子数组进行划分,每个子数组都是有序的;

      2.将长度为1的有序子数组两两合并,得到长度为2的有序子数组;

      3.重复以上步骤,直到得到一个完整有序的数组。

      代码实现:

void MergesortNonR(int* a, int n)
{
  int* temp = (int*)malloc(sizeof(int) * n);
  if (temp == NULL)
  {
    perror("malloc fail");
    return;
  }
  //设置一个gap用于从间距为1开始(也就是最开始的归并),对于数组进行归并操作,然后归并完一遍后让gap*2继续归并,以此类推
  int gap = 1;
  while (gap < n)//gap停止的条件,实际上gap在n的一半时就已经排好了
  {
    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;
      //以下是处理越界的情况,有些时候当数组会越界
      // 如果第二组不存在,这一组不用归并了
      if (begin2 >= n)
      {
        break;
      }
      // 如果第二组的右边界越界,修正一下
      if (end2 >= n)
      {
        end2 = n - 1;
      }
      //以下的操作就是和递归的操作相同的归并操作
      int index = i;
      while (begin1 <= end1 && begin2 <= end2)
      {
        if (a[begin1] < a[begin2])
        {
          temp[index++] = a[begin1++];
        }
        else
        {
          temp[index++] = a[begin2++];
        }
      }
      while (begin1 <= end1)
      {
        temp[index++] = a[begin1++];
      }
      while (begin2 <= end2)
      {
        temp[index++] = a[begin2++];
      }
      // 拷贝回原数组
      memcpy(a + i, temp + i, (end2 - i + 1) * sizeof(int));
    }
    gap *= 2;
  }
  free(temp);
}

♋️三、归并排序的特性总结

      1. 归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的

       外排序问题。

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

       3. 空间复杂度:O(N)

       4. 稳定性:稳定


  感谢你耐心的看到这里ღ( ´・ᴗ・` )比心,如有哪里有错误请踢一脚作者o(╥﹏╥)o! 

相关文章
|
2月前
|
算法 数据处理 C语言
C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合
本文深入解析了C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合,旨在帮助读者掌握这一高效的数据处理方法。
63 1
|
2月前
|
存储 算法 搜索推荐
【趣学C语言和数据结构100例】91-95
本文涵盖多个经典算法问题的C语言实现,包括堆排序、归并排序、从长整型变量中提取偶数位数、工人信息排序及无向图是否为树的判断。通过这些问题,读者可以深入了解排序算法、数据处理方法和图论基础知识,提升编程能力和算法理解。
60 4
|
2月前
|
存储 机器学习/深度学习 搜索推荐
【趣学C语言和数据结构100例】86-90
本文介绍并用C语言实现了五种经典排序算法:直接插入排序、折半插入排序、冒泡排序、快速排序和简单选择排序。每种算法都有其特点和适用场景,如直接插入排序适合小规模或基本有序的数据,快速排序则适用于大规模数据集,具有较高的效率。通过学习这些算法,读者可以加深对数据结构和算法设计的理解,提升解决实际问题的能力。
52 4
|
2月前
|
存储 算法 数据处理
【趣学C语言和数据结构100例】81-85
本文介绍了五个经典算法问题及其C语言实现,涵盖图论与树结构的基础知识。包括使用BFS求解单源最短路径、统计有向图中入度或出度为0的点数、统计无向无权图各顶点的度、折半查找及二叉排序树的查找。这些算法不仅理论意义重大,且在实际应用中极为广泛,有助于提升编程能力和数据结构理解。
54 4
|
2月前
|
算法 数据可视化 数据建模
【趣学C语言和数据结构100例】76-80
本文介绍了五种图论算法的C语言实现,涵盖二叉树的层次遍历及广度优先搜索(BFS)和深度优先搜索(DFS)的邻接表与邻接矩阵实现。层次遍历使用队列按层访问二叉树节点;BFS利用队列从源节点逐层遍历图节点,适用于最短路径等问题;DFS通过递归或栈深入图的分支,适合拓扑排序等场景。这些算法是数据结构和算法学习的基础,对提升编程能力和解决实际问题至关重要。
56 4
|
2月前
|
存储 算法 vr&ar
【趣学C语言和数据结构100例】71-75
本文介绍了五个C语言数据结构问题及其实现,涵盖链表与二叉树操作,包括按奇偶分解链表、交换二叉树左右子树、查找节点的双亲节点、计算二叉树深度及求最大关键值。通过递归和遍历等方法,解决了理论与实际应用中的常见问题,有助于提升编程能力和数据结构理解。
48 4
|
2月前
|
存储 算法 C语言
【趣学C语言和数据结构100例】66-70
本书《趣学C语言和数据结构100例》精选了5个典型的数据结构问题及C语言实现,涵盖链表与数组操作,如有序集合的集合运算、有序序列表的合并、数组中两顺序表位置互换、三递增序列公共元素查找及奇偶数重排。通过详细解析与代码示例,帮助读者深入理解数据结构与算法设计的核心思想,提升编程技能。
39 4
|
3天前
|
存储 人工智能 算法
【C++数据结构——内排序】二路归并排序(头歌实践教学平台习题)【合集】
本关任务是实现二路归并算法,即将两个有序数组合并为一个有序数组。主要内容包括: - **任务描述**:实现二路归并算法。 - **相关知识**: - 二路归并算法的基本概念。 - 算法步骤:通过比较两个有序数组的元素,依次将较小的元素放入新数组中。 - 代码示例(以 C++ 为例)。 - 时间复杂度为 O(m+n),空间复杂度为 O(m+n)。 - **测试说明**:平台会对你编写的代码进行测试,提供输入和输出示例。 - **通关代码**:提供了完整的 C++ 实现代码。 - **测试结果**:展示代码运行后的排序结果。 开始你的任务吧,祝你成功!
23 10
|
2月前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
79 5
|
2月前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
72 1