排序算法总结——归并排序

2023-10-29

1. 算法原理及步骤

2. 代码实现

3. 复杂度分析

4. 稳定性分析


1. 算法原理及步骤

       归并排序体现的是一种分治+合并的思想,我们知道,数组长度越小,排序越简单,而不管数组有多大,都是由小数组构成的,因此,要想对一个长度为N的数组进行排序,就可以将其进行分割,分割到大小为1的小数组,然后再将每个小数组进行排序再合并,最终合并为有序的原数组,如图所示:

       由图可知,归并排序主要是将原数组拆分成长度为1的小数组中,然后再将这些小数组两两归并再排序,然后再将归并后的数组两两归并再排序.....最终归并为长度为n的数组再对其进行排序即可。那么问题来了:归并最终也要对n的数组排序呀,它的效率体现在哪里呢?

        实际上,在每两个小数组归并的过程中,都是会对其归并结果进行排序的。最小的数组长度就是1,本身就是有序的,两个长度为1的数组再进行合并成长度为2的小数组并对其进行排序,然后再归并、再归并、....再归并为n的数组,可以发现,每次进行归并的两个小数组都是分别有序的,这就是归并排序能体现其效率的关键:相比于对无序数组排序,合并两个有序数组的时间复杂度只需要O(N)。

       因此,归并排序最关键的就是对两个有序数组进行排序了,可以采用双指针的方法,一开始分别指向两个数组头部元素,然后比较二者大小,将较小的作为合并结果的第一个元素,然后将较小数的指针往后移动一步,然后再比较,再将较小的作为合并结果的第二个元素......直到其中某一个指针走到尾部了,那么此时只需要将还没到尾的另一个数组剩下的元素直接按序放入合并数组的后面即可,整个过程如图所示:

     通过以上可以知道,归并排序实际上就是数组分割+合并排序。而其中数组分割是将数组二分为左半区间和右半区间,然后再对左半区间、右半区间进行二分.....直到最终数组长度为1,而合并排序即是对长度为1的数组开始自下而上开始两两归并并排序,最终得到有序的原数组。(以上图片来自于https://www.cnblogs.com/chengxiao/p/6194356.html

       总结可得递归排序的步骤:

       ①找到中点;

       ②根据中点划分左子区间及右子区间,并且分别递归两子区间;

       ③合并递归后的子区间。


2. 代码实现

void mergeTwoSortedParts(vector<int>& nums,int left,int right,int mid)//合并数组中的两个有序子区间,需要指定整个区间范围以及划分出子区间的中点
{
    int i=left;   //指向左区间头
    int j=mid+1;  //指向右区间头
    vector<int>temp;  //临时数组存放合并结果

    while(i<=mid&&j<=right)
    {
        if(nums[i]<nums[j])temp.push_back(nums[i++]);  //如果左区间数较小就放到临时数组中,然后左指针右移
        else temp.push_back(nums[j++]); //如果右区间数较小就放到临时数组中,然后右指针右移
    }

    if(i<=mid)  //如果左区间还没遍历完,直接将左区间剩下的接在临时数组后面
    {
        for(int l=i;l<=mid;l++)temp.push_back(nums[l]);
    }

    if(j<=right) //如果右区间还没遍历完,直接将右区间剩下的接在临时数组后面
    {
        for(int l=j;l<=right;l++)temp.push_back(nums[l]);
    }
    for(auto x:temp)nums[left++]=x;  //此时临时数组已经排好序,将临时数组复制到原数组中即可
    return ;
}
void divArraySort(vector<int>& nums,int left,int right)//分割排序函数,参数为待排序数组及区间
{
    if(right-left==0)return ; //数组分割到长度为1时返回

    int mid=left+(right-left)/2;  //取中点二分

    divArraySort(nums,left,mid); //分割左子区间并排序
    divArraySort(nums,mid+1,right); //分割右子区间并排序
    
    mergeTwoSortedParts(nums,left,right,mid); //对排序好的左子区间和右子区间进行合并排序
    return ;

}
void MergeSort(vector<int>& nums,int len) //归并排序函数,参数为待排序函数及其长度
{
    if(!len)return;
    divArraySort(nums,0,len-1);  //归并排序
    return;
}

3. 复杂度分析

       不难看出,归并排序的过程实际就是将原数组不断二分,到最后子数组长度为1,二分的次数当然就是logN次了,而另一方面,每一次二分都还需要将二分的数组再合并排序,这个排序的过程就是O(N)了,因此整个归并排序不管是最好情况还是最坏情况都一样,时间复杂度就是O(NlogN),当然其中还包括临时数组向原数组赋值的O(N)时间复杂度。在空间复杂度方面,开销主要是由合并排序引起的,合并排序需要一个与原数组大小相同的临时数组来存放合并结果,因此空间复杂度为O(N)

4. 稳定性分析

       由归并过程可知,只会改变两个有大小关系的元素间的位置,对于相等元素是不会改变二者相对位置的,因此归并排序是稳定的。

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

排序算法总结——归并排序 的相关文章

  • 数组随机排序的两种实现方法

    1 利用数组中的sort 方法 arr arr sort gt Math random 0 5 2 Fisher Yates Shuffle 复杂度为O n 从后向前遍历 不断将当前元素与随机位置的元素 除去已遍历的部分 进行交换 func
  • 数据结构<1>时间复杂度详解和leetcode例题

    文章目录 什么是时间复杂度和空间复杂度 前言 算法效率 时间复杂度的计算 空间复杂度的计算 oj练习 什么是时间复杂度和空间复杂度 前言 算法效率 算法效率分析分为两种 第一种是时间效率 第二种是空间效率 时间效率被称为时间复杂度 而空间效
  • 排序算法——比较类排序算法讲解以及c++实现

    首先我先抛一个老哥的博客 我是看着他的博客来学习理解 地址 https www cnblogs com onepixel p 7674659 html 首先说一下排序算法分为2类 一类是比较类排序算法 另一类是非比较类排序 这里主要讲常用的
  • 转-各种排序动图

    1 快速排序 介绍 快速排序是由东尼 霍尔所发展的一种排序算法 在平均状况下 排序 n 个项目要 n log n 次比较 在最坏状况下则需要 n2 次比较 但这种状况并不常见 事实上 快速排序通常明显比其他 n log n 算法更快 因为它
  • 快速排序————非递归实现

    二 递归实现快速排序 2 1 为什么我们要去通过递归实现我们的快速排序呢 大家有可能会想是不是因为递归非常的占用空间 我们都知道我们的局部变量是保存在栈上的我们的函数参数也是在栈上开辟的 所以说递归是不是会占用我们非常多的栈空间 同时呢我们
  • 数据结构-将升序数组转化为平衡二叉搜索树-java

    1 题目 给定一个升序排序的数组 将其转化为平衡二叉搜索树 BST 平衡二叉搜索树指树上每个节点 node 都满足左子树中所有节点的的值都小于 node 的值 右子树中所有节点的值都大于 node 的值 并且左右子树的节点数量之差不大于1
  • CDZSC_2022寒假个人训练赛21级(2)

    A 题解 输出n 1 2 3 4 即可 include
  • C语言算法--冒泡排序

    C语言算法 冒泡排序 1 什么是冒泡排序 冒泡排序是一种简单的排序算法 它通过比较相邻元素的大小 并根据需要交换它们的位置来排序数据 它的名称来自于越小的元素会慢慢 冒泡 到数组的开头 冒泡排序的基本思想是从数组的第一个元素开始 依次比较相
  • 【数据结构】——八大排序

    文章目录 1 插入排序 2 冒泡排序 3 希尔排序 4 选择排序 5 快速排序 快排优化 递归改非递归 6 堆排序 7 归并排序 递归归并排序 改成非递归 8 计数排序 9 题目 总结 排序的时间检验 对于不同排序的时间复杂度分析 1 插入
  • 8-13外部排序-败者树

    败者树是树形选择排序的一种变体 可视为一棵完全二叉树 通过败者树 可以在k个归并段中选出最小关键字所需要的关键字对比次数更少 绿色为叶子结点 存放初始数据 黑色为失败结点 蓝色为胜出结点 一 基本过程 以下按从小到大的方式构建 1 从8个归
  • 大数据量的冒泡排序 (计次数)

    题目描述 给定一个包含从0到n 1各一次的数组 若使用冒泡排序将其排为升序 问其中需要进行多少次交换 输入 测试数据有多组 每组由两行组成 第一行包含正整数n n lt 5000 下一行包含从0到n 1的n个整数的序列 输出 对于每组测试数
  • C++容器排序算法的简单应用

    功能实现 1 去掉所有重复的单词 2 按照单词的长度进行排序 3 统计长度等于或者超过6个字符的单词个数 4 按照单词的长度顺序进行输出 include
  • Java 常用的大算法详解

    Java 常用的大算法详解 排序算法是计算机科学中的重要主题之一 Java 提供了许多常用的排序算法 本文将详细介绍其中的几种 并提供相应的源代码实现 冒泡排序 Bubble Sort 冒泡排序是一种简单直观的排序算法 它重复地遍历待排序的
  • 快速排序(三种算法实现和非递归实现)

    快速排序 Quick Sort 是对冒泡排序的一种改进 基本思想是选取一个记录作为枢轴 经过一趟排序 将整段序列分为两个部分 其中一部分的值都小于枢轴 另一部分都大于枢轴 然后继续对这两部分继续进行排序 从而使整个序列达到有序 递归实现 v
  • 分治-归并算法——LCR 170. 交易逆序对的总数

    文章目录 0 归并排序 1 题目 2 算法原理 3 代码实现 0 归并排序 归并排序是典型的分治 将数组分成若干个子数组 数组两两比较 不是很清楚的 可以查看此篇文章 数据结构 七大排序 这里以力扣 9
  • 分治-归并排序

    文章目录 315 计算右侧小于当前元素的个数 1 题目 2 算法原理 3 代码实现 493 翻转对
  • 详解十大经典排序算法(四):希尔排序(Shell Sort)

    算法原理 希尔排序是一种基于插入排序的排序算法 也被称为缩小增量排序 它通过将待排序的序列分割成若干个子序列 对每个子序列进行插入排序 然后逐步缩小增量 最终使整个序列有序 算法描述 希尔排序 Shell Sort 是一种基于插入排序的算法
  • 八大排序(希尔排序)

    上篇文章我们来看了看插入排序是怎么实现的 本章内容就是在插入排序的基础上完成希尔排序 希尔排序是一个比较强大的排序 我们希尔排序的时间复杂度是比较难算的 这里直接给出的结论就是时间复杂度就是O N 1 3 比较难算的原因就是我们每一次的次数
  • 数组对象排序 (arr.sort())

    前端面试题库 面试必备 推荐 地址 前端面试题库 对象排序 arr sort 描述 方法sort 将在原数组上对 数组元素 进行排序 即排序时不创建新的数组副本 如果想按照别的顺序进行排序 就必须提供比较函数 该函数要比较两个值 然后返回一
  • 冒泡排序/选择排序/插入排序/快速排序/归并排序/桶排序/堆排序/希尔排序/计数排序/基数排序/二分查找/广度优先搜索/深度优先搜索

    排序算法 冒泡排序 Bubble Sort 通过重复地比较相邻的元素并交换它们 使得最大 或最小 的元素逐渐移动到列表的一端 从而实现排序 选择排序 Selection Sort 在未排序的部分中 选择最小 或最大 的元素 并将其放置在已排

随机推荐