之前发了一期归并排序递归版本 这期讲解一下非递归版本 用循环模拟

有没有人好奇 既然有了递归版本 为何还要搞非递归版本 这不是多此一举吗?

其实不然 正因为递归是基于栈帧的基础上实现的 是不断在栈上开辟空间 所以总归有消耗

既然是开辟空间 如果递归深度太深 总有空间被占据完的时候 这就会导致栈溢出(StakeOverFlow)^~^

那么递归在这种情况之下显得很乏力 这就引出了今天的主角非递归循环实现归并排序

就是模拟归并排序 也是分为很多区间段去比较合并 但是从思路图上来看

归并排序呈现给人的是一个总分总的结构 先将一段完整的区间递归分为许多小的单元 在将小的单元回溯 成为原来的区间段

非递归排序呈现给人的是 将递归版本的前半段去掉 (递归部分去掉)只保留回溯部分

这只是从思路图上 简单的提取 因为两种方法的实现是不相同的 非递归只是模仿递归的实现

具体见代码怎样实现(当然这个代码肯定不是完整正确的代码 判断思路是这样的 但是会有一些边界问题 你能否看的出哪里出来问题 当然 你也可以去调试 观察begin1 end1 begin2 end2看是否有越界的问题)^~^

void MergeSort(int* arr, int n)
{assert(arr);//开辟一个tmp临时数组 存储排序之后的数据int* tmp = (int*)malloc(sizeof(int) * n);if (tmp == NULL){printf("failed to allocate memory.");exit(-1);}int gap = 1;//相当于从归并排序的最小单元向最大单元开始循环比较while (gap < n){for (int i = 0; i < n; i += 2 * gap){//[i, i+gap-1] [i+gap,i+2*gap-1]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 (arr[begin1] > arr[begin2]){tmp[index++] = arr[begin2++];}else{tmp[index++] = arr[begin1++];}}while (begin1 <= end1){tmp[index++] = arr[begin1++];}while (begin2 <= end2){tmp[index++] = arr[begin2++];}}//将归并的数据拷贝回原数组for (int j = i;j < n; j++){arr[j] = tmp[j];}}gap *= 2;free(tmp);tmp = NULL;
}

刚开始 gap == 1 为什么这样做?有没有人产生过这样的疑问。

在前面就大致介绍了递归和非递归的大致实现方式

相当于非递归就只模仿了递归回溯的那部分 仅此而已

由上图可以看出 会有越界现象 所以上面代码是不完整的

具体应该怎样修改呢?

首先我们应分析问题 再从问题出发解决问题

具体问题分为三种

1,end1越界,那么后面的[begin2,end2]肯定就不存在了

2,end1没越界,但区间[begin2,end2]不存在

3,区间[begin2,end2]内有数据 说明begin2存在 end2存不存在就带考究了 存在就不会出问题了

那只有不存在时才会出问题

有没有人问 难道begin1就不会出问题吗?当然不会 为什么呢?你也不看看begin1=i 那又怎么样呢

它是由for循环控制的 出界的话循环就会停止的 这就不需要你担心了

既然问题分析完了 就该解决问题了

void MergeSort(int* arr, int n)
{assert(arr);//开辟一个tmp临时数组 存储排序之后的数据int* tmp = (int*)malloc(sizeof(int) * n);if (tmp == NULL){printf("failed to allocate memory.");exit(-1);}int gap = 1;while (gap < n){for (int i = 0; i < n; i += 2 * gap){//[i, i+gap-1] [i+gap,i+2*gap-1]int begin1 = i, end1 = i + gap - 1;int begin2 = i + gap, end2 = i + 2 * gap - 1;//end1越界 且 后面的区间不存在if (end1 >= n){end1 = n - 1;}//说明[begin2,end2]里面有数据 但是end2越界了if (end2 >= n){end2 = n - 1;}//既然你都不存在 那就让你这个区间不存在不就解决了吗if (begin2 >= n){begin2 = n;end2 = n - 1;}int index = i;while (begin1 <= end1 && begin2 <= end2){if (arr[begin1] > arr[begin2]){tmp[index++] = arr[begin2++];}else{tmp[index++] = arr[begin1++];}}//通过上面的循环 并不是所有的数据都被拷贝到 tmp数组 肯定有一区间段没有处理完while (begin1 <= end1){tmp[index++] = arr[begin1++];}while (begin2 <= end2){tmp[index++] = arr[begin2++];}}//将归并的数据拷贝回原数组for (int j = i; j < n; j++){arr[j] = tmp[j];}gap *= 2;}free(tmp);tmp = NULL;
}

