快速排序(Quick sort)

快速排序,和归并排序一样,采用分而治之和递归的方式。

原理##

快速排序的步骤为:

  1. 从待排序列表中选择一个轴(piovt:一般默认为选择index为0的元素,改进快速排序算法一般在轴的选择上作文章)。
  2. 划分大小区域(partitioning):对数组进行重新排序,使得值小于pivot的所有元素都在pivot之前,而值大于pivot的所有元素都在它之后(相同的值可以是任意一种)。 在此分区之后,枢轴处于其最终位置。 这称为分区操作。
  3. 递归调用1,2:递归地将上述步骤应用于具有较小值的元素的子列表,并分别应用于具有较大值的元素的子列表。
    递归的基本情况是大小为零或一的数组,按定义按顺序排列,因此它们永远不需要排序。

代码实现##

def quick_sort(a_list):
    quick_sort_helper(a_list, 0, len(a_list) - 1)


def quick_sort_helper(a_list, first, last):
    if last <= first:
        return

    split_point = partition(a_list, first, last)
    quick_sort_helper(a_list, first, split_point - 1)
    quick_sort_helper(a_list, split_point + 1, last)


def partition(a_list, first, last):
    pivot_value = a_list[first]

    left_mark = first + 1
    right_mark = last
    done = False
    while not done:
        while left_mark <= right_mark and a_list[left_mark] <= pivot_value:
            left_mark += 1
        while left_mark <= right_mark and a_list[right_mark] >= pivot_value:
            right_mark -= 1
        if right_mark < left_mark:
            done = True
        else:
            temp = a_list[left_mark]
            a_list[left_mark] = a_list[right_mark]
            a_list[right_mark] = temp

    temp = a_list[first]
    a_list[first] = a_list[right_mark]
    a_list[right_mark] = temp

    return right_mark

代码解读##

算法的重点在于partition函数,该函数的操作是在列表中将index值为0的元素通过比较,交换,放置在最终排序所在的位置。同时比它小的元素在它的左边,比它大的元素在它的右边。最后分别对左右的子列表进行递归计算。最后得到的列表就是排序好的列表。

总结##

快速排序是一种不稳定的排序算法。 快速排序的数学分析表明,平均而言,该算法需要进行\(O(nlog_2n)\)比较以对n个项进行排序。 在最坏的情况下,它会进行\(O(n^2)\)比较,尽管这种情况很少见。
要分析quick_sort函数,请注意,对于长度为list的列表,如果分区始终出现在列表的中间,则会再次出现\(O(log_2n)\)分区。 为了找到分割点,需要根据枢轴值检查每个𝑛项。 结果是\(O(nlog_2n)\)。 此外,在合并排序过程中不需要额外的内存。
不幸的是,在最坏的情况下,分裂点可能不在中间,并且可能非常偏向左侧或右侧,留下非常不均匀的分割。 在这种情况下,排序𝑛项目列表分为排序0项目列表和𝑛 - 1项目列表。 然后排序𝑛 - 1列表分为大小为0的列表和大小为𝑛 - 2的列表,依此类推。 结果是\(O(n^2)\)排序,具有递归所需的所有开销。

三平均分区法###

关于这一改进的最简单的描述大概是这样的:与一般的快速排序方法不同,它并不是选择待排数组的第一个数作为中轴,而是选用待排数组最左边、最右边和最中间的三个元素的中间值作为中轴。这一改进对于原来的快速排序算法来说,主要有两点优势:

  1. 首先,它使得最坏情况发生的几率减小了。
  2. 其次,未改进的快速排序算法为了防止比较时数组越界,在最后要设置一个哨点。
posted @ 2018-11-04 14:12  Jeffrey_Yang  阅读(260)  评论(0编辑  收藏  举报