С, С++

Інформація про навчальний заклад

ВУЗ:
Національний університет Львівська політехніка
Інститут:
Не вказано
Факультет:
КН
Кафедра:
Кафедра САПР

Інформація про роботу

Рік:
2011
Тип роботи:
Лабораторна робота
Предмет:
Алгоритмічні мови та програмування

Частина тексту файла (без зображень, графіків і формул):

МІНІСТЕРСТВО ОСВІТИ І НАУКИ, МОЛОДІ ТА СПОРТУ УКРАЇНИ НАЦІОНАЛЬНИЙ УНІВЕРСИТЕТ «ЛЬВІВСЬКА ПОЛІТЕХНІКА» Кафедра САПР Звіт до лабораторної роботи №13 на тему «ДЕРЕВА І ГРАФИ В МОВІ ПРОГРАМУВАННЯ С» з курсу «Проблемно-орієнтовані мови програмування» ЛЬВІВ 2011 Мета роботи Навчитися використовувати логічну структуру дерев для програмування задач з використанням графів. Теоретичні відомості Дерева являють собою найбільш важливі нелінійні структури, що зустрічаються в обчислювальних алгоритмах. Існує кілька класів дерев, серед яких особливою "популярністю" користуються бінарні (двійкові) дерева. Вони застосовуються у різноманітних алгоритмах (програмах): наприклад, деякі компілятори з мов високого рівня використовують їх для аналізу й обчислення арифметичних виразів. Ще однією причиною популярності бінарних дерев є простота їхньої організації. Дерево - це неорієнтований зв'язний граф без циклів. Визначимо формальне дерево як скінченну множину Т, яка складається з одного або більше вузлів, таких, що: є один позначений вузол, який називається коренем даного дерева; інші вузли (крім кореня) містяться в m >= 0 множинах Т1, Т2, ..., Тm, які попарно не перетинаються, і кожна з яких у свою чергу є деревом. Дерева Т1, Т2, ..., Тm називаються піддеревами даного дерева. Це визначення є рекурсивним, тобто воно визначає дерево в термінах самих же дерев. З нього слідує, що кожний вузол дерева є коренем деякого піддерева, що міститься в цьому дереві. Число таких піддерев у даному вузлі називають його ступенем. В бінарних деревах є також листя. Це вузли з нульовим степенем. Всі інші (некінцеві) вузли називають вузлами розгалуження. Корінь - це такий вузол, з якого йдуть зв'язки до всіх інших элементів дерева. Дерева на папері зображують так: спочатку малюють корінь, потім від нього малюють зв’язки до вузлів-нащадків, від них зв'язки до їхніх нащадків і т. д. Ще однією характеристикою дерева є його висота. Це шлях максимальної довжини від листка до кореня. У бінарному дереві кожний вузол має тільки два піддерева. У кожного вузла є ліве й праве піддерево. Вузол і його піддерева називають взагалі по-різному, наприклад: батько, син і брат; або: батько з "лівим" і "правим" синами. Більш формально бінарне дерево можна визначити як скінченну множину вузлів, яка або пуста, або складається з кореня з одним/двома бінарними деревами, що не перетинаються. На мові С вузол бінарного дерева можна описати у вигляді наступної структури: struct node { іnt key; // Ключ ... // Дані struct node *left; // Посилання на ліве пiддерево/вузол struct node *rіght; // Посилання на праве пiддерево/вузол }; Для обходу дерева використовують ключі. Ключ - спеціальна змінна, яка полегшує доступ до вузлів дерева. Звичайно, це ціле число, що зберігається в кожному вузлі дерева і задовольняює деяким умовам. Наприклад, таким: нехай всі ключі в лівому піддереві поточного вузла менші ключа в ньому, а всі ключі в правому піддереві - більші або рівні поточному. При роботі з бінарними деревами потрібно вміти додати, видалити, знайти в них вузол з необхідною інформацією, або створити довільне дерево. Однією з головних причин, що лежать в основі появи мов програмування високого рівня, є завдання, що вимагають великих обсягів обчислень. Тому до мов програмування ставляться вимоги максимального наближення форми запису обчислень до природної мови математики. У цьому зв'язку однією з перших областей системного програмування сформувалося дослідження способів трансляції виразів. Тут отримані численні результати, однак найбільше поширення одержав метод трансляції за допомогою зворотного польського запису, що запропонував польський математик Я. Лукашевич. Нехай задано простий арифметичний вираз: . (1) Представимо цей вираз у вигляді дерева, у якому вузлам відповідають операції, а листю - операнди. Побудову почнемо з кореня, у якості якого вибирається операція, що виконується останньою. Лівій вітці відповідає лівий операнд операції, а правій вітці - правий. Дерево виразу (1) показане на Рис. 6. Зробимо обхід дерева, під яким будемо розуміти формування рядка символів із символів вузлів і віток дерева. Обхід будемо робити від самої лівої вітки вправо й вузол переписувати у вихідний рядок тільки після розгляду всіх його віток. Результат обходу дерева має вигляд:  (2) Характерні риси виразу (2) полягають у проходженні символів операцій за символами операндів і у відсутності дужок. Такий запис називається зворотним польським записом. Рис. 6. Зворотний польський запис володіє рядом позитивних властивостей, які перетворюють його в ідеальну проміжну мову при трансляції. По-перше, обчислення виразу, записаного у зворотному польському записі, може проводитися шляхом однократного перегляду, що є досить зручним при генерації об'єктного коду програм. Нехай нам дана частина карти дорожньої мережі, і потрібно знайти найкращий маршрут від початкової вершини до кінцевої. Його можуть визначати багато факторів, такі, як відстань у кілометрах, час проходження маршруту з урахуванням обмеження швидкості, число міст, які необхідно відвідати з метою доставки вантажів. Існує безліч інших задач, які можна звести до відшукання найкоротшого шляху на мережі. Наприклад, знайти найменшу кількість часу, необхідну для будівництва будинку, або обчислити мінімальну вартість модернізації устаткування для підвищення продуктивності на якому-небудь підприємстві. Також можна виділити кілька типів задач про найкоротший шлях: 1. між двома заданими вершинами в мережі; 2. між даною вершиною й всіма іншими вершинами мережі; 3. між кожною парою вершин у мережі; 4. між двома заданими вершинами для шляхів, що проходять через задану вершину; 5. перший, другий, третій і так далі найкоротші шляхи в мережі. Рис. 7. Кожній дузі (х, у) вихідного графа G поставимо у відповідність число а(х, у) (Рис. 7). Якщо в графі G відсутня деяка дуга (х, у), покладемо а(х, у) рівним безмежності. Будемо називати число а(х, у) довжиною дуги (х, у), хоча а(х, у) може також інтерпретувати відповідні витрати й відповідний ваговий коефіцієнт. Визначимо довжину шляху як суму довжин окремих дуг, що становлять цей шлях. Для будь-яких двох вершин s і t графа G можуть існувати кілька шляхів, що з'єднують вершину s з вершиною t. Розглянемо алгоритм, що визначає шлях, що веде з вершини s у вершину t, і має мінімально можливу довжину. Цей шлях називається найкоротшим шляхом між вершинами s і t. Описаний далі алгоритм дозволяє знаходити в графі найкоротший шлях при додатних довжинах дуг і вважається одним з найбільш ефективних алгоритмів рішення задачі. Головна ідея полягає в послідовному визначенні найближчих до s вершин (тобто визначається 1- а найближча до s вершина, потім - 2- а, 3- я й так далі доти, поки наступна найближча вершина не виявиться вершиною t). Припустимо, що нам відомо m вершин, найближчих до вершини s (близькість будь-якої вершини х до вершини s визначається довжиною найкоротшого шляху, що веде з s у х). Нехай також відомі самі найкоротші шляхи, що з'єднують вершину s з виділеними m вершинами. Покажемо тепер, як може бути визначена (m+1)-a найближча до s вершина. Зафарбуємо (виділимо) вершину s і m найближчих до неї вершин. Побудуємо для кожної незафарбованої вершини y шляхи, що безпосередньо з'єднують за допомогою дуг (х, у) кожну зафарбовану вершину х з у. Виберемо із цих шляхів найкоротший і будемо вважати його умовно найкоротшим шляхом з вершини s у вершину у. Та вершина, для якої умовно найкоротший шлях має найменшу довжину, і буде (m+1)-ою найближчою до s вершиною. Починаючи з m =0, описана процедура повинна повторюватися доти, поки не буде отриманий найкоротший шлях, що веде з вершини s до вершини t. Тепер формально опишемо алгоритм Дейкстри: Крок 1. Перед початком виконання алгоритму всі вершини й дуги не зафарбовані. Кожній вершині в ході виконання алгоритму приписується число d(х), рівне довжині найкоротшого шляху з s в х, що включає тільки зафарбовані вершини. Покладемо d(s) = 0 і d(x) рівним безмежності для всіх х, відмінних від s. Зафарбуємо вершину s і покладемо y=s (y - остання з зафарбованих вершин). Крок 2. Для кожної незафарбованої вершини х у такий спосіб перерахуємо величину d(x): d(x) = mm{d(x), d(y) + a(x, y)}. (3) Якщо d(x) дорівнює безмежності, для всіх незафарбованих вершин х, закінчити процедуру алгоритму: у вхідному графі відсутні шляхи з вершини s у незабарвлені вершини. У протилежному випадку зафарбувати ту з вершин х, для якої величина d(x) є найменшою. Крім того, зафарбувати дугу, що веде в обрану на даному кроці вершину х (для цієї дуги досягався мінімум відповідно до виразу (3)). Покладаємо y= х. Крок 3. Якщо y = t, закінчити процедуру: найкоротший шлях з вершини s у вершину t знайдений (це єдиний шлях з s в t, складений із зафарбованих дуг). У протилежному випадку перейти до кроку 2. Відзначимо, що кожний раз, коли зафарбовуюється деяка вершина (не рахуючи вершини s), зафарбовується й деяка дуга, що заходить у дану вершину. Таким чином, на будь-якому етапі алгоритму в кожну вершину заходить не більш ніж одна зафарбована дуга. Крім того, зафарбовані дуги не можуть утворювати у вихідному графі цикл, тому що в алгоритмі не може зафарбовуватися дуга, кінцеві вершини якої вже зафарбовані. Отже, зафарбовані дуги утворять у вхідному графі орієнтоване дерево з коренем у вершині s. Це дерево називається орієнтованим деревом найкоротших шляхів. Єдиний шлях від вершини s до будь-якої вершини х, що належить дереву найкоротших шляхів, є найкоротшим шляхом між зазначеними вершинами. Якщо найкоротшому шляху з вершини s у вершину х в дереві найкоротших шляхів належить вершина y, то частина цього шляху, укладена між х i y, є найкоротшим шляхом між цими вершинами. Дійсно, якби між х i y існував більш короткий шлях, тo згаданий вище шлях між вершинами s і х не міг би бути найкоротшим. Алгоритм Дейкстри можна розглядати як процедуру нарощування орієнтованого дерева з коренем у вершині s. Коли у цій процедурі нарощування досягається вершина t, процедура може бути зупинена. Для визначення найкоротших шляхів з вершини s в усі вершини вхідного графа процедуру нарощування дерева варто продовжувати доти, поки всі вершини графа не будуть включені в орієнтоване дерево найкоротших шляхів. При цьому для вхідного графа було б отримане покриваюче орієнтоване дерево (за умови, що в цьому графі міститься хоча б одне таке дерево). Отже, для одержання дерева найкоротших шляхів від вершини s до всіх інших вершин, третій крок алгоритму повинен бути скоректований у такий спосіб: якщо всі вершини виявляються зафарбованими, закінчити процедуру (для будь-якої вершини х є єдиний шлях з s в х, що складається з зафарбованих дуг, і цей шлях є найкоротшим шляхом між відповідними вершинами); у протилежному випадку перейти до кроку 2. Початкове припущення в алгоритмі Дейкстри складалося в невід’ємності дуг вхідного графа. Якби деякі з довжин дуг були від’ємними, то алгоритм Дейкстри міг би невірно вказати найкоротший шлях. Для приклада розглянемо граф на рис. 8. 1-а і 2-а вершини є початковою й кінцевою вершинами графа відповідно. Довжини переходу між вершинами зазначені на рисунку. У цьому графі найкоротшим шляхом, що з'єднує вершини 1 і 2, є шлях 1 -> 3 -> 4 -> 6 -> 5 -> 2, довжина цього шляху дорівнює 2 + 1 + 4 – 5 - 2 = 0. Алгоритм Дейкстри помилково вкаже шлях 1-> 3 -> 4 -> 2, довжина якого дорівнює 5. Рис. 8. Алгоритм Дейкстри може бути узагальнений на випадок, коли деякі з дуг мають від’ємні довжини. Ідея відповідного узагальнення належить Фордові. Необхідна модифікація алгоритму Дейкстри полягає в наступному: на кроці 2 алгоритму перерахунок величин d(x) за допомогою співвідношення (3) відбувається для всіх вершин, а не тільки для незафарбованих. Отже, числа d(x) можуть зменшуватися як для зафарбованих, так і для незафарбованих вершин; якщо для деякої зафарбованої вершини х відбувається зменшення величини d(x), то із цієї вершини і ідентичній їй зафарбованій дузі фарбування знімається; процедура алгоритму закінчується тільки тоді, коли всі вершини зафарбовані і коли після виконання кроку 2 жодне із чисел d(x) не змінюється. Індивідуальне завдання Скласти програму упорядкування елементів дерева по зростанню з використанням рекурсивної функції. Текст програми #include <stdio.h> #include <conio.h> #include <iostream.h> #include <new.h> #define maximal 50 struct tree_el{int a;struct tree_el *left,*right;}; void add_item(int , struct tree_el**); void out_tree(struct tree_el*,int,int,int); void out_lr(struct tree_el*); void view_menu(void); int main() { struct tree_el *root=NULL; int mas[maximal]; int k,m,a; do { view_menu(); m=getch()-'0'; switch(m) { case 1: cout<<"Vvediye chislo:"; cin>>a; add_item(a,&root); break; case 2: cout<<"Rezim vivody:"<<endl; cout<<"1-po zrostanu"<<endl; cout<<"2-y viglyadi dereva"<<endl; m=getch()-'0'; if (m==1) out_lr(root); else if(m==2) out_tree(root,1,80,7); else cout<<"Error"<<endl; getch(); break; } }while (m); } void view_menu(void) { cout<<"1-dodatu vyzol"<<endl; cout<<"2-vuvid dereva"<<endl; cout<<"0-vuhid"<<endl; cout<<"Natisnit vidpovidny klavishy"<<endl; } void add_item(int a, struct tree_el **p) { int c; if(!*p) { if((*p=new struct tree_el)==NULL) { cout<<"Ne vustachae OP"<<endl; return; } (*p)->a=a; (*p)->left=(*p)->right=NULL; } else { c=((*p)->a)-a; if(c>0) add_item(a,&((*p)->left)); else if(c<0) add_item(a,&((*p)->right)); else cout<<"Element"<<a<<"Vhze e"<<endl; } } void out_tree(struct tree_el *p,int lb,int rb,int r) { if(p) { ((lb+rb)/2,r); cout<<p->a<<endl; out_tree(p->left,lb,(lb+rb)/2,r+1); out_tree(p->right,(lb+rb)/2,rb,r+1); } } void out_lr(struct tree_el *p) { if(p->left) out_lr(p->left); cout<<p->a<<endl; if(p->right) out_lr(p->right); } Результати обчислень  Висновок: Я навчився використовувати логічну структуру дерев для програмування задач з використанням графів.
Антиботан аватар за замовчуванням

29.05.2013 13:05-

Коментарі

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

Ділись своїми роботами та отримуй миттєві бонуси!

Маєш корисні навчальні матеріали, які припадають пилом на твоєму комп'ютері? Розрахункові, лабораторні, практичні чи контрольні роботи — завантажуй їх прямо зараз і одразу отримуй бали на свій рахунок! Заархівуй всі файли в один .zip (до 100 МБ) або завантажуй кожен файл окремо. Внесок у спільноту – це легкий спосіб допомогти іншим та отримати додаткові можливості на сайті. Твої старі роботи можуть приносити тобі нові нагороди!
Нічого не вибрано
0%

Оголошення від адміністратора

Антиботан аватар за замовчуванням

Подякувати Студентському архіву довільною сумою

Admin

26.02.2023 12:38

Дякуємо, що користуєтесь нашим архівом!