Materialy do wykladu (cz 2) id Nieznany

background image

AISD wer. 2 str. 52

Cyfrowe drzewa dostępu (ang. Radix Search Tries) są modyfikacją cyfrowych drzew
przeszukiwań taką, że dane są zapamiętywane tylko w liściach, zaś rozgałęzienia
następują w węzłach pośrednich na podstawie badania kolejnych cyfr klucza.

Przykład. Binarne drzewo dostępu dla kluczy
16, 54, 14, 63 62 48 21 53
010000, 110110, 001110, 111111, 111110, 110000, 010101, 110101

root

0xxxxx

1xxxxx

[14]

01xxxx

11xxxx

010xxx

110xxx

111xxx

[16] [21]

[48] 1101xx

1111xx

[53] [54]

11111x

[62] [63]

Zupełne drzewo dostępu (ang. Complete (or Pure) Radix Search Trie) różni się tym od
postaci standardowej, że wszystkie liście rezydują na najgłębszym możliwym poziomie
węzła. W takim drzewie wszystkie cyfry są badane na ścieżce dostępu do informacji i dlatego
klucz nie musi być zapamiętywany w liściu drzewa.

root

* *

* * *

* * * *

* * * * * *

* * * * * * *

[] [] [] [] [] [] [] []
14 16 21 48 53 54 62 63

Własność. Kształt (balans) cyfrowego drzewa przeszukiwań jest wrażliwy na cyfrowy rozkład
kluczy.

Klucze, które nie są równomiernie rozłożone (cyfrowo) są nazywane kluczami numerycznie
odchylonymi (ang. biased). Takie klucze powodują grupowanie (ang. cluster) danych w
cyfrowym drzewie przeszukiwań.

background image

AISD wer. 2 str. 53

Własność. Kształt (balans) cyfrowego drzewa dostępu (ang. trie) zawierającego n kluczy
jest niezależny od kolejności wstawiania tych kluczy. Unikatowe (jednoznaczne) drzewo
istnieje dla danego zbioru kluczy.

Własność. Poszukiwanie lub wstawienie węzla do M-arnego cyfrowego drzewa dostępu
wymaga średnio około log

M

(N) porównań a w najgorszym przypadku b porownań w drzewie

utworzonym z N losowych b-cyfrowych kluczy.

Cyfrowe drzewo dostępu może być kosztowne z punktu widzenia zasobu pamięci. Liczba
węzłów wewnętrznych może być znacznie większa od liczby liści. Jesli wzrasta liczba M, to
skraca się ścieżka do liści, ale z drugiej strony wzrasta liczba nieużywanych wskazań na
węzły potomne (dzieci).

Własność. Binarne drzewo dostępu utworzone z N losowych b-bitowych kluczy liczy średnio
około N/ln(2) = 1.44*N.
Własność. Dla M-arnego drzewa dostępu utworzonego z N losowych kluczy, liczba
używanych powiązań wynosi około M*N/ln(M).

Podsumowując można stwierdzić, że drzewa przeszkiwań oparte o porównania (całych
wartości kluczy) są silnie zależne od kolejności wprowadzania, wyważenie cyfrowych drzew
przeszukiwań w niewielkim stopniu zależy od tej kolejności, zaś drzewa dostępu są w pełni
niezależne od kolejności wprowaczania danych.

Hybrydowe drzewa dostępu znajdują zastosowanie w praktycznych rozwiązaniach
pozwalając na wyważenie szybkości przetwarzania i zajętości pamięci.

Zwiększenie stopnia drzewa dostępu zwiększa szybkość przetwarzania ponieważ do
pojedynczego porównania brana jest większa liczba bitów (i skraca się ścieżka dostępu). Ma
to sens w "górnej" części drzewa, gdzie zazwyczaj wszystkie rozgałęzienia są wykorzystane.
Gorzej jest w dolnej części drzewa, gdzie wiele wskazań na dzieci jest puste. W rozwiązaniu
hybrydowym dopuszcza się stosowanie niższego stopnia węzłów w tym obszarze drzewa.
Innym hybrydowym rozwiązaniem jest stosowanie porcji (ang. bucket) w liściach drzewa
dostępu, co umożliwia wprowadzanie wielu danych z tym samym kluczem.

Własność. Binarne drzewo dostępu dzieli zbiór danych w taki sam sposób jak algorytm
sortowania według cyfr (ang. Radix Exchange Sort).

Słowniki są często implementowane jako cyfrowe drzewa dostępu. Na przykład w języku
angielskim stopień takiego drzewa (M) wynosi 26. Istotną zaletą takiego rozwiązania jest
efektywne przetwarzanie procesu wyszukiwania i dopasowywania przedrostków, co jest
ważną cechą wyszukiwania słów oraz sprawdzania ich pisowni.
Często słowniki sa realizowane hybrydowo z binarnymu drzewami przeszukiwań (BST)
bliżej liści.

background image

AISD wer. 2 str. 54

Przykład.
*
a f u
* * *
t o s
* * *
r
*
g k m t
* * * *
e h i
* * *
f
*
y
*

Drzewa B (ang. B-Trees)

Drzewa B służą do przechowywania uporządkowanych danych w pamięci zewnętrznej (na
dyskach).

Własności drzewa B rzędu N:

-

Należy utrzymywać minimalną wysokość drzewa B.

-

Drzewo B musi być wyważone.

-

Wszystkie liście drzewa B pozostają na tym samym poziomie.

-

Nie istnieją puste poddrzewa powyżej poziomu liści.

-

Korzeń może nie mieć dzieci, jeśli drzewo B zawiera tylko jeden węzeł.

