为何快速排序算法在左右都等于pivot基准值时还要进行一次交换?

本文主要是介绍为何快速排序算法在左右都等于pivot基准值时还要进行一次交换?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言:

快排作为世界十大经典算法之一,其重要性就不再多谈了。 我在学习快排过程中有一个很大的疑惑是为什么在进行从左到右和从右到左的扫描时,如果左右都等于pivot基准值还要进行一次交换。这其实是因为一些其他场景的处理导致的一些没法避免的小问题。下面我们详细分析他真正想处理的问题是什么。

注意:快排有非常多的写法,我们只能针对一段代码中的扫描和什么时候停止扫描进行元素交换的逻辑进行分析。不能说本文的解析适用于所有人写的快排。

话不多说,先上java代码:
public class Solution {public void sortArray(int[] A) {if (A == null) return;helper(A, 0, A.length - 1);}private void helper(int[] A, int left, int right) {if (left >= right) {return;}int pivot = A[left + (right - left) / 2];int i = left, j = right;while (i <= j) {while (i <= j && A[i] < pivot) {i++;}while (i <= j && A[j] > pivot) {j--;}if (i <= j) {int tmp = A[i];A[i] = A[j];A[j] = tmp;i++;j--;}}helper(A, left, j);helper(A, i, right);}
}

分析为何左右都等于pivot时还要做一次交换

这里从代码来看也就是说为什么while (i <= j && A[i] < pivot)不能写成while (i <= j && A[i] <= pivot)

  1. 这里我们使用举例法, 比如一个A数组是[1,1,1]如果A[i] <= pivot都要继续扫描不停止,那么i会一直增长到3,大于j导致后面的while循环条件不满足。 后面去递归处理子问题时会成为helper(A, 0, 2)的情况,因为j都没有机会移动就被i跑到j右边去了,这就导致了无限循环永远结束不了的bug。
  2. 我们再举个例子, 比如数组A是[2,3,1],我们还假设A[i] <= pivot时不停止 。又出现了上面的情况,无限循环
  3. 但并不是所有的数组情况都会出错,比如如果换一个数组A[3,2,1,4,5]并还假设A[i] <= pivot时不停止那么是可以得到正确结果的。我们可以详细来画一下。
假设while (i <= j && A[i] <= pivot)时扫描继续,不停止,i继续执行++操作
[3,2,1,4,5]i   p   ji   j
[1,2,3,4,5]ijj 
此时因为 i >= j不再满足所以不进行交换和while循环, 第一轮结束
然后会有递归的两个式子:
helper(A, 0, 0);  //left == right 直接就return了
helper(A, 1, 4);
[1,2,3,4,5]i p   jij
此时因为 i >= j不再满足所以不进行交换和while循环, 第二轮结束
然后会有递归的两个式子:
helper(A, 1, 2);  //left == right 直接就return了
helper(A, 3, 4);
(1) 先看 helper(A, 1, 2);
[1,2,3,4,5]i jpij
此时因为 i >= j不再满足所以不进行交换和while循环, 第三轮第一组结束
然后会有递归的两个式子:
helper(A, 1, 1);  //left == right 直接就return了
helper(A, 2, 2); //left == right 直接就return了
(2) 再看 helper(A, 3, 4);
[1,2,3,4,5]i jpj i
此时因为 i >= j不再满足所以不进行交换和while循环, 第三轮第二组结束	    
然后会有递归的两个式子:
helper(A, 3, 3);  //left == right 直接就return了
helper(A, 4, 4); //left == right 直接就return了这样看来等于pivot时不交换对于这个序列没有影响
  1. 再举一个会出错的例子[5,4,3,2]。我们也可以详细来画一下。
