九大排序之交换排序

1.前言

所谓交换,就是根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置,交换排序的特点是:将键值较大的记录向序列的尾部移动,键值较小的记录向序列的前部移动。

重点:

冒泡排序和快速排序

2.冒泡排序

思路:冒泡排序是典型的交换排序,每趟排一个值,一直排n-1趟,这样就能把n个值按照一定的顺序排好。

  • end记录冒泡的最终位置;
  • 待排区间中的数据前后两两比较,交换,冒泡到end;
  • 如果在一趟比较中没有发生交换则提前结束循环;
  • –end,准备冒下一个泡。当end > 0时循环继续。

代码如下:

void Bubble(int* arr,int size)
{//1.先确定趟数int end=size-1;while(end>0){bool exchange=false;for(int i=1;i<=end;i++){if(arr[i]<arr[i-1]) {exchange=true;swap(&arr[i],&arr[i-1]);}}end--;if(exchange) break;}
}

动画演示如下:

冒泡排序总结:

时间复杂度:O(n)~O(n^2)

空间复杂度:O(1)

稳定性:稳定

3.快速排序

快排是hore在19世纪提出的一种基于二叉树结构的排序方法,其基本思想是:先选定基准值,然后比基准值的小的放在其左边,比基准值大的放在其右边。然后再进行递归左边的值,然后再进行递归右边的值。一直递归到只有一个值为止。

方法一左右指针法也称hore法:

1. 选择一个关键字key,一般选最左值或最右值。
2. 单趟排序:目的是利用基准值key将序列分成左右两个部分:key左边的值比key要小,右边的值比key要大。即直接将key移动到排序后的最终位置。
3. 递归思想:单趟排完,再使用同样的方法使得左子区间有序,右子区间也有序,整体就有序了。

void QuickSort(int* arr,int left,int right)
{if(left>=right) return;int mid=parition(arr,left,right);QuickSort(arr,left,mid-1);QuickSort(arr,mid+1,right);
}int parition(int* arr,int left,int right)
{int keyi=arr[left];while(left<right){while(left<right&&keyi<=arr[right]) right--;while(left<right&&keyi>=arr[left])  left++;swap(&arr[left],&arr[right]);}swap(&keyi,&arr[left]);return left;
}

 动画演示:

 

规律总结:

  • 选最左值做key,右边先走:左右相遇时比key小
  • 选最右值做key,左边先走: 左右相遇时比key大

为什么?
没有相遇之前谁先走都无所谓,L找大R找小
相遇时(key选最左),无非是 L<–R 或 L–>R

L<-R (R找不到小),由于上次交换后L还未发生移动,此时的L< key (或L == key,其余所有数都比key要大);

例:5 6 3 1 7 4 2 8 9 ---如果是左边先走那么最后一次交换是  5 2 3 1 4 7 6 8 9    left和right同时指向7所在的位置,又因为选择了左边做基准值,所以相遇的位置必须是比基准值小的,那么就只能右边先走,把所有的大的走完了,遇见的第一个比基准值小的就是相遇值。
L->R(L找不到大),由于是每次循环R先走,此时的R<key;(与上述同理)

方法二:前后指针法

1.定义两个指针(下标)cur与prev一前一后:prev指向left,cur指向left+1;
2.选最左端left做keyi;(需提前做三数取中优化:让left,mid,right三个数的中间值于left交换);
3.cur不断向前找小于key的数,找到后与++prev(大于key)交换;如果++prev==cur,则可以不交换。
经4.过这样的交换,prev左边的值 (keyi, prev] 都小于key,prev右边的值 (prev, cur)都大于等于key。(prev是左右区间的交界)
5.最后将prev和key交换,就可以实现快排单趟的分割。

代码如下:

//三数取中
int GetMidIndex(int *arr, int left, int right){int mid = left + (right - left) / 2;int tmp1 = arr[left] > arr[mid] ? left : mid;int tmp2 = arr[mid] > arr[right] ? mid : right;return arr[tmp1] > arr[tmp2] ? tmp2 : tmp1;}int Partion2(int *arr, int left, int right){//三数取中 -- 有序的情况每次二分,将最坏情况变成最好情况int midi = GetMidIndex(arr, left, right);Swap(&arr[midi], &arr[left]);int prev=left,cur=left+1;while(cur<=right){if(arr[cur]<arr[midi]&&prev+1!=cur){prev++;swap(&arr[prev],&arr[cur]);}cur++;}swap(&arr[midi],&arr[prev]);return prev;
}void QuickSort(int *arr,int left,int right)
{if(left>=right) return;int mid=Parition2(arr,left,right);QuickSort(arr,left,mid-1);QuickSort(arr,mid+1,right);
}

 关键点:这里是把三数取中的值,与最左边进行了互换,所以选取的是最左边作为关键值。

当选取左边为关键值时:

1.prev=left,cur=left+1(把基准值排除在外)

2.循环条件是  cur<=right

3.最后把基准值与prev的值进行交换(得到了左边比其小,右边比其大)

当选取右边为关键值时:

