■ 快速排序
个人感觉快速排序相对还好理解一些。大的框架上来说,快速排序使用的是递归的思想。
具体描述: 首先获取数组的第0元素作为一个基准(pivot),然后从第1元素开始向右遍历,将所有小于基准的值都尽量往左摆放。具体来说那就是在遍历过程中建立两个游标,一个游标i用来做全遍历,另一个游标d_index用来标明到那个元素为止,前面的所有元素都已经是被判定为小于基准因此被放到左边的边界。比较第i元素和基准大小,对于每比较到一次第i元素小于基准的情况,就交换当前i和d_index两个元素,并且将d_index自增1。遍历完一趟后此时应该交换d_index-1(此时的第d_index元素是属于大于基准的哦),这样基准元素就到了它正确的位置,剩余的事情就是再快速排序一下整个序列中[0:d_index-1]以及[d_index:]这两个子序列即可。
另外由于用了递归,所以得斟酌下递归返回的条件。可以想象,当递归不断深入,对于右半区的序列而言返回的d_index是越来越大的,总有一天+1后会大于right,同时左半区越来越小,会在某一天等于0。这两者都是跳出递归的条件。总的来说,可以设置一个left<right的条件,控制跳出。
用代码来说:
def quick_sort(lst,left=0,right=None): if right is None: right = len(lst) - 1 if left < right: partitionIndex = partition(lst,left,right) # 递归处理左半区和右半区(虽说是半区,但并不一定是对半开,根据partitionIndex大小不同可能会有偏颇 quick_sort(lst,left,partitionIndex-1) quick_sort(lst,partitionIndex+1,right) def partition(lst,left,right): ''' 对lst的[left:right+1]序列进行分区,最终返回分区元素的下标d_index-1 函数返回时数组所处的状态应该是d_index-1左边的都比它小,右边都比它大 :param lst: :param left: :param right: :return: ''' pivot = left i = d_index = pivot + 1 while i <= right: if lst[i] < lst[pivot]: lst[d_index],lst[i] = lst[i],lst[d_index] d_index += 1 i += 1 lst[d_index-1],lst[pivot] = lst[pivot],lst[d_index-1] return d_index - 1
(上面的"将小于基准的元素尽量放到左边"的逻辑是从左到右依次循环遍历,碰到小于基准的放到当前未遍历区的最左端。另外还可能有多种实现逻辑,比如两个游标分别从左右开始,右边游标遇到小于基准的值就将其值赋到左边,左边游标则是遇到大雨基准值的放到右边。需要注意要灵活一些。)
如果要求quick_sort只能接受一个lst参数,那么可以考虑将递归放在partition中进行:
def partition(lst,left,right): if left >= right: return pivot = left d = i = left + 1 while i <= right: if lst[pivot] < lst[i]: lst[d],lst[i] = lst[i],lst[d] d += 1 i += 1 lst[d-1],lst[pivot] = lst[pivot],lst[d-1] pivot = d - 1 # 别忘了这步,否则pivot是0 partition(lst,left,pivot-1) partition(lst,pivot+1,right) def quick_sort(lst): left = 0 right = len(lst) - 1 partition(lst,left,right)