【排序算法】C语言实现归并排序,包括递归和迭代两个版本

简介: 【排序算法】C语言实现归并排序,包括递归和迭代两个版本

🚀前言

大家好啊!阿辉接着更新排序算法,今天要讲的是归并排序,这里阿辉将讲到归并排序递归实现迭代实现,话不多说,开始咱们今天的学习吧!!!!

🚀归并排序介绍及其思想

归并排序这是阿辉讲的第一个时间复杂度O(nlogn)的排序算法,额外空间复杂度是O(n),归并排序可以做到稳定性。

思想

归并排序的思想就是分治分治的思想是将一个大问题分解成若干个小问题,然后分别解决这些小问题,最后将这些小问题的解合并起来得到原问题的解

由分治的思想很容易,想到用递归来实现归并排序,我们接着看👇

🚀递归实现

关于归并排序的递归方法主要由三个大的逻辑组成:

  • 分解:将待排序的数组分成两个子数组
  • 解决:对每个子数组进行排序
  • 合并:将排序好的子数组合并成一个有序的数组

这里我们使用递归很轻松就能把主逻辑写好,大家都知道写递归必须要有限制条件否则会造成死递归,对于归并排序的限制条件很简单,对于数组只有一个元素时自然就是有序的,直接返回即可

主逻辑:

merge函数相当于黑盒,作用就是把两个有序数组合成一个大的有序数组

void MergeSort(int a[], int l, int r) {// C/C++归并排序递归版本,主逻辑
  if (r == l) {//递归限制条件
    return;
  }
  int m = l + ((r - l) >> 1);//数组中位置下标
  MergeSort(a, l, m);//左部分排序
  MergeSort(a, m + 1, r);//右部分排序
  merge(a, l, m, r);//两部分有序数组合并
}

整个归并排序最重要的部分也就是有序数组合并的部分:

merge函数实现,还是不太懂的可以看一下下面的代码,有详细的注释

C语言版本:

void merge(int a[], int l, int m, int r) {
  int* help = (int*)malloc((r - l + 1) * 4);//申请辅助空间
  int i = 0;//作为help指针的偏移量,存储两有序数组排好序的大数组
  int first = l;//作为左部分数组的起始下标
  int second = m + 1;//作为右部分数组的起始下标
  while (first <= m && second <= r) {//哪一方下标越界就说明不用继续比较了
    //三目运算代码更简洁,谁小谁在前先赋值给help,后置++,
    // 赋值后i向后偏移一个位置,second或first也向后偏移一个位置
    help[i++] = a[first] <= a[second] ? a[first++] : a[second++];
  }
  //下面虽然两个while循环但是只会进去一个
  //还没存进help数组的继续存
  while (first <= m) {
    help[i++] = a[first++];
  }
  while (second <= r) {
    help[i++] = a[second++];
  }
  //最后把help管理的值,还原到原数组a中
  for (i = 0; i < r - l + 1; i++) {
    a[l + i] = help[i];
  }
  free(help);//释放申请的堆空间
  help = NULL;//野指针系上绳子
}

C++版本:

也就是用了STL的容器更方便

void merge(vector<int>& arr, int l, int mid, int r) {//合并有序数组
  vector<int> help(r - l + 1, 0);//用一个额外的数组装排好的数
  int first = l;
  int second = mid + 1;
  int i = 0;
  //合并过程
  while (first <= mid && second <= r) {
    help[i++] = arr[first] <= arr[second] ? arr[first++] : arr[second++];
  }
  while (first <= mid) {
    help[i++] = arr[first++];
  }
  while (second <= r) {
    help[i++] = arr[second++];
  }
  //将help数组拷贝到原数组
  for (int i = 0; i < r - l + 1; i++) {
    arr[l + i] = help[i];
  }
}

🚀迭代实现

归并排序的迭代实现就是把主逻辑从递归改为迭代了,有序合并部分并没有改变还是上面实现的merge函数

其实就是从递归的条件返回那一步往后推:

这里我们引入一个概念步长,用来表示左部分和右部分的数组长度,步长从1开始,然后每次倍增,就相当于递归的回溯过程

上图:

步长为左右部分长度,左右部分进行merge操作,没有右部分的跳过

主逻辑:

void MergeSort(int a[], int l, int r) {
  int len = 1;//步长
  while (len <= r) {
    l = 0;
    while (l <= r) {
      int m = l + len - 1;//计算左部分的最后一个位置
      if (m >= r) {//此时说明没有右部分,可以跳出循环进行下一轮了
        break;
      }
      //m + len是右部分的最后一个位置与r做比较防止越界,拿到一个正确的merge右边界
      int n = r <= m + len ? r : m + len;
      merge(a, l, m, n);
      l = n + 1;
    }
    if (len > r / 2) {//假如数组很长len×2可能溢出,防止溢出变成负数死循环
      break;
    }
  }
}

