Professional Documents
Culture Documents
О. Костів - Структури даних
О. Костів - Структури даних
О. Костів
СТРУКТУРИ ДАНИХ
Львів
Видавничий центр ЛНУ імені Івана Франка
. 2005
Міністерство освіти і науки України
Львівський національний університет імені Івана Франка
О. Костів
СТРУКТУРИ ДАНИХ
Львів
Видавничий центр ЛНУ імені Івана Франка
2005
ББК 3973.2-018
К-72
УДК 004.4'232
Рецензенти:
канд. екон. наук, доц. О. Т. Іващук,
(Тернопільська академія народного господарства);
д-р фіз.-мат. наук, проф. Г. Г. Цегелик,
(Львівський національний університет);
канд. фіз-.мат. наук, доц. С. Б. Костенко,
(Львівська комерційна академія)
Костів О.
К-72 Структури даних: Навч. посібн. - Львів: Видавничий центр ЛНУ
імені Івана Франка, 2005. - 146 с.
ББК 3973.2-018
Рис. 2
використовують операції, специфічні для конструйованого алгоритму і
класу об'єктів, вибраних як АСД.
Виконаний на абстрактному рівні опис алгоритму може містити
багато операцій, які дуже корисні під час розробки алгоритму і
дослідженні його властивостей, проте неефективні під час реалізації
у машині. Вилучення таких операцій під час переходу від
абстрактного опису алгоритму до програми конкретною мовою
програмування становить етап стратегічної оптимізації програми.
Можливість заміни абстрактних структур даних у разі
побудови реалізації початкового алгоритму зумовлена тим, іцо
відношення на множині елементарних об'єктів, задане АСД, у
20 1. Б А Г А Т О Р І В Н Е В Е В І Д О Б Р А Ж Е Н Н Я Д А Н И X
більшості випадків може бути зображене також іншими формальними
символьними конструкціями, а алгоритмічні дії над початковою АСД
можуть виражатися у термінах операцій над цими конструкціями
Наприклад, множини можна задати лінійними масивами, логічними
шкалами, таблицями, деревами. Розріджені масиви зображаюті.
таблицями, ключі яких формують з індексів позицій ненульових
елементів масиву. Таблиці та масиви можна зображати деревами,
дерева - рядками. Дерева довільної структури можна привести до
двійково-пошукового виду. Графи можна подавати у матричній і
множинній формах, з використанням некореневих дерев, а також за
допомогою рядків. У результаті вибору найефективнішого зображення
з можливих форм логічного задания АСД і розробки процедурної
реалізації алгоритму стосовно вибраного представлення, абстрактний
опис алгоритму конкретизується і перетворюється у конструктивно
задану процедуру.
Концепція типу
Найпростіше поняття, яке часто застосовують у мовах
гіроірамування, - це понятгя типу. Основні принципи концепції типу
такі [1]:
1) довільний тип даних визначає множину значень, до яких
може відноситись константа і яке може приймати змінна (чи вираз),
або виробляти операція (чи функція);
2) тип довільної величини може бути визначений за її виглядом
або описом;
3) кожна операція або функція вимагає аргументів певного типу
і дає результат також фіксованого типу.
Поняття тину даних відіграє важливу роль у мовах
програмування високого рівня. Тип можна визначити шляхом
задання множини значень даних, які належать до цього типу, та
операцій, визначених над елементами цієї множини.
Типом даних називають іноді метод інтерпретації бітової
комбінації, використовуваної для зображення даних. Та сама
послідовність 0 і 1 може розглядатись як число, символ або масив
логічних значень. Наприклад, послідовність 01000001 може
інтерпретуватись як ціле число (41) 16 , символ A (ASCII- код) або
логічний масив зі значеннями: хибне, істинне, хибне, хибне, хибне,
хибне, хибне, істинне.
Система команд конкретної ЕОМ уміє інтерпретувати
послідовності бітів. Таку інтерпретацію називають стандартними
простими типами. Можна вважати, що ці тини вбудовані в ЕОМ.
Найпоширеніші вбудовані типи:
логічний (boolean);
символьний (character);
]4 2. СТРУКТУРИ ЗБЕРІГАННЯ ДАІIIIX
цілий (integer);
дійсний (real).
Набір таких тииів даних, підтримуваних комп'ютерам,
визначають функції, закладені в його апаратну частину.
Традиційно використовувані в універсальних монах
програмування типи даних повинні задовольняти дві основні вимоги:
1) опис об'єктів реального світу з використанням засобів мони
програмування повинен бути, по можливості, простим для розуміння і
при цьому невеликим за обсягом;
2) реалізація мови програмування повинна забезпечувати
високу ефективність роботи існуючих комп'ютерів.
Основні типи даних можна класифікувати так:
1) прості типи;
2) структуровані типи;
3) тип посилання.
Прості типи даних не володіють внутрішньою структурою.
Набір цих типів скінченний. їх називають примітивними, елемен-
тарними чи базовими.
До простих типів, крім вбудованих, відносять також переліче-
ний тип. Вбудовані типи можна поділити на два класи: арифметичні
та рядкові. Елементи арифметичних тинів мають своїм значенням
числа і можуть бути використані в арифметичних операціях. Рядкові
елементи мають за значення послідовності символів деякого алфавіту.
Структуровані типи даних призначені для задання складних
структур даних. їх конструюють зі складових елементів, названих
компонентами, які можуть володіти структурою. Основою конструю-
вання є визначені правила (операції) конструювання (конструктори
типів).
Тип посилання призначено для забезпечення можливості
зазначити інші дані. Цей тип є засобом організації обробки складних
зв'язаних структур даних. Його називають вказівником.
Квантування пам'яті
Для опису різновидів СЗД зручно користуватися поняттям квант
пам'яті. Квант пам'яті - це сукупність сусідніх одиниць пам'яті, вміст
яких інтерпретується як єдине ціле, наприклад, як двійковий код для
зображення символу, число з фіксованою чи плаваючою крапкою,
адреса, елемент даних разом з його дескриптором, який описує,
15
наприклад, розмір елемента. Тоді внутрішню структуру агрегатів
пам'яті можна буде описувати не в термінах одиниць пам'яті базового
рівня, а враховуючи об'єкти вищого рівня — кванти пам'яті, які
містять елементи даних або вказівники зв'язку.
Адресація одиниць пам'яті визначає її структуру і доступ до неї.
Використання адреси кванта пам'яті (адреси його першої одиниці) дає
змогу реалізувати прямий доступ до пам'яті. Якщо задано адресу, то
можна додавати до неї деяке фіксоване число, яке залежить від
розміру кванта, тобто користуватися послідовним доступом до
пам'яті. Довільний доступ не вводить жодних структурних зв'язків
між квантами, а послідовний доступ накладає на пам'ять лінійну
структуру. Якщо сусідні кванти об'єднано у сукупність, то адресу
сукупності називають базовою, а адресу кванта щодо початку
сукупності - зміщенням,і тоді
адреса кванта = база + зміщення.
Спискові структури
Об'єднання квантів, розташованих по базовій пам'яті довільно,
за допомогою посилань від одного кванта до іншого, приводить до
агрегатів пам'яті зв'язного типу - спискових структур.
Спискова структура - це сукупність взаємозв'язаних ланок,
кожна з яких складається з двох полів: поля даних та поля зв'язку.
У полі зв'язку містяться адреси ланок, які визначають операцію
прямування на структурі. ГІоле даних призначено для збереження
елементів інформації або вказівника на інформацію.
Зв'язані структури класифікують за кількістю елементів у полі
зв'язку та за напрямом зв'язку. Іноді ще використовують фіксатори-
вказівники на певні ланки структури, які дають змогу реалізувати
прямий доступ до цих ланок. За кількістю елементів у полі зв'язку
спискові структури можна поділити на одноелементні та
багатоелем ентні.
Спискові структури 17
Одноелементні списки інакше називають лінійними або
ланцюговими. їх характеризує наявність єдиного зв'язку — з
наступною ланкою. Схематично ланцюгові списки зображають так:
Рис. 5
За напрямом зв'язків спискові структури поділяють на дві
групи: однонаправлсні та двонаправлені.
Лінійний список є прикладом однонаправленого списку. У
кожній ланці є явна вказівка на наступника. Якщо додати до кожної
ланки посилання на попередника, то одержимо найпростіший випадок
двонаправленого списку (див. рис. 6).
Початок
списку
20 2. СТРУКТУРИ ЗБЕРІГАННЯ ДАНИХ
Основною перевагою двонаправлених списків є можливість
переміщатись по них в обох напрямах.
Можливі варіанти організації багатозв'язних двонаправлених
списків. Структури даних, які розміщені в таких списках, іноді
називають плексами.
Важливим елементом спискової структури є вказівник початку
списку. У ролі такого вказівника може буги використана окрема ланка,
яку називають початковою. Крім посилання на перший елемент,
початкова ланка може містити адресу початку вільної пам'яті,
потрібної під час роботи зі списками.
У зв'язаних аїрегатах вказівники використовують не лише для
забезпечення доступу до пам'яті, але й для з'єднання пов'язаних за
змістом елементів даних. Вони допомагають організувати зв'язки
різного характеру між одними і тими ж елементами даних.
Вказівники надають пам'яті гнучкості, необхідної для
зображення та складної логічної обробки комбінаторних об'єктів.
Розсіяні структури
Третій тип структур зберігання даних - розсіяні структури -
виникає у результаті використання спеціальних механізмів розташу-
вання квантів у базовій пам'яті. Зазвичай це пов'язано з моделю-
ванням асоціативної пам'яті, яка на відміну від традиційної, адресу-
ється не за фізичним розташуванням даних, а за вмістом ключового
поля даних. Ключ, як послідовність бітів, інтерпретують не лише як
частину елемента даних, а й як число, над яким виконують
арифметичні дії, зазначені у функції розстановки (її називають також
функцією хешування, розсіювання, адресною функцією). У результаті
обчислень визначають відносну позицію елемента з заданим ключем у
блоці пам'яті, відведеному під агрегат, забезпечуючи швидкий пошук
даних із заданим вмістом.
Функція розстановки може бути задана таблицею, яка ставить у
відповідність ключам даних фізичні адреси. Організацію асоціативної
пам'яті за допомогою функції розстановки широко використовують у
трансляторах, системах інформаційного пошуку, банках даних.
До розсіяного збереження призводить також організація пам'яті
з використанням адресної арифметики. У такому випадку довільні
відношення, які можна зобразити у цілочисловій арифметиці,
Розсіяні структури 21
розуміють як відношення між позиціями квантів, які розставлені
відповідно до цих відношеннь. Такий спосіб особливо зручний для
збереження комбінаторних об'єктів регулярної структури.
Принципи послідовного, зв'язаного і розсіяного зберігання
даних можуть використовуватися разом, утворюючи структури
зберігання даних гібридного типу.
3. АБСТРАКТНІ СТРУКТУРИ ДАНИХ ТА ЇХНЄ
ЗОБРАЖЕННЯ СТРУКТУРАМИ ЗБЕРІГАННЯ ДАНИХ
Абстрактні структури даних - це організовані певним чином
сукупності даних. Кожну структуру визначають правила і обмеження,
за якими визначено зв'язки між різними частинами даних.
Важливим понятгям для визначення прямого доступу до
окремих елементів даних є поняття індексації.
Множину X називають індексованою, якщо задане її
відображення у натуральний ряд чисел, тобто
Значення
(властивості ідентифікатора)
Рис. 11
Основна операція в таблиці - пошук. Вона полягає в тому, щоб
за заданим ключем визначити адресу зберігання запису, якщо він є.
Важливо вибрати таку організацію, яка допускала б ефективний
пошук. Для оцінки цієї операції в термінах очікуваного числа
порівнянь важливим є коефіцієнт заповнення таблиці lf=n/N, де n -
Відображення масивів у структури зберігання 33
Рис. 15
Впорядкована таблиця може бути одержана з невпорядкованої
за допомогою будь-якого алгоритму сортування після її остаточного
заповнення. Впорядкування таблиці вимагає додаткових затрат часу,
тому впорядковані використовуються як постійні таблиці, наприклад,
у трансляторах. Можливий варіант побудови впорядкованої таблиці,
коли записи додають у табли-
цю в певному порядку, але це
вимагає додаткових затрат.
Ще один спосіб пред-
ставлення таблиці в пам'яті - у
вигляді дерева. Це різновид
спискового представлення.
Кожний елемент таблиці, орга-
нізованої у вигляді двійкового
дерева, супроводжується двома
Рис. 16
вказівниками на записи відпо-
35
5. ТАБЛИЦІ
Рис. 14
Пошук може бути ефективнішим, якщо таблиця впорядкована.
Якщо елементами таблиці є рядки літер, то найприроднішим є
лексикографічний порядок. Ефективним методом пошуку у
впорядкованих таблицях є двійковий пошук. Суть такого пошуку -
символ S, який треба знайти, порівнюють з елементом, що має
номер (n+1)/2 і розташований у середині таблиці. Якщо цей елемент
не є шуканим, то треба переглянути лише блок від 1 до (n+1)/2-1
або від (n+1)/2+1 до n, залежно від того чи елемент S менший чи
більший від елемента, з яким його порівнювали. Потім цей процес
продовжують, але кожен раз над блоком меншого розміру. Оскільки
число елементів для кожного перегляду скорочується наполовину, то
максимальне число порівнянь 1 + log 2 n.
1
Таблиці з прямим доступом 37
Оцінюючи складність доступу до окремого запису у таблиці, як
необхідну для цього кількість порівнянь, для таблиць з
обчислюваними входами ми отримаємо метод з мінімальною
складністю, яка дорівнює 1. Звичайно, треба затратити деякий час на
обчислення адресної функції, але для простих функцій доступ до
таблиці з обчислюваними входами має значну перевагу за часом.
Мірою використання пам'яті у таких таблицях є коефіцієнт
заповнення If, який визначають як відношення кількості записів п до
числа місць у таблиці N.
Перемішані таблиці
Природним розвитком таблиць з прямим доступом є таблиці,
обчислення адреси для яких відбувається не в повному проміжку від 0
1. Викликаючи програму, прийняти, що цілочислова змінна R
дорівнює 1.
2. Обчислювати кожне pj так:
а) визначити R =R*5;
б) виділити молодші q+2 розряди R і помістити результат у R;
в) взяти величину з R, зсунути її праворуч на 2 розряди і
результат назвати р j.
Важлива властивість цього методу, який попереджає
згромадження елементів в одній частині таблиці, полягає в тому, що
всі числа від pj до pj+q різні. (1/lf) * ln (1/(1-lf)(1/lf) )
Очікувану кількість порівнянь дає формула: Е = (l/lf)*ln(l-lf).
Рехешування іноді називають відкритою адресацією.
Розглянемо приклад побудови таблиці, в яку заноситимемо
прізвища студентів групи з 25 осіб. За хеш-функцію візьмемо
порядковий номер в алфавіті першої букви прізвища. Це дасть змогу
побудувати таблицю з 33 елементів (за кількістю букв в алфавіті). Для
розв'язання колізії скористаємось випадковим рехешуванням,
оскільки величина таблиці є степенем числа 2 (N = 33; q = 5).
Таблиця складатиметься з двох частин: таблиці означень (в яку
заноситимемо посилання на відповідні імена) та таблиці імен. У
таблиці імен будуть знаходитись ключі (імена) і значення, які
міститимуть деяку додаткову інформацію, пов'язану з відповідним
іменем. Для посилання на таблицю імен будуть використані значення
індексів з цієї таблиці.
Нехай треба помістити в таблицю такі прізвища:
Будна
Тройська
Годій
Гойцак
Гупаловська
38 5. ТАБЛИЦІ
до N-1, а в деякому обмеженому діапазоні. Цей метод відомий як
метод перемішаних адрес, або перемішаної пам'яті.
У простій таблиці з прямим доступом є N можливих ключів і
для кожного з них можна згенерувати унікальну адресу з діапазону від
0 до N-1. Якщо насправді є лише К ключів і K<<N, то не
використовується великий обсяг пам'яті. У такому випадку треба
обчислювати адресу в меншому діапазоні, наприклад, від 0 до р-1,
де К< р<<N. Це означає, що різні ключі можуть привести до однієї і
тієї ж адреси. Такий випадок називають колізією. Для розв'язання
колізії є два способи: рехешування та метод ланцюжків (або
використання області переповнення).
Суть рехешування. Нехай обчислено значення хеш-функції
для ключа S і це значення - h. При спробі занести елемент з цим
ключем у таблицю виявляється, що інший елемент зайняв місце за
адресою h. Тоді порівнюємо S з елементом поля (h + р1) mod N (де N
- довжина таблиці) для деякого значення р{. Якщо знову виникає
колізія, то порівнюємо S з елементом (h + р 2 ) mod N. Цей процес
продовжують доти, доки не буде знайдено деякий елемент
(h + pj) mod N, який або порожній, або містить S, або знову є
елементом h. В останньому випадку робота алгоритму припиняється,
оскільки таблиця повна.
Отже, якщо виникло і колізій, буде виконано j+1 порівняння з
елементами h j = ( h + p j ) m o d N . Величину p j треба вибирати так,
щоб очікуване число порівнянь Е було невеликим і щоб можна було
розглянути якнайбільше елементів. В ідеальному випадку pj повинні
охоплювати цілі числа 0,1,...,N-1.
Рехешування зазвичай пов'язують з терміном розсіяної
пам'яті, оскільки заповнені позиції виявляються розсіяними по всій
таблиці.
Тип рехешування визначається тим, як вибирають значення
Рi . Найпоширенішими є:
40 5. ТАБЛИЦІ
Дзіковська
Ці прізвища разом з інформацією, яку ми не описуватимемо,
будуть у таблиці імен, а в таблицю означень буде занесено вказівки па
них.
Для кожного імені, яке заносимо в таблицю, обчислюємо хеш-
функцію та (у разі потреби усунення колізії) значення р j .
Обчислимо хеш-функцію для першого прізвища:
h(Будна) = 2. Оскільки таблиця порожня, то з занесенням у неї
цього елемента немає жодних проблем.
Так само без проблем буде занесено у таблицю і друге прізвище,
бо h(Гронська) = 4.
Таблиця означень
0 12 24
1 13 25
2 100 14 26
3 300 15 27
4 150 16 28
5 200 17 29
6 350 18 30
7 19 31
8 20
9 21
10 250 22
11 23
Таблиця імен
Рис. 16
Формальні граматики
Доволі часто буває ситуація, коли інтсрсс викликають не всі
рядки, одержані із заданого алфавіту, а лише певна їх підмножина.
Таку иідмножину називають мовою : L с V* . Рядки, які належать
мові, називають реченнями. Речення будують на основі правил
граматики. Ці ж правила слугують для розпізнавання належності
певного рядка деякій мові.
Граматикою G називають четвірку (Vn, Vt, S, Р), де Vn -
алфавіт нетермінальних символів; Vt - алфавіт термінальних символів
(таких, які трапляються лише у правій частині правил); S - почат-
ковий символ (аксіома граматики); Р - система правил вигляду U :: =
х, де U - негермінальний символ, х - рядок з (Vn U Vt)* . Ці правила
іноді називають правилами підстановки.
Наприклад, розглянемо граматику для побудови цілих чисел
без знака.
L
7. ДИНАМІЧНІ СТРУКТУРИ
Є три динамічні структури - стеки, черги та деки. Особливістю
всіх динамічних структур є те, що елементи перебувають у них до
першого звертання. Додавання і видалення елементів відбувається не в
довільному місці структури, а в місці, яке визначається власне
структурою даних. Будь-яке звертання до такої структури змінює її
вміст.
Стеки
Однією з найважливіших динамічних структур є стек (stack).
Стек - це впорядкована, лінійна, динамічно змінювана
послідовність елементів, для якої виконуються такі умови:
1) новий елемент приєднується завжди до одного і того ж
краю послідовності;
2) доступ до елементів відбувається завжди з того краю
послідовності, до якого елементи приєднуються;
3) елемент зберігається в послідовності до моменту його
виклику.
Стек називають також послідовністю типу LIFO (last in first out).
Схематично стек можна зобоазити так:
Рис. 17 Рис. 18
Черги
Черга (queue) - це лінійна динамічно змінювана послідовність
елементів, для якої виконуються такі умови:
1) новий елемент приєднується завжди до одного і того ж
краю послідовності;
2) доступ до елементів, тобто їх вилучення, відбувається
завжди з іншого краю послідовності.
Місце вилучення називають головою черги, а місце включення
— хвостом.
Отже, у структурі черги потрібні два вказівники: один -
посилання на голову послідовності для вилучення елементів, а другий
— посилання на хвіст для включення елементів у чергу. Завжди при
читанні з черги вилучається найстаріший елемент.
Чергу також називають послідовністю типу FIFO (first in first
out).
Крім класичних черг, які ще називають лінійними, черги
бувають з пріоритетом та циклічні [8].
Прикладом лінійної черги є черга завдань в операційній системі,
коли кожне чергове завдання опрацьовується лише після того, як
опрацьовано поточне.
Чергу, для якої є можливість включати або вилучати елементи з
певної позиції залежно від деяких їхніх характеристик (таких,
наприклад, як пріоритет задачі), називають пріоритетною чергою.
Прикладом пріоритетної черги може бути порядок розв'язування задач
з потоку у деяких операційних системах.
Така черга зводиться до послідовності лінійних черг. Кожна така
черга складається з елементів з однаковим пріоритетом. Елементи з
черги з нижчим пріоритетом опрацьовують лише тоді, коли черги з
вищим пріоритетом порожні. Наприклад, нехай є потік завдань з
різними пріоритетами;
Ідентифікатор завдання
Пріоритет
Вилучення елемента з
черги передбачає зміну верши-
ни і приєднання вилученого
елемента до списку вільної
нам'яті. Схематично цю опера-
цію можна зобразити так
(див. рис. ЗО).
Деки
Дек - це впорядкована, лінійна, динамічно змінювана послідов-
ість елементів, для якої виконуються такі умови:
1) новий елемент може приєднуватись до будь-якого краю
послідовності;
2) вибір елемента теж може відбуватись з будь-якого краю
послідовності.
Схематично дек можна зобразити так:
68 8. СПИСКИ
Деки - це структури, які володіють більшою загальністю, ніж
стеки чи черги. їх часом називають чергами з двома кінцями, у яких
включення та вилучення відбувається з двох країв. У чистому вигляді
деки використовують у теоретичних дослідженнях. На практиці
використовують деки з обмеженнями.
Дек з обмеженим виходом. Це дек, у якому доступ (вилучення)
відбувається лише з одного кінця, а занесення елементів - з двох.
Наприклад, дек з правим виходом можна зобразити так:
Основні визначення
Поняття дерева (tree) виводять з теорії графів, але воно отримало
широке застосування в інформатиці. Тому в літературі [2, 6]
трапляється два визначення дерева:
1) на основі теорії графів: дерево - це зв'язний ациклічний граф;
2) рекурсивне: дерево - це скінчена множина Т, яка складається
з одного чи більше вузлів таких, що
• є один спеціальний вузол, який називають коренем
даного дерева;
• решта вузлів входять до складу m>0 множин T 1 ,...,T m ,
які попарно не перетинаються і кожна з яких сама є деревом
(T 1 ,--T m , називають піддеревами).
Рекурсивність є природною характеристикою деревовидних
структур і суттєво використовується у багатьох алгоритмах обробки
дерев.
Визначення дерева як ациклічного графа є загальнішим і в [6]
таке дерево названо вільним. Якщо ациклічний граф орієнтований і в
ньому виділено один спеціальний вузол, названий коренем, то дерево
називають кореневим. Визначення кореневого дерева еквівалентне
рекурсивному визначенню дерева.
Основні визначення 77
Кореневе орієнтоване дерево позначимо так: G=<A, Г> , де
А={а0,а],...,ап} - множина вузлів, Г- відношення підпорядко-
ваності на А, яке задає топологію дерева.
Дерево повинно мати принаймні одну вершину. Ізольована
вершина також дерево.
Є декілька способів зображення дерев [2, 6], але найчастіше
використовують графічне. Приклад такого зображення подано на
рис. 37.
Визначимо основні поняття, які використовують під час обробки
деревовидних структур.
З теорії графів використано поняття вузла та ребра. Вузол, у
який не входить жодне ребро, називають коренем (на рис. 37 - це
вузол а). Вузли, з яких не виходять ребра, називають термінальними
вузлами, або листками (на рис. 37 термінальними є вузли d. e.f, і, И).
Вузли, які не є термінальними, називають нетермінальними, або
внутрішніми.
Вузол у, який знахо-
диться безпосередньо під
вузлом х, називається без-
посереднім нащадком х; х
називається безпосереднім
предком у. Безпосередніх
нащадків вузла х називають
його синами, а сам вузол
називають батьківським. На
рис. 37 с, d, е — сини вузла Ь,
a f - батько вузла g. Ця
термінологія взята з генеало-
гічних дерев.
Довжина шляху між вузлами визначається кількістю ребер між
цими вузлами. Довжина шляху від кореня до деякого вузла
називається рівнем цього вузла. Рівень кореня дорівнює 0 (іноді
корінь вважається вузлом рівня 1, а рівень кожного вузла визначається
як довжина шляху, збільшена на 1). Максимальний рівень дерева
називається його висотою (висота дерева на рис/ 37 дорівнює 3).
Часом розглядається параметр дерева, який називається довжиною
шляху дерева, і визначається як сума довжин шляхів до всіх його
вузлів від кореня. Його часом називають довжиною внутрішнього
9. Д Е Р Е В О В И Д Н І С Т Р У К Т У Р И
шляху. Наприклад, довжина внутрішнього шляху дерева на рис. 37
дорівнює 16.
Важливою характеристикою кожного вузла є кількість його
безпосередніх нащадків, яка називається степенем виходу вузла. Всі
термінальні вузли мають степінь виходу, рівний 0. Степінь виходу
вузла b на рис. 37 дорівнює 3. Максимальний степінь всіх вузлів є
степенем дерева.
Кожний вузол дерева задає піддерево, утворене всіма вузлами,
які можуть бути досягнуті із нього. Отже, кожне дерево - це система
вкладених одне в одне піддерев. Така властивість дерев відображає
їхній рекурсивний характер.
Якщо з дерева видалити корінь і ребра, які з'єднують його з
вузлами першого рівня, то отримаємо деяку множину незв'язаних
дерев, яка називається лісом. Оскільки кожен вузол визначає
піддерево, то можна вважати, що піддерева, розташовані під вузлом,
утворюють ліс.
Дерево називається впорядкованим, якщо має значення
відносний порядок його піддерев. Наприклад, на рис. 38 подано два
різні впорядковані дерева.
Якщо R - відношення
порядку на множині вузлів, то
трійку D=<A,Г,R> називають
впорядкованим деревом. Одному
дереву G відповідає деякий клас
еквівалентних йому впорядкова-
них лепен
Окремий важливий клас складають двійково-пошукові
(двійкові) дерева. Ці дерева визначають так: з кожного вузла виходить
не більше двох гілок, і кожна гілка ідентифікується як ліва або як
права. Приклад двійково-пошукового дерева наведено на рис. 39.
Прямий обхід.
Опрацювання кореневого вузла.
Прямий обхід лівого піддерева.
Прямий обхід правого піддерева.
Для дерева на рис. 43 прямий обхід дасть таку послідовність вузлів:
abcdefgh.
Зворотний обхід.
Зворотний обхід лівого піддерева.
Опрацювання кореневого вузла.
Зворотний обхід правого піддерева.
Для дерева на рис. 43 прямий обхід дасть таку послідовність вузлів:
с b d е a g f h.
Симетричний обхід.
Симетричний обхід лівого піддерева.
Симетричний обхід правого піддерева.
Опрацювання кореня.
Для дерева на рис. 43 прямий обхід дасть таку послідовність вузлів: с е
d b g h f a.
Крім цих обходів можна визначити ще порівневі та
правосторонні обходи.
Пропоновані обходи можна узагальнити на дерева довільної
структури [1].
Нехай дерево Гскладається з кореня R та піддерев T1,T2,...,Tn,
як показано на рис. 44.
82 9. Д Е Р Е В О В И Д Н І С Т Р У К Т У Р И
Зображення виразів
Будь-які вирази у дужковому записі - це лінеаризовані
ієрархічні структури, причому лінеаризація відбувається унаслідок
використання дужок, які дають змогу вказати пріоритет, тобто
визначити ієрархію операцій. Якщо ж не проводити лінеаризацію, а
зображати вираз безпосередньо як ієрархічну структуру, то для цього
використовують дерева.
Дерево складових
У лінгвістиці для опису будови синтаксичної структури
речення використовують дерева. При цьому в реченні виділяють
складові частини — групи слів, які функціонують як цілісні
синтаксичні одиниці. Наприклад, у реченні „Реве та стогне Дніпр
широкий" (Т. Г. Шевченко) складовими будуть: все речення Р, кожне
його окреме слово та групи слів А = Реве та стогне; Б = та стогне; П =
Дніпр широкий. Дерево для цього речення подано на рис. 61.
94 9. Д Е Р Е В О В И Д Н І С Т Р У К Т У Р И
Таблиці рішень
Ці таблиці показують як умови зв'язані з діями. Детально
використання дерев для зображення таблиць рішень подано у [19].
Дерева сортувань
Як попередньо було показано, дерева можуть бути використані
для впорядкування масиву елементів за деякою ознакою, якщо поряд з
поступанням нових елементів використовують уже впорядковану
частину масиву, і подальшого пошуку деякого елемента у цьому
масиві.
Традиційно використовувані методи сортування приводять у
такому випадку до малоефективних алгоритмів, оскільки вимагають
для свого використання або взаємного переміщення елементів у
пам'яті, або неоднократного проходження впорядкованої частини
масиву, що займає значний час. Дерева сортувань дають змогу
визначити місцеположення нових елементів майже так само швидко,
як у впорядкованому послідовному масиві. Це позбавляє від
необхідності переміщати елементи, щоб звільнити місце для
розташування нових. Пошук при вже відсортованих елементах
виконується швидше, ніж у невпорядкованому масиві.
Нехай задано масив елементів, для яких визначено операцію
порівняння. Побудова дерева сортування може бути подана таким
алгоритмом (враховуючи те, що для зображення дерева буде
використано двозв'язний список):
Застосування д е р е в о в и д н и х структур 95
1. Перший елемент масиву занести в корінь дерева
(сформувати ланку з першим значенням і двома порожніми
вказівниками та встановити на неї вказівник дерева).
2. Кожний наступний елемент порівнювати з елементом у
вузлі. Якщо новий елемент має менше значення, то іти по
лівому піддереву, інакше по правому. Рух по дереву
здійснювати доти, поки не стане можливим приєднати новий
вузол (посилання відповідного напрямку - порожнє).
3. Для всіх елементів масиву повторити п. 2.
Нехай потрібно сформувати дерево сортування для масиву з
таких значень: 12, 8, 15, 14, 6, 7, 3, 17. Воно матиме вигляд (див. рис.
62):
Збалансовані дерева
Висота гілки дерева - це число вузлів, розташованих між
коренем і листком, включаючи і ці вузли. Висота дерева -
максимальна з висот його гілок.
Інтуїтивно зрозуміло, що якщо всі гілки дерева мають
приблизно однакову висоту, то пошук в середньому проходить
швидше, ніж у дереві з тими ж записами, але суттєво різними по
висоті гілками.
Якщо в дереві є 2n — 1 вузлів, то можна сформувати дерево, в
якому кожна гілка має висоту h. Наприклад, якщо n=15, то можна
сформувати дерево, кожна гілка якого має висоту 4. Якщо ж n=14, то
одна гілка буде висоти 3.
За оптимальне визначають дерево, гілки якого мають висоту від
h до h - 1. Оптимальне дерево вимагає багато зусиль для побудови і
супроводження.
Компромісним рішенням цієї проблеми є збалансоване дерево.
Задавши дерево, виберемо довільний з його вузлів. Цей вузол
визначає два піддерева. Висота кожного з них не повинна відрізнятись
більше ніж на 1. В такому випадку отримаємо збалансоване дерево.
Отже, бінарне дерево називається збалансованим за висотою,
якщо для кожного вузла висота піддерева з більшими ключами
відрізняється від висоти піддерева з меншими ключами не більше ніж
на 1 (приклад такого дерева на рис. 69).
Такі дерева дозволяють встановити прийнятну верхню границю
довжини пошуку, обмежену значенням log2 n.
Якщо дерево формується із записів, які поступають у випадковій
послідовності, воно переважно не буде збалансованим. Проте, в
середньому дерево буде близьким до збалансованого. Тому виникає
потреба перебудови дерева до збалансованого.
Поняття збалансованого дерева може бути поширене на дерева
довільної арності. В такому дереві кожний вузол мас однакову
кількість гілок, причому процес включення нових гілок у вузли йде
зверху вниз, а на кожному рівні — зліва направо (див. рис. 70).
Дерево називається ідеально збалансованим, якщо для кожного
його вузла кількість вузлів лівому і правому піддереві
відрізняються не більше ніж на 1 ( див. рис. 71).
Процедура включення, яка
відновлює ідеальну збалансова-
ність структури дерева, навряд чи
буде вигідною, оскільки таке
відновлення після випадкового
включення - доволі складна
операція. Але її можна спростити,
якщо дати менш строге визначення
"збалансованості". Такий недо-
сконалий критерій збалансованості
може вимагати простої перебудови
дерева при невеликому зменшенні
середньої швидкодії пошуку. Таке визначення дали Адельсон -
Вельский та Ландис, тому дерева називають АВЛ - деревами.
102 9. Д Е Р Е В О В И Д Н І С Т Р У К Т У Р И
Алгоритм побудови ідеально збалансованого дерева
""Припустимо, що треба сформувати дерево, яке містить вузли з
числовими значеннями, які будуть прочитані з вхідного файла. Будемо
будувати дерево з п вузлами і мінімальною висотою.
Щоб досягти мінімальної висоти при заданій кількості вузлів,
треба розташувати максимально можливу кількість вузлів на всіх
рівнях, крім найнижчого. Це можна зробити дуже просто, якщо
розподіляти всі вузли, які надходять, порівну ліворуч та праворуч від
кожного вузла. В результаті побудоване дерево при даному п має
вигляд, поданий на рис.72.
Рис. 72
Правило рівномірного розподілу при відомій кількості вузлів п
найкпаїпе формулюється за допомогою рекурсії:
1. Взяти один вузол за корінь.
2. Побудувати ліве піддерево з nl = n div 2 вузлами тим самим
способом.
3. Побудувати праве піддерево з nr = n div г вузлами тим самим
способом.
Бінарні дерева часто використовуються для зображення
множини даних, елементи яких шукаються за унікальним ключем.
Якщо дерево організовано таким чином, що для кожного вузла t i всі
Частосування деревовидних структур ЮЗ
ключі в лівому піддереві менші від ключа tj, а ключі в правому
піддереві більші від ключа t i , то це дерево називають деревом пошуку.
У дереві пошуку можна знайти місце кожного ключа. Якщо дерево
ідеально збалансоване, то для пошуку серед п елементів може бути
потрібно не більше log2n порівнянь. Пошук у такому випадку
проходить по єдиному шляху від кореня до шуканого вузла.
АВЛ дерева
Дерево називається збалансованим по висоті (ЛВЛ-деревом)
тоді і лише тоді, коли для кожного вузла висота його двох піддерев
відрізняється не більше ніж на 1.
Критерій їх збалансованості виявляється найкращим для
реалізації операцій сортування та пошуку інформації. Варто
відзначити, що всі ідеально збалансовані дерева є також ABJI-
деревами.
Це визначення не лише просте, але також приводить до легко
виконуваного балансування, а середня довжина пошуку залишається
практично такою ж, як в ідеально збалансованого дерева.
Зі збалансованими деревами можна виконувати наступні
операції за 0(log 2 n) одиниць часу, навіть у найгіршому випадку:
- знайти вузол із заданим значенням;
- включити вузол із заданим значенням;
- видалити вузол із заданим значенням.
Це є прямим наслідком теореми, доведеної Адельсоном —
Вельским і Ландісом, яка стверджує, що збалансоване дерево ніколи
не буде більше ніж на 45% вище від відповідного ідеального
збалансованого дерева, незалежно від кількості вузлів.
Якщо позначити висоту збалансованого дерева з п вузлами через
hB(n), то справедливе співвідношення:
Розглянемо включення у
дерево, зображене на рис. 74, вузлів зі
значеннями 1, 3, 5 або 7. Кожне таке
включення вимагає балансування.
Існує лише дві суттєво різні
можливості, які вимагають індивіду-
ального підходу. Інші можуть бути
отримані симетричними перетворен-
нями цих двох.
Випадок 1 виникає при вклю-
ченні вузлів зі значенням 1 або 3.
Вони будуть п о є д н у в а т и с ь до вузла зі
значенням 2 і при цьому буде
106 9. Д Е Р Е В О В И Д Н І С Т Р У К Т У Р И
порушено баланс. Такий випадок вимагає перебалансу вання
обертанням, у якому задіяно два вузли (однократне обертання). На
рис. 77 показано як виглядає дерево до балансування і після
перебалансування.
Випадок 2 виникає при включенні вузлів зі значенням 5 або 7.
Вони будуть під'єднуватись до вузла зі значенням 6 і при цьому також
буде порушено баланс. При перебалансуванні буде задіяно три вузли
(двократне обертання). На рис. 78 показано як виглядає дерево до
балансування і після такого перебалансування.
В обох випадках перекреслені квадрати позначають під'єднаний
вузол.
іастосунання деревовидних структур 107
Прості перетворення цих двох структур відновлюють потрібний
баланс. Відзначимо, що допускаються переміщення лише у
вертикальному напрямку, в той час як відносне горизонтальне
розташування показаних вузлів і піддерев повинне залишатись без
змін.
Алгоритм включення і балансування повністю визначається
способом зберігання інформації про збалансованість дерева. Одне з
вирішень цієї проблеми полягає у зберіганні цієї інформації повністю
у самій структурі дерева. Але в цьому випадку включення торкається
показника збалансованості вузла, що призводить до надзвичайно
високих затрат. Інший варіант - зберігати показник збалансованості
разом з інформацією, пов'язаною з кожним вузлом. Показник
збалансованості можна інтерпретувати як різницю між висотами
правого та лівого піддерева hR - hL. Тоді у кожному вузлі можна
тримати, наприклад, інформацію такого виду: bal: -1..1;
Алгоритм включення:
1. Переміщатись шляхом пошуку, доки не з'ясують, що ключа, який
передбачають включити, немає в дереві.
2. Включити новий вузол і визначити новий показник
збалансованості.
3. Пройти назад шляхом пошуку і перевірити показник
збалансованості для кожного вузла.
Очікувана висота AVL-збалансованого дерева рівна
h = log(n) + с, де с - мала константа (с = 0,25). Це означає, що на
практиці AVL-збалансовані дерева ведуть себе як ідеально
збалансовані дерева, хоча з ними простіше працювати.
Балансування в середньому відбувається приблизно один раз на
два включення. Причому однократне і двократне обертання рівно
можливі.
Через складність операцій балансування вважається, що
збалансовані дерева слід використовувати лише у тому випадку, коли
пошук інформації відбувається частіше, ніж включення.
Основні поняття
Визначення. Графом G = (V, Е) називають сукупність двох
множин: скінченої непорожньої множини V вершин (vertex) і
скінченої множини Е ребер (edge), які з'єднують пари вершин. Ребра
зображаються невиорядкованими парами вершин (u,v).
Основні поняття 113
Граф зручно зображати діаграмами (кресленнями), причому
один і той самий граф можна зобразити по-різному. На діаграмах
першини зображають точками, а ребра - відрізками прямих чи кривих.
Алгоритми побудови креслень, які дотримуються різних
природних обмежень, інтенсивно досліджували, що привело до
цікавих застосувань. Одним з найпростіших обмежень є вимога того,
щоб ребра не перетинались. Планарний граф ( planar graph) належить
до тих, які можна побудувати без перетину ребер.
Значення 0 - це значення,
яке не позначає ваги, а вказує на
нідсугність дуги між вершинами.
На рис. 96 зображено
навантажений орієнтований іраф
(навантаження виділено).
Матриця суміжності у
цьому випадку виглядатиме гак:
122 11. ГРАФИ
- 1 2 3 4 5
1 0 0 10 0 0
2 10 0 0 0 20
3 0 15 0 0 0
4 0 0 0 0 20
5 0 0 0 0 0
Застосування графів
Графи є найзагальнішими структурами даних, які слугують
моделями багатьох реальних задач. Під час розв'язання багатьох
задач, які стосуються графів, доводиться систематично обходити
вершини або ребра (чи дуги в орографах). Для цього використовують
алгоритми, які називають пошуком у глибину та пошуком у ширину.
Пошук у глибину є узагальненням методу обходу дерева в
прямому порядку. Передбачають, що спочатку всі вершини графа
відмічені як невідвідані. Пошук у глибину починається з вибору деякої
Застосування графів 127
початкової вершини v, яка помічається як відвідана. Потім для кожної
вершини, суміжної з вершиною, яку не відвідували раніше,
рекурсивно застосовується пошук у глибину. Коли всі вершини,
досяжні з v, будуть відвідані, пошук закінчується. Якщо деякі
вершини залишились не відвіданими, то вибирається одна з них і
пошук повторюється. Пошук продовжується доти, доки обходом не
будуть охоплені всі вершини графа. Цей метод називається пошуком у
глибину, оскільки пошук невідвіданих вершин іде у глибину доти,
доки це можливо. Для повернення використовують стек.
Пошук у ширину називається так через те, що при досягненні
під час обходу довільної вершини v далі розглядаються всі вершини,
суміжні з v, тобто відбувається перегляд вершин „у ширину". Так
само, як при застосуванні пошуку у глибину, за допомогою пошуку у
ширину створюється каркасний ліс. При цьому відвідані вершини
поміщають у чергу.
До типових алгоритмів над графами відносять також алгоритми
пошуку шляхів, зокрема, алгоритм Дейкстри пошуку найкоротшого
шляху між двома заданими вершинами та алгоритм Флойда, пошуку
па графі найкоротшого шляху між кожною парою вершин, алгоритм
подвійного пошуку, який знаходить k перших найкоротших шляхів з
деякої вершини до всіх інших вершин початкового графа.
Алгоритми Пріма та Краскала є прикладами алгоритмів
пошуку каркасний дерев у графі.
Для моделювання задачі, яка передбачає пересилання деяких
об'єктів з одного пункту в інший, використовують потоки. Стосовно
графів потік задає спосіб пересилання деяких об'єктів (одиниць
потоку) з однієї вершини (графа) в іншу (стік) по ребрах (або дугах)
графа. Задача про максимальний потік полягає у пошуку способу
пересилання максимальної кількості одиниць потоку з джерела у стік
за умови відсутності перевищення пропускних можливостей ребер
(дуг) початкового графа. Узагальненням алгоритму розв'язку цієї
задачі є алгоритм пошуку потоку мінімальної вартості. Крім цих,
існують інші потокові алгоритми.
Окремий набір становлять алгоритми пошуку паросполук та
покриттів. Паросполукою графа називають деяку множину його ребер
(дуг), таку, що кожна вершина графа інцидентна не більше ніж одному
ребру цієї множини.
128 11. ГРАФИ
Покриттям графа називають деяку множину ребер (дуг) таку,
що кожна вершина графа інцидентна принаймні одному ребру цієї
множини.
Очевидно, що довільна підмножина паросполук графа є також
паросполукою, а довільна множина ребер, яка містить як підмножину
покриття графа, є покриттям цього графа.
Існує кілька типів поширених задач про покриття та
паросполуки, зокрема, про покриття максимальної чи мінімальної
потужності, про покриття з мінімальною вагою, про паросполуку з
максимальною вагою.
Деякі задачі зводяться до пошуку ейлерового (задача листоноші)
чи гамільтонового (задача комівояжера) циклів у графі.
У посібник не входить розгляд цих алгоритмів, а їхній опис
можна знайти у [1,2, 4, 9, 11, 12, 13, 16, 18].
Як приклад використання розглянемо аспект, який розглядають
значно рідше, а саме, графи як моделі програм, даних та процесів. Ці
питання розглядаються, зокрема, у роботі [4]. Багато задач аналізу
програм, які виникають під час оптимізації, трансляції, верифікації,
тестування значно спрощуються, якщо їх розглядати на теоретичних
графових моделях.
Рис. 109
Список літератури
1. Ахо А., Хопкрофт Дж., Ульман Д. Структуры данных и
алгоритмы. М.: Вильяме, 2000.
2. Вирт Н. Алгоритмы + структуры данных = программы. М.: Мир,
1985 (1988).
3. ГрисД. Построение компиляторов для ЦВМ. М.: Мир, 1972.
4. Евстигнеев В.А. Применение теории графов в программировании.
М.:Наука, 1985.
5. Кнут Д. Искусство программирования. Т. 1: Основные алгоритмы.
М.: Мир, 1976.
6. Кнут Д. Искусство программирования. Т.З: Сортировка и поиск.
М.: Мир, 1978.
7. Кожевникова Г.П. Структуры данных и проектирование
эффективной вычислительной среды. Львов: Вища шк., 1986.
8. Кормен Т., Лейзер Ч., Ривест Р. Алгоритмы: построение и анализ.
М.,МЦНМО, 1999.
9. Костив О. В. Разработка и исследование оценочных базисов
прикладного сложностного анализа вычислений над деревьями:
Дисс. ... канд. физ.-мат. наук. Львов, 1985.
10. Кравець В.Л. Вступ до структур даних. К.: УМК ВО, 1989.
11. Кристофидес Н. Теория графом. Алгоритмический подход. М.:
Мир, 1978.
12. ЛипскийВ. Комбинаторика для программистов. М.: Мир, 1988.
13. Майника Э. Алгоритмы оптимизации на сетях и графах. М.: Мир,
1981.
14. Нагао М., Катаяма Т., Уэмура С. Структуры и базы данных. М.:
Мир, 1986.
15. Притула М.М., Щербина Ю.М. Алгоритми дискретної математики
та обчислювальна складність: Навч. посібн. Львів: Видавничий
центр ЛНУ ім. Івана Франка, 2002.
16. Проценко В.С.,Чаленко П.Й.,Ставровський Ф.Б. Техніка
програмування мовою Сі. К.: Либідь, 1993.
142 СПИСОК ЛІТЕРАТУРИ
17. Седжвик Р. Фундаментальные алгоритмы на С++. Ч. 5. Алгорит-
мы на графах. К.: Diasoft, 2002.
18. Седжвик Р. Фундаментальные алгоритмы на С++. 4.1-4. К.:
Diasoft, 2002.
19. Трамбле Ж., Соренсон П. Введение в структуры данных. М.:
Машиностроение, 1982.
20. Холл П. Вычислительные структуры. Введение в нечисленное
программирование. М.: Мир, 1978.
21. Цегелик Г.Г. Методы автоматической обработки информации.
Львов: Высшая шк., 1981.
143
ЗМІСТ
Вступ З
1. Багаторівневе відображення даних 6
Змістовний рівень опису даних 6
Абстрактний рівень опису даних 8
Декларований рівень даних 10
Базовий рівень даних 11
Агрегований рівень даних 12
2. Структури зберігання даних 13
Концепція типу 13
Квантування нам'яті 14
Послідовні структури зберігання 15
Спискові структури 16
Розсіяні структури 20
3. Абстрактні структури даних та їхнє зображення структурами
зберігання даних 22
4. Масиви 24
Відображення масивів у структури зберігання 26
5. Таблиці А 30
Таблиці з обчислювальними входами 36
Таблиці з прямим доступом 37
Перемішані таблиці 37
Функція розстановки (функція хешування) 43
6. Рядки : 47
Нормальні алгоритми Маркова 48
Формальні граматики 50
Операції над рядками 51
Відображення рядків у структури зберігання 52
7. Динамічні структури 56
Стеки 56
Відображення стеків у структури зберігання 60
Черги 62
Відображення черг у структури зберігання 64
Деки 67
8. Списки 69
Відображення списків у структури зберігання 71
9. Деревовидні структури і 76
Основні визначення 76
Базові оператори над деревами 83
Відображення дерев у структури зберігання 85
Послідовні структури 85
Спискові структури зберігання 88
Застосування деревовидних структур 91
Дерева сортувань 94
10. Сіткові структури 109
11. Графи 112
Основні понятгя 112
Відображення графів у структури зберігання 118
12. Множини 138
Список літератури 141
Н а в ч а л ь н е в и д а н н я
Костів Оксана
СТРУКТУРИ ДАНИХ
для студентів
факультету прикладної математики та інформатики
Редактор М. Михалюк
Корект ор В. Станкевич-Іванова
Технічний редактор С. Сеник