You are on page 1of 8

Мариана Горанова

A H I

Граф
J K

Граф е абстрактен тип данна, който B C G

представлява колекция от върхове и ребра.


Връх е прост обект, който има име и други
L M
D E

свойства.
Ребро е връзка между два върха.
F

Граф с върхове A B C D E F G H I J K L M
и множество от ребра
AG AB AC LM JM JL JK ED FD HI FE AF GE

Приложение
Път от връх x до връх y е списък от възлите,
– карта на транспортни пътища – маршрути които са свързани чрез ребра в графа.
(връзки) между градовете (върхове): най-
бързият път от София до Лондон със самолет, Пример: Път от B до G е списъкът BAFEG.
най-евтиният път от София до Лондон със Свързан граф е граф, в който има път от всеки
самолет; възел до всеки друг възел в графа.
– електрически схеми – свързване с проводници Несвързан граф е изграден от свързани
на елементите (транзистори, резистори, компоненти.
кондензатори и т.н.): свързани ли са всички
елементи в схемата, работоспособност на Пример: Графът е изграден от три свързани
схемата; компоненти.

– управление на заданията в производствен Прост път е път, в който няма повтарящи се


процес – задачите (върхове) се изпълняват в върхове.
някаква последователност, която се представя Например: BAFEGAC не е прост.
чрез връзки: кога всяка задача трябва да се
изпълни.

V – брой на върховете в граф


Цикъл е прост път, с изключение на първия и Е – брой на ребрата в граф
последния възел, които съвпадат.
Е се изменя от 0 до 1 V (V − 1) .
Пример: Пътят AFEGA е цикъл. 2
Пълен граф е граф, в който присъстват всички
Дърво е граф без цикли. ребра.
Гора е група от несвързани дървета. Разреден граф е граф с относително малък
брой ребра (по-малко от V log V ).
Покриващо дърво е подграф, който съдържа
всички върхове, но само онези ребра, които Плътен граф е граф с относително малък брой
формират дърво. липсващи ребра.
Алгоритмите имат различна ефективност в
зависимост от броя на ребрата в графа и
неговата разреденост.

Структури от данни и приложни


алгоритми 1
Мариана Горанова

Видове графи: Физическо представяне


1. Ориентирани и неориентирани 1. Чрез матрица на съседство
2. Претеглени (на всяко ребро се присвоява 2. Чрез структура на съседство
число – тегло, представящо напр. разстояние
или цена) и непретеглени
Мрежа е ориентиран претеглен граф.

Физическо представяне чрез матрица на Пример:


съседство A B C D E F G H I J K L M
Представяне чрез матрица на съседство – A 1 1 1 0 0 1 1 0 0 0 0 0 0
VxV масив от логически стойности, като B 1 1 0 0 0 0 0 0 0 0 0 0 0
adjmatrix[i][j] се установява в 1, ако има ребро от C 1 0 1 0 0 0 0 0 0 0 0 0 0
връх i до връх j и 0 в противен случай. D 0 0 0 1 1 1 0 0 0 0 0 0 0

Всяко ребро се представя чрез две стойности E 0 0 0 1 1 1 1 0 0 0 0 0 0


adjmatrix[i][j] и adjmatrix[j][i]. F 1 0 0 1 1 1 0 0 0 0 0 0 0
G 1 0 0 0 1 0 1 0 0 0 0 0 0
Приемаме, че има ребро от всеки връх към себе H 0 0 0 0 0 0 0 1 1 0 0 0 0
си – adjmatrix[i][i] = 1 за i от 1 до V.
I 0 0 0 0 0 0 0 1 1 0 0 0 0
J 0 0 0 0 0 0 0 0 0 1 1 1 1
K 0 0 0 0 0 0 0 0 0 1 1 0 0
L 0 0 0 0 0 0 0 0 0 1 0 1 1
M 0 0 0 0 0 0 0 0 0 1 0 1 1

Логическо описание Дефиниране

Съединение на елементи от тип ЦЯЛО, #define MAXV <константа> // максимален брой върхове
образуващи матрица на съседство с V върха и Е struct graph // ГРАФ
ребра. {
тип ГРАФ = (V: ЦЯЛО; {брой върхове} int V; // брой върхове
E: ЦЯЛО; {брой ребра} int E; // брой ребра
масив adjmatrix[1:MAXV][1:MAXV]: ЦЯЛО) int adjmatrix[MAXV][MAXV]; // матрица на съседство
};
typedef struct graph GRAPH;

