归并排序学习

归并排序采用了分而治之的思想,所以主要分为"分"和"治"两部分

  • 分:对数组取中点,分为两部分,两个子数组同理取中点,各自分为两部分...
  • 治:分到数组长度为 1 时自然就可以返回了,然后开始往上一步走,将左右两个子数组排序合并
  • 比如数组 [4,3,2,1] 会先分出 [4,3] 和 [2,1] ,然后 [4,3] 继续分为 [4],和 [3],这时数组长度为 1 了,向上进行合并,把 [4] 和 [3] 合并为 [3,4] ,[2,1] 同理最终得到 [1,2],此时来到递归最外层,数组为 [3,4,1,2] 然后得到 [1,2,3,4]。排序的原理则是双指针,因为你会发现这样我们会不断得到左右两个有序数组,比如最后的 [3,4,1,2] 左边的 [3,4] 和 右边的 [1,2] 都是有序的,所以让 i,j 分别指向左右子数组的首位。首先比较 3 和 1,取 1 为 [1],然后 j+1 ,此时比较 3 和 2,取 2 为 [1,2],由于右边的子数组取完了,所以之后不用比较了,把左边的继续按顺序填充进去就行,最后得到 [1,2,3,4]。
java 复制代码
  void mergeSort(int[] nums, int l, int r) {
      if (l >= r) return;
      int m = (l + r) / 2;
      mergeSort(l,m);
      mergeSort(m+1,r);
      // 复制当前要治的数组
      int[] tmp = new int[r - l + 1];
      for(int k=l; k<=r; k++)tmp[k-l] = nums[k];
      // 双指针排序,i:左数组首位,j:右数组首位(或者说当前总数组的中点位后一位)
      // 因为 tmp 最后一位下标为 r-l,所以如果你要把 j 写成 (r-l)/2+1 也行
      // 但其实 m=(l+r)/2, m-l+1 不就是 (l+r)/2-l+1,也就是 (r-l)/2+1
      // m-l 你也能理解成去掉 l 不从 0 开始的影响,比如数组长度为 8,进行后四位的治时
      // l 和 m 是 4 和 5,他们同时减去 l 也就等于把他们同时放在一条线的起点了,成了 0 和 1
      int i=0,j=m-l+1;
      for (int k = l; k <= r; k++) {  // 遍历合并左/右子数组
          if (i == m - l + 1)   // 如果左数组用完了那就直接填充左数组了
              nums[k] = tmp[j++];
          else if (j == r - l + 1) // 如果右数组用完了
              nums[k] = tmp[i++];
          else if (tmp[i] <= tmp[j]) // 正常比较大小,先放小的
              nums[k] = tmp[i++];
          else {                    // tmp[i]>tmp[j]
              nums[k] = tmp[j++];
          }
      }
  }
  • 其实右数组用完和右数组当前位更小能合并到一起
java 复制代码
  for (int k = l; k <= r; k++) {  // 遍历合并左/右子数组
          if (i == m - l + 1)   // 如果左数组用完了那就直接填充左数组了
              nums[k] = tmp[j++];
           // 如果右数组用完了或右数组当前位更小
          else if (j == r - l + 1 || tmp[i] <= tmp[j])
              nums[k] = tmp[i++];
          else {                    // tmp[i]>tmp[j]
              nums[k] = tmp[j++];
          }
      }
  • 你可能会想既然这样,为什么不直接
java 复制代码
  if (j == r - l + 1 || tmp[i] <= tmp[j])
     nums[k] = tmp[i++];
  else {                    
      nums[k] = tmp[j++];
  • 因为这样会在 i 被用完但是 tmp[i] <= tmp[j] 时继续用 i,但是其实这时候 i 都已经指到右数组去了,以 [3, 4, 1, 5] 为例模拟最后一轮排序就知道了,最后会得到 [1,3,4,1]
python 复制代码
  def merge_sort(nums, l, r):
      m = (l + r) // 2
      tmp = nums[l:r + 1]       
      i, j = 0, m - l + 1       
      for k in range(l, r + 1):
          if j == r - l + 1 or tmp[i] <= tmp[j]:
              nums[k] = tmp[i]
              i += 1
          else:
              nums[k] = tmp[j]
              j += 1
  # 调用
  nums = [3,4,1,5]
  merge_sort(nums, 0, len(nums) - 1)
  print(nums)
相关推荐
Love__Tay8 分钟前
【学习笔记】Python金融基础
开发语言·笔记·python·学习·金融
BUG收容所所长1 小时前
栈的奇妙世界:从冰棒到算法的华丽转身
前端·javascript·算法
有风南来1 小时前
算术图片验证码(四则运算)+selenium
自动化测试·python·selenium·算术图片验证码·四则运算验证码·加减乘除图片验证码
wangjinjin1801 小时前
Python Excel 文件处理:openpyxl 与 pandas 库完全指南
开发语言·python
XRZaaa1 小时前
常见排序算法详解与C语言实现
c语言·算法·排序算法
@我漫长的孤独流浪1 小时前
数据结构测试模拟题(4)
数据结构·c++·算法
智驱力人工智能1 小时前
智慧零售管理中的客流统计与属性分析
人工智能·算法·边缘计算·零售·智慧零售·聚众识别·人员计数
我的golang之路果然有问题1 小时前
云服务器部署Gin+gorm 项目 demo
运维·服务器·后端·学习·golang·gin
Yxh181377845542 小时前
抖去推--短视频矩阵系统源码开发
人工智能·python·矩阵
Lester_11012 小时前
嵌入式学习笔记 - freeRTOS xTaskResumeAll( )函数解析
笔记·stm32·单片机·学习·freertos