Странные результаты при измерении сортировки по основанию

Я измеряю время выполнения сортировки по основанию и подсчету, используя модуль timeit. Я использую 100 наборов случайных целых чисел, лежащих на интервале ‹0; 1000000>. Все целые числа уникальны в пределах множества. Первый набор состоит из 10000 целых чисел, последний набор 1000000 целых чисел. Каждый набор сортируется десять раз, и записывается среднее время (как full time/10). В файле журнала сортировки Radix есть некоторые странные результаты, и я не уверен, проблема ли это в модуле 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

Вы можете видеть, что сортировка большего набора, чем предыдущий, иногда занимает меньше времени. В случае сортировки подсчетом время увеличивается нормально.

Вот мой код для Radix Sort:

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_{0}k.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_{0}k.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 файле.


person jirinovo    schedule 28.12.2014    source источник
comment
Адекватно ли вы заранее перетасовали свои списки?   -  person Ffisegydd    schedule 28.12.2014
comment
@Ffisegydd Что вы подразумеваете под «предварительно перемешанным»?   -  person jirinovo    schedule 28.12.2014
comment
Ну, вы пытаетесь проверить своего рода, да? Итак, вы с самого начала убедились, что ваши списки не отсортированы?   -  person Ffisegydd    schedule 28.12.2014
comment
@Ffisegydd Эти списки состоят из случайных целых чисел, поэтому я уверен, что они не отсортированы. И из того, как работают эти алгоритмы, видно, что не имеет значения, отсортированы они или не отсортированы перед сортировкой.   -  person jirinovo    schedule 28.12.2014


Ответы (1)


Ваша сортировка по основанию много выделяет и перераспределяет память по ходу дела. Интересно, может, дело в этом? Что, если бы вы выделили память только один раз для своих структур данных и смирились с тем, что вам нужно будет выделить больше памяти.

Помимо этого, проверили ли вы, что окончательные списки действительно отсортированы? Просматривали ли вы другие статистические данные для времени вашей сортировки по основанию (т. е. мин./макс./медиана), возможно, есть случайные выбросы, их изучение может помочь вам объяснить ситуацию.

person user1245262    schedule 28.12.2014
comment
Да, не в коде, но я проверил окончательные списки с помощью sortedList == sorted(unsortedList), и алгоритм работает надежно. Хорошо, я посмотрю на модуль timeit точнее, потому что я читал несколько типов использования (например здесь для алгоритма сортировки) - person jirinovo; 28.12.2014
comment
@jirinovo Попробуйте переписать со структурами данных, которые не выделяются во время работы вашей программы. Со всеми добавлениями и расширениями в вашем коде я не удивлюсь, если есть разумная вероятность запуска сборки мусора, свопинга на диск или других процессов управления памятью. - person user1245262; 28.12.2014