Algorithmique avancée
les structures de données
Pourquoi structurer les données ?
Exemple de programme écrit de façon débile :
manipulation de N (<=100) entiers, avec uniquement des variables
void main(int argc, char **argv) { int v1,v2,v3,v4,v5,...,v100;
int nbvar = argc - 1;
if (nbvar>100) exit(1);
if (nbvar >= 1) v1 = atoi(argv[1]);
if (nbvar >= 2) v2 = atoi(argv[2]);
...
if (nbvar >= 100) v100 = atoi(argv[101]);
// calcul somme int somme = 0;
if (nbvar >= 1) somme += v1;
if (nbvar >= 2) somme += v2;
...
if (nbvar >= 100) somme += v100;
printf("somme des %d valeurs : %d\n",nbvar,somme);
> 200 lignes
de code
Pourquoi structurer les données ?
Même exemple de programme écrit intelligemment :
manipulation de N (<=100) entiers, avec un tableau
void main(int argc, char **argv) { int i,somme;
int tabv[100];
int nbvar = argc - 1;
if (nbvar>100) exit(1);
somme = 0;
for(i=0;i<nbvar;i++) {
tabv[i] = atoi(argv[i+1]);
somme += tabv[i];
}
printf("somme des %d valeurs : %d\n",nbvar,somme);
}
6 lignes de
code
Les structures classiques : tableau
●
Traitements classiques :
– accès en lecture/écriture à la cellule d'indice i
ex : écriture de 15 et 6 en cellule 1 et 2 (Þ écrasement en 2)
– insertion/suppression de données à l'indice i
ex : suppression en cellule 2 (Þ décalage à gauche des données suivantes)
-5 15 6 4 2 7
-5 30 4 2 7
-5 15 4 2 7
-5 15 6 4 2 7
Les structures classiques : liste
●
Traitements classiques :
– accès en lecture/écriture à la cellule d'indice i
ex : écriture de 15 et 6 en indice 1 et 2 (Þ écrasement des données)
– insertion/suppression de données à l'indice i
ex : suppression en indice 2 (Þ suppression de la cellule, diminution taille liste)
-5 30 4 2 7
-5 15 6 2 7
-5 15 6 2 7
-5 15 2 7
Les structures classiques : liste
Exemple d'algorithme : récupérer la valeur à l'indice i dans une liste d'entiers.
# déclaration types
cellule : {entier val, cellule suiv}
liste : {cellule tete, entier taille}
fonction : get(liste l, entier indice) → entier # déclaration variables
i : entier c : cellule # traitement
si indice > l.taille-1 retourne vide
finsi
c ← l.tete
pour i de 0 à indice-1 c ← c.suiv
finpour retourne c
Les structures classiques : liste
●
Pour simplifier certains traitements, les listes peuvent avoir une structure plus complexe :
– doublement chaînée : chaque cellule référence la suivante ET la précédente
– circulaire : la dernière cellule référence la première
– doublement chaînée et circulaire
– ...
-5 30 4 2 7
-5 15 6 2 7
Les structures classiques : arbre
●
Exemple, arbre stockant des entiers, avec un nombre variable de fils pour chaque nœud
-5
30 4
2 8 -3 7
1 1
Les structures classiques : arbre
●
Illustration des mots-clés.
-5
30 4
2 8 -3 7
1 1
racine feuille
sous-arbre
une branche
Les structures classiques : graphe
●
Exemple, graphe stockant des entiers
30 -5
4
2
7
8
-3
1
1
Les structures classiques : graphe
●
Remarque : un graphe non-orienté, sans circuit et connexe constitue un arbre (dont il faut définir la racine).
30 -5
4
2
7
8
-3
1
1
Corrélation structure/traitements
Exemple 4 : plus court chemin entre deux villes
●
Organisation naturelle : graphe pondéré, orienté.
– arête = route directe entre deux villes,
– pondération = nombre de kilomètres.
●
structure de stockage suffisante : tableau 2D
0 0 15 23 0
0 0 50 0 0
15 50 0 31 9
23 0 31 0 13
0 0 9 13 0
●
0 = pas d'arête
●
structure de matrice symétrique
●
implémentation sous forme de
tableau 1D ou bien tableau de
tableaux.
Exemple : l'arbre binaire en Java
classe Node stockant un int
class Node {
public Node left;
public Node right;
public int value;
public Node(value) { this.value = value;
left = null;
right = null;
} }
Exemple : l'arbre binaire en Java
classe BinaryTree
class BinaryTree { public Node root;
public BinaryTree() { root = null;
}
public void printDepth(Node n) { if (left!= null) {
printDepth(n.left);
}
if (right!= null) {
printDepth(n.right);
}
System.out.println(value); // ou qqchose d'autre }
...
}
Exemple : le graphe orienté/pondéré
classes Edge (arête), Vertex (sommet)
class Edge {
public Vertex from;
public Vertex to;
public double weight;
public Edge(Vertex from, Vertex to, double weight) { ... } ...
}
class Vertex {
public Set<Edge> edgesTo;
public Set<Edge> edgesFrom;
int value;
...
}
Exemple : le graphe orienté/pondéré
classe GraphOP
class GraphOp {
public Set<Vertex> vertices;
public int nbVertices; // pas nécessaire mais utile public int nbEdges; // pas nécessaire mais utile public GraphOp() {
vertices = new HashSet<Vertex>();
nbVertices = 0; nbEdges = 0;
} ...
public connectVertices(Vertex src, Vertex dest, double weight) { Edge e = new Edge(src, dest, weight);
src.edgesTo.add(e);
dest.edgesFrom.add(e);
nbEdges += 1;
} ...
}