Remarque : Il est possible d'affecter des valeurs, des poids (coefficients positifs), des couleurs, etc... aux arêtes (le plus souvent) ou bien aux sommets (parfois) : on parle de graphe valué. Ces valeurs peuvent indiquer des distances, des coûts, etc. Pour être plus précis, on peut utiliser les termes graphes pondérés pour un graphe valué par des nombres et graphe étiqueté pour un graphe valué par des chaînes de caractères.


Un peu de vocabulaire pour fixer ces notions :


Les parcours de graphes étant particulièrement importants, il faut connaître leur vocabulaire :
Dans un graphe connexe :

 
                
      Pour un graphe donné, on associe à chaque sommet
      la liste de ses voisins (sommets adjacents). Dans le cas
      d'un graphe orienté, on peut aussi parler de «liste de successeurs»
      (flèches partant du sommet considéré) ; dans le cas orienté, on peut aussi
      considérer la «liste de prédécesseurs» (flèches arrivant au sommet
      considéré). 
      Lorsque le graphe est valué, on associe à chaque sommet une liste de
      tuples (voisin, dictionnaire), où les clés du dictionnaire (poids,
      couleur) permettent d'accéder à la/les donnée(s) figurant sur l'arête. Si
      on utilise une seule donnée, le dictionnaire n'est pas nécessaire : on le
      remplace dans le tuple directement par cette seule donnée.
    

{A:[B,D,E],
 B:[A,E],
 C:[D,E],
 D:[A,C],
 E:[A,B,C]}

{A:[B,E],
 B:[E],
 C:[D,E],
 D:[A],
 E:[]} 

