python数据结构算法DAY2| 快速排序

发布于:2022-12-12 ⋅ 阅读:(252) ⋅ 点赞:(0)

目录

快速排序(quick sort)

1.什么是快速排序

2.快速排序思路

3.快速排序代码

4快速排序复杂度

5.快速排序函数与冒泡排序的效率比较

6.快速排序的缺点

解决办法:


快速排序(quick sort)

1.什么是快速排序

递归是快速排序的精髓,基本原理是采用分治法策略,把一个序列分为较小和较大的2个子序列,然后递归的排序子序列。

2.快速排序思路

1.首先挑选一个元素作为基准值(pivot)

2.分割重新排序数列,所以比基准值小的排在基准值一边,比基准值大的排在另外一边,完成基于基准值的排序

3.递归排序子序列:递归的将每次的基准值的左右两边排序,递归最底部的条件是判断数列元素大于1(left < right)

4.核心是partition函数,partition函数要做的是选择一个基准值(默认选择【left】),两个while循环实现基于基准值的排序

举例说明快速排序的思路

3.快速排序代码

def quick_sort(lst,left,right):  # 需要传入一个列表lst,以及最左边后最后边的位置
 
       if left < right:  # 如果左边小于右边,则说明列表内至少有两个元素
 
            mid = partition(lst,left,right)   # 通过partition获得基准值mid
 
    quick_sort(lst,left,mid-1)   # 递归左边的元素
 
    quick_sort(lst,mid+1,right)    # 递归右边的元素

那么快速排序的关键就在于如何设置基准值,即框架内的partition函数?

举例说明:

有如下列表

第一步:我们先存取“5”的位置,此时“5”的位置空出来,随后从左边和右边开始与“5”比较;

第二步:从最右边的位置的元素与“5”比较,如果比“5”大那么不动,发现比“5”小的(“2”)则放到刚刚空出来的“5”的位置;

第三步:移动了“2”之后原来“2”的位置就空出来,则从当前“2”的位置(左边)开始查找,将比“5”大的数(7)移动到原先“2”的位置;

第四步:重复第二到三步,直到左右的位置重合,即为“5”最终存放的位置

以上便是partition函数的思路(可能有点难理解)

实现快速排序算法代码

def partition(lst,left,right):  # partition(分割)函数
 
    tmp = lst[left]  # 存放基准点,以最左边的值为例
 
    while left < right:  # 当左边的位置(下标)小于右边的时候,说明还有至少两个元素,则进行排序
 
        while lst[right] >= tmp and left < right:  # 从右边找比tmp小的元素
 
            right -= 1  # 比tmp大,则往左移动一位
 
        lst[left] = lst[right]  # 如果出现lst[right] < tmp,则将右边的值lst[right]写到左边的空位lst[left]
 
        # print(f"从右边找比tmp小的数后的列表:{lst}")
 
        while lst[left] <= tmp and left < right:  # 从左边找比tmp大的元素lst[left],放到右边的空位上lst[right]
 
            left += 1
 
        lst[right] = lst[left]
 
        # print(f"从左边找比tmp大的数后的列表:{lst}")
 
    lst[left] = tmp  # 最后把tmp归位
 
    return left  # 返回mid的值
 
 
 
# lst1 = [5,7,4,2,6,8,3,1,9]
 
# print(f"分割前的列表{lst1}")
 
# partition(lst1,0,len(lst1)-1)
 
# print(f"最终tmp归为后的列表:{lst1}")
 
# 输出结果
 
# 分割前的列表[5, 7, 4, 2, 6, 8, 3, 1, 9]
 
# 从右边找比tmp小的数后的列表:[1, 7, 4, 2, 6, 8, 3, 1, 9]
 
# 从左边找比tmp大的数后的列表:[1, 7, 4, 2, 6, 8, 3, 7, 9]
 
# 从右边找比tmp小的数后的列表:[1, 3, 4, 2, 6, 8, 3, 7, 9]
 
# 从左边找比tmp大的数后的列表:[1, 3, 4, 2, 6, 8, 6, 7, 9]
 
# 从右边找比tmp小的数后的列表:[1, 3, 4, 2, 6, 8, 6, 7, 9]
 
# 从左边找比tmp大的数后的列表:[1, 3, 4, 2, 6, 8, 6, 7, 9]
 
# 最终tmp归为后的列表:[1, 3, 4, 2, 5, 8, 6, 7, 9]
 
 
 
# 随后完成快速排序主体部分的代码
 
def quick_sort(lst, left, right):  # 需要传入一个列表lst,以及最左边后最后边的位置
 
    if left < right:  # 如果左边小于右边,则说明列表内至少有两个元素
 
        mid = partition(lst, left, right)  # 通过partition获得基准值mid
 
        quick_sort(lst, left, mid - 1)  # 递归左边的元素
 
        quick_sort(lst, mid + 1, right)  # 递归右边的元素
 
 
 
 
 
lst2 = [5,7,4,2,6,8,3,1,9]
 
print(f"初始列表:{lst2}")
 
quick_sort(lst2,0,len(lst2)-1)
 
print(f"快速排序后的{lst2}")
 
# 输出结果
 
# 初始列表:[5, 7, 4, 2, 6, 8, 3, 1, 9]
 
# 快速排序后的[1, 2, 3, 4, 5, 6, 7, 8, 9]

4快速排序复杂度

O(nlogn)  (一层的复杂度是logn,总共n层)

5.快速排序函数与冒泡排序的效率比较

from runtime import *
import random,copy
@runtime
def bubble_sort(lst):
for i in range(len(lst) - 1):  # 表示第i趟

    exchange = False  # 每一趟做标记

    for j in range(len(lst)-i-1):  # 表示箭头

        if lst[j] > lst[j+1]: # 此时是升序排序,>改为<则改为了降序

            lst[j],lst[j+1] = lst[j+1],lst[j]

            exchange = True  # 进行了交换,exchange标记为Ture

    # print(f"第{i+1}趟后的列表为:{lst}")  # 查看排序过程

    if not exchange: # 如果没有进行交换,直接返回,优化的步骤

        return
@runtime
 
def time_quick_sort(lst):
 
    quick_sort(lst, 0, len(lst) - 1)
 
 
 
lst3 = list(range(10000))
 
random.shuffle(lst3)
 
lst_quick = copy.deepcopy(lst3)
 
lst_bubble = copy.deepcopy(lst3)
 
time_quick_sort(lst_quick)
 
bubble_sort(lst_bubble)
 
# 输出结果
 
# time_quick_sort执行用时0.0309906005859375s
 
# bubble_sort执行用时11.869966506958008s

6.快速排序的缺点

快速排序出现最糟糕情况时,例如列表从的元素是从10000到1,则突破了计算的最大深度,且复杂度达到了O(n2),空间复杂度也达到了O(n)。

此时可以通过调整运算的最大深度来进行运算(import sys --> sys.setrecursionlimit(100000)),但仍然运算的时间会变长,那么如何修改呢?

解决办法:

使用shuffle函数打乱序列排序

此时可以通过修改基准值位置随机取来调整,这样虽然不可以完全避免最坏情况,但是最坏情况的概率会降低。

十大排序之四大排序总结

稳定性说明:

3 2 1 2 4

稳定的排序可以保证左右两边的2的位置不变;

当我们换成字典来看时:

{"name":'a',"age":18}

{"name":'b',"age":19}

{"name":'a',"age":20}

如果按字母排序,稳定的排序,两个‘a’的位置不会改变

总的来说,挨个移动比较的排序算法为稳定的排序。

代码的复杂度:代表代码难不难写,应个人能力和主观感受而定。


网站公告

今日签到

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