上面的处理是对越界的代码进行修正处理

将上面的代码进行的修正处理还可以简化 下面就是简化后的代码以及完整的代码


#include<stdio.h>
#include<stdlib.h>
#include<assert.h>void Print(int* arr, int n)
{assert(arr);for (int i = 0; i < n; i++){printf("%d ", arr[i]);}printf("\n");
}void MergeSort(int* arr, int n)
{assert(arr);//开辟一个tmp临时数组 存储排序之后的数据int* tmp = (int*)malloc(sizeof(int) * n);if (tmp == NULL){printf("failed to allocate memory.");exit(-1);}int gap = 1;while (gap < n){for (int i = 0; i < n; i += 2 * gap){//[i, i+gap-1] [i+gap,i+2*gap-1]int begin1 = i, end1 = i + gap - 1;int begin2 = i + gap, end2 = i + 2 * gap - 1;end1越界 且 后面的区间不存在//if (end1 >= n)//{//    end1 = n - 1;//}说明[begin2,end2]里面有数据 但是end2越界了//if (end2 >= n)//{//    end2 = n - 1;//}既然你都不存在 那就让你这个区间不存在不就解决了吗//if (begin2 >= n)//{//    begin2 = n;//    end2 = n - 1;//}// 核心思想:end1、begin2、end2都有可能越界// end1越界 或者 begin2 越界都不需要归并if (end1 >= n || begin2 >= n){break;}// end2 越界,需要归并,修正end2if (end2 >= n){end2 = n - 1;}int index = i;while (begin1 <= end1 && begin2 <= end2){if (arr[begin1] > arr[begin2])//改升序或降序{tmp[index++] = arr[begin2++];}else{tmp[index++] = arr[begin1++];}}//通过上面的循环 并不是所有的数据都被拷贝到 tmp数组 肯定有一区间段没有处理完while (begin1 <= end1){tmp[index++] = arr[begin1++];}while (begin2 <= end2){tmp[index++] = arr[begin2++];}//将归并的数据拷贝回原数组for (int j = i; j <= end2; ++j){arr[j] = tmp[j];}}gap *= 2;}free(tmp);tmp = NULL;
}int main()
{int arr[] = { 8,9,6,5,7,4,1,2,3 };int sz = sizeof(arr) / sizeof(arr[0]);Print(arr, sz);MergeSort(arr, sz);Print(arr, sz);return 0;
}

有什么问题可以留言私信~

