Самый эффективный алгоритм сортировки для большого набора чисел

Я работаю над большим проектом, я не буду обобщать его здесь, но этот раздел проекта должен взять очень большой текстовый документ (минимум около 50 000 слов (не уникальный)), и вывести каждый уникальный слово в порядке от наиболее часто используемого к наименее используемому (вероятно, первые три будут «a», «an» и «the»).

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

Какие-либо предложения?


person aterimperator    schedule 05.06.2009    source источник
comment
Какой язык вы используете? Некоторые языки имеют встроенные обработчики для некоторых из этих вещей (например, LINQ).   -  person Eric    schedule 05.06.2009
comment
C++ В любом случае, этой информации на данный момент предостаточно, я сегодня слишком много работал, мне нужно будет заняться этим завтра вечером.   -  person aterimperator    schedule 06.06.2009


Ответы (9)


Во-первых, вам понадобится карта word -> count. 50 000 слов — это немного — в памяти легко уместится, так что не о чем беспокоиться. В С++ вы можете использовать стандартный STL std::map.

Затем, когда у вас есть карта, вы можете скопировать все ключи карты в вектор.

Затем отсортируйте этот вектор с помощью пользовательского оператора сравнения: вместо сравнения слов сравните количество на карте. (Не беспокойтесь о конкретном алгоритме сортировки — ваш массив не такой большой, поэтому вам подойдет любая стандартная библиотечная сортировка.)

person Igor Krivokon    schedule 05.06.2009

Я бы начал с быстрой сортировки и пошел дальше.

Посетите вики-страницу об алгоритмах сортировки, чтобы узнать о различиях.

person Eric    schedule 05.06.2009
comment
+1 за ссылку. Всем программистам необходимо хотя бы базовое понимание алгоритмов сортировки. - person Matthew Vines; 05.06.2009

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

person JP Alioto    schedule 05.06.2009

Взгляните на ссылку. Наглядное представление о том, как работает другой алгоритм. Это даст вам подсказку!

Алгоритмы сортировки

person aJ.    schedule 05.06.2009
comment
Мне больше нравится этот vision.bc.edu/~dmartin /обучение/сортировка/anim-html/all.html - person Tom Leys; 05.06.2009
comment
Оба они, кажется, предполагают, что оболочка лучше. - person aterimperator; 07.06.2009
comment
По состоянию на 18 марта 2013 г. и ссылка в ответе, и ссылка в комментарии Тома Лейса недействительны. - person Olfan; 18.03.2013

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

Первый шаг. Создайте хеш-карту со словами в качестве ключевых значений и частотностью в качестве связанных значений. Вы будете заполнять эту хеш-карту при анализе файла. Пока вы это делаете, обязательно отслеживайте самую высокую встречаемую частоту. Этот шаг имеет сложность O(n).

Второй шаг. Создайте список с количеством записей, равным наибольшей частоте из первого шага. Индекс каждого слота в этом списке будет содержать список слов с частотным подсчетом, равным индексу. Таким образом, слова, встречающиеся в документе 3 раза, попадут, например, в список[3]. Переберите хеш-карту и вставьте слова в соответствующие места в списке. Этот шаг имеет сложность O(n).

Третий шаг. Пройдитесь по списку в обратном порядке и выведите все слова. Этот шаг имеет сложность O(n).

В целом этот алгоритм выполнит вашу задачу за O(n) время, а не O(nlogn), которое требуется для быстрой сортировки.

person MahlerFive    schedule 05.06.2009
comment
Первый шаг O(n*m), где n — количество слов во входных данных, m — количество уникальных слов. Второй шаг использует память O(m) и делает это с шаблоном произвольного доступа, что ужасно для кеша. Если бы третий шаг использовался для ввода другого фрагмента кода, ему потребовалось бы выделить o(n) памяти. - Все это означает, что ваш код будет иметь плохую производительность памяти, которая будет доминировать над всеми очевидными улучшениями кода. - person Tom Leys; 05.06.2009
comment
Если вы использовали действительно эффективный хэш, первый шаг может быть только O(m), если вам очень повезет и не будет конфликтов хэшей. - person Tom Leys; 05.06.2009

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

Каждый раз, когда в моем профиле появляется сортировка, я пробую основные сорта. У меня никогда не было ничего, что превзошло бы и Quicksort, и Combsort.

person Nosredna    schedule 05.06.2009
comment
Это может быть поздний ответ. Но я полностью согласен с вами. Combsort работает очень быстро. Что удивительно, так это то, что сортировка гребнем — это небольшая вариация пузырьковой сортировки, которая чертовски медленная. Мне не удалось найти никаких ссылок, в которых говорится об анализе сложности комбинированной сортировки. Wiki говорит, что средняя сложность n^2/2^p. Но нет никаких подробностей о том, как это достигается. - person arunmoezhi; 15.04.2013

Я думаю, вы хотите сделать что-то, как описано в следующем посте:

http://karephul.blogspot.com/2008/12/groovy-closures.html

Языки, которые поддерживают закрытие, значительно упрощают решение, например, LINQ, как упомянул Эрик.

person Community    schedule 05.06.2009

Для больших наборов вы можете использовать так называемую «индексацию на основе сортировки» при поиске информации, но для 50 000 слов вы можете использовать следующее:

  • прочитать весь файл в буфер.
  • проанализируйте буфер и создайте вектор токенов с помощью struct token { char *term, int termlen; } term — указатель на слово в буфере.
  • отсортировать таблицу по терминам (лексикографическому порядку).
  • установить entrynum = 0, перебрать вектор терминов, когда термин новый, сохранить его в векторе: struct { char *term; внутренняя частота; } в index entrynum установите частоту равной 1 и увеличьте номер записи, в противном случае увеличьте частоту.
  • отсортировать вектор по частоте в порядке убывания.
person bill    schedule 13.06.2009

Вы также можете попробовать реализовать цифровые деревья, также известные как Trie. Вот ссылка

person unix_user    schedule 28.01.2013