归并排序与快速排序总结-c++

news2024/11/24 23:03:55

一,归并排序

归并排序(Merge sort)是建立在归并操作上的一种有效的排序算法。该算法分治法(Divide and Conquer)的一个非常典型的应用。

作为一种典型的分而治之思想的算法应用,归并排序的实现由两种方法:

1.自上而下的递归(所有递归的方法都可以用迭代重写)
2.自下而上的迭代
1.基本思想

归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。

在这里插入图片描述
简而言之,先通过递归的思想将数组分成一个一个的不可再分的子序列,接下来再对其中两个子序列按照升序或者降序合并,重复直到合并所有子序列合并完成。(子问题其实就是两个有序数组的合并)。

2.程序实现
#include<iostream>
using namespace std;
#define eleType int

//合并两个有序子序列
/*
参数含义: arr数组, left:序列的左边起始点 mid:中间下标 right:右边结束点
通过left mid right 将arr分成左右两个区域
*/
void merge(eleType *arr,int left,int mid,int right){
    int i = left, j = mid + 1;  // i为左边区域的指针 j 为右边区域的指针
    eleType *temp = new eleType[right + 1]; //临时数组,用来临时存放排序后的数字
    int index = 0; //临时数组的下标
    while(i <= mid && j <= right){ //当左右区域都有未比完的数字
        temp[index++] = arr[i] < arr[j] ? arr[i++] : arr[j++]; //选择较小的存入temp数组
    }
    while(i <= mid){ //当仅剩左边区域
        temp[index++] = arr[i++]; // 按顺序存入temp
    }
    while(j <= right){ //当仅剩右边区域
        temp[index++] = arr[j++]; //按顺序存入temp
    }
    for(int i = 0; i < index; i++){ //将temp重新放回arr
        arr[left + i] = temp[i];
    }
    delete [] temp; //删除临时temp数组
}
//归并排序
/* 
 参数含义: left:最左边下标  right : 最右边的下标
 通过left 和right 计算出中间数的下标
*/
void mergesort(eleType *arr,int left,int right){
    if(left < right){ //递归条件
        int mid = left + (right - left) / 2; //计算中间下标
        mergesort(arr,left,mid); //递归划分左边区域
        mergesort(arr,mid + 1, right);//递归划分右区域
        merge(arr,left,mid,right); //执行合并
    }
}
3.优缺点:

优点
稳定性: 稳定的排序算法,即相同元素的相对顺序在排序前后保持不变。
最佳、平均和最坏时间复杂度:归并排序在所有情况下(包括输入数组已排序或逆序)的时间复杂度都是O(n log n),n是数组的大小。它在处理大数据集时非常高效。
空间复杂度:虽然归并排序需要额外的空间来存储临时子数组,但它的空间复杂度是O(n),在实际应用中通常是可以接受的。
缺点
空间复杂度:虽然O(n)的空间复杂度可以接受的,但对于内存受限的环境或需要就地排序的场合,归并排序不是最佳选择。
数据移动次数:归并排序在合并过程中可能需要大量的数据移动操作,这可能导致在某些情况下效率较低。
不适合小数据集:对于非常小的数据集,归并排序的额外空间开销和递归调用相对于其他简单排序算法效率较低。但是在大数据集上,归并排序的O(n log n)时间复杂度远优于这些简单排序算法。
递归深度:归并排序是递归算法,对于非常大的数据集,递归深度可能会很大,可能导致栈溢出。

二,快速排序

1.基本思想

通过一次排序将待排序的数据分割成独立的两部分,其中一部分的所有数据都比另一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
在这里插入图片描述

2.实现步骤
  • 1.选择一个基准元素(pivot):通常选择待排序序列的第一个或最后一个元素作为基准。
  • 2.分割过程:将序列中小于基准的元素放在基准的左边,大于基准的元素放在基准的右边。这个过程称为分区(partition)操作,分区结束后基准元素所处的位置就是其在已排序序列中的正确位置。
  • 3.递归排序:分别对基准左右两边的子序列进行快速排序。
3.代码实现
#include<iostream>
using namespace std;
#define eleType int
/* 
	划分 将比基准数大的放右边,比基准数小的放左边
参数含义: arr数组,left:最左边的下标 right: 最右边的下标
*/

