经典算法之快速排序(QuickSort)

发布于:2023-01-11 ⋅ 阅读:(640) ⋅ 点赞:(0)

活动地址:CSDN21天学习挑战赛

1. 概念

快速排序,从名字得知,算法效率是快而高。快速排序是使用分治策略将一个序列分为两个子序列,再针对子序列又继续分若干个子序列。快速排序应该算是在冒泡排序基础上的递归分治法。针对该算法思想,举个例子演示一下,大家就一目了然了。

输入

6 1 2 7 9 3 4 5 10 8

算法执行详解

首先在这个序列中,随机找一个元素作为基准数,一般来说,选择最左边的元素作为基准数,即选择元素6作为基准数,然后将所有比基准数大的数放在6的右侧,比基准数小的数放在6的左侧。那该如何执行呢?在初始状态下,数字6在序列的第1位。我们的目标是将6挪到序列中间的某个位置,假设这个位置是k。现在就需要寻找这个k,并且以第k位为分界点,左边的数都小于等于6,右边的数都大于等于6。
最左边为i,最右边为j,首先从右往左找一个小于6的数,再从左往右找一个大于6的数,然后交换他们。
在这里插入图片描述

首先j开始往左移动,找到比6小的元素,此时找到了元素5,然后i往右移动,找到了元素7,此时交换5和7,就得到 6 1 2 5 9 3 4 7 10 8
在这里插入图片描述
然后,j继续往左移动找比6小的元素,找到了4,i继续往右移动找比6大的元素,找到了9,然后交换4和9的位置
在这里插入图片描述
然后,j继续往左移动找比6小的元素,找到了3,i继续往右移动,也走到了3面前,i与j相遇,至此移动结束,交换3和6的位置,
在这里插入图片描述
由图可以得到,以6为基准,左侧都是比6小的元素,右侧都是比6大的元素,第一轮交换结束,再针对子序列进行二轮交换。以此类推。

2. 伪代码

3. 代码实现

quickSort(array, left, right)
  if (left < right)
    pivotIndex <- partition(array,left, right)
    quickSort(array, left, pivotIndex - 1)
    quickSort(array, pivotIndex, right)

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

3.1 Java版

package DirectlnsertTest;

import java.util.Arrays;

public class QuickSort {
    public static void main(String[] args) {
        int[] nums = { 6, 1, 2, 7, 9, 3, 4, 5, 10, 8 };
        quickSort(nums, 0, nums.length - 1);
        System.out.println("快速排序后:" + Arrays.toString(nums));
    }

    public static void quickSort(int[] nums, int start, int end) {
        if (start > end)
            return;
        int i, j, base;
        i = start;
        j = end;
        base = nums[start];
        while (i < j) {
            while (i < j && nums[j] >= base)
                j--;
            while (i < j && nums[i] <= base)
                i++;
            if (i < j) {
                swap(nums, i, j);
            }
        }
        swap(nums, start, i);
        quickSort(nums, start, j - 1);
        quickSort(nums, j + 1, end);
    }

    public static void swap(int[] nums, int left, int right) {
        int temp = nums[left];
        nums[left] = nums[right];
        nums[right] = temp;
    }
}

3.2 Python核心代码

def quickSort(arr, left=None, right=None):
    left = 0 if not isinstance(left,(int, float)) else left
    right = len(arr)-1 if not isinstance(right,(int, float)) else right
    if left < right:
        partitionIndex = partition(arr, left, right)
        quickSort(arr, left, partitionIndex-1)
        quickSort(arr, partitionIndex+1, right)
    return arr

def partition(arr, left, right):
    pivot = left
    index = pivot+1
    i = index
    while  i <= right:
        if arr[i] < arr[pivot]:
            swap(arr, i, index)
            index+=1
        i+=1
    swap(arr,pivot,index-1)
    return index-1

def swap(arr, i, j):
    arr[i], arr[j] = arr[j], arr[i]

4. 算法效率分析

4.1 时间复杂度

  • 最好情况
    当每次待排元素恰好都处在中间位置,将原有序列分为等长的子序列,每次划分子序列都是这种情况,那么总共划分的次数是以2为底n的对数,所以时间复杂度为n倍的以2为底n的对数
  • 最坏情况
    如果序列是一个有序序列,每次都要比较一遍,所以时间复杂度为O(n^2)
  • 平均情况
    综上所述,平均时间复杂度为以2为底n的对数

4.2 空间复杂度

因为是递归操作,所以在执行过程时需要在栈中保存相关信息,所以,平均情况是以2为底n的对数

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到