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

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

一.归并排序简介及思想

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

归并排序(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).


结语

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

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

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



相关文章
|
21天前
|
算法 数据处理 C语言
C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合
本文深入解析了C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合,旨在帮助读者掌握这一高效的数据处理方法。
33 1
|
25天前
|
机器学习/深度学习 算法 数据挖掘
K-means聚类算法是机器学习中常用的一种聚类方法,通过将数据集划分为K个簇来简化数据结构
K-means聚类算法是机器学习中常用的一种聚类方法,通过将数据集划分为K个簇来简化数据结构。本文介绍了K-means算法的基本原理,包括初始化、数据点分配与簇中心更新等步骤,以及如何在Python中实现该算法,最后讨论了其优缺点及应用场景。
76 4
|
22天前
|
存储 算法 搜索推荐
Python 中数据结构和算法的关系
数据结构是算法的载体,算法是对数据结构的操作和运用。它们共同构成了计算机程序的核心,对于提高程序的质量和性能具有至关重要的作用
|
22天前
|
数据采集 存储 算法
Python 中的数据结构和算法优化策略
Python中的数据结构和算法如何进行优化?
|
1月前
|
算法
数据结构之路由表查找算法(深度优先搜索和宽度优先搜索)
在网络通信中,路由表用于指导数据包的传输路径。本文介绍了两种常用的路由表查找算法——深度优先算法(DFS)和宽度优先算法(BFS)。DFS使用栈实现,适合路径问题;BFS使用队列,保证找到最短路径。两者均能有效查找路由信息,但适用场景不同,需根据具体需求选择。文中还提供了这两种算法的核心代码及测试结果,验证了算法的有效性。
96 23
|
1月前
|
算法
数据结构之蜜蜂算法
蜜蜂算法是一种受蜜蜂觅食行为启发的优化算法,通过模拟蜜蜂的群体智能来解决优化问题。本文介绍了蜜蜂算法的基本原理、数据结构设计、核心代码实现及算法优缺点。算法通过迭代更新蜜蜂位置,逐步优化适应度,最终找到问题的最优解。代码实现了单链表结构,用于管理蜜蜂节点,并通过适应度计算、节点移动等操作实现算法的核心功能。蜜蜂算法具有全局寻优能力强、参数设置简单等优点,但也存在对初始化参数敏感、计算复杂度高等缺点。
59 20
|
21天前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
49 1
|
1月前
|
机器学习/深度学习 算法 C++
数据结构之鲸鱼算法
鲸鱼算法(Whale Optimization Algorithm,WOA)是由伊朗研究员Seyedali Mirjalili于2016年提出的一种基于群体智能的全局优化算法,灵感源自鲸鱼捕食时的群体协作行为。该算法通过模拟鲸鱼的围捕猎物和喷出气泡网的行为,结合全局搜索和局部搜索策略,有效解决了复杂问题的优化需求。其应用广泛,涵盖函数优化、机器学习、图像处理等领域。鲸鱼算法以其简单直观的特点,成为初学者友好型的优化工具,但同时也存在参数敏感、可能陷入局部最优等问题。提供的C++代码示例展示了算法的基本实现和运行过程。
49 0
|
1月前
|
搜索推荐 算法 C语言
【排序算法】八大排序(下)(c语言实现)(附源码)
本文继续学习并实现了八大排序算法中的后四种:堆排序、快速排序、归并排序和计数排序。详细介绍了每种排序算法的原理、步骤和代码实现,并通过测试数据展示了它们的性能表现。堆排序利用堆的特性进行排序,快速排序通过递归和多种划分方法实现高效排序,归并排序通过分治法将问题分解后再合并,计数排序则通过统计每个元素的出现次数实现非比较排序。最后,文章还对比了这些排序算法在处理一百万个整形数据时的运行时间,帮助读者了解不同算法的优劣。
105 7
|
1月前
|
算法 vr&ar 计算机视觉
数据结构之洪水填充算法(DFS)
洪水填充算法是一种基于深度优先搜索(DFS)的图像处理技术,主要用于区域填充和图像分割。通过递归或栈的方式探索图像中的连通区域并进行颜色替换。本文介绍了算法的基本原理、数据结构设计(如链表和栈)、核心代码实现及应用实例,展示了算法在图像编辑等领域的高效性和灵活性。同时,文中也讨论了算法的优缺点,如实现简单但可能存在堆栈溢出的风险等。
41 0
下一篇
DataWorks