Γράφοι
Διομήδης Σπινέλλης
Τμήμα Διοικητικής Επιστήμης και Τεχνολογίας
Οικονομικό Πανεπιστήμιο Αθηνών
dds@aueb.gr
Ορισμοί
- Ένας γράφος (graph) είναι ένα σύνολο από
κόμβους που ενώνονται με ακμές.
- Ο γράφος ορίζεται πλήρως από τους κόμβους και τη συνδεσμολογία τους.
- Αν οι ακμές είναι προσανατολισμένες (ορίζονται δηλαδή από διατεταγμένα
ζεύγη κόμβων) τότε ο γράφος λέγεται κατευθυνόμενος (directed).
- Αν οι ακμές δεν είναι προσανατολισμένες (ορίζονται δηλαδή από μη διατεταγμένα
ζεύγη κόμβων) τότε ο γράφος λέγεται μη κατευθυνόμενος (undirected).
- Αν οι ακμές είναι συνδεδεμένς με κάποια αξία (βάρος)
τότε ο γράφος λέγεται σταθμισμένος (weighted).
- Πλήρης (Complete) ορίζεται ο μη κατευθυνόμενος γράφος
που περιέχει ακμές που ενώνουν κάθε ζεύγος κόμβων.
- Αραιός καλείται ο γράφος που περιέχει λίγες
σχετικά ακμές (λ.χ. για ν κόμβους ο αριθμός των ακμών < ν log ν).
- Πυκνός (Dense) καλείται ο γράφος από τον οποίο
απουσιάζουν λίγες σχετικά ακμές.
Παράσταση
Ένας γράφος μπορεί εύκολα να παρασταθεί με δύο διαφορετικούς τρόπους:
- πίνακα γειτνίασης (adjacency matrix).
- λίστα γειτνίασης (adjacency list).
Και οι δύο τρόποι προϋποθέτουν ένα μονοσήμαντο σύστημα αρίθμησης των κόμβων.
Πίνακας γειτνίασης
Σε έναν γράφο με ν κόμβους ο πίνακας ν*ν γειτνίασης περιέχει 1 στις θέσεις
(κ,λ) όπου υπάρχει ακμή από τον κόμβο κ στον κόμβο λ.
Παράδειγμα για γράφο 100 κόμβων:
/*
* Adjacency matrix for a graph of 100 nodes
*/
static int adjmatrix[100][100];
main()
{
int a, b;
/* Read edges and connect them */
while (scanf(%d %d", &a, &b) == 2)
adjmatrix[a][b] = adjmatrix[b][a] = 1;
}
Λίστα γειτνίασης
Κάθε κόμβος συσχετίζεται με μια συνδεδεμένη λίστα γειτνίασης η οποία
περιέχει τα ονόματα των άλλων κόμβων με τους οποίους συνδέεται ο
συγκεκριμένος κόμβος.
Οι λίστες για όλους τους κόμβους ν μπορούν να ξεκινούν από έναν μονοδιάστατο
πίνακα μήκους ν ή από μια άλλη συνδεδεμένη λίστα.
Παράδειγμα για γράφο 10 κόμβων:
#include <stdlib.h>
#include <stdio.h>
/*
* Adjacency list for a graph of 10 nodes
*/
struct s_adjlist {
int node;
struct s_adjlist *next;
};
static struct s_adjlist *adj[10];
main()
{
int a, b;
struct s_adjlist *p;
int i;
/* Read edges and connect them */
while (scanf("%d %d", &a, &b) == 2) {
p = (struct s_adjlist *)malloc(sizeof(struct s_adjlist));
p->node = b;
p->next = adj[a];
adj[a] = p;
p = (struct s_adjlist *)malloc(sizeof(struct s_adjlist));
p->node = a;
p->next = adj[b];
adj[b] = p;
}
}
Πρόσθετοι ορισμοί
- Διαδρομή (path) καλείται μια διάταξη κόμβων οι
οποίοι ενώνονται με ακμές.
- Απλή διαδρομή (simple path) καλείται η παραπάνω
διάταξη όταν κάθε κόμβος εμφανίζεται μια μόνο φορά.
- Κύκλος (cycle) καλείται η διαδρομή δύο ή
περισσοτέρων κόμβων που καταλήγει στον κόμβο αρχής.
- Απόσταση (distance) μεταξύ δύο κόμβων καλείται
το μήκος της συντομότερης διαδρομής που τους ενώνει.
- Διαδρομή Euler (Euler path) καλείται η διαδρομή
ή οποία περνάει από όλες τις ακμές του γράφου ακριβώς μια φορά.
- Διαδρομή Hamilton (Hamilton path) καλείται η διαδρομή
ή οποία περνάει από όλους τους κόμβους του γράφου ακριβώς μια φορά.
- Γράφοι που περιέχουν τις παραπάνω διαδρομές ονομάζονται αντίστοιχα.
- Συνεκτικός (connected) ονομάζεται ο γράφος για τον
οποίο υπάρχει διαδρομή από κάθε κόμβο σε κάθε άλλο κόμβο.
- Βαθμός ενός κόμβου σε έναν μη κατευθυνόμενο γράφο καλείται ο αριθμός
των συνδεδεμένων με αυτόν ακμών.
- Βαθμός εισόδου (in-degree) σε έναν κατευθυνόμενο
γράφο καλείται ο αριθμός των ακμών που καταλήγουν σε αυτόν.
- Βαθμός εξόδου (out-degree) σε έναν κατευθυνόμενο
γράφο καλείται ο αριθμός των ακμών που ξεκινούν από αυτόν.
- Υπογράφος (subgraph) Β ενός γράφου Α καλείται ο
γράφος του οποίου όλες οι ακμές και οι κόμβοι περιέχονται στον Α.
- Δένδρο σκελετός (spanning tree) ενός γράφου καλείται
ο υπογράφος που περιέχει όλους του κόμβους αλλά μόνο όσες ακμές απαιτούνται
για να σχηματιστεί δένδρο.
Προτάσεις σε συνεκτικούς μη κυκλικούς γράφους
Οι παρακάτω προτάσεις είναι ισοδύναμες για πεπερασμένους γράφους με ν > 0
κόμβους:
- Ο γράφος Γ είναι συνεκτικός και μη κυκλικός.
- Αν διαγραφεί οποιαδήποτε ακμή ο γράφος θα πάψει να είναι συνεκτικός.
- Δύο διαφορετικοί κόμβοι συνδέονται από μια και μόνο μια απλή διαδρομή.
- Ο γράφος είναι μη κυκλικός και περιέχει ν - 1 ακμές.
- Ο γράφος είναι συνεκτικός και περιέχει ν - 1 ακμές.
Ψάξιμο κατά βάθος
Για να επισκευθούμε όλους τους κόμβους ενός γράφου με ν κόμβους χρειαζόμαστε
έναν πίνακα λογικών μεταβλητών μιας διάστασης και μήκους ν ο οποίος περιέχει
την τιμή "αληθές" για τους κόμβους τους οποίους έχουμε επισκευθεί.
Η συστηματική επίσκεψη όλων των κόμβων γίνεται σύμφωνα με τα παρακάτω
βήματα:
- Φυλάμε την τιμή "ψευδές" στον πίνακα επισκέψεων.
- Επισκεπτόμαστε όλους τους κόμβους που δεν έχουμε επισκευτεί.
Η επίσκεψη ενός κόμβου γίνεται σύμφωνα με τα παρακάτω βήματα:
- Σημειώνουμε στον πίνακα ότι έχουμε επισκευθεί τον κόμβο.
- Επισκεπτόμαστε όλους τους συνδεδεμένους κόμβους που δεν έχουμε επισκευθεί.
Το παρακάτω παράδειγμα περιέχει υλοποίηση για λίστα γειτνίασης:
#include <stdlib.h>
#include <stdio.h>
/*
* Adjacency list for a graph of 10 nodes
*/
struct s_adjlist {
int node;
struct s_adjlist *next;
};
static struct s_adjlist *adj[10];
static int visited[10];
/*
* Visit the nodes starting from node printing their value using
* depth first search
*/
static void
visit(int node)
{
struct s_adjlist *p;
visited[node] = 1;
printf("%d\n", node);
for (p = adj[node]; p != NULL; p = p->next)
if (!visited[p->node])
visit(p->node);
}
main()
{
int a, b;
struct s_adjlist *p;
int i;
/* Read edges and connect them */
while (scanf("%d %d", &a, &b) == 2) {
p = (struct s_adjlist *)malloc(sizeof(struct s_adjlist));
p->node = b;
p->next = adj[a];
adj[a] = p;
p = (struct s_adjlist *)malloc(sizeof(struct s_adjlist));
p->node = a;
p->next = adj[b];
adj[b] = p;
}
/* Depth first search/print of the graph */
for (i = 0; i < 10; i++)
visited[i] = 0;
for (i = 0; i < 10; i++)
if (!visited[i])
visit(i);
}
Αν το πρόγραμμα διαβάσει το γράφο:
2 3
3 8
8 6
4 9
θα τυπώσει την παρακάτω σειρά επίσκεψης:
0
1
2
3
8
6
4
9
5
7
Εφαρμογές
- Παράσταση διασυνδέσεων ανάμεσα σε αντικείμενα
- Ταξίδια ανάμεσα σε πόλεις
- Συνδέσεις υπολογιστών σε δίκτυο
- Συνδέσεις σελίδων σε υπερκείμενο
- Ανθρώπινες σχέσεις
- Παράσταση ηλεκτρονικών διαγραμμάτων
- Προγραμματισμός εργασιών
Βιβλιογραφία
- Χρήστος Κοίλιας
Δομές Δεδομένων και Οργανώσεις Αρχείων. σ. 98-105
Εκδόσεις Νέων Τεχνολογιών, 1993.
- Alfred V. Aho, John E.
Hopcroft, and Jeffrey D. Ullman.
The
Design and Analysis of Computer Algorithms, pages 172–309.
Addison-Wesley, 1974.
- Alfred V. Aho, John E.
Hopcroft, and Jeffrey D. Ullman.
Data Structures and Algorithms, pages 198–252.
Addison-Wesley, 1983.
- Donald E. Knuth.
The Art of Computer Programming, volume 1 / Fundamental
Algorithms, pages 362–378.
Addison-Wesley, second edition, 1973.
- Robert Sedgewick.
Algorithms in C, pages 415–508.
Addison-Wesley, 1990.