-

Każdy z węzłów zawiera co najmniej N kluczy i co najwyżej 2N kluczy. Węzeł
jest pełny jeśli zawiera 2N kluczy. Korzeń może zawierać tylko 1 klucz dla
dowolnego N

-

Drzewo B jest budowane przez wstawianie klucza do liścia. Drzewo wzrasta
"wszerz" i "wzwyż" na skutek podziału węzłów pełnych.

-

W trakcie wprowadzania nowego elementu danych do drzewa B zachowywany
jest odpowiedni porządek. Klucz wprowadzanej danej jest porównywany z
kluczem (kluczami) w korzeniu i po kolei z kluczami węzłów pośrednich, aż
trafia do odpowiedniego liścia (węzła X). Jeśli X jest pełen, to następuje jego
podział na dwa i klucz ze środkowej pozycji jest wstawiany do rodzica węzła X,
co również może spowodować podział. W ten sposób podziały mogą propagpwać
aż do korzenia. Jeśli natomiast węzeł X nie jest pełny, to nowa dana jest
umieszczana tak aby zachować porządek w węźle. Po wstawieniu węzła drzewo
musi zachowywać własności drzewa B.

-

Po usunięciu klucza drzewo musi zachowywać własności drzewa B.

background image

AISD wer. 2 str. 55

Przykład budowy drzewa B rzędu 2

Wstawiamy element 33

33
0 0

Wstawiamy elementy 60, 5 15

5 15 33 60
0 0 0 0 0

Wstawiamy element 25

15
* *
5 25 33 60 (nie jest B)
0 0 0 0 0 0

25
* *
5 15 33 60
0 0 0 0 0 0

Wstawiamy element 12

25
* *
5 12 15 33 60
0 0 0 0 0 0 0

Wstawiamy element 45
25
* *
5 12 15 33 45 60
0 0 0 0 0 0 0 0
Wstawiamy element 70
25
* *
5 12 15 33 45 60 70
0 0 0 0 0 0 0 0 0

Wstawiamy element 35
25 45
* * *
5 12 15 33 35 60 70
0 0 0 0 0 0 0 0 0 0

Wstawiamy element 7
25 45
* * *
5 7 12 15 33 35 60 70
0 0 0 0 0 0 0 0 0 0 0

W drzewie B nie można umieszczać duplikatów kluczy.

Częstość podziału węzłów można zmniejszyć przez zwiększenie stopnia drzewa B.

background image

AISD wer. 2 str. 56

Usuwanie klucza z drzewa B

1.

Usuwanie klucza z korzenia, który ma więcej niż 1 klucz i jest liściem.

2.

Usuwanie klucza z korzenia, który ma więcej niż 1 klucz i nie jest liściem.
Zastąpienie usuniętego klucza najmniejszym kluczem prawego poddrzewa
usuwanego klucza.
Zastąpienie usuniętego klucza największym kluczem lewego poddrzewa
usuwanego klucza.
Połączenie lewego i prawgo poddrzewa jeśli mają po N kluczy.

3.

Usuwanie klucza z korzenia, który ma 1 klucz i nie jest liściem. (jak 2.)

4.

Usuwanie klucza z korzenia, który ma 1 klucz i jest liściem.

5.

Usuwanie klucza z liścia, który ma co najmniej (N+1) kluczy.

6.

Usuwanie klucza z liścia, który ma N kluczy.
Weź klucz od lewego sąsiada, jeśli ma on co najmniej (N+1) kluczy.
Weź klucz od prawego sąsiada, jeśli ma on co najmniej (N+1) kluczy.
Lewy sąsiad ma dokładnie N kluczy. Połącz węzeł bieżący (z którego usuwamy
klucz) z lewym sąsiadem.
Prawy sąsiad ma dokładnie N kluczy. Połącz węzeł bieżący (z którego usuwamy
klucz) z prawym sąsiadem.

Przykład.
25 45
* * *
5 7 12 15 33 35 60 70
0 0 0 0 0 0 0 0 0 0 0

Usuwamy węzeł 7
25 45
* * *
5 12 15 33 35 60 70
0 0 0 0 0 0 0 0 0 0

Usuwamy węzeł 25
15 45
* * *
5 12 33 35 60 70
0 0 0 0 0 0 0 0 0

Usuwamy węzeł 33
45
* *
5 12 15 35 60 70
0 0 0 0 0 0 0 0

Usuwamy węzeł 45
35
* *
5 12 15 60 70
0 0 0 0 0 0 0

background image

AISD wer. 2 str. 57

Usuwamy węzeł 12
35
* *
5 15 60 70
0 0 0 0 0 0

Usuwamy węzeł 15
5 35 60 70
0 0 0 0 0

Drzewa BB (ang. Binary B-Trees)

Drzewo BB (drzewo 2-3) jest drzewem B rzędu 1. Węzeł drzewa zawiera jeden klucz (K)
oraz 3 wiązania: lewe, prawe i poziome. Jeżeli wiązanie lewe nie jest puste, to klucze tego
poddrzewa są mniejsze niż klucz K. Dla wiązań prawego i poziomego wskazywane przez nie
poddrzewa mają klucze większe.

1.

Dla żadnego węzła w drzewie nie mogą równocześnie występować wiązania
poziome i prawe.

2.

Poziome połączenia nie występują jedno po drugim, tzn. jeśli węzeł X ma
poziome połączenie, to korzeń poddrzewa wskazanego przez nie musi mieć
poziome połączenie "puste".

3.

