Python中的快速排序比较计数器

时间:2014-05-24 02:06:18

标签: python counter quicksort

我有一个功能齐全的快速排序分区算法,我正在努力适应每个比较的计数器。这给了我一个挑战。关于把这个计数器放在哪里的任何提示?

def partition(mylist, start, end):
    pos = start
    for i in range(start, end):
        if mylist[i] < mylist[end]:
            mylist[i],mylist[pos] = mylist[pos],mylist[i]
            pos += 1
    mylist[pos],mylist[end] = mylist[end],mylist[pos]
    return pos

def quicksort(mylist, start, end, c):
    if start < end:
        pos = partition(mylist, start, end)
        c= c+ (len(mylist) -1    )   
        quicksort(mylist, start, pos - 1, c)
        c= c+ (len(mylist) -1    )       
        quicksort(mylist, pos + 1, end, c)
        c= c+ (len(mylist) -1    )


count = (0)
quicksort(x, 0, len(x)-1, count)

x指的是整数列表

3 个答案:

答案 0 :(得分:0)

您只有两个显式比较发生的地方,两个都是if语句,您可以在这些行之前放置一个计数器增量,例如:

counter = 0 # the global variable

def myfunc1():
    global counter
    counter = counter + 1
    if my < comparison:
         pass

def myfunc2():
    global counter
    counter = counter + 1
    if my < comparison:
         pass

print(counter)

例如,这并不计算for循环机制中的隐式比较,但我认为这不是你想要做的。

这是另一种可以传递计数器信息的可爱方式,并避免全局:

def myfunc1():
    myfunc1.counter += 1
    if 2 < 1:
         pass

def myfunc2():
    myfunc2.counter += 1
    if 1 < 2:
         pass

myfunc1.counter = 0
myfunc2.counter = 0

for f in (myfunc1, myfunc2):
    print("{} had {} comparisons".format(f.__name__, f.counter))

编辑/注意:这里的一些答案使用传递到每个函数的参数来跟踪计数器。这也是一种有效的方法,但实际上我们需要的是一种更通用的方法(否则你会无休止地在一般情况下绕过计数器,这很痛苦)。总结:

  • 全球变量(不是良好做法)
  • 功能属性(不是很好的做法)
  • 传递额外参数并返回额外参数(痛苦,但总的来说更好)
  • 实例变量,您的函数是类的成员(但如果您不想使用对象,该怎么办?)
  • 也许是一种更普遍适用的方式,下面的工作示例:

请注意,这使用装饰器,这意味着您可以添加任意数量的函数,例如less_than,而不会让他们理解计数要求。

def count(func):
    def inner(*args):
        inner.counter += 1
        return func(*args)
    inner.counter = 0
    return inner

@count
def less_than(op1, op2):
    return op1 < op2

def partition(mylist, start, end):
    pos = start
    for i in range(start, end):
        if less_than(mylist[i], mylist[end]):
            mylist[i],mylist[pos] = mylist[pos],mylist[i]
            pos += 1
    mylist[pos],mylist[end] = mylist[end],mylist[pos]
    return pos

def quicksort(mylist, start, end):
    if less_than(start, end):
        pos = partition(mylist, start, end)
        quicksort(mylist, start, pos - 1)
        quicksort(mylist, pos + 1, end)


x = [3, 2, 5, 1, 0]
quicksort(x, 0, len(x)-1)
print(x)
print(less_than.counter)

您可以通过创建一个计数器类来进一步组织它,该计数器类跟踪任何数量的函数以及它们被调用的所有时间,并删除函数属性,将数据存储在例如。字典。

答案 1 :(得分:0)

def partition(mylist, start, end, count):
    pos = start
    for i in range(start, end):
        count += 1
        if mylist[i] < mylist[end]:
            mylist[i],mylist[pos] = mylist[pos],mylist[i]
            pos += 1
    mylist[pos],mylist[end] = mylist[end],mylist[pos]
    return pos, count

def quicksort(mylist, start, end, count):
    if start < end:
        pos, count = partition(mylist, start, end, count)        
        count = quicksort(mylist, start, pos - 1, count)
        count = quicksort(mylist, pos + 1, end, count)
    return count


x = [2,3,1]
count = quicksort(x, 0, len(x)-1, 0)
print x, count

答案 2 :(得分:0)

要进一步改进一些现有的答案,除非你试图使这个尾部递归(这对于快速排序不起作用),你不需要传递计数值。相反,您可以只维护每个对分区的调用返回其已执行的所有比较的计数的不变量,并且每次调用quicksort都会返回由它执行的所有分区的计数或其中的任何递归调用。

此外,我们可以将quicksort的递归实现放入一个辅助函数中并将其包装在一个很好的函数中,该函数只需要一个列表,因此我们不必手动传入开始和结束索引。

实现这一点为我们提供了以下内容:

def _partition(mylist, start, end):
    count = 0
    pos = start
    for i in xrange(start, end):
        count += 1
        if mylist[i] < mylist[end]:
            mylist[i], mylist[pos] = mylist[pos], mylist[i]
            pos += 1
    mylist[pos], mylist[end] = mylist[end], mylist[pos]
    return pos, count

def _quicksort(mylist, start, end):
    count = 0
    if start < end:
        pos, count = _partition(mylist, start, end)        
        count += _quicksort(mylist, start, pos - 1)
        count += _quicksort(mylist, pos + 1, end)
    return count

def quicksort(mylist, start=None, end=None):
    if start is None:
        start = 0
    if end is None:
        end = len(mylist) - 1
    return _quicksort(mylist, start, end)

x = [2,3,1]
count = quicksort(x)
print x, count