Aller au contenu
Réussir mon BTS SIO

Tape une notion, une commande ou le nom d'une épreuve.

Par exemple

Chapitre 516 minIntermédiaire

Niveaux d'un graphe sans circuit et arborescence

Par Josselyn C., prof de BTS SIO. Mis à jour le .

À la fin de ce chapitre, tu sauras

  • déterminer les niveaux d'un graphe sans circuit ;
  • détecter un circuit pendant la recherche ;
  • dessiner un graphe ordonné par niveaux ;
  • utiliser les niveaux pour trouver un chemin hamiltonien ;
  • reconnaître une arborescence.

5 exercices corrigés2 schémas

Dans un graphe sans circuit, le niveau d'un sommet est la longueur du plus long chemin qui arrive à ce sommet : les sommets sans prédécesseur sont au niveau 0, ceux qui n'ont que des prédécesseurs de niveau 0 au niveau 1, et ainsi de suite. Ranger les sommets par niveaux permet de dessiner le graphe proprement, de gauche à droite, avec toutes les flèches dans le même sens, et donne l'ordre dans lequel traiter des tâches qui dépendent les unes des autres. Ce chapitre donne la méthode pour déterminer les niveaux, la représentation par niveaux, le lien avec les chemins hamiltoniens, puis la notion d'arborescence.

Pourquoi « sans circuit » ?

Les niveaux n'existent que si le graphe n'a aucun circuit. Dans un circuit comme (A, B, A), A devrait être après B et B après A : impossible de les ranger. Un graphe sans circuit, en revanche, peut toujours être rangé : il a au moins une source (un sommet sans prédécesseur), sinon on pourrait remonter de prédécesseur en prédécesseur indéfiniment et on finirait par repasser par un sommet, c'est-à-dire par trouver un circuit.

Le graphe G du ticket a des circuits : il n'a pas de niveaux. Les exemples de ce chapitre sont des graphes de dépendances, sans circuit par nature.

Définition du niveau d'un sommet

Dans un graphe sans circuit :

  • les sommets sans prédécesseur (les sources) sont de niveau 0 ;
  • un sommet est de niveau k quand le plus long chemin qui arrive à lui, en partant d'une source, a pour longueur k.

Concrètement, on ne calcule pas les plus longs chemins : on « épluche » le graphe. On retire les sommets de niveau 0 ; dans ce qui reste, les nouveaux sommets sans prédécesseur sont de niveau 1 ; on les retire à leur tour ; les nouveaux sommets sans prédécesseur sont de niveau 2, etc.

La méthode du tableau des prédécesseurs

Exemple : un pipeline d'intégration continue. À chaque modification du code d'une application, un serveur exécute ces étapes :

ÉtapeDescriptionPrédécesseurs
Arécupérer le code—
Binstaller les dépendancesA
CcompilerB
Dlancer les tests unitairesC
Eanalyser la qualité du codeB
Fconstruire l'image DockerC
GdéployerD, E, F

On dresse un tableau : une ligne par sommet avec ses prédécesseurs, puis une colonne par niveau. À chaque étape, on raye les sommets déjà classés dans les listes de prédécesseurs ; les sommets dont la liste est vide entrent dans le niveau suivant.

SommetPrédécesseursNiveau 0Niveau 1Niveau 2Niveau 3Niveau 4
A—A
BAB
CBC
DCD
EBE
FCF
GD, E, FG

Le raisonnement, étape par étape :

  1. Niveau 0 : seul A n'a pas de prédécesseur. N₀ = {A}.
  2. On raye A. B n'a plus de prédécesseur non classé. N₁ = {B}.
  3. On raye B. C et E n'ont plus de prédécesseur non classé. N₂ = {C, E}.
  4. On raye C et E. D et F sont libres ; G attend encore D et F. N₃ = {D, F}.
  5. On raye D et F. N₄ = {G}.