merge函数和前面的一样,阿辉就不水了

相关文章
|
11月前
|
搜索推荐 C语言
【排序算法】快速排序升级版--三路快排详解 + 实现(c语言)
本文介绍了快速排序的升级版——三路快排。传统快速排序在处理大量相同元素时效率较低,而三路快排通过将数组分为三部分(小于、等于、大于基准值)来优化这一问题。文章详细讲解了三路快排的实现步骤,并提供了完整的代码示例。
348 4
|
8月前
|
存储 算法 Java
算法系列之递归反转单链表
递归反转链表的基本思路是将当前节点的next指针指向前一个节点,然后递归地对下一个节点进行同样的操作。递归的核心思想是将问题分解为更小的子问题,直到达到基本情况(通常是链表末尾)。
233 5
算法系列之递归反转单链表
|
9月前
|
搜索推荐 C语言
数据结构(C语言)之对归并排序的介绍与理解
归并排序是一种基于分治策略的排序算法,通过递归将数组不断分割为子数组,直到每个子数组仅剩一个元素,再逐步合并这些有序的子数组以得到最终的有序数组。递归版本中,每次分割区间为[left, mid]和[mid+1, right],确保每两个区间内数据有序后进行合并。非递归版本则通过逐步增加gap值(初始为1),先对单个元素排序,再逐步扩大到更大的区间进行合并,直至整个数组有序。归并排序的时间复杂度为O(n*logn),空间复杂度为O(n),且具有稳定性,适用于普通排序及大文件排序场景。
|
11月前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
321 1
|
11月前
|
搜索推荐 算法 C语言
【排序算法】八大排序(下)(c语言实现)(附源码)
本文继续学习并实现了八大排序算法中的后四种:堆排序、快速排序、归并排序和计数排序。详细介绍了每种排序算法的原理、步骤和代码实现,并通过测试数据展示了它们的性能表现。堆排序利用堆的特性进行排序,快速排序通过递归和多种划分方法实现高效排序,归并排序通过分治法将问题分解后再合并,计数排序则通过统计每个元素的出现次数实现非比较排序。最后,文章还对比了这些排序算法在处理一百万个整形数据时的运行时间,帮助读者了解不同算法的优劣。
391 7
|
11月前
|
搜索推荐 算法 C语言
【排序算法】八大排序(上)(c语言实现)(附源码)
本文介绍了四种常见的排序算法:冒泡排序、选择排序、插入排序和希尔排序。通过具体的代码实现和测试数据,详细解释了每种算法的工作原理和性能特点。冒泡排序通过不断交换相邻元素来排序,选择排序通过选择最小元素进行交换,插入排序通过逐步插入元素到已排序部分,而希尔排序则是插入排序的改进版,通过预排序使数据更接近有序,从而提高效率。文章最后总结了这四种算法的空间和时间复杂度,以及它们的稳定性。
462 8
|
11月前
|
算法 Python
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果;贪心算法在每一步选择局部最优解,追求全局最优;动态规划通过保存子问题的解,避免重复计算,确保全局最优。这三种算法各具特色,适用于不同类型的问题,合理选择能显著提升编程效率。
220 2
|
24天前
|
传感器 机器学习/深度学习 编解码
MATLAB|主动噪声和振动控制算法——对较大的次级路径变化具有鲁棒性
MATLAB|主动噪声和振动控制算法——对较大的次级路径变化具有鲁棒性
142 3
|
29天前
|
存储 编解码 算法
【多光谱滤波器阵列设计的最优球体填充】使用MSFA设计方法进行各种重建算法时,图像质量可以提高至多2 dB,并在光谱相似性方面实现了显著提升(Matlab代码实现)
【多光谱滤波器阵列设计的最优球体填充】使用MSFA设计方法进行各种重建算法时,图像质量可以提高至多2 dB,并在光谱相似性方面实现了显著提升(Matlab代码实现)
|
18天前
|
机器学习/深度学习 算法 数据可视化
基于MVO多元宇宙优化的DBSCAN聚类算法matlab仿真
本程序基于MATLAB实现MVO优化的DBSCAN聚类算法,通过多元宇宙优化自动搜索最优参数Eps与MinPts,提升聚类精度。对比传统DBSCAN,MVO-DBSCAN有效克服参数依赖问题,适应复杂数据分布,增强鲁棒性,适用于非均匀密度数据集的高效聚类分析。

热门文章

最新文章