int getKeyPositon(eleType *arr,int left,int right){
    int key = arr[left]; //将第一个数作为基准数
    while(left < right){
        while(arr[right] >= key && left < right){ //右边先移动,找比基准数小的
            right--;
        }
        arr[left] = arr[right]; //找到之后赋值给左边left的位置
        while(arr[left] <= key && left < right){ //之后左边移动,找比基准数大的
            left++;
        }
        arr[right] = arr[left];//找到之后赋值给右边right的位置
    }
    arr[left] = key; //左右指针相遇之后,将基准数放回相遇的位置
    return left; //返回基准数的位置
}
/*
排序过程,不停的基准数放到正确位置
参数含义: arr数组,left:最左边的下标 right: 最右边的下标
*/
void quickSort(eleType *arr,int left,int right){
    if(left < right){ //递归条件
        int position = getKeyPositon(arr,left,right); //基准数归位之后,数组被分成左右两部分
        quickSort(arr,left,position - 1); //对左边部分排序
        quickSort(arr,position + 1,right); //对右边部分排序
    }
}
优缺点

优点:
速度快:在平均情况下,快速排序的时间复杂度为O(n log n),比许多排序算法都要快。
原地排序:只需要一个很小的栈空间来保存递归的调用,不需要额外的存储空间。
缺点:
最坏情况:在最坏情况下(输入数据已经有序或接近有序),快速排序的时间复杂度会退化到O(n^2)。
空间复杂度:虽然快速排序是原地排序,但在递归调用时可能会占用较大的栈空间。对于非常大的数据集,会导致栈溢出。
对基准元素的选择敏感:基准元素的选择会影响到排序的性能。如果每次选择的基准元素都是序列中最小或最大的元素,排序的效率就会降低。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1861378.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

机器学习/pytorch笔记:time2vec

1 概念部分 对于给定的标量时间概念 t&#xff0c;Time2Vec 的表示 t2v(t)是一个大小为 k1的向量&#xff0c;定义如下&#xff1a; 其中&#xff0c;t2v(t)[i]是 t2v(t)的第 i 个元素&#xff0c;F是一个周期性激活函数&#xff0c;ω和 ϕ是可学习的参数。 以下是个人理解&am…

最热门的智能猫砂盆好不好用?这期统统告诉你!

身为上班族的我们&#xff0c;常常被工作和出差填满日程。忘记给猫咪铲屎也不是一次两次了。但我们必须意识到&#xff0c;不及时清理猫砂盆不仅会让猫咪感到不适&#xff0c;还可能引发泌尿系统感染、皮肤疾病等健康问题。为了解决这个问题&#xff0c;越来越多的铲屎官开始将…

JavaWeb——MySQL:navicate客户端工具简单使用

目录 1. 连接 2. 新建数据库 3. 使用数据库 4. 新建表 5.使用表 6. 导出数据库 我这里是英文版&#xff0c;没有进行汉化。 1. 连接 点击左上角Connection&#xff0c;选择MySQL&#xff0c;&#xff08;我连接的是自己计算机上的数据库&#xff09;连接名输入&#x…

Java面试题:聚簇索引和非聚簇索引

聚簇索引和非聚簇索引 聚簇索引(聚集索引) 将数据的存储和索引放在一块,索引结构的叶子节点保存了行数据 索引字段必须存在,且只能存在一个 非聚集索引(二级索引) 将数据和索引分开存储,索引结构的叶子节点关联的是对应的主键 索引字段可以存在多个 索引的选取规则 如果…

Unity2D - 碰撞检测及边界检测

1. 地面检测 1.1 地面检测的逻辑及代码 一般情况下&#xff0c;对于手人物进行事件处理或动作处理时&#xff0c;我们需要判定人物是否在地面上&#xff0c;这个时候最好的方式是设定地面碰撞器&#xff0c;只有角色在地面时才可以进行跳跃; 我们可以想象物体的重心向地面延伸…

Java的gui开发-Swing如何一键打包exe、dmg等

java的gui开发其实很方便&#xff0c;性能也不错&#xff0c;知名的idea开发工具也是java-swing开发&#xff0c;只是用的人少&#xff0c;看了我的例子3分钟就能学会&#xff0c;分分钟写桌面端&#xff0c;下面教你如何一键打包windows端exe Java-Swing-Template java的gui开…

解决SD卡被写保护问题

存储卡在使用过程中&#xff0c;有时会遇到写保护问题&#xff0c;导致无法写入或删除数据。这可能会对用户的正常使用造成困扰。MK米客方德将为您介绍几种常见的解决方法&#xff0c;帮助用户解除存储卡的写保护。 一、检查物理写保护开关 许多存储卡&#xff0c;如SD卡&…

深入剖析Tomcat(十二) 详解StandardContext

StandardContext是Context容器的一个标准实现&#xff0c;一般情况下&#xff0c;Tomcat都是使用StandardContext类来创建Context容器。前面讲过&#xff0c;Context容器代表了一个Web应用&#xff0c;Tomcat本身支持部署多个应用&#xff0c;相应的每个应用都会有一个Standard…

解锁小红书新玩法:中小企业出海营销的集成策略

