Вы просто замечаете влияние других процессов на вашем компьютере.
Вы запускаете функцию сортировки 100 раз для размера ввода 1 и записываете общее время, потраченное на это. Затем вы запускаете его 100 раз для размера ввода 2 и записываете общее время, потраченное. Вы продолжаете делать это, пока не достигнете размера ввода 1000.
Допустим, время от времени ваша ОС (или вы сами) начинаете делать что-то интенсивное использование процессора. Допустим, этот «всплеск» длится столько, сколько вам потребуется, чтобы запустить функцию сортировки 5000 раз. Это означает, что время выполнения будет выглядеть медленным при 5000/100 = 50 последовательных входных размеров. Некоторое время спустя происходит новый всплеск, и другой диапазон размеров ввода выглядит медленным. Это именно то, что вы видите на графике.
Я могу придумать, как избежать этой проблемы. Запустите функцию сортировки только один раз для каждого размера ввода: 1, 2, 3, ..., 1000. Повторите этот процесс 100 раз, используя те же 1000 входов (это важно, см. Пояснение в конце). Теперь возьмите минимум времени, потраченного на каждый входной размер, в качестве конечной точки данных для диаграммы.
Таким образом, ваши пики должны влиять только на каждый входной размер только несколько раз из 100 прогонов; и поскольку вы берете минимум, они, скорее всего, никак не повлияют на окончательный график.
Если ваши всплески действительно очень длинные и частые, вам, конечно, может потребоваться увеличить количество повторений сверх текущих 100 на входной размер.
Глядя на ваши всплески, я замечаю, что выполнение замедляется ровно в 3 раза во время всплеска. Я предполагаю, что ОС дает вашему процессу Python один слот из трех во время высокой нагрузки. Правильно ли мое предположение или нет, рекомендованный мной подход должен решить эту проблему.
EDIT:
Я понял, что не уточнил ни одного момента в моем предложенном решении вашей проблемы.
Следует ли использовать один и тот же вход в каждом из ваших 100 прогонов для заданного размера ввода? Или следует использовать 100 различных (случайных) входов?
Поскольку я рекомендовал взять минимальное время выполнения, входные данные должны быть одинаковыми (в противном случае вы получите неправильный вывод, поскольку вы будете измерять сложность алгоритма в лучшем случае вместо средней сложности!).
Но когда вы берете те же входные данные, вы создаете некоторый шум на диаграмме, поскольку некоторые входные данные просто быстрее, чем другие.
Таким образом, лучшим решением является решение проблемы загрузки системы, не создавая проблему только одного ввода на размер ввода (это, очевидно, псевдокод):
seed = 'choose whatever you like'
repeats = 4
inputs_per_size = 25
runtimes = defaultdict(lambda : float('inf'))
for r in range(repeats):
random.seed(seed)
for i in range(inputs_per_size):
for n in range(1000):
input = generate_random_input(size = n)
execution_time = get_execution_time(input)
if runtimes[(n, i)] > execution_time:
runtimes[(n,i)] = execution_time
for n in range(1000):
runtimes[n] = sum(runtimes[(n,i)] for i in range(inputs_per_size))/inputs_per_size
Теперь вы можете использовать runtimes [n] для построения своего графика.
Конечно, в зависимости от того, является ли ваша система очень шумной, вы можете изменить (repeats, inputs_per_size)
с (4,25)
на (10,10)
или даже (25,4)
.