Tous les sommets sont classés : le graphe est sans circuit, et ses niveaux sont N₀ = {A}, N₁ = {B}, N₂ = {C, E}, N₃ = {D, F}, N₄ = {G}.

La représentation par niveaux

On dessine les niveaux en colonnes, de gauche à droite (ou en lignes, de haut en bas), et on place les arcs. Toutes les flèches vont alors d'un niveau vers un niveau plus grand : le dessin se lit dans un seul sens, sans croisement inutile.

Niveau 0Niveau 1Niveau 2Niveau 3Niveau 4ABECDFGcodedépendancesqualitécompilertestsimagedéployer
Le graphe ordonné par niveaux : chaque flèche va vers un niveau plus grand, et les sommets d'un même niveau ne dépendent pas les uns des autres

Ce que la représentation apprend. Deux sommets d'un même niveau ne sont jamais reliés par un arc : ils ne dépendent pas l'un de l'autre. Dans le pipeline, l'analyse de qualité (E) peut tourner en parallèle de la compilation (C), et les tests (D) en parallèle de la construction de l'image (F). Le nombre de niveaux, 5, est le nombre minimal de « vagues » successives pour tout exécuter, même avec autant de serveurs qu'on veut.

Lire les sommets niveau par niveau (A, B, C, E, D, F, G) donne un ordre dans lequel chaque sommet vient après tous ses prédécesseurs. Les informaticiens appellent cela un tri topologique : c'est l'ordre dans lequel un gestionnaire de paquets installe les dépendances, ou dans lequel un outil comme make ou un orchestrateur de pipeline lance ses tâches.

Niveaux et chemin hamiltonien

Dans un graphe sans circuit, le niveau maximal est la longueur du plus long chemin du graphe. Un chemin hamiltonien, qui passe par les n sommets, a n − 1 arcs : s'il existe, le plus long chemin a n − 1 arcs, il y a donc n niveaux (0 à n − 1) pour n sommets, soit un sommet par niveau. Inversement, s'il y a un sommet par niveau, le sommet du dernier niveau est au bout d'un chemin de longueur n − 1, qui passe forcément par les n sommets.

Le pipeline a deux sommets aux niveaux 2 et 3 : il n'a pas de chemin hamiltonien. On ne peut pas enchaîner toutes les étapes en une seule file en suivant les arcs : C et E, par exemple, ne sont reliés dans aucun sens.

Exemple avec chemin hamiltonien. Le graphe de sommets A, B, C, D, E et de prédécesseurs Γ⁻(A) = {C}, Γ⁻(B) = ∅, Γ⁻(C) = {B}, Γ⁻(D) = {A, C}, Γ⁻(E) = {B, D} a pour niveaux N₀ = {B}, N₁ = {C}, N₂ = {A}, N₃ = {D}, N₄ = {E}. Un sommet par niveau : le chemin hamiltonien est (B, C, A, D, E), et on vérifie que les arcs B → C, C → A, A → D et D → E existent.

Les arborescences

Une arborescence est un graphe orienté qui a un sommet particulier, la racine, tel que :

  • la racine n'a aucun prédécesseur ;
  • tout autre sommet a exactement un prédécesseur ;
  • tout sommet peut être atteint depuis la racine.

De façon équivalente, il existe un et un seul chemin de la racine vers chaque autre sommet. Une arborescence n'a donc pas de circuit, et ses niveaux sont simplement les distances à la racine : la racine au niveau 0, ses successeurs au niveau 1, etc.

Le vocabulaire vient de la généalogie et de la botanique : le prédécesseur d'un sommet est son père (ou parent), ses successeurs sont ses fils (ou enfants), et les sommets sans successeur sont les feuilles.

/etchomevarsshaliceboblogwwwniveau 0niveau 1niveau 2racinefeuille
Une arborescence : un seul chemin de la racine / vers chaque répertoire, par exemple (/, var, log) pour /var/log