1.那么cur应该为cur=left,prev=left-1;

2.cur<right(把基准值排除在外)

3.最后把基准值与prev的值进行交换

方法三:挖洞法

挖洞法的中心思想就是,把基准值挖掉,用一个数记录下来,然后左边找比他大的,右边找比他小的,填到洞里面,然后找到的那个就是一个新的洞

int Partion3(int *arr, int left, int right){//三数取中 -- 将有序的最坏情况变成最好情况int midi = GetMidIndex(arr, left, right);Swap(&arr[midi], &arr[left]);int tmp = arr[left];int hole = left;while (left < right){//右边找小,放到左边的坑while (arr[right] >= key && left < right){right--;}arr[hole] = arr[right];hole = right;//左边找大,放到右边的坑while (arr[left] <= key && left < right){left++;}arr[hole] = arr[left];hole = left;}arr[hole] =tmp;return hole;
}

动画如下:

快速排序的特性总结:
1. 快速排序整体的综合性能和使用场景都是比较好的,所以才敢叫快速排序
2. 时间复杂度:O(N*logN)~O(N^2)
3. 空间复杂度:O(logN)~O(N)(栈结构消耗)
4. 稳定性:不稳定---排序主要依靠的是选基准值。如果每次选的基准值都是最大的,那就是O(n^2)
5. 数据敏感性:敏感,越无序效率越高

快排的复杂度和优化分析

复杂度:

如果每次选取的基准值都是中间值的话,那么就会形成一棵二叉树

那么时间复杂度就是O(N*logN),空间复杂度就是O(logN)

如果每次排序的话选取的基准值都是最大值的话,那么就无法形成两端区间。

那么时间复杂度就是0(N*2),空间复杂度也是O(N)

如果数据太多,会因此调用堆栈空间太多,而导致栈溢出。

优化:

1.发现时间和空间复杂度都与基准值的选取有关,那么就可以利用三数取中的方式,来尽量找到一个中间值,使其成为一棵二叉树

2.当快排分割区间分割到一定的程序的时候,试试用直接插入排序来对这段区间排序,减少递归的次数

快排的缺陷

无法解决值相等或者重复序列排序的问题

例如: 3,4,4,3,3,4,3,4,3,4

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

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

相关文章

OpenCV库模块解析

1.OpenCV库每个模块解析 2.OpenCV的常用函数 它为计算机视觉应用程序提供了一个通用的基础设施&#xff0c;并加速了在商业产品中使用机器感知。作为BSD许可的产品&#xff0c;OpenCV使企业可以很容易地利用和修改代码。该库拥有超过2500个优化算法&#xff0c;其中包括经典和最…

网站优化门槛低了还是高了?

自从2015年刚接触网站时&#xff0c;从一无所知到现在无人指导&#xff0c;一直跌跌撞撞走过来&#xff0c;当年花了1500元找了广东一个网友用织梦CMS做了一个门户网站&#xff0c;记得那时一星期没下楼&#xff0c;把网站折腾的千疮百孔&#xff0c;而终逐步熟悉网站建设与搜索…

【在Linux世界中追寻伟大的One Piece】DNS与ICMP

