快速排序算法

文章目录

    • 一、快速排序概述
      • 1.1 什么是快速排序
      • 1.2 快速排序过程解析
    • 二、快速排序的具体步骤
    • 三、快速排序的代码实现

一、快速排序概述

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张图片

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

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

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

二、快速排序的具体步骤

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

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

    快速排序算法_第2张图片

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

    快速排序算法_第3张图片

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

    快速排序算法_第4张图片

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

    快速排序算法_第5张图片

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

    快速排序算法_第6张图片

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

三、快速排序的代码实现

【案例需求】

假设待排序序列如下:

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 进行排序,最终排序结果正确。

你可能感兴趣的:(算法与数据结构,排序,快速排序,排序算法,java,算法)