L'arborescence des fichiers est l'exemple que tu manipules tous les jours : le chemin absolu d'un fichier, comme /var/log, est exactement l'unique chemin de la racine vers ce sommet. On rencontre aussi des arborescences dans :

  • le DNS : la racine, puis les domaines de premier niveau (fr, com), puis les domaines (exemple.fr), puis les sous-domaines ;
  • l'Active Directory : le domaine, ses unités d'organisation, leurs sous-unités et leurs objets ;
  • une page web : l'arbre DOM des balises HTML, chaque balise ayant une seule balise parente ;
  • un organigramme hiérarchique, où chacun a un seul supérieur direct.

En Python : calculer les niveaux

python
def niveaux(predecesseurs):
    """Renvoie la liste des niveaux, ou None si le graphe a un circuit."""
    restants = dict(predecesseurs)          # sommet -> liste de prédécesseurs
    classes = set()
    resultat = []
    while restants:
        niveau = sorted(x for x, preds in restants.items()
                        if all(p in classes for p in preds))
        if not niveau:                      # plus aucun sommet libre : circuit
            return None
        resultat.append(niveau)
        classes.update(niveau)
        for x in niveau:
            del restants[x]
    return resultat

pipeline = {"A": [], "B": ["A"], "C": ["B"], "D": ["C"],
            "E": ["B"], "F": ["C"], "G": ["D", "E", "F"]}
print(niveaux(pipeline))
# [['A'], ['B'], ['C', 'E'], ['D', 'F'], ['G']]

C'est la traduction directe de la méthode du tableau. Le cas None correspond à l'étape où plus aucun sommet n'est libre : un circuit bloque le classement.

Exercices

Exercice 1 sur 5 Déterminer des niveaux Réussi À revoir

Un graphe a pour tableau des prédécesseurs :

SommetABCDEFGH
Prédécesseurs—A, DB—A, DC, EEF, G
  1. Détermine les niveaux de ce graphe.
  2. Représente-le ordonné par niveaux.
  3. A-t-il un chemin hamiltonien ?
Voir la réponseMasquer la réponse de l'exercice 1
  1. N₀ = {A, D} (pas de prédécesseur). On raye A et D : B et E sont libres, N₁ = {B, E}. On raye B et E : C et G sont libres (F attend C), N₂ = {C, G}. On raye C et G : N₃ = {F}. On raye F : N₄ = {H}.
