【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,一经查实,立即删除!

相关文章

Node.js 和浏览器环境中都使用 WebSocket

使用WebSocket为什么不适配双端 浏览器环境本身就支持 WebSocket&#xff0c;直接使用 JavaScript 内置的 WebSocket 对象来建立连接。 Node中本身并没有内置 WebSocket 协议的支持&#xff0c;所以需要使用第三方库 ws来实现 WebSocket 功能。 一. 使用跨平台 WebSocket 库 …

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;点击【文…

网络安全筑基篇——反序列化漏洞

目录 序列化是什么&#xff1f; 反序列化又是什么&#xff1f; 反序列化漏洞的危害 代码样例 常见的魔术方法 修复方式有哪些&#xff1f; 常见的反序列化漏洞 Shiro反序列化漏洞 Fastjson反序列化漏洞 序列化是什么&#xff1f; 将实例化对象转换成字节流的过程 反序…

Harmony OS UI框架探索笔记

本文探讨了如何将现有的常用架构理论与Arkts和ArkUI结合起来&#xff0c;使代码更有条理&#xff0c;并利用Previewer快速调整布局&#xff0c;同时在不改变代码的情况下运行显示真实数据。 开发环境 Windows 11DevEco Studio 4.0 ReleaseBuild Version: 4.0.0.600, built on…

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

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

API-回调函数

学习目标&#xff1a; 掌握回调函数 学习内容&#xff1a; 回调函数小结综合案例 回调函数&#xff1a; 如果将函数A做为参数传递给函数B时&#xff0c;我们称函数A为回调函数。 简单理解&#xff1a;当一个函数当作参数来传递给另外一个函数的时候&#xff0c;这个函数就是…

遗传编程(Genetic Programming, GP)和大规模语言模型(Large Language Models, LLMs)的相似之处

遗传编程&#xff08;Genetic Programming, GP&#xff09;和大规模语言模型&#xff08;Large Language Models, LLMs&#xff09;虽然在实现和用途上有所不同&#xff0c;但也有一些相似之处&#xff1a; 相似之处 自动化生成&#xff1a; GP&#xff1a;自动生成程序或表达…

DM达梦数据库函数分析(与oracle相应函数区别及用法分析)

💝💝💝首先,欢迎各位来到我的博客,很高兴能够在这里和您见面!希望您在这里不仅可以有所收获,同时也能感受到一份轻松欢乐的氛围,祝你生活愉快! 💝💝💝如有需要请大家订阅我的专栏【数据库系列】哟!我会定期更新相关系列的文章 💝💝💝关注!关注!!请…

Python生成图形验证码

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

探索AI的巅峰:详解GPT-3.5与GPT-4系列模型的区别

人工智能领域不断涌现出令人惊叹的技术突破&#xff0c;其中OpenAI的ChatGPT系列模型尤为引人注目。随着GPT-4的发布&#xff0c;技术开发者们对比分析其与前一代GPT-3.5的差异显得尤为重要。本文将深入探讨GPT-3.5和GPT-4系列模型的主要区别&#xff0c;帮助大家更好地理解和应…

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…

学生表的DDL和DML

DDL -- 创建学生表 CREATE TABLE students (student_id INT PRIMARY KEY AUTO_INCREMENT,studentname VARCHAR(50),age INT,gender VARCHAR(10) );-- 创建课程表 CREATE TABLE courses (course_id INT PRIMARY KEY AUTO_INCREMENT,course_name VARCHAR(50) );-- 创建教师表 CR…

鸿蒙开发设备管理:【@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;格式模板&…

【面试系列】C#高频面试题

欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;欢迎订阅相关专栏&#xff1a; ⭐️ 全网最全IT互联网公司面试宝典&#xff1a;收集整理全网各大IT互联网公司技术、项目、HR面试真题. ⭐️ AIGC时代的创新与未来&#xff1a;详细讲解AIGC的概念、核心技术、…