使用 Java 实现快速排序(详解)

2023-05-16

在这里插入图片描述

一、概述

最近在看一些面试题,发现很多面试过程中都会要求手写快速排序,查阅一些博客发现别人写的并不是特别清楚而且也很难记住,所以为了更好的掌握这个算法,所以在这篇文章中,将自己的学习过程记录下来,你将学习到快速排序算法和使用 Java 如何实现快速排序。

快速排序是一种基于分而治之的排序算法,其中:
1、通过从数组中选择一个中心元素将数组划分成两个子数组,在划分数组时,将比中心元素小的元素放在左子数组,将比中心元素大的元素放在右子数组。
2、左子数组和右子数组也使用相同的方法进行划分,这个过程一直持续到每个子数组都包含一个元素为止。
3、最后,将元素组合在一起以形成排序的数组。

中心元素(pivot element):有的地方翻译为:枢轴元素、基元,基准元素,我这里就叫做中心元素

二、快速排序算法的工作原理

1、选择中心元素

选择不同位置的中心元素,快速排序就有不同的变体,比如可以选择:第一个元素、最后一个元素以及左端、右端和中心位置上的三个元素的中值作为中心元素,在这里,我们将选择数组的最后一个元素作为中心元素。

2、重新排列数组

现在重新排列数组,将比中心元素小的放在左边,比中心元素大的放在右边。

重新排列数组的方法如下:
1、指针固定在中心元素上,将中心元素与从第一个索引开始的元素进行比较。

2、如果该元素大于中心元素,则为该元素设置第二指针。

3、现在将中心元素与其他元素进行比较,如果到达的元素小于中心元素,则将较小的元素和上次找到的较大元素交换位置。

4、同样,重复该过程以将下一个更大的元素设置为第二指针,并且将其和另一个较小的元素交换位置。

5、该过程一直进行到到达倒数第二个元素为止。

6、最后将中心元素与第二个指针指向的元素交换位置。

3、划分子数组

再次分别为左子部分和右子部分选择了中心元素,并且重复步骤2,子数组被分割,直到每个子数组只有一个元素,至此,该数组已经通过快速排序算法升序排好序了。

4、快速排序可视化插图说明

可以借助以下插图了解快速排序算法的工作原理。

三、快速排序算法伪代码

1、伪代码说明

quickSort(array, leftmostIndex, rightmostIndex)
  if (leftmostIndex < rightmostIndex)
    pivotIndex <- partition(array,leftmostIndex, rightmostIndex)
    quickSort(array, leftmostIndex, pivotIndex - 1)
    quickSort(array, pivotIndex, rightmostIndex)

partition(array, leftmostIndex, rightmostIndex)
  set rightmostIndex as pivotIndex
  storeIndex <- leftmostIndex - 1
  for i <- leftmostIndex + 1 to rightmostIndex
  if element[i] < pivotElement
    swap element[i] and element[storeIndex]
    storeIndex++
  swap pivotElement and element[storeIndex+1]
return storeIndex + 1

四、Java 实现快速排序

Java 实现快速排序的代码如下:


public class QuickSort {

    public static int partition(int[] array, int low, int high) {
        // 取最后一个元素作为中心元素
        int pivot = array[high];
        // 定义指向比中心元素大的指针,首先指向第一个元素
        int pointer = low;
        // 遍历数组中的所有元素,将比中心元素大的放在右边,比中心元素小的放在左边
        for (int i = low; i < high; i++) {
            if (array[i] <= pivot) {
                // 将比中心元素小的元素和指针指向的元素交换位置
                // 如果第一个元素比中心元素小,这里就是自己和自己交换位置,指针和索引都向下一位移动
                // 如果元素比中心元素大,索引向下移动,指针指向这个较大的元素,直到找到比中心元素小的元素,并交换位置,指针向下移动
                int temp = array[i];
                array[i] = array[pointer];
                array[pointer] = temp;
                pointer++;
            }
            System.out.println(Arrays.toString(array));
        }
        // 将中心元素和指针指向的元素交换位置
        int temp = array[pointer ];
        array[pointer] = array[high];
        array[high] = temp;
        return pointer;
    }