Wysokości wszystkich następników (poddrzew) dla każdego węzła w drzewie są
takie same; przy liczeniu wysokości drzewa połączenia poziome jej nie
zwiększają.

Wstawianie do drzew BB wykonuje się tak jak do drzew B, a równoważenie wykonywane
jest według 5 schematów.

Schematy równoważenia drzewa BB.

A B C A B

a B A c d a b C
1
b c a b c d
3 5
B
A B
A C
a b c
a b c d

B 4
A C
A c 2
a B d
a b
b c

background image

AISD wer. 2 str. 58

Przykład. Wstawianie kluczy do drzewa BB. Klucze: A, Z, Y, X, B

1. A

2. A Z

3. A Z 4 Y

Y A Z

4. Y

A X Z

5. Y Y B Y

A X Z 4 B Z 2 A X Z

B A X

Grafy

Definicja. Grafem G nazywamy parę zbioru węzłów V, oraz zbioru krawędzi E, takich że dla
skończonego n

G = {V, E}, gdzie

V = {V

1

, V

2

, ..., V

n

}

E = {E

ij

= (V

i

, V

j

), 1 <= i <= n, 1 <= j <= n }

Krawędź, (albo łuk) określa połączenie między dwoma węzłami. Krawędź nieskierowana
jest definiowana przez parę węzłów np. (A, B). Krawędź skierowana jest określona przez
uporządkowaną parę węzłów <A, B>, gdzie A jest początkiem, a B końcem krawędzi.
Graf skierowany (ang. directed graph - digraph) składa się z węzłów i krawędzi
skierowanych.
Dwa węzły są sąsiednie, jeśli występuje między nimi krawędź. Cyklem (lub pętlą) w grafie
nazywamy taką ścieżkę w grafie, której początek i koniec są w tym samym węźle. Graf jest
acykliczny, jeśli nie ma w nim cykli. Krawędź tworzy cykl, jeśli łączy ze sobą ten sam węzeł.
Stopniem węzła w grafie (deg(A)) nazywamy liczbę krawędzi wychodzących z tego węzła.
Krawędź będąca pętlą dodaje 2 do stopnia węzła. W grafie skierowanym stopniem
wejściowym węzła (ang. in-degree) (deg(A)) nazywamy liczbę krawędzi zakończonych w tym
węźle. Stopień wyjściowy (ang. out-degree) (deg

+

(A)) to liczba krawędzi rozpoczynających

się w danym węźle. Węzeł A jest odizolowany (niepołączony) jeśli deg(A)=0. Graf jest
połączony (ang. connected), jeśli nie zawiera węzłów odizolowanych. Z krawędzią może być
związana wartość zwana wagą (np. koszt, odległość).
Ścieżka z węzła A do węzła B w grafie skierowanym (nieskierowanym) to sekwencja
krawędzi skierowanych (nieskierowanych) oznaczonych przez p(A, B). Ścieżka ma długość
m, jeśli w jej skład wchodzi m krawędzi (m+1 węzłów)

background image

AISD wer. 2 str. 59

V

0

=A, V

1

, V

2

, ... V

m

=B

Najkrótszą ścieżką w grafie ważonym jest ścieżka z minimalną sumą wag krawędzi.

Graf można przeglądać według dwóch metod:
- przeglądanie w głąb (ang. depth-first traversal DFS)
- przeglądanie wszerz (ang. breadth-first traversal BFS)

Przeglądanie grafu nie jest jednoznaczne. Może być rozpoczynane od dowolnego

węzła. Zastosowania: sprawdzanie połaczenia, wyznaczanie najkrótszej (wagowo) ścieżki.

Aby uniknąć wielokrotnego uwzględniania tego samego węzła, do którego można

dotrzeć z różnych stron stosuje się wskaźnik (ang. flag) informujący, czy dany węzeł był już
wizytowany.

Przeglądanie w głąb zwane jest również przeglądaniem z powrotami (ang.

backtracking) i polega na posuwaniu się jak najdalej od bieżącego węzła, powrocie i
analizowaniu kolejnych możliwości.

Rekursywny algorytm DFS ma następującą postać:

// Wskaźniki wizytacji mają wartość FALSE dla wszystkich
// węzłów w grafie

Depth_First_Search (VERTEX A)
{

Visit A;
Set_ON_Visit_Flag (A); // to TRUE

For all adjecent vertices A

i

(i = 1, ..., p) of A

if (A

i

has not been previously visited)

Depth_First_Search (A

i

);

}

Przykład.

Węzeł

Sąsiedzi

A B C D

A

B, H

B

A, C, G, F, H

C

B, D, F

H G F E

D

C, E, F

E

D, F

F

B, C, D, E, G

G

B, F, H

H

A, B, G

Przeglądanie wszerz (BFS) polega na przeglądaniu danego węzła i wszystkich jego sąsiadów,
a potem po kolei sąsiadów sąsiadów, itd.

background image

AISD wer. 2 str. 60

Algorytm BFS
1. Odwiedź węzeł startowy A.
2. Wstaw węzeł A do kolejki.
3. Dopóki kolejka nie jest pusta wykonuj kroki 3.1 - 3.2

3.1. Weź węzeł X z kolejki
3.2. Dla wszystkich sąsiadów X

i

(X-a) wykonuj

3.2.1

Jeśli X

i

, był odwiedzony zakończ jego przetwarzanie.

3.2.2

Odwiedź węzeł X

i

.

3.2.2

Wstaw do kolejki węzeł X

i

.

