Skip to main content Informatique en prépa - Lycée Malherbe 

12- Graphes

Les graphes sont une manière, en informatique, de représenter des données avec des liens. Par exemple (on appellera ce graphe le graphe 1) :

A A B B A--B C C A--C E E A--E B--C D D B--D D--E

I. Présentation générale

Définition : graphe

Un graphe est un couple , où est un ensemble fini de sommets (ou nœuds) et est l'ensemble des arêtes. Chaque arête relie deux sommets distincts.

On dit que le graphe est orienté si les arêtes ont un sens ("que ce sont des flèches"). On les appelle alors souvent des arcs.

Définition : voisin

Si on a une arête , on dit que est un voisin de .

Par exemple, dans le graphe orienté suivant (le graphe 2), les voisins de H sont J et I.

G G H H G->H I I G->I K K G->K H->I J J H->J I->G J->H J->K K->H L L
Définition : degré d'un sommet

Dans un graphe non orienté, le degré d'un sommet , noté , est le nombre d'arêtes qui le touchent.

Dans un graphe orienté, on note le degré sortant et le degré entrant, qui sont respectivement le nombre d'arcs qui partent de et qui arrivent en .

Par exemple :

II. Chemins, cycles et connexité

Définition : chemin

Un chemin dans un graphe est une suite finie d'arêtes consécutives .

On parle de chemin élémentaire lorsque les sommets sont distincts, et de chemin simple lorsque les arêtes sont distinctes (ces mots de vocabulaire ne sont pas exigibles).

Par exemple, AB, BD, DE est un chemin :

A A B B A--B C C A--C E E A--E B--C D D B--D D--E
Définition : cycle

Un cycle est un chemin simple dont le premier et le dernier sommet sont les mêmes.

Par exemple, HI, IG, GK, KH est un cycle :

G G H H G->H I I G->I K K G->K H->I J J H->J I->G J->H J->K K->H L L
Définition : connexité

Un graphe non orienté est connexe si, pour tous sommets , il existe un chemin de à .

Le graphe 1 est connexe. En revanche, le graphe suivant n'est pas connexe :

A A B B A--B C C

La notion de connexité est hors-programme pour les graphes orientés. Pour donner une idée, on parlera de graphe fortement connexe si, pour tous sommets , il existe un chemin de à et de à .

III. Représentation informatique

Il y a plusieurs manières de représenter les graphes en Python. On va en voir deux principales.

a) Représentation par liste d'adjacence

L'idée ici est de stocker, pour chaque sommet, l'ensemble de ses voisins. Dans le cas des graphes non orientés, on stockera en général les connexions dans les deux sens.

Par exemple, pour le graphe 1, la liste d'adjacence du sommet A est :

['B', 'C', 'E']

Ensuite, on va regrouper toutes ces listes d'adjacence dans un dictionnaire, pour avoir la représentation suivante :

Python

Loading editor...

g = {
    'A': ['B', 'C', 'E'],
    'B': ['A', 'C', 'D'],
    'C': ['A', 'B'],
    'D': ['B', 'E'],
    'E': ['A', 'D']
}

La fonction afficher_graphe (du module affichage du site) dessine un graphe donné par listes d'adjacence :

Python

Loading editor...

from affichage import afficher_graphe

afficher_graphe(g)
print(g['B'])        # les voisins de B
print(len(g['B']))   # le degré de B

Faites la même chose avec le graphe 2.

Python

Loading editor...

g = {
    'G': ['H', 'I', 'K'],
    'H': ['I', 'J'],
    'I': ['G'],
    'J': ['K', 'H'],
    'K': ['H'],
    'L': []
}

Dans le cas où les sommets sont numérotés de à , on peut utiliser une liste à la place d'un dictionnaire.

La représentation par liste d'adjacence est très adaptée lorsqu'on veut souvent accéder aux voisins d'un sommet particulier, par exemple lors d'une exploration du graphe.

b) Matrice d'adjacence

Dans le cas de la matrice d'adjacence, on va toujours numéroter les sommets de à .

On va alors se donner une matrice de taille , et à la position , on va placer si l'arête existe, et sinon.

Dans le cas du graphe 1 (avec les sommets A, B, C, D, E numérotés de 0 à 4) :

Python

Loading editor...

g = [[0, 1, 1, 0, 1],
     [1, 0, 1, 1, 0],
     [1, 1, 0, 0, 0],
     [0, 1, 0, 0, 1],
     [1, 0, 0, 1, 0]]
Python

Loading editor...

print(g[0][1])   # 1 : il y a une arête entre A (0) et B (1)
print(g[2][3])   # 0 : il n'y en a pas entre C (2) et D (3)
print(sum(g[1])) # le degré de B

La matrice d'adjacence d'un graphe non orienté est symétrique.

Faites la même chose avec le graphe 2.

