【高效且应用广泛的排序 —— 快速排序算法】

高效且应用广泛的排序 —— 快速排序算法

快速排序是一种常用的排序算法,主要采用分治的思想。以下是对快速排序算法的详细介绍及代码示例:

快速排序的基本思路是,每次将一个位置上的数据归位,使得该数左边的所有数据都比该数小,右边所有的数据都比该数大,然后递归将已归位的数据左右两边再次进行快排,从而实现所有数据的归位。

算法步骤如下:

  1. 从数列中挑出一个元素,称为“基准”。
  2. 重新排序数列,所有比基准值小的元素摆放在基准前面,所有比基准值大的元素摆在基准后面(相同的数可以到任何一边)。在这个分区结束之后,该基准就处于数列的中间位置。这个称为分区操作。
  3. 递归地把小于基准值元素的子数列和大于基准值元素的子数列排序。

在这里插入图片描述

例如,对于数组,选择最左边的元素 29 作为中间点元素,然后将数组分成三部分:(0, 14, 15, 20, 25),(29),(44, 37)。中间节点 29 已经排好序了,不需要处理。接下来再对左右分别进行快速排序。

下面是 Java 代码示例:

public class QuickSort {// 测试public static void main(String[] args) {int[] arr = {5,2,9,6,3,1,7,8,4};int left = 0;int right = arr.length - 1;quickSort(arr, left, right);System.out.println("排序结果:");for(int num : arr){System.out.print(num + " ");}}// 快速排序算法public static void quickSort(int[] arr,int left,int right) {if(left < right) {int partitionIndex = partition(arr, left, right);// 将数组划分为两部分,并返回划分点的索引quickSort(arr, left, partitionIndex - 1);// 递归排序左子数组quickSort(arr, partitionIndex + 1, right);// 递归排序右子数组}}// 划分函数public static int partition(int[] arr,int left,int right) {int pivot = arr[right];// 选择最后一个元素作为基准值int i = left - 1;// i 为较小元素的索引for(int j = left; j < right; j++){if(arr[j] <= pivot){i++;swap(arr, i, j);// 交换较小元素与当前元素}// 如果数组元素大于等于 middleValue,则继续向后遍历,middleIndex 值不变}swap(arr, i + 1, right);// 将基准值放置到正确的位置上return i + 1;// 返回划分点的索引}// 交换数组中两个元素的位置public static void swap(int[] arr,int i,int j) {int temp = arr[i];arr[i]= arr[j];arr[j]= temp;}
}

快速排序在平均情况下时间复杂度为 O(n log n),但在最坏情况下时间复杂度会变为 O(n²)。可以通过随机选择基准元素或使用三数取中法等方法来避免最坏情况。空间复杂度为 O(log n),因为在递归调用中需要使用栈来存储中间结果。快速排序虽然在最坏情况下时间复杂度可能较高,但在实际应用中通常表现良好,尤其对于大规模数据集的排序。如果实现得当,它是一种高效的排序算法。

快速排序算法基本思路

在这里插入图片描述

快速排序是一种高效的排序算法,其基本思路是分治法。首先从数列中取出一个数作为基准数,然后进行分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。接着再对左右区间重复这个步骤,直到各区间只有一个数。概括来说就是“挖坑填数+分治法”。

快速排序就像整理一堆杂乱的卡片。假设我们有一叠无序的数字卡片,我们随机选取一张卡片作为基准数,比如选择第一张卡片。然后我们从这叠卡片的右边开始,找到比基准数小的卡片,从左边开始找到比基准数大的卡片,找到后交换这两张卡片的位置。这样不断进行,直到左右指针相遇。此时,我们把基准数放到正确的位置上,这个位置左边的数字都小于等于基准数,右边的数字都大于基准数。然后我们再对左右两边的子序列重复这个过程,直到所有的子序列都只有一个数字,此时整个序列就有序了。

例如,有一组数字。我们选择4作为基准数,首先从右边开始,9大于4,继续向左,3小于4,此时停下。然后从左边开始,1小于4,继续向右,6大于4,停下。交换3和6的位置,得到。接着继续这个过程,指针不断移动,直到左右指针相遇。最后把4放到正确的位置上,此时序列变为。然后再对左边的子序列和右边的子序列分别进行快速排序,直到所有子序列都有序。

