【排序算法】快速排序

文章目录

  • 一:基本概念
    • 1.1 介绍
    • 1.2 排序流程
    • 1.3 图解算法
      • 1.3.1 第一步
      • 1.3.2 第二步
      • 1.3.3 第三步
      • 1.3.4 第四步
    • 1.4 动画展示
  • 二:算法性能
    • 2.1 时间复杂度
      • 2.1.1 理想情况
      • 2.1.2 最坏情况
    • 2.2 空间复杂度
      • 2.2.1 原地排序
      • 2.2.2 非原地排序
      • 2.2.3 稳定性
  • 三:代码实现

一:基本概念

1.1 介绍

快速排序由C. A. R. Hoare在1962年提出,它是一种基于二叉树结构的交换排序算法,它采用了一种分治的策略,通常称其为分治法。该方法的基本思想是:先从数列中取出一个数作为基准数,然后将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边,再对左右区间重复第二步,直到各区间只有一个数。快速排序是一种不稳定的排序方法,但是他的效率非常快,比肩希尔和堆排序也略胜一筹。

快速排序(Quicksort)是对冒泡排序的一种改进。基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

1.2 排序流程

快速排序算法通过多次比较和交换来实现排序,其排序流程如下:

1、首先设定一个分界值,通过该分界值将数组分成左右两部分。

2、将大于或等于分界值的数据集中到数组右边,小于分界值的数据集中到数组的左边。此时,左边部分中各元素都小于或等于分界值,而右边部分中各元素都大于或等于分界值。

3、然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理。

4、重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当左、右两个部分各数据排序完成后,整个数组的排序也就完成了。

概括来说为 挖坑填数 + 分治法。

1.3 图解算法

快速排序主要有三个参数,left 为区间的开始地址,right 为区间的结束地址,Key 为当前的开始的值。

我们从待排序的记录序列中选取一个记录(通常第一个)作为基准元素(称为key)key=arr[left],然后设置两个变量,left指向数列的最左部,right 指向数据的最右部。

在这里插入图片描述

1.3.1 第一步

key 首先与 arr[right] 进行比较,如果 arr[right]<key,则arr[left]=arr[right]将这个比key小的数放到左边去,如果arr[right]>key则我们只需要将right–,right–之后,再拿arr[right]与key进行比较,直到arr[right]<key交换元素为止。
在这里插入图片描述

1.3.2 第二步

如果右边存在arr[right]<key的情况,将arr[left]=arr[right],接下来,将转向left端,拿arr[left ]与key进行比较,如果arr[left]>key,则将arr[right]=arr[left],如果arr[left]<key,则只需要将left++,然后再进行arr[left]与key的比较。
在这里插入图片描述

1.3.3 第三步

然后再移动right重复上述步骤
在这里插入图片描述

1.3.4 第四步

最后得到 {23 58 13 10 57 62} 65 {106 78 95 85},再对左子数列与右子数列进行同样的操作。最终得到一个有序的数列。

{23 58 13 10 57 62} 65 {106 78 95 85}

{10 13} 23 {58 57 62} 65 {85 78 95} 106

10 13 23 57 58 62 65 78 85 95 106

1.4 动画展示