{A:[(B,1), (E,2)],
 B:[(E,2)],
 C:[(D,1), (E,3)],
 D:[(A,3)],
 E:[]}
 
                
      La matrice d'adjacence est un tableau carré (à double
      entrée). Les lignes et les colonnes correspondent aux sommets (ordonnés
      dans l'ordre alphanumérique si rien n'est précisé). 
      Si le sommet X et adjacent à Y (X-->Y), on remplit dans la matrice, à
      l'intersection de la ligne de X et de la colonne de Y, un 1 (ou un V pour
      «vrai»), ou bien une donnée si le graphe est valué (il y aura alors une
      matrice d'adjacence selon chaque type de donnée). S'il n'y a pas de
      relation entre X et Y, on note un 0 (ou un F pour «faux»).
      Lorsque le graphe n'est pas orienté, la matrice d'adjacence est symétrique
      par rapport à sa diagonale (diagonale principale : de en haut à gauche à
      en bas à droite) ; aussi, les boucles apparaissent sur la diagonale.
    

[ [0, 1, 0, 1, 1], [1, 0, 0, 0, 1], [0, 0, 0, 1, 1], [1, 0, 1, 0, 0], [1, 1, 1, 0, 0] ]

[ [0, 1, 0, 0, 1],
  [0, 0, 0, 0, 1],
  [0, 0, 0, 1, 1],
  [1, 0, 0, 0, 0],
  [0, 0, 0, 0, 0] ] 
      

[ [0, 1, 0, 0, 2], [0, 0, 0, 0, 2], [0, 0, 0, 1, 3], [3, 0, 0, 0, 0], [0, 0, 0, 0, 0] ]
[ [0, 1, 0, 1, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0], [1, 0, 0, 1, 0, 0, 0], [0, 1, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 1, 0, 1] ]
 
                creer_graphe construit un graphe vide, non-orienté par défaut et
              orienté si le booléen ori est vrai.est_oriente : renvoie vrai lorsque le graphe est orienté.ajouter_sommet : ajoute un sommet s au graphe G . sommet_existe : renvoie vrai lorsque le sommet s est dans G.ajouter_arc : ajoute un arc de poids w entre les sommets sa et
              sd au graphe G. (Pour un graphe non-pondéré, w peut valoir par défaut 1.) w : sd → sa et sa → sd.arc_existe : renvoie vrai lorsque l'arc entre sa et sd est dans G.supprimer_sommet : enlève un sommet s de G et supprime aussi ses
              arcs incidents.supprimer_arc : enlève les arcs entre les sommets sa et sd.| Graphe | 
|---|
| creer_graphe(ori) : vide | 
| est_oriente(G) : booléen | 
| ajouter_sommet(G, s) [sommet pas encore dans G] : vide | 
| sommet_existe(G, s) : booléen | 
| ajouter_arc(G, sd, sa, w) [sa et sd sont dans G, l'arc pas encore] : vide | 
| arc_existe(G, sd, sa) : booléen | 
| supprimer_sommet(G, s) [s est dans G] : vide | 
| supprimer_arc(G, sd, sa) [sa et sd sont dans G] : vide | 
voisins(G, s) qui retourne la liste des voisins du sommet s dans G.
    
voisins_poids(G, s) qui retourne une liste de tuples (v, p) avec les voisins d'un sommet s et le poids de l'arête.
liste_adj qui retourne la liste d'adjacence et matrice_adj qui retourne la matrice d'adjacence du graphe.
L'algorithme de parcours en largeur (ou BFS, pour Breadth First Search en anglais) permet le parcours d'un graphe ou d'un arbre de la manière suivante : on commence par explorer un nœud source, puis ses successeurs, puis les successeurs non-explorés des successeurs, etc. L'algorithme de parcours en largeur permet de calculer les distances de tous les nœuds depuis un nœud source dans un graphe non-pondéré (orienté ou non-orienté). Il peut aussi servir à déterminer si un graphe non-orienté est connexe.
Pseudo code : L'algorithme s'implémente à l'aide d'une file.
ParcoursLargeur(Graphe G, Sommet s)
    f = CreerFile()
    f.enfiler(s)
    marquer(s)
    tant que la file est non-vide
        s = f.defiler()
        afficher(s)
        pour tout voisin t de s dans G
            si t non-marqué
                f.enfiler(t)
                marquer(t)            Complexité : La complexité en temps dans le pire cas est en `O( | S | + | A | )` où `| S |` est le nombre de sommets et `| A |` est le nombre d'arcs. En effet, chaque arc et chaque sommet est visité au plus une seule fois.
Graphe déjà
        construite.
      L'exploration d'un parcours en profondeur depuis un sommet S fonctionne
      comme suit : on suit un chemin dans le graphe jusqu'à un cul-de-sac ou
      alors jusqu'à atteindre un sommet déjà visité. On revient alors sur le
      dernier sommet où on pouvait suivre un autre chemin puis on explore un
      autre chemin. L'exploration s'arrête quand tous les sommets depuis S ont
      été visités. Bref, l'exploration progresse à partir d'un sommet S en
      s'appelant récursivement pour chaque sommet voisin de S. 
      Le nom d'algorithme en profondeur est dû au fait que, contrairement à
      l'algorithme de parcours en largeur, il explore en fait « à fond » les
      chemins un par un : pour chaque sommet, il marque le sommet actuel, et il
      prend le premier sommet voisin jusqu'à ce qu'un sommet n'ait plus de
      voisins (ou que tous ses voisins soient marqués), et revient alors au
      sommet père. 
      Si G n'était pas un arbre, l'algorithme pourrait a priori tourner
      indéfiniment si on continuait l'exploration depuis un sommet déjà visité.
      Pour éviter cela, on marque les sommets que l'on visite, de façon à ne pas
      les explorer à nouveau. Dans le cas d'un arbre, le parcours en profondeur
      est utilisé pour caractériser l'arbre.
    
explorer(graphe G, sommet s)
    marquer le sommet s
    afficher(s)
    pour tout sommet t voisin du sommet s
        si t n'est pas marqué alors
              explorer(G, t);
                   
parcoursProfondeur(graphe G, sommet s)
    pour tout sommet du graphe G en partant du sommet s
        si s n'est pas marqué alors
              explorer(G, s)            Graphe déjà construite.
      
set pour désigner une composante connexe. Graphe déjà
        construite. Chaque composante sera représentée par la liste de ses sommets.
      
      Ces algorithmes sont utilisés pour traiter des problèmes d'optimisation (transports, câblage électrique ou réseau, déplacements de pnj dans un jeu vidéo, ...).
Illustration de ces algorithmes sur une carte réelle avec : Pathfinding.

Graph déjà construite. 
        Conseils : 
        
        Définir deux fonctions :
        def dijkstra(self, sd): Pour créer le tableau de l'
arbre couvrant (arbre qui recouvre tous les sommets d'un graphe) issu du sommet de départdef chemin_dijkstra(self, sd, sa): Pour extraire le plus court chemin de ce tableau.Le principe doit être vu à titre culturel et peut être travaillé comme approfondissement.
On pourra à ce titre consulter l'article : A*.

import networkx as nxnx est souvent l'abréviation consacrée).
pip install networkx ou bien pip3 install networkx.
                Graphe que nous avons implémentée est petite en regard des 4 classes de graphes (Graph, DiGraph, MultiGraph, MultiDiGraph) utilisés par networkx. Dans un premier temps, on peut remarquer que créer une arête crée aussi les sommets mentionnés, même s'ils ne sont pas présents dans le graphe.            #!/usr/bin/env python
# -*- coding: utf-8 -*-
import matplotlib.pyplot as plt   # pour les dessins
import networkx as nx
# Créer un objet graphe (Graph)
G = nx.Graph()
# G = nx.DiGraph()   # pour les graphes orientés
# G = nx.MultiGraph() # avec arêtes parallèles
# G = nx.MultiDiGraph() # avec arêtes parallèles orientées
# Ajouter un sommet / une arête (tout objet hashable sauf None) :
G.add_node("A")
G.add_edge("A", "B")  # le sommet "B" est ajouté directement
# Ajouter depuis un conteneur plusieurs sommets/arêtes (ici : list, aussi : dict, set, Graph, fichier, ...)
G.add_nodes_from(["B", "C", "D"])
G.add_edges_from([("B", "C"), ("C", "D"), ("A", "C"), ("E","E")])
# On peut ajouter des étiquettes { : } sur les arêtes :
# (début, fin, {clé : valeur} )
G.add_edges_from([("A", "E", {"info": 7}), ("B", "E", {"info": 8})])
print("sommets : \n", G.nodes())
print("triés : \n", sorted(G.nodes(), key=str))
print("nombre de sommets : \n",G.number_of_nodes())
print("arêtes : \n", G.edges(data=True))
print("nombre d'arêtes : \n", G.number_of_edges())
print("plus court chemin : \n", nx.shortest_path(G, "A", "D"))
print("distance : \n", nx.shortest_path_length(G, "A", "D"))
print("Diamètre : \n", nx.diameter(G))
print("Rayon : \n", nx.radius(G))
print("Centre : \n", nx.center(G))
print("accès à une étiquette : \n", G["A"]["E"]["info"])
# G[u][v]['width'] est identique à G.edges[u, v]['width']
# print("vue selon les étiquettes : \n", [G.edges.data("info")])
# print("liste des voisins d'un sommet : \n",[item for item in G.neighbors("E")])
# --- LISTE ET MATRICE D'ADJACENCE ---
# print("liste d'adjacence : \n",[item for item in G.adjacency()])
MatAdjG = nx.adjacency_matrix(G)
MatAdjG.setdiag(MatAdjG.diagonal()*2)    # def : boucles comptent 2
print("matrice d'adjacence : \n", MatAdjG.todense())networkx et matplotlib :
            | En français | En anglais | 
|---|---|
| algorithme de parcours en profondeur | Depth-First Search (DFS) | 
| algorithme de parcours en largeur | Breadth First Search (BFS) | 
| nœud | node | 
| arête | edge | 
| chemin | path | 
| graphe représentant un réseau | network |