快速排序算法步骤

  1. 从序列中任选一个数作为基准数,一般就使用第一个数。
  2. 进行分区操作,将大于基准数的数放在右边,小于基准数的数放在左边,注意一定要先右后左。具体操作是设置两个指针i和j,分别指向数组的第一个元素和最后一个元素。从j开始向左挪动,直到找到一个小于基准数的数停下来;然后切换到i再向右挪动,直到找到一个数大于基准数的数停下来。最后将i和j指向的元素进行交换位置。重复这个过程直到i和j重合,此时把重合点的元素与基准元素交换位置。
  3. 对左右区间分别执行上述步骤,直到每个区间只有一个数为止。

例如对于数组,选择5作为基准数。首先j从6开始向左移动,找到3小于5停下。i从0开始向右移动,找到8大于5停下。交换3和8的位置,得到。接着j继续向左移动,找到1小于5停下。i继续向右移动,找到2小于5不停下,继续移动找到8大于5停下。交换1和8的位置,得到。此时i和j重合在1的位置,把1和5交换位置,得到。然后对左边的子序列和右边的子序列分别进行快速排序,直到所有子序列都有序。

快速排序代码示例解析

以下是一段快速排序的 Python 代码示例:

def quickSort(lists, left, right):# 快速排序if left >= right:return listskey = lists[left]low = lefthigh = rightwhile left < right:while left < right and lists[right] >= key:right -= 1lists[left] = lists[right]while left < right and lists[left] <= key:left += 1lists[right] = lists[left]lists[right] = keyprint("lists:", lists)quickSort(lists, low, left - 1)quickSort(lists, left + 1, high)return lists

这段代码首先判断左右指针的位置,如果左指针大于等于右指针,说明该子序列已经有序,直接返回。然后选择左指针指向的元素作为基准数key。接着使用两个循环,从右向左找到小于基准数的元素,从左向右找到大于基准数的元素,然后交换这两个元素的位置。当左右指针相遇时,将基准数放到正确的位置上。最后递归地对左右子序列进行快速排序。

以列表为例,调用quickSort函数进行排序。首先选择3作为基准数,从右向左找到2小于3停下,从左向右找到6大于3停下,交换2和6的位置,得到。接着继续这个过程,直到左右指针相遇,把3放到正确的位置上。然后对左边的子序列和右边的子序列分别进行快速排序,直到整个列表有序。

快速排序时间复杂度分析

快速排序的时间复杂度与划分是否平衡密切相关。最优情况下,时间复杂度为 O(nlogn)。这是因为每次划分都能将序列均匀地分成两部分,此时快速排序的性能与归并排序一样。

例如,对于一个包含 n 个数的序列,递归的第一层,将 n 个数划分为 2 个子区间,每个子区间的数字个数约为 n/2;递归的第二层,将 n 个数划分为 4 个子区间,每个子区间的数字个数约为 n/4;以此类推,递归的第 logn 层,将 n 个数划分为 n 个子区间,每个子区间的数字个数为 1。在每一层的划分过程中,时间复杂度约为 O(n),而总共需要划分 logn 层,所以最优情况下的时间复杂度为 O(nlogn)。

然而,在最坏情况下,时间复杂度为 O(n^2)。当每次选择的基准元素是最大或最小元素时,快速排序的时间复杂度是 O(n^2)。例如,序列已经是有序的,每次选择第一个元素作为基准数,那么每次划分只能分出一个元素,导致递归的深度达到 n,而每一层的时间复杂度为 O(n),所以最坏情况下的时间复杂度为 O(n^2)。

平均情况下,快速排序的时间复杂度也是 O(nlogn)。在实际应用中,快速排序通常表现良好,尤其对于大规模数据集的排序。

快速排序避免最坏情况方法

为了避免快速排序的最坏情况,可以采用以下几种方法:

  1. 随机选取划分点:每次随机从待排序序列中选取一个元素作为划分点,从而降低最坏情况的概率。这样可以避免每次都选择到最大或最小元素作为基准数,使得划分更加平衡。
  2. 三数取中法:选取待排序序列的第一个、中间一个、最后一个元素中的中间值作为划分点,从而降低最坏情况的概率。例如对于序列,可以选择1、6、3中的中间值3作为基准数,这样可以在一定程度上避免选择到最大或最小元素。
  3. 在递归深度较浅时采用其他排序算法,比如插入排序或归并排序等,从而避免快速排序退化成 O(n^2) 的情况。当问题规模小于某一 k 值时,采用插入排序,提高算法效率。

