Adloun

Probleme – Du tableau rectangulaire au tableau de départs

Exercice · niveau 3 (difficile) · informatique (MP2I/MPI), chapitre 13 — Le modèle des graphes

Énoncé

On veut une représentation par listes d'adjacence qui occupe véritablement , sans allocation dynamique.

Corrigé

1. La représentation. On concatène toutes les listes d'adjacence dans un unique tableau arrivee de taille , et l'on retient dans depart l'indice où commence la liste de chaque sommet.


int depart[N_MAX + 1];   /* la liste de u occupe arrivee[depart[u] .. depart[u+1]-1] */
int arrivee[A_MAX];      /* les m arcs, groupés par sommet d'origine */

L'invariant tient en trois points :

La case n'est pas un détail : c'est une sentinelle qui évite un cas particulier pour le dernier sommet.

2. L'accès.


/* Parcourir les voisins de u. Complexité : Theta(d+(u)). */
for (int k = depart[u]; k < depart[u+1]; k = k + 1) {
    int v = arrivee[k];
    /* ... */
}

Mesuré sur le graphe du chapitre : et . On lit les voisins de aux indices et — soit et —, ceux de à l'indice — soit —, et le sommet n'en a aucun, puisque . Vérifié : ce sont exactement les listes que donne le tableau rectangulaire.

tableau rectangulairetableau de départs
mémoire
parcourir les voisins de
lire
ajouter un arcimpossible sans tout décaler

3. La construction en . On la fait en trois passes, sans jamais trier : c'est un tri par comptage déguisé.


/* Construit depart/arrivee à partir de mm arcs donnés par src[] et dst[].
   Précondition : 0 <= src[k], dst[k] < n pour tout k ; mm <= A_MAX.
   Complexité : Theta(n + mm) en temps, O(n) en mémoire supplémentaire. */
void construire(int n, int mm, const int src[], const int dst[]) {
    /* (a) COMPTER : depart[u+1] recevra d+(u). */
    for (int u = 0; u <= n; u = u + 1) { depart[u] = 0; }
    for (int k = 0; k < mm; k = k + 1) { depart[src[k] + 1] += 1; }
    /* (b) SOMMES PARTIELLES : depart[u] devient l'indice de début de u. */
    for (int u = 0; u < n; u = u + 1) { depart[u+1] += depart[u]; }
    /* (c) PLACER : un curseur par sommet, initialisé à son début. */
    int curseur[N_MAX];
    for (int u = 0; u < n; u = u + 1) { curseur[u] = depart[u]; }
    for (int k = 0; k < mm; k = k + 1) {
        arrivee[curseur[src[k]]] = dst[k];
        curseur[src[k]] += 1;
    }
}

Le décalage d'un cran en (a) — écrire dans et non dans — est l'astuce qui permet à la passe (b) de transformer les comptes en indices de début par une simple somme partielle, sans tableau auxiliaire. C'est le motif du tri par comptage, et il vaut d'être reconnu : compter, cumuler, placer.

Correction : après (b), , qui est bien l'indice où doit commencer la liste de . En (c), le curseur de parcourt exactement les cases qui lui sont réservées, donc aucune écriture ne déborde sur la liste d'un autre. Terminaison : trois boucles bornées. Complexité : pour (a) et (b), pour (c) — soit , ce qu'on voulait.

4. Ce qu'elle interdit, et pourquoi on l'emploie quand même. Elle interdit l'ajout et le retrait d'arcs : insérer un voisin à demanderait de décaler tout arrivee au-delà, en . C'est une représentation figée, à construire une fois et à lire ensuite.

Or c'est précisément le cas d'usage. Un réseau routier, un graphe du web, un réseau social sont lus des milliards de fois entre deux modifications ; on les reconstruit à intervalles, on ne les édite pas en place. En échange, on obtient trois choses que le tableau rectangulaire ne donne pas : la mémoire exacte , sans marge de sécurité à deviner — et donc sans DEG_MAX arbitraire dont un sommet pourrait sortir ; des voisins contigus en mémoire, donc parcourus à pleine vitesse par le processeur ; et aucune allocation dynamique, donc aucune fuite possible.

C'est le format qu'emploient réellement les bibliothèques de calcul sur graphes et de matrices creuses, sous le nom de stockage par lignes comprimées. Le chapitre a raison de recommander le tableau rectangulaire pour l'épreuve écrite ; celui-ci est ce qu'on écrit quand dépasse le million.

Les autres exercices de ce chapitre Le cours du chapitre

Un blocage sur cet exercice ? Le tuteur d'Adloun guide par questions, sans donner la réponse.