Definicja. Graf w ujęciu ATD jest strukturą danych, która zawiera skończony zbiór węzłów i
skończony zbiór krawędzi oraz operacje pozwalające na definiowanie, manipulowanie oraz
abstrahowanie pojęć węzłów i krawędzi.

Przykładowe metody klasy reprezentującej graf

Twórz i inicjalizuj obiekt grafu.
Usuń obiekt grafu.
Sprawdź, czy zbiór węzłów jest pusty.
Sprawdź, czy zbiór krawędzi jest pusty.
Sprawdź, czy dwa węzły są sąsiednie.
Buduj graf z danego zbioru węzłów i krawędzi.
Dodaj węzeł do grafu.
Szukaj węzła przechowującego zadany klucz.
Usuń węzeł przechowujący zadany klucz.
Modyfikuj informację w węźle o zadanym kluczu.
Dodaj krawędź do grafu.
Szukaj krawędź identyfikowaną przez zadany klucz.
Usuń krawędź identyfikowaną przez zadany klucz.
Przejdź graf metodą w głąb.
Przejdź graf metodą wszerz.
Drukuj obiekt grafu.
Określ atrybuty grafu.
Znajdź (oblicz) najkrótszą ścieżkę w grafie.

Implementacja grafu przy pomocy macierzy powiązań (sąsiedztwa).

Dla grafu bez wagi

1, jeśli A

i

jest sąsiednie z A

j

Adj_Mat[i][j] =

0, jeśli A

i

nie jest sąsiednie z A

j

background image

AISD wer. 2 str. 61

Dla grafu z wagami

w

ij

, jeśli A

i

jest sąsiednie z A

j

Adj_Mat[i][j] =

0, jeśli A

i

nie jest sąsiednie z A

j

Dla grafu nieskierowango macierz powiązań jest symetryczna
Adj_Mat[i][j] = Adj_Mat[j][i]

Do oznaczenia braku sąsiedztwa zamiast 0 stosuje się czasami oznaczenie nieskończoności.

Algorytm Dijkstry wyznaczania najkrótszej ścieżki w grafie.
1.

Dany jest graf ważony G ze zbiorem n węzłów:
A = A

0

, A

1

, A

2

, ... , A

n-1

= Q,

krawędzi (A

i

, A

j

) (lub <A

i

, A

j

>) i wag w

ij

2.

Zbiór roboczy węzłów S jest początkowo pusty. Każdemu węzłowi jest
przypisywana etykieta L, która ma następujące znaczenie: L(A

k

) oznacza wagę

najkrótszej ścieżki od węzła początkowego A do węzła A

k

. L(A)=0 i dla

wszystkich węzłów L(A

i

)=nieskończoność (np. 99999999)

3.

(Iteracja) Dopóki węzeł docelowy Q nie jest w zbiorze S wykonuj kroki 3.1 - 3.5.

3.1.

Wybierz najbliższy węzeł A

k

, taki że nie należy do S i L(A

k

) jest najmniejsze

spośród wszystkich węzłów nie należących do S.

3.2.

Dodaj A

k

do zbioru S

3.3.

Jeśli A

k

=Q, zwróć L(A

k

) i zakończ

3.4.

Dla wszystkich sąsiadów A

j

węzła A

k

, które nie są w S modyfikuj ich etykietę L

przez minimum z L(A

j

) i z L(A

k

)+w

kj

3.5.

Wróć do początku kroku 3.

4.

L(Q) jest wagą najkrótszej ścieżki od A do Q. Droga taka została znaleziona.

class Graph {
public:
virtual int build_graph(void) = 0;
virtual int is_graph_empty(void) = 0;
virtual void find_shortest_path(void) = 0;
virtual int get_min(void) = 0;
virtual void show_paths(KEY_TYPE src_vrtx, KEY_TYPE dst_vrtx) = 0;
virtual int check_graph(void) = 0;
virtual void print_graph(void) = 0;
};

#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include <stdlib.h>
typedef int KEY_TYPE;

background image

AISD wer. 2 str. 62

#include "bc_graph.h" // For base class "Graph"
typedef int WEIGHT; // weight = arc length
const int HUGE_WEIGHT = 999999999;
// NOTFOUND is a phase of a vertex in the graph
// where the vertex has not been found yet via
// the relax() function
const int NOTFOUND = 0;
// FOUND is a phase of a vertex in the graph where
// the vertex has been found but the shortest
// path not yet determined
const int FOUND = 1;
// TAKEN is a phase of a vertex in the graph where
// the vertex's shortest path has been found.
const int TAKEN = 2;

#define ERROR1 "ERROR, TOO MANY VERTICES FOR THIS CONFIG"
#define ERROR2 "ERROR, NEGATIVE LENGTHS"
#define ERROR3 "ERROR, INVALID SOURCE VERTEX"
#define ERROR4 "ERROR, INVALID DESTINATION VERTEX"

class Weighted_DiGraph : private Graph {
private:
int MAX_VERTEX;

// adjacency matrix of the directed graph
// int WT_ADJACENCY_MATRIX[MAX_VERTEX +1][MAX_VERTEX +1];
WEIGHT *WT_ADJACENCY_MATRIX;
// VERTEX structure of a vertex which contains
// the vertexs' phase and shortest path.
struct VERTEX {
int shortestpath;
char phase;
};
VERTEX *VERTICES;
int NUM_OF_VERTICES;
// For store & retrieve A[i][j]
WEIGHT &adj_matrix (int i, int j)
{ return WT_ADJACENCY_MATRIX [i* (MAX_VERTEX + 1) + j]; }
void relax(int);
void init_digraph(void);
void init_digraph_vertices(void);
int check_digraph(void);
int create_directed_graph(void);
void Dijkstra_shortest_path(void);
public:
Weighted_DiGraph(int max_vrtx);
~Weighted_DiGraph();
void intro (void);
int build_graph(void) {return create_directed_graph();}
int is_graph_empty(void) { return 0;}
void find_shortest_path(void) {Dijkstra_shortest_path();}
int get_min(void);
void show_paths(KEY_TYPE src_vrtx, KEY_TYPE dst_vrtx);
void show_paths();
int check_graph(void) { return check_digraph();}
void print_graph(void) {printf("\nNot implemented\n");}
};

