快速排序算法

一、快速排序概述

1.1 什么是快速排序

快速排序(Quick Sort)是对冒泡排序的一种改进。它的基本思想是:通过一趟排序将待排序记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可以分别对着两部分记录继续进行排序,以达到整个序列有序。

1.2 快速排序过程解析

假设待排序的序列为 arr[0]~arr[n-1],首先任意选取一个元素(通常选取第一个)为基准元素(pivot),然后按照下述原则重新排列其余记录:将所有比它小的元素都安置在它的位置之前,将所有比它大的元素都安置在它的位置之后。最后以该基准元素所落的位置 i 作为分界线,可以将序列分割成 arr[0]~arr[i-1]arr[i+1]~arr[n-1] 两个子序列。这个过程叫做一趟快速排序(或一次划分)。

快速排序法的排序过程示意图如下所示:

在这里插入图片描述

从上图可以看到,完整的快速排序是建立在一趟快速排序之上的,它的具体步骤如下:

  1. 首先对待排序序列进行一趟快速排序;
  2. 一趟排序下来之后,基准元素的左边都是比它小的元素,右边都是比它大的元素;
  3. 再对基准元素左边的序列进行快速排序,对右边也进行快速排序;
  4. 重复步骤2、3,直到序列排序完成。

从快速排序的步骤中我们不难发现:快速排序其实使用的是分而治之的思想,它的排序过程是一个递归调用的过程

二、快速排序的具体步骤

快速排序最核心的地方在于一趟快速排序过程。一趟快速排序的具体步骤是(以从小到大排序为例):

  1. 附设两个指针 leftright,它们初始分别指向待排序序列的左端和右端;此外还要附设一个基准元素 pivot(一般选取第一个,本例中初始 pivot 的值为 20)。

    在这里插入图片描述

  2. 首先从 right 所指的位置从右向左搜索找到第一个小于 pivot 的元素,然后将其记录在基准元素所在的位置。

    在这里插入图片描述

  3. 接着从 left 所指的位置从左向右搜索找到第一个大于 pivot 的元素,然后将其记录在 right 所指向的位置。

    在这里插入图片描述

  4. 然后再从 right 所指向的位置继续从右向左搜索找到第一个小于 pivot 的元素,然后将其记录在 left 所指向的位置。

    在这里插入图片描述

  5. 接着,left 继续从左向右搜索第一个大于 pivot 的元素,如果在搜索过程中出现了 left == right ,则说明一趟快速排序结束。此时将 pivot 记录在 leftright 共同指向的位置即可。

    在这里插入图片描述

上述便是一轮快速排序的过程。

三、快速排序的代码实现

【案例需求】

假设待排序序列如下:

int[] arr = {8,9,1,7,2,3,5,4,6,0};

要求将上面的序列使用快速排序算法按照从小到大顺序排序。

【思路分析】

首先我们要确定一趟快速排序的代码,根据第二部分 快速排序的具体步骤 ,我们可以很容易写出一趟快速排序的代码:

/**
 * @Description 一趟快速排序:將序列分片,基准元素左边的都是小于它的,右边的都是大于它的
 * @Param [arr, left, right]
 */
public static int partition(int[] arr, int left, int right){
    int pivot = arr[left];        	// 选取第一个为基准元素
    while(left<right){
        /* 先从右往移动,直到遇见小于 pivot 的元素 */
        while (left<right && arr[right]>=pivot){
            right--;
        }
        arr[left] = arr[right];         // 记录小于 pivot 的值
        
        /* 再从左往右移动,直到遇见大于 pivot 的元素 */
        while(left<right && arr[left]<=pivot){
            left++;
        }
        arr[right] = arr[left];         // 记录大于 pivot 的值
    }
    arr[left] = pivot;            		// 记录基准元素到当前指针指向的区域
    return left;						// 返回基准元素的索引
}

运行后结果如下:

在这里插入图片描述

从运行结果中可以看到,基准元素 arr[0] 左边的都是比它小的,右边都是比它大的。

完整的快速排序其实就是对一趟快速排序的递归调用,当 left == right 时退出排序。

【代码实现】

完整的快速排序代码如下:

/**
 * 快速排序
 */
public static void quickSort(int[] arr, int left, int right){
    if (left < right){
        // 把数组分块
        int pivot = partition(arr, left, right);
        System.out.println(Arrays.toString(arr));
        // 基准元素左边递归
        quickSort(arr, left, pivot-1);
        // 基准元素右边递归
        quickSort(arr, pivot+1, right);
    }
}

public static int partition(int[] arr, int left, int right){
    int pivot = arr[left];        	// 选取第一个为基准元素
    while(left<right){
        /* 先从右往移动,直到遇见小于 pivot 的元素 */
        while (left<right && arr[right]>=pivot){
            right--;
        }
        arr[left] = arr[right];         // 记录小于 pivot 的值
        
        /* 再从左往右移动,直到遇见大于 pivot 的元素 */
        while(left<right && arr[left]<=pivot){
            left++;
        }
        arr[right] = arr[left];         // 记录大于 pivot 的值
    }
    arr[left] = pivot;            		// 记录基准元素到当前指针指向的区域
    return left;						// 返回基准元素的索引
}

经测试,使用上述快速排序代码对数组 arr 进行排序,最终排序结果正确。

  • 78
    点赞
  • 297
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值