总结

快速排序算法是一种高效的排序算法,其基本思路是分治法,通过不断地划分和递归,将序列分成越来越小的子序列进行排序,直到所有子序列都有序。在实际应用中,可以根据不同的情况选择合适的方法来避免最坏情况的发生,以提高算法的性能。

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

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

相关文章

工业物联网关为工业生产数字化转型赋能-天拓四方

一、引言 在工业4.0的大背景下&#xff0c;工业物联网关成为了制造业转型升级的关键技术之一。它通过连接设备和系统&#xff0c;实现数据的实时采集、处理和传输&#xff0c;从而提升生产效率、降低成本、优化资源配置&#xff0c;并最终推动整个制造业的数字化进程。本文将详…

AJAX 入门 day3 XMLHttpRequest、Promise对象、自己封装简单版的axios

目录 1.XMLHttpRequest 1.1 XMLHttpRequest认识 1.2 用ajax发送请求 1.3 案例 1.4 XMLHttpRequest - 查询参数 1.5 XMLHttpRequest - 数据提交 2.Promise 2.1 Promise认识 2.2 Promise - 三种状态 2.3 案例 3.封装简易版 axios 3.1 封装_简易axios_获取省份列表 3…

Android OpenGLES2.0开发(二):环境搭建

世界没有悲剧和喜剧之分&#xff0c;如果你能从悲剧中走出来&#xff0c;那就是喜剧&#xff0c;如果你沉缅于喜剧之中&#xff0c;那它就是悲剧。——科马克麦卡锡《路》 ​​​ OpenGL ES环境搭建 Android 应用中使用 OpenGL ES 绘制图形&#xff0c;必须创建一个显示容器。…

Rust - 字符串:str 与 String

在其他语言中&#xff0c;字符串通常都会比较简单&#xff0c;例如 “hello, world” 就是字符串章节的几乎全部内容了。 但是Rust中的字符串与其他语言有所不同&#xff0c;若带着其他语言的习惯来学习Rust字符串&#xff0c;将会波折不断。 所以最好先忘记脑中已有的关于字…

【一起学NLP】Chapter2-学习神经网络

目录 学习神经网络损失函数Tip:One-hot向量导数与梯度Tip:严格地说链式法则计算图反向传播其他典型的运算结点乘法结点分支节点Repeat节点Sum节点MatMul节点 Tip:浅拷贝和深拷贝的差异梯度的推导和反向传播的实现Sigmoid层Affine层Softmax with Loss层 权重的更新——随机梯度下…

机械手末端快换技术:工业自动化的强大新动力

在飞速发展的工业自动化领域&#xff0c;机械手无疑是生产线上的关键成员&#xff0c;其性能与效率对整个生产流程的顺畅性与高效性起着至关重要的作用。而机械手末端快换技术&#xff0c;作为这一领域的创新性突破&#xff0c;正以其卓越的优势引领着工业生产的巨大变革。 机…

迷雾大陆免费辅助:强流派推荐攻略!VMOS云手机自动辅助挂机教程!

使用VMOS云手机辅助《迷雾大陆》游戏&#xff0c;让你的游戏体验更轻松高效。VMOS云手机专为《迷雾大陆》提供了定制版的云手机&#xff0c;内置游戏安装包&#xff0c;无需再次下载安装。同时&#xff0c;VMOS云手机支持免费的辅助工具&#xff0c;可以24小时不间断地辅助游戏…

多肽合成的一般步骤 -- 固相合成篇

1.1 溶剂的处理 DMF、甲醇在使用前用G3孔的分子筛浸泡过夜除杂质和水。 1.2 树脂的充分溶胀 称取2.0 g 空白Wang树脂于洁净干燥的反应管中&#xff0c;加入15 mL DMF&#xff0c;室温活化30 min左右。 1.3 接第一个氨基酸 室温下&#xff0c;通过沙芯抽滤掉上步溶剂&#xf…

中电金信 :基于开放架构的私有云建设实践

01开放架构私有云诞生背景 随着国产化创新建设的深化&#xff0c;产业侧行业软件持续进行云原生改造&#xff0c;金融机构拥抱云和容器技术&#xff0c;实现数智化转型已是大势所趋。近年&#xff0c;云原生技术以及架构发展速度更是惊人&#xff0c;私有云开始有了新架构、有了…

