快速排序Quick Sort

Quick Sort

主要思想:

1、递归;

2、让元素去到自己该去的地方(左边都比它小,右边都比它大)

约定:首先归位第一个元素

将第一个元素提出并存储为temp;

设置left指向列表最左边,right指向列表最右侧,从列表右侧开始向左遍历,把每一个元素都与temp比较:如果比temp大,那么right向左移动一位,继续比;如果比temp小,就把这个值赋值给left此时所指的位置;然后从left+1的位置开始遍历,如果遇到比temp小的,left向右移动一位,继续比较;如果比temp大的,就把这个值赋值给right此时所指的位置,以此往复,直到left与right重合时,此时的位置,就是temp该在的位置

演示如下:

# 原列表 [5, 6, 3, 7, 4, 1, 8, 2, 9],5存起来
# 第一次,从9开始,9比5大,看前一位的2,2比5小,就把2放在原来5的位置
right [2, 6, 3, 7, 4, 1, 8, 2, 9] 
# 第二次,从6开始,6比5大,就把6放在原来2的位置
left  [2, 6, 3, 7, 4, 1, 8, 6, 9] 
# 第三次,从8开始,8比5大,看前一位的1,1比5小,就把1放在原来6的位置
right [2, 1, 3, 7, 4, 1, 8, 6, 9]
# 第四次,从3开始,3比5小,看后一位的7,7比5大,就把7放在原来1的位置
left  [2, 1, 3, 7, 4, 7, 8, 6, 9]
# 第五次,从4开始,4比5小,就把4放在原来7的位置
right [2, 1, 3, 4, 4, 7, 8, 6, 9]
# 第六次,从4开始,此时left与right重合,指向原列表的4的位置
left  [2, 1, 3, 4, 4, 7, 8, 6, 9]
# 最后,把存起来的5放在这个位置
end   [2, 1, 3, 4, 5, 7, 8, 6, 9]

运用递归的方法,将 归位好的数的两边切片为两个小列表,继续归位,直到左右指针(left、right)重合。代码如下:

# 归位函数
def partition(list,left,right):
    temp = list[left] # 存储最左值
    while left < right: # 用循环保证temp能够去到该去的位置,left<right是控制循环结束的条件
        # 先从右边找比temp小的数
        while left < right and list[right] >= temp:
            right -= 1
        list[left] = list[right]
        # 再从左边找比temp大的数
        while left < right and list[left] <= temp:
            left += 1
        list[right] = list[left]
    list[left] = temp
    return left

# 快速排序函数
def quick_sort(list,left,right):
    if left < right:
        mid = partition(list,left,right)
        quick_sort(list,left,mid-1)
        quick_sort(list,mid+1,right)
    return list
-----------------------------------------------
list3 = [5,6,3,7,4,1,8,2,9]
print(quick_sort(list3,0,len(list3)-1))
---->[1, 2, 3, 4, 5, 6, 7, 8, 9]
  1. 外层循环的left<right是为了控制循环结束,循环的作用又是为了使内层的两个小循环往复作用,而不是各走一次就停下

  2. 内层循环的left<right也是为了控制循环结束,因为整体上是left与right向内移动,找到两者重合的位置,所以要设置left<right,内层循环跳出,在外层循环也跳出,就是时候把目标数放到这个地方去

  3. partition函数中内层的两个小循环的条件中>=和<=,当遇到与temp值相等的数,放左边与放右边其实没什么区别,都行,但还是要移动的

  4. partition函数返回的是temp值的下标,因为两个指针都重合了,就取left了

  5. 在quick_sort函数中,递归调用时的切片,一个是从left开始到mid-1,另一个是从mid+1到right

  6. 时间复杂度为O(nlogn),用不那么严谨的方法推导:假定每次切片都是刚好对半开,那么就是每次递归都在二分列表,所以就是O(logn);partition函数虽然有两层循环,但实际上整个列表只遍历了一次,所以时间复杂度是O(n),所以整个快速排序算法就是O(nlogn)

  7. 递归对于python有递归最大深度,会消耗一定的系统资源

  8. 快速排序的最坏情况:

    # 当列表为[9,8,7,6,5,4,3,2,1]时,9被提出
    # 第一次,从右边找,1比9小,1放在原来9的位置,9放在1的位置上9只有左边有数,右边是空的
    [1, 8, 7, 6, 5, 4, 3, 2, 9]
    # 第二次,在列表[1, 8, 7, 6, 5, 4, 3, 2]中重新调用partition函数继续
    # 发现1就在原本的位置上,又对右侧的列表[8, 7, 6, 5, 4, 3, 2]继续调用partition函数
    # 以此类推,每一次递归调用都只能归位一个元素
    

    这种情况下,快速排序的时间复杂度就达到了O(n的平方)

  9. 对于时间复杂度,有:最快时间复杂度,一般时间复杂度和最坏时间复杂度,通常情况下只考虑后两种

posted @ 2025-03-05 00:15  Hua的阿鸡  阅读(22)  评论(0)    收藏  举报