迭代归并:归并排序非递归实现解析

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
简介: 迭代归并:归并排序非递归实现解析

一、非递归实现的思想

归并实现的思想无非就是先将 每个数都递归 分割为一个小区间然后再进行排序,之后递归 回溯 上一个区间 这时 上一个区间都排好了所以可以在进行排序就这样循环上去。

既然要用非递归那么我们是不是可以这样想 直接吧每个区间定义为 1 进行归并然后再来进行循环到上一组归并排序:

这样就可以利用循环来吧归并排序非递归化了

二、非递归实现的过程

好了具体思想那么我们懂了,既然要进行从最小区间 1 开始那么我们肯定需要需要定义 一个 gap = 1 开始循环

  • 然后每次gap * = 2; 来进行调整我们的归并区间的间距进行归并
  • 而排序的时候则又需要一个循环了来进行进行对每个区间进行归并排序
  • int i = 0; i < n; i += (gap*2)
  • 为什么每次 i += (gap*2)因为 每次当这个区间排完了之后就需要跳到下一个区间开始

🍸 代码演示:

// 归并排序非递归实现
void MergeSortNonR(int* a, int n)
{
  int* tmp = (int*)malloc(sizeof(int) * n);
  if (tmp == NULL)
  {
    perror("malloc file");
    exit(-1);
  }
  int gap = 1;
  while (gap < n)
  {
    for (int i = 0; i < n; i += (gap*2))
    {
      int begin1 = i, end1 = i + gap - 1;
      int begin2 = i + gap, end2 = i + (2 * gap) - 1;
      int index = i;
      while (begin1 <= end1 && begin2 <= end2)
      {
        if (a[begin1] < a[begin2])
        {
          tmp[index++] = a[begin1++];
        }
        else
        {
          tmp[index++] = a[begin2++];
        }
      }
      while (begin1 <= end1)
      {
        tmp[index++] = a[begin1++];
      }
      while (begin2 <= end2)
      {
        tmp[index++] = a[begin2++];
      }
      memcpy(a + i, tmp + i, sizeof(int) * (2*gap));
    }
    printf("\n");
    gap *= 2;
  }
  free(tmp);
}

2.1 非递归实现的调整

以上就是非递归实现的代码了,但你真的以为非递归就这样结束了?哈哈哈其实没有我们前面举例的是2的倍数来进行排序的但是当我们排序10之类的不是2的倍数就会出现越界的情况:

🔥 注:是上面我们每次 第二个区间都是 i + (2 * gap) - 1 但是当不是2的整数倍来实现的话不就越界了

2.2 调整思路讲解

哦豁大家是不是看到了当第二次排序的时候 begin2end2 都越界了,第三次归并的时候甚至 end2 都 越界了

这其实非常简单既然第二个区间都越界的话那么是不是就不需要进行归并了,你想啊连第二个区间都不存在的话第一个区间和谁归并?

  • 而只有 end2 越界的话咱们修正一下不就好了,只让它归并一个数

🔥 注:这里还要注意memcpy 的时候的copy大小。

以前我们进行 copy 的时候都是 2倍的gap 但是当才不是整数倍的时候就需要调整了

i 每次都是要归并的区间开头, 而 end2 倍修正了之后就是区间尾了他们一相减就好了

🔥 注:相减了之后要加1,因为是闭区间。(3-0)虽然是相减了但是我们实际复制的是4个数

2.3 归并非递归完整代码

// 归并排序非递归实现
void MergeSortNonR(int* a, int n)
{
  int* tmp = (int*)malloc(sizeof(int) * n);
  if (tmp == NULL)
  {
    perror("malloc file");
    exit(-1);
  }
  int gap = 1;
  while (gap < n)
  {
    for (int i = 0; i < n; i += (gap*2))
    {
      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;
      printf("[%d,%d][%d,%d] ", begin1, end1, begin2, end2);
      int index = i;
      while (begin1 <= end1 && begin2 <= end2)
      {
        if (a[begin1] < a[begin2])
        {
          tmp[index++] = a[begin1++];
        }
        else
        {
          tmp[index++] = a[begin2++];
        }
      }
      while (begin1 <= end1)
      {
        tmp[index++] = a[begin1++];
      }
      while (begin2 <= end2)
      {
        tmp[index++] = a[begin2++];
      }
      memcpy(a + i, tmp + i, sizeof(int) * (end2-i+1));
    }
    printf("\n");
    gap *= 2;
  }
  free(tmp);
}

