快速排序计数

时间:2017-07-15 00:11:51

标签: python-3.x

再次提出Python问题。 我想计算快速排序执行的比较操作的数量。因为我使用递归函数,我不认为将count = 0赋值给函数体的开头是不合适的,所以我做了如下。

def QuickSort(lst, count = 0):
    if len(lst) > 1:
        pivot_idx = len(lst) // 2
        smaller_nums, larger_nums = [], []

        for idx, num in enumerate(lst):

            if idx != pivot_idx:
                if num < lst[pivot_idx]:
                    smaller_nums.append(num)

                else:
                    larger_nums.append(num)

        count = QuickSort(smaller_nums, count + 1)[1]
        count = QuickSort(larger_nums, count + 1)[1]
        lst[:] = smaller_nums + [lst[pivot_idx]] + larger_nums

    return lst, count

然而,在计算之后,我确认计数远远低于我的预期。根据big o,快速排序必须显示n * log(n)的计算,但它显示了更低的计数。例如,在使用1000个随机元素对列表进行排序时,我们希望看到计数为1000 * log(1000)= 6907,但实际上只有1164个计数。我想知道我是否滥用了函数中的计数或误解了它。 谢谢。

2 个答案:

答案 0 :(得分:2)

您的帖子在几点上有误:

  • Big-O允许任意常数因子,也忽略&#34; small&#34; n的值,其中&#34;小&#34;对于任何给定的分析,可以任意大。所以你的计算毫无意义。
  • 你的罪名是错的。每个循环迭代有一个比较。你还在计算别的东西。
  • 这是一种编码计数的奇怪方法。只需使用全局变量。

试试这个。请注意,您确实使用了两倍于此报告的比较。通过更智能的实现可以消除循环索引不是枢轴的检查。

c = 0

def QuickSort(lst):
    if len(lst) <= 1:
        return lst
    pivot_idx = len(lst) // 2
    smaller, larger = [], []
    for idx, num in enumerate(lst):
        if idx != pivot_idx:
            global c
            c += 1
            (larger, smaller)[num < lst[pivot_idx]].append(num)
    return QuickSort(smaller) + [lst[pivot_idx]] + QuickSort(larger)

def Run(n):
    lst = [random.randint(0,1000) for r in xrange(n)]
    QuickSort(lst)
    print c

Run(1000)

如果你对使用全局变量的前景感到震惊,那么你可以将排序包装在一个类中:

import random

class QuickSort:

    def __init__(self):
        self.comparisons = 0

    def sort(self, lst):
        if len(lst) <= 1:
            return lst
        pivot_idx = len(lst) // 2
        smaller, larger = [], []
        for idx, num in enumerate(lst):
            if idx != pivot_idx:
                self.comparisons += 1
                (larger, smaller)[num < lst[pivot_idx]].append(num)
        return self.sort(smaller) + [lst[pivot_idx]] + self.sort(larger)

def Run(n):
    lst = [random.randint(0,1000) for r in xrange(n)]
    quicksort = QuickSort()
    print quicksort.sort(lst)
    print quicksort.comparisons

Run(100)

答案 1 :(得分:0)

在吉恩(Gene)提供的答案的基础上,添加了打印语句和排序“错误”范围,他的示例非常有助于我理解快速排序以及错误术语对操作性能比较的巨大影响。

    class QuickSort:

    def __init__(self):
        self.comparisons = 0

    def sort(self, lst):
        k_err = 0 # k << n, the value the sort array can be in error 
        if len(lst) <= 1:
            return lst
        pivot_idx = len(lst) // 2
        smaller, larger = [], []
        for idx, num in enumerate(lst):
            if idx != (pivot_idx) :
                self.comparisons += 1
                try:
                  (larger, smaller)[(num - k_err) < lst[pivot_idx]].append(num)
                except:
                  (larger, smaller)[(num + k_err) < lst[pivot_idx]].append(num)
            print(pivot_idx,"larger", self.comparisons, larger)
            print(pivot_idx, "smaller", self.comparisons,  smaller, )
        return self.sort(smaller) + [lst[pivot_idx]] + self.sort(larger)

def Run(n):
    random.seed(100) 
    lst = [random.randint(0,round(100,0)) for r in range(n)]
    quicksort = QuickSort()
    print(len(lst), lst)
    print(quicksort.sort(lst))
    print(quicksort.comparisons, quicksort.comparisons/n, ((quicksort.comparisons/n)/math.log(n,10)), math.log(n,10)  )