Weighted_DiGraph::Weighted_DiGraph (int max_vrtx)

background image

AISD wer. 2 str. 63

{
MAX_VERTEX = max_vrtx;
WT_ADJACENCY_MATRIX = new WEIGHT [(MAX_VERTEX + 1) * (MAX_VERTEX + 1)];
VERTICES = new VERTEX [MAX_VERTEX + 1];
}

Weighted_DiGraph::~Weighted_DiGraph () // Destructor
{
delete [] WT_ADJACENCY_MATRIX;
delete [] VERTICES;
}

int Weighted_DiGraph::create_directed_graph (void)
{
char answer[4];
WEIGHT new_wt;
printf (" Enter number of vertices in graph ==> ");
scanf ("%d", &NUM_OF_VERTICES);
if (NUM_OF_VERTICES > MAX_VERTEX) {
printf("%s \n", ERROR1);
return (0);
}
if (NUM_OF_VERTICES < 1) // invalid input
return (0);
init_digraph();
printf("\n");

for (int i = 1; i <= NUM_OF_VERTICES; i++) {
for (int j = 1; j <= NUM_OF_VERTICES; j++) {
printf("%s %d to vertex %d (Y/N) ==> ",
" Is there a path from vertex",i,j);
scanf("%s", answer);
if ((answer[0] == 'y') || (answer[0] == 'Y')) {
printf(" Enter path length ==> ");
scanf("%d", &new_wt);
adj_matrix(i, j) = new_wt;
}
}
}
return (1);
}

void Weighted_DiGraph::Dijkstra_shortest_path(void)
{
int source, // source vertex
destination, // destination vertex
min; // index of vertex with shortest path
// error = 1 if there is a negative path weight or
// impossible source and destination vertices.
int error;
// size = count of the number of vertexs which have
// had their shortest paths determined.
int size;
error = check_digraph();
if (error) {
printf(" %s \n", ERROR2);
return;
}
error = 1;

background image

AISD wer. 2 str. 64

while (error) {
printf("\n Enter the Source Vertex Number ==> ");
scanf("%d", &source);
if ((source >= 1) && (source <= NUM_OF_VERTICES))
error = 0;
else
printf("%s \n", ERROR3);
}
error = 1;
while (error) {
printf("\n Enter the Destination Vertex Number ==> ");
scanf("%d", &destination);
if ((destination >= 1) &&
(destination <= NUM_OF_VERTICES))
error = 0;
else
printf(" %s \n", ERROR4);
}
// put all vertex phases to NOTFOUND and
// shortestpath lengths to HUGE_WEIGHT
init_digraph_vertices();
VERTICES[source].shortestpath = 0;
VERTICES[source].phase = FOUND;
size = 0;
while (size++ < NUM_OF_VERTICES) {
// return vertex with minimum shortest path
min = get_min();
// this vertex is no longer available, i.e., TAKEN.
VERTICES[min].phase = TAKEN;
// determine shortest paths from a given vertex.
relax (min);
}
// show the shortest path from source to destination.
show_paths (source, destination);
}

void Weighted_DiGraph::init_digraph(void)
{
int i, j;
for (i = 1; i <= NUM_OF_VERTICES; i++)
for (j = 1; j <= NUM_OF_VERTICES; j++)
adj_matrix(i, j) = 0;
}

void Weighted_DiGraph::init_digraph_vertices(void)
{
for (int i = 1; i <= NUM_OF_VERTICES; i++) {
VERTICES[i].phase = NOTFOUND;
VERTICES[i].shortestpath = HUGE_WEIGHT;
}
}

// get_min():
// Returns shortest path to an available vertex
//

int Weighted_DiGraph::get_min(void)
{
int min = HUGE_WEIGHT, // min path found so far

background image

AISD wer. 2 str. 65

index = 0; // vertex index
for (int i = 1; i <= NUM_OF_VERTICES; i++) {
if (VERTICES[i].phase == FOUND) { // vertex is available
if (VERTICES[i].shortestpath < min) {
// new minimum
index = i;
min = VERTICES[i].shortestpath;
}
}
}
return index;
}

// relax():
// Determines shortest paths to vertices
// reachable from a given vertex.
//

void Weighted_DiGraph::relax(int min)
{
for (int i = 1; i <= NUM_OF_VERTICES; i++) {
// WT_ADJACENCY_MATRIX[min][i] == adj_matrix(min, i)
if (adj_matrix(min, i) &&
(VERTICES[i].phase != TAKEN)) {
// there is a path and the end vertex is available
VERTICES[i].phase = FOUND;
if ((VERTICES[min].shortestpath +
adj_matrix(min, i)) < (VERTICES[i].shortestpath))
// a shorter path then previously found is available.
// Store newly found shortest path.
VERTICES[i].shortestpath = VERTICES[min].shortestpath +
adj_matrix(min, i);
}
}
}