三、归并排序的总结

  1. 归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。
  2. 时间复杂度:O(N*logN)
  3. 空间复杂度:O(N)
  4. 稳定性:稳定

📝文章结语:

看到这里了还不给博主扣个:
⛳️ 点赞🍹收藏 ⭐️ 关注

💛 💙 💜 ❤️ 💚💓 💗 💕 💞 💘 💖

拜托拜托这个真的很重要!

你们的点赞就是博主更新最大的动力!

有问题可以评论或者私信呢秒回哦。

目录
相关文章
|
6月前
|
算法 数据库
递归最佳解析
递归最佳解析
78 0
|
19天前
|
前端开发 JavaScript 开发者
揭秘前端高手的秘密武器:深度解析递归组件与动态组件的奥妙,让你代码效率翻倍!
【10月更文挑战第23天】在Web开发中,组件化已成为主流。本文深入探讨了递归组件与动态组件的概念、应用及实现方式。递归组件通过在组件内部调用自身,适用于处理层级结构数据,如菜单和树形控件。动态组件则根据数据变化动态切换组件显示,适用于不同业务逻辑下的组件展示。通过示例,展示了这两种组件的实现方法及其在实际开发中的应用价值。
27 1
|
1月前
|
存储 搜索推荐 算法
【排序算法(二)】——冒泡排序、快速排序和归并排序—>深层解析
【排序算法(二)】——冒泡排序、快速排序和归并排序—>深层解析
|
2月前
|
设计模式 存储 人工智能
深度解析Unity游戏开发:从零构建可扩展与可维护的游戏架构,让你的游戏项目在模块化设计、脚本对象运用及状态模式处理中焕发新生,实现高效迭代与团队协作的完美平衡之路
【9月更文挑战第1天】游戏开发中的架构设计是项目成功的关键。良好的架构能提升开发效率并确保项目的长期可维护性和可扩展性。在使用Unity引擎时,合理的架构尤为重要。本文探讨了如何在Unity中实现可扩展且易维护的游戏架构,包括模块化设计、使用脚本对象管理数据、应用设计模式(如状态模式)及采用MVC/MVVM架构模式。通过这些方法,可以显著提高开发效率和游戏质量。例如,模块化设计将游戏拆分为独立模块。
180 3
|
3月前
|
缓存 JavaScript 前端开发
|
6月前
|
域名解析 网络协议 安全
【域名解析DNS专栏】DNS递归查询与迭代查询的区别及影响
【5月更文挑战第24天】DNS的递归查询与迭代查询是域名解析的两种方式。递归查询由客户端发起,DNS服务器负责全程解析,速度快但可能增加服务器负载和安全风险。迭代查询则需客户端参与多次查询,虽慢但分散负载,提高安全性。理解两者差异有助于优化网站访问体验和安全性。
909 0
【域名解析DNS专栏】DNS递归查询与迭代查询的区别及影响
|
5月前
|
SQL 算法 数据可视化
LeetCode题目92:反转链表ll 【python 递归与迭代方法全解析】
LeetCode题目92:反转链表ll 【python 递归与迭代方法全解析】
|
6月前
|
存储 搜索推荐 算法
归并排序算法深入解析
归并排序算法深入解析
|
6月前
|
机器学习/深度学习 C语言
函数递归深入解析(C语言)
函数递归深入解析(C语言)
|
6月前
|
算法 Java
Java必刷入门递归题×5(内附详细递归解析图)
Java必刷入门递归题×5(内附详细递归解析图)
92 1

推荐镜像

更多