Відображення АСД на СДХ. h2>
Наше завдання: p>
1.Найті відображення АСД
-> СДХ; p>
2.Оценіть складність
алгоритмів операцій вставки, заміни, пошуку і
видалення при різних способах відображеннях. p>
1. Відображення на вектор. H2>
Будемо припускати що ми
маємо справу з несортованими структурами. Детально що означає умова
сортування ми розглянемо в розділі IV "Сортування." p>
1.1. Рядок h2>
Відображення рядка на
вектор будується так: p>
1. Візьмемо антітранзітіное відношення R 'таке що його Транзитивне
замикання дає R (для цього достатньо розглянути відношення лінійного порядку
R без умови 2 - умови транзитивності: p>
якщо (a, b) і (b, c)
належать R, то (a, c) теж належить R; p>
Ясно що R 'задає відношення сусідства, тобто (a, b) принале. R '
якщо і тільки якщо p>
Не істот. c: c принале.
M, (a, c) прінадл.R 'і (c, b) прінадл.R' p>
2.Возьмем мінімальний елемент у рядку (він існує в силу
властивості відношення лінійного порядку R), і нехай це a; p>
3.Елементи a зіставимо перший компонент вектора: I (a) = 1; p>
4.Паре (b, c) прінадл.R 'зіставимо I (c) = I (b) 1. p>
В одному векторі можна
зберігати декілька рядків. Для цього існує два принципово різних способи:
рядки розділяються спеціальним ознакою - ознакою кінця, якого немає серед
символів строк; інший спосіб - на початку кожного рядка вказується її довжина. p>
Останній спосіб
краще коли ми маємо справу з рядками змінної довжини, а першу
хороший коли рядки фіксованої довжини. p>
Розглянемо складність операцій пошуку, вставки, видалення і заміни.
Операції вставки, видалення і заміни містять операцію пошуку як складову
частину. p>
Припускаємо що частота
зустрічальності всіх елементів у рядку одна й та ж. Тоді в середньому (коли ми
маємо справу з безліччю рядків, а не з однією, двома) нам доведеться просомтреть
половину рядки, щоб знайти потрібний символ:
(1/N) + (1/N) 2 + (1/N) 3 +...+( 1/N) N = (N +1)/2 = ~ N/2 p>
Звідси випливає складність пошуку (кількість операцій порівняння)
пропорційна половині довжини рядка. p>
Для операції вставки
складність проворціональна довжині рядка. Дійсно, нам треба N/2 порівнянь,
щоб знайти місце для вставки, а потім N/2 зрушень вправо, щоб звільнити
місце для нового елемента. p>
Складність операції
видалення дорівнює складності операції вставки. Міркування тут аналогічно
попереднім. p>
Неважко підрахувати
складність операції заміни - N/2 1. p>
Основний висновок полягає в тому, що при відображенні рядка на вектор
всі операції з рядком мають лінійну складність, пропорційну довжині
рядка. p>
1.2. Граф (дерево) h2>
Відображення графа на
вектор будується через метріцу суміжності або матрицю інцідентностей. У Pascal,
де є двовимірні масиви таке подання графа очевидно. (Див.
подання лабіринту в задачі про Аріадні і Тезея.) При відображенні на вектор
можливо два підходи: відображення по рядках або по стовпцях. p>
Тут ми розглянемо випадок
відображення по рядках. Випадок відображення по стовпцях повністю аналогічний.
При відображенні за рядками елементу матриці A [i, j] зіставляється елемент
вектора V [k], де p>
k = (i-1) n + j, де n --
довжина рядка. p>
Тепер оцінимо складність операції пошуку. Нам доведеться переглянути
в середньому половину рядків - N/2, і половину елементів у кожному рядку - N/2 при
умови, що часто зустрічальності всіх елементів однакова. Таким чином складність
операції пошуку пропорційна N ^ 2/4 або N ^ 2 при великих N. p>
Однак при оперції
видалення нам не треба зрушувати всі елементи як у випадку з рядком. Однак,
операція вставки трубет зміни розмірності матриці суміжності по кожному
вимірюванню з N на N +1. Для цього нам доведеться виконати (N +1) операцій
привласнення, щоб заповнити новий рядок у векторі, плюс N 1 зрушень рядків,
щоб додати до кожної старої рядку по новому елементу, що відповідає N 1
колонку. Кількість операцій зсуву визначається таким співвідношенням: p>
p>
Таким чином складність операції вставки буде дорівнює p>
N ^ 2/4 + N ^ 3/2 = N ^ 2 (N +2)/2. p>
Слід звернути увагу що як і раніше значний внесок у
складність операцій з графами становить операція пошуку. p>
Для k-ічного дерева можна
запропонувати спеціальний спосіб відображення на вектор. Компоненту V [0]
співставляємо кореня дерева; компоненти V [1] ... V [k] співставляємо нащадкам кореня,
потім з V [k +1] з V [2k] розміщуємо нащадків V [1], з V [2k +1] - V [3k] - нащадків
V [2] і т.д. У загальному випадку нащадки i-ї вершини, розташованої на j ярусі,
буде розміщатися в компонентах вектора p>
з V [k (k ^ j -1)/(k-1) +
(i-1) k] компоненту p>
з V [k (k ^ j -1)/(k-1) + ik]
компонент. p>
Оцінимо складність операції пошуку при такому відображенні дерева на
вектор. Враховуючи, що висота k-ічного дерева з N вершин дорівнює p>
H = log (N (k-1) +1) - 1 ~ log (k) N p>
отримуємо що кількість листя в такому дереві ~ N ^ 2. Звідси, при
умови равновстречаемості елементів у лісі, нам треба переглянути в середньому
половину шляхів (їх число дорівнює чмслу листя в дереві) довжини H кожен. Ці
міркування дають нам величину p>
~ Nlog (k) N. p>
Порівнюючи цю оцінку з попередньою для векторного представлення
графа N, можна побачити що це подання багато ефективніше. p>
1.3. Стек h2>
Оскільки стек є мо
суті одиничне дерево всі операції з якими здійснюються через корінь,
то відображення на стека на вектор цілком зрозуміло. З вектором свзиваем
вказівник p, який вказує на той компонент вектора, де в даний момент
розміщується корінь дерева. Спочатку p = 0. Операція вставки суть
p: = p +1; V [p]: =. Операція видалення: p: = p-1. P>
Найважливіший висновок полягає
в тому, що операції над стеком при векторному поданні не залежать від довжини
стека. p>
1.4. Черга h2>
Для векторного
подання черги нам будуть потрібні дві покажчика t і h для хвоста і голови
черзі відповідно. Нагадаємо, що видалення елемента з черги можливо
тільки з голови черги, а вставка - тільки з хвоста. p>
Одне з можливих відображень
черги на вектор полягає в тому, що вважаємо спочатку h: = N; t: = N. Тоді
вилучення елемента - h: = h-1; а вставка - t: = t-1.
Таке відображення володіє тим недоліком, що якщо загальне число
елементів, які пройшли через чергу - M>> N, за умови, що довжина черги
не більше N, то після вставки N елементів ми вичерпаємо довжину вектора в покажчику
t. p>
Можна модифіковані цей метод - зафіксувати положення
покажчика h: = N. Тоді при вилученні елемента з черги нам треба буде переміщувати
всі елементи на одиницю вправо і коректувати значення покажчика t. Чим
більше середня довжина черги, тим менш вигідно таке подання (довжина
зсуву збільшується). p>
Третій спосіб
подання черги через вектор полягає в тому, що ми "загинаємо"
вектор в кільце. Для цього достатньо виконувати всі операції в покажчиками по
модулю N. При такому поданні черги складність операцій вставки та вилучення
стають абсолютно не залежними від розміру черги. p>
1.5. Таблиці h2>
Відображення таблиць на
векторну пам'ять буде розглянуто пізніше в розділі "Таблиці". p>
Основним недоліком
векторного подання АСД - обмеженість довжини вектора. Її ми повинні знати
заздалегідь. Крім цього, як ми бачили досить часто нам доводиться рухати
компоненти вектора при вставці і видалення елементів у векторі. p>
2. Представлення АСД в списковому пам'яті h2>
2.1. Поняття списку h2>
Списком називається
безліч ланок виду p>
|------------------------------------| p>
| тіло ... | Вказівник на
ланка | p>
|------------------------------------| p>
ув'язаних в ланцюжок за допомогою покажчиків один на одного. p>
Поле тіло предназнаяено
для зберігання власне даних, поле покажчик на ланка - для посилання на
сусіднє ланка. В одній ланці може бути кілька полів покажчик на ланка.
Значення цього поля - посилання на ланка. P>
Кожне посилання відповідає
орієнтованої, впорядкованої парі щодо деякої структури даних.
Уздовж покажчика можна рухатися тільки в одному напрямку. P>
Ланки можна використовувати
як для представлення елементів безлічі структури, так і для представлення
елементів відносини. Ланки можна використовувати для нарощування довжини поля тіло,
для зв'язку ланок між собою. p>
Основний недолік списку
- Витрати пам'яті на зберігання покажчиків. Чим складніша структура - тим більше
покажчиків треба для її подання, тим більше пам'яті витрачається під
покажчики. p>
Основна перевага --
необмеженість за розміром, динамічність у керуванні й організації. p>
2.2. Представлення рядків h2>
Для подання рядків
можна використовувати ланки з наступними видами поля тіло: p>
- односімвольние ланки; p>
- многосімвольние ланки; p>
- ланки змінної довжини
(в Pascal де динамічні структури змінної довжини не підтримуються цього
виду ланки не ефективні); p>
По організації поля вказівник на інше ланка: p>
-односпрямовані; p>
-двонаправлені; p>
-мультіссилочние (коли
один елемент структури пов'язаний з декількома іншими елементами). p>
Зауважимо, що у разі
мультіссилочного ланки по деяких напрямках ми можемо мати двонаправлену
зв'язок між ланками, а за деякими - однонапрвленную. p>
2.3. Представлення графів h2>
При поданні графів можна використовувати кілька підходів: p>
- використовувати ланки
тільки для представлення вершин, а дуги відображати через покажчики; недоліком
тут є те, що ніде відобразити інформацію, наприклад, про вагу дуги, а
так само - у разі неорієнтованого графа одній дузі буде відповідати два
покажчика. p>
- використовувати ланки для
дуг, а вершини відображати як посилання між дугами інцідентнимі однієї і тієї ж
вершині; в цьому підході утруднене подання орінетірованних дуг, а так само
інфомація про вершини; p>
- нарешті можна ввести дві
виду ланок один для представлення дуг, інший для подання вершин;
ланки-дуги погоджуються в список, ланки-вершини також погоджуються в список з
перехресними посиланнями між списками. p>
Особливий випадок представляють
нерегулярні графи, тобто графи у яких ступінь вершин - величина змінна.
У цьому випадку використовуються спеціальні службові ланки з двох
полів-покажчиків. Одне поле служить для посилання на двругое аналогічне ланка, а
друге поле - для посилання на соотвествующий елемент структури. p>
2.4. Уявлення стека і черги h2>
Стек представляється
однонапрвленним списком з ланок, що складаються з двох полів: тіла та посилання.
Нижче наводяться процедури, що реалізують операції в завантаження і вивантаження з стека.
p>
type p>
ланка = record тіло: char; наступний: зв'язок end; p>
зв'язок = Iзвено; p>
var тіло: char; p>
стек: зв'язок; p>
procedure завантажити (тіло: char; var стек: зв'язок); p>
var елемент: зв'язок; p>
begin new (елемент); елементI.тело: = тіло; елементI.следующій: = стек; p>
стек: = елемент p>
end (завантажити) p>
procedure вивантажити (var тіло: char; var стек: зв'язок); p>
var спожитий: зв'язок; p>
begin ifnot (стек = nil) then p>
begin тіло
: = СтекI.тело; спожитий: = стек; p>
стек: = стекI.следующій;
dispose (використаний) end p>
else write ( 'стек порожній') p>
end (завантажити) p>
Зверніть увагу на значення оператора dispose. p>
Усі міркування про
поданні черги в списковому пам'яті аналогічні тим, що були приведені в
розділі векторного подання черги. Зауважимо що кільцеву чергу легше
організувати через список. черги. p>
Структури даних h2>
АСД (абстрактні структури даних) - математична структура, з
допомогою якої ми представляємо прикладні дані програми. p>
АЛГОРИТМ ------> МОВА ПРОГРАМУВАННЯ p>
У кожній мові програмування існує своя концепція даних. p>
Назвемо структури даних конкретного ЯП структурою даних зберігання
(СДХ). P>
ПРОБЛЕМА: як відобразити АСД алгоритму на СДХ ЯП? p>
Над "АСД
визначені деякі операції (видалити, замінити елемент і т.д.) p>
Критерієм вибору СДХ є складність. Слід вибирати як
можна більш прості СДХ. p>
ЗАВДАННЯ. Дано: АСД і
набір СДХ. p>
Потрібно: побудувати АСД -----> СДХ так, щоб складність
Пераціму з СДХ (аналогічних операцій з АСД) була мінімальною. p>
Визначення: стосовно порядку R на множині M називають
безліч пар, які мають такі властивості: p>
1) рефлексивність: (a, a)