Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
курсова1.doc
Скачиваний:
2
Добавлен:
11.07.2019
Размер:
146.94 Кб
Скачать

Побудова таблиць ідентифікаторів за методом бінарного дерева

Як мінімум, при додаванні нового ідентифікатора в таблицю компілятор повинен перевірити, чи існує там такий ідентифікатор, так як в більшості мов про ¬ граммирования жоден ідентифікатор не може бути описаний більше одного разу.Слідів ¬ вательно, кожна операція додавання нового елемента тягне, як правило, не менше однієї операції пошуку.

Можна скоротити час пошуку шуканого елементу в таблиці ідентифікаторів, не збільшуючи значно час, необхідний на її заповнення.Для цього треба відмовитися від організації таблиці у вигляді безперервного масиву даних. Існує метод побудови таблиць, при якому таблиця має форму бінару ¬ ного дерева.Кожен вузол дерева являє собою елемент таблиці, причому кореневий вузол є першим елементом, зустрінутим при заповненні таблиці.

Дерево називається бінарним, оскільки кожна вершина в ньому може мати не більше двох гілок. Для визначеності будемо називати гілки «права» і «ліва». Розглянемо алгоритм заповнення бінарного дерева.Будемо вважати, що алго ¬ ритм працює з потоком вхідних даних, що містить ідентифікатори (в ком ¬ піляторе цей потік даних породжується в процесі розбору тексту вихідної програми). Перший ідентифікатор, як уже було сказано, міститься в вер ¬ шину дерева.Всі подальші ідентифікатори потрапляють в дерево по следующе ¬ му алгоритмом:

Крок 1. Вибрати черговий ідентифікатор з вхідного потоку даних. Якщо оче ¬ редней ідентифікатора ні, то побудова дерева закінчено. Крок 2. Зробити поточним вузлом дерева кореневу вершину. Крок 3.Порівняти черговий ідентифікатор з ідентифікатором, що містяться в поточному вузлі дерева.

Крок 4. Якщо черговий ідентифікатор менше, то перейти до кроку 5, якщо ра ¬ вен - повідомити про помилку і припинити виконання алгоритму (двох одинако ¬ вих ідентифікаторів бути не повинно!), Інакше - перейти до кроку 7.Крок 5. Якщо в поточного вузла існує ліва вершина, то зробити її поточним вузлом і повернутися до кроку 3, інакше перейти до кроку 6.

Крок 6. Створити нову вершину, помістити в неї черговий ідентифікатор, сде ¬ лать цю нову вершину лівої вершиною поточного вузла і повернутися до кроку 1. Крок 7.Якщо в поточного вузла існує права вершина, то зробити її поточним вузлом і повернутися до кроку 3, інакше перейти до кроку 8.

Крок 8. Створити нову вершину, помістити в неї черговий ідентифікатор, сде ¬ лать цю нову вершину правою вершиною поточного вузла і повернутися до кроку 1.Розглянемо як приклад послідовність ідентифікаторів GA, Dl, М22, Е, А12, ВС, F. На рис. 2.2 проілюстрований весь процес побудови бінарного дерева для цієї послідовності ідентифікаторів.

Пошук потрібного елемента в дереві виконується за алгоритмом, схожим з алго ¬ ритмом заповнення дерева:

Крок 1. Зробити поточним вузлом дерева кореневу вершину.

Крок 2. Порівняти шуканий ідентифікатор з ідентифікатором, що містяться

в поточному вузлі дерева.

Крок 3.Якщо ідентифікатори збігаються, то шуканий ідентифікатор знайдений, ал ¬ горітм завершується, інакше треба перейти до кроку 4.

Крок 4. Якщо черговий ідентифікатор менше, то перейти до кроку 5, інакше - пе ¬ рейти до кроку 6.

Крок 5.Якщо в поточного вузла існує ліва вершина, то зробити її поточним вузлом і повернутися до кроку 2, інакше шуканий ідентифікатор не знайдений, алгоритм завершується.

Крок 6.Якщо в поточного вузла існує права вершина, то зробити її поточним вузлом і повернутися до кроку 2, інакше шуканий ідентифікатор не знайдений, алгоритм завершується.

Мал.2.2. Заповнення бінарного дерева для послідовності

індефікаторів GA, D1, M22, E, A12, BC, F

Наприклад, зробимо пошук в дереві, зображеному на рис. 2.2, Код ¬ ра А12. Беремо кореневу вершину (вона стає поточним вузлом), порівнюємо ідентифікатори GA і А12. Шуканий ідентифікатор менше - поточним вузлом стає ліва вершина D1. Знову порівнюємо ідентифікатори.Шуканий ідентифікатор менше - поточним вузлом стає ліва вершина А12. При наступному порівнянні шуканий ідентифікатор знайдений.

Якщо шукати відсутній ідентифікатор - наприклад, All, - то пошук знову піде від кореневої вершини. Порівнюємо ідентифікатори GA і АН.Шуканий ідентифікатор менше - поточним вузлом стає ліва вершина 01. Знову порівнюємо ідентифікатори. Шуканий ідентифікатор менше - поточним вузлом стає ліва вершина А12.Шуканий ідентифікатор менше, але ліва вер ¬ шина у вузла А12 відсутня, тому в даному випадку шуканий ідентифікатор не знайдений.

Для даного методу число необхідних порівнянь і форма отриманого дерева залежать від того порядку, в якому надходять ідентифікатори. Наприклад, якщо