随着全球数字化浪潮的推进&#xff0c;小红书作为生活方式分享平台的崛起&#xff0c;为中小企业提供了一个全新的营销舞台。NetFarmer&#xff0c;作为专注于企业数字化出海的服务商&#xff0c;深谙小红书的营销策略&#xff0c;并致力于通过HubSpot产品销售与实施&#xff0…

spring boot jar 启动报错 Zip64 archives are not supported

spring boot jar 启动报错 Zip64 archives are not supported 原因、解决方案问题为什么 spring boot 不支持 zip64zip、zip64 功能上的区别zip 的文件格式spring-boot-loader 是如何判断是否是 zip64 的&#xff1f; 参考 spring boot 版本是 2.1.8.RELEASE&#xff0c;引入以…

Chrome开发者工具学习

打开开发者工具&#xff1a; 可以通过在网页上点击右键并选择“检查”来打开。 或者使用快捷键Ctrl Shift I&#xff08;在Windows/Linux上&#xff09;或Command Option I&#xff08;在Mac上&#xff09;。 界面概览&#xff1a; 熟悉DevTools的基本面板&#xff0c;如“…

Mongo Express 未授权访问漏洞

【产品&&漏洞简述】 Mongo Express 是一个基于 Node.js 和 express 的开源的 MongoDB Web管理界面。Mongo Express存在未授权访问漏洞&#xff0c;攻击者可通过该漏洞获取用户信息或修改系统数据。 【资产测绘Query】 title"Home - Mongo Express" 【产品界…

期货交易中的几种常见心态管理

期货交易通常涉及到风险和收益的权衡&#xff0c;因此参与者的心态可以显著影响他们的决策和最终结果。以下是一些炒期货的常见心态&#xff1a; 1. 利润最大化心态&#xff1a;持有这种心态的投资者不关心风险&#xff0c;只考虑高利润。他们可能会盲目追求高回报&#xff0…

【D3.js in Action 3 精译】1.1.3 D3.js 的工作原理

译者注 上一节我们探讨了 D3.js 的适用场景——需要高度定制化、可以尽情释放想象力的复杂图表。这一节我们再跟随作者的视角&#xff0c;看看 D3.js 的工作原理究竟是怎样的。 1.1.3 D3.js 的工作原理 您可能已经体验过 D3 并且发现它不太容易上手。这也许是因为您把它当成了…

【Linux】使用信号进行进程间通信

&#x1f525;博客主页&#xff1a; 我要成为C领域大神&#x1f3a5;系列专栏&#xff1a;【C核心编程】 【计算机网络】 【Linux编程】 【操作系统】 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 本博客致力于知识分享&#xff0c;与更多的人进行学习交流 ​ ​ 实现原理&a…

互联网直播/点播技术与平台创新应用:视频推拉流EasyDSS案例分析

随着互联网技术的快速发展&#xff0c;直播/点播平台已成为信息传播和娱乐的重要载体。特别是在电视购物领域&#xff0c;互联网直播/点播平台与技术的应用&#xff0c;不仅为用户带来了全新的购物体验&#xff0c;也为商家提供了更广阔的营销渠道。传统媒体再一次切实感受到了…

QT学习积累——在C++中,for循环中使用``与不使用``的区别和联系

目录 引出使用&与不使用&除法的一个坑 总结自定义信号和槽1.自定义信号2.自定义槽3.建立连接4.进行触发 自定义信号重载带参数的按钮触发信号触发信号拓展 lambda表达式返回值mutable修饰案例 引出 QT学习积累——在C中&#xff0c;for循环中使用&与不使用&的…

MATLAB算法实战应用案例精讲-【数模应用】线性判别分析(附MATLAB、python和R语言代码实现)

目录 前言 算法原理 什么是判别分析 线性判别分析(LDA) 数学模型 二分类 多分类LDA ​编辑 算法思想: 费歇(FISHER)判别思想 贝叶斯(BAYES)判别思想 LDA算法流程 LDA与PCA对比 SPSSPRO 1、作用 2、输入输出描述 3、案例示例 4、案例数据 5、案例操作 …

新手教学系列——“笑看”单元测试(pytest)

探索单元测试的必要性 你是否曾经思考过,当前的业务场景是否真的需要单元测试?我们每个人负责的模块是否也需要单元测试?什么阻碍了我们进行单元测试呢?时间紧,任务重,还要写测试?这些都是我们在开发过程中常见的问题。假设我们有一个计划开发一周的项目,让我们看看有…

rapidocr-onnxruntime库及在open-webui上传PDF 图像处理 (使用 OCR)应用

背景 rapidocr-onnxruntime是一个跨平台的OCR库&#xff0c;基于ONNXRuntime推理框架。 目前已知运行速度最快、支持最广&#xff0c;完全开源免费并支持离线快速部署的多平台多语言OCR。 缘起&#xff1a;百度paddle工程化不是太好&#xff0c;为了方便大家在各种端上进行oc…