测量基数排序时的奇怪结果

Posted

技术标签:

【中文标题】测量基数排序时的奇怪结果【英文标题】:Strange results when measuring Radix sort 【发布时间】:2014-12-28 14:45:42 【问题描述】:

我正在使用timeit 模块测量基数和计数排序的执行时间。我正在使用 100 组位于区间 。所有整数在集合中都是唯一的。第一组由 10000 个整数组成,最后一组由 1000000 个整数组成。每组排序十次并记录平均时间(作为full time/10)。在基数排序的日志文件中有一些奇怪的结果,我不确定这是timeit模块的问题还是我的排序算法:

基数排序日志

integers count, average time
......,.............
760000,1.51444417528
770000,1.31519716697
780000,1.33663102559
790000,1.3484539343
800000,1.37114722616
810000,1.61706798722
820000,1.4034960851
830000,1.65582925635
840000,1.68017826977
850000,1.69828582262
860000,1.47601140561
870000,1.73875506661
880000,1.75641094733
890000,1.54894320189
900000,1.80121665926
910000,1.56070168632
920000,1.8451221867
930000,1.8612749805
940000,1.61202779665
950000,1.63757506657
960000,1.64939744866
970000,1.66534313097
980000,1.68155078196
990000,1.69781920007
1000000,2.00389959994

您可以看到,比以前更大的集合的排序有时需要更少的时间。在计数排序的情况下,时间通常会增加。

这是我的基数排序代码:

from __future__ import division

def sortIntegerList (listToSort, base):
    maxkey = len(str(max(listToSort)))

    for i in range(maxkey):
        bucketList = [[] for x in range(base)]

        for number in listToSort:
            bucketList[(number//base**i) % base].append(number)

        listToSort = []

        for l in bucketList:
            listToSort.extend(l)

    return listToSort

这是我的计数排序代码:

def sortIntegerList (listToSort):
    maxkey = max(listToSort)
    countingList = [0 for x in range(maxkey + 1)]

    for i in listToSort:
        countingList[i] += 1

    for i in range(1, len(countingList)):
        countingList[i] += countingList[i-1]

    sortedList = [0 for x in range(len(listToSort) + 1)]

    for i in listToSort:
        sortedList[countingList[i]] = i
        countingList[i] -= 1

    del sortedList[0]
    return sortedList

这里是测量执行时间的代码:

import timeit

outputFileCounting = "count,time\n"
outputFileRadix = "count,time\n"

# Counting Sort
for x in range(10, 1001, 10):
    setup_counting = """
from sorters import counting_sort
import cPickle
with open("ri_0-1000k_0k.pickle", mode="rb") as f:
    integerList = cPickle.load(f)
        """.format(x)

    time_counting = timeit.timeit("""counting_sort.sortIntegerList(integerList)""",
                                setup = setup_counting, number=10)

    outputFileCounting += "0,1\n".format(str(x*1000), time_counting/10)

    with open("sort_integer_counting_results.csv", mode="w") as f:
        f.write(outputFileCounting)

# Radix Sort
for x in range(10, 1001, 10):
    setup_radix = """
from sorters import radix_sort
import cPickle
with open("ri_0-1000k_0k.pickle", mode="rb") as f:
    integerList = cPickle.load(f)
        """.format(x)

    time_radix = timeit.timeit("""radix_sort.sortIntegerList(integerList, 10)""",
                                setup = setup_radix, number=10)

    outputFileRadix += "0,1\n".format(str(x*1000), time_radix/10)

    with open("sort_integer_radix_results.csv", mode="w") as f:
        f.write(outputFileRadix)

每个整数集都以列表形式存储在pickle 文件中。

【问题讨论】:

您是否充分地预先洗牌? @Ffisegydd “预洗牌”是什么意思? 嗯,你正在尝试测试一个排序,是吗?那么,您是否确保您的列表一开始就没有排序? @Ffisegydd 这些列表是由随机整数组成的,所以我确信它们是未排序的。从这些算法的工作方式可以看出,在排序之前它们是排序还是未排序都没有关系。 【参考方案1】:

您的基数排序在执行过程中会进行大量内存分配和重新分配。我想知道,也许,这就是问题所在。如果您只为数据结构分配一次内存,并接受需要过度分配的事实会怎样。

除此之外,您是否检查过最终列表是否真正排序?您是否查看了基数排序(即最小/最大/中位数)时间的其他统计数据,也许偶尔会有异常值,调查它们可以帮助您解释问题。

【讨论】:

是的,不是在代码中,但我已经用sortedList == sorted(unsortedList) 检查了最终列表,并且算法可靠地工作。好吧,我会更准确地看timeit模块,因为我阅读了几种类型的用法(for example here for sorting algorithm) @jirinovo 尝试使用程序运行时未分配的数据结构进行重写。通过代码中的所有附加和扩展,如果有合理的机会触发垃圾收集、交换到磁盘或其他内存管理进程,我不会感到惊讶。

以上是关于测量基数排序时的奇怪结果的主要内容,如果未能解决你的问题,请参考以下文章

基数排序 Java 实现

八大基本排序--基数排序

排序算法之基数排序

桶排序/基数排序(Radix Sort)

基数排序不排序“一些”数字?

排序算法——快速排序