void Weighted_DiGraph::show_paths(int source, int destination)
{
if (VERTICES[destination].shortestpath < HUGE_WEIGHT)
printf("\n Shortest %s %d to %d = %d\n",
"path from vertex", source, destination,
VERTICES[destination].shortestpath);
else // vertex was not reachable from source
printf("\nNo path available %s %d to %d\n",
"from vertex", source, destination);
}

int Weighted_DiGraph::check_digraph (void)
{
int i, j;
for (i = 1; i <= NUM_OF_VERTICES; i++)
for (j = 1; j <= NUM_OF_VERTICES; j++)
// if (WT_ADJACENCY_MATRIX[i][j] < 0)
if (adj_matrix(i, j) < 0)
return 1;
return 0;
}

// intro(): Prints introduction and limitation.

background image

AISD wer. 2 str. 66

void Weighted_DiGraph::intro (void)
{
printf ("\n *** OOP IMPLEMENTATION OF %s %s %s",
"WEIGHTED DIGRAPH ***",
"\n USING ADJACENCY MATRIX AND",
"\n DIJKSTRAS SHORTEST PATH");
printf ("\n\n %s %s %s %s %s %s \n\n",
"This program will create a directed graph via",
"\n inputs from the screen, determine the shortest",
"\n path from a given source to a given destination,",
"\n and output the shortest path length.",
"\n\n NOTE: This program currently has a limitation",
"\n of no more than 100 vertices in the digraph.");
}

void main(void)
{
Weighted_DiGraph digraph_obj(100);
int success;

digraph_obj.intro();
success = digraph_obj.build_graph();
if (success)
digraph_obj.find_shortest_path();
}

Implementacja grafu przy pomocy listy powiązań (sąsiedztwa).

Przykład

B

C

A *-> (B,7)*-> (D,5)*-> (F,6)NULL
B *-> (C,10)NULL

A

D

C *-> (D,20)NULL
D NULL

F

E

E *-> (D,5)NULL
F *-> (E,8)NULL

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
typedef int KEY_TYPE;

#include "bc_graph.h" // For base class "Graph"

const int HUGE_WEIGHT = 999999999; // for infinity
enum VISIT_FLAG {TRUE, FALSE};

class Wt_DiGraph : private Graph {
private:
typedef char DATA_TYPE;
typedef int WEIGHT;
typedef int INDEX;

typedef struct ADJACENT_VERTEX {
KEY_TYPE vrtx_key;
WEIGHT weight;

background image

AISD wer. 2 str. 67

ADJACENT_VERTEX *next;
} *ADJACENCY_LIST_PTR;

typedef struct VERTEX {
KEY_TYPE vrtx_key;
DATA_TYPE data;
WEIGHT label;
VISIT_FLAG visited;
int hops, path[20];
ADJACENCY_LIST_PTR adj_list_hd_ptr;
} *VERTEX_PTR;

// VERTEX_ARY[MAX_VERTEX] :An array of vertices
VERTEX_PTR VERTEX_ARY;
int MAX_VERTEX;
INDEX TAIL;
int build_wt_digraph();
void print_digraph(void);

public:
Wt_DiGraph (int max_no_of_vertices);
~Wt_DiGraph();
int build_graph(void) {return build_wt_digraph();}
int is_graph_empty(void);
void find_shortest_path(void);
int get_min(void) {return 0;} // Not implemented
void show_paths(int, int) {} // Not implemented
int check_graph(void) {return 0;} // Not implemented
void print_graph(void) { print_digraph(); }
VERTEX_PTR create_vertex();
void intro (void);
void add_vertex(KEY_TYPE, DATA_TYPE);
INDEX search_vertex(KEY_TYPE);
void add_adjacent_vrtx(KEY_TYPE, KEY_TYPE, WEIGHT);
void get_src_dst_vertices(KEY_TYPE *src_vrtx_key,
KEY_TYPE *dst_vrtx_key);
};

Wt_DiGraph::Wt_DiGraph(int max_no_of_vertices)
{
MAX_VERTEX = max_no_of_vertices;
VERTEX_ARY = new VERTEX[MAX_VERTEX];
TAIL = -1; // array of vertices is empty
}

Wt_DiGraph::~Wt_DiGraph()
{
if (!is_graph_empty()) {
for (INDEX i = 0; i <= TAIL; i++) {
ADJACENCY_LIST_PTR
adjacency_ptr = VERTEX_ARY[i].adj_list_hd_ptr;
while (adjacency_ptr != NULL) {
ADJACENCY_LIST_PTR tmp_ptr = adjacency_ptr;
adjacency_ptr = adjacency_ptr->next;
delete tmp_ptr;
}
}
}
delete [] VERTEX_ARY;

background image

AISD wer. 2 str. 68

}

int Wt_DiGraph::is_graph_empty(void)
{
return (TAIL == -1);
}

Wt_DiGraph::VERTEX_PTR Wt_DiGraph::create_vertex()
{
VERTEX_PTR new_ptr;
new_ptr = new VERTEX;
if (new_ptr == NULL)
printf("\n create_vertex: alloc failed \n");
return (new_ptr);
}

void Wt_DiGraph::add_vertex(KEY_TYPE new_key, DATA_TYPE new_data)
{
// Is the vertex array full? If so, error msg
if ((TAIL + 1) != MAX_VERTEX) {
VERTEX_ARY[++TAIL].vrtx_key = new_key;
VERTEX_ARY[ TAIL].data = new_data;
VERTEX_ARY[ TAIL].label = 0;
VERTEX_ARY[ TAIL].hops = 0;
VERTEX_ARY[ TAIL].visited = FALSE;
VERTEX_ARY[ TAIL].adj_list_hd_ptr = NULL;
}
else
printf ("\n add_vertex: Array of vertices is full\n");
}