归并排序非递归——C语言讲解相关推荐

  1. 归并排序(非递归,Java实现)

    归并排序(非递归):自底向上 public class MergeSort {/*** @param arr 待排序的数组* @param left 本次归并的左边界* @param mid 本次归并 ...

  2. java 归并排序 非递归_归并排序-递归及非递归的JAVA实现

    归并排序介绍 平均时间复杂度: O(NLogN) 最好情况时间复杂度: O(NLogN) 最差情况时间复杂度: O(NLogN) 所需要额外空间: 递归:O(N + LogN), 非递归:O(N) 稳 ...

  3. 斐波那契数列,递归与非递归c语言实现

    问题描述:求解斐波那契数列,分别采用递归方式与非递归方式  =2" class="mathcode" src="https://private.codecogs ...

  4. 归并排序 | 递归 非递归 |C语言

    一.递归算法 // L = 左边起始位置,R = 右边起始位置,RightEnd = 右边终点位置 void Merge(ElementType A[], ElementType TmpA[], in ...

  5. c语言归并排序数组不固定,归并排序非递归实现C语言

    话说这个东西写到凌晨3点27分,都没有写好.刚才睡醒了写完的.主要遇到的问题就是当数组大小不是2的幂的时候发生的 right_end 越界的时候.我的逻辑起初偏于复杂,后来重新组织逻辑,当发生 rig ...

  6. 二叉树的非递归遍历(前序中序后序非递归C语言)

    前两天做数据结构实验,要求用非递归算法遍历二叉树.只知道用栈来储存数据,具体算法还不太清楚.经过两天的搜索,看到网上很多种解法,很多解法都是用C++来写的算法,一直找不到用C语言写的算法,所以就总结了 ...

  7. polar SC译码(非递归) C语言+matlab混和编程

    #include<stdio.h> #include<math.h> #include<stdlib.h> #include "mex.h" / ...

  8. 排序下---(冒泡排序,快速排序,快速排序优化,快速排序非递归,归并排序,计数排序)

    排序上 排序上 交换类排序 基本思想:所谓交换,就是根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置,交换排序的特点是:将键值较大的记录向序列的尾部移动,键值较小的记录向序列的前部移动. ...

  9. 计算机算法设计与分析 递归实现归并排序和非递归实现归并排序

    递归实现归并排序 输入排序的数组的长度,程序用随机数生成对应的数组,之后递归调用排序,排序过程中思想类似于二分,当每个最小分组中只有一个元素时开始返回,直到排完整个数组. #include<bi ...

最新文章

  1. Java培训都学什么
  2. STL的一些基本概念
  3. 皮一皮:谁没有年少轻狂过...
  4. python在哪里写代码比较适合-AI辅助写代码,Python之父都爱不释手的工具
  5. 深度学习(二十八)——SOM, Group Normalization, MobileNet, 花式卷积进阶
  6. ABP入门系列(15)——创建微信公众号模块
  7. SecureCRT护眼设置
  8. 爬取了 B 站上的 17398 条评论,分析这部二次元番剧为何受到技术宅的追捧?
  9. java json 转数据_Java解析(读取)Json数据{}、[{}](转)
  10. ScheduledThreadPoolExecutor之scheduleWithFixedDelay和scheduleAtFixedRate的区别
  11. 《Python编程从入门到实践》———第一章
  12. Git 使用源代码包编译、配置部署和使用 使用包管理工具安装
  13. 5.JVM三大性能调优参数:-Xms -Xmx -Xss
  14. 光子晶体和深度学习结合进行多相流检测
  15. Itext中强行调整行高缩小行间距
  16. 3、哈哈哈-(2)hahaha1.py
  17. 手机使用计算机网络打印机,手机也可连接打印机 NETGEAR WNDR4700 无线打印
  18. 从哪里租vps远程桌面服务器,租vps远程桌面服务器
  19. 非985/211面试大厂校招经历经验总结(安全工程师/渗透工程师)
  20. vue简单的复制粘贴功能 this.$copyText()

热门文章

  1. python3爬取微博评论教程_用python 爬取微博评论,怎么打开微博评论下的查看更多|...
  2. 这次的深夜食堂来到了清迈,只为寻找那些…
  3. Openzeppelin库第八期:Crowdsale
  4. TIA博途_OB组织块的功能和使用方法介绍
  5. mysql创建单表只读访问用户及过程问题处理:如mysql: command not found ///GRANT command denied to user
  6. 优秀互联网面试题总结
  7. 一篇文章解读人工智能的原理及产业升级机会
  8. foxmail清除无法清除的未读邮件
  9. 计算机怎样禁用中等加密算法,限制加密算法和协议 - Windows Server | Microsoft Docs...
  10. WMS系统学习之ModernWMS