в розглянутому вище прикладі замість послідовності ідентифікаторів ЗА, Dl, М22, Е, А12, ВС, F взяти послідовність А12, GA, Dl, М22, Е, ВС, F, то отриманий ¬ ве дерево матиме інший вигляд.А якщо як приклад взяти последова ¬ ність ідентифікаторів А, В, С, D, Е, F, то дерево виродиться в упорядкований односпрямований зв'язний список. Ця особливість є недоліком даного методу організації таблиць ідентифікаторів.Іншим недоліком є ​​не ¬ обхідних роботи з динамічним виділенням пам'яті при побудові дерева.Якщо припустити, що послідовність ідентифікаторів у вихідній про ¬ грамі є статистично невпорядкованою (що в цілому відповідає дійсності), то можна вважати, що побудоване бінарне дерево буде невиродженим.Тоді середній час на заповнення дерева (Т3) і на пошук еле ¬ мента в ньому (Т ") можна оцінити таким чином [4, т.2]:

Т3 = N * 0 (log2 N) Т "- 0 (log2 N)

У цілому метод бінарного дерева є досить вдалим механізмом для організації таблиць ідентифікаторів.Він знайшов своє застосування в ряді ком ¬ піляторов. Іноді компілятори будують кілька різних дерев для ідентифікаторів різних типів і різної довжини [17, 50].

Хеш-функції і хеш-адресація Принципи роботи хеш-функцій

Логарифмічна залежність часу пошуку і часу заповнення таблиці ідентифікаторів - це найкращий результат, якого можна досягти за рахунок застосування різних методів організації таблиць.Однак у реальних вихідних програмах кількість ідентифікаторів настільки велике, що навіть ло ¬ гаріфміческую залежність часу пошуку від їх числа не можна визнати удов ¬ летворітельной. Необхідні більш ефективні методи пошуку інформації в таблиці ідентифікаторів.

Кращих результатів можна досягти, якщо застосувати методи, пов'язані з ви ¬ користуванням хеш-функцій та хеш-адресації.

Хеш-функцією F називається деяке відображення множини вхідних елементів ¬ тів R на безліч цілих невід'ємних чисел Z: F (r) = n, reR, neZ.Сам термін «хеш-функція» походить від англійського терміна «hash function * (hash -« заважати »,« змішувати »,« плутати »). Замість терміна «хешування» іно ¬ гда використовуються терміни «рандомізація»,«Переупорядочивание». Безліч допустимих вхідних елементів R називається областю визначення ¬ ня хеш-функції.Безліччю значень хеш-функції F називається подмно ¬ дружність М з безлічі цілих невід'ємних чисел Z: McZ, що містить всі можливі значення, які повертаються функцією F: VreR: F (r) eM і VmeM: 3reR: F (r) = m.Процес відображення області визначення хеш-функції на множест ¬ во значень називається «хешем».

При роботі з таблицею ідентифікаторів хеш-функція повинна виконувати ото ¬ бражения імен ідентифікаторів на безліч цілих невід'ємних чисел.Областю визначення хеш-функції буде безліч всіх можливих імен ідентифікаторів.

Хеш-адресація полягає у використанні значення, що повертається хеш-функцією, як адресу комірки з деякого масиву даних.Тоді раз ¬ заходів масиву даних повинен відповідати області значень використовуваної хеш-функції. Отже, в реальному компіляторі область значень хеш-функції ніяк не повинна перевищувати розмір доступного адресного пространст ¬ ва комп'ютера.

Метод організації таблиць ідентифікаторів, заснований на використанні хеш-адресації, полягає в розміщенні кожного елемента таблиці у комірці, адреса якої повертає хеш-функція, обчислена для цього елемента.Тоді в ідеальному випадку для розміщення будь-якого елементу в таблиці ідентифіка ¬ торів достатньо тільки обчислити його хеш-функцію і звернутися до потрібної осередку масиву даних.Для пошуку елемента в таблиці необхідно обчислити хеш-функцію для шуканого елемента і перевірити, чи не є задана нею комірка масиву порожньою (якщо вона не порожня - елемент знайдений, якщо порожня - не знайдено).Спочатку таблиця ідентифікаторів повинна бути заповнена інформацією, яка дозволила б говорити про те, що всі її осередки є порожніми.

На рис. 2.3 проілюстрований метод організації таблиць ідентифікаторів з ви ¬ користуванням хеш-адресації.Трьом різним ідентифікаторам Al, А2, A3 соот ¬ повідають на малюнку три значення хеш-функції nl, п2, ПЗ. У комірки, адресовані nl, п2, ПЗ, міститься інформація про ідентифікаторах Al, А2, A3.При пошуку ідентифікатора A3 обчислюється значення адреси П3 і вибираються дані з со ¬ ответствующее клітинки таблиці.

Цей метод досить ефективний, оскільки як час розміщення елемента в таб ¬ лиці, так і час його пошуку визначаються тільки часом, що витрачається на обчислення хеш-функції, яке в загальному випадку незрівнянно менше време ¬ ні, необхідного для виконання багаторазових порівнянь елементів таблиці.Метод має два очевидних недоліки. Перший з них - неефективне вико ¬ користування обсягу пам'яті під таблицю ідентифікаторів: розмір масиву для її зберігання повинен відповідати області значень хеш-функції, в той час як реально збережених у таблиці ідентифікаторів може бути істотно менше.Другий недолік - необхідність відповідного розумного вибору хеш-функції. Цьому істотного питанню присвячені наступні два підпункти.