отчет - line.tom.ru

advertisement
Научно-исследовательский университет
Томский политехнический университет
Институт Кибернетики
Кафедра ОСУ
Пояснительная записка к курсовой работе
по дисциплине «Структуры и алгоритмы обработки данных»
Вариант №15
Исполнитель
студент, 8В83
____________
Б.А. Сафронов
(подпись)
____________
(дата)
Руководитель
доцент
____________
О.Б. Фофанов
(подпись)
____________
(дата)
Томск 2010
Содержание
1.
Моделирование абстрактных типов данных (АТД) для различных реализаций ..........4
1.1 Постановка задачи .............................................................................................................4
1.2 Краткое теоретическое описание реализуемых объектов ............................................6
1.3 Набор допустимых операций ...........................................................................................6
1.4 Результат работы программы...........................................................................................7
Вывод по разделу ....................................................................................................................7
2.
Поиск информации в различных структурах данных .......................................................8
2.1 Постановка задачи .............................................................................................................8
2.2 Краткое теоретическое описание реализуемых объектов ............................................8
2.3 Анализ результатов ...........................................................................................................9
Вывод по разделу ....................................................................................................................9
3. Исследование эффективности алгоритмов сортировок для различных структур и
размерностей данных ...............................................................................................................10
3.1 Постановка задачи ...........................................................................................................10
3.2 Краткое теоретическое описание реализуемых объектов ..........................................10
Сортировка Шелла: ............................................................................................................10
Сортировка пузырьком: .....................................................................................................10
Глупая сортировка:.............................................................................................................10
3.3 Анализ результатов .........................................................................................................11
Вывод по разделу ..................................................................................................................14
4. Реализация структур данных типа дерево и типовые алгоритмы их обработки ..........15
4.1 Постановка задачи ...........................................................................................................15
4.2 Краткие теоретические сведения...................................................................................15
Добавление элемента в Б-дерево. ...................................................................................15
Удаление элементов из Б-дерева.....................................................................................15
Поиск в Б-дереве. ...............................................................................................................16
4.3 Структура дерева .............................................................................................................16
4.4 Анализ результатов .........................................................................................................17
Вывод по разделу ..................................................................................................................18
5. Реализация функций расстановки (хеширование) и разрешение коллизий методом
построения цепочки. .................................................................................................................19
5.1 Постановка задачи ...........................................................................................................19
2
5.2 Краткие теоретические сведения...................................................................................19
5.3 Описание хеш-функции ...................................................................................................20
5.4 Анализ результатов .........................................................................................................21
Вывод по разделу ..................................................................................................................23
Список литературы ....................................................................................................................24
Приложение 1 ............................................................................................................................25
Приложение 2 ............................................................................................................................34
Приложение 3 ............................................................................................................................36
Приложение 4 ............................................................................................................................37
Приложение 5 ............................................................................................................................43
3
1.
Моделирование абстрактных типов данных (АТД) для
различных реализаций
1.1 Постановка задачи
Номер задачи: 7;
Система состоит из двух процессоров P1 и P2, трёх очередей F1, F2, F3 и стека (рис.1.7). В
систему могут поступать запросы на выполнение задач трёх типов – Т1, Т2, Т3. Задача
типа Т1 может выполняться только процессором P1. Задача типа Т2 может выполняться
только процессором P2. Задача типа Т3 может выполняться любым процессором. Запрос
можно представить записью.
Type
TInquiry= record
Name: String[10]; {имя запроса}
Time: Word; {время обслуживания}
T: Byte; {тип запроса}
end;
Генератор
задач
О
Ч
Е
Р
Е
Д
Ь
О
Ч
Е
Р
Е
Д
Ь
О
Ч
Е
Р
Е
Д
Ь
F1
F2
F3
P1
P2
Стек
Рис.1
4
Поступающие запросы ставятся в соответствующие типам задач очереди. Если очередь
F1 не пуста и процессор P1 свободен, то задача из очереди F1 поступает на обработку в
процессор P1. Если процессор Р1 обрабатывает задачу типа Т3, а процессор Р2 свободен
и очередь F2 пуста, то задача из процессора Р1 поступает в процессор Р2, а задача из
очереди F1 в процессор Р1, если же процессор Р2 занят или очередь F2 не пуста, то
задача из процессора Р1 помещается в стек.
Если очередь F2 не пуста и процессор P2 свободен, то задача из очереди F2 поступает на
обработку в процессор P2. Если процессор Р2 обрабатывает задачу типа Т3, а процессор
Р1 свободен и очередь F1 пуста, то задача из процессора Р2 поступает в процессор Р1, а
задача из очереди F2 - в процессор Р2, если же процессор Р1 занят или очередь F1 не
пуста, то задача из процессора Р1 помещается в стек.
Если очередь F3 не пуста и процессор P1 свободен, и очередь F1 пуста или свободен
процессор Р2 и очередь F2 пуста, то задача из очереди F3 поступает на обработку в
свободный процессор. Задача из стека поступает на обработку в свободный процессор
Р1, если очередь F1 пуста, или в свободный процессора Р2, если очередь F2 пуста.
Стек: 4;
Стек в динамической памяти (связанная схема).
Очередь: 5;
Очередь на ОЛС. “Хвост” очереди – последний, а “голова” - первый элемент ОЛС
5
1.2 Краткое теоретическое описание реализуемых объектов
Стек – это специальный тип списка, в котором все вставки и удаления выполняются в
начале(FIFO-first in first out), называемом вершиной (top). То есть всегда есть доступ
только к верхнему элементу, к дальнейшим можно обращаться только после удаления
первого. В нашем случае стек представлен динамической структурой: элемент стека –
запись, содержащая указатель на следующий элемент.
Очередь – специальный тип списка - (queue), в котором вставка элементов
осуществляется с одного конца (rear), а удаление с другого (front). В динамической
реализации в записи присутствуют 3 указателя: на следующий элемент, на текущий и на
предыдущий.
1.3 Набор допустимых операций
Для стека:
IndexLast () - возвращает индекс последнего элемента стека.
Size() - возвращает размер стека.
get() - удаляет элемент из вершины стека (выталкивает из стека)
add (x). Помещает элемент х в вершину стека.
Для очереди:
getLast() – возвращает последний элемент очереди.
add (x). Помещает элемент х в конец очереди.
deq() удаляет последний элемент очереди, при этом возвращая его .
Size() - возвращает размер очереди.
6
1.4 Результат работы программы
Пример работы программы:
Step:1
Processor "P1": Type1Works. Time left: 3.
Processor "P2": Type2Works. Time left: 2.
List:(49,1,2)(45,1,6)(44,1,2)(40,1,2)(33,1,3)(31,1,3)(30,1,5)(29,1,4)(23,1,2)(21,1,6)(19,1,2)(16,1
,2)(14,1,2)(13,1,4)(11,1,2)(8,1,4)(7,1,6)(6,1,3)(5,1,3)(4,1,2)
List:(47,2,5)(42,2,6)(38,2,5)(37,2,4)(36,2,2)(35,2,6)(32,2,6)(25,2,6)(24,2,5)(18,2,4)(17,2,2)(15,2
,2)(12,2,3)(10,2,5)(2,2,4)
List:(48,3,4)(46,3,3)(43,3,4)(41,3,4)(39,3,4)(34,3,4)(28,3,3)(27,3,2)(26,3,4)(22,3,3)(20,3,2)(9,3,
2)(1,3,5)
Stack:
…
Step:154
Processor "P1": Type1Works. Time left: 5.
Processor "P2": Idle.
List:(22,1,4)(19,1,5)(17,1,2)(10,1,4)(9,1,6)(7,1,6)(6,1,5)
List:(28,2,5)(27,2,2)(26,2,6)(18,2,4)(15,2,3)(13,2,2)(3,2,5)(2,2,4)
List:(29,3,2)(25,3,4)(24,3,2)(23,3,2)(21,3,4)(20,3,6)(16,3,2)(14,3,2)(12,3,2)(11,3,2)(8,3,3)(1,3,3)
(25,3,3)(21,3,4)(17,3,3)(16,3,6)(14,3,4)(10,3,2)(9,3,3)(1,3,2)(48,3,4)(46,3,3)(43,3,4)(41,3,4)(39,
3,4)
Stack:(34,3,3)
Step:155
Processor "P1": Type1Works. Time left: 4.
Processor "P2": Type2Works. Time left: 3.
List:(22,1,4)(19,1,5)(17,1,2)(10,1,4)(9,1,6)(7,1,6)(6,1,5)
List:(28,2,5)(27,2,2)(26,2,6)(18,2,4)(15,2,3)(13,2,2)(3,2,5)
List:(29,3,2)(25,3,4)(24,3,2)(23,3,2)(21,3,4)(20,3,6)(16,3,2)(14,3,2)(12,3,2)(11,3,2)(8,3,3)(1,3,3)
(25,3,3)(21,3,4)(17,3,3)(16,3,6)(14,3,4)(10,3,2)(9,3,3)(1,3,2)(48,3,4)(46,3,3)(43,3,4)(41,3,4)(39,
3,4)
Stack:(34,3,3)
…
Step:224
Processor "P1": Idle.
Processor "P2": Idle.
List:
List:
List:
Stack:
Вывод по разделу
В ходе моделирования комплексной структуры состоящей из очереди, трех
обработчиков задачи и стека, были показаны принципы работы АТД список и очередь,
так же их возможная совместная реализации.
7
2.
Поиск информации в различных структурах данных
2.1 Постановка задачи
Изучение алгоритмов поиска контекста в больших объемах текстовой информации и
закрепление навыков в проведении сравнительного анализа алгоритмов.
1. Реализовать алгоритм поиска Кнута — Морриса — Пратта.
2. Построить графики зависимости количества операций сравнения от количества
символов в массиве.
3. Определить временную сложность алгоритма и сравнить с экспериментальными
исследованиями
2.2 Краткое теоретическое описание реализуемых объектов
Алгоритм Кнута — Морриса — Пратта использует предобработку искомой строки, а
именно: на ее основе создается префикс-функция. При этом используется следующая
идея: если префикс (он же суффикс) строки длинной i длиннее одного символа, то он
одновременно и префикс подстроки длинной i-1. Таким образом, мы проверяем
префикс предыдущей подстроки, если же тот не подходит, то префикс ее префикса, и
т.д. Действуя так, находим наибольший искомый префикс. Следующий вопрос, на
который стоит ответить: почему время работы процедуры линейно, ведь в ней
присутствует вложенный цикл? Ну, во-первых, присвоение префикс-функции происходит
четко m раз, остальное время меняется переменная k. Так как в цикле while она
уменьшается (P[k]<k), но не становится меньше 0, то уменьшаться она может не чаще,
чем возрастать. Переменная k возрастает на 1 не более m раз. Значит, переменная k
меняется всего не более 2m раз. Выходит, что время работы всей процедуры есть O(m).
8
2.3 Анализ результатов
Количество знаков в тексте 856415.
Тест №1 ( Длинная строка )
Строка1: «который заснул тотчас же, как лег на постель, никто долго не спал эту
ночь.»
Время1: 43254170
Тест №2 ( Средняя строка )
Строка2: «который заснул тотчас же, как лег на постель,»
Время2: 55077812
Тест №3 ( Короткая строка )
Строка3: «который зас»
Время3: 66908248
Зависимость времени от длины строки
80000000
70000000
60000000
50000000
40000000
30000000
20000000
10000000
0
Строка1
Строка2
Строка3
На графике видно, что скорость поиска линейно зависима от длины строки.
Вывод по разделу
Исходя из экспериментальных данных, видно, что при увеличении сложности фразы
время поиска линейно уменьшается. Алгоритм КМП хорош тем, что имеет сложность
O(n+m), что обеспечивает более быстрый поиск, чем, например, поиск слова методом
посимвольного сравнения. Однако нельзя полностью полагаться на этот алгоритм: при
больших запросах, состоящих из неодинаковых символов, время работы алгоритма
будет большим.
9
3. Исследование эффективности алгоритмов сортировок для
различных структур и размерностей данных
3.1 Постановка задачи