在这里插入图片描述

  1. 首先,操作数列中的所有数字
  2. 在所有数字中选择一个数字作为排序的基准(pivot), pivot 通常是随机选择的,在这里为了演示方便,我们选择最右边的数字作为
    pivot
  3. 选取好 pivot 后,在操作数列中选择最左边的数字标记为 左标记 ,最右边的数字标记为 右标记
  4. 将左边的标记向右移动
  5. 当 左标记 达到超过 pivot 的数字时,停止移动
  6. 在这里,8 > 6 ,所以停止移动
  7. 然后将右边的标记向左移动
  8. 当 右标记 达到小于 pivot 的数字时,停止移动
  9. 在这里,4 > 6 ,所以停止移动
  10. 当左右标记停止时,更改标记的数字
  11. 因此,左标记 的作用是找到一个大于 pivot 的数字,右标记 的作用是找到一个小于 pivot 的数字
  12. 通过交换数字,可以在数列的左边收集小于 pivot 的数字集合,右边收集大于 pivot 的数字集合
  13. 交换之后,继续移动 左标记
  14. 在这里,9 > 6 ,所以停止移动
  15. 然后将右边的标记向左移动
  16. 当 右标记 碰撞到 左标记 时也停止移动
  17. 如果左右侧的标记停止时,并且都在同一个位置,将这个数字和 pivot 的数字交换
  18. 这就完成了第一次操作
  19. 小于 6 的都在 6 的左侧,大于 6 的都在 6 的右侧
  20. 然后递归对这分成的两部分都执行同样的操作
  21. 完成 快速排序

二:算法性能

2.1 时间复杂度

2.1.1 理想情况

如果足够理想,那我们期望每次都把数组都分成平均的两个部分,如果按照这样的理想情况分下去,我们最终能得到一个完全二叉树。如果排序 n 个数字,那么这个树的深度就是log2n+1,如果我们将比较 n 个数的耗时设置为 T(n),那我们可以得到如下的公式

T(n)2T(n/2) + n,T(1) = 0  
T(n)2(2T(n/4)+n/2) + n = 4T(n/4) + 2n  
T(n)4(2T(n/8)+n/4) + 2n = 8T(n/8) + 3n  
......
T(n) ≤ nT(1) + (log2n)×n = O(nlogn) 

2.1.2 最坏情况

而在最坏的情况下,这个树是一个完全的斜树,只有左半边或者右半边。这时候我们的比较次数就变为
在这里插入图片描述

2.2 空间复杂度

2.2.1 原地排序

原地快排的空间占用是递归造成的栈空间的使用,最好情况下是递归(log_{2}n)次,所以空间复杂度为O(long2n)
,最坏情况下是递归 n-1 次,所以空间复杂度是O(n)。

2.2.2 非原地排序

对于非原地排序,每次递归都要声明一个总数为n的额外空间,所以空间复杂度变为原地排序的n倍,即最好情况下O(nlog2n)
,最差情况下(O(n^{2}))。

2.2.3 稳定性

不稳定。

三:代码实现

public class QuickSort {
    public static void main(String[] args) {
        int[] arr = {-9, 78, 0, 23, -567, 70, 23, 78, 958, 7, -15698, -56, 515};
        long s = System.currentTimeMillis();
        quickSort(arr, 0, arr.length - 1);
        long e = System.currentTimeMillis();
        System.out.println("arr=" + Arrays.toString(arr));
        System.out.println("quickSort执行时间为:" + (e - s));
    }

    /**
     * 快速排序
     *
     * @param arr   数组
     * @param left  左侧索引
     * @param right 右侧索引
     */
    public static void quickSort(int[] arr, int left, int right) {
        //左下标
        int l = left;
        //右下标
        int r = right;
        //pivot 中轴值
        int pivot = arr[(left + right) / 2];
        //临时变量。作为交换时使用
        int temp = 0;
        //while循环的目的是让比pivot值小的放到左边,比pivot值大的放到右边
        while (l < r) {
            //在pivot的左边一直找,找到大于等于pivot的值,才退出
            while (arr[l] < pivot) {
                l = l + 1;
            }
            //在pivot的右边一直找,找到小于等于pivot的值,才退出
            while (arr[r] > pivot) {
                r = r - 1;
            }
            //如果l >= r,说明pivot左右两边的值,符合左边小于等于pivot,左边大于等于pivot
            if (l >= r) {
                break;
            }
            //交换
            temp = arr[l];
            arr[l] = arr[r];
            arr[r] = temp;
            //如果交换完成以后,发现arr[l] = pivot,则需要将r--,前移一步
            if (arr[l] == pivot) {
                r = r - 1;
            }
            //如果交换完成以后,发现arr[r] = pivot,则需要将l++,后移一步
            if (arr[r] == pivot) {
                l = l + 1;
            }
        }
        //如果l == r ,必须执行l++,r--操作,否则会出现栈内存溢出的情况
        if (l == r) {
            l = l + 1;
            r = r - 1;
        }
        //向左递归
        if (left < r) {
            quickSort(arr, left, r);
        }
        //向右递归
        if (right > l) {
            quickSort(arr, l, right);
        }

    }

}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

