归并排序(递归,非递归)
目录
写在前面的话
一,归并思想
二,归并排序递归实现
2.1思想实现
2.2排序实现
2.3代码实现
三,归并排序非递归实现
3.1思路实现(小区间优化)
3.2边界值处理
3.2代码实现
写在前面的话
小伙伴们大家好啊!今天依旧小菜鸡库森,为大家带来的是有关归并排序的内容,好的,那么我们废话不多说,直接进入主题。
一,归并思想
那么首先,对于归并,从其字面意思来说,其实就是将两个事物合二为一。
其次,我们则需要这两个需要排序的事物是有序的,如果不是有序的,那么是不能进行归并排序的,因为这是归并的前提条件。
二,归并排序递归实现
2.1思想实现
好的,那么首先,我们的思路是依旧是“大事化小”,采用“分治”的思路实现。
如下图所示(升序为例):
我们既然想要归并,那么首先我们需要两个数组,然后比较他们中的数据,将较小的数放入一个新数组,然后依次比较存入,最后将剩余的那个数组的数直接拷贝到新数组即可。这样就完成了一次归并排序。(如果对于归并思想不是很理解的同学,可以移步 up 主的另一篇文章哦!牛客网第100题:有序序列合并_菜还不承认的库森的博客-CSDN博客目录思路代码实现本文将为大家带来一篇有关有序序列合并的文章。主要内容是:两个有序序列,将两个序列合并后,输出一个有序序列。在此我们规定:1.两个序列中的每个值范围均为:【0~100】2.两个序列的长度均为:【0~50】在开始合并之前:我们通过键盘输入两个升序序列,如图所示:思路首先,该两个序列均为有序序列,所以我们的思路如下:第一步:将两个序列的第一个元素进行比较,假设某一序列的首元素比较大,则将该值打印,然后将序列首元素的位置向后移动一位,指向第二个元素,此.https://blog.csdn.net/qq_52777887/article/details/122809339?spm=1001.2014.3001.5502
但是我们做上一步的前提是:这两组数必须是有序的,如果不是有序的,那么比较之后插入的元素依旧可能是乱序的。
所以对于归并排序而言,最主要问题的就是如何将这两组数变成有序的两组数。
2.2排序实现
那么这里首先我们用最熟悉的递归实现。如下图所示:
采用“分治”的思想,我们将一组数无限化小,直到每个数组中只剩余一个元素(这里的判断条件一定是头指针 begin 不再小于尾指针 end ),此时我们可以保证这两个数组一定是有序的,所以接下来我们只需要对其进行归并到新数组 tmp 中,然后再将其拷贝到原数组(这里一定不能忘记考回原数组,如果不考回,那么原数组的元素依旧没有发生变化)。
然后再层层归并拷贝,最后两个数组归并拷贝到一起之后,便完成了我们的归并排序。
2.3代码实现
void _MergeSort(int* a, int begin, int end, int* tmp)
{if (begin >= end){return;}int keyi = (begin + end) / 2;_MergeSort(a, begin, keyi ,tmp);_MergeSort(a, keyi + 1, end, tmp);//归并,从 tmp 数组拷贝到 a int begin1 = begin, end1 = keyi;int begin2 = keyi + 1, end2 = end;int i = begin;while (begin1<=end1 && begin2 <= end2){if (a[begin1] > a[begin2]){tmp[i++] = a[begin2++];}else{tmp[i++] = a[begin1++];}}while (begin1 <= end1){tmp[i++] = a[begin1++];}while (begin2 <= end2){tmp[i++] = a[begin2++];}for (int j = begin; j <= end; j++){a[j] = tmp[j];}
}void MergrSort(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);assert(tmp);_MergeSort(a, 0, n - 1, tmp);//释放free(tmp);tmp = NULL;
}
三,归并排序非递归实现
3.1思路实现(小区间优化)
好的,那么上面我们通过递归思路实现了归并排序,接下来我们通过非递归实现一下。
如下图所示:
这里我们的思路是,首先将一组数通过 gap 划分为 n 个数组(实际上并没有实际的数组,只是我们将其认为是数组),然后对其进行比较归并。
第一次当 gap 为 1 的时候,我们将距离为 1 的两个数组(其实就是两个元素为 1 的数)进行归并,得到了拥有两个元素的一个有序数组,然后通过循环将后面的元素全部用同样的方式归并。然后就得到了如上图所示蓝色表示的元素排布。
同时我们在将这一步骤之后的数组拷贝回到原数组。在进行接下来的操作(这里的意思和上递归的是一样的)。
接着每次将 gap 的值增加 2 倍,直到 gap 的值不小于 n 结束归并。
这个过程我们将其称为小区间优化。
3.2边界值处理
那么因为在归并的时候,这里我们需要将每两个小区间进行归并,所以这里仍旧涉及到四个指针的问题,那么接下来我们对四个指针的越界问题逐一修正。
1.首先我们考虑到的是因为 begin1 的值是循环的次数 i,所以不需要考虑其是否越界。
2.其次就是如果 end1 越界,说明在这个归并中,只剩一个数 begin1 了,此时它就是有序的,而且这组数说明也有序了。所以我们不进行归并,直接退出循环。
3.对于begin2越界也是同样的,不需要做任何处理,因为前面的数组本来就是有序的,如果begin2所在的数组不为空,那么我们才需要归并,如果不是,那么就不需要做任何处理了。
4.那么当 end2 越界时,如下所示,我们需要作出调整:
边界值处理代码展示:
3.2代码实现
void MergeSortNonR(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);assert(tmp);int gap = 1;//外层循环,控制gap的值,gap每次增加二倍while (gap < n){//n是数组元素个数for (int i = 0; i < n; i += 2 * gap){//归并 [i,i+gap-1] [i+gab,i+2*gap-1]int begin1 = i, end1 = i + gap - 1;int begin2 = i + gap, end2 = i + 2 * gap - 1;//处理边界值//如果是 end1 越界或者 begin2 越界,直接退出即可,不需要归并if (end1 >= n || begin2 >= n){break;}//如果是 end2 越界。需要归并if (end2 >= n){end2 = n - 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++];}//小区间优化拷贝回数组afor (int j = i; j <= end2; j++){a[j] = tmp[j];}}gap *= 2;}//释放free(tmp);tmp = NULL;
}
好的,那么对于归并排序的问题到这里就结束啦,如有问题,还请留言评论哦!
归并排序(递归,非递归)相关推荐
- 排序算法杂谈(三) —— 归并排序的非递归实现
1. 递归 在众多排序算法中,归并排序(Merge Sort)和快速排序(Quick Sort)都是时间复杂度为 O(nlog2n) 的高效排序. 这两种排序有一种共性,就是运用到了递归的思想. 在程 ...
- 归并排序详解(递归+非递归)
目录 归并排序 归并排序的思想 递归实现 非递归实现 归并排序 归并排序和之前讲的快速排序.希尔排序.堆排序一样,时间复杂度是O(N*logN). 它相对难理解一点,接下来我就从递归以及非递归两个方面 ...
- 归并排序(递归+非递归)
目录 一.什么是归并排序? 二.归并排序(递归) 三.归并排序(非递归) 一.什么是归并排序? 归并排序,是创建在归并操作上的一种有效的排序算法.算法是采用分治法(Divide and Conquer ...
- 一文彻底搞定二叉树的前序、中序、后序遍历(图解递归非递归)
前言 大家好,我是bigsai,在数据结构与算法中,二叉树无论是考研.笔试都是非常高频的考点内容,在二叉树中,二叉树的遍历又是非常重要的知识点,今天给大家讲讲二叉树的层序遍历. 这部分很多人可能会但是 ...
- java 建树源码_Java实现的二叉树常用操作【前序建树,前中后递归非递归遍历及层序遍历】...
import java.util.ArrayDeque; import java.util.Queue; import java.util.Stack; //二叉树的建树,前中后 递归非递归遍历 层序 ...
- 快排递归非递归python_Python递归神经网络终极指南
快排递归非递归python Recurrent neural networks are deep learning models that are typically used to solve ti ...
- c语言折半查找递归程序,C语言数据结构中二分查找递归非递归实现并分析
C语言数据结构中二分查找递归非递归实现并分析 前言: 二分查找在有序数列的查找过程中算法复杂度低,并且效率很高.因此较为受我们追捧.其实二分查找算法,是一个很经典的算法.但是呢,又容易写错.因为总是考 ...
- 二叉树的深度(前序 中序 后序 递归非递归搜素)、广度、搜索 C++
a b c 使用 1 2 3 表示 /* 描述:二叉树的深度(前序 中序 后序 递归非递归搜素).广度.搜索 作者:jz 日期:20140819 */ #include<stdio.h> ...
- 二叉树——中序遍历(递归/非递归)
中序遍历,即遍历顺序为:左节点.根节点.右节点. 二叉树节点: public class Node {public Node left;public Node right;public int val ...
- 树的深度 递归非递归实现
树的深度 递归非递归实现 package com.dugstudio.SwordToOffer;import java.util.LinkedList;/*** 树的深度递归和非递归算法*/ clas ...
最新文章
- c#获取应用程序目录
- tab s6 linux on dex,S Pen + DeX模式 三星Galaxy Tab S6让你秒变办公达人
- 《xUnit Test Patterns》学习笔记6 - Test Double
- 原生js绑定click为什么点一次执行两次_前端小知识10点(2020.10.8)
- 【BZOJ】1679: [Usaco2005 Jan]Moo Volume 牛的呼声(数学)
- python2.7输出语句_python2.7入门---模块(Module)
- Android笔记 动画之tween(补间)动画demo
- 恒大汽车参展车辆竟全都是模型;华为官宣卖车,门店连夜上新摆车...
- Backbone 学习笔记
- 无线通信信道的衰落特性(大尺度衰落和小尺度衰落)
- 《老罗Android开发视频教程》
- windows批量转换网易ncm音乐
- ML Mastery 博客文章翻译 20220116 更新
- CAD中打开CAD图纸看不到内容怎么办?
- 2.flask模板--jinja2
- Python游戏概率保底算法PRD的实现
- pcb焊接的一些技巧
- Quartus联合modelsim的ip核仿真——以FIFO为例——(报错问题解决)
- 数据库中查询经纬度距离远近
- Openlayers 6 零基础教程