Структури от данни и приложни


алгоритми 2
Мариана Горанова

Операции
Характеристики
1. Създаване на граф
1. Представянето чрез матрица на съседство е
подходящо за плътни графи – матрицата 2. Обхождане на граф в дълбочина
изисква V2 елемента памет и V2 стъпки само
за инициализация.
2. Имената на върховете се представят чрез
цели числа между 1 и V – бърз достъп до
информацията във всеки възел. Използваме
1-буквени имена на върховете, като iтата
буква от азбуката съответства на цялото
число i.

1. Създаване на граф // Конвертира 1-буквените имена на върхове на граф в


// цяло число – приемаме, че името на връх е главна буква
ЦЯЛО име на връх
Алгоритъм
въведи V и E int index (char c)
за i от 1 до V повтаряй
{
за j от 1 до V повтаряй
adjmatrix[i][j] ← 0 return (c-'A'+1);
за i от 1 до V повтаряй }
adjmatrix[i][i] ← 1
за k от 1 до E повтаряй // Конвертира цяло число в 1-буквено име на връх на граф
въведи символвръх1 и символвръх2
i ← конвертиран символвръх1 в ЦЯЛО име на връх ЦЯЛО
j ← конвертиран символвръх2 в ЦЯЛО char name (int i)
adjmatrix[i][j] ← 1 {
adjmatrix[j][i] ← 1
return (i+'A'-1);
}

ГРАФ for (k=1; k<=g.E; k++)


GRAPH create() {
{ printf ("Въведи ребро:\n");
GRAPH g; printf ("Връх 1: ");
int i, j, k; fflush (stdin);
char v1, v2; v1 = getchar();
printf ("Въведи брой върхове = "); printf ("Връх 2: ");
scanf ("%d", &g.V); fflush (stdin);
printf ("Въведи брой ребра = "); v2 = getchar();
scanf ("%d", &g.E); i = index (v1);
for (i=1; i<=g.V; i++) j = index (v2);
for (j=1;j <=g.V; j++) g.adjmatrix[i][j] = 1;
g.adjmatrix[i][j] = 0; g.adjmatrix[j][i] = 1;
}
for (i=1; i<=g.V; i++) return g;
g.adjmatrix[i][i] = 1;
}

Структури от данни и приложни


алгоритми 3
Мариана Горанова

2. Обхождане на граф в дълбочина Алгоритъм


за k от 1 до V повтаряй
val[k] ← НЕПОСЕТЕН
за k от 1 до V повтаряй
ако val[k] е НЕПОСЕТЕН
Масив val[V] – съхранява реда, в който
посети връх k
върховете се посещават.

ГРАФ масив за реда на


#define UNUSED 0 // върхът не е посетен посещение на върховете
#define USED 1 // върхът е посетен void search (GRAPH g, int val[])
{
int k;
for (k=1; k<=g.V; k++) // инициализиране
val[k] = UNUSED;
for (k=1; k<=g.V; k++)
if (val[k] == UNUSED) // посещение на първия
visit (g, val, k); // непосетен връх
}

посещение на връх k
val[k] ← ПОСЕТЕН
печат на името на посетения възел Обхождане на граф в дълбочина
за t от 1 до V повтаряй при следната последователност от въвеждане на
ако adjmatrix[k][t] != 0 ребрата:
ако val[t] e НЕПОСЕТЕН AG AB AC LM JM JL JK ED FD HI FE AF GE.
посети връх t

ГРАФ връх за посещение ABCFDEGHIJKLM


void visit (GRAPH g, int val[], int k)
{
int t; масив за реда на
val[k] = USED; посещение на върховете
printf("%c ", name(k));
for (t=1; t<=g.V; t=t++)
if (g.adjmatrix[k][t] != 0) // съществува ребро
if (val[t] == UNUSED) // съседният връх t не е посетен
visit (g, val, t);
}

Физическо представяне чрез структура на Пример:


съседство
Представяне чрез структура на съседство –
всички върхове, свързани към даден връх, се
изобразяват чрез списък на съседство за този
връх.
Списъкът на съседство за даден връх се
представя чрез структурата линеен списък.
Началните възли на всеки списък се
съхраняват в масив adj, индексиран от върха.