    public static void quickSort(int[] array, int low, int high) {
        if (low < high) {
            // 获取划分子数组的位置
            int position = partition(array, low, high);
            // 左子数组递归调用
            quickSort(array, low, position -1);
            // 右子数组递归调用
            quickSort(array, position + 1, high);
        }
    }

    public static void main(String[] args) {
        int[] array = {6,72,113,11,23};
        quickSort(array, 0, array.length -1);
        System.out.println("排序后的结果");
        System.out.println(Arrays.toString(array));
    }
}

排序过程的结果如下:

[6, 72, 113, 11, 23]
[6, 72, 113, 11, 23]
[6, 72, 113, 11, 23]
[6, 11, 113, 72, 23]
[6, 11, 23, 72, 113]
[6, 11, 23, 72, 113]
排序后的结果
[6, 11, 23, 72, 113]

从这个排序结果我们可以知道整个排序过程。

五、快速排序的复杂性

时间复杂度O表示
最好O(n * log n)
最差O(n * n)
平均O(n * log n)
空间复杂度O(log n)
稳定性不稳定

1、时间复杂度

  • 最坏的情况复杂度[Big-O] :
    当选择的中心元素是最大或最小的元素时发生,这种情况导致中心元素位于已排序数组的最末端,一个子数组始终为空,而另一个子数组包含元素,因此,仅在此子数组上调用quicksort,快速排序算法对于分散的数据具有更好的性能。
  • 最好的情况复杂度[Big-O] :
    当中心元素始终是中间元素或靠近中间元素时,会发生这种情况。
  • 平均复杂度[Big-O] :
    在不出现上述条件时发生。

2、空间复杂度

快速排序的空间复杂度为O(log n)。

六、快速排序的应用

