Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
АМ_4_LR_5.doc
Скачиваний:
11
Добавлен:
23.08.2019
Размер:
188.42 Кб
Скачать

Міністерство освіти і науки, молоді та спорту України

Прикарпатський національний університет

імені Василя Стефаника

Кафедра радіофізики і електроніки

Лабораторна робота №4

з дисципліни

"Алгоритми та методи обчислень"

бінарні Дерева

Івано-Франківськ – 2011

Мета роботи:

- оволодіти навичками роботи з бінарними деревами;

- оволодіти навичками доступу до даних і роботи з пам'яттю в бінарних деревах;

- оволодіти навичками вирішення завдання з використанням алгоритмів обходу бінарних дерев.

Теоретичні відомості

Ключові терміни:

дерево - це структура даних, що представляє собою сукупність елементів і відносин, які утворюють ієрархічну структуру цих елементів.

піддерево - це частина деревоподібної структури даних, що може бути представлена у вигляді окремого дерева;

бінарне (двійкове) дерево - це дерево, у якому кожна вершина має не більше двох нащадків;

повне бінарне дерево - це дерево, що містить тільки повністю заповнені рівні;

корінь дерева - це початковий вузол дерева, йому відповідає нульовий рівень;

вершина (вузол) дерева - це кожний елемент дерева;

гілка дерева - це спрямовані дуги, якими з'єднані вершини дерева;

листи дерева - це вершини, у які входить одна гілка і не виходить ні однієї гілки;

висота (глибина) дерева - це кількість рівнів, на яких розташовуються його вершини;

неповне бінарне дерево - це дерево, рівні якого заповнені не повністю;

нестроге бінарне дерево - це дерево, у якого вершини мають ступінь нуль (у листів), один або два (у вузлів);

обхід дерева - це впорядкована послідовність вершин дерева, у якій кожна вершина зустрічається тільки один раз;

предок - це вершина, з якої виходять гілки до вершин наступного рівня;

нащадки - це всі вершини, у які входять гілки, що виходять із однієї загальної вершини;

ступінь дерева - це максимальний ступінь вершин, що входять у дерево;

ступінь вершини - це кількість дуг, що виходить із цієї вершини;

рівень вершини - це кількість дуг від кореня дерева до вершини.

строге бінарне дерево - це дерево, у якого вершини мають ступінь нуль (у листів) або два (у вузлів);

майже збалансоване дерево - це дерево, у якого довжини всіляких шляхів від кореня до зовнішніх вершин відрізняються не більш, ніж на одиницю;

збалансоване дерево - це дерево, у якого довжини всіх шляхів від кореня до зовнішніх вершин рівні між собою;

впорядковане дерево - це дерево, у якого гілки, що виходять із кожної вершини, впорядковані за певним критерієм;

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

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

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

Кожне дерево має наступні властивості:

- існує вузол, у який не входить ні однієї дуги (корінь);

- у кожну вершину, крім кореня, входить одна дуга.

Дерева особливо часто використовують на практиці при зображенні різних ієрархій. Наприклад, популярні генеалогічні дерева.

Рисунок 1.  Дерево

Всі вершини, у які входять гілки, що виходять із однієї загальної вершини, називаються нащадками, а сама вершина - предком. Рівень нащадка на одиницю перевершує рівень його предка. Корінь дерева не має предка, а листя дерева не мають нащадків.

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

Піддерево - частина деревоподібної структури даних, що може бути представлена у вигляді окремого дерева.

Ступенем вершини в дереві називається кількість дуг, що з її виходить. Ступінь дерева дорівнює максимальному ступеню вершин, що входять у дерево. При цьому листами в дереві є вершини, що мають ступінь нуль. За величиною ступеня дерева розрізняють два типи дерев:

- двійкові - ступінь дерева не більше двох;

- такі, що сильно гілкуються - ступінь дерева довільна.

Впорядковане дерево - це дерево, у якого гілки, що виходять із кожної вершини, впорядковані за певним критерієм.

Дерева є рекурсивними структурами, тому що кожне піддерево також є деревом. Таким чином, дерево можна визначити як рекурсивну структуру, у якій кожний елемент є:

- або порожньою структурою;

- або елементом, з яким зв'язане кінцеве число піддерев.

Дії з рекурсивними структурами зручніше за все описуються за допомогою рекурсивних алгоритмів.

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

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

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

При обході всі вершини дерева повинні відвідуватися в певному порядку. Існує кілька способів обходу всіх вершин дерева. Виділимо три найбільш часто використовуваних способи обходу дерева (рис. 2):

- прямій;

- зворотний;

- симетричний.

Рисунок 2.  Обходи дерев

