Initial commit

This commit is contained in:
user
2026-07-12 14:22:00 +04:00
commit 49ecd4784c
90 changed files with 6910 additions and 0 deletions
+139
View File
@@ -0,0 +1,139 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Страница 8</title>
</head>
<body>
<p style="text-align: center">
<i><b>Страница 8</b></i>
</p>
<hr />
<h1 style="text-align: center">Анализ хеш-таблиц и алгоритмов поиска</h1>
<h2 style="text-align: center">Общее описание [2, c. 285-318]</h2>
<p style="text-align: justify">
Хеш-таблица представляет собой эффективную структуру данных для реализации
словарей. Хотя на поиск элемента в хеш-таблице может в наихудшем случае
потребоваться столько же времени, сколько на поиск в связанном списке, а
именно - <i>&Theta;(n)</i>, на практике хеширование исключительно
эффективно. При вполне обоснованных допущениях среднее время поиска
элемента в хеш-таблице составляет <i>O(1)</i>.
</p>
<h2 style="text-align: center">
Таблица с прямой адресацией, как хеш-таблица
</h2>
<p style="text-align: justify">
Хеш-таблица обобщает обычный массив. Возможность прямой индексации
элементов обычного массива обеспечивает доступ к произвольной позиции в
массиве за время <i>O(1)</i>. Хеширование представляет собой исключительно
эффективную и практичную технологию: в среднем все базовые словарные
операции выполняются за время <i>O(1)</i><i>.</i>
</p>
<p style="text-align: justify">
Недостаток прямой адресации очевиден: если совокупность ключей
<i>U</i> велика, хранение таблицы <i>T</i> размером
<i>|U|</i> непрактично, а то и вовсе невозможно - в зависимости от
количества доступной памяти и размера совокупности ключей. Кроме того,
множество <i>K</i> реально сохранённых ключей может быть мало по сравнению
с совокупностью ключей <i>U</i>, а в этом случае память, выделенная для
таблицы <i>T</i>, в основном расходуется напрасно.
</p>
<p style="text-align: justify">
Когда множество <i>K</i> хранящихся в словаре ключей гораздо меньше
совокупности возможных ключей <i>U</i>, для хеш-таблицы требуется
существенно меньше места, чем для таблицы с прямой адресацией<sup>1</sup>.
Точнее говоря, требования к памяти могут быть снижены
до&nbsp;<i>&Theta;(/K/)</i>, при этом время поиска элемента в хеш-таблице
останется равным <i>O(1)</i>. Нужно только заметить, что это граница
времени поиска в среднем случае, в то время как в случае таблицы с прямой
адресацией эта граница справедлива для наихудшего случая.
</p>
<h2 style="text-align: center">Хеш-таблица с прямым связыванием</h2>
<p>
Время, необходимое для вставки в наихудшем случае, равно <i>O(1)</i>.
Процедура вставки выполняется очень быстро, в частности, потому, что
предполагается, что вставляемый элемент отсутствует в таблице. Время
работы поиска в наихудшем случае пропорционально длине списка. Удаление
элемента может быть выполнено за время <i>O(1)</i> при использовании
дважды связанных списков.
</p>
<p>
Пусть у нас есть хеш-таблица T с m ячейками, в которых хранятся n
элементов. В наихудшем случае хеширование с цепочками ведёт себя крайне
неприятно: все n ключей хешированы в одну и ту же ячейку, создав список
длиной n. Таким образом, время поиска в наихудшем случае равно&nbsp;<i
style="text-align: justify"
>&Theta;(n)</i
>
плюс время вычисления хеш-функции, что ничуть не лучше, чем в случае
использования связного списка для хранения всех n элементов. Понятно, что
использование хеш-таблиц в наихудшем случае совершенно бессмысленно.
</p>
<h3>Теорема 8.1<sup>2</sup></h3>
<p>
В хеш-таблице с разрешением коллизий методом цепочек время неудачного
поиска в среднем случае в предположении простого равномерного хеширования
составляет&nbsp;<i style="text-align: justify">&Theta;(1 + a).</i>
</p>
<h3>Теорема 8.2</h3>
<p>
В хеш-таблице с разрешением коллизий методом цепочек время успешного
поиска в среднем случае в предположении простого равномерного хеширования
в среднем равно&nbsp;<i style="text-align: justify">&Theta;(1 + a).</i>
</p>
<p style="text-align: justify">
Если количество ячеек в хеш-таблице как минимум пропорционально количеству
элементов, хранящихся в ней, то <i>n = O(m)</i> и, следовательно,
коэффициент заполнения равен <i>n/m = O(m)/m = O(1).</i>&nbsp;Таким
образом, поиск элемента в хеш-таблице в среднем требует постоянного
времени. Поскольку в худшем случае вставка элемента в хеш-таблицу занимает
O(1) времени (как и удаление элемента при использовании дважды связанных
списков), можно сделать вывод, что все словарные операции в хеш-таблице в
среднем выполняются за время O(1).
</p>
<h2 style="text-align: center">Хеш-таблица с открытой адресацией</h2>
<p style="text-align: justify">
Мы проанализируем математическое ожидание количества исследований для
хеширования с открытой адресацией в предположении равномерного хеширования
и начнём с анализа количества исследований в случае неудачного поиска.
</p>
<h3>Теорема 8.3</h3>
<p>
Математическое ожидание количества исследований при неудачном поиске в хеш
таблице с открытой адресацией и коэффициентом заполнения
<i>a = n/m &lt; 1</i> в предположении равномерного хеширования не
превышает <i>1/(1-a).</i>
</p>
<h3>Следствие 8.1</h3>
<p>
Вставка элемента в хеш-таблицу с открытой адресацией и коэффициентом
заполнения a в предположении равномерного хеширования требует в среднем не
более <i>1/(1-a)</i> исследований.
</p>
<h3>Теорема 8.4</h3>
<p>
Математическое ожидание количества исследований при удачном поиске в
хеш-таблице с открытой адресацией и коэффициентом заполнения <i>a &lt; 1</i>, в
предположении равномерного хеширования и равновероятного поиска любого из
ключей не превышает
</p>
<div style="text-align: center">
<img src="8.1.png" width="150" />
</div>
<p>&nbsp;</p>
<hr />
<p>
<sup>1</sup>В данном контексте автор, упоминая таблицу с прямой
адресацией, не применяет термин хеш, так как, предположительно, в примере
оригинальной книги не используется хеш-функция для операций поиска
элемента или все операции вставки элемента являются инъективными и не
нуждаются в решении проблем коллизий.
</p>
<p>
<sup>2</sup>Все доказательства теорем представлены в книге автора с целью
описания минимума методического материала
</p>
</body>
</html>
+149
View File
@@ -0,0 +1,149 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Страница 2</title>
</head>
<body>
<p style="text-align: center">
<i><b>Страница 2</b></i>
</p>
<hr />
<h1 style="text-align: center">Дискретная математика</h1>
<h2 style="text-align: center">
Функция, как тип бинарных отношений [4, c. 96-100]
</h2>
<p>
Отношения эффективно применяются для описания связей между парами
элементов, выбранных из двух множеств <i>А</i> и <i>В</i>. Функции &mdash;
это частный случай бинарных отношений, на которые наложены дополнительные
ограничения.
</p>
<p>
Функцией из множества <i>А</i> в множество <i>В</i> называется бинарное
отношение, при котором <i>каждый</i> элемент множества <i>А</i> связан с
единственным элементом множества <i>В</i>. Другими словами, для каждого
<i>a&nbsp;&isin;&nbsp;A</i>&nbsp;существует ровно одна пара из отношения
вида <i>(а, b)</i>.
</p>
<p>
В графических терминах функция описывается таким графом, у которого из
каждой вершины, изображающей элементы множества <i>A</i>, выходит
<i>ровно одна</i> стрелка.
</p>
<p>
Например, на рис. 2.1 изображен граф, представляющий функцию из множества
<i>{а, b, с}</i> в <i>{1, 2}</i>, состоящую из пар <i>(а, 1),</i>
<i>(b, 1)</i> и <i>(с, 2)</i>.
<div style="text-align: center">
<img src="2.1.png" height="150" />
<p style="text-align: center">Рисунок 2.1 - функция из множества</p>
</div>
</p>
<p style="text-align: justify">
Пусть <i>f</i> - функция из множества <i>A</i> в множество <i>B</i>.
Поскольку для каждого <i>x&nbsp;&isin;&nbsp;A</i> существует единственным
образом определённый <i>y&isin;&nbsp;B</i>, такой, что
<i>(x, y) &isin; f</i>, мы будем писать: <i>y = f(x)</i>, и говорить, что
функция <i>f</i> <i>отображает </i>множество <i>A</i> в множество
<i>B</i>, а <i>f(x)</i> называть <i>образом x</i> при отображении
<i>f</i> или <i>значением</i> <i>f</i>, соответствующим аргументу
<i>x</i>.
</p>
<p style="text-align: justify">
Кроме того, можно написать <i>f : A&nbsp;&rarr;&nbsp;B</i>, чтобы
подчеркнуть, что функция <i>f</i> переводит элементы из <i>A</i> в
элементы из <i>B</i>. Множество <i>A </i>принято называть
<i>областью определения</i>, а <i>B</i> -
<i>областью значений</i> функции<sup>1</sup> <i>f</i>.
</p>
<p style="text-align: justify">
Для уточнения подмножества элементов, в которые переводятся элементы из
<i>A</i> функцией <i>f</i>, вводят понятие &quot;образ&quot; или
&quot;множество значений функции&quot;. А именно,
<i>множеством значений</i> функции <i>f</i> называется подмножество в
<i>B</i>, состоящее из образов всех
элементов&nbsp;<i>x&nbsp;&isin;&nbsp;A</i>. Оно обозначается символом
<i>f(A)</i> и формально определяется так:
</p>
<p style="text-align: center">
<i
>f(A) = {f(x) : x&nbsp;<i style="text-align: justify">&isin;&nbsp;</i
>A}</i
>
</p>
<p style="text-align: center">&nbsp;</p>
<h2 style="text-align: center">Свойства функций</h2>
<p style="text-align: justify">
Пусть <i>f : A&nbsp;&rarr;&nbsp;B</i> - функция. Мы будем называть её
<i>инъективной </i>или <i>инъекцией</i>, или <i>взаимно однозначной</i>,
если
</p>
<p style="text-align: center">
<i
>f(a<sub>1</sub>) = f(a<sub>2</sub>)&nbsp;&rArr;&nbsp;a<sub>1 </sub
>=<sub>&nbsp;</sub>a<sub>2</sub></i
>
</p>
<p style="text-align: justify">
для всех&nbsp;<i>a<sub>1</sub>,&nbsp;a<sub>2&nbsp;</sub>&isin;&nbsp;A</i>.
</p>
<p style="text-align: justify">
Это определение логически эквивалентно тому, что
</p>
<p style="text-align: center">
<i
>a<sub>1&nbsp;</sub>&ne;&nbsp;a<sub>2</sub>&nbsp;&rArr;&nbsp;f(a<sub>1</sub>)&nbsp;&ne;&nbsp;f(a<sub>2</sub>),</i
>
</p>
<p style="text-align: justify">
т.е. у инъективной функции нет повторяющихся значений. Иными словами,
разные входные данные дают различные выходные данные.
</p>
<p style="text-align: justify">
Будем называть функцию <i>f</i> <i>сюръективной </i>или <i>сюръекцией</i>,
или <i>функцией &quot;на&quot;</i>, если множество её значений совпадает с
областью значений. Это означает, что для каждого
<i>b&nbsp;&isin;&nbsp;B</i> найдётся такой <i>a&nbsp;&isin;&nbsp;A</i>,
что <i>b = f(a)</i>. Таким образом, каждый элемент области значений
является образом какого-то элемента из области определения <i>f</i> .
</p>
<p style="text-align: justify">
Мы называем <i>f</i> <i>биективной </i>функцией или просто
<i>биекцией</i>, если она как инъективна, так и сюръективна.
</p>
<p style="text-align: justify">&nbsp;</p>
<p>На рисунке 2.2 представлены различные виды функций.</p>
<div style="text-align: center">
<img src="2.2.png" height="350" />
<p style="text-align: center">Рисунок 2.2 - различные виды функций</p>
</div>
<p>Описание:</p>
<ul>
<li>
В случае (a) функция не инъективна, поскольку значение 1 соответствует
как a, так и b. Она не является и сюръективной, ввиду того, что в
элемент 2 ничего не переходит.
</li>
<li>
В случае (б) функция инъективна, так как не имеет повторяющихся
значений. Она же и сюръективна, поскольку множество ее значений
совпадает со всей областью значений.
</li>
<li>
Значение 1 эта функция в случае (в) принимает как на а, так и на Ь.
Следовательно, она не инъективна. Однако данная функция сюръективна,
поскольку в ее множество значений входят все элементы области значений.
</li>
<li>Последняя функция в случае (г) инъективна, но не сюръективна.</li>
<li>Только в случае (б) мы имеем биекцию.</li>
</ul>
<hr />
<p>
<sup>1</sup>Довольно часто говорят, что функция f определена или задана на
множестве A со значениями в множестве B. - Прим. перев.
</p>
</body>
</html>
+56
View File
@@ -0,0 +1,56 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Страница 6</title>
</head>
<body>
<p style="text-align: center">
<i><b>Страница 6</b></i>
</p>
<hr />
<h1 style="text-align: center">Решение проблем коллизий</h1>
<h2 style="text-align: center">Метод цепочек или прямое связывание [5, c. 170-171]</h2>
<p style="text-align: justify">
В хеш таблице с прямым связыванием (рис 6.1) значения ключей (бункеры)
хранятся в специальных наборах записей, называемых <i>блоками.</i> Каждый
из них является вершиной связного списка, в котором находятся привязанные
к блоку элементы.
</p>
<div style="text-align: center">
<img src="6.1.png" height="350" />
<p style="text-align: center">Рисунок 6.1 - хеш-таблица с прямым связыванием</p>
</div>
<p style="text-align: justify">
Поиск элементов в хеш-таблице пройдёт быстрее, если связанные списки будут
содержать ключи в отсортированном порядке. В этом случае алгоритм сделает
вывод, что ключа нет, если дойдёт до значения больше ключевого и не станет
просматривать список до конца. Теоретически время его работы составит
<i>O(N/B)</i>, но на практике оно будет немного меньше.
</p>
<p style="text-align: justify">
Чтобы найти нужный элемент, программе необходимо хешировать ключ и
определить, в каком из блоков он может содержаться, а затем двигаться по
связному списку до тех пор, пока не будет достигнут его конец или не
обнаружится искомое. Если вы доберётесь до конца списка, значит,
запрашиваемого элемента в хеш-таблице нет. Как и в случае с добавлением
элемента, предстоит выполнить <i>O(N/B)</i> шагов.
</p>
<p style="text-align: justify">
Хеш-таблица с прямым связыванием может расширяться и сжиматься<sup>1</sup>
по мере необходимости, поэтому вам не нужно специально изменять её размер.
Однако если связные списки станут слишком длинными, поиск и удаление
элементов займут много времени. В этом случае вам понадобится увеличить
таблицу, чтобы создать больше блоков. Поскольку при рехешировании таблицы
не надо проводить поиск дубликатов до конца связного списка в каждом
блоке, полностью справиться с операцией можно за время <i>O(N)</i>.
</p>
<hr />
<p>
<sup>1</sup>Удаление элементов в данном методическом материале
рассматриваться не будет
</p>
</body>
</html>
+52
View File
@@ -0,0 +1,52 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Страница 3</title>
</head>
<body>
<p style="text-align: center">
<i><b>Страница 3</b></i>
</p>
<hr />
<h1 style="text-align: center">Дискретная математика</h1>
<h2 style="text-align: center">Принцип Дирихле [4, c. 105]</h2>
<p>
Пусть <i>f : A&nbsp;<i style="text-align: justify">&rarr;&nbsp;</i>B</i> -
функция, причём как <i>A</i>, так и <i>B</i> - конечные множества.
Предположим, что <i>A</i> состоит из <i>n</i> элементов:
<i>a<sub>1</sub>, a<sub>2</sub>,..., a<sub>n</sub></i
>. Принцип Дирихле гласит, что если <i>|A| &gt; |B|</i>, то по крайней
мере одно значение <i>f</i> встретится более одного раза<sup>1</sup>.
Проще говоря, найдётся пара элементов
<i
>a<sub>i&nbsp;</sub><i style="text-align: center">&ne;</i
><sub>&nbsp;</sub>a<sub>j</sub></i
>, для которых <i>f(a<sub>i</sub>) = f(a<sub>j</sub>)</i>.
</p>
<p>
Чтобы убедиться в истинности принципа, предположим, что для любой пары
разных индексов
<i>i&nbsp;<i style="text-align: center">&ne;&nbsp;</i>j</i> мы имеем:
<i>f(a<sub>i</sub>)&nbsp;</i><i style="text-align: center">&ne;&nbsp;</i
><i>f(a<sub>j</sub>)</i>. Тогда множество <i>B</i> содержит по крайней
мере <i>n</i> различных элементов:
<i>f(a<sub>1</sub>), f(a<sub>2</sub>),..., f(a<sub>n</sub>)</i>. И уж во
всяком случае, <i>|B|&nbsp;&ge;&nbsp;n</i>, что противоречит
предположению: <i>n = |A| &gt; |B|</i>. Следовательно, есть хотя бы два
разных элемента
<i
>a<sub>i</sub>, a<sub>j&nbsp;</sub
><i style="text-align: justify">&isin;&nbsp;</i>A</i
>, для которых <i>f(a<sub>i</sub>) = f(a<sub>j</sub>)</i>.
</p>
<hr />
<p>
<sup>1</sup>Допуская некоторую вольность, принцип Дирихле можно
переформулировать в легко запоминающейся форме: нельзя рассадить 10 зайцев
в 9 клеток так, чтобы в каждой клетке сидел один заяц - Прим. перев.
</p>
</body>
</html>
+102
View File
@@ -0,0 +1,102 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Страница 4</title>
</head>
<body>
<p style="text-align: center">
<i><b>Страница 4</b></i>
</p>
<hr />
<h1 style="text-align: center">Хеш-фукнция</h1>
<h2 style="text-align: center">Свойства хеш-функции</h2>
<p style="text-align: justify">
Хеш-функция&nbsp;(англ.&nbsp;hash function&nbsp;от&nbsp;hash&nbsp;&mdash;
&laquo;превращать в фарш&raquo;), или&nbsp;функция свёртки&nbsp;&mdash;
функция, осуществляющая преобразование&nbsp;массива&nbsp;входных данных
произвольной длины в выходную&nbsp;битовую&nbsp;строку установленной
длины, выполняемое&nbsp;определённым алгоритмом. Преобразование,
производимое хеш-функцией, называется&nbsp;хешированием. Исходные данные
называются входным массивом, &laquo;ключом&raquo; или
&laquo;сообщением&raquo;. Результат преобразования называется
&laquo;хешем&raquo;, &laquo;хеш-кодом&raquo;, &laquo;хеш-суммой&raquo;,
&laquo;сводкой&nbsp;сообщения&raquo;.[<a
href="https://ru.wikipedia.org/wiki/Хеш-таблица"
>7</a
>]
</p>
<p style="text-align: justify">Свойства хеш-функции:</p>
<ul>
<li style="text-align: justify">Должна обладать свойствами функции.</li>
<li style="text-align: justify">
Не должна обязательно являться инъективной или сюръективной.
</li>
</ul>
<p style="text-align: justify">Определения :</p>
<ul>
<li style="text-align: justify">
Если известна область определения и можно задать отображение в область
значений, мощность которого будет больше или эквивалентна мощности
области определения, при котором хеш-функция будет являться
<i>инъективной</i>, то такая хеш-функция будет являться<i
>&nbsp;идеальной хеш-функцией</i
>.
</li>
<li style="text-align: justify">
Если область определения неизвестна&nbsp;и можно задать отображение в
область значений, мощность которого будет больше или эквивалентна
мощности области определения, при котором хеш-функция будет
являться&nbsp;<i>инъективной</i>, то такая хеш-функция будет являться<i
>&nbsp;динамической идеальной хеш-функцией</i
>.
</li>
<li style="text-align: justify">
Если известна&nbsp;область определения и можно задать отображение в
область значений, мощность которого будет эквивалентна&nbsp;мощности
области определения, при котором хеш-функция будет
являться&nbsp;<i>биективной</i>, то такая хеш-функция будет являться
<i>минимальной идеальной хеш-функцией</i>.
</li>
<li style="text-align: justify">
Хеш-функция является <i>k-совершенной хеш-функцией</i>,
если&nbsp;область определения неизвестна и можно задать отображение в
область значений, любой элемент которого будет обладать не более чем k
отношениями.
</li>
</ul>
<div style="text-align: justify">
Существует несколько терминов, связанных с хеш-функцией:
</div>
<dl>
<dt style="text-align: justify"><i>Хеш</i></dt>
<dd style="text-align: justify">
элемент области значений, соотнесённый с заранее известным элементом из
области определения.
</dd>
<dt style="text-align: justify"><i>Хеширование</i></dt>
<dd style="text-align: justify">это процесс получения хеша.</dd>
<dt style="text-align: justify"><i>Коллизия</i></dt>
<dd style="text-align: justify">
ситуация, при которой нарушается условие инъективности хеш-функции.
</dd>
</dl>
<p style="text-align: justify">
Производительность хеширования в среднем случае зависит от того, насколько
хорошо хеш-функция приближена к биективной k-совершенной хеш-функции, где
разность количества отношейний любых двух элементов области значений
стремиться к нулю. Другими словами, каждый элемент области значений
обладает минимально возможным количеством отношений. Данное хеширование
автор книги [2, с. 291] Томас Кормен называет
<i>простым равномерным хешированием</i>.
</p>
<div style="text-align: justify">
Существует множество разнообразных хеш-функций, алгоритмы которых
применяются в различных ситуациях, например, когда требуется скорость
вычисления хеш-значения, но с повышенным шансом появления коллизии или
наоборот.
</div>
</body>
</html>
+120
View File
@@ -0,0 +1,120 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Страница 5</title>
</head>
<body>
<p style="text-align: center">
<i><b>Страница 5</b></i>
</p>
<hr />
<h1 style="text-align: center">Хеш-таблица</h1>
<h2 style="text-align: center">Свойства хеш-таблицы</h2>
<p style="text-align: justify">
Хеш-таблицы являются одним из способов хранения данных при помощи
ассоциативного массива [<a
href="https://ru.wikipedia.org/wiki/Ассоциативный_массив"
target="_blank"
>12</a
>].
</p>
<p style="text-align: justify">
Хеш-таблицы решают несколько главных проблем при оперировании с данными:
</p>
<ul>
<li style="text-align: justify">
<i
>Создание отношения (связи) между ключом и абсолютно любым
значением.</i
>
</li>
<li style="text-align: justify"><i>Решение проблем коллизий.</i></li>
</ul>
<p style="text-align: justify">
Для большего понимания материала требуется ознакомиться с новыми терминами
хеш-таблицы:
</p>
<dl>
<dt><i>Ключ или сообщение</i></dt>
<dd>использующийся хеш-таблицей произвольный элемент из области определения хеш-функции.</dd>
<dt><i>Бункер или корзина</i></dt>
<dd>произвольный элемент, который хранит данные хеш-таблицы.</dd>
<dt><i>Коэффициент заполнения</i></dt>
<dd>
отношение количества заполненных бункеров на количество возможных ключей.
</dd>
</dl>
<p style="text-align: justify">
Исходя из определений, бункер - это условная единица хранимой информации в
хеш-таблице (ассоциативном массиве данных).
</p>
<p>
<i
><span style="text-align: justify"
>Решение первой проблемы.&nbsp;</span
></i
>Хеш-функции в хеш-таблице, нужны по причине получения хеша в процессе
хеширования ключа, однако хеш - значение абстрактное, так как невозможно
создать такой алгоритм, который бы выдавал хеш, как набор данных,
используемый в процессе работы программы или это очень сложно.<br />
Для большего понимания нужно вспомнить пример о&nbsp;<span
style="text-align: justify"
>&quot;продавце в маленьком магазинчике&quot;, где &quot;помощница&quot;
абстрагирует понятие хеш-функции, которая выдавала для каждого товара
конкретную цену, что возможно, но трудозатратно.</span
><br />
<span style="text-align: justify"
>Для этого требуется хеш-функция, где хеш является универсальным
идентификатором конкретного бункера, в котором располагается необходимый
пользователю набор данных.</span
>
</p>
<p>
Томас Кормен говорит в книге [2, c.288], что цель хеш-функции состоит в
том, чтобы уменьшить рабочий диапазон индексов массива - размер массива
может быть равен соотносительно намного меньшему значению, чем мощность
множества всех существующих значений ключей, которые могут потенциально
использоваться в процессе работы программы.
</p>
<p style="text-align: justify">
<span style="text-align: justify"
>Из этого можно выделить несколько особенностей хеш-таблиц:</span
>
</p>
<ul>
<li style="text-align: justify">
Каждый бункер имеет&nbsp;в качестве уникального&nbsp;идентификатора
хеш-значение
</li>
<li style="text-align: justify">
Каждый ключ гарантированно имеет связь только с одним бункером.
</li>
<li style="text-align: justify">
Количество бункеров относительно количества ключей сильно ограниченно.
</li>
<li style="text-align: justify">
От хеш-функции зависит коэффициент заполнения.
</li>
<li style="text-align: justify">
По принципу Дирихле коллизия неизбежна в ситуации, когда количество ключей больше, чем количество бункеров.
</li>
</ul>
<p style="text-align: justify">
<i>Решение второй проблемы</i>. Хеш-таблицы используют в качестве
алгоритма поиска элемента контейнера (бункера) хеш-функцию, которая по
принципу Дирихле гарантированно создаст коллизии в ситуации, когда
количество ключей больше, чем количество бункеров, а обычно так бывает
всегда.
</p>
<p style="text-align: justify">
Хеш-таблицы решают данную проблему двумя способами:&nbsp;
</p>
<ul>
<li style="text-align: justify">Метод цепочек или прямым связыванием.</li>
<li style="text-align: justify">Открытой адресацией.</li>
</ul>
</body>
</html>
+116
View File
@@ -0,0 +1,116 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Страница 1</title>
</head>
<body>
<p style="text-align: center">
<i><b>Страница 1</b></i>
</p>
<hr />
<h1 style="text-align: center">Введение</h1>
<h2 style="text-align: center">Гардероб [3, с. 393-394]</h2>
<p style="text-align: justify">
Когда вы сдаете в гардероб пальто или сумку, вам выдают номерок. Когда же
вы собираетесь покинуть помещение, вы отдаете номерок, и вам возвращают
ваше пальто или сумку.
</p>
<p style="text-align: justify">
Если вдуматься, какую задачку решает данный процесс, можно увидеть, что
это задача о поиске и нахождении объекта. Ваше пальто &mdash; это объект,
который вы передаете гардеробщику; пальто сначала привязывают к
определенному номерку, а затем возвращают вам. Метод работает за счет
того, что в гардеробе находятся ряды пронумерованных вешалок для одежды и
пронумерованные отделения для сумок. Вашему номерку соответствует
определенная вешалка или определенное отделение. Гардеробщик же отвечает
за то, чтобы разместить ваш объект в нужном месте и чтобы забрать его с
помощью отданного вами номерка.
</p>
<p style="text-align: justify">
Когда речь идет о поиске, люди чаще всего представляют себе, что нужно
перебирать вещи до тех пор, пока не найдется нужная; процесс становится
проще, если вещи отсортированы так, что мы можем искать среди них более
слаженно. Гардероб же показывает, что есть и другой способ: присвоить вещи
адрес, где она будет располагаться, и затем сразу достать ее из указанного
места. В гардеробе адрес указан на номерках, и гардеробщик на самом деле
ищет не ваши вещи: он смотрит на номерок, на адрес и идет к указанной
вешалке или отделению с вашими вещами.
</p>
<p style="text-align: justify">
Весь метод в целом можно назвать определением местонахождения
<i>без поиска</i>: мы не ищем объект, а получаем адрес места, где он будет
храниться. Соотносим объект с адресом, а затем, когда хотим найти объект,
мы идем прямиком к нужному месту.
</p>
<p style="text-align: justify">
Теперь рассмотрим данный метод с точки зрения компьютерного мира, где наши
объекты представлены в виде записей, содержащих атрибуты. Мы хотим уметь
переходить напрямую от&nbsp;записи к адресу, по которому она размещена;
адресом будет число, соответствующее области в компьютерной памяти.
Главная загвоздка в такой задачке &mdash; то, как соотнести адрес с
элементом. Нам нужен быстрый и надежный способ, и мы не можем положиться
на какого-либо посредника. Когда мы ищем запись, мы ищем ее по одному или
большему числу атрибутов, которые формируют ключ записи, поэтому нам нужен
метод получения адреса из ключа записи. Так как адрес &mdash; это число,
нам нужен способ, который перенесет нас от ключей к числам. Иными словами,
мы нуждаемся в функции, скажем, <i>f(K)</i>, которая возьмет ключ K записи
R и вернет значение <i>a = f(K)</i>. Значение a представляет собой адрес,
где будет храниться запись, мы идем по нему и оставляем там нашу запись.
Каждый раз, когда нам требуется достать нашу запись с помощью ключа, мы
снова прибегаем к функции <i>f(K)</i>, которая вернет то же адресное
значение a, откуда мы и заберем нашу запись. Функция должна быть быстрой и
достаточно скоро находить нужный адрес: как минимум, не дольше, чем поиск
по записям до тех пор, пока не найдется та, которую мы ищем. В противном
случае толку от такой функции никакого. Если же мы в самом деле
обзаведемся такой функцией, то разрешим нашу задачку с местоположением
новым способом: не мы будем искать элемент, а сам элемент расскажет нам,
где его найти: расскажет с помощью нашей функции.
</p>
<h2 style="text-align: center">Продавец</h2>
<p style="text-align: justify">
Так же стоит привести введение в теоретический материал, описанное автором
книги [1, c. 100-101], где описывается пример с &quot;продавцом в
маленьком магазинчике&quot;.
</p>
<p style="text-align: justify">
В ситуации, когда клиент покупает
у&nbsp;продавца&nbsp;товар&nbsp;необходимо определить ценность предмета.
Изначально стоит отметить, что цены в магазинах на один и тот же товар
всегда одинаковый в один момент времени, поэтому необходимо хранить
информацию о ценах, например, в книге, однако данный метод оперирования
информацией будет весьма утомителен и ужасно&nbsp;неэффективен. Для
решения этой проблемы&nbsp;продавец&nbsp;нанимает помощницу, которая
безошибочно определяет цену на товар, если посмотрит на него или узнает
его название.
</p>
<p style="text-align: justify">
Автор абстрактно описывает проблему с упорядоченным контейнером данных,
где может потребоваться простой поиск, алгоритм которого обладает линейной
сложностью. В данном примере контейнер является хранилищем элементов,
каждый из которых может повторяться, но обязан иметь только один
уникальный идентификатор. Можно с уверенностью выделить две проблемы, от
которых можно избавиться в <i>идеальных </i>условиях &mdash; затраты на
хранение элементов и поиск каждого из них при помощи уникального
идентификатора. В приоритете необходимо выполнять успешный поиск элемента,
алгоритм которого будет выполняться за константное время.
</p>
<p style="text-align: justify">
Решением является использование функции [4, c. 96] из множества <i>A</i> в
множество <i>B.</i>&nbsp;Данная функция описывает бинарное отношение, при
котором <i>каждый</i>&nbsp;элемент множества <i>А</i> связан с
единственным элементом множества <i>B</i>.&nbsp; Данная функция в
программировании имеет название хеш-функция. Избавиться от необходимости в
хранении множеств элементов, чтобы сохранялась возможность определять
новые бинарные отношения, не изменяя другие очень сложно, однако это
возможно. Обычно, когда известны все элементы множества <i>А</i> и все
элементы множества <i>B</i>, реализуют функцию, при которой любой элемент
множества <i>А</i> имеет одно отношение с любым элементом из множества
<i>B</i>. Например, данную функцию можно применить в примере с продавцом и
помощницей, если каталог товаров не изменяется, но цены на разные товары
могут совпадать.
</p>
</body>
</html>
+170
View File
@@ -0,0 +1,170 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Теоретический материал</title>
</head>
<body>
<h1 style="text-align: center">Теоретический материал</h1>
<h2 style="text-align: center">
Необходимый минимум теории по теме<br />
"Алгоритм вставки в хеш-таблицу"
</h2>
<h3>Описание страницы:</h3>
<p>
Главная страница, предоставляющая пользователю быстрый и удобный поиск
нужного разбитого по темам материала.<br />
Каждый элемент списка оглавления является гиперссылкой при нажатии на
которую можно мгновенно перейти к необходимому разделу информации.<br />
Предоставленный пользователю теоретический материал был взят из списка
использованной литературы в конце данной страницы.
</p>
<p>Оглавление:</p>
<ol>
<li>
<a href="introduction.html">Введение.</a>
</li>
<li>Дискретная математика:
<ul>
<li>
<a href="binaryRelationship.html">Функция.</a>
</li>
<li>
<a href="dirichletPrinciple.html">Принцип Дирихле.</a>
</li>
</ul>
</li>
<li>
<a href="hashFunction.html">Хеш-функция.</a>
</li>
<li>
<a href="hashTable.html">Хеш-таблица.</a>
</li>
<li>Решение проблем коллизий:
<ul>
<li>
<a href="chainMethod.html">Метод цепочек или прямое связывание.</a>
</li>
<li><a href = "openAddressing.html">Открытая и прямая адресации.</a></li>
</ul>
</li>
<li><a href = "analysis.html">Анализ хеш-таблиц и алгоритмов поиска.</a></li>
</ol>
<h3 style="text-align: center">Список использованной литературы</h3>
<ol>
<li>
<em
>Бхаргава, А. Грокаем алгоритмы. Иллюстрированное пособие для
программистов и любопытствующих&nbsp;/ Адитья Бхаргава. — СПб. :
Питер, 2017. - 288 с. : ил. — (Библиотека программиста).</em
>
</li>
<li>
<em
>Кормен, Т. Х. Алгоритмы: построение и анализ, 3-е изд / Томас Кормен ; пер. с англ. — Москва :
ООО "И. Д. Вильямс", 2013. — 1328 с. : ил. — Парал. тит. англ.</em
>
</li>
<li>
<em
>Луридас, П. Алгоритмы для начинающих : теория и практика для
разработчика / Панос Луридас ; пер. с англ. Е.М. Егоровой. — Москва :
Эксмо, 2020. — 608 с. — (Мировой компьютерный бестселлер).</em
>
</li>
<li>
<em
>Хаггарти, Р. Дискретная математика для программистов, 2-е издание, исправленное / Род
Стивенс. — Москва : ТЕХНОСФЕРА, 2019. — 400 c.</em
>
</li>
<li>
<em
>Стивенс, Р. Алгоритмы. Теория и практическое применение / Род
Стивенс. — Москва : Издательство "Э", 2016. — 544 c. — (Мировой
компьютерный бестселлер).</em
>
</li>
<li>
<em
>Хеш-таблица [Электронный ресурс]: Википедия. Свободная энциклопедия.
— URL:&nbsp;<a
href="https://ru.wikipedia.org/wiki/Хеш-таблица"
target="_blank"
>https://ru.wikipedia.org/wiki/Хеш-таблица</a
>&nbsp;(дата обращения: 03.11.2021).</em
>
</li>
<li>
<em
>Хеш-функция [Электронный ресурс]: Википедия. Свободная энциклопедия.
— URL:&nbsp;<a
href="https://ru.wikipedia.org/wiki/Хеш-функция"
target="_blank"
>https://ru.wikipedia.org/wiki/Хеш-функция</a
>&nbsp;(дата обращения: 03.11.2021).</em
>
</li>
<li>
<em
>Хеш-функция, что это такое? [Электронный ресурс]: Хабр. Сообщество
IT-специалистов. — URL:&nbsp;<a
href="https://habr.com/ru/post/534596/"
target="_blank"
>https://habr.com/ru/post/534596/</a
>
(дата обращения: 03.11.2021).</em
>
</li>
<li>
<em
>Хеш-таблицы [Электронный ресурс]: Хабр. Сообщество IT-специалистов. —
URL:&nbsp;<a href="https://habr.com/ru/post/509220/" target="_blank"
>https://habr.com/ru/post/509220/</a
>
(дата обращения: 03.11.2021).</em
>
</li>
<li>
<em
>Хеш-таблицы [Электронный ресурс]: CodeChick. Задачи по
программированию с проверкой. — URL:&nbsp;<a
href="https://codechick.io/tutorials/dsa/dsa-hash-table"
target="_blank"
>https://codechick.io/tutorials/dsa/dsa-hash-table</a
>&nbsp;(дата обращения: 03.11.2021).</em
>
</li>
<li>
<em
>FowlerNollVo hash function [Электронный ресурс]: Википедия.
Свободная энциклопедия. — URL:&nbsp;<a
href="https://en.wikipedia.org/wiki/FowlerNollVo_hash_function"
target="_blank"
>https://en.wikipedia.org/wiki/FowlerNollVo_hash_function</a
>&nbsp;(дата обращения: 03.11.2021).</em
>
</li>
<li>
<em
>Ассоциативный массив [Электронный ресурс]: Википедия.
Свободная энциклопедия. — URL:&nbsp;<a
href="https://ru.wikipedia.org/wiki/Ассоциативный_массив"
target="_blank"
>https://ru.wikipedia.org/wiki/Ассоциативный_массив</a
>&nbsp;(дата обращения: 06.11.2021).</em
>
</li>
</ol>
</body>
</html>
+274
View File
@@ -0,0 +1,274 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Страница 7</title>
</head>
<body>
<p style="text-align: center">
<i><b>Страница 7</b></i>
</p>
<hr />
<h1 style="text-align: center">Решение проблем коллизий</h1>
<h2 style="text-align: center">
Открытая и прямая адресации [5, c. 170-179]
</h2>
<p>Оглавление:</p>
<ul>
<li><a href="#description">Описание.</a></li>
<li><a href="#linear">Линейное пробирование.</a></li>
<li><a href="#quadratic">Квадратичное пробирование.</a></li>
<li><a href="#pseudorandom">Псевдослучайное пробирование.</a></li>
<li><a href="#double">Двойное хеширование.</a></li>
</ul>
<div>
<h3 style="text-align: center"><a name="description">Описание</a></h3>
<p style="text-align: justify">
Безусловно, прямое связывание имеет свои преимущества. Основное из них
заключается в том, что общее количество значений не зависит от
количества блоков. Однако есть у таких хеш-таблиц и некоторые
недостатки. Например, если элементов в блоках накопится слишком много,
поиск нужного займет продолжительное время. Чтобы сократить временные
затраты, число блоков можно увеличить, но тогда вы рискуете получить ряд
пустых, которые потребуют места в памяти и не будут использоваться
таблицей.
</p>
<p style="text-align: justify">
Еще один способ реализации хеш-таблиц &mdash; <i>открытая адресация</i>.
В этом случае значения хранятся в массиве, а функция хеширования
представляет собой некоторые расчеты.
</p>
<p style="text-align: justify">
Хеш-таблица с <i>прямой адресацией</i> отличается от хеш-таблицы с
открытой адресацией тем, что в первом случае гарантировано должна
использоваться идеальная хеш-функция. Это обусловлено тем, что в данной
хеш-таблице должны отсутствовать коллизии, соответственно, как и методы
их разрешения. Стоит отметить, что под данное описание подходит
<i>идеальное хеширование</i> хеш-таблицы<sup>1</sup>.
</p>
<p style="text-align: justify">
В разных видах открытой адресации используются различные функции
хеширования. Неодинакова и политика разрешения коллизий, но в общем
случае она выглядит так: для каждого значения в массиве подбирается
несколько ячеек, и если первая уже занята, алгоритм пробует использовать
вторую, затем третью и так до тех пор, пока не найдет свободную или не
придет к выводу, что таковой нет.
</p>
<p style="text-align: justify">
Серия ячеек, которую алгоритм подбирает для значения, называется пробной
последовательностью. По ее средней длине хорошо оценивать наполненность
хештаблицы. В идеале пробная последовательность должна равняться 1 или
2, большие цифры говорят о полной таблице.
</p>
<p style="text-align: justify">
Иногда политика разрешения коллизий такова, что для элемента может не
найтись свободной ячейки, даже когда она есть. Если пробная
последовательность повторяет саму себя перед тем, как проверить
очередную запись, некоторые записи могут остаться неиспользованными.
</p>
<p style="text-align: justify">
Чтобы найти элемент в хеш-таблице, алгоритм следует за пробной
последовательностью, пока не произойдет одно из трех событий.
</p>
<ol>
<li style="text-align: justify">
Если пробная последовательность сумела отыскать элемент, задача
выполнена.
</li>
<li style="text-align: justify">
Если пробная последовательность находит пустую запись в массиве,
элемента нет.
</li>
<li style="text-align: justify">
Пробная последовательность проверяет <i>M</i> записей (по размеру
массива) &mdash; и алгоритм приходит к выводу, что значение
отсутствует. Последовательность может перебрать не все элементы, но
если пройдет по всем, вы будете знать, что они точно пересмотрены или
что целевой элемент не найден. Она также может проверить в цикле одну
и ту же позицию несколько раз. В любом случае значение не должно
присутствовать, поскольку иначе оно бы добавлялось к массиву с
использованием той же пробной последовательности.
</li>
</ol>
<p style="text-align: justify">
При разумном заполнении хеш-таблицы открытая адресация работает очень
быстро. Если длина пробной последовательности равна 1 или 2, добавление
и нахождение элементов выполняются за время <i>O(1)</i>. Но если массив
из N элементов существенно переполнен, производительность снижается. В
наихудшем случае алгоритм придет к выводу, что элемента в массиве нет,
за время <i>O(N)</i>. Поиск присутствующих элементов также будет
выполняться крайне медленно.
</p>
<p style="text-align: justify">
Вы можете увеличить размер массива, чтобы уменьшить коэффициент
наполненности хеш-таблицы. Для этого создайте новый массив и рехешируйте
элементы в нем. Для каждого из них операция займет <i>O(1)</i> времени,
а общая производительность алгоритма составит <i>O(N)</i>.
</p>
</div>
<div>
<h3 style="text-align: center">
<a name="linear">Линейное пробирование</a>
</h3>
<p style="text-align: justify">
В линейном пробировании политика разрешения коллизий добавляет к каждой
ячейке постоянное число (чаще всего 1), называемое шагом по индексу,
которое генерирует пробную последовательность. При каждом очередном
добавлении берется размер массива по модулю, стало быть, при
необходимости последовательность возвращается к началу массива.
</p>
<p style="text-align: justify">
Предположим, в хеш-таблице 100 элементов, а правило хеширования звучит
следующим образом: N связано с ячейкой N mod 100. Тогда пробная
последовательность для значения 2197 проверяет ячейки 97, 98, 99, 0, 1,
2 и т. д.
</p>
<p style="text-align: justify">
На рисунке 7.1 представлен массив из 10 записей, который уже содержит
несколько значений. Чтобы добавить в него новое значение 71, используя
линейную пробную последовательность, нужно связать его с ячейкой 71 mod
10 = 1. Но эта ячейка уже занята значением 61, поэтому алгоритм
переходит к ячейке 2, которая тоже заполнена. Следующей должна быть
ячейка 3 &mdash; она свободна, и алгоритм размещает там 71.
</p>
<div style="text-align: center">
<img src="7.1.png" width="800" />
<p style="text-align: center">
Рисунок 7.1 - линейная пробная последовательность
</p>
</div>
<p style="text-align: justify">
Преимущество данного метода &mdash; в его простоте. Если необходимо,
пробная последовательность пройдет по каждой ячейке массива и вставит
элемент в свободное место, если оно еще осталось. Но есть и
сопутствующий недостаток &mdash; так называемая
<i>первичная кластеризация</i>, которая проявляется в образовании
больших блоков смежных записей и приводит к длинным пробным
последовательностям. В результате при добавлении нового элемента и его
хешировании к какой-либо записи в кластере пробная последовательность
вынуждена пройти через весь кластер, чтобы найти свободную ячейку.
</p>
<p style="text-align: justify">
Чтобы понять, как формируются кластеры, рассмотрим пример пустой
хеш-таблицы. Предположим, в ней содержится <i>N</i> записей и существует
вероятность <i>1/N</i>, что она закончится в любой данной позиции при
добавлении случайного числа. А теперь представим, что <i>K</i> &mdash;
конечная позиция таблицы. Существует вероятность <i>1/N</i>, что новое
случайное число попадет в позицию K и линейное пробирование попытается
расположить элемент в позиции <i>K + 1</i>. Но та же вероятность
характерна и для случая, при котором новый элемент будет связан с
позицией <i>K + 1</i> напрямую. Значит, существует вероятность
<i>2/N</i>, что элемент займет конечную позицию <i>K + 1</i> и
сформируется малый кластер.
</p>
<p style="text-align: justify">
Через какое-то время таких кластеров станет много. Чем больше они будут,
тем больше вероятность того, что новый элемент добавится в конец одного
из них. В итоге более мелкие кластеры сольются в более крупные, массив
заполнится ими &mdash; и возникнут длинные пробные последовательности.
</p>
</div>
<div>
<h3 style="text-align: center">
<a name="quadratic">Квадратичное пробирование</a>
</h3>
<p style="text-align: justify">
Возникновение больших кластеров при линейном пробировании связано с тем,
что новые элементы связываются с ячейками, стоящими в конце группы, и
постепенно увеличивают ее. Предотвратить подобную ситуацию помогает
<i>квадратичное пробирование</i>. Для создания пробной
последовательности в качестве шага по индексу берется квадрат количества
ячеек. Другими словами, если в линейном пробировании существует
последовательность <i>K, K + 1, K + 2, K + 3,</i> ... то в квадратичном
варианте она будет выглядеть так:
<i>K, K + 12, K + 22, K + 32, ...</i> В этом случае,&nbsp;если два
элемента окажутся связанными с разными позициями в одном и том же
кластере, они не обязательно будут придерживаться одной пробной
последовательности и попадут в конец кластера.
</p>
<p style="text-align: justify">
На рисунке 7.2 показана хеш-таблица, в начале которой есть группа из
пяти элементов. Новое значение 71 получает пробную последовательность
<i>1, 1 + 12 = 2, 1 + 22 = 5, 1 + 32 = 10</i> и не добавляется к
существующему кластеру. Значение <i>93 </i>поначалу связано с тем же
кластером, но согласно собственной пробной последовательности
<i>3, 3 + 12 = 4, 3 + 22 = 7</i> также не попадает в него.
</p>
<div style="text-align: center">
<img src="7.2.png" width="800" />
<p style="text-align: center">Рисунок 7.2 - Квадратичное пробирование</p>
</div>
<p style="text-align: justify">
Квадратичное пробирование предотвращает первичную, но не
<i>вторичную кластеризацию</i>, при которой значения, связанные с
одинаковой начальной позицией в массиве, получают одну и ту же пробную
последовательность, иногда очень длинную. В результате образуется точно
такая же группа элементов, но уже не собранных вместе, а распределенных
по всему массиву.
</p>
<p style="text-align: justify">
Еще один недостаток квадратичного пробирования связан с тем, что оно
может не найти свободную позицию, даже если в хеш-таблице их несколько.
Дело в том, что с каждым разом перемещение по массиву происходит все
дальше и дальше, и незаполненная ячейка попросту пропускается.
</p>
</div>
<div>
<h3 style="text-align: center">
<a name="pseudorandom">Псевдослучайное пробирование</a>
</h3>
<p style="text-align: justify">
Это пробирование подобно линейному, за исключением того, что шаг по
индексу формирует псевдослучайная функция изначально связанной ячейки.
Предположим, что это ячейка <i>K</i>, тогда пробная последовательность
будет выглядеть следующим образом: <i>K, K + p, K + 2p, ...</i> где p
определяется псевдослучайной функцией.
</p>
<p style="text-align: justify">
Подобно квадратичному пробированию, псевдослучайное предотвращает только
первичную кластеризацию, но страдает от вторичной: значения, связанные с
одной и той же начальной позицией, размещаются в хеш-таблице согласно
одной и той же пробной последовательности. Точно так же псевдослучайное
пробирование может пропускать некоторые неиспользуемые записи.
</p>
</div>
<div>
<h3 style="text-align: center">
<a name="double">Двойное хеширование</a>
</h3>
<p style="text-align: justify">
Чтобы избавиться от вторичной кластеризации значения, связанные с одной
и той же начальной ячейкой, должны получать разные пробные
последовательности. И здесь пригодится двойное хеширование. Оно похоже
на псевдослучайное пробирование, только шаг для индекса задается не
псевдослучайной функцией начальной ячейки, а второй функцией
хеширования.
</p>
<p style="text-align: justify">
Допустим, значения <i>A</i> и <i>B</i> связаны с позицией <i>K</i>. В
псевдослучайном пробировании шаг по индексу <i>p</i> генерируется
функцией <i>F<sub>1</sub> (K)</i>, затем оба значения используют пробную
последовательность <i>K, K + p, K + 2p, K + 3p, ...</i> В двойном
хешировании для связывания начальных значений <i>А</i> и
<i>В</i> применяется функция псевдослучайного хеширования
<i>F<sub>2</sub></i
>. В итоге при одном и том же начальном <i>K</i> образуются две пробные
последовательности с различными шагами по индексу:
<i>p<sub>A</sub> = F<sub>2</sub> (A)</i> и
<i>p<sub>B</sub> = F<sub>2</sub> (B)</i> соответственно.
</p>
<p style="text-align: justify">
Несмотря на то, что двойное хеширование хорошо справляется с первичной и
вторичной кластеризациями, оно точно так же, как и псевдослучайное
пробирование, может пропускать неиспользуемые записи.
</p>
</div>
<hr />
<p>
<sup>1</sup>Данный метод хеширования хорошо описан в книге Томаса Кормена
[2]
</p>
</body>
</html>