Провести экспериментальный сравнительный анализ различных методов
сортировки. Для чистоты эксперимента сортировка должна проводиться на
одинаковых наборах входных данных, которые генерируются случайным
образом. Для более полного анализа методов сортировка должна
проводиться для различных размерностей данных
Проследить динамику роста требуемого для сортировки времени.
Проверить, как ведут себя методы на различных входных данных: упорядоченных
в прямом порядке, упорядоченных в обратном порядке и случайных.
Сравнить теоретические оценки времени сортировки и числа требуемых
операций с экспериментальными.
3.2 Краткое теоретическое описание реализуемых объектов
Быстрая сортировка:
 выбрать элемент, называемый опорным.
 сравнить все остальные элементы с опорным, на основании сравнения разбить
множество на три — «меньшие опорного», «равные» и «большие», расположить
их в порядке меньшие-равные-большие.
 повторить рекурсивно для «меньших» и «больших».
Сортировка Шелла:
Идея сортировки состоит в сравнении элементов, стоящих не только рядом, но и на расстоянии
друг от друга. Иными словами — сортировка вставками либо сортировка простыми обменами с
предварительными «грубыми» проходами.
При сортировке Шелла сначала сравниваются и сортируются между собой ключи, отстоящие
один от другого на некотором расстоянии d. После этого процедура повторяется для некоторых
меньших значений d, а завершается сортировка Шелла упорядочиванием элементов при d = 1
Сортировка пузырьком:
Алгоритм состоит в повторяющихся проходах по сортируемому массиву. За каждый
проход элементы последовательно сравниваются попарно и, если порядок в паре
неверный, выполняется обмен элементов. Проходы по массиву повторяются до тех пор,
пока на очередном проходе не окажется, что обмены больше не нужны, что означает —
массив отсортирован. При проходе алгоритма, элемент, стоящий не на своём месте,
«всплывает» до нужной позиции как пузырёк в воде, отсюда и название алгоритма.
Глупая сортировка:
Имеет нечто общее с сортировкой пузырьком: идёт поиск от начала массива, текущий элемент
сравнивается со следующим, если следующий меньше, то производится обмен и возврат в
начало цикла.
10
3.3 Анализ результатов
Исследования проводились на одинаковых данных, для получения более точных
результатов. Быстрая сортировка №1 – опорным элементом выбирается средний
элемент. Быстрая сортировка №2 – опорным элементом выбирается самый крайний.
Пример работы программы
Сравнительный анализ алгоритмов сортировки в не отсортированном
массиве размерностью N:
N
500
1000
3000
5000
8000
10000
30000
60000
Пузырьком,
нс
1343266
5410761
49207911
144599151
357047808
550873282
5177930700
21100235280
Быстрая 1
,нс
67489
143822
471958
891783
1331624
1712354
5902243
12367204
Быстрая 2,
нс
52594
113568
397487
702814
1167323
1482426
5334407
10575726
Шелла, нс
Глупая, нс
49802
110310
399815
725620
1248310
1665344
5915276
12836367
32128987
248885732
6886380054
45285407760
184958931443
258014094452
-
11
Как видно из таблицы наиболее худшее время показала «Глупая» сортировка, что
подтверждает ее теоретическая временная сложность O(n3). Наилучшие результаты, при
больших размерах массива, показала Быстрая сортировка №2, при небольшом размере
массива наиболее эффективная сортировка Шелла. Сортировка пузырьком показывает
не плохие значения только при небольших размерах массива, при увеличении размера
массива эффективность этого алгоритма резку уменьшается. В исследование были
использованы два вида Быстрой сортировки, имеющие одинаковый алгоритм, но
различную реализацию, что показывает то, что для достижения минимального времени
обработки данных, не достаточно применить быстрейший алгоритм, но и важно
осуществить его оптимальную реализацию.
30
25
20
Пузырька
Быстрая 1
15
Быстрая 2
Шелла
10
Глуппая
5
0
500
1000
3000
5000
8000
10000
30000
60000
График зависимости времени выполнения от размерности не упорядоченного
массива (мс)
Сравнительный анализ алгоритмов сортировки в отсортированном
массиве в прямом порядке размерностью N:
N
500
1000
3000
5000
8000
10000
30000
60000
Пузырьком,
нс
Быстрая 1
,нс
Быстрая 2,
нс
Шелла, нс
Глупая, нс
4189
5585
13963
20480
31650
41425
114498
227135
29789
58645
200604
322085
515242
726552
2155918
4483117
266232
1099835
9231535
26003197
66452720
-
18617
37236
125669
224808
373748
562251
1986963
3417260
3724
4189
9309
13963
20945
27927
74471
148476
В упорядоченном массиве результаты обратные чем полученные ранее, самыми
12
эффективными оказались сортировка пузырьком и «Глуппая» сортировка, так как они
имеют самый простой алгоритм и реализацию, в упорядоченном массиве их временная
сложность О(n), что подтверждается графиком(Рис. 4). Худшей оказалась «Быстрая 2»
сортировка, при размерности массива более 8000, компилятор выдавал исключения из
перегрузки стека, в следствии слишком глубокой рекурсии и не правильного выбора
опорного элемента. «Быстрая 1» сортировка выполняется корректно, хотя имеет такой
же алгоритм, но опорный элемент всегда выбирается по центру. Алгоритм Шелла
показал
стабильные
результаты.
5
4.5
4
3.5
Пузырька
3
Быстрая 1
2.5
Быстрая 2
2
Шелла
Глуппая
1.5
1
0.5
0
500
1000
3000
5000
8000
10000
30000
60000
График зависимости времени выполнения от размерности упорядоченного по
возрастанию массива (мс)
Сравнительный
анализ
алгоритмов
сортировки
отсортированном массиве в обратном порядке размерностью N:
Быстрая 2,
Шелла, нс
Глупая, нс
нс
1103092
32116
271352
25599
49428789
500
5193378
69816
1110074
61438
559108776
1000
38735306
220153
9379545
178264
15227837962
3000
108025813
511053
26131193
326739
50150923083
5000
276824583
514777
66425259
371421
209714885467
8000
439645241
679077
91452894
505467
415666856722
10000
2333839112
2478468
1943677
30000
16794486864
4936456
5198964
60000
Если массив упорядочен в обратном порядке «Глупая» сортировка опять показывает
наихудший результат так как ее временная сложность О(n!). «Быстрая 2» сортировка так
же оказалось не стабильной из-за глубокой рекурсии. Лучший результат при небольших
N
Пузырьком, нс
в
Быстрая 1 ,нс
13
размерностях массива показала сортировка Шелла, а при больших «Быстрая 1»
сортировка.
5
4.5
4
3.5
Пузырька
3
Быстрая 1
2.5
Быстрая 2
2
Шелла
1.5
Глуппая
1
0.5
0
500
1000
3000
5000
8000
10000
30000
60000
График зависимости времени выполнения от размерности упорядоченного в
обратном порядке массива (мс)
Вывод по разделу
Для получения наиболее стабильных результатов сортировки предпочтительней
использовать сортировку Шелла, а если необходима обрабатывать массивы большой
размерностью то эффективней будет быстрая сортировка но при оптимальной ее
реализации, которая исключает глубокую рекурсию. Сортировку пузырьком и «Глупую»
сортировку целесообразно использовать только в упорядоченных или частично
упорядоченных массивах, из-за их простого алгоритма и реализации.
14
4. Реализация структур данных типа дерево и типовые алгоритмы
их обработки
4.1 Постановка задачи
Реализовать методы создания сильноветвящихся деревьев реализующих информацию
соответствующей предметной области, а также методы поиска, удаления и добавления
узлов в них
4.2 Краткие теоретические сведения
Если узлы дерева имеют более двух потомков, то такие деревья принято называть
сильноветвящимися деревьями. Одна из важных областей применения
сильноветвящихся деревьев - это формирование и использование крупномасштабных
деревьев поиска. Если множество данных, состоящее, например, из миллиона
элементов, хранится в виде бинарного дерева, то для поиска элемента потребуется в
среднем около log2106 т.е. приблизительно 20 шагов поиска. Поскольку каждый шаг
поиска включает обращение к элементам структуры, для достижения минимального
количества обращений сильноветвящееся дерево является идеальным решением.
Добавление элемента в Б-дерево.
1. Элементы вставляются в страницу содержащую m<2n элементов. Тогда процесс
включения ограничивается данной страницей.
2. Включение элемента в заполненную таблицу:
a. Поиск по дереву элемента с данным ключом, и если элемента нет, то
определение страницы, где элемент должен быть.
b. Если на этой странице количество элементов m<2n, то включение
производится только на данной странице.
c. Иначе размещается новая страница, количество ключей m+1(ключ,
который вставляется) поровну распределяется на две страницы, а средний
ключ перемещается на уровень вверх
d. Все выполняется , начиная с пункта b но уже со страницей верхнего
уровня.
Удаление элементов из Б-дерева.
Возможны два случая:
1. Удаляемый элемент находиться на странице-листе. Тогда алгоритм прост и
очевиден.
2. Удаляемый элемент находиться не на странице-листе.
Алгоритм
1. Производим поиск смежного ключа(самый правый левого поддерева или самый
левый правого поддерева ). Допустим, находим его на странице Р.
2. Заменяем удаляемый элемент на смежный , а Р уменьшаем на единицу.
3. Проверяем число элементов на уменьшенной странице Р. Если m<n, то нарушено
свойство Б-деревьев и нужно совершить дополнительные действия:
15


