python - 快速排序更快地对较大的数字进行排序?

标签 python algorithm performance sorting quicksort

我正在用 Python 乱搞,试图练习我的排序算法并发现了一些有趣的东西。

我有三个不同的数据:

  • x = 要排序的数字数
  • y = 数字所在的范围(所有随机生成的整数)
  • z = 排序所用的总时间

时间:
x = 100000 和
y = (0,100000) 那么
z = 0.94182094911 秒

时间:
x = 100000 和
y = (0,100) 那么
z = 12.4218382537 秒

时间:
x = 100000 和
y = (0,10) 那么
z = 110.267447809 秒

有什么想法吗?

代码:

import time
import random
import sys

#-----Function definitions

def quickSort(array): #random pivot location quicksort. uses extra memory.
    smaller = []
    greater = []
    if len(array) <= 1:
        return array
    pivotVal = array[random.randint(0, len(array)-1)]
    array.remove(pivotVal)
    for items in array:
        if items <= pivotVal:
            smaller.append(items)
        else:
            greater.append(items)
    return concat(quickSort(smaller), pivotVal, quickSort(greater))

def concat(before, pivot, after):
    new = []
    for items in before:
        new.append(items)
    new.append(pivot)
    for things in after:
        new.append(things)
    return new

#-----Variable definitions
list = []
iter = 0
sys.setrecursionlimit(20000)
start = time.clock() #start the clock

#-----Generate the list of numbers to sort
while(iter < 100000):
    list.append(random.randint(0,10))  #modify this to change sorting speed
    iter = iter + 1
timetogenerate = time.clock() - start #current timer - last timer snapshot

#-----Sort the list of numbers
list = quickSort(list)
timetosort = time.clock() - timetogenerate #current timer - last timer snapshot

#-----Write the list of numbers
file = open("C:\output.txt", 'w')
for items in list:
    file.write(str(items))
    file.write("\n")
file.close()
timetowrite = time.clock() - timetosort #current timer - last timer snapshot

#-----Print info
print "time to start: " + str(start)
print "time to generate: " + str(timetogenerate)
print "time to sort: " + str(timetosort)
print "time to write: " + str(timetowrite)
totaltime = timetogenerate + timetosort + start
print "total time: " + str(totaltime)

--------修改了新代码------------------------- ---

def quickSort(array): #random pivot location quicksort. uses extra memory.
    smaller = []
    greater = []
    equal = []
    if len(array) <= 1:
        return array
    pivotVal = array[random.randint(0, len(array)-1)]
    array.remove(pivotVal)
    equal.append(pivotVal)
    for items in array:
        if items < pivotVal:
            smaller.append(items)
        elif items > pivotVal:
            greater.append(items)
        else:
            equal.append(items)
    return concat(quickSort(smaller), equal, quickSort(greater))

def concat(before, equal, after):
    new = []
    for items in before:
        new.append(items)
    for items in equal:
        new.append(items)
    for items in after:
        new.append(items)
    return new

最佳答案

我认为这与支点的选择有关。根据您的分区步骤的工作方式,如果您有很多重复值,当遇到许多重复时,您的算法可能会退化为二次行为。例如,假设您正在尝试对该流进行快速排序:

 [0 0 0 0 0 0 0 0 0 0 0 0 0]

如果您不小心执行分区步骤,这可能会很快退化。例如,假设您选择枢轴作为第一个 0,留下数组

 [0 0 0 0 0 0 0 0 0 0 0 0]

进行分区。您的算法可能会说较小的值是数组

 [0 0 0 0 0 0 0 0 0 0 0 0]

而较大的值是数组

 []

这种情况会导致快速排序退化为 O(n2),因为每个递归调用只是将输入的大小缩小一倍(即,通过拉出枢轴元素) .

我注意到在您的代码中,您的分区步骤确实这样做了:

for items in array:
    if items <= pivotVal:
        smaller.append(items)
    else:
        greater.append(items)

给定一个流是同一元素的一大堆副本,这会将所有这些副本放入一个数组中以进行递归排序。

当然,这似乎是一个荒谬的案例——这与减少数组中的值数量有什么关系? - 但当您对许多不明显的元素进行排序时,它确实会出现。特别是,经过几次分区后,您可能会将所有相等的元素组合在一起,这会将您带入这种情况。

关于如何防止这种情况发生的讨论,有一个非常棒的演讲 by Bob Sedgewick and Jon Bentley关于如何修改分区步骤以在存在重复元素时快速工作。它连接到 Dijkstra 的 Dutch national flag problem ,而且他们的解决方案非常聪明。

一个可行的选择是将输入分成三组 - 小于、等于和大于。一旦你以这种方式分解输入,你只需要对更少和更大的组进行排序;相等的组已经排序。上面的谈话链接显示了如何或多或少地就地执行此操作,但由于您已经在使用非就地快速排序,因此修复应该很容易。这是我的尝试:

for items in array:
    if items < pivotVal:
        smaller.append(items)
    elif items == pivotVal:
        equal.append(items)
    else:
        greater.append(items)

顺便说一句,我从来没有写过一行 Python,所以这可能是完全非法的语法。但我希望这个想法很清楚! :-)

关于python - 快速排序更快地对较大的数字进行排序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4964004/

相关文章:

php - 使用广度优先搜索用 PHP 解决 3x3 难题

c# - PerfView:分析应用程序的性能,包括数据库调用

python - 连接字符串的大多数 Pythonic 方式

python - Linux、Python打开终端运行全局python命令

python - 名称错误 : name 'array' is not defined in python

c - 判断一个数是否是另一个数的幂的算法

python - Pandas - 逗号分隔行中的每个字符串在数据框中出现的频率

c - 链表在打印时仅显示第一个节点元素

android - 图像处理算法在安卓智能手机上的性能

android - 如何 VACUUM RoomDatabase?