<刷题笔记> 力扣105/106题 使用中序+前(后)序构造二叉树

在曾经的博客中&#xff0c;曾经记录过这样一题&#xff1a; 二叉树遍历_牛客题霸_牛客网 (nowcoder.com) 这是一个只需要前序就能构造二叉树的题&#xff0c;因为一旦遇到空&#xff0c;就有"#"作为返回的标志&#xff0c;能够立刻返回。 1. 中序前序 完全可以借鉴…

select查询表单

select查询语法&#xff1a; select 【1】from 【2】where 【3】 1若为*表示显示全部数据列&#xff0c;若为某一列列名则只显示本列内容&#xff08;也可为多列列名&#xff09;。若在1后面加as ‘c’&#xff0c;则表示把查询的列名换成c。 2为要查询的表表名。 3为查询的…

众数信科 AI智能体智慧文旅解决方案——智能旅行助手

智慧文旅解决方案 智能旅行助手方案 利用先进的AI算法 提供个性化旅游体验的智能服务 众数信科AI智能体 产品亮点 旅游路线智能规划 旅游景点智能问答 旅行游记智能生成等 构建旅行实用指南 让旅游更加便捷、高效、智能化 关于我们 众数信科成立于2021年&#xff0c;由…

CentOS Linux教程(6)--CentOS目录

文章目录 1. 根目录2. cd目录切换命令3. CentOS目录介绍4. pwd命令介绍5. ls命令介绍5.1 ls5.2 ls -a5.3 ls -l 1. 根目录 Windows电脑的根目录是计算机(我的电脑)&#xff0c;然后C盘、D盘。 Linux系统的根目录是/&#xff0c;我们可以使用cd /进入根目录&#xff0c;然后使…

【mysql】case...when...、group...by、sum() 聚合函数... 企业组合使用实际场景示例

文章目录 查询需求场景预设查询结果SQL实现查询 查询需求场景 -- 统计当月不同流程类型的审批通过流程数、审批终止流程数、审批驳回流程数、新增流程数&#xff08;归档终止退回&#xff09;、申请总条目数&#xff08;关联任务单申请条目数总数&#xff09;-- 查询思路&…

蘑菇成熟待收检测系统源码分享

蘑菇成熟待收检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer…

最适配达梦、人大金仓的sql工具是什么?

SQLynx是一款功能强大的数据库管理工具&#xff0c;它不仅支持Oracle、MySQL等国际主流数据库&#xff0c;还很好地支持了武汉达梦、人大金仓等国产数据库。这款工具具有以下几个特点&#xff1a; 1.广泛支持&#xff1a;SQLynx支持多种数据库系统&#xff0c;包括PostgreSQL、…

ADC 位的作用

示波器的横轴表示时间基准&#xff08;秒/格或 s/p&#xff09;&#xff0c;而纵轴表示电压&#xff08;伏/格或 V/p&#xff09;。垂直精度是指示波器显示信号电压的准确程度&#xff0c;这对于视觉呈现和测量至关重要。示波器屏幕上的电压读数越接近实际信号电压&#xff0c;…

专为工程地质领域安全监测而设计,BWII型广播预警遥测系统助您实现全面监测!

专为工程地质领域安全监测而设计&#xff0c;BWII型广播预警遥测系统助您实现全面监测&#xff01; BWII型广播预警遥测系统是一款新型的雨量预警监测仪&#xff0c;具备多通道和多类型传感器接入功能。该系统能够定时采集和发送电压、电流、数字和脉冲等信息&#xff0c;同时结…

Day4-C语言高级编程

1. gcc和gdb的用法 GNU工具&#xff1a;编译工具&#xff1a;把一个源程序编译为一个可执行程序调试工具&#xff1a;能对执行程序 进行源码或汇编调试软件工程工具&#xff1a;用于协助多人开发或大型软件项目的管理&#xff0c;如make、CVS、Subvision其他工具&#xff1a;用…

Informer模型复现项目实战

加入会员社群&#xff0c;免费获取本项目数据集和代码&#xff1a;点击进入>> 1. 项目简介 A034-Informer模型复现项目实战的目标是通过复现Informer模型&#xff0c;帮助理解其在时间序列预测中的实际应用和效果。该项目基于深度学习模型Informer&#xff0c;这是一种针…