[5,4,3,2]i p   j
[2,4,3,5]i jpi
此时因为 i >= j不再满足所以不进行交换和while循环, 第一轮结束
然后会有递归的两个式子:
helper(A, 0, 2);  
helper(A, 3, 3); //left == right 直接就return了
然后我们只用看helper(A, 0, 2); 
[2,4,3,5]i   ji(//越界)
此时j都没机会动i就大于j了, while循环结束。继续进入递归的式子
helper(A, 0, 2);  
helper(A, 3, 2); //left >= right 直接就return了
然后helper(A, 0, 2);  就无限循环导致stack overflow栈内存溢出了

这篇关于为何快速排序算法在左右都等于pivot基准值时还要进行一次交换?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/949943

相关文章

深入理解Mysql OnlineDDL的算法

《深入理解MysqlOnlineDDL的算法》本文主要介绍了讲解MysqlOnlineDDL的算法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小... 目录一、Online DDL 是什么?二、Online DDL 的三种主要算法2.1COPY(复制法)

使用EasyPoi快速导出Word文档功能的实现步骤

《使用EasyPoi快速导出Word文档功能的实现步骤》EasyPoi是一个基于ApachePOI的开源Java工具库,旨在简化Excel和Word文档的操作,本文将详细介绍如何使用EasyPoi快速... 目录一、准备工作1、引入依赖二、准备好一个word模版文件三、编写导出方法的工具类四、在Export

Python进行word模板内容替换的实现示例

《Python进行word模板内容替换的实现示例》本文介绍了使用Python自动化处理Word模板文档的常用方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友... 目录技术背景与需求场景核心工具库介绍1.获取你的word模板内容2.正常文本内容的替换3.表格内容的

Git进行版本控制的实战指南

《Git进行版本控制的实战指南》Git是一种分布式版本控制系统,广泛应用于软件开发中,它可以记录和管理项目的历史修改,并支持多人协作开发,通过Git,开发者可以轻松地跟踪代码变更、合并分支、回退版本等... 目录一、Git核心概念解析二、环境搭建与配置1. 安装Git(Windows示例)2. 基础配置(必

Nginx中配置使用非默认80端口进行服务的完整指南

《Nginx中配置使用非默认80端口进行服务的完整指南》在实际生产环境中,我们经常需要将Nginx配置在其他端口上运行,本文将详细介绍如何在Nginx中配置使用非默认端口进行服务,希望对大家有所帮助... 目录一、为什么需要使用非默认端口二、配置Nginx使用非默认端口的基本方法2.1 修改listen指令

Python多线程实现大文件快速下载的代码实现

《Python多线程实现大文件快速下载的代码实现》在互联网时代,文件下载是日常操作之一,尤其是大文件,然而,网络条件不稳定或带宽有限时,下载速度会变得很慢,本文将介绍如何使用Python实现多线程下载... 目录引言一、多线程下载原理二、python实现多线程下载代码说明:三、实战案例四、注意事项五、总结引

MySQL按时间维度对亿级数据表进行平滑分表

《MySQL按时间维度对亿级数据表进行平滑分表》本文将以一个真实的4亿数据表分表案例为基础,详细介绍如何在不影响线上业务的情况下,完成按时间维度分表的完整过程,感兴趣的小伙伴可以了解一下... 目录引言一、为什么我们需要分表1.1 单表数据量过大的问题1.2 分表方案选型二、分表前的准备工作2.1 数据评估

C#使用Spire.XLS快速生成多表格Excel文件

《C#使用Spire.XLS快速生成多表格Excel文件》在日常开发中,我们经常需要将业务数据导出为结构清晰的Excel文件,本文将手把手教你使用Spire.XLS这个强大的.NET组件,只需几行C#... 目录一、Spire.XLS核心优势清单1.1 性能碾压:从3秒到0.5秒的质变1.2 批量操作的优雅

MySQL进行分片合并的实现步骤

《MySQL进行分片合并的实现步骤》分片合并是指在分布式数据库系统中,将不同分片上的查询结果进行整合,以获得完整的查询结果,下面就来具体介绍一下,感兴趣的可以了解一下... 目录环境准备项目依赖数据源配置分片上下文分片查询和合并代码实现1. 查询单条记录2. 跨分片查询和合并测试结论分片合并(Shardin

Mybatis-Plus 3.5.12 分页拦截器消失的问题及快速解决方法

《Mybatis-Plus3.5.12分页拦截器消失的问题及快速解决方法》作为Java开发者,我们都爱用Mybatis-Plus简化CRUD操作,尤其是它的分页功能,几行代码就能搞定复杂的分页查询... 目录一、问题场景:分页拦截器突然 “失踪”二、问题根源:依赖拆分惹的祸三、解决办法:添加扩展依赖四、分页