【数据结构】八大排序之归并排序算法

简介: 【数据结构】八大排序之归并排序算法

一.归并排序简介及思想

"归并"一词的中文含义就是合并,并入的意思,而在数据结构中的定义将两个或两个以上的有序表组合成一个新的有序表.

归并排序(Merging Sort)就是利用归并的思想实现的排序方法.

它的原理是:

      假设初始序列含有n个记录,则可看成是n个有序的子序列,每个子序列的长度为1,然后两两归并,得到 ( 表示不小于x的最小整数)个长度为2或1的有序子序列;再两两归并,......,如此重复,直至得到一个长度为n的有序序列为止,这种排序方法称为2路归并排序.

算法动图演示如下:

算法逻辑演示:


二.归并排序的代码实现

算法实现步骤:(以升序为例)

  1. 将数组中的n个数据看成n个有序子序列
  2. 然后将其两两归并到新数组内,得到 +1或 个长度为1或2的有序子序列,将新数组的数据拷贝回原数组.
  3. 重复步骤2,直到归并得到一个长度为n的有序序列为止.

综上,归并排序的代码实现如下:

//归并递归子函数
void _MergeSort(int* a, int begin, int end, int* tmp)
{
  if ( begin >= end )
    return;
 
  int mid = (begin + end) / 2;
  
  //先递归后访问进行操作,类似于树的后序遍历
  _MergeSort(a, begin, mid, tmp);
  _MergeSort(a, mid+1, end, tmp);
 
  //递归到叶子数组后,开始归并
  int begin1 = begin, end1 = mid;
  int begin2 = mid + 1, end2 = end;
  int i = begin;
 
  while (begin1 <= end1 && begin2 <= end2)
  {
    if (a[begin1] < a[begin2])//循环将小值尾插进新数组
    {
      tmp[i++] = a[begin1++];
    }
    else
    {
      tmp[i++] = a[begin2++];
    }
  }
 
    //防止合并时有数组没拷贝完
  while (begin1 <= end1)
  {
    tmp[i++] = a[begin1++];
  }
 
  while (begin2 <= end2)
  {
    tmp[i++] = a[begin2++];
  }
 
  //拷贝tmp回原数组
  memcpy(a + begin, tmp + begin, sizeof(int) * (end - begin + 1));
 
}
 
//归并排序
void MergeSort(int* a, int n)//不写区间,因为该函数不递归自己,否则每次都要malloc
{
  //开数组
  int* tmp = (int*)malloc(sizeof(int) * n);
  if (tmp == NULL)
  {
    perror("malloc fail::\n");
    return;
  }
 
  _MergeSort(a, 0, n - 1, tmp);//归并递归子函数
 
  free(tmp);
}

三.归并排序的非递归代码实现

算法实现思路:(以升序为例)

      因为归并排序递归是将完整的数组不断分割成只有一个元素的数组进行归并的,那么我们实现非递归的时候,就可以在一开始直接将数组视为n个只有一个元素的子序列进行归并,然后再按照两个两个元素的数组进行归并,一直向上归并,直到归并成为一个有n个元素的有序数组为止.

       归并排序在非递归实现时需要额外注意当n不是2的次方倍时归并数组末尾的越界现象,并对此错误现象做出及时的修正.

归并排序的非递归实现代码如下:

//归并排序非递归
void MergeSortNonR(int* a, int n)
{
  //开数组
  int* tmp = (int*)malloc(sizeof(int) * n);
  if (tmp == NULL)
  {
    perror("malloc fail::\n");
    return;
  }
 
  int gap = 1;
 
  while (gap < n)
  {
    for (int i = 0; i < n; i =i+ 2 * gap)
    {
      int begin1 = i, end1 = i + gap - 1;
      int begin2 = i + gap, end2 = i + 2 * gap - 1;
 
      //修正数组非2的次方倍数时的越界现象
      if (end1 >= n)
      {
        end1 = n - 1;
        begin2 = n;
        end2 = n - 1;
      }
      else if (begin2 >= n)
      {
        begin2 = n;
        end2 = n - 1;
      }
      else if (end2 >= n)
      {
        end2 = n - 1;
      }
 
      int j = i;
      while (begin1 <= end1 && begin2 <= end2)
      {
        if (a[begin1] < a[begin2])
        {
          tmp[j++] = a[begin1++];
        }
        else
        {
          tmp[j++] = a[begin2++];
        }
      }
 
      while (begin1 <= end1)
      {
        tmp[j++] = a[begin1++];
      }
      while (begin2 <= end2)
      {
        tmp[j++] = a[begin2++];
      }
    }
    memcpy(a, tmp, sizeof(int) * n);
    gap *= 2;
  }
 
  free(tmp);
}