KT148A语音芯片一线串口的控制时序起始脉宽的长度说明

一、KT148A一线串口细节点 KT148A语音芯片支持一线串口控制&#xff0c;单线的时序逻辑&#xff0c;所以就存在两个注意细节 起始脉宽的长度要求数据0和数据1的脉宽分配 一线通讯的时序要求 详见完整开发资料的“KT148A语音芯片使用手册3_V4.pdf”文档 章节3.1有详细的描述…

AD20-Excel创建IC类元件库

目录 准备模板AD操作 准备模板 AD操作 结果生成如下&#xff1a; over&#xff01;&#xff01;&#xff01;

CRM客户管理系统好不好用,有哪些判断标准?

市场上有着众多的CRM客户关系管理系统&#xff0c;从中选择一个适合自己企业的系统并非易事。除了需要了解自己的业务需求之外&#xff0c;还需要对市场上CRM系统的区别有一定的了解。不同的CRM系统各有特点&#xff0c;但有一些通用的标准可以用来评估它们的适用性。那么&…

Three.js中文网14入门案例

Three.js中文网 <template><div id"webgl"></div> </template><script setup> import * as THREE from three; import { OrbitControls } from three/addons/controls/OrbitControls.js;// 创建3D场景对象Scene const scene new TH…

Vue学习计划-Vue2--VueCLi(五)全局事件总线、消息订阅与发布(pubsub)

抛出问题:我们多级组件&#xff0c;或者任意不想关的子组件如何传递数据呢&#xff1f; 1. 全局事件总线&#xff08;$bus&#xff09; 一种组件间通信的方式&#xff0c;适用于任意组件间通信 全局事件总线示意图&#xff1a; 安装全局事件总线&#xff1a; new Vue({..…

ES 如何将国际标准时间格式进行格式化与调整时区

需求&#xff0c;日志收集的时候&#xff0c;时间格式是国际标准时间格式。形如yyyy-MM-ddTHH:mm:ss.SSS。 &#xff08;2023-12-05T02:45:50.282Z&#xff09;这个时区也不对&#xff0c;那如何将此类型的时间&#xff0c;进行格式化呢&#xff1f; 本篇文章体统一个案例&…

前端非常好用的免费网页工具推荐(值得收藏)

1、iloveimg 可在线进行图片编辑、压缩、转换等功能&#xff0c;操作方便&#xff0c;完全免费 2、草料二维码 可在线进行文本、网站、文件、图片、微信等二维码生成 3、比特虫 在线制作网站 ico 图标 4、facicongrabber 免费网页 favicon 提取 5、bazhan.wang 在线扒站工…

上海亚商投顾:沪指收复3000点,房地产板块集体走强

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一.市场情绪 沪指昨日窄幅震荡&#xff0c;创业板指走势较弱&#xff0c;科创50指数跌近1%。房地产板块集体走强&#xff0…

系统的安全性设计

要设计一个安全的系统&#xff0c;除了要了解一些前面讲到的常用的保护手段和技术措施外&#xff0c;还要对系统中可能出现的安全问题或存在的安全隐患有充分的认识&#xff0c;这样才能对系统的安全作有针对性的设计和强化&#xff0c;即“知己知彼&#xff0c;百战百胜”。 下…

调用第三方http接口 hutool工具类

1、引入依赖 <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.0.M2</version> </dependency>2、请求组装 String params"<BSXml>" " <MsgHeader>&…