Балансировку: вызывается соседняя страница Q и элементы страниц P и Q
поровну распределяются на обе страницы.
Слияние: используется, если страница Q достигла своего минимального значения.
Процесс слияния полностью обратен процессу расщипления.
Поиск в Б-дереве.
Если ключ содержится в корне, он найден. Иначе определяем интервал и идём к
соответствующему сыну. Повторяем, пока не дошли до листа.
Схематичная структура узлов.
4.3 Структура дерева
При создании дерева была использована предметная область служба занятости
Для этого было реализовано Б-дерево, которое хранит список всех безработных,
критерием сортировке в дереве был выбран алфавитный порядок по фамилии.
16
4.4 Анализ результатов
Для изучения эффективности такого типа данных как дерево, были проведены
эксперименты в которых исследовалось средняя скорость поиска и удаления в АТД
дерево и список при различном количестве исходных данных:
25000000
Время, нс
20000000
15000000
10000000
5000000
1000
950
900
850
800
750
700
650
600
550
500
450
400
350
300
250
200
150
100
50
0
Количество объектов, т. шт.
Как видно из графика скорость выполнения операции поиска и удаления в дереве
практически не зависит от количества объектов, а в большей степени зависит от высоты
дерева. Напротив скорость удаления и поиска в списке линейно зависит от количества
объектов.
Пример работы программы:
Size:8
Добавление фамилии: Test
Size:9
Удаление фамилии: Sidorov:
Size:8
Поиск фамилии: Safronov
17
Вывод по разделу
Тип данных дерево позволяет сократить количество обращений к объектам, это дает
большое преимущество при хранении объектов на носителях информации с большим
временем отклика. Так же операции с деревом дают лучшие временные показатели по
сравнению с операциями списков.
18
5. Реализация функций расстановки (хеширование) и разрешение
коллизий методом построения цепочки.
5.1 Постановка задачи
Хеш-таблица представляет базу данных предметной области, соответствующей
варианту.
Реализовать:
 Выбор ключа для соответствующей базы данных
 По крайней мере, 3 различных функции хеширования для конкретных данных
 Заполнение таблицы для каждой функции
 Добавление новых данных для каждой функции
 Удаление данных
 Поиск данных по ключу
 Оценку качества хеширования для каждой функции
 Сравнение функций хеширования
 Двойное хеширование