Існує велике різноманіття деревоподібних структур даних. Виділимо найпоширеніші з них: бінарні (двійкові) дерева, червоно-чорні дерева, В-дерева, АВЛ-дерева, матричні дерева, змішані дерева і т.д.

Бінарні дерева є деревами зі ступенем не більше двох.

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

Рисунок 3.  Бінарне дерево і його організація

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

- інформаційне поле (ключ вершини);

- службове поле (їх може бути декілька або жодного );

- вказівник на ліве піддерево;

- вказівник на праве піддерево.

За ступенем вершин бінарні дерева діляться на (рис. 4):

Рисунок 4.  Вигляд бінарних дерев за ступенем вершин

- строгі - вершини дерева мають ступінь нуль (у листів) або два (у вузлів);

- нестрогі - вершини дерева мають ступінь нуль (у листів), один або два (у вузлів).

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

Дерево називається збалансованим, якщо довжини всіх шляхів від кореня до зовнішніх вершин рівні між собою. Дерево називається майже збалансованим, якщо довжини всіляких шляхів від кореня до зовнішніх вершин відрізняються не більш, ніж на одиницю.

Бінарне дерево може являти собою порожню множину. Бінарне дерево може виродитися у список (рис. 5).

Рисунок 5.  Список як окремий випадок бінарного дерева

Структура дерева відбивається у вхідному потоці даних так: кожному порожньому зв'язку, що вводиться, відповідає умовний символ, наприклад, '*' (зірочка). При цьому спочатку описуються ліві нащадки, потім, праві. Для структури бінарного дерева, представленого на наступному рисунку 6, вхідний потік має вигляд: ABD*G***CE**FH**J**.

Рисунок 6.  Адресація у бінарному дереві

Бінарні дерева можуть застосовуватися для пошуку даних у спеціально побудованих деревах (бази даних), сортуванні даних, обчислення арифметичних виразів, кодування (метод Хаффмана) і т.д.

Опис бінарного дерева виглядає в такий спосіб:

struct имя_типа {

інформаційне поле;

[службове поле;]

адреса лівого поддерева;

адреса правого поддерева;

};

де

- інформаційне поле - це поле кожного раніше оголошеного або стандартного типу;

- адреса лівого (правого) піддерева - це вказівник на об'єкт того ж типу, що і обумовлена структура, у нього записується адреса наступного елемента лівого (правого) піддерева.

Наприклад:

struct point {

int data;// інформаційне поле

int count; // службове поле

point *left;// адреса лівого піддерева

point *right;// адреса правого піддерева

};

Основними операціями, що здійснюються з бінарними деревами, є:

- створення бінарного дерева;

- друк бінарного дерева;

- обхід бінарного дерева;

- вставка елемента в бінарне дерево;

- видалення елемента з бінарного дерева;

- перевірка чи порожнє бінарне дерево;

- вилучення бінарного дерева.

Для опису алгоритмів цих основних операцій використовується наступне оголошення:

struct BinaryTree{

int Data; //поле даних

BinaryTree* Left; // вказівник на лівий нащадок

BinaryTree* Right; / вказівник на правий нащадок

};

. . . . . . . . . .

BinaryTree* BTree = NULL;

Методичні вказівки

В даній роботі пропонується написати програму обраною мовою програмування, у якій сформувати бінарне дерево відповідно до завдання на основі базових алгоритмів: створення, друк, обхід бінарного дерева, вставка та вилучення елемента в бінарне дерево, перевірка чи порожнє бінарне дерево, вилучення бінарного дерева;

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

При написанні програми виконуйте коментування коду.

Література

1. Ахо А., Хопкрофт Дж., Ульман Дж. Структуры данных и алгоритмы. – М.: Издательский дом “Вильямс”, 2001. – 384 с.

2. Вирт Н. Структуры данных и алгоритмы. С примерами на Паскале. Издание 2. – СПб.: Невский диалект, 2008. – 352 с.

3. Кнут Д. Искусство программирования для ЭВМ / В 3-х томах. – М.: “Мир”, 2008.

4. Новиков Ф. А. Дискретная математика для программистов. Учебник для вузов. 2-е изд. – СПб.: Питер, 2005. – 364 с.

Завдання

1. Вивчіть завдання, виділивши при цьому всі види даних;

2. Сформулюйте математичну постановку завдання;

3. Виберіть метод рішення завдання, якщо це необхідно;

4. Розробіть алгоритм рішення завдання;

5. Написати програму обраною мовою програмування;

6. Підготуйте тестові дані для перевірки різних режимів роботи програми;

7. Виконайте тестування програми;

8. Порівняйте отриманий результат з підготовленим для тестування;

9. Здійснити відлагодження програми;