目录 1 -> DNS(Domain Name System) 1.1 -> DNS背景 2 -> 域名简介 2.1 -> 域名解析过程 3 -> 使用dig工具分析DNS 4 -> ICMP协议 4.1 -> ICMP功能 4.2 -> ICMP报文格式 4.3 -> Ping命令 4.4 -> traceroute命令 1 -> DNS(Domain Na…

webGL进阶(一)多重纹理效果

效果&#xff1a; 代码&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content&q…

【Unity踩坑】Unity导出的UWP项目编译失败

在Unity中导出了UWP平台的项目后&#xff08;Xaml或D3D&#xff09;&#xff0c;使用Visual Studio编译时发生错误&#xff1a; Error: Unity.IL2CPP.Building.BuilderFailedException: Lump_libil2cpp_vm.cpp 查找后发现是Visual Studio 与Unity兼容的问题 原贴&#xff1a;…

黑神话:仙童,数据库自动反射魔法棒

黑神话&#xff1a;仙童&#xff0c;数据库自动反射魔法棒 Golang 通用代码生成器仙童发布了最新版本电音仙女尝鲜版十一及其介绍视频&#xff0c;视频请见&#xff1a;https://www.bilibili.com/video/BV1ET4wecEBk/ 此视频介绍了使用最新版的仙童代码生成器&#xff0c;将 …

C++-容器适配器- stack、queue、priority_queue和仿函数

目录 1.什么是适配器 2.deque 1.简单了解结构 2.deque的缺陷 3.为什么选择deque作为stack和queue的底层默认容器 3.stack&#xff08;栈&#xff09; 4.queue&#xff08;队列&#xff09; 5.仿函数 6.priority_queue&#xff08;优先级队列&#xff09;&#xff08;堆…

Linux C接口编程入门之文件I/O

一切皆文件 "Linux一切皆文件"是Linux操作系统中的一个重要理念和设计原则。在Linux系统中&#xff0c;几乎所有的设备、资源都以文件的形式进行访问和操作。简化了操作系统的设计和管理&#xff0c;提供了一种统一的抽象模型&#xff0c;使得应用程序可以使用相同的…

docker简述

1.安装dockers&#xff0c;配置docker软件仓库 安装&#xff0c;可能需要开代理&#xff0c;这里我提前使用了下好的包安装 启动docker systemctl enable --now docker查看是否安装成功 2.简单命令 拉取镜像&#xff0c;也可以提前下载使用以下命令上传 docker load -i imag…

【gRPC】1—gRPC是什么

gRPC是什么 ⭐⭐⭐⭐⭐⭐ Github主页&#x1f449;https://github.com/A-BigTree 笔记链接&#x1f449;https://github.com/A-BigTree/Code_Learning ⭐⭐⭐⭐⭐⭐ 如果可以&#xff0c;麻烦各位看官顺手点个star~&#x1f60a; &#x1f4d6;RPC专栏&#xff1a;https://b…

脉冲下跳沿提取电路

本例中的电路可将负脉冲转换为正脉冲。尽管这个任务看似简单&#xff0c;但负脉冲的幅度为-5V~-2V。按照不同应用要求&#xff0c;正脉冲也需要不同的脉冲宽度&#xff0c;而负脉冲是梯形的。脉冲必须先经过一个长距离的传输线才能到达某个控制设备。有多个电路可以解决这一问题…

jQuery——解决快速点击翻页的bug

本文分享到此结束&#xff0c;欢迎大家评论区相互讨论学习&#xff0c;下一篇继续分享jQuery中内置动画的学习。

谷歌AI大模型Gemini API快速入门及LangChain调用视频教程

1. 谷歌Gemini API KEY获取及AI Studio使用 要使用谷歌Gemini API&#xff0c;首先需要获取API密钥。以下是获取API密钥的步骤&#xff1a; 访问Google AI Studio&#xff1a; 打开浏览器&#xff0c;访问Google AI Studio。使用Google账号登录&#xff0c;若没有账号&#xf…

大数据ETL数据提取转换和加载处理

什么是 ETL&#xff1f; 提取转换加载&#xff08;英语&#xff1a;Extract, transform, load&#xff0c;简称ETL&#xff09;&#xff0c;用来描述将资料从来源端经过抽取、转置、加载至目的端的过程。ETL一词较常用在数据仓库&#xff0c;但其对象并不限于数据仓库。 ETL&…

C++竞赛初阶—— 石头剪子布

题目内容 石头剪子布&#xff0c;是一种猜拳游戏。起源于中国&#xff0c;然后传到日本、朝鲜等地&#xff0c;随着亚欧贸易的不断发展它传到了欧洲&#xff0c;到了近现代逐渐风靡世界。简单明了的规则&#xff0c;使得石头剪子布没有任何规则漏洞可钻&#xff0c;单次玩法比…

Spring Cloud Netflix Zuul 网关详解及案例示范

1. 引言 在微服务架构中&#xff0c;API 网关作为服务间通信的入口&#xff0c;扮演着重要的角色。Netflix Zuul 是一个提供动态路由、监控、安全等功能的 API 网关服务器&#xff0c;它可以为微服务系统提供统一的入口&#xff0c;简化服务间的交互。在业务系统中&#xff0c…

【计网】【计网】从零开始学习http协议 ---理解http重定向和请求方法

去光荣地受伤&#xff0c; 去勇敢地痊愈自己。 --- 简嫃 《水问》--- 从零开始学习http协议 1 知识回顾2 认识网络重定向3 http请求方法3.1 http常见请求方法3.2 postman工具进行请求3.3 处理GET和POST参数 1 知识回顾 前面两篇文章中我们学习并实现了http协议下的请求与应…

Linux 命令 netstat 的 10 个基本用法

Netstat 简介 Netstat 是一款命令行工具&#xff0c;可用于列出系统上所有的网络套接字连接情况&#xff0c;包括 tcp, udp 以及 unix 套接字&#xff0c;另外它还能列出处于监听状态&#xff08;即等待接入请求&#xff09;的套接字。如果你想确认系统上的 Web 服务有没有起来…

行为设计模式 -观察者模式- JAVA

观察者模式 一.简介二. 案例2.1 抽象主题&#xff08;Subject&#xff09;2.2 具体主题&#xff08;Concrete Subject&#xff09;2.3 抽象观察者&#xff08;Observer&#xff09;2.4 具体观察者&#xff08;Concrete Observer&#xff09;2.5 测试 三. 结论3.1 优缺点3.2 使用…

STM32外设详解——ADC

来源&#xff1a;铁头山羊 基本概念 ①ADC是模数转换器的统称&#xff0c;stm32f103c8t6内部集成了2个12位主次逼近型ADC&#xff0c;外设名称为ADC1、ADC2。 ② 采样深度为12位意味着ADC可以将0~3.3V的模拟电压等比转换为0~4095的数字值&#xff08;分割为2的12次方份&…