Структура от списъци на съседство


при следната последователност от въвеждане
на ребрата: AG AB AC LM JM JL JK ED FD HI FE AF GE.

Структури от данни и приложни


алгоритми 4
Мариана Горанова

Логическо описание Дефиниране


#define MAXV <константа>
Съединение на елементи от тип ВЪЗЕЛ,
struct node // възел
образуващи масив от линейни списъци на
{
съседство за граф с V върха и Е ребра.
int v; // данни
тип ВЪЗЕЛ = (данна: ЦЯЛО; {данна} struct node *next; // връзка
следващ: *ВЪЗЕЛ; {връзка}) };
тип ГРАФ = (V: ЦЯЛО; {брой върхове} typedef struct node NODE;
E: ЦЯЛО; {брой ребра} typedef NODE *LINK;
масив adj[1:MAXV]: *ВЪЗЕЛ) struct graph // ГРАФ
{
int V; // брой върхове
int E; // брой ребра
LINK adj[MAXV]; // масив от линейни списъци
}; // на съседство

typedef struct graph GRAPH;

Операции
Характеристики
1. Създаване на граф
1. Представянето чрез структура на съседство е
подходящо за разредени графи – 2. Обхождане на граф в дълбочина
необходимото пространство е О(V+E) за ─ рекурсивен вариант
разлика от О(V2), необходимо за
представянето чрез матрица на съседство. ─ нерекурсивен вариант
3. Обхождане на граф в ширина
2. Всяко ребро се представя два пъти отново –
ребро между върховете i и j се представя като
връх, съдържащ i в списъка на съседство на j
и като връх, съдържащ j в списъка на
съседство на i.
3. Важен е редът, в който се въвеждат ребрата.

ГРАФ
1. Създаване на граф GRAPH create()
{ GRAPH g;
Алгоритъм int i, j, k;
въведи V и E
char v1, v2;
за i от 1 до V повтаряй
adj[i] ← ПРАЗНО LINK t;
за k от 1 до E повтаряй printf ("Въведи брой върхове = ");
въведи символвръх1 и символвръх2 scanf ("%d", &g.V);
i ← конвертиран символвръх1 в ЦЯЛО printf ("Въведи брой ребра = ");
j ← конвертиран символвръх2 в ЦЯЛО scanf ("%d", &g.E);
t ← нов връх for (i=1; i<=g.V; i++)
данниt ← i g.adj[i] = NULL;
следващt ← adj[j] for (k=1; k<=g.E; k++)
adj[j] ← t {
t ← нов връх printf ("Въведи ребро:\n");
данниt ← j
printf ("Връх 1: ");
следващt ← adj[i]
fflush (stdin);
adj[i] ← t
v1 = getchar();

Структури от данни и приложни


алгоритми 5
Мариана Горанова

printf ("Връх 2: "); 2. Обхождане на граф в дълбочина


fflush (stdin);
v2 = getchar(); – рекурсивен вариант
i = index (v1);
j = index (v2); Масив val[V] – съхранява реда, в който
t = (LINK) malloc (sizeof (NODE)); върховете се посещават.
t->v = i; // връх i се добавя
t->next = g.adj[j]; // в списъка на съседство на #define UNUSED 0 // върхът не е посетен
g.adj[j] = t; // връх j #define USED 1 // върхът е посетен
t = (LINK) malloc (sizeof(NODE));
t->v = j; // връх j се добавя
t->next = g.adj[i]; // в списъка на съседство на
g.adj[i] = t; // връх i
}
return g;
}

Алгоритъм посещение на връх k


val[k] ← ПОСЕТЕН
за k от 1 до V повтаряй
печат на името на посетения възел
val[k] ← НЕПОСЕТЕН
за t от първия до последния връх в списъка adj[k]
за k от 1 до V повтаряй
повтаряй
ако val[k] е НЕПОСЕТЕН
ако val[t] e НЕПОСЕТЕН
посети връх k
посети връх t

ГРАФ връх за посещение


