【算法学习笔记06】分治思想之QuickSort快速排序

快速排序是常见的冒泡排序的改进。和经典的排序算法合并排序一样,快速排序也运用了分治的思想。冒泡排序是在一个序列中只把一个元素冒泡到数列的一端,而快排是每次选中一个pivot当作基准元素,小于pivot放在pivot的左边,反之放在右边,从而将序列分为了两个部分。

1 快排的前身冒泡排序

        冒泡排序的思路:就像是冒泡一样,依次比较相邻的两个数,如果第一个大于第二个那么就将这两个数交换。重复以上的步骤,直到没有任何一个数字需要比较。

 如图就像冒泡一样:

图片来源:简书,侵删  

        冒泡排序的实现:      

def bubble(arr):
    n=len(arr)
    for i in range(n-1):
        for j in range(i,n):
            if arr[i]>arr[j]:
                temp=arr[i]
                arr[i]=arr[j]
                arr[j]=temp
    return arr

        时间复杂度分析: 由于在遍历数组时,每次遍历都会再遍历一遍数组,所以时间复杂度为O(N^2)

2 快速排序QuickSort

        2.1 快速排序的思路:每次都在数列中选定一个数当作pivot一个基准。将数列依次与pivot进行比较,如果小于pivot,那么将该元素放在pivot左边,反之放在pivot右边。这样每一轮计算都能将数组分为两个部分,比pivot大和比pivot小。这是一个很典型的分治思想,将一个大问题分成了子问题。

        往往pivot的设立是不定的,可以是序列的中间,可以是开头,结尾。

         2.2选定pivot后每次该如何移动到左边或右边:知道了大概的算法思路,现在要来解决,每次计算时如何将比pivot小的移动到左边,比它大的移动到右边。

        我们采取这样的办法,在序列最左边最右边设立两个哨兵,分别叫做i,j。这两个哨兵会向序列中间移动,i向右-> ,  j向左<-。当i指向的数字大于pivot时,i停止移动,当j指向的数字小于pivot时,j停止移动。当i和j都停止移动时,将i和j进行交换。直到最后i和j重复,此时停止比较。此时我们就可以将序列分为两部分,小于pivot和大于pivot,那么整个pivot的位置就是可以确定下来的了。

如以下例子,我们拥有一个序列[1,2,7,5,6,4,8],并且将5作为pivot:

         重复以上的方法,直到pivot左右都只有一个元素后停止,不再划分。

    2.3 快速排序的图解:

来源百度,侵删 

        2.4 快速排序的代码实现:

        在有了每一次的排序方法后,我们只需要不断地将序列分割。一个典型的分治思想,我们可以运用递归的方法来实现。

        假定每次pivot都选中序列的最左边位置:

def quick_sort(list, low, high):
    i = low
    j = high
    if i >= j:
        return list
    pivot = list[i]  
    while i < j:
        while i < j and list[j] >= pivot:
            j = j - 1
        list[i] = list[j]
        while i < j and list[i] <= pivot:
            i = i + 1
        list[j] = list[i]
    list[i] = pivot
    quick_sort(list, low, i - 1)
    quick_sort(list, j + 1, high)
    return list

时间复杂度分析:

        快排对我们选择pivot非常相关,

        最坏的情况:如果pivot刚好就选中的是最大的或者最小那一个,那么我们根本就起不到分块的作用,所以时间复杂度是O(n^2)

        最好的情况:每次的pivot选择刚好就是在中间的那个,每次都平分,那么就和归并排序一样,时间复杂度也是O(nlogn)

        平均时间复杂度为O(nlogn)

        详细证明过程可以参考快速排序时间复杂度分析 - 知乎 (zhihu.com)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值