首页 > 其他分享 >11.5 快速排序

11.5 快速排序

时间:2024-06-09 12:31:00浏览次数:16  
标签:right nums int 11.5 数组 排序 快速 left

目录

11.5   快速排序

11.5.1   算法流程

11.5.2   算法特性

11.5.3   快速排序为什么快

11.5.4   基准数优化

11.5.5   尾递归优化


11.5   快速排序

快速排序(quick sort)是一种基于分治策略的排序算法,运行高效,应用广泛。

快速排序的核心操作是“哨兵划分”,其目标是:选择数组中的某个元素作为“基准数”,将所有小于基准数的元素移到其左侧,而大于基准数的元素移到其右侧。具体来说,哨兵划分的流程如图 11-8 所示。

  1. 选取数组最左端元素作为基准数,初始化两个指针 i 和 j 分别指向数组的两端。
  2. 设置一个循环,在每轮中使用 ij)分别寻找第一个比基准数大(小)的元素,然后交换这两个元素。
  3. 循环执行步骤 2. ,直到 i 和 j 相遇时停止,最后将基准数交换至两个子数组的分界线。

<1><2><3><4><5><6><7><8><9>

pivot_division_step9

图 11-8   哨兵划分步骤

哨兵划分完成后,原数组被划分成三部分:左子数组、基准数、右子数组,且满足“左子数组任意元素 ≤ 基准数 ≤ 右子数组任意元素”。因此,我们接下来只需对这两个子数组进行排序。

快速排序的分治策略

哨兵划分的实质是将一个较长数组的排序问题简化为两个较短数组的排序问题。

quick_sort.c

/* 元素交换 */
void swap(int nums[], int i, int j) {
    int tmp = nums[i];
    nums[i] = nums[j];
    nums[j] = tmp;
}

/* 哨兵划分 */
int partition(int nums[], int left, int right) {
    // 以 nums[left] 为基准数
    int i = left, j = right;
    while (i < j) {
        while (i < j && nums[j] >= nums[left]) {
            j--; // 从右向左找首个小于基准数的元素
        }
        while (i < j && nums[i] <= nums[left]) {
            i++; // 从左向右找首个大于基准数的元素
        }
        // 交换这两个元素
        swap(nums, i, j);
    }
    // 将基准数交换至两子数组的分界线
    swap(nums, i, left);
    // 返回基准数的索引
    return i;
}

11.5.1   算法流程

快速排序的整体流程如图 11-9 所示。

  1. 首先,对原数组执行一次“哨兵划分”,得到未排序的左子数组和右子数组。
  2. 然后,对左子数组和右子数组分别递归执行“哨兵划分”。
  3. 持续递归,直至子数组长度为 1 时终止,从而完成整个数组的排序。

快速排序流程

图 11-9   快速排序流程

quick_sort.c

/* 快速排序 */
void quickSort(int nums[], int left, int right) {
    // 子数组长度为 1 时终止递归
    if (left >= right) {
        return;
    }
    // 哨兵划分
    int pivot = partition(nums, left, right);
    // 递归左子数组、右子数组
    quickSort(nums, left, pivot - 1);
    quickSort(nums, pivot + 1, right);
}

11.5.2   算法特性

相关文章

  • nginx快速分析日志并找出攻击IP
    第一步:分析NGINX日志分析日志主要目的是寻找那些异常活跃的IP地址,通过以下命令可以快速找出。 cataccess.log|awk'{print$1}'|sort|uniq-c|sort-rn|head-10命令说明:cataccess.log:将access.log文件的内容输出到标准输出。awk'{print$1}':awk是一个强大的文本......
  • 数据结构与算法之归并排序,以及它的代码实现与事例
    目录前言定义策略代码实现结果结束语前言今天是坚持写博客的第22天,我们来看看数据结构与算法当中的归并排序。定义首先我们来看看什么是归并排序?归并排序(MergeSort)是一种分治思想的排序算法。它将待排序的数组分成若干个子数组,每个子数组都是有序的,然后再将有序......
  • 外链建设平台:选择合适平台,快速建设外链
    外链建设平台:选择合适平台,快速建设外链在当今数字化时代,互联网已成为企业宣传和推广的重要渠道。在搜索引擎优化(SEO)中,外链被视为提高网站排名和流量的关键因素之一。然而,建设大量高质量的外链并非易事,需要耗费时间和精力。为了解决这个问题,外链建设平台应运而生。本文将探讨如何......
  • 数据结构学习笔记-堆排序
    堆排序算法的设计与分析问题描述:设计并分析堆排序【前置知识:什么是堆?】堆(Heap)是一种特殊的树形数据结构,它满足以下两个条件之一:最大堆(MaxHeap):每个节点的值都大于或等于其子节点的值。换句话说,根节点的值是整个堆中最大的。最小堆(MinHeap):每个节点的值都小于或等于其......
  • ArcGIS和ArcGIS Pro快速加载ArcGIS历史影像World Imagery Wayback
    ArcGIS在线历史影像网站WorldImagery Wayback(网址:https://livingatlas.arcgis.com/wayback/)提供了数期历史影像在线浏览服务,之前不少自媒体作者在文中宣称其能代表GoogleEarth历史影像。1、一点对比(1)同一级别下的版本覆盖面以下述区域为例,自2014年2月20日至2022年5月18......
  • 快速使用 ThreadPoolExecutor 并行加速
    总览一般的Python脚本只会用上单线程。对于IO密集型任务,用多线程加速会快得多。本文会给出一个模板,使用ThreadPoolExecutor进行并行加速。注意,由于GIL的存在,对于CPU密集型任务ProcessPoolExecutor是更好的选择。快速使用ThreadPoolExecutor请看以下模板。fro......
  • 8645 归并排序(非递归算法)
    Description用函数实现归并排序(非递归算法),并输出每趟排序的结果输入格式第一行:键盘输入待排序关键的个数n第二行:输入n个待排序关键字,用空格分隔数据输出格式每行输出每趟排序的结果,数据之间用一个空格分隔输入样例105480932671输出样例4508392......
  • 常见排序算法
    文章目录冒泡排序插入排序希尔排序选择排序堆排快速排序递归版前后指针版用栈实现快排归并排序用循环方式归并冒泡排序冒泡排序应该是最先学到的一种排序算法,也是最简单的一种排序算法。思路就是,从最前面开始两两比较大的放后面。但是要注意一个问题每走一趟就把......
  • 【排序算法】快速排序
    一、定义:        快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法(也叫Hoare排序),是一种基于分治的排序方。其基本原理是将待排序的数组通过一趟排序分成两个独立的部分,其中一部分的所有数据比另一部分的所有数据都要小,然后再按此方法对这两部分数据分别进......
  • SpringBoot 快速实现 api 加密!
    在项目中,为了保证数据的安全,我们常常会对传递的数据进行加密。常用的加密算法包括对称加密(AES)和非对称加密(RSA),博主选取码云上最简单的API加密项目进行下面的讲解。https://gitee.com/isuperag/rsa-encrypt-body-spring-boot项目介绍该项目使用RSA加密方式对API接口返回的......