SommetPrédécesseursN₀N₁N₂N₃N₄
A—A
BA, DB
CBC
D—D
EA, DE
FC, EF
GEG
HF, GH
  1. Colonnes de gauche à droite : {A, D}, {B, E}, {C, G}, {F}, {H}. Arcs : A → B, A → E, D → B, D → E, B → C, E → F, E → G, C → F, F → H, G → H, tous dirigés vers la droite.
  2. Les niveaux 0, 1 et 2 contiennent deux sommets : pas de chemin hamiltonien. (Il y a d'ailleurs deux sources, A et D, ce qui suffisait à conclure.)

Tu avais trouvé ?

Exercice 2 sur 5 Un circuit caché Réussi À revoir

Un graphe a pour tableau des prédécesseurs : Γ⁻(A) = ∅, Γ⁻(B) = {A, E}, Γ⁻(C) = {B}, Γ⁻(D) = {C}, Γ⁻(E) = {D}, Γ⁻(F) = {C}.

  1. Commence la recherche des niveaux. Que constates-tu ?
  2. Trouve le circuit.
Voir la réponseMasquer la réponse de l'exercice 2
  1. N₀ = {A}. On raye A : B a encore le prédécesseur E, non classé ; C, D, E, F ont aussi des prédécesseurs non classés. Aucun sommet n'est libre : la recherche s'arrête, le graphe a un circuit, il n'a pas de niveaux.
  2. On remonte les prédécesseurs : B ← E ← D ← C ← B. Le circuit est (B, C, D, E, B).

Tu avais trouvé ?

Exercice 3 sur 5 Niveaux et chemin hamiltonien Réussi À revoir

Un graphe a pour matrice d'adjacence (ordre A, B, C, D, E) :

ABCDE
A00010
B00101
C10010
D00001
E00000
  1. Donne le tableau des prédécesseurs, puis les niveaux.
  2. Justifie que le graphe a un chemin hamiltonien et donne-le.
Voir la réponseMasquer la réponse de l'exercice 3
  1. On lit les colonnes : Γ⁻(A) = {C}, Γ⁻(B) = ∅, Γ⁻(C) = {B}, Γ⁻(D) = {A, C}, Γ⁻(E) = {B, D}. Niveaux : N₀ = {B}, N₁ = {C}, N₂ = {A}, N₃ = {D}, N₄ = {E}.
  2. Le graphe est sans circuit (les niveaux existent) et chaque niveau contient un seul sommet : il a un chemin hamiltonien, qui parcourt les niveaux dans l'ordre, (B, C, A, D, E). Vérification dans la matrice : (B, C), (C, A), (A, D) et (D, E) valent bien 1.

Tu avais trouvé ?

Exercice 4 sur 5 Arborescence ou pas ? Réussi À revoir

Pour chaque graphe, dis s'il s'agit d'une arborescence et, si oui, donne sa racine et ses feuilles.

  1. Arcs (A, B), (A, C), (B, D), (B, E), (C, F).
  2. Arcs (A, B), (A, C), (B, D), (C, D).
  3. Arcs (R, S), (S, T), (T, R), (R, U).
  4. Arcs (fr, gouv.fr), (fr, exemple.fr), (exemple.fr, www.exemple.fr), (exemple.fr, mail.exemple.fr).
Voir la réponseMasquer la réponse de l'exercice 4
  1. Oui. A n'a pas de prédécesseur, chaque autre sommet en a exactement un, et tous sont atteints depuis A. Racine A, feuilles D, E, F.
  2. Non : D a deux prédécesseurs, B et C. Il y a deux chemins de A vers D.
  3. Non : (R, S, T, R) est un circuit, et aucun sommet n'est sans prédécesseur.
  4. Oui : c'est un morceau de l'arborescence du DNS. Racine fr, feuilles gouv.fr, www.exemple.fr, mail.exemple.fr. (Dans le DNS réel, la racine de tout l'arbre est la zone racine, notée « . ».)

Tu avais trouvé ?

Exercice 5 sur 5 Ordre d'installation Réussi À revoir

Un logiciel L nécessite les bibliothèques P et Q ; P nécessite R et S ; Q nécessite S ; S nécessite T ; R et T ne nécessitent rien.

  1. Construis le graphe « x doit être installé avant y » et détermine ses niveaux.
  2. Propose un ordre d'installation, puis le nombre minimal de vagues si l'on peut installer plusieurs bibliothèques en parallèle.
Voir la réponseMasquer la réponse de l'exercice 5
  1. Arcs (« avant ») : R → P, S → P, S → Q, T → S, P → L, Q → L. Prédécesseurs : R : ∅ ; T : ∅ ; S : {T} ; P : {R, S} ; Q : {S} ; L : {P, Q}. Niveaux : N₀ = {R, T}, N₁ = {S}, N₂ = {P, Q}, N₃ = {L}.
  2. Un ordre possible, niveau par niveau : R, T, S, P, Q, L. Avec du parallélisme, il faut 4 vagues : {R, T}, puis S, puis {P, Q}, puis L, une par niveau.

Tu avais trouvé ?

Chapitre terminé !

Fais les 5 exercices avant de passer à la suite : c'est en t'entraînant que tout se fixe.

chapitres
–
de série
–
du cours
–
Chapitre suivant : Graphe valué et chemin optimal en longueur et en valeurRevoir le sommaire du cours