10. Підготуйте звіт.

Вимоги до звіту

Звіт до лабораторної роботи повинен відповідати наступній структурі:

- титульний лист.

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

- математична модель. У цьому підрозділі вводяться математичні описи даних і математичний опис їхньої взаємодій. Ціль підрозділу - подати розв'язуване завдання у математичному формулюванні.

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

- лістинг програми. Підрозділ повинен містити текст програми обраною мовою програмування.

- контрольний тест. Підрозділ містить набори вихідних даних і отримані в ході виконання програми результати.

- висновки по лабораторній роботі.

- відповіді на контрольні питання.

Приклад виконання роботи

Приведемо функції перерахованих основних операцій при роботі з бінарним деревом.

// створення бінарного дерева

void Make_Binary_Tree(BinaryTree** Node, int n){

BinaryTree** ptr;// допоміжний вказівник

srand(time(NULL)*1000);

while (n > 0) {

ptr = Node;

while (*ptr != NULL) {

if ((double) rand()/RAND_MAX < 0.5)

ptr = &((*ptr)->Left);

else ptr = &((*ptr)->Right);

}

(*ptr) = new BinaryTree();

cout << "Введіть значення ";

cin >> (*ptr)->Data;

n--;

}

}

//друк бінарного дерева

void Print_BinaryTree(BinaryTree* Node, int l){

int i;

if (Node != NULL) {

Print_BinaryTree(Node->Right, l+1);

for (i=0; i< l; i++) cout << " ";

printf ("%4ld", Node->Data);

Print_BinaryTree(Node->Left, l+1);

}

else cout << endl;

}

//прямий обхід бінарного дерева

void PreOrder_BinaryTree(BinaryTree* Node){

if (Node != NULL) {

printf ("%3ld",Node->Data);

PreOrder_BinaryTree(Node->Left);

PreOrder_BinaryTree(Node->Right);

}

}

// зворотний обхід бінарного дерева

void PostOrder_BinaryTree(BinaryTree* Node){

if (Node != NULL) {

PostOrder_BinaryTree(Node->Left);

PostOrder_BinaryTree(Node->Right);

printf ("%3ld",Node->Data);

}

}

// симетричний обхід бінарного дерева

void SymmetricOrder_BinaryTree(BinaryTree* Node){

if (Node != NULL) {

PostOrder_BinaryTree(Node->Left);

printf ("%3ld",Node->Data);

PostOrder_BinaryTree(Node->Right);

}

}

// вставка вершини в бінарне дерево

void Insert_Node_BinaryTree(BinaryTree** Node,int Data) {

BinaryTree* New_Node = new BinaryTree;

New_Node->Data = Data;

New_Node->Left = NULL;

New_Node->Right = NULL;

BinaryTree** ptr = Node;// допоміжний вказівник

srand(time(NULL)*1000);

while (*ptr != NULL) {

double q = (double) rand()/RAND_MAX;

if ( q < 1/3.0) ptr = &((*ptr)->Left);

else if ( q > 2/3.0) ptr = &((*ptr)->Right);

else break;

}

if (*ptr != NULL) {

if ( (double) rand()/RAND_MAX < 0.5 )

New_Node->Left = *ptr;

else New_Node->Right = *ptr;

*ptr = New_Node;

}

else{

*ptr = New_Node;

}

}

// вилучення вершини з бінарного дерева

void Delete_Node_BinaryTree(BinaryTree** Node,int Data){

if ( (*Node) != NULL ){

if ((*Node)->Data == Data){

BinaryTree* ptr = (*Node);

if ( (*Node)->Left == NULL && (*Node)->Right == NULL ) (*Node) = NULL;

else if ((*Node)->Left == NULL) (*Node) = ptr->Right;

else if ((*Node)->Right == NULL) (*Node) = ptr->Left;

else {

(*Node) = ptr->Right;

BinaryTree ** ptr1;

ptr1 = Node;

while (*ptr1 != NULL)

ptr1 = &((*ptr1)->Left);

(*ptr1) = ptr->Left;

}

delete(ptr);

Delete_Node_BinaryTree(Node,Data);

}

else {

Delete_Node_BinaryTree(&((*Node)->Left),Data);

Delete_Node_BinaryTree(&((*Node)->Right),Data);

}

}

}

// перевірка чи порожнє бінарне дерево

bool Empty_BinaryTree(BinaryTree* Node){

return ( Node == NULL ? true : false );

}

// звільнення пам'яті, виділеної під бінарне дерево

void Delete_BinaryTree(BinaryTree* Node){

if (Node != NULL) {

Delete_BinaryTree(Node->Left);

Delete_BinaryTree(Node->Right);

delete(Node);

}

}

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]