Vue3上传图片和删除图片

<div class"illness-img"><van-uploader:after-read"onAfterRead"delete"onDeleteImg"v-model"fileList"max-count"9":max-size"5 * 1024 * 1024"upload-icon"photo-o"upload-text"上传图…

GaussDB如何创建和管理视图

GaussDB如何创建和管理视图 一、什么是视图 当用户对数据库中的一张或者多张表的某些字段的组合感兴趣&#xff0c;而又不想每次键入这些查询时&#xff0c;用户就可以定义一个视图&#xff0c;以便解决这个问题。 视图与基本表不同&#xff0c;不是物理上实际存在的&#x…

静态HTTP应用的性能优化技巧

在Web开发中&#xff0c;静态HTTP应用以其简单、快速和安全的特点受到了广泛欢迎。然而&#xff0c;随着Web应用的规模不断扩大&#xff0c;性能问题也日益突出。本文将为你介绍一些静态HTTP应用的性能优化技巧&#xff0c;让你的应用飞得更快、更稳定。 一、压缩文件 文件压…

iPhone手机中备忘录如何改变字体颜色

作为一名iPhone用户&#xff0c;我经常使用手机备忘录来记录生活中的点点滴滴。这样&#xff0c;我的大脑就能从繁琐的记忆任务中解脱出来&#xff0c;专注于更重要的事情。 而且&#xff0c;我有一个特别的习惯&#xff0c;那就是使用不同颜色的字体来区分不同的备忘录。这样…

基于SpringBoot的就业信息管理系统设计与实现(源码+数据库+文档)

摘 要 在新冠肺炎疫情的影响下&#xff0c;大学生的就业问题已经变成了一个引起人们普遍重视的社会焦点问题。在这次疫情的冲击之下&#xff0c;大学生的就业市场的供求双方都受到了不同程度的影响&#xff0c;大学生的就业情况并不十分乐观。目前&#xff0c;各种招聘平台上…

解决:Component name “index“ should always be multi-word

原因 要求组件名称以驼峰格式命名&#xff0c;自定义组件名称应该由多单纯组成&#xff0c;防止和html标签冲突&#xff0c;所以index.vue 会报错 解决 1、按照规则驼峰格式&#xff0c;如&#xff1a;appIndex.vue 2、若有.eslintrc.js文件&#xff0c;并在规则中(rules)关…

【数字电路】MacBook使用iverilog进行数字电路仿真

安装流程 在终端中用brew包管理工具进行安装仿真工具&#xff1a; 编译verilog代码&#xff1a; brew install icarus-verilog编译verilog代码&#xff1a; brew install verilatorMacOS系统显示UNIX GUI brew install xquartz可视化仿真波形图&#xff1a; brew install gtk…

柯桥西班牙语里最“好用”的脏话:一些关于cojones的表达

Creo que una de las palabras con ms contextos donde se puede utilizar y que adems pronto es conocida por los estudiantes de espaol es esta que est en el ttulo. 相信标题中的这个单词“cojones”&#xff0c;使用时总是包含很多含义&#xff0c;同时也是西语学习者最…

郝斌C语言自学教程笔记

赫斌C语言——笔记目录 c语言编程预备知识流程控制函数变量指针结构体位运算符 前段时间康哥看我C语言基础不牢,推荐我学习郝斌老师的C语言课程&#xff0c;花2周看完之后发现确实是目前所看的C语言课程中最好的&#xff0c;不仅非常适合入门&#xff0c;而且对即使学了几年C语…

ARM开发

ARM课程介绍 课程特点 ARM开发 --> Linux移植 --> 驱动开发 前后联系&#xff1a;ARM和系统移植为驱动开发学习做准备工作 所需知识&#xff1a;C语言基础及STM32需要的硬件知识 课程要求 目标&#xff1a;学习程序运行原理、硬件的控制原理 会看原理图、芯片手册、学习…