【CPP】交换排序:冒泡排序、快速排序

目录

  • 1.冒泡排序
      • 简介
      • 代码
      • 分析
  • 2.快速排序
    • 2.1霍尔版本
      • 简介
      • 代码
      • 分析
    • 2.2挖坑版本
    • 2.3前后指针版本
    • 2.4非递归的快排
      • 思路
      • 代码

什么是交换排序?
基本思想:所谓 交换,就是根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置,交换排序的特点是:将键值较大的记录向序列的尾部移动,键值较小的记录向序列的前部移动。
其中,冒泡排序快速排序 均属于 交换排序

1.冒泡排序

简介

略。
在这里插入图片描述

代码

在这里插入图片描述

分析

最好的时间复杂度:O(N)
最差的时间复杂度:O(N^2)

2.快速排序

基本思想:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。

下面是不同版本的快速排序:

2.1霍尔版本

简介

概述:快速排序属于交换排序的一种,是Hoare于1962年提出的一种二叉树结构的交换排序方法

在这里插入图片描述

思路:

  • 先选定key值,右边先走。
  • 右边找小,左边找大,左右交换
  • 重复第二步,直到left和right相遇与key进行交换

问:为什么相遇位置一定比key值小???
答:因为右边先走决定的。
分析:相遇有两种情况:

  • right 遇 left
    这时候相遇点是 left选定的位置
    • 假如说left是已经走过的,left是找大的,但是找到大之后会与right交换,所以left此时是小值。 汇合点是小值。
    • 假如说left一次都没有走过,right一路“滑铁卢”走到left的起始位置,left的起始位置是key值本身,汇合点是key值,key自己与自己交换没有影响。
  • left 遇 right
    能让left找到right,可以说明right已经找到了小,并且此时值并没有发生交换(因为右边先走!),然后此时right是小值,left遇到了right,汇合点也一定是小值。

代码

在这里插入图片描述

分析

这个版本的快排细节比较多,主要有下面坑:

  • left = begin + 1,问题就是当原数组恰好就是有序的时候反而用了快排会被打乱顺序。
  • while(left < right) 相遇即停止,写成小于等于那很容易造成越界问题。
  • while(left < right && arr[right] >= arr[keyi])
    • 容易造成左右指针错过问题
    • 容易导致arr[left] = arr[right] = arr[keyi]死循环问题
  • keyi = left;要及时更新keyi值,因为对于不同的递归下keyi值都是不同的。


快排与希尔排序:

  • 快排与希尔排序是一个量级的,在数据量巨大的情况下,
    • 若重复数据比较多,快排比较快一点;
    • 若重复数据比较少,希尔排序更快一点。
  • 然而序列有序情况下,快排很吃亏,很慢。

序列有序情况下,快排效率低下的原因分析及解决方法:
在这里插入图片描述
有序序列快排时间复杂度:O(N^2)
理想序列快排时间复杂度:O(N*logN)
总结来看,就是因为在有序序列情况下,快排每次的keyi值都是第一个数导致效率编程>了N^2的情况。注:如果是有序序列,几千的数就会因为递归深度太深而挂掉,因为要递归几千次。

结论:所以我们把keyi值选择不固定即可,可以随机选keyi值也可以三数取中(begin,end,mid)取中间值的下标。

解决方案:①三数取中 或 ②随机数选key
在这里插入图片描述

优化:小区间优化
在上面所说的排序中,其中最后三排的数字占了整个序列的大概百分之八十左右,也就是说为了最后三排的数字排序 多调用栈帧百分之八十左右
小区间优化:用插入排序进行优化(插入排序的小区间适应性更好)。
在这里插入图片描述

实际上,在DeBug环境下,效率大概可以略提升一些,感觉有十分之一吧。
在Release环境下,因为编译器对函数栈帧优化作用极大,以至于小区间优化的作用约等于没有,甚至不如没有小区间优化的版本。
正确代码:
在这里插入图片描述

void quickSort(int* arr, int begin, int end) /** begin指区间起始下标,end指区间最后数字下标 */ // 希望[begin,end]有序
{if (begin >= end) return; //begin > end 没有实际意义 ; begin == end 仅有一个数,当作keyi就结束了if (end - begin + 1 < 10) insertSort(arr + begin, end - begin + 1); // 小区间优化else{// 1.先控制单趟快排,希望[begin,key-1] < [key+1,end]int right = end;int left = begin;int midi = getMidi(arr, begin, end);swap(&arr[midi], &arr[begin]);int keyi = begin;while (left < right) // 相遇停止{while (left < right && arr[right] >= arr[keyi]) right--;while (left < right && arr[left] <= arr[keyi]) left++;swap(&arr[right], &arr[left]);}// 交换swap(&arr[keyi], &arr[left]);keyi = left;//更新下一个递归的keti值// 2.再控制整体多个递归quickSort(arr, begin, keyi - 1);quickSort(arr, keyi + 1, end);}
}

思考:为什么这个代码会有问题?
在这里插入图片描述
在这里插入图片描述

