快速排序算法:python实现、时间复杂度和算法稳定性讨论

快速排序算法的思路

默认升序排列
排列中的一个元素,如果它左边的数都比它小,右边的数都比它大,那么它的索引就是完全排序后的索引,这个元素就找到了它在排序后的正确位置。
对左右两边的子序列重复这个方法(递归过程),最后就能得到一个有序的序列。

具体步骤

  1. 定义三个变量,to_sort表示先安排谁的位置,默认为一个排列的第一个数字;low表示左边的游标,和to_sort相同,默认为一个排列的第一个数字;high表示右边的游标,默认为一个排列的最后一个数字。
  2. 对于一个排列,第一个数字就是我们要安排的数字,已经存入了to_sort变量中,实际上是一个坑,一个可以被覆盖的空位。首先从high游标开始往左走,遇到小于to_sort的数字就停止,然后把这个数字扔给low游标(这里low游标的数字会被覆盖,而且high本身的位置上由于数值已经备份给了low游标,所以形成一个可以被覆盖的坑),此时轮到low游标走,low游标向右走,遇到比to_sort大或者相等的(这里我们统一把相等的值扔到右边)就停下扔给high,然后high继续走,high和low交替向中间靠拢直到相遇,相遇的位置会形成一个可以被覆盖的坑(它的值已经在其他位置被保存),把to_sort扔到最后剩下的坑里,完成第一次排序
    图片非原创,其他地方找来的
  3. 第一次排序之后,左右两边分别形成一个排列,对排列重复2过程,当最后子排列中只有一个数值的时候,就完成了排序,这是一个递归过程。

python代码实现

def quick_sort(arr, start, end):
    # 递归的出口
    if start >= end:
        return
    # 需要三个变量,分别记录要找位置的数值(默认为第一个,存在to_sort中),左边的low游标,右边的high游标
    to_sort = arr[start]
    # 左边游标
    low = start
    # 右边游标
    high = end
    # 当low >= high的时候,说明完成了一个元素位置的查找,跳出循环
    while low < high:
        # 控制右边游标的移动,如果数字比to_sort大或者相等,游标持续左移,不满足条件时,将值赋给另一个游标
        while low < high and arr[high] >= to_sort:
            high -= 1
        arr[low] = arr[high]
        # 控制左边游标的移动,如果数字比to_sort小,游标持续右移,不满足条件时,将值赋给另一个游标
        while low < high and arr[low] < to_sort:
            low += 1
        arr[high] = arr[low]
    # 剩下一个low的坑,用来放to_sort
    arr[low] = to_sort
    # 这个地方用递归,对左右两边的排列再次调用快排
    quick_sort(arr, start, low-1)
    quick_sort(arr, low+1, end)


arr1 = [20, 87, 20, 89, 20, 20, 10]
quick_sort(arr1, 0, len(arr1)-1)
print(arr1)

时间复杂度的探讨

最优时间复杂度O(nlogn)

最优的情况就是我们每个要安排的元素都可以把待排序的区间分裂成左右两个排列。
第1次排序 得到2个排列 共安排了1个元素 时间复杂度n
第2次排序 得到4个排列 共安排了2+1个元素 时间复杂度n
第3次排序 得到8个排列 共安排了4+2+1个元素 时间复杂度n
以此类推,如果要安排n个元素,需要log2(n+1)次排序,而单次排序的时间复杂度固定为n,所以时间复杂度为nlogn

最坏时间复杂度O(n2

最坏的情况就是每次要安排的元素都位于边缘,只在to_sort的一边有元素,而另一边没有。
第1次排序 得到1个排列 共安排了1个元素 时间复杂度n
第2次排序 得到1个排列 共安排了1+1个元素 时间复杂度n
第3次排序 得到1个排列 共安排了1+1+1个元素 时间复杂度n
以此类推,如果要安排n个元素,需要n次排序,而单次排序的时间复杂度固定为n,所以时间复杂度为O(n2

快排算法稳定性的讨论

排序算法的稳定性指的是对于值相同的两个数字,排序后会不会改变它们的相对位置,如果改变就是不稳定的。
比如考虑列表a = [18,20,20,25,10],排序后第一个20(a[1])会被扔到第二个20(a[2])的右边,那么列表中的两个20非原序,即非稳定的。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python中常用的排序算法有冒泡排序、选择排序、插入排序快速排序、归并排序和堆排序等。每个排序算法时间复杂度不同。 冒泡排序时间复杂度为O(n^2)。每次比较相邻的两个元素,如果顺序错误,则交换位置,重复这个过程直到整个数组排序完成。由于需要多次遍历数组,所以时间复杂度较高。 选择排序时间复杂度也为O(n^2)。每次从未排序的部分中选择最小的元素,然后与未排序部分的第一个元素交换位置。重复这个过程直到整个数组排序完成。 插入排序时间复杂度为O(n^2)。将未排序的元素逐个插入已排序的部分中的正确位置。具体操作是从后往前比较,如果当前元素比前一个元素小,则交换位置,重复这个过程直到整个数组排序完成。 快速排序的平均时间复杂度为O(nlogn)。通过选择一个基准元素,将数组分为两个子数组,其中一个子数组的所有元素小于基准元素,另一个子数组的所有元素大于基准元素。然后对两个子数组分别递归地进行快速排序,最后合并两个子数组得到有序数组。 归并排序时间复杂度也为O(nlogn)。通过将数组递归地拆分成更小的子数组,然后对子数组进行排序,最后将排好序的子数组合并成一个有序数组。 堆排序时间复杂度为O(nlogn)。首先将数组构建成一个最大堆或最小堆,然后不断地将堆顶元素与堆的最后一个元素交换位置,并重新调整堆,重复这个过程直到整个数组排序完成。 综上所述,Python中常用的排序算法及其时间复杂度如上所示。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [常见排序算法及其对应的时间复杂度和空间复杂度](https://blog.csdn.net/weixin_39734493/article/details/110335437)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [python实现排序算法 时间复杂度稳定性分析 冒泡排序、选择排序、插入排序、希尔排序](https://blog.csdn.net/weixin_39852276/article/details/110335432)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值