QuickSort对于低范围数据运行缓慢

时间:2018-03-23 21:14:22

标签: python python-3.x algorithm quicksort

最近我在python中比较了不同类型的排序算法。我注意到我的快速排序没有处理重复值的输入。

dragInteractionEnabled = true

然后我测试了这个

def compare_asc(a, b):
    return a <= b


def partition(a, p, r, compare):
    pivot = a[r]
    i = p-1
    for j in range(p, r):
        if compare(a[j], pivot):
            i += 1
            a[i], a[j] = a[j], a[i]
    a[i+1], a[r] = a[r], a[i+1]
    return i + 1


def part_quick_sort(a, p, r, compare):
    if p < r:
        q = partition(a, p, r, compare)
        part_quick_sort(a, p, q-1, compare)
        part_quick_sort(a, q+1, r, compare)


def quick_sort(a, compare):
    part_quick_sort(a, 0, len(a)-1, compare)
    return a

在这个示例中,我得到import numpy as np from timeit import default_timer as timer import sys test_list1 = np.random.randint(-10000, 10000, size=10000).tolist() start = timer() test_list1 = quick_sort(test_list1, compare_asc) elapsed = timer() - start print(elapsed) test_list2 = np.random.randint(0, 2, size=10000).tolist() start = timer() test_list2 = quick_sort(test_list2, compare_asc) elapsed = timer() - start print(elapsed) ,所以我添加了RecursionError: maximum recursion depth exceeded in comparison,之后我得到了这个输出:

sys.setrecursionlimit(1000000)

任何人都可以解释为什么它只在排序第二个列表时抛出这个递归深度错误?为什么会有这么大的时差?

1 个答案:

答案 0 :(得分:3)

这里有一个提示:传递一个列表,其中所有元素都是相同的,并逐行观察它的作用。元素数量需要时间二次,并递归到大约等于元素数量的水平。

通常的快速分区实现从两端开始,因此在完全相同的情况下,列表切片大约被切成两半。在这种情况下,你可以获得不错的表现,只需从左到右看&#34;方法,但最明确的方法是划分为三个区域:&#34;小于&#34;,&#34;等于&#34;,&#34;大于&# 34。

这可以在一次从左到右的传递中完成,通常称为&#34; Dutch national flag problem&#34;。正如链接页面上的文字所示,

  

这个问题的解决方案对设计排序算法很感兴趣;特别是,必须对重复元素具有鲁棒性的快速排序算法的变体需要一个三向分区函数...

CODE

具体而言,这是一个完整的实施,一次通过&#34;从左到右&#34;单枢轴3路分区。它还包含了其他众所周知的变化,这些变化使得quicksort能够稳健地用于生产。注意:

  • 您不能创建一个避免最坏情况二次时间的纯粹快速排序。您可以做的最好的是平均时间O(N*log(N))时间,并且(如下所示,一种方式)使最坏情况O(N**2)时间不太可能。
  • 您可以(如下所示)保证最坏情况下的对数递归深度。
  • 在这种方法中,所有相等元素的列表并不是一个坏的情况,而是一个非常的情况:分区例程只调用一次。

代码:

from random import randrange

def partition(a, lo, hi, pivot):
    i = L = lo
    R = hi
    # invariants:
    # a[lo:L]  < pivot
    # a[L:i]  == pivot
    # a[i:R]     unknown
    # a[R:hi]  > pivot
    while i < R:
        elt = a[i]
        if elt < pivot:
            a[L], a[i] = elt, a[L]
            L += 1
            i += 1
        elif elt > pivot:
            R -= 1
            a[R], a[i] = elt, a[R]
        else:
            i += 1
    return L, R

def qsort(a, lo=0, hi=None):
    if hi is None:
        hi = len(a)

    while True:   # sort a[lo:hi] in place
        if hi - lo <= 1:
            return

        # select pivot ar random; else it's easy to construct
        # inputs that systematically require quadratic time
        L, R = partition(a, lo, hi, a[randrange(lo, hi)])

        # must recur on only the shorter chunk to guarantee
        # worst-case recursion depth is logarithmic in hi-lo
        if L - lo <= hi - R:
            qsort(a, lo, L)
            # loop to do qsort(a, R, hi)
            lo = R
        else:
            qsort(a, R, hi)
            # loop to do qsort(a, lo, L)
            hi = L