Plan Langage C
• Tableaux multi-dimensionnels
• Unions
Algorithmique
• Graphes
• Arbres
• Tas
• Tri par tas
Tableaux
int t[7][8];
int *s[7];
• Lors de la déclaration de t , 56
emplacements de la taille d'un entier sont réservés en mémoire.
• En revanche, lors de la déclaration de s, 7 pointeurs sont déclarés, mais pas initialisés. Il faudra allouer la mémoire
"à la main". Par exemple
for (i = 0; i <= 6; i++)
s[i] = (int *)calloc(8, sizeof(int));
• La seconde méthode est cependant
plus souple : on peut avoir des lignes de taille inégale si on le souhaite.
#include <stdlib.h>
#include <stdio.h>
static int t[7][8];
static int *s[7];
void TestTableaux(void) { int i, j;
for (i = 0; i <= 6; i++)
s[i] = (int *)calloc(8, sizeof (int));
for (i = 0; i <= 6; i++) for (j = 0; j <= 7; j++) { t[i][j] = (i+1) * (j+1);
s[i][j] = (i+1) * (j+1);
} }
int t[];
déclare t comme un tableau d'entiers mais ne réserve rien en mémoire. En revanche, la taille des éléments du tableau est bien définie.
int t[][5];
déclare t comme un tableau de tableaux de 5 entiers mais ne réserve rien en mémoire. En revanche, la taille des éléments du tableau est bien définie.
int t[][];
est incorrect, car la taille des éléments du tableau n'est pas définie.
union
union Element { char c;
int i;
double d;
};
union Element p;
p.c = 'a';
p.i = 25;
p.d = 0.235;
• Même syntaxe que pour struct .
• Lors de la définition de p comme variable de type union Element , un espace mémoire est alloué : il suffit à contenir l'un quelconque des champs de l'union, mais pas tous les champs
simultanément !
La taille allouée est donc le max de
sizeof(char), sizeof(int), sizeof(double)
• Un graphe est un couple G = (S, A)
où S est un ensemble (l'ensemble des sommets) et A est une partie de S x S, l'ensemble des arêtes.
• Deux arêtes (s, t) et (s', t') sont consécutives si t = s'
A = {(1, 2), (1, 4), (2, 4), (3, 3), (4, 3)}
Arêtes consécutives (1, 2) et (2, 4) Graphes
1 2
3 4
Graphes
• Un chemin dans un graphe est une suite d'arêtes consécutives.
(1, 4)(4, 3)(3, 3)(3, 3) : chemin
• On convient de définir un chemin vide autour de chaque sommet.
• Graphe non dirigé : si (s, t) est une arête, (t, s) est une arête
1 2
3 4
Arbres
Un arbre est un graphe non dirigé muni d'un sommet distingué (la racine) et tel qu'il existe un chemin unique de la racine à un sommet quelconque.
Vocabulaire sur les arbres
• Noeuds, branches, feuilles, nœuds internes, arité, parents, enfants, frères ou sœurs, ancêtres, descendants, niveau, hauteur (ou profondeur!)
• Forêts, arbres ordonnés
• Arbre binaire, ternaire, etc.
sous-arbre gauche ou droit
• Arbre binaire homogène, plein, complet
• Arbre étiqueté
Parcours en largeur
1
2 3
4 5 6 7
8 9 10
Parcours en profondeur préfixe
1 2
3
4 5
6 7
8
9 10
Prop 1 Il existe un chemin (réduit) et un seul entre deux sommets.
Prop 2 Tout nœud, sauf la racine, a un unique parent. Deux nœuds quelconques ont un plus petit ancêtre commun.
Prop 3 Un arbre ayant n nœuds possède n-1 arêtes. Un arbre binaire ayant n nœuds internes possède n+1 feuilles.
Prop 4 La hauteur d'un arbre binaire complet de n sommets est O(log n).
Tas
Opérations de base :
• Insertion d'un nouvel élément
• Trouver le maximum
• Modifier la valeur de la racine
• Supprimer le maximum
1
2 3
4 5 6 7
8 9 10
23
15 7
6 1
12
4 8
5
2
Représentation par tableau
Racine : 1
Parent (i) : i/2
Fils gauche : 2i, Fille droite : 2i+1
1
2 3
4 5 6 7
8 9 10
23
15 7
6 1
12
4 8
5
2
23 15 7 12 5 6 1 4 8 2
1 2 3 4 5 6 7 8 9 10 11 12 … 16
Insertion
Nouveau nœud d'étiquette 21
• Le placer dans la première position libre (N° 11)
• Permuter avec le parent jusqu'à ce qu'on obtienne un tas
1
2 3
4 5 6 7
8 9 10
23
15 7
6 1
12
4 8
5
2 21
11
Modifier la valeur de la racine
Passer de 23 à 3 : on remplace 23 par 3, puis on échange 3 avec le plus grands des enfants (ici 15) et on continue le processus d'échange
23
15 7
6 1
12
4 8
5
2
Suppression de la racine
Pour retirer 23, il suffit de supprimer 2 et de remplacer 23 par 2 …
1
2 3
4 5 6 7
8 9 10
23
15 7
6 1
12
4 8
5
2
Tri par Tas (HeapSort)
• On construit un tas dans le tableau en ajoutant les élements un à un.
• On retire ensuite les élements un par un pour les mettre à droite du tableau (position N, puis N-1, etc.)
#define N 15
void Ajouter(int v);
Element Maximum(void);
void Supprimer(void);
void HeapSort(void);
static int nTas = 0;
Element a[N] = {1, 18, 14, 17, 19, 9, 6, 7, 5, 23, 1, 12, 15, 11, 5};
void Ajouter(int v) { int i;
++nTas;
i = nTas - 1;
while (i > 0 && a[(i - 1)/2] <= v) { a[i] = a[(i - 1)/2];
i = (i - 1)/2;
}a[i] = v;
}
Element Maximum(void) { return a[0];
}
void Supprimer(void) { int i, j;
Element v;
a[0] = a[nTas - 1];
--nTas;
i = 0;
v = a[0];
while (2 * i + 1 < nTas) { j = 2*i + 1;
if (j + 1 < nTas)
if (a[j + 1] > a[j]) if (v >= a[j])++j;
break ; a[i] = a[j];
i = j;
}a[i] = v;
}
void HeapSort(void) { int i;
Element v;
nTas = 0;
for (i = 0; i < N; ++i) Ajouter(a[i]);
for (i = N - 1; i >= 0; --i) { v = Maximum();
Supprimer();
a[i] = v;
} }
Tri par Tas