Изменения

Перейти к: навигация, поиск

Участник:Nechaev/Черновик

8254 байта добавлено, 15:50, 11 июня 2012
Нет описания правки
'''Сортировка подсчётомХеширование''' {{---}} алгоритм сортировки целых чисел класс методов поиска, идея которого состоит в вычислении хеш-кода, однозначно определяемого элементом с помощью хеш-функции, и использовании его, как основы для поиска (индексирование в памяти по хеш-коду выполняется за <tex>O(1)</tex>). В общем случае, однозначного соответствия между исходными данными и хеш-кодом нет в силу того, что количество значений хеш-функций меньше, чем вариантов исходных данных, поэтому существуют элементы, имеющие одинаковые хеш-коды — так называемые коллизии, но если два элемента имеют разный хеш-код, то они гарантированно различаются. Вероятность возникновения коллизий играет немаловажную роль в диапазоне от оценке качества хеш-функций.{{Определение|id=def1|definition=<tex>U </tex> {{---}} множество объектов (универсум).<br> <tex>h : U \rightarrow S = \mathcal {f} 0... m - 1 \mathcal {g}</tex> {{---}} называется хеш-функцией, где множество <tex>S</tex> до некоторой константы хранит ключи из множества <tex>kU</tex>, работающий за линейное время.<br> Если <tex>x \in U</tex> значит <tex>h(x) \in S</tex> <br> '''Коллизия:''' <tex>\exists x \neq y : h(x) = h(y)</tex>}}
== Основная идея ==
Основная идея состоит в том, чтобы для каждого элемента входного массива подсчитать количество элементов, меньших данного. Эта информация будет указывать на позиции элементов в отсортированном массиве. Например, если для элемента <tex>x</tex> количество таких элементов будет <tex>42</tex>, то <tex>x</tex> будет занимать <tex>43</tex>-ю позицию в отсортированном массиве. Если элементы могут иметь одинаковые значения, то необходимо модифицировать алгоритм, так как нельзя разместить все такие элементы в одну позицию.
== Простой алгоритм == Виды хеширования ====Это простейший вариант алгоритма* По способу хранения:** Статическое {{---}} фиксированное количество элементов. Создать вспомогательный массив <tex>C[0..k Один раз заполняем хеш- 1]</tex>, состоящий из нулей, затем последовательно прочитать элементы входного массива <tex>A</tex> таблицу и для каждого <tex>A[i]</tex> увеличить <tex>C[A[i]]</tex> осуществляем только проверку на единицуналичие в ней нужных элементов. Теперь достаточно пройти по массиву <tex>C</tex> и для каждого <tex>number \in \** Динамическое {{0, ..., k - 1\--}</tex> в массив <tex>A</tex> последовательно записать число <tex>number\</tex> <tex> C[number]</tex> раз} добавляем, удаляем и смотрим на наличие нужных элементов.<code> SimpleCountingSort for number = 0 to k * По виду хеш- 1 C[number] = 0;функции: for i = 0 to length[A] ** Детерминированная хеш- 1функция. C[A[i]] = C[A[i]] + 1; pos = 0; for number = 0 to k ** Случайная хеш- 1 for i = 0 to C[j] - 1 A[pos] = number; pos = pos + 1;</code>функция.
== Устойчивый алгоритм ==В этом варианте помимо входного массива <tex>A</tex> потребуется два вспомогательных массива — <tex>C[0..k Хеш- 1]</tex> для счётчика и <tex>B[0..n - 1]</tex> для отсортированного массива. Сначала следует заполнить массив <tex>C</tex> нулями, и для каждого <tex>A[i]</tex> увеличить <tex>C[A[i]]</tex> на 1. Далее подсчитывается число элементов меньше или равных текущему. Для этого каждый <tex>C[number]</tex>, начиная с <tex>C[1]</tex>, увеличивают на <tex>C[number - 1]</tex>. На последнем шаге алгоритма читается входной массив с конца и в каждый <tex>B[C[A[i]]]</tex> записывается <tex>A[i]</tex>, а значение <tex>C[A[i]]</tex> уменьшается на 1. Алгоритм устойчив. Устойчивость может потребоваться при [[Сортировка_подсчетом_сложных_объектов|сортировке сложных структур данных]]. <code> StableCountingSort for number таблица = 0 to k - 1 C[number] = 0; for i = 0 to length[A] - 1 C[A[i]] = C[A[i]] + 1; for number = 1 to k - 1 C[j] = C[j] + C[j - 1]; for i = length[A] - 1 to 0 B[C[A[i]]] = A[i]; C[A[i]] = C[A[i]] - 1;</code>
== Обобщение на произвольный целочисленный диапазон ==Если диапазон значений '''Хеш-табли́ца''' {{---}} структура данных, реализующая интерфейс ассоциативного массива. Представляет собой эффективную структуру данных для реализации словарей, а именно, она позволяет хранить пары (min ключ, значение) и max) заранее не известенвыполнять три операции: операцию добавления новой пары, можно воспользоваться линейным поиском min операцию поиска и max, что не повлияет на асимптотику алгоритма. При работе с массивом <tex>C</tex> из <tex>A[i]</tex> необходимо вычитать min, а при обратной записи прибавлятьоперацию удаления пары по ключу.
== Анализ = Введение ===В первом алгоритме первые Существует два цикла работают за <tex>\Theta(k)</tex> основных вида хеш-таблиц: ''с цепочками'' и <tex>\Theta(n)</tex>, соответственно; двойной цикл за <tex>\Theta(n + k)</tex>''открытой адресацией''. Во втором алгоритме циклы занимают <tex>\Theta(k)</tex>, <tex>\Theta(n)</tex>, <tex>\Theta(k)Хеш-таблица содержит некоторый массив </tex> и <tex>\Theta(n)H</tex>, соответственно. Итого оба алгоритма имеют линейную временную трудоёмкость <tex>\Thetaэлементы которого есть пары (n + kхеш-таблица с открытой адресацией)</tex>. Используемая память в первом алгоритме равна <tex>\Theta(k)</tex>, а во втором <tex>\Thetaили списки пар (n + kхеш-таблица с цепочками)</tex>.
Использование сортировки подсчётом целесообразноВыполнение операции в хеш-таблице начинается с вычисления хеш-функции от ключа. Хеш-код <tex>i = h(key)</tex> играет роль индекса в массиве <tex>H</tex>, а зная индекс, когда диапазон возможных мы можем выполнить требующуюся операцию (добавление, удаление или поиск). Количество коллизий зависит от хеш-функции; чем лучше используемая хеш-функция, тем меньше вероятность их возникновения. При вставке в хеш-таблицу размером 365 ячеек всего лишь 23-х элементов вероятность коллизии превышает 50 % (при равномерном распределении значений входных хеш-функции)<ref>[http://ru.wikipedia.org/wiki/Парадокс_дней_рождения Парадокс дней рождения {{---}} Википедия]</ref>. Способ разрешения коллизий — важная составляющая любой хеш-таблицы. Полностью избежать коллизий для произвольных данных достаточно мал невозможно в принципе, и хорошая хеш-функция в состоянии только минимизировать их количество. Но, в некоторых специальных случаях их удаётся избежать. Если все ключи элементов известны заранее, либо меняются очень редко, то можно подобрать хеш-функцию, с помощью которой, все ключи будут распределены по сравнению хеш-таблице без коллизий. Это хеш-таблицы с количеством ''прямой адресацией''; в них все операции, такие как: поиск, вставка и удаление работают за <tex>O(1)</tex>. Если мы поделим число хранимых элементов на размер массива <tex>H</tex> (число возможных значений хеш-функции), то узнаем коэффициент заполнения хеш-таблицы (англ. ''load factor''). От этого параметра зависит среднее время выполнения операций. === Свойства хеш-таблицы === На поиск элемента в хеш-таблице в сортируемом множествехудшем случае, напримерможет потребоваться столько же времени, если как и в списке, а именно <tex>\Theta(n = 1000000)</tex>, но на практике хеширование более эффективно. При некоторых разумных допущениях математическое ожидание времени поиска элемента в хеш-таблице составляет <tex>O(1)</tex>. А все операции (поиск, вставка и удаление элементов) в среднем выполняются за время <tex>O(1)</tex>.При этом не гарантируется, что время выполнения отдельной операции мало́, так как при достижении некоторого значения коэффициента заполнения необходимо [[Перехеширование. Амортизационный анализ|перехешировать]] таблицу: увеличить размер массива <tex>H</tex> и заново добавить в новую хеш-таблицу все элементы натуральные числа меньшие пары. == Разрешение коллизий == === Открытое хеширование ===[[Файл:open_hash.png|thumb|380px|right|Разрешение коллизий при помощи цепочек.]]Открытое хеширование или хеширование цепочками. Каждая ячейка <tex>i</tex> массива <tex>H</tex> содержит указатель на начало списка всех элементов, хеш-код которых равен <tex>i</tex>, либо указывает на их отсутствие. Коллизии приводят к тому, что появляются списки размером больше одного элемента. Время, необходимое для вставки в наихудшем случае равно <tex>1000O(1)</tex>. Это операция выполняет быстро, так как считается, что вставляемый элемент отсутствует в таблице, но если потребуется, то перед вставкой мы можем выполнить поиск этого элемента. Время работы поиска в наихудшем случае пропорционально длине списка, а если все <tex>n</tex> ключей захешировались в одну и ту же ячейку (создав список длиной <tex>n</tex>) время работы алгоритма поиска будет равно <tex>\Theta(n)</tex>плюс время вычисления хеш-функции, что ничуть не лучше, чем использование связного списка для хранения всех <tex>n</tex> элементов. Удаления элемента может быть выполнено за <tex>O(1)</tex>, как и вставка, при использовании двухсвязного списка.<ref>Анализ хеширования с цепочками, вы можете найти в книге Томаса Кормена: «Алгоритмы. Построение и анализ.»</ref> === Закрытое хеширование ===[[Файл:close_hash.png|thumb|380px|right|Пример хеш-таблицы с открытой адресацией и линейным пробированием.]]В случае метода открытой адресации (или по-другому {{---}} метод закрытого хеширования) все элементы хранятся непосредственно в хеш-таблице, без использования связных списков. Эффективность алгоритма падаетВ отличии от хеширования с цепочками, при использовании метода открытой адресации может возникнуть ситуация, когда необходимо сортировать различные хеш-таблица окажется полностью заполненной, следовательно будет невозможно добавлять в неё новые элементы. Так что при возникновении такой ситуации решением может быть динамическое увеличение размера хеш-таблицы, с одновременной её перестройкой. Рассмотрим один из методов борьбы с коллизиями.<ref>Другой метод борьбы с коллизиями {{---}} [[Двойное хеширование | двойное хеширование]]</ref> ==== Линейное разрешение коллизий ====В массиве <tex>H</tex> хранятся сами пары ключ-значение. Алгоритм вставки элемента проверяет ячейки массива <tex>H</tex> в заданном порядке до тех пор, пока не будет найдена первая свободная ячейка, в неё и будет записан новый элемент. Это позволяет сэкономить память на хранение указателей. Последовательность, в которой просматриваются ячейки хеш-таблицы, называется последовательностью проб. В общем случае, она зависит только от ключа элемента, то есть это последовательность <tex>h_0(x)</tex>, <tex>h_1(x)</tex>, ...,<tex>h_n</tex><tex>_-</tex><tex>_1</tex><tex>(x)</tex>, где <tex>x</tex> — ключ элемента, а <tex>h_i(x)</tex> — произвольные функции, сопоставляющие каждому ключу ячейку в хеш-таблице. Первый элемент в последовательности, как правило, равен значению некоторой хеш-функции от ключа, а остальные считаются от него каким-нибудь способом. Для успешной работы алгоритмов поиска последовательность проб должна быть такой, попавшие чтобы все ячейки хеш-таблицы оказались просмотренными ровно по одному разу. Алгоритм поиска просматривает ячейки хеш-таблицы в одну том же порядке, что и при вставке, пока не найдется элемент с искомым ключом, либо свободная ячейка (что означает отсутствие элемента в хеш-таблице). Удаление элементов в такой схеме несколько затруднено. Можно поступить так: будем помечать каждую ячейкупо признаку: удалили мы из неё элемент, или нет.В этом случае, удалением является установка метки «удалён», для соответсвующей ячейки хеш-таблицы. Остаётся только модифицировать поиск (если удалён, то занято) и вставку (если удалён, то пусто) элементов. == Примечания ==<references/>
== Источники ==
* Томас Кормен, Чарльз Лейзерсон, Рональд Ривест, Клиффорд Штайн. «Алгоритмы. Построение и анализ» {{---}} «Вильямс», 2011 г. {{---}} 1296 стр. {{---}} ISBN 978-5-8459-0857-5, 5-8459-0857-4, 0-07-013151-1
* Дональд Кнут. «Искусство программирования, том 3. Сортировка и поиск» {{---}} «Вильямс», 2007 г. {{---}} 824 стр. {{---}} ISBN 0-201-89685-0* [http://ru.wikipedia.org/wiki/Сортировка_подсчётом Сортировка подсчетом Хеширование Хеширование {{---}} Википедия]* [http://ru.wikipedia.org/wiki/Хеш-таблица Хеш-таблица {{---}} Википедия]
[[Категория:Дискретная математика и алгоритмы]]
[[Категория:СортировкаХеширование]]
277
правок

Навигация