2016-11-20 2 views
4

У меня есть две реализации сортировки вставки. Первая довольно много транскрипция, например, в моем учебнике Java (хотя и с while петли вместо Java for циклом)Что вызывает разницу в производительности между этими двумя реализациями сортировки вставки?

def insertion_sort(array): 
    for i in range(1,len(array)): 
     j = i 
     while j > 0 and array[j] < array[j-1]: 
      array[j],array[j-1] = array[j-1], array[j] 
      j=j-1 
    return array 

вторых кажется более вещими реализации.

def insertion_sort2(array): 
    for i in range(1,len(array)): 
     for j in range(i-1,-1,-1): 
      if array[j+1] < array[j]: 
       array[j+1],array[j] = array[j],array[j+1] 
      else: 
       break 
    return array 

После синхронизации обоих, кажется, второй намного медленнее (от 3 до 4 раз медленнее), когда список уже отсортирован, или почти отсортирован. Однако, по мере увеличения количества инверсий, вторая реализация, похоже, одерживает верх (на 10-15% быстрее). Мне просто интересно, может ли кто-нибудь объяснить, в чем причина этого несоответствия. Благодаря!

Редактировать: Вот функция, которую я использую для создания случайного списка.

def rand_list(length): 
    return [random.randint(0,9*length) for _ in range(length)] 

Когда я хочу список, который частично отсортированных я просто называю list(range(length1)) + rand_list(length2).

Что касается сроков, сколько времени они берут для запуска, я использовал инструмент %timeit и разницу между двумя вызовами datetime.now(). Они дали довольно последовательные результаты. Также я хочу подчеркнуть, что каждый раз создаю новый список, не сортируя уже отсортированный список.

+0

Это Python 2 или 3? если Python 2 попробует xrange, диапазон предварительно распределяет список в Python2, тогда как в Python3 он возвращает итератор. – totoro

+1

Python 3, в частности 3.5.2. Я обновил теги, чтобы это отразить! – CopOnTheRun

+0

@totoro Вопрос заключался не в том, как сделать это быстрее, а в том, чтобы * объяснить разницу * –

ответ

1

Я смог воспроизвести ваши тайминги. Для случайных данных или данных с обратной сортировкой Вставка_sort2 немного быстрее, чем insertion_sort на Python3.6. Однако, как вы отметили, insertion_sort2 в три раза медленнее для данных, которые уже отсортированы.

Причина в первом случае (немного быстрее на случайных или отсортированных данных) является то, что range_iterator объекты генерируют целые числа быстрее, уменьшая (с использованием C-кода внутренне), чем вручную писать j=j-1 и j > 0 которые оба чистые шаги Python. Соответственно, как только цикл for-warm разогревается, он работает немного быстрее, чем эквивалент while-loop.

Причина того, что второй случай (намного медленнее по отсортированным данным) заключается в том, что цикл while дешевле, чем эквивалентный для цикла, когда есть нулевые итерации. Это связано с тем, что цикл while не имеет затрат на установку. Эквивалент для цикла все равно должен создать как диапазон объект, так и объект range_iterator, прежде чем он сможет определить, нет ли итераций. Соответственно, while-loops beat for-loops при пустом или почти пустом, потому что они избегают затрат на установку.

Смежные вопросы