int Wt_DiGraph::build_wt_digraph(void)
{
KEY_TYPE key1, key2;
int n_vertices, edge_weight,
maxweight = HUGE_WEIGHT,
vrtx_ary_index;
printf("\n Enter number of vertices in your Weighted DiGraph:");
scanf("%d", &n_vertices);
if (n_vertices > MAX_VERTEX) {
printf ("\n build_wt_digraph: %s %d \n",
"Number of vertices is more than max",
MAX_VERTEX);
return(0);
}
for (INDEX i = 0; i < n_vertices; i++) {
add_vertex(i, i);
printf("\n Vertex: %2d has been created.", i);
}
printf("\n");
for (i = 0; i < n_vertices; i++) {
key1 = (KEY_TYPE) i;
vrtx_ary_index = search_vertex(key1);
for (INDEX j = 0; j < n_vertices; j++) {
key2 = (KEY_TYPE) j;
if (j != i) {
printf(" Enter %s %2d to Vertex %2d: ",

background image

AISD wer. 2 str. 69

"distance from Vertex", i, j);
// printf(" Else enter n/N for next vertex\n");
if (scanf("%d", &edge_weight) == 1) {
getchar(); // if there is an edge then insert it
add_adjacent_vrtx (key1, key2, edge_weight);
printf("%s: %2d to Vertex: %2d %s\n",
" Edge from Vertex", i ,j, "was created");
if (maxweight < edge_weight)
maxweight = edge_weight;
} // end of (scanf( ...))
else {
getchar();
printf(" No new edge was created.\n");
}
} // if j != i
} // for j < n_vertexs
} // for i < n_vertexs
return(1);
}

void Wt_DiGraph::print_digraph(void)
{
ADJACENCY_LIST_PTR adjacency_hd_ptr;
printf("\n\n GRAPH VERTICES ADJACENCY LISTS");
printf("\n ============== ===============\n");
if (is_graph_empty()) {
printf("\n Weighted digraph is empty");
return;
}
for (INDEX i = 0; i <= TAIL; i++) {
printf(" %d: ",
VERTEX_ARY[i].vrtx_key);
adjacency_hd_ptr = VERTEX_ARY[i].adj_list_hd_ptr;
while (adjacency_hd_ptr != NULL) {
printf(" %d ->", adjacency_hd_ptr->vrtx_key);
adjacency_hd_ptr = adjacency_hd_ptr->next;
}
printf(" NULL \n");
}
}

Wt_DiGraph::INDEX Wt_DiGraph::search_vertex(KEY_TYPE srch_key)
{
if (!is_graph_empty()) {
for (INDEX i = 0; i <= TAIL; i++)
if (srch_key == VERTEX_ARY[i].vrtx_key)
return (i);
}
return (-1); // not found
}

void Wt_DiGraph::add_adjacent_vrtx(
KEY_TYPE to_adjacent_key,
KEY_TYPE adjacent_vrtx_key, WEIGHT new_weight)
{
INDEX vertex1;
vertex1 = search_vertex (to_adjacent_key);
if (vertex1 == -1) {
printf("\n add_adjacent_vrtx: %s \n",

background image

AISD wer. 2 str. 70

"To-adjacent vertex not in graph");
return;
}
if (search_vertex (adjacent_vrtx_key) == -1) {
printf("\n add_adjacent_vrtx: %s \n",
"Adjacent vertex not in graph");
return;
}
ADJACENCY_LIST_PTR new_ptr = new ADJACENT_VERTEX;
if (new_ptr == NULL)
return;
new_ptr->vrtx_key = adjacent_vrtx_key;
new_ptr->weight = new_weight;
new_ptr->next = NULL;
new_ptr->next = VERTEX_ARY[vertex1].adj_list_hd_ptr;
VERTEX_ARY[vertex1].adj_list_hd_ptr = new_ptr;
}