ГРАФ масив за реда на
посещение на върховете void visit (GRAPH g, int val[], int k)
void search (GRAPH g, int val[]) {
{ LINK t; масив за реда на
int k; val[k] = USED; посещение на върховете
for (k=1; k<=g.V; k++) // инициализиране printf ("%c ", name(k));
val[k] = UNUSED; for (t = g.adj[k]; t != NULL; t = t->next)
for (k=1; k<=g.V; k++) if (val[t->v] == UNUSED)
if (val[k] == UNUSED) // посещение на първия visit (g, val, t->v);
visit (g, val, k); // непосетен връх }
}

2. Обхождане на граф в дълбочина


– нерекурсивен вариант – използва стек, масив за реда на
който съхранява върховете, които са ГРАФ
посещение на върховете
докоснати, но все още не са посетени.
void search (GRAPH g, int val[], STACK s)
{
СТЕК
int k;
Масив val[V] – съхранява реда, в който for (k=1; k<=g.V; k++)
върховете се посещават. val[k] = UNUSED;
val[i] = UNUSED върхът не е посетен for (k=1; k<=g.V; k++)
if (val[k] == UNUSED)
val[i] = -1 върхът е в стека visit (g, val, s, k);
val[i] = 1:V върхът е посетен }

Структури от данни и приложни


алгоритми 6
Мариана Горанова

ГРАФ СТЕК връх за посещение


посещение на връх k
включи възел k във върха на стека void visit (GRAPH g, int val[], STACK s, int k)
докато стекът стане празен повтаряй {
изключи възел k от върха на стека
val[k] ← ПОСЕТЕН
LINK t;
масив за реда на
печат на името на посетения възел push (&s,k); посещение на върховете
за t от първия до последния връх в списъка adj[k] while (s.top != NULL)
повтаряй {
ако val[t] e НЕПОСЕТЕН pop (&s, &k);
включи възел t във върха на стека
val[t] ← -1
val[k] = USED;
printf ("%c ", name(k));
for (t = g.adj[k]; t != NULL; t = t->next)
if (val[t->v] == UNUSED)
{
push (&s, t->v);
val[t->v] = -1;
}
}
}

3. Обхождане на граф в ширина – използва


опашка, която съхранява върховете, които са
докоснати, но все още не са посетени. ГРАФ
масив за реда на
посещение на върховете
void search (GRAPH g, int val[], QUEUE q)
{
int k; ОПАШКА
for (k=1 ;k <= g.V; k++)
val[k] = UNUSED;
for (k=1; k<=g.V; k++)
if (val[k] == UNUSED)
visit (g, val, q, k);
}

ГРАФ ОПАШКА връх за посещение


посещение на връх k
включи възел k в опашката
докато опашката стане празна void visit (GRAPH g, int val[], QUEUE q, int k)
изключи възел k от опашката { LINK t;
масив за реда на
val[k] ← ПОСЕТЕН put (&q, k);
посещение на върховете
печат на името на посетения възел while (!(q.front == NULL && q.rear == NULL))
за t от първия до последния връх в списъка adj[k] {
повтаряй
ако val[t] e НЕПОСЕТЕН
get (&q, &k);
включи възел t в опашката val[k] = USED;
val[t] ← -1 printf ("%c ", name(k));
for (t = g.adj[k]; t != NULL; t = t->next)
if (val[t->v] == UNUSED)
{
put (&q, t->v);
val[t->v] = -1;
}
}
}

Структури от данни и приложни


алгоритми 7
Мариана Горанова

Задача: Абстрактен тип данни ГРАФ 4. Реализирайте граф чрез структура на


1. Реализирайте граф чрез матрица на съседство.
съседство. 5. Напишете функция print(), която отпечатва
2. Напишете функция print(), която отпечатва граф, представен чрез структура на
граф, представен чрез матрица на съседство.
съседство.

Алгоритъм
Алгоритъм за i от 1 до V повтаряй
за i от 1 до V повтаряй отпечатай името на връх i
отпечатай името на връх i докато adj[i] e различно от ПРАЗНО повтаряй
за i от 1 до V повтаряй отпечатай името на върха в adj[i]
отпечатай името на връх i t ← следващия елемент на adj[i]
за j от 1 до V повтаряй adj[i] ← t
отпечатай admatrix[i][j]

3. Отпечатайте графа, като използвате 6. Отпечатайте графа, като използвате


функцията print(). функцията print().

Структури от данни и приложни


алгоритми 8

You might also like