INFO0902 – Data Structures and Algorithms Concepts et définitions

publicité
INFO0902 – Data Structures and
Algorithms
Graphes
Justus H. Piater
Concepts et définitions
Graphe
Définition : Un graphe est (ici) un ensemble
de nœuds (vertices) et un ensemble de paires
d’éléments de , les arêtes (edges).
Deux nœuds liés par une arête sont adjacents.
Le degré d’un nœud est le nombre des arêtes
incidentes.
Exemples ?
Concepts et définitions
3 / 40
Graphes orientés
Une arête peut être orientée (directed) ou non.
Un graphe est orienté si toutes les arêtes sont
orientées.
Une arête orientée a une origine et une destination.
Un nœud peut avoir des arêtes entrantes et des
arêtes sortantes.
Exemples ?
Concepts et définitions
4 / 40
Propriétés basiques
Proposition : Si
alors
est un graphe avec
arêtes,
.
Proposition : Si
est un graphe orienté avec
arêtes, alors
.
Proposition : Soit un graphe simple avec
nœuds et
arêtes. Le nombre des arêtes est
: Si
est non-orienté, alors
; si est orienté,
alors
.
Concepts et définitions
5 / 40
Graphes pondérés
Les arêtes sont annotées d’une étiquette numérique,
son poids.
Exemples ?
BOS
2704
867
187
SFO
1846
PVD
849
ORD
337
1464
144
740
802
621
JFK
1258
184
1235
DFW
1391
BWI
1121
LAX
964
1090
2342
MIA
Concepts et définitions
6 / 40
TDA, SDD et algorithmes basiques
TDA graphe
Vertices vertices(void);
Edges edges(void);
Edges incidentEdges(Vertex v);
Vertex opposite(Vertex v, Edge e);
Array endVertices(Edge e);
Boolean areAdjacent(Vertex v, Vertex w);
Object replace(Vertex v, Object o);
Object replace(Edge e, Object o);
Vertex insertVertex(Object o);
TDA, SDD et algorithmes basiques
8 / 40
TDA graphe (suite)
Edge insertEdge(Vertex v, Vertex w, Object o);
Object removeVertex(Vertex v);
Object removeEdge(Edge e);
TDA, SDD et algorithmes basiques
9 / 40
Structure de liste des arêtes
Deux conteneurs
Nœud :
et :
• une référence vers sa propre position (ou entrée)
dans
• une référence vers les données
Arête :
• une référence vers sa propre position (ou entrée)
dans
• une référence vers les données
• deux références vers les nœuds connectés
Regardons un exemple…
Complexité en espace ?
Complexité en temps des méthodes ?
TDA, SDD et algorithmes basiques
10 / 40
Structure de liste des adjacences
Pour éviter le parcours de toutes les arêtes, on
représente les incidences explicitement :
Incidence :
• une référence vers l’arête incidente
Au nœud on ajoute une référence vers le conteneur
des incidences sur .
À l’arête connectant et on ajoute deux références
vers les incidences associées à dans
et
.
Regardons un exemple…
Complexité en espace ?
Complexité en temps des méthodes ?
TDA, SDD et algorithmes basiques
11 / 40
Structure de matrice des adjacences
Pour déterminer les adjacences entre deux nœuds en
temps constant, on ajoute à la structure de liste des
arêtes une matrice des adjacences :
Matrice des adjacences :
• une matrice
dont l’élément
contient une
référence vers l’arête correspondante (ou nulle si elle
n’existe pas).
À chaque nœud on ajoute un indice (clé) entre
et
.
Regardons un exemple…
Complexité en espace ?
Complexité en temps des méthodes ?
TDA, SDD et algorithmes basiques
12 / 40
Parcours en profondeur
• un fil (comme l’utilisa Thésée pour sortir du
labyrinthe)
• de la peinture (comme Thésée aurait pû l’utiliser
pour trouver le Minotaure plus vite)
Algorithm DFS( , ):
Input: A graph and a vertex of .
Output: A labeling of the edges in the connected component
of as discovery edges and back edges.
label as visited
foreach in .incidentEdges( ) do
if is unvisited then
.opposite( , )
if is unexplored then
label as a discovery edge
DFS( , )
else
label as a back edge
TDA, SDD et algorithmes basiques
13 / 40
Un exemple
TDA, SDD et algorithmes basiques
A
B
C
D
E
F
G
H
I
J
K
L
M
N
O
P
14 / 40
Parcours en profondeur : propriétés
Proposition : Les arêtes de découverte forment un
arbre couvrant.
À prouver :
• Tous les nœuds sont atteints.
• Les arêtes de découverte ne forment aucun cycle.
Temps de calcul ? Exigences aux structures de
données ?
TDA, SDD et algorithmes basiques
15 / 40
Parcours en largeur
Avancer par « couches » de distance constante du
nœud de départ
Regardons un exemple…
TDA, SDD et algorithmes basiques
16 / 40
Parcours en largeur (suite)
Algorithm BFS( , ):
Input: A graph and a vertex of .
Output: A labeling of the edges in the connected component
of as discovery edges and cross edges.
label as visited; insert it into container
while is not empty do
create empty container
foreach in do
foreach in .incidentEdges( ) do
if is unexplored then
.opposite( , )
if is unexplored then
label as a discovery edge
label as visited; insert it into
else
label as a cross edge
TDA, SDD et algorithmes basiques
17 / 40
Parcours en largeur : propriétés
Proposition : Les arêtes de découverte forment un
arbre couvrant.
Les conteneurs contiennent les nœuds des plus
courts chemins de longueur à partir de .
Temps de calcul ? Exigences aux structures de
données ?
TDA, SDD et algorithmes basiques
18 / 40
Implémentation
Comment attacher des attributs (visited, discovery
edge, back edge, cross edge) aux nœuds et arêtes :
• Prévoir un champ explored ?
• Table de hashage externe ?
Le design pattern décorable : attacher une application
à (ici) la position.
Object element(void);
Object get(Object key);
Object put(Object key, Object value);
Object remove(Object key);
Entries entries(void);
TDA, SDD et algorithmes basiques
Plus courts chemins – Dijkstra
19 / 40
Plus courts chemins (shortest paths)
La longueur ou le poids d’un chemin
des poids des arêtes de :
est la somme
.
La distance
d’un nœud à un nœud est la
longueur d’un plus court chemin (chemin de poids
minimal) de à , ou
.
Note
Attention aux poids négatifs – un plus court chemin
n’est pas défini pour un cycle de poids négatif !
Comment trouver les plus courts chemins d’un
nœud désigné vers tous les autres nœuds si
pour tous les ?
Plus courts chemins – Dijkstra
21 / 40
L’algorithme de Dijkstra
Pour trouver les plus courts chemins (ici non orientés)
d’un nœud désigné vers tous les autres nœuds d’un
graphe (arbre des plus courts chemins) – single-source
shortest paths (shortest-path tree)
•
• méthode gloutonne : recherche « pondérée » en
largeur
Plus courts chemins – Dijkstra
22 / 40
Survol
dénote la longueur du plus court chemin de
trouvé jusqu’à présent.
1.
2.
3.
, et
pour
« nuage » de nœuds
Répéter :
a.
b.
Choisir
de
à
.
minimale, et l’ajouter à
Relaxation : pour tous les
mettre à jour
.
.
voisins de ,
Regardons un exemple…
Plus courts chemins – Dijkstra
23 / 40
Algorithme
Algorithm DijkstraShortestPaths( , ):
Input: A simple, undirected, weighted graph
with nonnegative edge weights, and
a distinguished vertex of .
Output: A label
for each vertex of
that gives the distance from to in .
foreach vertex
of
do
Let be a PQ containing all
using the
while is not empty do
.removeMin()
foreach vertex
adjacent to do
if
then
Update
as keys.
accordingly
Plus courts chemins – Dijkstra
24 / 40
Correction
Proposition : Quand un nœud
insertion dans ,
.
est choisi pour
Preuve (par contradiction) : Soit
•
le premier nœud choisi avec
(l’impossibilité de
est facilement prouvée
par construction),
• le plus court chemin de à ,
• le dernier nœud de dans ,
• son successeur (le premier nœud de pas dans ).
Alors,
Plus courts chemins – Dijkstra
25 / 40
Correction (suite)
Puisque est le prochain nœud choisi,
Puisque est dans ,
implique que
.
, ce qui
ce qui contredit notre définition de .
Plus courts chemins – Dijkstra
26 / 40
Temps d’exécution
Pour l’algorithme, il faut préciser les structures de
données et leurs implémentations.
PQ adaptable avec localisateur basée
tas : Temps total de la boucle while :
d’après notre proposition.
PQ basée séquence non triée : puisque est simple.
Plus courts chemins – Dijkstra
27 / 40
Remarques
• L’algorithme de Dijkstra s’adapte facilement aux
graphes orientés.
• L’algorithme de Bellman-Ford est
et fonctionne
en présence de poids négatifs (orientés) dans le
graphe.
Plus courts chemins – Dijkstra
28 / 40
Arbres couvrants minimaux
Arbres couvrants minimaux
(minimum spanning trees)
P.ex., pour connecter un ensemble d’ordinateurs entre
eux avec un minimum de cablage :
Pour un graphe
minimise
Arbres couvrants minimaux
, trouver un arbre
qui
.
30 / 40
Une propriété clé des ACMs
Proposition : Soient
•
•
un graphe pondéré et connexe,
et
une partition de
disjoints et non vides,
en deux ensembles
•
une arête de poids minimal parmi celles connectant
et .
Alors fait partie d’un arbre couvrant minimal.
Preuve (par construction) : Soit un ACM ne
comportant pas . On l’ajoute alors à , ce qui crée
un cycle dont et une arête connectent
et .
Puisque (par le choix de )
, on peut recréer
un ACM en supprimant .
Arbres couvrants minimaux
31 / 40
Une propriété clé des ACMs (suite)
Note
Cette proposition est vraie même en présence de
poids négatifs.
Arbres couvrants minimaux
32 / 40
L’algorithme de Kruskal
Regardons un exemple.
Algorithm KruskalMST( ):
Input: A simple, connected, weighted graph
with vertices and
edges.
Output: A minimum spanning tree for .
foreach
do
define an elementary cluster
Initialize a PQ containing all
with weights as keys.
while
has fewer than
edges do
.removeMin()
Let
,
be the clusters containing , .
if
then
Add
to .
Merge
and
.
Arbres couvrants minimaux
33 / 40
L’algorithme de Kruskal (suite)
Note
Sa correction est une conséquence de la proposition
précédente.
Arbres couvrants minimaux
34 / 40
Temps d’exécution
Pour l’algorithme, il faut préciser les structures de
données et leurs implémentations :
• Arêtes dans une file de priorité basé tas : prochaine
arête en
• Nœuds d’un groupe dans une liste non triée stockés
avec une référence vers son propre groupe ; fusion
par l’ajout du plus petit groupe au plus grand :
en
, temps total de
pour les
fusions (voir le transparent prochain)
Le temps total de Kruskal est
.
Arbres couvrants minimaux
35 / 40
Fusion des groupes des nœuds
Proposition : Pour un graphe avec nœuds,
l’algorithme de Kruskal prend un temps total de
pour fusionner tous les groupes.
Preuve : À chaque fusion, la taille du cluster ajouté
est multipliée par deux au moins. Soit
le nombre
de fois un nœud est ajouté à un autre groupe. Alors,
. Le temps maximal total pour tous les nœuds
est donc proportionnel à
Arbres couvrants minimaux
.
36 / 40
L’algorithme de Prim-Jarník
Algorithm PrimJarníkMST( ):
Input: A simple, connected, weighted graph
with vertices and
edges.
Output: A minimum spanning tree for .
Pick any vertex of
foreach vertex
do
Initialize a PQ with keys
, elements
while is not empty do
.removeMin()
Add vertex , edge to
foreach vertex
adjacent to do
if
then
Change to
Change to
the element of
the key of in
null
in
Arbres couvrants minimaux
37 / 40
Prim-Jarník : remarques
Regardons un exemple.
Il s’agit d’une variation simple de l’algorithme de
Dijkstra ; son implémentation est un peu plus simple
que celui de Kruskal.
Temps d’exécution ?
Arbres couvrants minimaux
38 / 40
Résumé
Graphes
• Structures de données : liste des arêtes, liste des
adjacences, matrice des adjacences
• Parcours en profondeur et en largeur
• Plus courts chemins : Dijkstra
• Arbres couvrants minimaux : Kruskal et Prim-Jarník
Résumé
40 / 40
Téléchargement