void Wt_DiGraph::find_shortest_path(void)
{
ADJACENCY_LIST_PTR adjacency_ptr;
VERTEX_PTR end_ptr, min_label_vertex, tmp_vertex;
WEIGHT label, temp, shortest_dist = 0;
INDEX src_vrtx_index, dst_vrtx_index;
KEY_TYPE src_vrtx_key, dst_vrtx_key;
if (is_graph_empty()) {
printf("\n find_shortest_path: Empty graph\n");
return;
}
get_src_dst_vertices(&src_vrtx_key, &dst_vrtx_key);
for (INDEX i = 0; i <= TAIL; i++)
VERTEX_ARY[i].label = HUGE_WEIGHT;
src_vrtx_index = search_vertex (src_vrtx_key);
if (src_vrtx_index == -1) {
printf("\n find_shortest_path: Source vertex %i %s",
src_vrtx_key, "is not in graph");
return;
}

dst_vrtx_index = search_vertex (dst_vrtx_key);
if (dst_vrtx_index == -1) {
printf("\n find_shortest_path: Dest vertex %i %s",
dst_vrtx_key, "is not in graph");
return;
}
end_ptr = &VERTEX_ARY[dst_vrtx_index];
min_label_vertex = &VERTEX_ARY[src_vrtx_index];
min_label_vertex->label = 0;

min_label_vertex->path[min_label_vertex->hops] =
min_label_vertex->vrtx_key;
while (min_label_vertex->vrtx_key != end_ptr->vrtx_key) {
temp = HUGE_WEIGHT;
for (INDEX i = 0; i <= TAIL; i++) {
if ((VERTEX_ARY[i].visited != TRUE) &&
(temp > VERTEX_ARY[i].label)) {
temp = VERTEX_ARY[i].label;
min_label_vertex = &VERTEX_ARY[i];
}

background image

AISD wer. 2 str. 71

}
shortest_dist = min_label_vertex->label;
adjacency_ptr = min_label_vertex->adj_list_hd_ptr;
label = min_label_vertex->label;
while (adjacency_ptr != NULL) {
tmp_vertex = &VERTEX_ARY[search_vertex (
adjacency_ptr->vrtx_key)];
tmp_vertex->label = label + adjacency_ptr->weight;
// Keep shortest path information for each vertex
// starting from source vertex to it
for (i = 0; i < min_label_vertex->hops; i++) {
tmp_vertex->path[i] = min_label_vertex->path[i];
}
tmp_vertex->hops = min_label_vertex->hops;
tmp_vertex->path[tmp_vertex->hops++] =
min_label_vertex->vrtx_key;
// elist_ptr = elist_ptr->next;
adjacency_ptr = adjacency_ptr->next;
} // end of while (adjacency_ptr != NULL)
min_label_vertex->visited = TRUE;
} // end of while (min_label_vertex->vrtx_key ...)
// --- Print shortest path
printf("\n %s: %2d to Vertex: %2d is: %d\n",
"Shortest Distance from Vertex", src_vrtx_key,
dst_vrtx_key, shortest_dist);
printf(" The Shortest Path is: ");
for (i = 0; i < end_ptr->hops; i++)
printf(" %d ->", end_ptr->path[i]);
printf(" %d \n", end_ptr->vrtx_key);
// --- Print number of hops in shortest path
printf(" %s: %2d to Vertex: %2d is: %d\n",
"Number of Hops from Vertex", src_vrtx_key,
dst_vrtx_key, end_ptr->hops);
}

void Wt_DiGraph::get_src_dst_vertices(
KEY_TYPE *src_vrtx_key, KEY_TYPE *dst_vrtx_key)
{
KEY_TYPE vertex1, vertex2;
int num_vertices = 0;
int try1, again;

do {
printf("\n ** To quit enter q/Q **\n");
printf(" ** To calculate shortest %s **\n\n",
"path between two Vertices");
printf(" Enter Source Vertex: ");
try1 = 0;
if (scanf("%d", &vertex1) != 1) {
try1 = 1;
exit (1);
}
// if ((vertex1 < 0) || (vertex1 >= num_vertices)) {
if ((vertex1 < 0) || (vertex1 > TAIL)) {
printf("\n Vertex ** %d ** does not exist\n",
vertex1);
exit(1);
}
getchar();

background image

AISD wer. 2 str. 72

do {
again = 0;
printf(" Enter Destination Vertex: ");
if (scanf("%d", &vertex2) != 1)
again = 1;
if ((vertex2 < 0) ||(vertex2 > TAIL)) {
printf("\n Vertex ** %d ** does not exist\n",
vertex2);
exit (1);
}
getchar();
} while (again);
} while (try1);
*src_vrtx_key = vertex1;
*dst_vrtx_key = vertex2;
}

void Wt_DiGraph::intro(void)
{
printf ("\n *** OOP IMPLEMENTATION OF %s %s %s",
"WEIGHTED DIGRAPH ***",
"\n USING LINKED ADJACENCY LIST AND",
"\n DIJKSTRAS SHORTEST PATH");
printf("\n USAGE: \n %s",
"\n You will first be prompted for number of\n");
printf(" vertices in Digraph, MAX = %d. %s \n",
MAX_VERTEX, "These will be created");
printf("%s %s %s %s %s %s %s",
" and then you will be prompted to create the\n",
" edges with corresponding distance, press n/N\n",
" for the next edge. The Weighted DiGraph will be\n",
" then printed in linearized form. And you will be\n",
" prompted for start vertex, and end vertex of\n",
" path wanted. This will be calculated and\n",
" printed in linearized form. \n");
}
void main(void)
{
Wt_DiGraph lnk_wt_digraph_obj(20);
lnk_wt_digraph_obj.intro();
if (lnk_wt_digraph_obj.build_graph()) {
lnk_wt_digraph_obj.print_graph();
lnk_wt_digraph_obj.find_shortest_path();
}
}


Wyszukiwarka

Podobne podstrony:
MATERIALY DO WYKLADU CZ V id 2 Nieznany
Materialy do wykladu (cz 1) id Nieznany
Materialy do wykladu (cz 3) id Nieznany
MATERIALY DO WYKLADU CZ V id 2 Nieznany
MATERIALY DO WYKLADU CZ VIII i Nieznany
MATERIALY DO WYKLADU CZ VIII i Nieznany
MATERIALY DO WYKLADU CZ IV id Nieznany
MATERIALY DO WYKLADU CZ III id Nieznany
MATERIALY DO WYKLADU CZ IV id Nieznany
Materialy do wykladu nr 5 id 28 Nieznany
MATERIAŁY DO WYKŁADU CZ I
MATERIAŁY DO WYKŁADU CZ. VI
Materialy do wykladu 5 (02 11 2 Nieznany
Materiały do wykładów cz. 2, AJD - PEDAGOGIKA, I rok, I semestr, Wstęp do filozofii
MATERIAŁY DO WYKŁADU CZ VII
Materialy do wykladu 1 (06 10 2 Nieznany
MATERIAŁY DO WYKŁADU CZ VI
MATERIAŁY DO WYKŁADU CZ II
materialy do wykladow w 06 Samo Nieznany

więcej podobnych podstron