Какой алгоритм использует сортировка?

24

Мне нужно добавить одно целое число в список, который уже отсортирован, так что он идет в нужном месте. Моя первая мысль была что-то вроде

(sort (cons newelt list) #'<)

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

Итак, какой алгоритм sortиспользует?

Буду ли я лучше делать что-то вроде следующего?

(let ((tail list))
  ;; The first element is never less-than
  (while (and tail (< newelt (cadr tail)))
    (setq tail (cdr tail)))
  (setcdr tail (cons newelt (cdr tail)))
  list)
Malabarba
источник
1
Я бы использовал двоичную кучу (например, heap.el ), если бы это была частая операция в моем коде.
lunaryorn
Пусть Bбудут изначально уже отсортированные listи Aи Cизначально пустые списки. Разделите Bна две части B1, B2длины mи mили m+1и m, сравните neweltс первым элементом B2. Если neweltэто расширение Aвправо с помощью B1и заменить Bс B2, в противном случае расширить Cего слева с B2и заменить Bна B1. После O(log n)таких шагов ничего не осталось B. Затем Aсодержит вещи ≤ newelt, и Cте > newelt, и конкатенация создает расширенный отсортированный список. Извиняюсь за не очень e-lispпохожий язык.
JFBU

Ответы:

26

Если у вас установлен исходный код Emacs, вы можете найти исходный код для sortс M-x find-function.

Там вы можете увидеть, что sortвыполняет сортировку слиянием. Он проверяет длину списка, разбивает список на две части, сортирует «переднюю» и «заднюю» части по рекурсии по отдельности, а затем объединяет их.

Что касается того, будет ли ваша реализация быстрее - измерьте это! Он более эффективен в теории (O (n) по сравнению с O (n log n)), но sortимеет преимущество в том, что он написан на C, поэтому результат может пойти в любую сторону. (Конечно, не забудьте побайтно скомпилировать вашу функцию.)

legoscia
источник
@Malabarba Для справки, на какой шкале длин вы тестировали?
Т. Веррон
8
Протестировано 1000 раз, вставляя случайное число в список из 1000 случайных чисел (все сгенерированы). Ручной метод был в 6 раз быстрее.
Малабарба