四.归并排序的复杂度分析

📌时间复杂度

从最开始的示意图我们可以看出,归并排序一趟总共处理n个元素,而总共要处理logn趟,因此归并排序的最好,最坏,以及平均时间复杂度都是一样的,那就是O(nlogn).


📌空间复杂度

而我们在排序过程中需要一个和原数组相同大小的临时数组来对数组进行归并排序,因此归并排序的空间复杂度为O(n).


结语

希望这篇归并排序算法详解能对大家有所帮助,欢迎大佬们留言或私信与我交流.

学海漫浩浩,我亦苦作舟!关注我,大家一起学习,一起进步!

数据结构排序算法篇思维导图:



相关文章
|
12天前
|
存储 搜索推荐 算法
【初阶数据结构篇】归并排序和计数排序(总结篇)
归并排序(MERGE-SORT)是建⽴在归并操作上的⼀种有效的排序算法,该算法是采⽤分治法(Divide andConquer)的⼀个⾮常典型的应⽤。
|
3天前
|
C语言
数据结构——排序【上】
数据结构——排序【上】
13 2
|
10天前
|
算法 搜索推荐 Java
算法实战:手写归并排序,让复杂排序变简单!
归并排序是一种基于“分治法”的经典算法,通过递归分割和合并数组,实现O(n log n)的高效排序。本文将通过Java手写代码,详细讲解归并排序的原理及实现,帮助你快速掌握这一实用算法。
29 0
|
12天前
|
算法
【初阶数据结构】复杂度算法题篇
该方法基于如下的事实:当我们将数组的元素向右移动 k 次后,尾部 kmodn 个元素会移动至数组头部,其余元素向后移动 kmodn 个位置。
|
14天前
|
机器学习/深度学习 人工智能 算法
【人工智能】线性回归模型:数据结构、算法详解与人工智能应用,附代码实现
线性回归是一种预测性建模技术,它研究的是因变量(目标)和自变量(特征)之间的关系。这种关系可以表示为一个线性方程,其中因变量是自变量的线性组合。
30 2
|
10天前
|
数据采集 搜索推荐 算法
【高手进阶】Java排序算法:从零到精通——揭秘冒泡、快速、归并排序的原理与实战应用,让你的代码效率飙升!
【8月更文挑战第21天】Java排序算法是编程基础的重要部分,在算法设计与分析及实际开发中不可或缺。本文介绍内部排序算法,包括简单的冒泡排序及其逐步优化至高效的快速排序和稳定的归并排序,并提供了每种算法的Java实现示例。此外,还探讨了排序算法在电子商务、搜索引擎和数据分析等领域的广泛应用,帮助读者更好地理解和应用这些算法。
11 0
|
12天前
|
算法
【初阶数据结构篇】二叉树算法题
二叉树是否对称,即左右子树是否对称.
|
12天前
|
算法 索引
【初阶数据结构篇】单链表算法题进阶
深拷贝应该正好由 n 个全新节点组成,其中每个新节点的值都设为其对应的原节点的值。
|
12天前
|
存储 算法
【初阶数据结构篇】顺序表和链表算法题
此题可以先找到中间节点,然后把后半部分逆置,最近前后两部分一一比对,如果节点的值全部相同,则即为回文。
|
18天前
|
算法
基于模糊控制算法的倒立摆控制系统matlab仿真
本项目构建了一个基于模糊控制算法的倒立摆控制系统,利用MATLAB 2022a实现了从不稳定到稳定状态的转变,并输出了相应的动画和收敛过程。模糊控制器通过对小车位置与摆的角度误差及其变化量进行模糊化处理,依据预设的模糊规则库进行模糊推理并最终去模糊化为精确的控制量,成功地使倒立摆维持在直立位置。该方法无需精确数学模型,适用于处理系统的非线性和不确定性。
基于模糊控制算法的倒立摆控制系统matlab仿真
下一篇
云函数