5.2 Краткие теоретические сведения
Хеширование – расширенный вариант поиска с использованием индексации по
ключу, применяемый в более типовых приложениях поиска, в которых не приходиться
рассчитывать на наличие ключей со столь удобными свойствами.
Алгоритм поиска , которые используют хеширование, состоят из двух отдельных
частей. Первый шаг – вычисление хеш-функции, которая преобразует ключи поиска в
адрес в таблице. В идеале различные ключи должны были бы отображаться на
различных адресах, но часто два и более различных ключа могут преобразоваться в
один и тот же адрес в таблице. Поэтому вторая часть поиска методом хеширования –
процесс разрешения коллизий, которые обрабатывают такие ключи.
Существует много различных методов разрешения коллизий, например,
линейное опробование (поиск следующего незанятого в таблице). Недостатком
линейного опробования является возможность переполнения таблицы. Однако если
строить цепочку (односвязный список) на каждый адрес коллизии, то переполнения
таблицы можно избежать.
Другим достоинством цепочки является то, что другие элементы не скапливаются
вблизи первичного и не увеличивают, таким образом, вероятности возникновения
других коллизий в этом районе.
19
Среди недостатков необходимо отметить относительную сложность в реализации
(введение указателей и присущее им падение скорости) по сравнению с линейным
опробованием.
5.3 Описание хеш-функции
Хеш-таблица содержит список объектов «Книга» которые имеют текстовое поле Имя и
числовое поле Количество страниц.
Хеш-Функция №1 – Использует комплексный алгоритм хеширования включающий
текстовое и числовое поле объекта.
Хеш-Функция №2 – Использует только текстовое поле объекта, и более простые
алгоритмы.
Хеш-Функция №3 – Использует только числовое поле объекта, не применяя функций.
20
5.4 Анализ результатов
Для трех разных хеш-функций были проведены исследования, в которых были получены
зависимости количества коллизий от количества элементов(N)(считались все коллизии,
включая те которые возникли при дальнейшем хешировании (двойное хеширование),
для решения первой коллизии ) в хеш-таблице, при определенном размере хештаблице (100 000), полученные данные приведены ниже:
N
Количество коллизий, миллионов шт.
10000
20000
30000
40000
50000
60000
70000
80000
90000
100000
Хеш-функция 1
213730
1461716
3799095
7525307
12761750
22067937
39533473
76047918
162639909
415248303
Хеш-функция 2
3629714
38812821
135950276
283519526
430977922
681551206
984392742
1338561997
1666211950
2527274840
Хеш-функция 3
6845698
78163926
248101457
519513746
889194094
1361034476
1929252012
2600076076
3369783990
4239301377
4500
4000
3500
3000
2500
Hash1
2000
hash2
1500
Hash3
1000
500
0
10000 20000 30000 40000 50000 60000 70000 80000 90000 100000
Количество элементов, шт
Как видно из графиков количество коллизий возрастает экспоненциально. Лучшие
результаты показывает первая хеш-функция из сложного алгоритма и большого
21
диапазоны значений. Худшие результаты показывает хеш-функция №3 так как она имеет
диапазон значений много меньше чем количество элементов. Так же для первой
функции, для получения хороших результатов, следует не допускать заполнения
таблицы более 50%.
Зависимость количества коллизий от размера хеш-таблицы при фиксированном
количестве добавляемых объектов в хеш-таблицу (10000 объектов).
Размер
11000
21000
31000
41000
51000
61000
71000
81000
91000
101000
Хеш-Функция
1
984852
249446
239175
224635
198098
194154
229861
190343
174189
195330
Хеш-Функция
2
7778899
2751223
2684380
2983706
2754744
2281584
2253284
2595359
2635975
2433977
Хеш-Функция 3
6726262
6691327
6830156
6664464
6849117
6684149
6921839
6898305
6625759
6790354
9000000
Количество колизий
8000000
7000000
6000000
5000000
Hash1
4000000
Hash2
3000000
Hash3
2000000
1000000
0
11000 21000 31000 41000 51000 61000 71000 81000 91000 101000
Размер хеш-таблицы
При наполненности
хеш-таблицы более 90% количество коллизий резко
возрастает . Hash3 имеет стабильно большое количество коллизий из того , что у него
очень маленький диапазон значений хеш-функции, порядка 1500 значений и функция
двойного хеширование имеет небольшие значения. Наиболее оптимальной хешфункцией является Hash1, так как ее алгоритмы наиболее запутаны, и дают наиболее
22
рассеянные и в большем диапазоне результаты. При наполненности менее 40% все хешфункции показывают стабильные результаты вследствие ограниченного диапазона
значений и не совершенства алгоритмов хеширования.
Пример работы программы:
Hash1 collisions(10000):195931
Hash2 collisions(10000):2668034
Hash3 collisions(10000):6758486
Hash1 collisions(20000):1372783
Hash2 collisions(20000):73758493
Hash3 collisions(20000):77969000
Hash1 collisions(30000):3857532
Hash2 collisions(30000):247281076
Hash3 collisions(30000):247580921
Hash1 collisions(40000):7457602
Hash2 collisions(40000):522236138
Hash3 collisions(40000):518361767
Hash1 collisions(50000):12821905
Hash2 collisions(50000):896274527
Hash3 collisions(50000):888439511
Hash1 collisions(60000):20967275
Hash2 collisions(60000):1372106088
Hash3 collisions(60000):1359837921
Hash1 collisions(70000):36867706
Hash2 collisions(70000):1945767204
Hash3 collisions(70000):1929221346
Hash1 collisions(80000):73648426
Hash2 collisions(80000):2617168891
Hash3 collisions(80000):2597547521
Hash1 collisions(90000):172512680
Hash2 collisions(90000):3396294430
Hash3 collisions(90000):3371072896
Hash1 collisions(100000):427674036
Hash2 collisions(100000):4268782428
Hash3 collisions(100000):4240361188
Вывод по разделу
Для создания наиболее эффективной хеш-таблицы не достаточно использовать хорошую
хеш-функцию надо чтобы функция подходила конкретным данным с точки зрения
диапазона и рассеивания так же что бы процент наполненности таблицы не превышал
определенного значения. Двойное хеширование позволяет избежать скопление
значений в одной области хеш-таблицы, при большой наполненности таблицы
эффективность этого метода значительно снижается.
23
Список литературы
 Альфред Ахо, Джон Э. Хопкрофт, Д. Ульман Структуры данных и алгоритмы. М.,
Изд-во "Вильямс", 2000 г.
 Н. Вирт Алгоритмы и структуры данных. М., Издат-во "Вильямс", 1998г.
 Д. Кнут. Искусство программирования для ЭВМ. Т.1. Основные алгоритмы. М., Издво "Вильямс", 2000г.
 Уильям Топп, Уильям Форд. Структуры данных в С++. М., Изд-во "Бином", 2000 г.
 Роберт Седвидж. Фундаментальные алгоритмы на С++
 Д. Кнут. Искусство программирования для ЭВМ. Т.1. Основные алгоритмы. М.,
"Мир", 1976 г., переиздание - М.,Изд-во "Вильямс", 2000г.
 Д. Кнут. Искусство программирования для ЭВМ. Т.3. Сортировка и поиск. М.,
"Мир", 1978 г., переиздание - М.,Изд-во "Вильямс", 2000 г.
 Н. Вирт Алгоритмы и структуры данных. М., Издат-во "Вильямс", 1998г.
 Хэширование-Википедия.-10.12.2010.-Режим доступа:
http://ru.wikipedia.org/wiki/Хэширование
 Методы сортировки массивов и поисков в них параметрических элементов26.11.2010.- Режим доступа: http://serzik.ru/?id=31