在以下情况下使用Quicksort算法

  • 编程语言适合递归
  • 时间复杂度很重要
  • 空间复杂性很重要
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 Java 实现快速排序(详解) 的相关文章

  • fon in 和 for of 的区别

    for 循环 其实他一般情况下是根据数组 xff0c 类数组的length的属性值去循环 for in 一般的作用是枚举把key枚举出来 xff0c 但是当我们枚举数组 xff0c 或者字符串的时候会把原型上的方法枚举出来 Object p
  • 词云图wordcloud学习笔记

    词云图 也叫文字云 是对文本中出现频率较高的 关键词 予以视觉化的展现 词云图过滤掉大量的低频低质的文本信息 使得浏览者只要一眼扫过文本就可领略文本的主旨 github https github com amueller word clou
  • ++a-a++解析

    有题目当a为1的时候 43 43 a a 43 43 为多少答案为0 我们再输出a这个时候a等于3 为什么呢 xff1f 运算顺序 前置递增 减 大于 数字运算和后置递增 减 大于 比较 布 大于 逻辑 或 且 大于 赋值 好当我们把运算顺
  • sync修饰符的使用

    为什么使用sync 再vue中官网的介绍 xff1a 我们可能需要对一个 prop 进行 双向绑定 不幸的是 xff0c 真正的双向绑定会带来维护上的问题 xff0c 因为子组件可以修改父组件 xff0c 且在父组件和子组件都没有明显的改动
  • vue中 methods computed watch filters区别

    在vue中事件 xff0c 计算属性 xff0c 帧听器 xff0c 过滤器的区别 其实共同点 xff1a 修改数据 事件methods和计算属性computed 作用 xff1a 对数据进行逻辑运算 区别 计算属性是基于它们的响应式依赖进
  • 前端面试题----js基础测试35

    得分 这个题目总共8分的我只有3分 xff0c 但是说实话我写这个题目的时候信心爆棚 xff0c 我觉得我自己应该是写出来的的 xff0c 但是可惜 解析 第一题 正解 xff1a 1 encodeURI 函数假设参数是完整的 URIs x
  • 前端面试题----DOM测试35

    得分 这个题目8分我5分 重新复习 HTML lt form id 61 34 loginForm 34 action 61 34 account login 34 method 61 34 POST 34 gt lt p gt 账号 xf
  • 前端小测---css基础测试10

    得分 总共8分得了6分有一个背景样式没处理好 重点 无js使用details和summary组合动画处理 xff0c 使用max height 0来过渡 HTML lt div class 61 34 container 34 gt lt
  • 前端小测试---- 图片上传

    得分 8分我自己得了4分 第一问 xhr onprogress和xhr upload onprogress的区别 xff1a 这两个都能显示进度百分比 xff0c 但是 xff0c 前者显示的是服务器返回的数据 xff0c 后者是发送给服务
  • js 部分代码注释规范

    普通注释 单行 单行注释 文字和 有一个空格 多行 多行注释 1 总是再多行注释的结束符前留一个空格 使星号对齐 2 不要把注释写再多行注释的开始符 xff0c 和结束符所在行 文档注释 Core模块提供最基础 最核心的接口 文档说明 64
  • js代码优化

    原文 xff1a https dmitripavlutin com unlearn javascript bad coding habits 一 xff1a 不要使用隐式类型转换 大多数运算符 43 61 61 不包括 61 61 61 再
  • Python爬虫基础(一) —— 基本爬虫库的使用

    文章目录 使用urllib库使用request模块发送请求1 使用urlopen urlopen data参数urlopen timeout参数 2 Request 3 高级用法验证代理Cookies 使用error模块处理异常1 URLE
  • Django使用websocket实现实时消息推送和聊天

    websocket简介 WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议 WebSocket 使得客户端和服务器之间的数据交换变得更加简单 允许服务端主动向客户端推送数据 在 WebSocket
  • word 使用域对公式进行编号

    需要的快捷键 xff1a alt 43 F9 切换为域代码编辑模式 ctrl 43 A 选中所有再点F9进行域更新 在公式最后面加 1 再回车 xff0c 生成靠右的编号 点中1 的右侧 xff0c 插入 gt 文档部件 gt 域 gt 如
  • 【Linux】(一)深度学习环境多用户共用,配置共用cuda anaconda pycharm,vnc4server创建多用户虚拟xfce桌面

    深度学习环境共用配置 系列文章 一 写在前面问题方法简介 首次配置说明1 新建用户2 安装cuda3 安装anaconda3及pycharm 1 上传安装文件 2 安装anaconda3 3 安装pycharm 4 安装VNC服务所需资源5
  • 【Java】购买腾讯云服务器,并部署Spring boot项目,再到部署自己的个人博客,域名备案,安全连接配置

    云服务器部署 一 购买腾讯云服务器二 简单配置2 1 进入控制台2 2 配置防火墙2 3 配置访问密码 三 远程ssh登录连接服务器四 云服务器安装软件4 1 安装JDK4 2 安装MySql4 2 安装Redis 五 Spring boo
  • 【Linux】腾讯云服务器,使用FRP内网穿透,端口映射,远程访问内网主机、代理内网

    FRP内网穿透 一 需求分析1 1 情况1 2 需求1 3 解决方案 二 云服务器开放端口访问2 1 进入控制台2 2 配置防火墙 三 安装FPR3 1 限定3 2 云服务器 服务端 安装FPR3 3 局域网内机器 客户端 安装FPR 四
  • 【Linux】云服务器Centos 7安装nginx,设置二级域名转发端口

    这里写目录标题 一 Nginx 安装1 1 安装Nginx1 2 使用1 3 自启动配置 二 Nginx详细2 1 相关命令2 2 二级域名转发 三 SSL配置3 1 确保Nginx安装了SSL模块3 2 下载证书其它 一 Nginx 安装
  • 【Python】极简部署私有化ChatGPT-Web,使用Flask框架编写网页版ChatGPT

    极简部署私有化ChatGPT 使用ChatGPT最新API创建的聊天页面 xff0c 模型回复效果与官网的ChatGPT一致特性演示动图使用前提介绍 使用ChatGPT最新API创建的聊天页面 xff0c 模型回复效果与官网的ChatGPT
  • 【python】使用apikey查询OpenAi可用余额

    2023 04 02似乎官方禁用了之前的获取方式 xff0c 通过https api openai com dashboard billing credit grants将会得到如下回复 Your request to GET dashbo

随机推荐