2.2挖坑版本

在这里插入图片描述
思路:

  • key先形成坑位
  • 右边先走,找到比key小的,放到左边的坑位
  • 左边再走,找道比key大的,放到右边的坑位
  • 直到left和right相遇

\

// 挖坑法
int PartSort2(int* a, int begin, int end)
{int midi = getMidi(a, begin, end);swap(&a[midi], &a[begin]);int key = a[begin];int hole = begin;while (begin < end){// 右边找小,填到左边的坑while (begin < end && a[end] >= key){--end;}a[hole] = a[end];hole = end;// 左边找大,填到右边的坑while (begin < end && a[begin] <= key){++begin;}a[hole] = a[begin];hole = begin;}a[hole] = key;return hole;
}

2.3前后指针版本

在这里插入图片描述
思路:cur是一个评判数字要掠过还是交换的角色,prev是一个保证其走过的路都是小值得一个角色。

  • 选定key值,cur先走
  • cur找到小值,prev++,cur与prev的值交换;cur++
  • cur找到大值,cur++;
int PartSort3(int* a, int begin, int end)
{int midi = getMidi(a, begin, end);swap(&a[midi], &a[begin]);int key = begin;int cur = begin + 1;int prev = begin;while (cur <= end){/*if (a[cur] < a[key]) {prev++; swap(&a[prev], &a[cur]);}*/if (a[cur] < a[key] && ++prev != cur) swap(&a[prev], &a[cur]);cur++;}swap(&a[prev], &a[key]);return prev;
}

2.4非递归的快排

思路

用循环写快排,只需要模拟递归的过程即可。
在这里插入图片描述

代码

在这里插入图片描述


EOF

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

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

相关文章

2.树莓派4b+ubuntu18.04(ros版本melodic)+arduino mega自制两轮差速小车,实现建图导航功能

这篇文章介绍arduino使用和安装arduino_bridge 将arduino与树莓派连接 查看arduino的端口号&#xff0c;我们这里查看到的时ttyUSB0 ll /dev/ttyUSB*将当前用户添加进dialout组 sudo usermod -a -G dialout your_user_name然后重启树莓派&#xff0c;然后才能生效 然后如果你…

PyCharm2024 for mac Python编辑开发

Mac分享吧 文章目录 效果一、下载软件二、开始安装1、双击运行软件&#xff08;适合自己的M芯片版或Intel芯片版&#xff09;&#xff0c;将其从左侧拖入右侧文件夹中&#xff0c;等待安装完毕2、应用程序显示软件图标&#xff0c;表示安装成功3、打开访达&#xff0c;点击【文…

机器人控制系列教程之URDF自动生成工具

URDF文件的编写较为复杂&#xff0c;ROS官方提供了URDF的SolidWorks插件&#xff0c;可方便地将 SW 零件和装配体导出为 URDF 文件。导出器将创建一个类似 ROS 的软件包&#xff0c;其中包含网格、纹理和机器人&#xff08;URDF 文件&#xff09;目录。对于单一的 SolidWorks 零…

Python生成图形验证码

文章目录 安装pillow基本用法生成代码 安装pillow pip install pillow 基本用法 特殊字体文字 如下所示&#xff0c;将下载下来的ttf字体文件放到py文件同一文件夹下 分享一个免费下载字体网站&#xff1a;http://www.webpagepublicity.com/free-fonts.html 我选的字体是Baj…

Linux 基于sqlite3数据库的学生管理系统

一、数据库 sqlite官网&#xff1a;www.sqlite.org 1.1 数据库的安装 离线安装&#xff1a; sudo dpkg -i sqlite3_3.22.0-1ubuntu0.4_amd64.deb //数据库软件 sudo dpkg -i libsqlite3-dev_3.22.0-1ubuntu0.4_amd64.deb //数据库的库函数 在线安装&#xff1a; sudo apt-get …

推荐系统三十六式学习笔记:原理篇.模型融合13|经典模型融合办法:线性模型和树模型的组合拳

目录 为什么要融合&#xff1f;“辑度组合”原理逻辑回归梯度提升决策树GBDT二者结合 总结 推荐系统在技术实现上一般划分为三个阶段&#xff1a;挖掘、召回、排序 。 为什么要融合&#xff1f; 挖掘的工作是对用户和物品做非常深入的结构化分析&#xff0c;各个角度各个层面…

MySQL之可扩展性(六)

可扩展性 向外扩展 12.重新均衡分片数据 如有必要&#xff0c;可以通过在分片间移动数据来达到负载均衡。举个例子&#xff0c;许多读者可能听一些大型图片分享网站或流行社区网站的开发者提到过用于分片间移动用户数据的工具。在分片间移动数据的好处很明显。例如&#xff…

鸿蒙开发设备管理:【@ohos.batteryInfo (电量信息)】

电量信息 该模块主要提供电池状态和充放电状态的查询接口。 说明&#xff1a; 本模块首批接口从API version 6开始支持。后续版本的新增接口&#xff0c;采用上角标单独标记接口的起始版本。 导入模块 import batteryInfo from ohos.batteryInfo;属性 描述电池信息。 系统能…

NLP经典论文研读--xlnet论文代码复现记录

xlnet源码解读(简易pytorch实现版本) xlnet这个模型还是相当复杂的&#xff0c;我看了很长一段时间也还是有很多地方没有搞明白&#xff0c;最后又在网上搜了很多大佬写的相关博客&#xff0c;才算是大致弄明白了&#xff0c;想了解xlnet的原理&#xff0c;请参考原论文&#…

(2024,RNN,梯度消失和爆炸,记忆诅咒,重参数化和动态学习率,权重矩阵对角化,复值 RNN)梯度消失和爆炸并不是故事的结局

Recurrent neural networks: vanishing and exploding gradients are not the end of the story 公和众与号&#xff1a;EDPJ&#xff08;进 Q 交流群&#xff1a;922230617 或加 VX&#xff1a;CV_EDPJ 进 V 交流群&#xff09; 目录 0. 摘要 1. 梯度消失和梯度爆炸 2. 记…

%运算符

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 语法介绍 在python中&#xff0c;可以使用%运算符进行灵活多样的格式化处理&#xff0c;通用的语法格式为&#xff1a; &#xff08;格式模板&…

面试突击:ArrayList源码详解

本文已收录于&#xff1a;https://github.com/danmuking/all-in-one&#xff08;持续更新&#xff09; 前言 哈喽&#xff0c;大家好&#xff0c;我是 DanMu。ArrayList 是我们日常开发中不可避免要使用到的一个类&#xff0c;并且在面试过程中也是一个非常高频的知识点&#…

机器人控制系列教程之URDF文件语法介绍

前两期推文&#xff1a;机器人控制系列教程之动力学建模(1)、机器人控制系列教程之动力学建模(2)&#xff0c;我们主要从数学的角度介绍了机器人的动力学建模的方式&#xff0c;随着机器人技术的不断发展&#xff0c;机器人建模成为了机器人系统设计中的一项关键任务。URDF&…

ZSWatch 开源项目介绍

前言 因为时不时逛 GitHub 会发现一些比较不错的开源项目&#xff0c;突发奇想想做一个专题&#xff0c;专门记录开源项目&#xff0c;内容不限于组件、框架以及 DIY 作品&#xff0c;希望能坚持下去&#xff0c;与此同时&#xff0c;也会选取其中的开源项目做专题分析。希望这…

基于Java的汽车租赁系统【附源码】

论文题目 设计&#xff08;论文&#xff09;综述&#xff08;1000字&#xff09; 当今社会&#xff0c;汽车租赁已成为一种受欢迎的出行方式。本文旨在探讨汽车租赁行业的发展趋势、市场规模及其对环境的影响。目前&#xff0c;汽车租赁行业正在经历着快速的发展。随着经济的发…

【独家揭秘】SmartEDA电路仿真软件:电子电路基础学习的神器!

在电子科技日新月异的今天&#xff0c;电路基础学习的重要性愈发凸显。但你是否曾为复杂的电路图、难以理解的电路原理而感到困扰&#xff1f;今天&#xff0c;我要向大家推荐一款学习神器——SmartEDA电路仿真软件&#xff0c;让你轻松踏入电子电路基础学习的殿堂&#xff01;…

22 Shell编程之免交互

目录 22.1 Here Document免交互 22.1.1 Here Document概述 22.1.2 Here Document免交互 22.1.3 Here Document变量设定 22.1.4 Here Document格式控制 22.1.5 Here Document多行注释 22.2 expect免交互 22.2.1 expect概述 22.2.2 expect安装 22.2.3 基本命令介绍 22.2.4expec…

ARM裸机:地址映射

S5PV210的地址映射详解 什么是地址映射&#xff1f; S5PV210属于ARM Cortex-A8架构&#xff0c;32位CPU&#xff0c;CPU设计时就有32根地址线&32根数据线。 32根地址线决定了CPU的地址空间为4G&#xff0c;那么这4G空间如何分配使用&#xff1f;这个问题就是内存映射问题。…

NAND闪存巨头铠侠(Kioxia)计划最迟于10月下旬通过首次公开募股IPO

据路透社于6月26日引用消息来源的报道&#xff0c;在半导体市场条件反弹及财务业绩迅速改善的背景下&#xff0c;NAND闪存巨头铠侠&#xff08;Kioxia&#xff09;正准备尽快提交初步申请&#xff0c;并计划最迟于10月下旬通过首次公开募股&#xff08;IPO&#xff09;在东京证…

9.二维数组的遍历和存储

二维数组的遍历和存储 二维数组的遍历 二维数组a[3][4],可分解为三个一维数组,其数组名分别为: 这三个一维数组都有4个元素,例如:一维数组a[0]的 元素为a[0][0],a[0][1],a[0][2],a[0][3]。所以遍历二维数组无非就是先取出二维数组中得一维数组, 然后再从一维数组中取出每个元…