Python

Loading editor...

Avec les sommets G, H, I, J, K, L numérotés de 0 à 5 :

g = [[0, 1, 1, 0, 1, 0],
     [0, 0, 1, 1, 0, 0],
     [1, 0, 0, 0, 0, 0],
     [0, 1, 0, 0, 1, 0],
     [0, 1, 0, 0, 0, 0],
     [0, 0, 0, 0, 0, 0]]

La représentation par matrice d'adjacence est adaptée lorsqu'on a souvent besoin de tester si deux sommets sont adjacents.

IV. Pondération

a) Applications

Les graphes se retrouvent un peu partout en informatique :

Dans tous ces exemples, des algorithmes sur les graphes (on en étudiera quelques-uns) sont utilisés. Par exemple, la recherche d'itinéraire de votre appli de carte préférée, le programme qui décide comment acheminer votre message WhatsApp, ou encore les moteurs de recherche (Google).

Dans beaucoup de ces applications, toutes les arêtes ne sont pas égales. Par exemple, un trajet en train peut prendre deux fois plus longtemps qu'un autre.

b) Graphes pondérés

Pour représenter ces différences, on va introduire la pondération.

Définition : graphe pondéré

Un graphe pondéré est un graphe , orienté ou non, auquel on associe une fonction de pondération qui associe un poids (ou étiquette) à chaque arête.

est ici un ensemble quelconque, mais en pratique, ce sera souvent ou .

Voici par exemple quelques villes et le temps de trajet en train entre elles :

Caen Caen Paris Paris Caen--Paris 2 Rennes Rennes Caen--Rennes 3.5 Tours Tours Caen--Tours 3 Paris--Tours 1.3 Lyon Lyon Paris--Lyon 2 Rennes--Paris 2 Tours--Lyon 3

Quels sont les chemins possibles entre Caen et Lyon ? Quel est leur poids ?

On peut alors parler du poids d'un chemin, d'un cycle, etc. : c'est la somme des poids de ses arêtes.

c) Implémentation des graphes pondérés

Liste d'adjacence : on peut stocker les poids directement dans la liste d'adjacence, en mettant des couples (voisin, poids) au lieu des simples voisins :

Python

Loading editor...

g = {
    'Caen': [('Rennes', 3.5), ('Tours', 3.0), ('Paris', 2.0)],
    'Rennes': [('Caen', 3.5), ('Paris', 2.0)],
    'Paris': [('Caen', 2.0), ('Rennes', 2.0), ('Tours', 1.3), ('Lyon', 2.0)],
    'Tours': [('Caen', 3.0), ('Paris', 1.3), ('Lyon', 3.0)],
    'Lyon': [('Paris', 2.0), ('Tours', 3.0)]
}
Python

Loading editor...

afficher_graphe(g)
for (voisin, poids) in g['Caen']:
    print("De Caen à", voisin, ":", poids, "h")

Matrice d'adjacence : on peut mettre le poids de l'arête à la place de , et utiliser une valeur qui n'est pas dans les poids à la place de (par exemple , ou, si ce n'est pas une option, ). Ici, les sommets sont numérotés dans l'ordre Caen, Rennes, Paris, Tours, Lyon.

Python

Loading editor...

g = [[-1.0, 3.5, 2.0, 3.0,-1.0],
     [ 3.5,-1.0, 2.0,-1.0,-1.0],
     [ 2.0, 2.0,-1.0, 1.3, 2.0],
     [ 3.0,-1.0, 1.3,-1.0, 3.0],
     [-1.0,-1.0, 2.0, 3.0,-1.0]]

Exercices

Exercice 1

Écrire une fonction nb_aretes(g) qui renvoie le nombre d'arêtes d'un graphe non orienté donné par listes d'adjacence (un dictionnaire).

Python

Loading editor...

Chaque arête apparaît dans les listes d'adjacence de ses deux extrémités :

def nb_aretes(g):
    total = 0
    for s in g:
        total += len(g[s])
    return total // 2
Exercice 2

Écrire une fonction matrice_vers_listes(M) qui convertit la matrice d'adjacence d'un graphe (sommets numérotés de 0 à ) en une liste de listes d'adjacence.

Python

Loading editor...

def matrice_vers_listes(M):
    n = len(M)
    return [[j for j in range(n) if M[i][j] == 1] for i in range(n)]
Exercice 3

Écrire une fonction degre_max(g) qui renvoie un sommet de degré maximal d'un graphe non orienté (dictionnaire de listes d'adjacence). Le tester sur le graphe 1.

Python

Loading editor...

def degre_max(g):
    meilleur = None
    for s in g:
        if meilleur is None or len(g[s]) > len(g[meilleur]):
            meilleur = s
    return meilleur

Sur le graphe 1, on trouve 'A' (degré 3 ; 'B' a aussi le degré 3).