美文网首页
快速排序

快速排序

作者: 小吉头 | 来源:发表于2020-11-22 21:35 被阅读0次

关键点

  • 将第一个元素放到中间的位置,使得左边都小于它,右边都大于它
  • 第一个元素的左边和右边,按照步骤一递归


尝试代码实现

def quick_sort(li,left,right):
    if left < right:
        mid = partition(li,left,right)
        quick_sort(li,left,mid-1)
        quick_sort(li,mid+1,right)

def partition(li,left,right):
    tmp = li[left]
    while left < right: #从右边取值放左边空位,从左边取值放右边空位。这样不断循环。
        while li[right] >= tmp:
            right -= 1
        li[left] = li[right]
        while li[left] <= tmp:
            left += 1
        li[right] = li[left]
    li[left] = tmp
    return left

运行后发现,报错了:

while li[right] >= tmp:
IndexError: list index out of range

从第一趟排序过程走一遍,发现并不满足左边比5小,右边比5大:



一开始的示例图是我们预期的情况,看下实际代码执行,left和right相遇时,left指向的空位其实是有值的,因为值比5小,所以left继续向右走,导致最后5的顺序错误


代码修正

确保left < right

def quick_sort(li,left,right):
    if left < right:
        mid = partition(li,left,right)
        quick_sort(li,left,mid-1)
        quick_sort(li,mid+1,right)

def partition(li,left,right):
    tmp = li[left]
    while left < right:
        while left < right and li[right] >= tmp:
            right -= 1
        li[left] = li[right]
        while left < right and li[left] <= tmp:
            left += 1
        li[right] = li[left]
    li[left] = tmp
    return left

时间复杂度

普通情况下复杂度


共logn层,粗略假设每层大概插入的位置在中间左右,每次调用partition()后,下次的基数比原来少一半左右。但是每层的复杂度加起来仍然是O(n)
复杂度是:O(nlogn)

最坏情况下复杂度

li = [10,9,8,7,6,5,4,3,2,1]排序时,第一次排序结果:
第一次结果:

def quick_sort(li,left,right):
    if left < right:
        mid = partition(li,left,right) #li=[10,9,8,7,6,5,4,3,2,1],left=0,right=9。返回mid=9
        quick_sort(li,left,mid-1) #li=[1,9,8,7,6,5,4,3,2,10],left=0,right=8
        quick_sort(li,mid+1,right)#li=[1,9,8,7,6,5,4,3,2,10],left=10,right=9

第一次调用partition()后,左边还有9个数,右边0个,接下来也类似,每次都只减少1个数。容易导致超过最大递归深度


复杂度是:O(n^2)

解决最坏情况下的最大递归深度问题

left元素向后随机取数,和left指向的元素交换。随机取数为最大值概率比较低,这样就极大地避免每次排序后只减少一个数,即减少最大递归深度错误的出现。

import random

def quick_sort(li,left,right):
    if left < right:
        mid = random_partition(li,left,right)
        quick_sort(li,left,mid-1)
        quick_sort(li,mid+1,right)

#left元素向后随机取数,和left指向的元素交换
def random_partition(li,left,right):
    i = random.randint(left,right)
    li[i],li[left] = li[left],li[i]
    mid = partition(li,left,right)
    return mid


def partition(li,left,right):
    tmp = li[left]
    while left < right:
        while left < right and li[right] >= tmp:
            right -= 1
        li[left] = li[right]
        while left < right and li[left] <= tmp:
            left += 1
        li[right] = li[left]
    li[left] = tmp
    return left

其他方式实现

占用了一些内存,时间复杂度和上面两种情况一样,也要区分普通和最坏情况。为了尽可能避免最坏情况,也可以从后面元素中随机取一个跟第一个元素交换。

def quick_sort2(li):
    if len(li) < 2:
        return li
    tmp = li[0]
    left = [value for value in li[1:] if value <= tmp]
    right = [value for value in li[1:] if value > tmp]
    left = quick_sort2(left)
    right = quick_sort2(right)
    return left + [tmp] + right

相关文章

  • 七大排序算法之快速排序

    七大排序算法之快速排序 @(算法笔记)[排序算法, 快速排序, C++实现] [TOC] 快速排序的介绍: 快速排...

  • 面试准备--排序

    堆排序 快速排序(simple) 快速排序(regular) 归并排序 Shell排序 插入排序 选择排序 冒泡排序

  • 排序

    插入排序 选择排序 冒泡排序 归并排序 快速排序* 三路快速排序

  • 算法笔记01-排序#2

    快速排序敢叫快速排序,那它一定得快。 快速排序 概述 快速排序也是分治排序的典型,它快,而且是原地排序。不过,要防...

  • PHP 实现快速排序

    导语 这篇了解下快速排序。 快速排序 快速排序(英语:Quicksort),又称划分交换排序(partition-...

  • 快速排序的Python实现

    目录 快速排序的介绍 快速排序的Python实现 快速排序的介绍 快速排序(quick sort)的采用了分治的策...

  • 数据结构与算法 快速排序

    起因:快速排序,又称分区交换排序,简称快排,之前没有了解过,抽空学习一下。 快速排序 1 快速排序 快速排序的定义...

  • 数组-快速排序

    采用快速方式对数组进行排序 快速排序百科:快速排序(Quicksort)是对冒泡排序算法的一种改进.快速排序是通过...

  • OC数据结构&算法

    更多整理资料尽在?一平米小站 目录 选择排序 冒泡排序 插入排序 快速排序 双路快速排序 三路快速排序 堆排序 选...

  • 要成功就做一百题-94

    题目名称 今天来几个排序,都是经典题目,包括带拆分的快速排序,堆排序,归并排序。 描述 快速排序快速排序核心就是分...

网友评论

      本文标题:快速排序

      本文链接:https://www.haomeiwen.com/subject/cadzbktx.html