24
Приложение 1
Исходный код программы по реализации АТД структур
PACKAGE PART_1;
IMPORT JAVA.UTIL.RANDOM;
PUBLIC CLASS MAIN {
PUBLIC STATIC VOID MAIN(STRING[] ARGS) {
STACK S = NEW STACK();
QUEUE Q1 = NEW QUEUE();
QUEUE Q2 = NEW QUEUE();
QUEUE Q3 = NEW QUEUE();
RANDOM RND = NEW RANDOM();
FOR (INT I = 0; I < 50; I++) {
INT R = RND.NEXTINT(3) + 1;
INT TI = RND.NEXTINT(5) + 2;
TASK T = NEW TASK("" + I, R, TI);
IF (R == 1) {
Q1.ENQUEUE(T);
}
IF (R == 2) {
Q2.ENQUEUE(T);
}
IF (R == 3) {
Q3.ENQUEUE(T);
}
}
PROCESSOR P1 = NEW PROCESSOR("P1");
PROCESSOR P2 = NEW PROCESSOR("P2");
INT STEP = 1;
WHILE (Q1.SIZE() > 0 || Q2.SIZE() > 0 || Q3.SIZE() > 0 || P1.ISWORK() || P2.ISWORK() || S.TAIL
25
!= NULL) {
SYSTEM.OUT.PRINTLN("STEP:" + STEP);
TASK T;
IF (Q1.SIZE() > 0 && !P1.ISWORK()) {
T = Q1.DEQUEUE();
P1.ADDTASK(T);
}
IF (Q1.SIZE() > 0 && P1.ISWORK() && P1.GETTASK().PRIORITY == 3) {
S.PUSH(P1.GETTASK());
P1.ADDTASK(Q1.DEQUEUE());
}
IF (Q2.SIZE() > 0 && P2.ISWORK() && P2.GETTASK().PRIORITY == 3) {
S.PUSH(P2.GETTASK());
P2.ADDTASK(Q2.DEQUEUE());
}
IF (((Q1.ISEMPTY() && !P1.ISWORK()) || (Q2.ISEMPTY() && !P2.ISWORK())) &&
!S.ISEMPTY()) {
IF (Q1.ISEMPTY()) {
P1.ADDTASK(S.POP());
} ELSE {
P2.ADDTASK(S.POP());
}
}
IF (Q2.SIZE() > 0 && !P2.ISWORK()) {
T = Q2.DEQUEUE();
P2.ADDTASK(T);
}
IF (((Q1.ISEMPTY() && !P1.ISWORK()) || (Q2.ISEMPTY() && !P2.ISWORK())) &&
!Q3.ISEMPTY()) {
IF (Q1.ISEMPTY()) {
P1.ADDTASK(Q3.DEQUEUE());
26
} ELSE {
P2.ADDTASK(Q3.DEQUEUE());
}
}
P1.NEXTSTEP();
P2.NEXTSTEP();
SYSTEM.OUT.PRINTLN(P1.GETINFO());
SYSTEM.OUT.PRINTLN(P2.GETINFO());
Q1.SHOW();
Q2.SHOW();
Q3.SHOW();
S.SHOW();
IF (STEP == 30 || STEP == 150) {
FOR (INT I = 0; I < 30; I++) {
INT R = RND.NEXTINT(3) + 1;
INT TI = RND.NEXTINT(5) + 2;
T = NEW TASK("" + I, R, TI);
IF (R == 1) {
Q1.ENQUEUE(T);
}
IF (R == 2) {
Q2.ENQUEUE(T);
}
IF (R == 3) {
Q3.ENQUEUE(T);
}
}
}
STEP++;
}
27
}
}
PACKAGE PART_1;
PUBLIC CLASS PROCESSOR {
PRIVATE BOOLEAN INWORK;
PRIVATE TASK TASK;
PRIVATE INT TIME;
PRIVATE STRING NAME;
PUBLIC PROCESSOR(STRING NAME) {
NAME = NAME;
INWORK = FALSE;
TASK = NULL;
TIME = 0;
}
PUBLIC VOID ADDTASK(TASK TASK) {
TASK = TASK;
TIME = TASK.TIME;
INWORK = TRUE;
}
PUBLIC STRING GETNAME() {
RETURN NAME;
}
PUBLIC BOOLEAN ISWORK() {
RETURN INWORK;
}
PUBLIC TASK GETTASK() {
RETURN TASK;
}
PUBLIC INT TIMELEFT() {
RETURN TIME;
28
}
PUBLIC BOOLEAN NEXTSTEP() {
IF (TASK != NULL) {
TASK.TIME--;
}
IF (TIME-- == 0) {
INWORK = FALSE;
TASK = NULL;
RETURN FALSE;
} ELSE {
RETURN TRUE;
}
}
PUBLIC STRING GETINFO() {
STRING S = "PROCESSOR \"" + NAME + "\": ";
IF (INWORK) {
S += "TYPE" + TASK.PRIORITY + "WORKS. " + "TIME LEFT: " + TIME + ".";
} ELSE {
S += "IDLE.";
}
RETURN S;
}
}
PACKAGE PART_1;
PUBLIC CLASS QUEUE {
PRIVATE CLASS NODE {
PUBLIC TASK VALUE;
PUBLIC NODE NEXT;
PUBLIC NODE() {
}
29
PUBLIC NODE(TASK TASK, NODE NEXT) {
THIS.VALUE = TASK;
THIS.NEXT = NEXT;
}
}
PRIVATE NODE TOPOFQUEUE;
PUBLIC QUEUE() {
TOPOFQUEUE = NULL;
}
PUBLIC BOOLEAN ISEMPTY() {
RETURN TOPOFQUEUE == NULL;
}
PUBLIC VOID MAKEEMPTY() {
TOPOFQUEUE = NULL;
}
PUBLIC VOID ENQUEUE(TASK X) {
TOPOFQUEUE = NEW NODE(X, TOPOFQUEUE);
}
PUBLIC TASK DEQUEUE() {
IF (ISEMPTY()) {
THROW NEW UNDERFLOWEXCEPTION("LISTSTACK EMPTY");
}
IF (SIZE() == 1) {
TASK E = TOPOFQUEUE.VALUE;
TOPOFQUEUE = NULL;
RETURN E;
}
NODE T = TOPOFQUEUE;
NODE T1 = NULL;
FOR (INT I = 0; I < SIZE() - 1; I++) {
T1 = T;
30
T = T.NEXT;
}
T1.NEXT = NULL;
RETURN T.VALUE;
}
PUBLIC VOID SHOW() {
NODE LISTNODE = TOPOFQUEUE;
SYSTEM.OUT.PRINT("LIST:");
INT I = 0;
IF (!ISEMPTY()) {
WHILE (I < SIZE()) {
I++;
SYSTEM.OUT.PRINT("(" + LISTNODE.VALUE.NAME + "," + LISTNODE.VALUE.PRIORITY
+ "," + LISTNODE.VALUE.TIME + ")");
LISTNODE = LISTNODE.NEXT;
}
}
SYSTEM.OUT.PRINTLN();
}
PUBLIC INT SIZE() {
IF (ISEMPTY()) {
RETURN 0;
} ELSE {
INT I = 1;
NODE LISTNODE = TOPOFQUEUE;
WHILE (LISTNODE.NEXT != NULL) {
LISTNODE = LISTNODE.NEXT;
I++;
}
RETURN I;
}
}}
PACKAGE PART_1;
PUBLIC CLASS STACK {
31
PRIVATE CLASS NODE {
PUBLIC TASK VALUE;
PUBLIC NODE PREV;
PUBLIC NODE() {
}
PUBLIC NODE(TASK TASK, NODE PREV) {
THIS.VALUE = TASK;
THIS.PREV = PREV;
}
}
NODE TAIL;
PUBLIC STACK() {
}
PUBLIC VOID PUSH(TASK TASK) {
TAIL = NEW NODE(TASK, TAIL);
}
PUBLIC TASK POP() {
IF (TAIL != NULL) {
NODE TEMP = TAIL;
TAIL = TAIL.PREV;
RETURN TEMP.VALUE;
} ELSE {
RETURN NULL;
}
}
PUBLIC TASK TOP() {
RETURN TAIL.VALUE;
}
PUBLIC VOID CLEAN() {
TAIL = NULL;
}
PUBLIC BOOLEAN ISEMPTY() {
RETURN TAIL == NULL;
}
32
PUBLIC VOID SHOW() {
NODE T;
SYSTEM.OUT.PRINT("STACK:");
IF (!ISEMPTY()) {
T = TAIL;
WHILE (T.PREV != NULL) {
SYSTEM.OUT.PRINT("(" + T.VALUE.NAME + "," + T.VALUE.PRIORITY + "," +
T.VALUE.TIME + ")");
T = T.PREV;
+ ")");
}
SYSTEM.OUT.PRINT("(" + T.VALUE.NAME + "," + T.VALUE.PRIORITY + "," + T.VALUE.TIME
}
SYSTEM.OUT.PRINTLN(); }}
PACKAGE PART_1;
PUBLIC CLASS TASK {
PUBLIC INT TIME;
STRING NAME;
INT PRIORITY;
PUBLIC TASK() {
NAME = "";
PRIORITY = 0;
TIME = 0;
}
PUBLIC TASK(STRING NAME, INT PRIORITY, INT TIME) {
THIS.NAME = NAME;
THIS.PRIORITY = PRIORITY;
THIS.TIME = TIME;
}
PUBLIC STRING TOSTRING() {
RETURN NAME + "(" + PRIORITY + "," + TIME + ")";
}
PUBLIC INT GETPRIORITY() {
RETURN PRIORITY;
}}
33
Приложение 2
Исходный код программы по реализации поиска
PACKAGE PART_2;
IMPORT JAVA.IO.BUFFEREDREADER;
IMPORT JAVA.IO.FILEREADER;
IMPORT JAVA.IO.IOEXCEPTION;
PUBLIC CLASS MAIN {
PUBLIC STATIC VOID MAIN(STRING[] ARGS) THROWS IOEXCEPTION {
STRING FILENAME = "E:\\TEXT.TXT";//ИМЯ ФАЙЛА
STRING SEARCHSTRING = "ЛЕВ НИКОЛАЕВИЧ ТОЛСТОЙ";//ТО, ЧТО НУЖНО НАЙТИ
BUFFEREDREADER FILEIN = NEW BUFFEREDREADER(NEW FILEREADER(FILENAME));
STRING LINE;
INT LINECOUNTER = 0;
LONG STARTTIME = SYSTEM.NANOTIME();
WHILE ((LINE = FILEIN.READLINE()) != NULL) {
LINECOUNTER++;
INT OFFSET = KMP.KMP(LINE.TOCHARARRAY(), SEARCHSTRING.TOCHARARRAY());
IF (OFFSET != -1) {
SYSTEM.OUT.PRINTLN("СТРОКА " + LINECOUNTER);
STARTTIME = SYSTEM.NANOTIME() - STARTTIME;
SYSTEM.OUT.PRINTLN(STARTTIME);
BREAK;
} }}}
PACKAGE PART_2;
PUBLIC CLASS KMP {
PUBLIC STATIC INT KMP(CHAR[] HAYSTACK, CHAR[] NEEDLE) {
INT M = NEEDLE.LENGTH;
INT N = HAYSTACK.LENGTH;
INT[] PF = NEW INT[M + 1];
PF[0] = -1;
34
FOR (INT I = 1; I < M; I++) {
PF[I] = PF[I - 1] + 1;
WHILE (PF[I] > 0 && NEEDLE[I - 1] != NEEDLE[PF[I] - 1]) {
PF[I] = PF[PF[I] - 1] + 1;
}}
FOR (INT I = 0, J = 0; I < N; I++) {
WHILE (J > 0 && NEEDLE[J] != HAYSTACK[I]) {
J = PF[J];
}
IF (NEEDLE[J] == HAYSTACK[I]) {
J++;
}
IF (J == M) {
J = PF[J];
RETURN (I - M + 1);
}}
RETURN -1;
}}
35
Приложение 3
Исходный код программы по реализации сортировки.
PACKAGE PART_4;
36
Приложение 4
Исходный код программы по реализации сильноветвящегося дерева
PACKAGE PART_4;
IMPORT JAVA.UTIL.ARRAYLIST;
CLASS FAMILY {
PUBLIC STRING NAME;
PUBLIC FAMILY(STRING S) {
NAME = S;
}}
CLASS NODE {
PUBLIC NODE PREV;
PUBLIC ARRAYLIST NODE;
PUBLIC ARRAYLIST FAMILY;
PUBLIC NODE() {
NODE = NEW ARRAYLIST();
FAMILY = NEW ARRAYLIST();
}}
CLASS TREE {
PUBLIC NODE ROOT = NULL;
PUBLIC STATIC INT MIN = 2;
PUBLIC STATIC INT MAX = MIN * 2;
STATIC INT SIZE = 0;
PUBLIC INT LVL = 1;
PUBLIC FAMILY BK;
PUBLIC TREE() {
}
PUBLIC INT SIZE() {
SIZE = 0;
FOR (INT I = 0; I < ROOT.FAMILY.SIZE(); I++) {
SIZE++;
37
}
FOR (INT I = 0; I < ROOT.NODE.SIZE(); I++) {
S1(((NODE) ROOT.NODE.GET(I)));
}
RETURN SIZE;
}
PRIVATE VOID S1(NODE N) {
FOR (INT I = 0; I < N.FAMILY.SIZE(); I++) {
SIZE++;
}
FOR (INT I = 0; I < N.NODE.SIZE(); I++) {
S1(((NODE) N.NODE.GET(I)));
}
}
PRIVATE VOID S(NODE N) {
SYSTEM.OUT.PRINTLN(N.FAMILY.SIZE());
FOR (INT I = 0; I < N.FAMILY.SIZE(); I++) {
SYSTEM.OUT.PRINTLN(((FAMILY) N.FAMILY.GET(I)).NAME);
}
FOR (INT I = 0; I < N.NODE.SIZE(); I++) {
SYSTEM.OUT.PRINTLN(N.NODE.SIZE());
S(((NODE) N.NODE.GET(I)));
}
}
PUBLIC VOID SHOW() {
SYSTEM.OUT.PRINTLN(ROOT.FAMILY.SIZE());
FOR (INT I = 0; I < ROOT.FAMILY.SIZE(); I++) {
SYSTEM.OUT.PRINTLN(((FAMILY) ROOT.FAMILY.GET(I)).NAME);
}
FOR (INT I = 0; I < ROOT.NODE.SIZE(); I++) {
S(((NODE) ROOT.NODE.GET(I)));
}
}
38
PRIVATE NODE SRCH(NODE N, FAMILY B) {
IF (N.NODE.ISEMPTY()) {
RETURN N;
} ELSE {
FOR (INT I = 0; I < N.FAMILY.SIZE(); I++) {
IF (B.NAME.CHARAT(0) == ((FAMILY) N.FAMILY.GET(I)).NAME.CHARAT(0)) {
RETURN N;
}
IF (B.NAME.CHARAT(0) < ((FAMILY) N.FAMILY.GET(I)).NAME.CHARAT(0)) {
RETURN SRCH((NODE) N.NODE.GET(I), B);
}
}
RETURN SRCH((NODE) N.NODE.GET(N.FAMILY.SIZE()), B);
}
}
PUBLIC NODE SEARCH(FAMILY N) {
IF (ROOT.NODE.ISEMPTY()) {
RETURN ROOT;
} ELSE {
FOR (INT I = 0; I < ROOT.FAMILY.SIZE(); I++) {
IF (N.NAME.CHARAT(0) == ((FAMILY) ROOT.FAMILY.GET(I)).NAME.CHARAT(0)) {
RETURN ROOT;
}
IF (N.NAME.CHARAT(0) < ((FAMILY) ROOT.FAMILY.GET(I)).NAME.CHARAT(0)) {
RETURN SRCH((NODE) ROOT.NODE.GET(I), N);
}
}
WHILE (ROOT.NODE.SIZE() <= ROOT.FAMILY.SIZE()) {
ROOT.FAMILY.REMOVE(ROOT.FAMILY.SIZE() - 1);
}
RETURN SRCH((NODE) ROOT.NODE.GET(ROOT.FAMILY.SIZE()), N);
}
}
PRIVATE INT SET(NODE D, FAMILY B) {
FOR (INT I = 0; I < D.FAMILY.SIZE(); I++) {
39
IF (B.NAME.CHARAT(0) < ((FAMILY) D.FAMILY.GET(I)).NAME.CHARAT(0)) {
D.FAMILY.ADD(I, B);
RETURN I;
}
}
D.FAMILY.ADD(D.FAMILY.SIZE(), B);
RETURN D.FAMILY.SIZE() - 1;
}
PRIVATE VOID OVERROOT(NODE D, FAMILY B) {
NODE N1 = NEW NODE();
NODE N2 = NEW NODE();
SET(D, B);
INT T = SET(N2, (FAMILY) (D.FAMILY.REMOVE(MIN)));
N2.NODE.ADD(T, N1);
FOR (INT I = 0; I < MIN; I++) {
SET(N1, (FAMILY) (D.FAMILY.REMOVE(0)));
}
N2.NODE.ADD(T + 1, D);
N1.PREV = N2;
D.PREV = N2;
ROOT = N2;
}
PUBLIC NODE OVER(NODE D, FAMILY B) {
NODE N1 = NEW NODE();
SET(D, B);
SET(D.PREV, (FAMILY) D.FAMILY.GET(MIN));
D = D.PREV;
RETURN D;
}
PUBLIC VOID ADD(FAMILY B) {
IF (ROOT == NULL) {
40
ROOT = NEW NODE();
ROOT.FAMILY.ADD(B);
} ELSE {
NODE D = SEARCH(B);
IF (D.FAMILY.SIZE() < MAX) {
SET(D, B);
} ELSE {
IF (D.PREV == NULL) {
OVERROOT(D, B);
} ELSE {
WHILE (D.FAMILY.SIZE() == MAX) {
IF (D.PREV == NULL) {
OVERROOT(D, B);
RETURN;
} ELSE {
NODE N1 = NEW NODE();
SET(D, B);
INT T = SET(D.PREV, (FAMILY) D.FAMILY.REMOVE(MIN));
D.PREV.NODE.ADD(T, N1);
FOR (INT I = MIN; I < MAX; I++) {
SET(N1, (FAMILY) (D.FAMILY.REMOVE(MIN)));
}
N1.PREV = D.PREV;
D = D.PREV;
}
}
}
}
}
}
PUBLIC VOID DEL(STRING S) {
FAMILY B = NEW FAMILY(S);
NODE D = SEARCH(B);
FOR (INT I = 0; I < D.FAMILY.SIZE(); I++) {
IF (((FAMILY) D.FAMILY.GET(I)).NAME.EQUALS(B.NAME)) {
41
D.FAMILY.REMOVE(I);
}
}
}
PUBLIC VOID FIND(STRING S) {
FAMILY B = NEW FAMILY(S);
NODE D = SEARCH(B);
FOR (INT I = 0; I < D.FAMILY.SIZE(); I++) {
IF (((FAMILY) D.FAMILY.GET(I)).NAME.EQUALS(B.NAME)) {
SYSTEM.OUT.PRINTLN("НАЙДЕНА ФАМИЛИЯ:" + ((FAMILY) D.FAMILY.GET(I)).NAME);
}
}
}}
PUBLIC CLASS MAIN {
PUBLIC STATIC VOID MAIN(STRING[] ARGS) {
TREE T = NEW TREE();
FAMILY B = NEW FAMILY("IVANOV");
FAMILY B1 = NEW FAMILY("PETROV");
FAMILY B2 = NEW FAMILY("SIDOROV");
FAMILY B3 = NEW FAMILY("STAVCHUK");
FAMILY B4 = NEW FAMILY("SAFRONOV");
FAMILY B5 = NEW FAMILY("CHISTYAKOV");
FAMILY B6 = NEW FAMILY("LAYCOM");
FAMILY B7 = NEW FAMILY("MIN");
FAMILY B8 = NEW FAMILY("TEST");
T.ADD(B);
T.ADD(B1);
T.ADD(B2);
T.ADD(B3);
T.ADD(B4);
T.ADD(B5);
T.ADD(B6);
T.ADD(B7);
SYSTEM.OUT.PRINTLN("SIZE:" + T.SIZE());
42
SYSTEM.OUT.PRINTLN("ДОБАВЛЕНИЕ ФАМИЛИИ:" + B8.NAME);
T.ADD(B8);
SYSTEM.OUT.PRINTLN("SIZE:" + T.SIZE());
SYSTEM.OUT.PRINTLN("УДАЛЕНИЕ ФАМИЛИИ: SIDOROV:");
T.DEL("SIDOROV");
SYSTEM.OUT.PRINTLN("SIZE:" + T.SIZE());
SYSTEM.OUT.PRINTLN("ПОИСК ФАМИЛИИ: SAFRONOV");
T.FIND("SAFRONOV");
}}
Приложение 5
Исходный код программы по реализации хеширования и разрешения
коллизий (Двойное хеширование).
PACKAGE PART_5;
IMPORT JAVA.UTIL.RANDOM;
CLASS BOOK {
PUBLIC STRING NAME = "";
PUBLIC INT PAGE = 0;
PUBLIC BOOK() {
}
PUBLIC BOOK(STRING N, INT PG) {
NAME = N;
PAGE = PG;
}}
CLASS HASHTABLE {
PUBLIC LONG COL = 0;
PUBLIC INT HASHSIZE;
PUBLIC BOOK HT[];
PUBLIC HASHTABLE() {
}
PUBLIC HASHTABLE(INT SIZE) {
HT = NEW BOOK[SIZE];
HASHSIZE = SIZE;
}
PUBLIC INT HF(BOOK KEY) {
INT H = 0;
FOR (INT I = 0; I < KEY.NAME.LENGTH(); I++) {
INT Y = KEY.NAME.CHARAT(I);
Y *= I * Y;
H += Y + KEY.PAGE * I;
}
RETURN H % HASHSIZE;
}
PUBLIC INT HF_2(BOOK KEY) {
INT H = 0;
FOR (INT I = 0; I < KEY.NAME.LENGTH(); I++) {
INT Y = KEY.NAME.CHARAT(I);
43
H += Y;
}
RETURN H % HASHSIZE;
}
PUBLIC INT HF_3(BOOK KEY) {
INT H = 0;
H = KEY.PAGE;
RETURN H % HASHSIZE;
}
PUBLIC INT HF2(BOOK KEY, INT INDEX) {
INT H = INDEX;
FOR (INT I = 0; I < KEY.NAME.LENGTH(); I++) {
H += KEY.NAME.CHARAT(I);
}
RETURN H % HASHSIZE;
}
PUBLIC VOID SHOWTABLE() {
FOR (INT I = 0; I < HT.LENGTH; I++) {
STRING N = "";
INT P = 0;
IF (HT[I] != NULL) {
N = HT[I].NAME;
P = HT[I].PAGE;
}
SYSTEM.OUT.PRINT("IN:" + I);
SYSTEM.OUT.PRINT(" NAME:" + N);
SYSTEM.OUT.PRINTLN(" , PAGE:" + P);
} }
PUBLIC VOID ADD(BOOK B) {
IF (HT[HF(B)] == NULL) {
HT[HF(B)] = B;
} ELSE {
INT H = HF(B);
INT SW = 0;
WHILE (TRUE) {
COL++;
IF (HT[HF2(B, H)] == NULL) {
HT[HF2(B, H)] = B;
BREAK;
} ELSE {
IF (SW > 10) {
H++;
H %= HASHSIZE;
IF (SW > HASHSIZE) {
SYSTEM.OUT.PRINTLN("OOPS");
}
} ELSE {
H = HF2(B, H);
}
}
SW++;
}
} }
PUBLIC VOID DEL(STRING S, INT P) {
BOOK B = NEW BOOK(S, P);
IF (HT[HF(B)] != NULL && B.NAME.EQUALS(HT[HF(B)].NAME) && B.PAGE == HT[HF(B)].PAGE)
{
44
HT[HF(B)] = NULL;
} ELSE {
INT H = HF(B);
INT SW = 0;
WHILE (TRUE) {
IF (HT[HF2(B, H)] != NULL && B.NAME.EQUALS(HT[HF2(B, H)].NAME) && B.PAGE ==
HT[HF2(B, H)].PAGE) {
HT[HF2(B, H)] = NULL;
BREAK;
} ELSE {
IF (SW > 10) {
H++;
H %= HASHSIZE;
IF (SW > HASHSIZE) {
SYSTEM.OUT.PRINTLN("OOPS");
BREAK;
}
} ELSE {
H = HF2(B, H);
}
}
SW++;
}
} }
PUBLIC VOID SEARCH(STRING S, INT P) {
BOOK B = NEW BOOK(S, P);
IF (HT[HF(B)] != NULL && B.NAME.EQUALS(HT[HF(B)].NAME) && B.PAGE == HT[HF(B)].PAGE)
{
SYSTEM.OUT.PRINTLN("BOOK: " + B.NAME + " (" + B.PAGE + ") IS FOUND AT INDEX " +
HF(B));
} ELSE {
INT H = HF(B);
INT SW = 0;
WHILE (TRUE) {
IF (HT[HF2(B, H)] != NULL && B.NAME.EQUALS(HT[HF2(B, H)].NAME) && B.PAGE ==
HT[HF2(B, H)].PAGE) {
SYSTEM.OUT.PRINTLN("BOOK: " + B.NAME + " (" + B.PAGE + ") IS FOUND AT INDEX "
+ HF2(B, H));
BREAK;
} ELSE {
IF (SW > 10) {
H++;
H %= HASHSIZE;
IF (SW > HASHSIZE) {
SYSTEM.OUT.PRINTLN("OOPS");
BREAK;
}
} ELSE {
H = HF2(B, H);
}
}
SW++;
}
} }
PUBLIC VOID SEARCH_2(STRING S, INT P) {
BOOK B = NEW BOOK(S, P);
IF (HT[HF_2(B)] != NULL && B.NAME.EQUALS(HT[HF_2(B)].NAME) && B.PAGE ==
HT[HF_2(B)].PAGE) {
SYSTEM.OUT.PRINTLN("BOOK: " + B.NAME + " (" + B.PAGE + ") IS FOUND AT INDEX " +
HF_2(B));
45
} ELSE {
INT H = HF_2(B);
INT SW = 0;
WHILE (TRUE) {
IF (HT[HF2(B, H)] != NULL && B.NAME.EQUALS(HT[HF2(B, H)].NAME) && B.PAGE ==
HT[HF2(B, H)].PAGE) {
SYSTEM.OUT.PRINTLN("BOOK: " + B.NAME + " (" + B.PAGE + ") IS FOUND AT INDEX "
+ HF2(B, H));
BREAK;
} ELSE {
IF (SW > 10) {
H++;
H %= HASHSIZE;
IF (SW > HASHSIZE) {
SYSTEM.OUT.PRINTLN("OOPS");
BREAK;
}
} ELSE {
H = HF2(B, H);
}
}
SW++;
}
} }
PUBLIC VOID SEARCH_3(STRING S, INT P) {
BOOK B = NEW BOOK(S, P);
IF (HT[HF_3(B)] != NULL && B.NAME.EQUALS(HT[HF_3(B)].NAME) && B.PAGE ==
HT[HF_3(B)].PAGE) {
SYSTEM.OUT.PRINTLN("BOOK: " + B.NAME + " (" + B.PAGE + ") IS FOUND AT INDEX " +
HF_3(B));
} ELSE {
INT H = HF_3(B);
INT SW = 0;
WHILE (TRUE) {
IF (HT[HF2(B, H)] != NULL && B.NAME.EQUALS(HT[HF2(B, H)].NAME) && B.PAGE ==
HT[HF2(B, H)].PAGE) {
SYSTEM.OUT.PRINTLN("BOOK: " + B.NAME + " (" + B.PAGE + ") IS FOUND AT INDEX "
+ HF2(B, H));
BREAK;
} ELSE {
IF (SW > 10) {
H++;
H %= HASHSIZE;
IF (SW > HASHSIZE) {
SYSTEM.OUT.PRINTLN("OOPS");
BREAK;
}
} ELSE {
H = HF2(B, H);
}
}
SW++;
}
} }
PUBLIC VOID DEL_2(STRING S, INT P) {
BOOK B = NEW BOOK(S, P);
IF (HT[HF_2(B)] != NULL && B.NAME.EQUALS(HT[HF_2(B)].NAME) && B.PAGE ==
HT[HF_2(B)].PAGE) {
HT[HF_2(B)] = NULL;
} ELSE {
INT H = HF_2(B);
INT SW = 0;
46
WHILE (TRUE) {
IF (HT[HF2(B, H)] != NULL && B.NAME.EQUALS(HT[HF2(B, H)].NAME) && B.PAGE ==
HT[HF2(B, H)].PAGE) {
HT[HF2(B, H)] = NULL;
BREAK;
} ELSE {
IF (SW > 10) {
H++;
H %= HASHSIZE;
IF (SW > HASHSIZE) {
SYSTEM.OUT.PRINTLN("OOPS");
BREAK;
}
} ELSE {
H = HF2(B, H);
}
}
SW++;
}
} }
PUBLIC VOID DEL_3(STRING S, INT P) {
BOOK B = NEW BOOK(S, P);
IF (HT[HF_3(B)] != NULL && B.NAME.EQUALS(HT[HF_3(B)].NAME) && B.PAGE ==
HT[HF_3(B)].PAGE) {
HT[HF_3(B)] = NULL;
} ELSE {
INT H = HF_3(B);
INT SW = 0;
WHILE (TRUE) {
IF (HT[HF2(B, H)] != NULL && B.NAME.EQUALS(HT[HF2(B, H)].NAME) && B.PAGE ==
HT[HF2(B, H)].PAGE) {
HT[HF2(B, H)] = NULL;
BREAK;
} ELSE {
IF (SW > 10) {
H++;
H %= HASHSIZE;
IF (SW > HASHSIZE) {
SYSTEM.OUT.PRINTLN("OOPS");
BREAK;
}
} ELSE {
H = HF2(B, H);
}
}
SW++;
}
} }
PUBLIC VOID ADD_2(BOOK B) {
IF (HT[HF_2(B)] == NULL) {
HT[HF_2(B)] = B;
} ELSE {
INT H = HF_2(B);
INT SW = 0;
WHILE (TRUE) {
COL++;
IF (HT[HF2(B, H)] == NULL) {
HT[HF2(B, H)] = B;
BREAK;
} ELSE {
IF (SW > 10) {
47
H++;
H %= HASHSIZE;
IF (SW > HASHSIZE) {
SYSTEM.OUT.PRINTLN("OOPS");
}
} ELSE {
H = HF2(B, H);
}
}
SW++;
}
} }
PUBLIC VOID ADD_3(BOOK B) {
IF (HT[HF_3(B)] == NULL) {
HT[HF_3(B)] = B;
} ELSE {
INT H = HF_3(B);
INT SW = 0;
WHILE (TRUE) {
COL++;
IF (HT[HF2(B, H)] == NULL) {
HT[HF2(B, H)] = B;
BREAK;
} ELSE {
IF (SW > 10) {
H++;
H %= HASHSIZE;
} ELSE {
H = HF2(B, H);
}
}
SW++;
}
} }}
PUBLIC CLASS MAIN {
PUBLIC STATIC VOID MAIN(STRING[] ARGS) {
RANDOM RND = NEW RANDOM();
INT SIZE = 0;
WHILE (SIZE < 95000) {
HASHTABLE TABLE = NEW HASHTABLE(100000);
HASHTABLE TABLE1 = NEW HASHTABLE(100000);
HASHTABLE TABLE2 = NEW HASHTABLE(100000);
SIZE += 10000;
FOR (INT I = 0; I < SIZE; I++) {
INT P = RND.NEXTINT(1500) + 1;
INT G = RND.NEXTINT(10) + 1;
STRING S = "";
FOR (INT J = 0; J < G; J++) {
CHAR Q = (CHAR) (RND.NEXTINT(26) + 97);
S += Q;
}
BOOK B = NEW BOOK(S, P);
TABLE.ADD(B);
TABLE1.ADD_2(B);
TABLE2.ADD_3(B);
}
SYSTEM.OUT.PRINTLN("HASH1 COLLISIONS(" + SIZE + "):" + TABLE.COL);
SYSTEM.OUT.PRINTLN("HASH2 COLLISIONS(" + SIZE + "):" + TABLE1.COL);
SYSTEM.OUT.PRINTLN("HASH3 COLLISIONS(" + SIZE + "):" + TABLE2.COL);
} }}
48
Download