Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Р3.doc
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
1.71 Mб
Скачать

3 Побудова алгоритмів

3.1 Алгоритми для роботи з множинами

У цілого ряду додатків використовується така структура даних: елементів розбиті на непусті множини, що не перетинаються.

Система множин, що не перетинаються це набір непустих множин, що не пересікаються, і у кожному із яких зафіксований один із елементів – представник. Точніше, елементи множини є об’єктами і робота з ними здійснюється за допомогою покажчика. При цьому повинні підтримуватись такі процедури.

«Створити множину» (MakeSet) Процедура створює нову множину, у якій елемент задається за допомогою вказівника . Оскільки множини не повинні перетинаються, вимагається, щоб вказував на новий елемент, що не лежить ні в одному із уже створених множин.

«Знайти множину» (FindSet). Повертає вказівник на представника множини, що вміщує елемент, на який вказує .

«Об’єднання» (Union). Процедура тоді може бути застосована, якщо елементи і належать до двох різних множин і , і замінюють ці дві множини на одну ; при цьому вибирається деякий представник для елементу множини . Самі множини і вилучаються.

У певних випадках вибір представника повинен підкорятись деяким правилам, наприклад, елементи можуть бути упорядковані і представником є найменший елемент множини. У будь-якому випадку суттєвим є те, що вказівник залишається незмінним до тиго часу, поки сама множина не змінюється.

Приклад 3.1. Алгоритм ConnectedComponents (зв’язані компоненти), що наведений нижче, розбиває множину вершин графа на множини, що не пересікаються, і які відповідають зв’язаним компонентам; після цього за допомогою процедури SameComponent можна з’ясувати чи містяться дві дані вершини в одній компоненті.

Позначимо через і множину вершин і ребер графа .

ConnectedComponents

1 for (для) кожної вершини

2 MakeSet(w)

3 end for

4 for (для) кожного ребра

5 if

6 then Union(v,w)

7 end if

8 end for

SameComponent

1 if

2 then return true

3 else return false

4 end if

Алгоритм ConnectedComponents працює таким чином (рис. 3.1) Спочатку кожна вершина розглядається як одноелементна підмножина. Потім для кожного ребра графа об’єднуємо підмножини, у які попали кінці цього ребра. Коли всі ребра опрацьовані, множина вершин розбита на зв’язані компоненти.

На рис 3.1,а показаний граф, що складається із чотирьох зв’язаних компонент: , , та . У процесі роботи алгоритму стан системи множин, що не перетинаються послідовно змінюється і на останньому кроці алгоритм формує чотири зв’язані компоненти (рис. 3.1,б).

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

Ребро, що опрацьовується

Множини, що не перетинаються

початок

б)

a)

Рисунок 3.1 – Процес опрацювання множин вершин графа

Виконуючи операцію об’єднання (Union(x,y)) додаємо список, що вміщує до кінця списку, що вміщує . Тепер представником нового списку буде його початок, тобто представник списку, що вміщує . При цьому виникає необхідність у правильній установці вказівників на початок списку для всіх колишніх елементів множини, що вміщувала . Час на виконання цієї операції лінійно залежить від розміру вказаної множини.

Рисунок 3.2 – Схема ідентифікації списків за допомогою функції розстановки

Припустимо, що список складається із елементів , , …, . Виконаємо операції MakeSet(xi)для всіх , а потім операцій Union(x1,x2), Union(x2,x3), …,

Union(xn-1,xn). марна вартість операції Union(xі,xі+1) пропорційна , то сумарна вартість виконання операцій буде

.

Використовуючи формулу суми членів арифметичної прогресії , де - перший член прогресії; - різниця прогресії, і враховуючи те, що , і , знайдемо

,

тобто

.

Описаний вище спосіб реалізації процедури Union вимагає порядку операцій. Алгоритм Union можна покращити, якщо до довшого списку долучати коротший. Такий прийом називається ваговою евристикою. Якщо списки, що об’єднуються вміщують приблизно рівну кількість елементів, то великого виграшу не буде, але у протилежному випадку економія може бути відчутною.

Якщо довжина більшого списку , а довжина меншого , то загальне число операцій з об’єднання двох списків буде .

Приклад 3.2. Нехай задано два списки і , які вміщують певні числові величини. Необхідно їх об’єднати в один, використавши прийом вагової евристики. Алгоритм Union у псевдокоді буде мати такий вигляд:

Union(А,В)

1 n1=length(A) Кількість елементів у списку А

2 n2=length(B) Кількість елементів у списку В

Першим у загальному списку буде довший список

3 n=max(n1,n2)

4 if n1>n2

5 then C=A

6 D=B

7 else C=B

8 D=A

9 end if

10 k=1

11 for i=n+1 to n1+n2

12 C(i)=D(k)

13 k=k+1

14 end for