0229 Formation Algorithmie Cryptographie PDF
0229 Formation Algorithmie Cryptographie PDF
0229 Formation Algorithmie Cryptographie PDF
http://alexandre-mesle.com
30 octobre 2008
Table des matières
2 Algorithmes itératifs 9
2.1 Invariants de boucle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.1.1 Le principe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.1.2 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.2 Terminaison . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.2.1 Le principe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.2.2 Fin de l’exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.2.3 Un autre exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.3 Complexité . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
3 Récursivité 14
3.1 Sous-programmes récursifs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
3.1.1 Factorielle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
3.2 Sous-programmes récursifs terminaux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
3.2.1 Factorielle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.2.2 Exponentiation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.2.3 Itérateurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
3.3 Listes chaı̂nées . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.3.1 Notations et conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.3.2 Rédaction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.4 Exemple de calcul de complexité d’un algorithme récursif . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.4.1 L’algorithme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.4.2 Résolution exacte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.4.3 Vérification par récurrence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.4.4 Problèmes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
3.4.5 L’heure du code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
4 Arbres 33
4.1 Définitions par induction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
4.1.1 Définition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
4.1.2 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
4.1.3 Expressions arithmétiques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
1
4.1.4 Application aux arbres binaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
4.2 Preuves par induction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
4.2.1 Lien avec les preuves par récurrence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
4.2.2 Application aux EATPs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
4.3 Algorithmique dans les arbres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
4.4 Arbres n-naires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
5 Files de priorité 36
5.1 Implémentations naı̈ves . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
5.2 Tas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
5.2.1 Définition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
5.2.2 Extraction du minumum . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
5.2.3 Insertion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
5.2.4 Suppression du minimum . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
5.2.5 Implémentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
5.3 Tas binomial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
5.3.1 Arbre binomial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
5.3.2 Fusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
5.3.3 Tas binomial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
5.3.4 Implémentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
5.3.5 Extraction du minimum . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
5.3.6 Fusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
6 Hachage 40
6.1 Principe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
6.2 Collisions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
6.2.1 Gestion des collisions par chaı̂nage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
6.2.2 Gestion des collisions par adressage ouvert . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
7 AVL 42
7.1 Arbres binaires de recherche . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
7.2 Complexité dans le pire de cas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
7.3 Rotations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
7.4 AVLs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
7.4.1 Rééquilibrage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
7.4.2 Insertion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
7.4.3 Suppression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
7.4.4 Compléments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
8 Modélisation 51
8.1 Définition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
8.2 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
8.2.1 Données . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
8.2.2 Contraintes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
8.2.3 Question . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
8.3 Sensibilisation à la complexité . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
8.3.1 Le tour de la table . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
8.3.2 De la terre à la Lune . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
8.3.3 En bref . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
8.4 Terminologie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
8.4.1 Difficulté . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
8.4.2 Rappels de théorie des graphes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
8.4.3 Définition d’un problème . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
8.4.4 Problèmes d’optimisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
8.5 Problèmethèque . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
2
8.5.1 Arbre couvrant de poids minimal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
8.5.2 Ensemble stable maximal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
8.5.3 Circuit eulérien . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
8.5.4 Circuit hamiltonien . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
8.5.5 Voyageur de commerce . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
8.5.6 SAT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
8.5.7 Couverture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
8.5.8 Coloration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
8.5.9 Plus court chemin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
8.5.10 Sac à dos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
8.6 Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
9 Programmation linéaire 61
9.1 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
9.2 Algorithme du simplexe en bref . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
9.3 Modéliser un programme linéaire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
9.4 GLPK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
9.4.1 Qu’est-ce que c’est ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
9.4.2 Où le trouver ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
9.4.3 La documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
9.4.4 Les fonctions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
10 Théorie de la complexité 68
10.1 Terminologie et rappels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
10.1.1 Problèmes de décision . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
10.1.2 Instances . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
10.1.3 Algorithme polynomial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
10.2 Les classes P et NP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
10.2.1 La classe P . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
10.2.2 La classe NP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
10.2.3 Relations d’inclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
10.3 Réductions polynomiales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
10.3.1 Définition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
10.3.2 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
10.3.3 Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
10.4 Les problèmes NP-complets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
10.4.1 Courte méditation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
10.4.2 3-SAT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
10.4.3 Conséquences déprimantes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
10.4.4 Un espoir vain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
11 Introduction la cryptographie 74
11.1 Définitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
11.2 La stéganographie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
11.3 Les chiffres symétriques sans clé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
11.4 Les chiffres symétriques à clé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
11.4.1 Le chiffre de Vigenère . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
11.4.2 Enigma . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
11.5 Les algorithmes asymétriques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
11.5.1 Un peu d’histoire[1] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
11.5.2 Le principe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
3
12 GnuPG 77
12.1 Présentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
12.2 Utilisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
12.2.1 Génération d’une clé privée . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
12.2.2 Exportation de la clé publique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
12.2.3 Importation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
12.2.4 Liste des clés . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
12.2.5 Chiffrement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
12.2.6 Déchiffrement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
12.2.7 Signature . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
12.2.8 Bref . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
13 GMP 80
13.1 Présentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
13.2 Quelques points délicats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
13.2.1 Compilation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
13.2.2 Initialisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
13.2.3 Les fonctions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
13.2.4 Affichage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
13.2.5 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
13.2.6 Pour terminer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
14 Arithmétique 84
14.1 Divisibilité . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
14.2 Division euclidienne . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
14.3 PGCD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
14.4 Nombres premiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
14.5 Nombres premiers entre eux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
14.6 Décomposition en produit de facteurs premiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
14.6.1 Application à la divisibilité . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
14.6.2 Application au calcul du PGCD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
14.7 Théorème de Bezout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
14.7.1 Théorème de Gauss . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
14.8 Algorithme d’Euclide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
14.8.1 Algorithme d’Euclide pour le PGCD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
14.8.2 Algorithme d’Euclide étendu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
14.8.3 Morceaux choisis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
14.8.4 Applications avec GMP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
15 Arithmétique modulaire 91
15.1 Congruences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
15.2 Rappels d’algèbre . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
15.2.1 Monoı̈des . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
15.2.2 Groupes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
15.2.3 Anneaux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
15.2.4 Corps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
15.2.5 Relations d’équivalence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
15.3 Espaces quotients . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
15.3.1 Classes d’équivalence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
15.3.2 Z/nZ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
15.4 Inverses modulaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
15.4.1 Eléments inversibles et fonction φ d’Euler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
15.4.2 Pratique de l’inversion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
4
16 RSA 97
16.0.3 Principe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
16.0.4 Résistance aux attaques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
5
Chapitre 1
Un algorithme, programmé dans un langage différent, ou lancé sur une machine différente, ne mettra pas le temps
à exécuter. Il serait pourtant important de trouver un moyen de mesurer son temps d’exécution, pour le comparer par
exemple à d’autres algorithmes. Nous nous intéresserons à un critère, appelé complexité dans le pire des cas, qui
nous permettra d’évaluer les performances d’un algorithme en terme de temps d’exécution.
6
1.2.2 Algorithmes de complexité linéaire, O(n)
Un algorithme est de complexité linéaire si le temps de calcul croı̂t de façon linéaire en fonction du nombre de
données. Si vous traitez deux fois plus de données, le temps d’exécution sera multiplié par deux. Par exemple, la
recherche séquentielle dans un tableau non trié est de complexité linéaire. En effet, on effectue une recherche en
parcourant le tableau avec une boucle (ou un algorithme récursif). Chacune des itérations se fait en temps constant,
il suffit donc de compter le nombre d’itérations. Dans le pire des cas, l’élément que l’on recherche est celui qui est
examiné en dernier. Il est donc nécessaire d’effectuer n itérations.
Exercice 1 - Tableaux
Déterminer la complexité dans le pire cas (précisez quel est ce pire cas) des opérations suivantes sur un tableau
t = [t1 , . . . , tn ] à n éléments non triés,
1. Affichage du k-ème élément de t.
2. Affichage des éléments de t.
3. Calcul de la somme cumulée des éléments de t.
4. Décalage vers la droite de la tranche [tk , . . . , tn ] et insertion d’un élément au rang k.
5. Décalage vers la gauche de la tranche [tk+1 , . . . , tn ] pour supprimer tk .
6. Recherche séquentielle d’un élément.
7. Vérification de l’appartenance de chaque élément de t à un tableau q non trié.
7
Exercice 2 - Listes chaı̂nées
Déterminer la complexité dans le pire des cas (précisez de quel cas il s’agit) des opérations ci-dessous sur une liste
chaı̂née l = l1 −→ l2 −→ . . . −→ ln à n éléments non triés. La seule information à notre disposition au début de
l’exécution de chacun de ces algorithmes est un pointeur vers le premier élément de la liste. :
1. Affichage du k-ème élément de l.
2. Affichage des éléments de l.
3. Calcul de la somme cumulée des éléments de l.
4. Suppression du premier élément.
5. Suppression de l’élément de rang k, adresse du (k − 1)-ème élément connue.
6. Suppression de l’élément de rang k, adresse du (k − 1)-ème élément inconnue.
7. Recherche séquentielle d’un élément.
8. Vérification de l’appartenance de chaque élément de l à une liste q non triée.
8
Chapitre 2
Algorithmes itératifs
Un algorithme itératif est contruit avec des boucles, par opposition à récursif qui remplace les boucles par ds appels
à lui-même.
Définition 2.1.1 Un invariant de boucle est une propriété qui est vraie à chaque passage dans la boucle.
On raisonne par récurrence pour montrer qu’une telle propriété est préservée à chaque itération de la boucle. Elle
suffit à prouver la validité de l’algorithme si elle est trivialement vraie à la première itération et qu’à la dernière
itération, sa véracité entraı̂ne celle de l’algorithme. Voyons cela sur un exemple.
2.1.2 Exemple
On divise deux entiers strictement positifs a et b en déterminant deux entiers q et r tels que a = bq + r avec
0 ≤ r < b. Voici un algorithme déterminant q et r :
q ←− 0
r ←− a
tant que r ≥ b
q ←− q + 1
r ←− r − b
fin tant que
2.2 Terminaison
2.2.1 Le principe
La démonstration ci-dessus est incomplète, d’une part on n’a pas démontré que le programme s’arrêtait, et de plus
rien ne montre (pour le moment) que s’il s’arrête, on aura bien 0 ≤ r < b. On montre qu’un programme s’arrête en
9
prouvant que la séquence formée par les valeurs des variables au fil des itérations converge vers une valeur satisfaisant
la condition d’arrêt.
– Montrons que le programme se termine. La séquence formée par les valeurs prises par m au fil des itérations est
strictement croissante, il y a donc un moment où m ≥ a. Donc l’algorithme se termine.
– Considérons comme invariant de boucle p = m.b, montrons par récurrence qu’il est vérifiée.
– m est p sont initialisés à 0, on a bien 0 = 0.b.
– montrons maintenant que la propriété est conservée. Supposons qu’au début d’une itération donnée, on ait
p = m.b. Soient p′ et m′ les valeurs de ces variables à la fin de cette itération, montrons que l’on a p′ = m′ .b.
On a les relations p′ = p + b et m′ = m + 1. Donc p′ = p + b = m.b + b = (m + 1).b = m′ .b. La propriété est
donc conservée par chaque itération de l’algorithme.
– La première de valeur de m qui nous fera sortir de la boucle est a, donc après la dernière itération on aura
p = mb = ab. Ce programme place donc dans p le produit de a par b.
Exercice 1 - Exponentiation
Ecrire un algorithme de calcul de bn où n est un entier positif ou nul. Prouver sa terminaison et sa validité.
10
Procédure insere(T, k)
i ←− k tant que i > 0 ∧ T [i − 1] > T [i]
echanger(T [i − 1], T [i])
i ←− i − 1
fin tant que
FIN
Prouver que si on passe en paramètre à insere un tableau T dont les k − 1 premiers éléments sont triés, alors à la
fin de son exécution, les k premiers éléments dont triés. Etant donné le programme suivant :
Procédure triInsertion(T [n])
pour i ∈ {2, . . . , n}
insere(T, i)
fin pour
FIN
11
2.3 Complexité
On détermine la complexité d’un programme itératif en comptant le nombre d’itérations. Lorsque deux boucles
sont imbriquées, on est amené à compter pour chaque itération de la boucle principale le nombre d’itérations de la
boucle imbriquée et à les additionner. Par exemple,
pour i ∈ {1, . . . , n − 1}
pour j ∈ {i + 1, . . . , n}
(* opération en O(1) *)
fin pour
fin pour
n−1
X ((n − 1) − 1 + 1)(n − 1 + n − (n − 1)) (n − 1)n
(n − 1) + (n − 2) + . . . + (n − (n − 1)) = (n − i) = = ∈ O(n2 )
i=1
2 2
Exercice 5 - Sommations
Simplifier les sommes suivantes :
n+2
X
– i
i=1
n
X
– i+1
i=0
P n
– en i=1 ln(i)
X
– (3i − 2)
i=1
n n−1
X X
– 1
i=1 j=i
Xn n−1
X
– (3( 1) − 2)
i=1 j=i
n+3
X
– (i − 1)
i=5
Xn
– (2n − 3i)
i=1
Morceaux choisis
Exercice 7 - Polynômes
n
X
Nous représenterons un polynôme P (x) = p0 xn + p1 xn−1 + . . . + pn−1 x + pn = pi xn−i de degré n à l’aide d’un
i=0
tableau [p0 , p1 , . . . , pn−1 , pn ] à n + 1 éléments. Notez bien que ce tableau est indicé à partir de 0.
12
1. Que fait la fonction suivante ?
Fonction mystery([p0 , . . . , pn ], x)
somme ←− 0
pour i ∈ {0, . . . , n}
terme ←− 1
j ←− 1
tant que j ≤ n − i
terme ←− terme × x
j ←− j + 1
fin tant que
terme ←− terme × pi
somme ←− somme + terme
fin pour
retourner somme
FIN
13
Chapitre 3
Récursivité
Ce sous-programme affiche n si celui-ci est positif ou nul, puis se rappelle en passant n − 1 en paramètre. Il va se
rappeler jusqu’à ce que le paramètre prenne la valeur −1, affichant ainsi un compte à rebours dont la dernière valeur
affichée sera 0. Lorsque qu’un sous-programme se rappelle, on dit qu’il effectue un appel récursif. Pour observer ce
que cela fait, considérez le programme suivant :
#include<s t d i o . h>
void countDown ( i nt n )
{
i f ( n >= 0 )
{
p r i n t f ( ”%d\n” , n ) ;
countDown ( n − 1 );
}
}
i nt main ( )
{
countDown ( 1 0 ) ;
return 0 ;
}
Il affiche
10
9
8
7
6
5
4
14
3
2
1
0
3.1.1 Factorielle
Soit n un nombre entier positif ou nul, le nombre n!, dit ”factorielle n”, est défini comme suit :
n
Y
n! = 1 × 2 × . . . × n = i
i=1
– Observez bien que la condition d’arrêt est testée dès le début de l’exécution de l’algorithme, et qu’elle permet
de calculer la valeur 0!
– Dans le cas général, le calcul n! se fait en passant par le calcul de (n − 1)!. Comme la valeur passée en paramètre
dans l’appel récursif est n − 1 et est strictement inférieure à n, alors la séquence des valeurs passées en paramètre
au fil des appels récursifs
n −→ n − 1 −→ . . . −→ 1 −→ 0
est strictement décroissante et converge vers 0. Il est très important de vérifier que quelques soient les valeurs
passées en paramètre, la séquence de valeurs formée par les appels récursifs converge vers une valeur satisfaisant
la condition d’arrêt, 0 dans le cas présent.
– On remarque par ailleurs que cet algorithme n’est pas récursif terminal, en effet l’appel récursif précède une
multiplication par n, la dernière instruction n’est donc pas un appel récursif.
Les doutes des plus sceptiques seront, je l’espère apaisés par la vue du sous-programme suivant :
long f a c t o r i e l l e ( long n )
{
i f ( n == 0 )
15
return 1 ;
return n ∗ f a c t o r i e l l e ( n − 1 ) ;
}
Il faut faire en sorte qu’une fois la condition d’arrêt vérifiée le paramètre r contienne le résultat.
16
3.2.1 Factorielle
Étudions un exemple,
Fonction f actorielleT (n, r)
si n = 0 alors
retourner r
sinon
retourner f actorielleT (n − 1, r × n)
fin
FIN
Tout d’abord, on remarque que f actorielleT est bien une fonction récursive terminale. Ensuite observons que si
l’on invoque f actorielleT (n, 1), on obtient la séquence suivante :
(n, 1) −→ (n − 1, n) −→ (n − 2, n × (n − 1)) −→ . . .
n
Y
. . . −→ (i, k) −→ . . .
k=i+1
n
Y n
Y n
Y
. . . −→ (2, k) −→ (1, k) −→ (0, k)
k=3 k=2 k=1
Qn
Au moment où la condition d’arrêt est vérifiée, le paramètre r contient la valeur k=1 k, à savoir n!. On se sert de
l’accumulateur pour fabriquer le résultat. Démontrons par récurrence sur n que f actorielleT (n, r) = r(n!) :
– Tout d’abord, on constate que f actorielleT (0, r) = r
– Supposons que f actorielleT (n − 1, r′ ) retourne la valeur (n − 1)! × r′ , donc f actorielleT (n − 1, n × r) = (n −
1)!(r × n) = r(n!). D’où f actorielleT (n, r) = f actorielleT (n − 1, n × r) = r(n!)
On en déduit qu’en posant r = 1, on a f actorielleT (n, 1) = n! On encapsule f actorielleT dans le sous-programme
f actorielle que l’on redéfinit de la sorte :
Fonction f actorielle(n)
retourner f actorielleT (n, 1)
FIN
3.2.2 Exponentiation
Essayons de créer une fonction récursive terminale calculant bn , comme cette valeur s’obtient par des multiplications
successives, l’accumulateur a est une valeur par lequel le résultat sera multiplié. Nous souhaitons donc mettre un point
une fonction puissanceT (a, b, n) qui retourne a(bn ). On obtiendra bn en initialisant a à 1. On détermine une relation
de récurrence entre bn et bn−1 de la sorte : bn = b.bn−1 , donc abn = (ab)bn−1 , à savoir puissanceT (a × b, b, n − 1).
Allons-y,
Fonction puissanceT (a, b, n)
si n = 0 alors
retourner a
sinon
retourner puissanceT (a × b, b, n − 1)
fin
FIN
17
On calcule donc bn en invoquant puissanceT (1, b, n). On redéfinit puissance(b, n) de la sorte :
Fonction puissance(b, n)
retourner puissanceT (1, b, n)
FIN
Vous avez des doutes ? Traduisez donc ces sous-programmes en C en observez ce qui se passe...
3.2.3 Itérateurs
Exercice 4 - Introduction aux itérateurs
Etant donné une fonction f , on note f n la composition de f par elle-même n fois. Par exemple : f 3 = f ◦ f ◦ f , si
f : x 7→ x + 1, alors f 3 (x) = f (f (f (x))) = x + 3. Par convention, on a f 0 = id, avec id : x 7→ x.
1. Si f : x 7→ x + 1, démontrez par récurrence que f n : x 7→ x + n
2. Si f : x 7→ 2x, démontrez par récurrence que f n : x 7→ 2n x
3. Si f : x 7→ x2 , démontrez par récurrence que f n : x 7→ x( 2n )
4. Ecrire une fonction récursive applyF non terminale prenant en paramètre une fonction f , un nombre n et un
argument x, et retournant f n (x). Ce type de fonction sera appelé un itérateur.
5. Ecrire une version récursive terminale de applyF .
6. Soit f : (a, b) 7→ (a + b, b), montrez par récurrence que f n : (0, b) 7→ (bn, b)
7. Ecrire une fonction f prenant en paramètre le couple (a, b) et retournant (a + b, b).
8. Ecrire la fonction multiplie en utilisant f et applyF .
18
3. Prouvez que I(δ, f, n, b) = bn
4. Ecrivez en C la fonction unsigned long slowPuissanceIT(unsigned long b, unsigned long n), vous utili-
serez applyFD et traduirez en C les fonctions f et δ définies dans la question préccédente.
5. Ecrivez deux fonctions f et δ telles que I(δ, f, n, 1) = n!
6. Prouvez que I(δ, f, n, 1) = n!
7. Ecrivez en C la fonction unsigned long fatorielleIT(unsigned long b, unsigned long n), vous utiliserez
applyFD.
8. Ecrivez une fonction récursive f astP uissance(b, n) calculant bn sans utiliser d’itérateur, vous utiliserez le fait
n n
que bn = (b2 ) 2 si n est pair et bn = b(b2 )⌊ 2 ⌋ sinon.
9. Traduisez-là en C en utilisant le prototype suivant unsigned long fastPuissance(unsigned long b, unsigned
long n).
10. Majorez le nombre d’appels récursifs en fonction de n, est-ce performant ?
11. Ecrivez la fonction f et la fonction δ de sorte que I(δ, f, n, b) = bn . Notez le fait que f prend le couple (n, b) en
paramètre.
12. Prouvez par récurrence la validité de I(δ, f, n, b) = bn .
13. Ecrivez en C la fonction unsigned long fastPuissanceIT(unsigned long b, unsigned long n), vous utili-
serez la fonction applyFD.
19
3.3 Listes chaı̂nées
3.3.1 Notations et conventions
La récursivité est particulièrement adaptée lorsque l’on souhaite manipuler des listes chaı̂nées. Nous utiliserons
pour ce faire les fonctions suivantes :
1. premier(l) retourne la donnée se trouvant dans le premier élément de la liste chaı̂née l.
2. suivants(l) retourne un pointeur l′ vers le deuxième élément de l, cette fonction ne produit aucun effet de bord
et ne modifie pas le chaı̂nage.
3. ajoute(z, l) ajoute la donnée z au début de la liste l et retourne un pointeur vers la liste obtenue, elle modifie
le chaı̂nage.
4. estV ide(l) retourne vrai si et seulement si la liste l ne contient aucun élément.
5. listeV ide() retourne une constante que nous identifierons à la liste vide, c’est-à-dire ne contenant aucun élément.
Vous prendrez soin de ne pas confondre les listes et les données. Ces dernières sont génériques, vous pouvez placer
dans une liste des données de n’importe quel type, même d’autres listes... Nous noterons mathématiquement les listes
entre des crochets, par exemple [1, 4, 3, 7]. La liste vide, retournée par la fonction listeV ide() sera notée []. Vous pourrez
créer une liste à un élément par exemple en écrivant
3.3.2 Rédaction
Les règles de la récursivité sont les mêmes quand on manipule des listes chaı̂nées, on teste le cas de base en premier :
la liste vide, et on fait en sorte que la séquence formée par les valeurs passées en paramètre au file des appels récursifs
converge vers la liste vide. Par exemple,
Procédure sommeListe(l)
si estV ide(l) alors
retourner 0
sinon
retourner premier(l) + sommeListe(suivants(l))
fin
FIN
20
–
– listIndexesSorted(l, i) retourne une liste contenant tous les éléments de la liste l dont l’indice se trouve dans la
liste i. i est supposée triée.
– listDeleteByIndexes(l, i) retourne une liste contenant tous les éléments de l dont l’indice se trouve dans i, i est
supposée triée.
Exercice 9 - Tris
Ecrire les fonctions suivantes en pseudo-code :
– listInsert(l, a), insère la donnée k dans la liste l, retourne un pointeur vers le premier élément de la liste.
– listInsertionSort(l), retourne les éléments de l triés par la méthode du tri par insertion.
– listSplit(l), retourne un couple de listes (m, n) dans lesquelles ont été repartis de façons arbitraire les éléments
de l et telle que le nombre de données de m et n diffère au plus de 1.
– listM erge(l1, l2), retourne une liste l triée contenant les éléments de l1 et de l2. l1 et l2 sont supposées triées.
– listF usionSort(l) retourne une liste contenant les éléments de l triés avec la méthode du tri fusion.
Soit un le nombre d’instructions élémentaires exécutées par af f icheListe si la liste l comporte n maillons. Si n = 0,
l’algorithme s’exécute en temps constant. Sinon, l’appel récursif nécessite un−1 opérations, les autres opérations (au
nombre de k) s’exécutent en temps constant. On définit donc u comme suit : un = un−1 + k, comment exprimer un
en fonction de u0 , de n et de k ?
21
On montre aisément que a et b choisis conformément aux conditions précédant la démonstration par récurrence
an + b
détermine une suite an + b qui majore un . On remarque que an + b croı̂t de façon linéaire, en effet −→ a, donc
n
on a an + b ∈ O(n). Comme un est majorée par une suite linéaire, un ∈ O(n).
Prouvons pour le sport que si un ≤ vn et vn ∈ O(wn ), alors un ∈ O(wn ). Comme vn ∈ O(wn ), alors ∃k, ∃N, ∀n >
N, vn ≤ k.wn , comme un ≤ vn , alors pour les mêmes valeurs k et N , un ≤ vn ≤ k.wn et de ce fait un ≤ k.wn .
Deux ensembles de méthodes ressortent dans les exemples :
– La résolution exacte, elle nécessite le connaissance de bon nombre de méthodes mathématiques, bien qu’élégante,
elle devient vite très compliquée.
– La conjecture d’une majoration suivie d’une preuve par récurrence de cette majoration. La preuve est en règle
générale plus simple à mettre en oeuvre, la partie la plus difficile est de conjecturer une majoration valide et la
moins grossière possible.
3.4.4 Problèmes
Exercice 10 - Tours de Hanoı̈
On dispose de n disques numérotés de 1 à n. Les disques peuvent être empilés sur des socles à partir du moment
où tout disque repose sur un disque de numéro plus élevé. On dispose de trois socles S1 , S2 et S3 , les n disques sont
empilés sur le socle de gauche S1 , ceux du milieu et de droite S2 et S3 sont vides. Le but est de déplacer toute la
pile de disques sur le socle de droite, sachant qu’on ne peut déplacer les disques que un par un, et qu’il ne faut qu’à
aucun moment, un disque numéroté k se trouve sur un disque numéroté m avec m < k (i.e un disque plus petit). Par
exemple, si n = 3, on a
1
2
3
------------
2
3 1
------------
3 2 1
------------
1
3 2
------------
1
2 3
------------
1 2 3
------------
2
1 3
------------
1
2
3
------------
On dispose d’un sous-programme deplaceDisque(Si, Sj ) qui enlève le disque se trouvant au sommet de la pile Si
et la place au sommet de la pile Sj .
1. Trouver un algorithme récursif deplaceDisques(n, Sf rom, Svia , Sto ) permettant de déplacer n disques du socle
Sf rom au socle Sto en utilisant Svia comme socle intermédiaire.
2. Codez en C un programme qui affiche chaque étape du déplacement des n disques, que remarquez-vous lorsque
l’on prend des grandes valeurs de n ?
22
3. Déterminer une relation de récurrence permettant de dénombrer le nombre d’étapes nécessaires pour déplacer n
disques. Résolvez-là.
4. Est-il envisageable de déplacer 100 disques en un temps raisonnable ?
Exercice 12 - Pgcd
Le plus grand commun diviseur de deux entiers relatifs a et b, noté pgcd(a, b), est défini par la relation de récurrence
pgcd(a, b) = pgcd(b, a mod b), avec pgcd(a, 0) = a.
1. Ecrire une fonction récursive calculant le pgcd de deux entiers relatifs.
2. Ecrire une fonction itérative retournant le i-ème nombre de fibonacci.
3. Ecrire les deux sous-programmes unsigned long pgcd(unsigned long a, unsigned long b) et unsigned
long fibonacci(unsigned long l)
4. Tester la fonction pgcd avec des nombres de fibonacci consécutifs. Qu’observez-vous ?
5. Si on s’intéresse au nombre d’appels récursifs nécessaires pour calculer un pgcd, quel est le pire des cas ?
Fn+1
6. Quel est la valeur du quotient ?
Fn
7. En déduire que les entrées de la forme (Fn+1 , Fn forment les pires cas.
8. Combien d’itérations sont nécesaires pour calculer pgcd(Fn+1 , Fn ) ?
9. Prouver que Fn est majoré par une suite géométrique.
√
1+ 5
10. Prouver que le nombre d’appels récursifs est majoré par un logarithme de base φ = .
2
11. Quelle est la complexité de pgcd, est-ce efficace ?
23
2. résolvez le problème pour tout n ≥ 0, vous montrerez que si l’on est capable de résoudre ce problème pour une
valeur n donnée, alors il est possible de le résoudre pour une valeur n + 1.
3. programmez cet algorithme en C, remplissez chaque case avec un caractère. Vous représenterez une pièce en
affectant le même caractère à toutes les cases occupées par cette pièce. Par exemple (avec n = 4),
@ @ ? ? ; ; : : + + * * & & % %
@ > > ? ; 9 9 : + ) ) * & $ $ %
A > B B < < 9 = , ) - - ’ ’ $ (
A A B 8 8 < = = , , - # # ’ ( (
E E D 8 J J I I 0 0 / # 5 5 4 4
E C D D J H H I 0 . / / ! 5 3 4
F C C G K H L L 1 . . 2 6 3 3 7
F F G G K K L " 1 1 2 2 6 6 7 7
U U T T P P O " " j i i e e d d
U S S T P N O O j j h i e c c d
V S W W Q N N R k h h l f f c g
V V W M Q Q R R k k l l b f g g
Z Z Y M M _ ^ ^ o o n b b t s s
Z X Y Y _ _ ] ^ o m n n t t r s
[ X X \ ‘ ] ] a p m m q u r r v
[ [ \ \ ‘ ‘ a a p p q q u u v v
Vous remarquez que la case noircie est celle avec le point d’exclamation. Représentez la matrice en mémoire
de sorte à faciliter l’implémentation récursive de l’algorithme. C’est à dire en indicant de la façon suivante (si
n = 3) ;
0 1 4 5 16 18 20 21
2 3 6 7 17 19 22 23
8 9 12 13 24 25 28 29
10 11 14 15 26 27 30 31
32 33 36 37 48 49 52 53
34 35 38 39 50 51 54 55
40 41 44 45 56 57 60 61
42 43 46 47 58 59 62 63
#include ” l i n k e d L i s t . h”
/∗
Type complexe
∗/
typedef s tr u ct
{
24
/∗
Partie r e e l l e
∗/
double r e ;
/∗
p a r t i e imaginaire
∗/
double im ;
/∗
module
∗/
double mod ;
/∗
argument , nu l s i l e nombre e s t 0 + 0 i
∗/
double a r g ;
} complexe , ∗ pComplexe ;
double reComplexe ( c o m p l e x e c ) ;
/∗
Retourne l a p a r t i e i m a g i n a i r e
∗/
double imComplexe( c o m p l e x e c ) ;
/∗
Retourne l e module
∗/
double modComplexe ( c o m p l e x e c ) ;
/∗
Retourne l ’ argument
∗/
double argComplexe ( c o m p l e x e c ) ;
/∗
A f f i c h e c so u s forme e x p o n e n t i e l l e
∗/
void printExpComplexe ( c o m p l e x e c ) ;
/∗
A f f i c h e l ’ a f f i x e de c
∗/
void p r i n t A f f C o m p l e x e ( c o m p l e x e c ) ;
/∗
Cree un complexe a p a r t i r de son a f f i x e
∗/
c o m p l e x e makeAffComplexe ( double r e , double im ) ;
/∗
Cree un complexe a p a r t i r de sa forme e x p o n e n t i e l l e
∗/
c o m p l e x e makeExpComplexe( double mod , double a r g ) ;
/∗
Retourne l e c o nju g u e de c
∗/
c o m p l e x e c o n j u g u e Co m ple xe ( c o m p l e x e c ) ;
/∗
S o u s t r a i t c1 e t c2
∗/
c o m p l e x e subComplexe ( c o m p l e x e c1 , c o m p l e x e c 2 ) ;
/∗
Ad d it io nne c1 e t c2
∗/
c o m p l e x e addComplexe ( c o m p l e x e c1 , c o m p l e x e c 2 ) ;
/∗
M u l t i p l i e c1 e t c2
∗/
c o m p l e x e multComplexe ( c o m p l e x e c1 , c o m p l e x e c 2 ) ;
/∗
Multiplie c par l e reel d
25
∗/
c o m p l e x e multReelComplexe ( double d , c o m p l e x e c ) ;
/∗
D i v i s e c2 par c1
∗/
c o m p l e x e divComplexe ( c o m p l e x e c1 , c o m p l e x e c 2 ) ;
/∗
Eleve c a l a puissance n
∗/
c o m p l e x e p u i ssCo m p l e x e ( c o m p l e x e c , unsigned long n ) ;
/∗
Retourne un p o i n t e u r v e r s une c o p i e du complexe c .
∗/
pComplexe copyComplexe ( c o m p l e x e c ) ;
#en d i f
#d ef i n e LINKED LIST H
/∗
M a il l o n de l a liste chainee
∗/
typedef s tr u ct l
{
/∗
p o i n t e u r v e r s l a donnee
∗/
void∗ d a t a ;
/∗
pointeur vers l e maillon suivant
∗/
s tr u ct l ∗ n e x t ;
} link ;
/∗
Type e n c a p s u l a n t l a liste chainee
∗/
typedef s tr u ct
{
/∗
nombre d ’ e l e m e n t s de l a liste chainee
∗/
int s i z e ;
/∗
p o i n t e u r v e r s l e p r e m ie r e l e m t n de l a liste chainee
∗/
link ∗ f i r s t ;
/∗
p o i n t e u r v e r s l e d e r n i e r e l e m e nt de l a liste chainee
∗/
link ∗ last ;
} linkedList ;
/∗
Cree une l i s t e c h a i n e e ne c o nt e na nt aucun e l e m e nt .
∗/
linkedList ∗ linkedListCreate ( ) ;
/∗
Ajo u t e l ’ e l e m e nt x dans a l a f i n de l a liste chainee l
∗/
void l i n k e d L i s t A p p e n d ( l i n k e d L i s t ∗ l , void∗ x ) ;
26
/∗
Ajo u t e l e m a i l l o n l k a l a f i n de l a liste l
∗/
void l i n k e d L i s t A p p e n d L i n k ( l i n k e d L i s t ∗ l , link ∗ lk );
/∗
Ajo u t e l ’ e l e m e nt x dans au d e b u t de l a liste chainee l
∗/
void l i n k e d L i s t P u s h ( l i n k e d L i s t ∗ l , void∗ x ) ;
/∗
Ajo u t e l e m a i l l o n l k au d e b u t de l a liste l
∗/
void l i n k e d L i s t P u s h L i n k ( l i n k e d L i s t ∗ l , link ∗ lk ) ;
/∗
Retourne l a t a i l l e de l a liste l
∗/
int l i n k e d Li st Ge t S i z e ( l i n k e d L i s t ∗ l ) ;
/∗
Retourne un p o i n t e u r v e r s l e p r e m ie r m a i l l o n de
l a l i s t e c h a i n e e l , NULL s i l e s t v i d e .
∗/
/∗
Retourne un p o i n t e u r v e r s l e p r e m ie r m a i l l o n de l ,
e n l e v e ce m a i l l o n de l a l i s t e l . Retourne NULL
si l est vide .
∗/
/∗
Retourne une l i s t e c h a i n e e c o nt e na nt t o u t e s l e s images
d e s donnees par l a f o n c t i o n f . En p o sa nt f = id , on o b t i e n t
une f o n c t i o n de c o p i e .
∗/
l i n k e d L i s t ∗ l i n k e d L i s t M a p ( l i n k e d L i s t ∗ l , void∗ ( ∗ f ) ( void ∗ ) ) ;
/∗
Concatene l e s deux l i s t e s b e g i n e t end , l a deuxieme e s t a j o u t e e
a l a f i n de l a p r e m ie r e .
∗/
void l i n k e d L i s t C o n c a t ( l i n k e d L i s t ∗ b e g i n , l i n k e d L i s t ∗ end ) ;
/∗
Ap p l iq u e l a f o n c t i o n f a t o u t e s l e s donnees de l a l i s t e l .
P a sse r une f o n c t i o n d ’ a f f i c h a g e permet par exemple d ’ a f f i c h e r
l e s donnees de chaque m a i l l o n .
∗/
/∗
Desalloue l et tous ses maillons , applique le destructeur fr
a l a donnee de chaque m a i l l o n .
∗/
#en d i f
27
– link* triInsertion(link* list, int (*estInf)(void*, void*)), trie par insertion la liste list en utili-
sant la fonction de comparaison estInf.
– void linkedListSort(linkedList* l, int (*estInf)(void*, void*)), trie la liste l en modifiant le chaı̂nage,
vous n’oublierez pas de mettre à jour l->first et l->last.
– Identifez le pire des cas et observez la façon dont le temps d’exécution croı̂t avec le nombre de maillons. Est-ce
que cela corrobore les conclusions théoriques ?
n−1
X
1. Soit P (x) = a0 + ai xi un polynome de degré n − 1. Que vaut l’algorithme A(P, x, n) ?
i=1
28
2. Quelle est la complexité de A ?
3. La méthode de Horner est basée sur la relation suivante P (x) = a0 + x(a1 + x(a2 + x(. . .))). Ecrivez l’algorithme
récursif horner qui calcule P (x) en utilisant cette relation.
4. Quelle est la complexité de horner ?
n−1
X
5. Soit P (x) = a0 + ai xi un polynôme de degré n − 1 et b = T F (a). Montrez que bp = P (wnp ).
i=1
6. Comment calculer T F (a) en utilisant le sous-programme horner ? Ecrivez le sous-programme T F .
7. On note T F −1 la transformée inverse de Fourier, nous admettrons que si a = T F −1 (b), alors
n−1
1X
aq = bk ωn−kq
n
k=0
Ecrivez le sous-programme T F −1 .
8. Quelle sont les complexités de T F et de T F −1 ?
2k
9. Prouvez que pour tous n et k, ω2n = ωnk .
10. Supposons que n est pair, donc qu’il existe m tel que n = 2m. Soit a[0] = (a0 , a2 , . . . , a2m ), a[1] = (a1 , a3 , . . . , a2m+1 ),
b[0] = T F (a[0] ) et b[1] = T F (a[1] ). Soit q ∈ {0, . . . , m − 1}, montrez que
bq = b[0] q [1]
q + ωn bq
puis que
bq+m = b[0] q+m [1]
q + ωn bq
11. Ecrire le sous-programme F F T qui calcule la transformée discrète de Fourier d’un vecteur de taille n = 2k en
utilisant la relation de récurrence ci-dessus.
12. Quelle est la complexité de F F T ?
13. Supposons que n est pair, donc qu’il existe m tel que n = 2m. Soit b[0] = (b0 , b2 , . . . , b2m ), b[1] = (b1 , b3 , . . . , b2m+1 ),
y [0] = T F −1 (b[0] ) et y [1] = T F −1 (b[1] ). Soit p ∈ {0, . . . , m − 1} et y = T F −1 (b). Montrez que
1 [0]
yp = (y + ωn−p yp[1] )
2 p
puis que
1 [0]
yp+m = (y + ωn−(p+m) yp[1] )
2 p
14. Ecrire le sous-programme F F T −1 qui calcule la transformée inverse de Fourier d’un vecteur de taille n = 2k en
utilisant la relation de récurrence ci-dessus.
15. Quelle est la complexité de F F T −1 ?
16. Ecrivez les fonctions du fichier fourier.c correspondant au fichier fourier.h ci-dessous.
#i f n d e f FOURIER H
#d ef i n e FOURIER H
#include ” l i n k e d L i s t . h”
#include ” c o m p l e x e . h”
/∗
Retourne l a t r a n s f o r m e e d i s c r e t e de Fo u r ie r du v e c t e u r l .
Al g o r it h m e i t e r a t i f en O( n ˆ 2 ) .
∗/
linkedList ∗ transformeeFourierIt ( linkedList ∗ l );
/∗
Retourne l a t r a n s f o r m e e d i s c r e t e de Fo u r ie r i n v e r s e
du v e c t e u r l . Al g o r it h m e i t e r a t i f en O( n ˆ 2 ) .
∗/
linkedList ∗ transformeeInverseFourierIt ( linkedList ∗ l );
29
/∗
Retourne l a t r a n s f o r m e e d i s c r e t e de Fo u r ie r du v e c t e u r l , de t a i l l e
n = 2ˆm. Al g o r it h m e r e c u r s i f en O( n l o g n ) .
∗/
l i n k e d L i s t ∗ FFT( l i n k e d L i s t ∗ l ) ;
/∗
Retourne l a t r a n s f o r m e e d i s c r e t e de Fo u r ie r i n v e r s e
du v e c t e u r l de t a i l l e n = 2ˆm. Al g o r it h m e r e c u r s i f en
O( n l o g n ) .
∗/
l i n k e d L i s t ∗ i n v e r se F F T ( l i n k e d L i s t ∗ l ) ;
#en d i f
{(1, P (1)), (2, P (2)), (3, P (3)), (4, P (4)), (5, P (5))}
et
{(1, Q(1)), (2, Q(2)), (3, Q(3)), (4, Q(4)), (5, Q(5))}
Cela nous donne 5 points par lesquels passe la courbe de P Q :
{(1, P (1)Q(1)), (2, P (2)Q(2)), (3, P (3)Q(3)), (4, P (4)Q(4)), (5, P (5)Q(5))}
Il suffit ensuite d’effectuer une interpolation des coefficients a, b, c, d et e de la courbe de P Q, cela se fait en
résolvant le système d’équations
{a14 + b13 + c12 + d11 + e = P (1)Q(1), a24 + b23 + c22 + d21 + e = P (2)Q(2), . . .}
Chacune de ces méthoes requiert O(n2 ) opérations. Il est cependant possible d’affiner la deuxième en choisissant
judicieusement les points servant à évaluer puis à interpoler. En prenant Wn comme ensemble de points, on ramène les
évaluations de ces points à des transformées de Fourier et l’interpolation à une transformation inverse de Fourier. Cela
permet de multiplier des polynômes en O(n log2 n). Voyez [2] pour un exposé davantage détaillé. Ecrivez les fonctions
du fichier polynomes.c correspondant au fichier polynomes.h ci-dessous. Vous prendrez soin de vous assurer que la
multiplication à l’aide de la transformée de Fourier est plus rapide que la version pour boeufs.
#i f n d e f POLYNOME H
#d ef i n e POLYNOME H
#include ” l i n k e d L i s t . h”
#include ” c o m p l e x e . h”
#include ” f o u r i e r . h”
/∗
Nous r e p r e s e n t e r o n s un polynome a v e c une l i s t e c h a i n e e c o nt e na nt
l e s c o e f f i c i e n t s du polynome par o r d r e de d e g r e c r o i s s a n t .
∗/
/∗
Retourne un polynome v i d e .
∗/
30
l i n k e d L i s t ∗ makePolynome ( ) ;
/∗
Retourne une c o p i e de l , c o p i e a u s s i l e s coefficients .
∗/
l i n k e d L i s t ∗ copyPolynome ( l i n k e d L i s t ∗ l ) ;
/∗
D e t r u i t l e polynome l e t s e s c o e f f i c i e n t s .
∗/
void d e st r o y P o l y n o m e ( l i n k e d L i s t ∗ l ) ;
/∗
A f f i c h e polynome l e p l u s proprement p o s s i b l e .
∗/
void p r i n t P o l y n o m e ( l i n k e d L i s t ∗ polynome ) ;
/∗
Retourne l e d e g r e de l .
∗/
int degreePolynome( l i n k e d L i s t ∗ l ) ;
/∗
Ajo u t e un monome de c o e f f i c i e n t c o e f f a l a f i n du polynome , faisant
a i n s i c r o u t r e son d e g r e de 1 .
∗/
void appendCoeffPolynome ( l i n k e d L i s t ∗ polynome , double c o e f f ) ;
/∗
Cree e t r e t o u r n e l e polynome de d e g r e n−1 dont l e s
c o e f f i c i e n t s s o n t p a s s e s dans l e t a b l e a u d .
∗/
l i n k e d L i s t ∗ makeArrayPolynome( double∗ d , i n t n ) ;
/∗
Retourne l e polynome nu l .
∗/
l i n k e d L i s t ∗ z e r o P o l y n o me ( ) ;
/∗
Retourne l e polynome u n i t e .
∗/
l i n k e d L i s t ∗ u n i t P o l y n o me ( ) ;
/∗
Ajo u t e l a c o n s t a n t e d au polynome l .
∗/
void addRealPolynome( l i n k e d L i s t ∗ l , double d ) ;
/∗
M u l t i p l i e l e polynome l par l e r e e l d .
∗/
void multRealPolynome ( l i n k e d L i s t ∗ l , double d ) ;
/∗
M u l t i p l i e l e polynome l par Xˆn
∗/
void multXNPolynome ( l i n k e d L i s t ∗ l , i n t n ) ;
/∗
M u l t i p l i e l e polynome l par c o e f f ∗Xˆ exp
∗/
void multMonomePolynome ( l i n k e d L i s t ∗ l , double c o e f f , i n t exp ) ;
/∗
A d d i t i o n e l e s deux polynomes a e t b , r e t o u r n e c e t t e somme.
∗/
l i n k e d L i s t ∗ addPolynome ( l i n k e d L i s t ∗ a , l i n k e d L i s t ∗ b ) ;
/∗
M u l t i p l i e a e t b avec l a recurrence
( a 0 + a 1X + . . . + a nXˆn)Q(X)
= a 0 ∗ Q(X) + X ∗ ( a 1 + a 2 X. . . + a n Xˆ(n−1)) ∗ Q(X)
∗/
l i n k e d L i s t ∗ slowMultPolynome ( l i n k e d L i s t ∗ a , l i n k e d L i s t ∗ b ) ;
/∗
M u l t i p l e a e t b en p a s s a n t par une t r a n s f o r m e e de f o u r i e r .
∗/
l i n k e d L i s t ∗ multPolynome ( l i n k e d L i s t ∗ a , l i n k e d L i s t ∗ b ) ;
31
/∗
E v a l u e l e polynome l en x a v e c l a methode de Horner .
∗/
double e v a l u a t e P o l y n o m e ( l i n k e d L i s t ∗ l , double x ) ;
#en d i f
32
Chapitre 4
Arbres
4.1.1 Définition
On définit un ensemble E par induction en deux étapes :
– La base La base est une liste d’éléments de E qui sont des atomes. On les notes A et on la propriété A ⊂ E.
– L’induction L’induction est un ensemble de règles permettant de créer un élément de E avec d’autres éléments
de E. Chaque règle est une fonction f : E k −→ E telle que si (E1 , . . . , Ek ) est un k-uplet d’éléments de E, alors
f (E1 , . . . , Ek ) ∈ E.
4.1.2 Exemple
Considérons l’ensemble IN des entiers naturels, on le définit de la sorte :
– Base la seul atome de IN est 0. Donc On les note A = {0}.
– Induction On prend comme unique règle la fonction s : x 7→ x + 1 appelée successeur. Pour tout élément n de
IN, on a s(n) ∈ N .
On conviendra donc que IN est l’ensembles de tous les éléments faisant soit partie de A, soit pouvant être obtenu
par application d’un nombre fini de règles. Par exemple, 0 ∈ IN, car 0 ∈ A, 4 ∈ IN, car 0 ∈ A et 4 = s(s(s(s(0)))) ∈ IN
(vous remarquez que 4 s’obtient par application d’un nombre fini de règles).
33
4.1.4 Application aux arbres binaires
Soit f une fonction prenant an argument un arbre binaire, la façon la plus claire et la précise de définir une telle
fonction est souvent de la caractériser par induction. Par exemple
Définition 4.1.2 On note |A| le nombre de noeuds d’un arbre A. On le définit par induction :
– |∅| = 0
– |(A, r, B)| = 1 + |A| + |B|
34
Si a est une variable de type AB alors a.cle est la clé de la racine de l’arbre a, a.d est un pointeur vers le sous-arbre
droit, a.g est un pointeur vers le sous-arbre gauche. Si un pointeur ne pointe vers aucune valeur, on dira qu’il prend
la valeur null. On fera une allocation dynamique en utilisant la fonction AB(fg , c, fd ) pour créer un noeud de clé c et
de sous-arbre gauche (resp. droit) fg (resp. fd ) de type AB.
Exercice 3 - Hauteur
Ecrire une fonction retournant la hauteur d’un arbre A.
Exercice 4 - Profondeur
Ecrire une fonction retournant la profondeur d’un noeud x dans un arbre A.
35
Chapitre 5
Files de priorité
Une file de priorité est une structure de donnée permettant de stocker un ensemble d’éléments munis d’une clé
d’ordre total, et dans laquelle on s’intéresse aux opérations suivantes :
– Extraction du plus petit élément
– Ajout d’un élément
– Suppression du plus petit élément
5.2 Tas
5.2.1 Définition
Un tas est un arbre binaire vérifiant les propriétés suivantes :
1. Tous les niveaux sont remplis sauf éventuellement le dernier.
2. Dans le dernier niveau, les noeuds sont disposés le plus à gauche possible.
36
3. Tous noeud possède une clé inférieure à celle de ses deux fils.
Par exemple,
1
2 6
7 3 7 11
8 12
Vous remarquez que les trois premiers niveaux sont remplis et que dans le quatrième niveau, les noeuds disposés
le plus à gauche possible. De même, on constate que chaque noeud a une clé inférieure à celle de ses fils.
Exercice 5 - Définition
Représenter un tas contenant les éléments suivants : {3, 87, −1, 0, 3, 9, 54, −3}. Vous disposerez les éléments à votre
convenance du moment que l’arbre considéré est bien un tas.
Exercice 6 - Hauteur
Majorer la hauteur d’un tas contenant n éléments.
5.2.3 Insertion
Pour insérer un élément dans un tas, on choisit l’unique emplacement qui permet de conserver les deux premières
propriétés ? Ensuite on réequilibre le tas. Le soin de cette procédure vous est laissé en exercice.
Exercice 7 - Ajout
Décrire la procédure permettant de déterminer où insérer un nouvel élément dans un tas.
5.2.5 Implémentation
En règle générale, on implémente un tas avec un tableau. Les éléments sont disposés dans l’ordre d’un parcours en
largeur de la gauche vers la droite.
37
Exercice 9 - Indices
Nous indicerons les tableaux à partir de 1. Déterminez une relation de récurrence entre l’indice d’un noeud et les
indices de ses voisins (père, fils gauche, fils droit).
Exercice 10 - Performances
Faites le point sur les temps d’exécution des diverses opérations. Est-ce efficace ?
B n−1
B n−1
Exercice 12 - Propriétés
Prouver par induction les propriétés suivantes :
1. Bn contient 2n noeuds.
2. Bn est de hauteur n.
3. La racine de Bn a n fils.
4. Les n fils de la racine de Bn sont B0 , B1 , . . ., Bn−1 .
5. Il y a Cnk noeuds de profondeur k dans Bn .
5.3.2 Fusion
Etant donnés deux arbres binomiaux, on les fusionne en faisant de l’un un fils de la racine de l’autre. Cette opération
(jeu d’adresses) se fait en temps constant.
38
5.3.3 Tas binomial
Un tas binomial est une liste d’arbres binomiaux vérifiant les propriétés suivantes :
– Dans chaque arbre, tout noeud est de clé inférieure à ses fils.
– Tous les arbres sont d’ordres distincts.
5.3.4 Implémentation
Les tas binomiaux ne sont pas triviaux à implémenter. On représente un tas binomial par une liste chaı̂née d’arbre
binomiaux. Chaque arbre binomial est représenté par un ordre, une clé, et un pointeur vers la liste chaı̂née de ses fils.
Le premier des fils est l’arbre d’ordre le plus élevé.
Exercice 13 - Implémentation
Représenter graphiquement la représentation en mémoire d’un tas binomial.
Exercice 15 - Complexité
Quelle est la complexité de l’extraction du minimum ?
5.3.6 Fusion
Etant donnés deux tas binomiaux, il est possible de les fusionner en utilisant comme sous-programme la fusion de
deux arbres.
Exercice 16 - Fusion
Décrire une méthode récursive permettant de fusionner deux tas binomiaux. Quelle en est la complexité ?
39
Chapitre 6
Hachage
6.1 Principe
Une table de hachage est une structure de données indexée par des valeurs V = {1, . . . , m}, comme un tableau.
On dit alors que cette table est de taille m. Une table de hachage contient des éléments posédant chacun une clé, on
note C = {1, . . . , n} l’ensemble des clés. Il existe en règle générale beaucoup plus de clés que d’indices dans une table.
On affecte à chaque élément, donc à chaque clé, un (ou plusieurs) indice dans la table. Pour ce faire, on dispose d’une
fonction de hachage h : C −→ V , qui à toute clé c associe un indice h(c) permettant de placer (rechercher, ou
supprimer) un élément dans la table de hachage.
6.2 Collisions
Comme |C| > |V |, h ne peut être injective. Par conséquent, il est possible que des éléments se téléscopent, c’est-à-
dire que deux clés distinctes aient la même image par h. Deux techniques existent pour gérer les collisions :
1. Le chaı̂nage
2. L’adressage ouvert
40
Exercice 2 - Temps moyen de recherche d’un noeud
On considère une fonction de hachage h qui répartit uniformément les clés dans une table de hachage de taille m
dans laquelle les collisions sont résolues par chaı̂nage.
1. Si n clés sont présentes dans la table, quelle est la longueur moyenne d’une liste.
2. Quelle est la durée moyenne d’une recherche infructueuse dans la table ?
3. On part du principe que si r(x) est le rang d’insertion de la clé x dans la table, les n valeurs que peut prendre
r(x) sont équiprobables. Déterminer la durée moyenne d’une recherche de x.
4. Quelle est la durée moyenne de recherche d’une clé présente dans la table ?
5. Quelle est la durée moyenne moyenne de recherche d’une clé dans une table de hachage de taille m contenant
O(m) clés ?
41
Chapitre 7
AVL
Exercice 1 - Définition
Construire tous les ABR contenant les valeurs {1, 2, 3}
Exercice 3 - Insertions
1. Dessiner l’arbre A(v) défini comme suit :
– a = (∅, 4, ∅)
– b = ((∅, 11, ∅), 7, ∅)
– c = (∅, 3, (∅, 9, ∅))
– d = ((∅, 12, ∅), 6, (∅, 2, ∅))
– v = ((a, 5, b), 1, (c, 10, d))
2. Est-ce un ABR bien formé ?
3. Changer l’ordre des noeuds de sorte que A(v) devienne un ABR.
4. Insérez le noeud de clé 8 dans cet arbre
Exercice 4 - Suppression
On notera
– succA (x) le successeur de x dans A, c’est-à-dire l’élément de A(x) de plus petite clé parmi les éléments de clé
supérieure à celle de x.
– premier(A(x)) le plus petit élément de A(x)
1. Prouvez que si un noeud x d’un arbre A a deux fils, alors succA (x) n’a pas de fils gauche.
2. Montrez que y = succA (x) si et seulement si y = premier(Ad (x) ou x = dernier(Ag (y)).
3. Supprimez la racine de l’arbre de l’exercice précédent
42
Exercice 5 - Fonctions récursives
1. Ecrire une fonction insérant une clé x dans un arbre A et retournant l’arbre obtenu.
2. Ecrire une fonction retournant la clé minimale de l’arbre A.
3. Ecrire une fonction prenant un arbre A en paramètre et retournant le couple (A privé de sa clé minimale, la clé
minimale de A).
4. Ecrire une fonction retournant vrai si et seulement si l’arbre A passé en paramètre est un ABR bien formé.
5. Ecrire une fonction prenant en paramètres un arbre A est une valeur c, et retournant l’arbre A dans lequel aura
été supprimé le noeud de clé c.
7.3 Rotations
Nous allons étudier une opération sur les ABR s’appelant la rotation (je vous conseille de faire des dessins si vous
tenez à vous représenter les choses concrètement). Il existe deux rotations simples (la rotation droite et la rotation
gauche), et deux rotations doubles (la rotation droite-gauche et la rotation gauche-droite). La rotation droite est définie
de la sorte :
43
rotationDroite(((B, y, C), x, D)) = (B, y, (C, x, D))
De façon symétrique, on définit la rotation gauche :
7.4 AVLs
Si pour un noeud v d’un ABR, les hauteurs des sous-arbres droit et gauche de v diffèrent de au plus 1, on dit que
ce noeud est équilibré. Un AVL est un ABR dans lequel tous les noeuds sont équilibrés.
7.4.1 Rééquilibrage
Les rotations vont servir à maintenir l’équilibre de chaque noeud. Nous allons nous intéresser à l’équilibre d’un
arbre de racine v dont les deux sous-arbres (G et D) sont équilibrés, et ont des hauteurs qui diffèrent de 2. Supposons,
sans perte de généralité, que h(D) = n, et que h(G) = n + 2. Soit G = (B, y, D), alors deux cas se présentent :
– si h(B) = n + 1, alors une rotation droite de v équilibre l’arbre.
– si h(B) 6= n + 1, alors une rotation gauche-droite de v équilibre l’arbre.
7.4.2 Insertion
Pour insérer un noeud, procédez comme avec des ABR pour l’ajouter en tant que feuille. Ensuite, contrôlez
l’équilibre de chaque noeud et faites des rotations si nécessaire sur le chemin allant de la feuille nouvellement insérée
à la racine.
7.4.3 Suppression
De la même façon qu’avec des ABR, on supprime un noeud en le remplaçant par le noeud du plus grande clé du
sous-arbre gauche, ou celui de plus petite clé du sous-arbre droit. La suppression du minimum ou du maximum a
les mêmes conséquences que pour l’insertion, il est nécessaire de contrôler l’équilibre de chaque noeud sur le chemin
menant du père de la feuille supprimée à la racine.
7.4.4 Compléments
Pour plus de détails, je vous conseille de vous reporter à [3]. L’applet [4] illustre graphiquement le fonctionnement
d’un AVL.
Exercices
Exercice 8 - Implémentation en C
Ecrivez les fonctions du fichier avl.c correspondant au fichier avl.h ci-dessous :
#i f n d e f AVL H
#include ” l i n k e d L i s t . h”
#d ef i n e AVL H
typedef s tr u ct
{
44
/∗
P o int e u r v e r s une f o n c t i o n p e r m e t t a nt de
r e c u p e r e r l a c l e de chaque donnee .
∗/
i n t ( ∗ getKey ) ( void ∗ ) ;
/∗
P o int e u r v e r s une f o n c t i o n p e r m e t t a nt de
de d e t r u i r e chaque donnee .
∗/
void ( ∗ f r e e D a t a ) ( void ∗ ) ;
/∗
P o int e u r v e r s l a r a c i n e de l ’ a r b r e .
∗/
void∗ r o o t ;
} avl ;
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Retourne un AVL v i d e .
∗/
/∗
M o d ifie l a f o n c t i o n de d e s t r u c t i o n d e s donnees .
∗/
/∗
Affiche les c l e s de l ’AVL a dans l ’ o r d r e c r o i s s a n t , O(n ) .
∗/
void a v l P r i n t K e y s ( a v l ∗ a ) ;
/∗
I n s e r e l a donnee v dans l ’AVL a , O( l o g n ) .
∗/
void a v l I n s e r t ( a v l ∗ a , void∗ v ) ;
/∗
Retourne l a donnee de c l e x s i elle s e t r o u v e dans l ’AVL a ,
NULL sinon , O( l o g n ) .
∗/
void∗ a v l F i n d ( a v l ∗ a , i n t x ) ;
/∗
Supprime l e noeud de c l e k de l ’AVL a , a p p l i q u e l a f o n c t i o n
de d e s t r u c t i o n a l a donnee de c l e k , O( l o g n ) .
∗/
void avlRemove ( a v l ∗ a , i n t k ) ;
/∗
D e t r u i t l ’AVL a , a p p l i q u e l a f o n c t i o n de d e s t r u c t i o n a
t o u t e s l e s donnees du sous−a r b r e , O(n ) .
∗/
void a v l D e s t r o y ( a v l ∗ a ) ;
/∗
Retourne une l i s t e c h a i n e e c o nt e na nt t o u t e s l e s donnees
de l ’AVL a d i s p o s e e s dans l ’ o r d r e c r o i s s a n t , O(n ) .
∗/
l i nk e dL i s t ∗ avlToList ( avl ∗ a ) ;
#en d i f
Et voici avl.c.
#include<s t d i o . h>
#include<m a l l o c . h>
#include ” a v l . h”
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
45
/∗
Noeud de l ’ABR.
∗/
typedef s tr u ct nd
{
/∗
k e y e s t l a c l e du noeud c o u r a nt .
∗/
i n t key ;
/∗
p o i n t e u r v e r s l ’ e l e m e nt de c l e k e y
∗/
void∗ d a t a ;
/∗
h a u t e u r du sous−a r b r e :
0 s i ce noeud e s t une f e u i l l e .
∗/
int height ;
/∗
P o int e u r v e r s l e sous−a r b r e d r o i t .
∗/
s tr u ct nd ∗ l e f t ;
/∗
P o int e u r v e r s l e sous−a r b r e gauche .
∗/
s tr u ct nd ∗ r i g h t ;
} node ;
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Retourne l a h a u t e u r de l ’ a r b r e de r a c i n e l ,
−1 s i l e s t v i d e .
∗/
i n t g e t H e i g h t ( node ∗ l )
{
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Retourne l a p l u s grande d e s deux v a l e u r s i et j .
∗/
i n t max ( i n t i , i n t j )
{
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Met a j o u r l a h a u t e u r de l a r a c i n e l en f o n c t i o n d e s
h a u t e u r s d e s r a c i n e s d e s deux sous−a r b r e s .
∗/
void s e t H e i g h t ( node∗ l )
{
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Cree un noeud c o nt e na nt l a donnee data ,
a ya nt pour sous−a r b r e gauche l e t
pour sous−a r b r e d r o i t r .
∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Retourne un a v l v i d e
46
∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
F a i t de f r e e D a t a l a f o n c t i o n de d e s t r u c t i o n d e s donnees .
∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Affiche toutes l e s c l e s du sous−a r b r e de r a c i n e n dans
l ’ ordre c r o i s s a n t .
∗/
void n o d e P r i n t K e y s ( node ∗ n )
{
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
A f f i c h e pour t o u s l e s noeuds du sous−a r b r e de r a c i n e n
l a d i f f e r e n c e e n t r e l e s h a u t e u r s du sous−a r b r e d r o i t e t
gauche .
∗/
void n o d e P r i n t L e v e l s ( node∗ n )
{
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
E f f e c t u e une r o t a t i o n d r o i t e de l ’ a r b r e de r a c i n e x ,
r e t o u r n e l a r a c i n e de l ’ a r b r e a p r e s r o t a t i o n .
∗/
node∗ r o t a t e R i g h t ( node ∗ x )
{
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
E f f e c t u e une r o t a t i o n gauche de l ’ a r b r e de r a c i n e x ,
r e t o u r n e l a r a c i n e de l ’ a r b r e a p r e s r o t a t i o n .
∗/
node∗ r o t a t e L e f t ( node ∗ x )
{
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
E f f e c t u e une r o t a t i o n gauche−d r o i t e de l ’ a r b r e de r a c i n e x ,
r e t o u r n e l a r a c i n e de l ’ a r b r e a p r e s r o t a t i o n .
∗/
node∗ r o t a t e L e f t R i g h t ( node ∗ x )
{
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
E f f e c t u e une r o t a t i o n d r o i t e −gauche de l ’ a r b r e de r a c i n e x ,
r e t o u r n e l a r a c i n e de l ’ a r b r e a p r e s r o t a t i o n .
∗/
node∗ r o t a t e R i g h t L e f t ( node ∗ x )
{
47
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
R e e q u i l i b r e l ’ a r b r e de r a c i n e x , r e t o u r n e l a r a c i n e de
l ’ a r b r e a p r e s r e e q u i l i b r a g e . On p a r t du p r i n c i p e
que l e s h a u t e u r s d e s sous−a r b r e s d r o i t e t gauche d i f f e r e n t
de au p l u s 1 .
∗/
node∗ b a l a n c e ( node∗ x )
{
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
I n s e r e l a donnee v dans l ’ a r b r e de r a c i n e n
e t r e e q u i l i b r e l ’ a r b r e , r e t o u r n e l a r a c i n e de
l ’ arbre apres inse rtion et re e q u i l i b r a g e .
∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
I n s e r e l a donnee v dans l ’ a r b r e a , O( l o g n ) .
∗/
void a v l I n s e r t ( a v l ∗ a , void∗ v )
{
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Affiche les c l e s de l ’AVL a dans l ’ o r d r e c r o i s s a n t , O(n )
∗/
void a v l P r i n t K e y s ( a v l ∗ a )
{
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
A f f i c h e pour chaque noeud l a d i f f e r e n c e e n t r e l e s hauteurs
d e s sous−a r b r e s d r o i t e t gauche de l ’AVL.
∗/
void a v l P r i n t L e v e l s ( a v l ∗ a )
{
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Retourne l a donnee de c l e k s i elle s e t r o u v e dans l e sous−a r b r e
de r a c i n e n , NULL sino n .
∗/
void∗ f i n d N o d e ( node∗ n , i n t k )
{
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Retourne l a donnee de c l e x s i elle s e t r o u v e dans l ’AVL a ,
NULL sinon , O( l o g n)
∗/
void∗ a v l F i n d ( a v l ∗ a , i n t x )
{
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
48
/∗
F a i t p o i n t e r ∗max v e r s l e noeud de c l e maximale dans
l e sous−a r b r e de r a c i n e n , d e t a c h e l e noeud ∗max de l ’ a r b r e
e t r e t o u r n e l a r a c i n e de l ’ a r b r e a p r e s s u p p r e s s i o n .
∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
F a i t p o i n t e r ∗min v e r s l e noeud de c l e minimale dans
l e sous−a r b r e de r a c i n e n , d e t a c h e l e noeud ∗min de l ’ a r b r e
e t r e t o u r n e l a r a c i n e de l ’ a r b r e a p r e s s u p p r e s s i o n .
∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Supprime l e noeud de c l e k du sous−a r b r e de r a c i n e n ,
a p p l i q u e l a f o n c t i o n de d e s t r u c t i o n a l a donnee de ce noeud ,
e t r e t o u r n e l a r a c i n e de l ’ a r b r e a p r e s l a s u p p r e s s i o n .
∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Supprime l e noeud de c l e k de l ’AVL a , a p p l i q u e l a f o n c t i o n
de d e s t r u c t i o n a l a donnee de c l e k , O( l o g n ) .
∗/
void avlRemove ( a v l ∗ a , i n t k )
{
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
P l a c e dans l a l i s t e c h a i n e e l t o u t e s l e s donnees
du sous−a r b r e de r a c i n e n dans l ’ o r d r e c r o i s s a n t .
∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Retourne une l i s t e c h a i n e e c o nt e na nt t o u t e s l e s donnees
de l ’AVL a d i s p o s e e s dans l ’ o r d r e c r o i s s a n t , O(n ) .
∗/
l i nk e dL i s t ∗ avlToList ( avl ∗ a )
{
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
D e t r u i t t o u s l e s noeuds du sous−a r b r e de r a c i n e n ,
a p p l i q u e l a f o n c t i o n de d e s t r u c t i o n f r a t o u t e s l e s
donnees du sous−a r b r e .
∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
49
/∗
D e t r u i t l ’AVL a , a p p l i q u e l a f o n c t i o n de d e s t r u c t i o n a
t o u t e s l e s donnees du sous−a r b r e , O(n ) .
∗/
void a v l D e s t r o y ( a v l ∗ a )
{
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Pour t e s t e r les algorithmes
∗/
void d e s t r o y I n t ( void∗ i )
{
f r e e ( ( int ∗) i ) ;
}
i n t g e t I n t K e y ( void∗ i )
{
return ∗ ( ( i n t ∗ ) i ) ;
}
void doNothing ( )
{
i n t main ( )
{
int i ;
int∗ d ;
linkedList ∗ l ;
l i n k ∗ m;
a v l ∗ a = a v l Cr e a t e ( getIntKey , d e s t r o y I n t ) ;
f o r ( i = 0 ; i < 40 ; i ++)
{
d = ( int ∗) malloc ( s i zeo f ( int ) ) ;
∗d = i ;
avlInsert (a , d ) ;
}
avlPrintKeys ( a ) ;
avlPrintLevels (a );
f o r ( i = 0 ; i < 40 ; i +=5)
avlRemove ( a , i ) ;
avlPrintKeys ( a ) ;
avlPrintLevels (a );
l = avlToList ( a ) ;
f o r (m = l i n k e d L i s t G e t F i r s t ( l ) ; m != NULL ; m = m−>n e x t )
p r i n t f ( ”%d −> ” , ∗ ( i n t ∗ ) (m−>d a t a ) ) ;
p r i n t f ( ” \n” ) ;
l i n k e d L i s t D e s t r o y ( l , doNothing ) ;
avlSetFreeFunction( a , de stroyInt ) ;
avlDestroy (a ) ;
return 0 ;
}
50
Chapitre 8
Modélisation
8.1 Définition
Modéliser est une des compétences les plus importantes en algorithmique. A partir d’un problème concret (in-
dustriel, logistique, économique, etc.), on effectue une modélisation en formalisant le problème avec une terminologie
mathématique, et en reformulant la question de façon précise. Meilleure est la modélisation, plus il est simple de
résoudre le problème.
8.2 Exemple
Voici un exemple de problème : comment placer 8 reines sur un échiquer de sorte qu’aucune ne puisse s’emparer
d’une autre ? Si vous souhaitez réaliser un programme qui résolve ce problème, vous allez d’abord devoir le modéliser
mathématiquement. Dans la plupart des problèmes, on a
– des données : les emplacement des reines
– des contraintes : toutes les reines sont placées, il n’existe pas de couple de reines sur la même ligne, la même
colonne, ou la même diagonale
– une question : est-il possible de placer ces huit reines sans violer de contrainte ?
Il faut donc commencer par réfléchir à une façon de modéliser les emplacement des reines.
8.2.1 Données
Première modélisation
On pourrait, naı̈vement prendre une matrice M de dimensions 8 ∗ 8, et placer 0 dans une case s’il ne s’y trouve pas
de reine, 1 s’il s’en trouve une.
Première modélisation
Ou bien considérer huit couples de données qui contiendraient les coordonnées de la case sur laquelle serait placée
chaque reine. Ainsi, la i-ème reine occupe la case (li , ci )
Première modélisation
Ou plus simplement, puisqu’il n’y a qu’une reine par ligne, un vecteur de 8 valeurs nous donnerait la colonne sur
laquelle serait placée chaque reine. ci est donc la colonne sur laquelle on a placé la reine de la ligne i.
Bref
Considérons comme critère la place mémoire occupée, il va de soi que ces solutions sont de qualité croissante. Nous
allons voir qu’elles le sont aussi quand il s’agit de poser les contraintes.
51
8.2.2 Contraintes
La façon d’exprimer les contraintes dépend de la façon dont ont été représentées les données.
Première modélisation
8 X
X 8
– toutes les reines sont placées : mij = 8
i=1 j=1
X8
– une reine par ligne : ∀i ∈ {1, . . . , 8}, mij = 1
i=1
8
X
– une reine par colonne : ∀j ∈ {1, . . . , 8}, mij = 1
j=1
X X
– pas plus d’une reine par diagonale : ∀p ∈ {2, . . . , 16}, mij ≤ 1 et ∀p ∈ {−7, . . . , 7}, mij ≤ 1.
i+j=p i−j=p
compliqué, non ?
Deuxième modélisation
– toutes les reines sont placées : rien à faire
– une reine par ligne : ∀i ∈ {1, . . . , 8}, ∀j ∈ {1, . . . , 8} tel que i 6= j, li 6= lj
– une reine par colonne : ∀i ∈ {1, . . . , 8}, ∀j ∈ {1, . . . , 8} tel que i 6= j, ci 6= cj
– pas plus d’une reine par diagonale : ∀i ∈ {1, . . . , 8}, ∀j ∈ {1, . . . , 8} tel que i 6= j, |ci − cj | =
6 |li − lj |
C’est plus simple, non ?
Troisième modélisation
– toutes les reines sont placées : rien à faire
– une reine par ligne : rien à faire
– une reine par colonne : ∀i ∈ {1, . . . , 8}, ∀j ∈ {1, . . . , 8} tel que i 6= j, ci 6= cj
– pas plus d’une reine par diagonale : ∀i ∈ {1, . . . , 8}, ∀j ∈ {1, . . . , 8} tel que u 6= j, |i − j| =
6 |ci − cj |
Encore plus simple.
Bref
Vous remarquez que ces modèles sont aussi de qualité croissante si on prend comme critère la simplicité de l’ex-
pression des contraintes.
8.2.3 Question
La question est à chaque fois la même : quelles valeurs donner aux variables pour ne violer aucune contrainte ?
Mais le nombre de jeux de valeurs à donner aux variables n’est pas le même à chaque fois.
1. 264 possibilités, ce qui est de loin supérieur au nombre d’atomes dans l’univers...
2. (82 )8 possibilités, c’est déjà mieux, ça fait ((23 )2 )8 = 248 combinaisons possibles.
3. 88 possibilités, à savoir (23 )8 = 224 combinaisons, ce qui représente seulement quelques millions de possibilités...
Parmi les modélisations proposées, la dernière est donc la meilleure sur tous les plans. Seul inconvénient pour le
moment, on ne voit pas comment résoudre ce problème sans énumérer toutes les possibilités... Nous répondrons à cette
question dans les cours suivants.
52
personnes à la même place). Combien de temps vous faudra-t-il pour vous attabler suivant toutes les configurations
possibles ?
8.3.3 En bref
Lorsque vous cherchez des solutions à des problèmes combinatoires, bannissez d’entrée de jeu toute méthode basée
sur une exploration exhaustive de l’ensemble des solutions.
8.4 Terminologie
8.4.1 Difficulté
Nous allons passer en revue dans la section suivante quelques problèmes classiques d’optimisation combinatoire.
Nous les classerons en deux catégories
– Les problèmes faciles : c’est-à-dire ceux qui se résolvent en temps polynomial, autrement dit sans avoir à
explorer l’intégralité des solutions.
– Les problèmes difficiles : c’est-à-dire ceux qu’on ne peut résoudre qu’en explorant toutes les solutions. On dit
que ces problèmes sont NP-Complets.
La définition ci-dessus est très shématique, tenez-vous en à celle-ci pour le moment, un cours sera ultérieurement
consacré à l’etude des problèmes NP-Complets.
53
– les problèmes d’optimisation : questions sous la forme ”trouver ... minimal (ou maximal) tel que...”. La réponse
doit satisfaire des contraintes et être optimale.
8.5 Problèmethèque
8.5.1 Arbre couvrant de poids minimal
Soit G = (S, A) un graphe non orienté muni d’une valuation des arêtes c, T = (ST , SA ) est un arbre couvrant G si
– T est un arbre
– ST = S
– T est connexe
Le poids de T est X
c(a)
a∈AT
54
8.5.4 Circuit hamiltonien
Soit G un graphe (orienté ou non), un circuit hamiltonien dans G est un circuit passant par une et une seule fois
par chaque sommet de G. Le problème du circuit hamiltonien est le suivant :
– données : un graphe G
– question : trouver un circuit hamiltonien dans G.
Ce problème est NP-Complet.
8.5.6 SAT
Soit une expression booléenne à n variables sous forme clausale (conjonction de disjonctions), par exemple,
{C1 , c2 , . . . , ck }
8.5.7 Couverture
Soit G = (S, A) un graphe non orienté muni d’une pondération p un sous-ensemble K de S est une couverture si
∀a = (e, e′ ) ∈ A, e ∈ K ou e′ ∈ K
55
8.5.8 Coloration
Soit G = (S, A) un graphe non orienté, une k-coloration c de g est une application de S dans un ensemble E tel
que |E| = k vérifiant
∀(e, e′ ) ∈ A, c(e) 6= c(e′ )
Le problème de la k-coloration est défini comme suit :
– données : un graphe G
– question : trouver une k-coloration de G.
Ce problème est NP-Complet.
Le nombre chromatique χG d’un graphe est la plus petite coloration de ce graphe. Autrement dit,
– données : un graphe G
– question : trouver le nombre chromatique de G.
Ce problème est aussi NP-Complet.
8.6 Exercices
Exercice 1 - Digicode
Vous souhaitez craker un digicode, vous devez pour cela trouver un code de k chiffres, le digicode en comportant
n.
1. Combien de chiffres seront, dans le pire des cas, saisies sur le clavier si vous décidez d’énumérer tous les codes
les uns à la suite des autres, et suivant un ordre lexicographique ?
2. Si vous décidez d’entremêler les codes les uns dans les autres, donnez un minorant de la meilleure méthode
envisageable.
56
3. Modélisez ce problème comme un problème de recherche d’un circuit hamiltonnien dans un graphe orienté. La
résolution est-elle facile ?
4. Modélisez ce problème comme un problème de recherche d’un circuit eulérien dans un graphe, le problème est-il
facile ?
Exercice 2 - Rattrapages
Un ensemble E = {e1 , . . . , en } doivent passer des sessions de rattrapages dans les matières M = {m1 , . . . , mk }.
Vous disposez d’un ensemble de couples C = (c1 , . . . , cj ) tel ci = (e, m) signifie que l’étudiant e doit repasser la matière
m. Nous souhaitons organiser les rattrapages en affectant chaque épreuve à un jour. Plusieurs épreuves puissent se
dérouler le même jour tant qu’un même candidat n’a pas deux ratrappages à effectuer le même jour. Nous souhaitons
minimiser le nombre de jours que dureront les rattrapages.
1. Comment modéliser le problème de la façon la plus simple possible ?
2. Est-il polynomial ?
57
avec
A1 = {{(s, j), (s, j ′ )}|s ∈ S, 1 ≤ j < j ′ ≤ k}
un ensemble d’arêtes formant |S| sous-graphes complets de k sommets et
Exercice 6 - Ordonnancement
En votre qualité de manager, vous vous retrouvez confronté au problème suivant : vous avez un ensemble de tâches
à effectuer, chacune d’elle ayant un temps d’exécution connu à l’avance et une date de fin souhaitée. De plus, il existe
pour chaque tâche une date avant laquelle il n’est pas possible de commencer son exécution. Votre équipe ne peut pas
travailler sur deux tâches différentes en même temps et il n’est pas possible de fractionner ou d’interrompre l’exécution
d’une tâche. Si l’exécution d’une tâche n’est pas achevée avant la date de fin souhaitée, on dit de cette tâche qu’elle
est en retard. Votre objectif est de déterminer un calendrier d’exécution des tâches de sorte à minimiser la somme des
retards. Voici les projets à réaliser en septembre :
numéro nom exécution au plus tôt durée deadline
1 changer la plomberie 1 1 6
2 débugger le projet A 2 3 4
3 nettoyer la voiture du PDG 1 1 6
Par exemple, l’installa-
4 installer le progiciel B 8 2 23
5 créer la base de donnée pour C 1 5 12
6 coder une interface graphique pour C 10 5 15
7 préparer le planning d’octobre 17 2 19
tion du progiciel B prend 2 jours consécutifs, elle ne peut pas commencer avant le 8 septembre, et doit se terminer au
plus tard le 23 septembre. Il possible de commencer le 8 et de terminer le 9 tout comme il est possible de commencer
le 22 et de terminer le 23.
1. Donnez une solution réalisable pour ce problème. Vous présenterez la solution sous forme d’un tableau, chaque
tâche occupera une ligne et celles-ci seront disposées dans l’ordre de leur exécution. Vous utiliserez quatre colonnes
– le nom de la tâche
– la date de début
– le temps d’exécution
– la date de fin d’éxecution
2. Formalisons le problème.
– Données : un nombre n de tâches, un ensemble de durées {d1 , . . . , dn }, un ensemble de dates de début
d’exécution au plus tôt {r1 , . . . , rn }, un ensemble de dates de fin d’exécution au plus tard {f1 , . . . , fn }, une
constante M .
– Question : Existe-t-il un ordre d’exécution des tâches tel que la somme cumulée des retards n’excède pas M ?
Nous appelerons ce problème SCHEDULING. Soient {s1 , . . . , sn } les dates de début d’exécution de chacune des
tâche. Soient {t1 , . . . , tn } les dates de fin d’exécution. Donnez une relation simple entre ti , si et di . Prenez bien
soin de vérifier que cette relation est vérifiée dans l’exemple de la question précédente.
3. L’exécution de la tâche i ne peut pas commencer avant la date ri . Exprimez cette contrainte avec les notations
des questions précédentes.
58
4. Deux tâches d’indices respectifs i et j ne peuvent pas se superposer, exprimez cette contrainte à l’aide d’une
proposition portant sur si , sj , ti et tj .
5. Combien y a-t-il de contraintes de cette forme ? Vous justifierez votre réponse en dénombrant les couples (i, j)
tels que 1 ≤ i < j ≤ n.
6. Nous notons max(a, b) la plus grande des deux valeurs a et b. A quoi correspond la valeur max(0, ti − fi ) ?
7. Nous choisissons comme fonction objectif la somme cumulée des retards. Exprimez cette fonction objectif à partir
des ti et des fi
8. Exprimez la condition “la somme cumulée des retards n’excède pas M ” avec les notations de la question
précédente
Exercice 7 - Sac-à-dos
Nous souhaitons résoudre le problème du sac à dos par énumération exhaustive des solutions, c’est à dire comme des
boeufs. Nous représenterons une solution s (réalisable ou non) par la liste chaı̂née des indices des objets sélectionnés
dans s. Nous représenterons une instance i par deux tableaux p (poids des objets) et v (valeurs des objets). Une
solution sera la liste chaı̂née des indices des objets placés dans le sac. Ecrivez les corps des sous-programmes suivants :
1. void* linkedListCopy(void* l). Copie les maillons de la liste chaı̂née l, mais pas les valeurs pointées par les
maillons. Vous utiliserez linkedListMap.
2. Ecrivez le sous-programme void knapSackPrintSolution(linkedList* l), affiche la liste des indices formant
la solution l, vous utiliserez linkedListApply.
3. Ecrivez un sous-programme linkedList* parties(linkedList* l), ce sous-programme prend en paramètre
un ensemble représenté par une liste chaı̂née et retourne une liste chaı̂née dans laquelle chaque maillon est une
liste chaı̂née contenant une partie de l. Vous utiliserez linkedListApply.
4. void knapSackPrintParties(linkedList* l), affiche toutes les parties de l, vous utiliserez linkedListApply.
5. void knapSackDestroyParties(linkedList* l) détruit l et les listes chaı̂nées pointées par chaque maillon de
cette liste.
Nous représenterons une instance du problème sac à dos avec une variable du type :
typedef struct
{
/∗
nombre t o t a l d ’ o b j e t s
∗/
long nbItems ;
/∗
t a b l e a u de n ombreO bjet s e l e m e n t s c o n t e n a n t l e p o i d s de
chaqu e e l e m e n t
∗/
long∗ w e i g h t s ;
/∗
t a b l e a u de n ombreO bjet s e l e m e n t s c o n t e n a n t l a v a l e u r de
chaqu e e l e m e n t
∗/
long∗ v a l u e s ;
/∗
Poids maximum qu ’ i l e s t p o s s i b l e de p l a c e r dans l e s a c à dos .
∗/
long maxWeight ;
} knapSack ;
59
Ecrivez les corps des sous-programmes suivants :
1. knapSack* knapSackMake(long nbItems, long maxWeight), alloue la mémoire pour contenir l’instance ainsi
que les deux tableaux.
2. void knapSackSetItem(knapSack* k, long index, long value, long weight), fixe les poids (weight) et
valeur (value) de l’objet d’indice i de l’instance k.
3. long knapSackValue(knapSack* instance, linkedList* solution), retourne la somme des valeurs des ob-
jets de instance dont les indices sont dans la liste solution. Vous utiliserez la fonction linkedListApply.
4. long knapSackWeight(knapSack* instance, linkedList* solution), retourne le poids de la solution solution
relative à l’instance instance. Vous procéderez de la même façon que dans la question précédente.
5. int knapSackIsFeasible(knapSack* instance, linkedList* solution), retourne vrai si est seulement si la
solution solution relative à l’instance instance est réalisable.
6. void knapSackPrintInstance(knapSack* k), affiche la liste des poids des des valeurs de tous les objets de
l’instance k. Par exemple,
(i = 0, v = 1, w = 1)
(i = 1, v = 2, w = 2)
(i = 2, v = 9, w = 7)
(i = 3, v = 8, w = 2)
(i = 4, v = 5, w = 7)
(i = 5, v = 6, w = 6)
(i = 6, v = 7, w = 7)
(i = 7, v = 4, w = 2)
(i = 8, v = 3, w = 7)
(i = 9, v = 10, w = 2)
(i = 10, v = 1, w = 1)
(i = 11, v = 2, w = 2)
(i = 12, v = 9, w = 7)
(i = 13, v = 8, w = 2)
(i = 14, v = 5, w = 7)
(i = 15, v = 6, w = 6)
(i = 16, v = 7, w = 7)
(i = 17, v = 4, w = 2)
(i = 18, v = 3, w = 7)
(i = 19, v = 10, w = 2)
(i = 20, v = 1, w = 1)
7. void knapSackDestroy(knapSack* k), vous avez vraiment besoin que je vous donne des indications ?
8. linkedList* knapSackListInit(long n), retourne une liste chaı̂née contenant les éléments {1, . . . , n}. Vous
l’implémenterez de façon récursive.
9. linkedList* knapSackBruteForceSolve(knapSack* k) retourne la liste chaı̂née contenant la liste des indices
des objets formant la solution optimale du problème k.
10. Jusqu’à quelle valeur de n parvenez-vous à résoudre le problème ?
11. Montrez que le temps d’exécution est proportionnel au nombre de maillons crées, toutes listes confondues.
12. Evaluez le nombre de maillons en fonction de n, donnez la complexité de la résolution de knapsack par énumération
de toutes les solutions.
13. Est-ce que cela vous explique pourquoi l’exécution est si longue ?
60
Chapitre 9
Programmation linéaire
9.1 Exemple
Nous disposons de 500 kilos de matière première MA , et de 600 kilos de matière première MB . Pour fabriquer un
exemplaire de produit P1 il faut 10 kilos de MA et 20 kilos de MB , pour fabriquer un exemplaire de produit P2 il faut
20 kilos de MA et 10 kilos de MB . La vente d’un exemplaire de P1 rapporte 10 euros, celle d’une exemplaire de P2
rapporte 12 euros. Soit x1 le nombre de produits P1 fabriqués x2 le nombre de produits P2 fabriqués. Comment fixer
x1 et x2 pour maximiser les bénéfices ?
Ce problème se modélise et se note de la façon suivante :
max 10x1 + 12x2
s.c. 10x1 + 20x2 ≤ 500
20x1 + 10x2 ≤ 600
x1 , x2 ≥ 0
61
Soient x le vecteur à n lignes et 1 colonne
x1
..
.
xn
c le vecteur à n lignes et 1 colonne
c1
..
.
cn
Alors on exprime la valeur de la fonction objectif avec le produit scalaire ct x. Soit A la matrice à m lignes et n
colonnes
a11 . . . a1i . . . a1n
.. .. ..
. . .
aj1 . . . aji . . . ajn
. .. ..
..
. .
am1 . . . ami . . . amn
et b le vecteur à m lignes et 1 colonne
b1
..
.
bm
Alors les contraintes s’écrivent
Ax ≤ b
Finalement, un programme linéaire est de la forme
max ct x
s.c. Ax ≤ b
Le coût d’acheminement de 1 tonne de mort au rat du point de fabrication i au point de vente j est donné par c(i, j).
Comment faire pour satisfaire la demande de chaque point de vente tout minimisant le coût total d’acheminement ?
Modélisez ce problème par un programme linéaire.
62
2. B doit 57 euros à A
3. E doit 228 euros à B
4. B doit 129 euros à D
5. D doit 78 euros à A
6. C doit 45 euros à B
7. B soit 187 euros à E
On remarque que ce graphe contient des circuits, et que pour certains couples, de sommets, il existe plusieurs
chemins. Utiliser le graphe tel qu’il est pour planifier les remboursements conduirait à des remboursements redondants
(C donne à B qui donne à A qui donne à C...). En réfléchissant, il remarque que peu importe qui rembourse qui, ce qui
compte, c’est que chacun retrouve son argent. Pour simplifier le problème, il décompose donc S en deux sous-ensembles
S + (ceux à qui on doit de l’argent qu’ils n’en doive) et S − (ceux qui doivent de l’argent plus qu’on leur en doit).
Chaque sommet s est étiqueté par la valeur
X X
| c(s, t) − c(t, s)|
t∈Γ+ (s) t∈Γ− (s)
Quels sont les sommets et les étiquettes des sommets de ce nouveau graphe ? La question est de trouver comment
placer les arêtes de la façon la plus simple possible. Modélisez ce problème comme un problème de flot max. Nous
souhaitons maintenant minimiser le nombre de transaction. Est-ce possible avec un algorithme de flot maximum ?
Nous verrons dans une autre section que ce problème est NP-Complet.
Chaque camion à une contenance K, le problème est comment affecter chaque camion à un centre de fabrication et
un centre de livraison pour utiliser un minimum de camions ? Montrez que ce problème est le même que le précédent.
9.4 GLPK
9.4.1 Qu’est-ce que c’est ?
GLPK [6] est une librairie de résolution de programmes linéaires. Elle contient une implémentation de l’algorithme
du simplexe. Il est possible de lancer GLPK en ligne de commande, ou bien d’importer la librairie dans un programme
C.
63
9.4.2 Où le trouver ?
Utilisez urpmi ou apt-get.
9.4.3 La documentation
Le manuel de référence[7] est très complet mais quelque peu difficile à lire quand on n’est pas habitué. Cette annexe
est aussi là pour vous vous aider à le lire.
i nt main ( )
{
LPX∗ l p = l p x c r e a t e p r o b ( ) ;
double c o e f f s [ 4 + 1 ] ;
i nt rows [ 4 + 1 ] , c o l s [ 4 + 1 ] ;
l p x s e t o b j d i r ( lp , LPX MAX ) ;
l p x a d d r o w s ( lp , 2 ) ;
l p x s e t r o w b n d s ( lp , 1 , LPX UP , 0 . 0 , 5 0 0 . 0 ) ;
l p x s e t r o w b n d s ( lp , 2 , LPX UP , 0 . 0 , 6 0 0 . 0 ) ;
l p x a d d c o l s ( lp , 2 ) ;
l p x s e t c o l b n d s ( lp , 1 , LPX LO , 0 . 0 , 0 . 0 ) ;
l p x s e t c o l b n d s ( lp , 2 , LPX LO , 0 . 0 , 0 . 0 ) ;
l p x s e t o b j c o e f ( lp , 1 , 1 0 . ) ;
l p x s e t o b j c o e f ( lp , 2 , 1 2 . ) ;
c o e f f s [ 1 ] = 10 ; rows [ 1 ] = 1 ; c o l s [ 1 ] = 1 ;
c o e f f s [ 2 ] = 20 ; rows [ 2 ] = 1 ; c o l s [ 2 ] = 2 ;
c o e f f s [ 3 ] = 20 ; rows [ 3 ] = 2 ; c o l s [ 3 ] = 1 ;
c o e f f s [ 4 ] = 10 ; rows [ 4 ] = 2 ; c o l s [ 4 ] = 2 ;
l p x l o a d m a t r i x ( lp , 4 , rows , c o l s , c o e f f s ) ;
lpx simplex ( lp ) ;
p r i n t f ( ” v a l e u r de l a f o n c t i o n o b j e t i f : %l f \n” , l p x g e t o b j v a l ( l p ) ) ;
p r i n t f ( ” q u a n t i t e de p r o d u i t s A : %l f \n” , l p x g e t c o l p r i m ( lp , 1 ) ) ;
p r i n t f ( ” q u a n t i t e de p r o d u i t s B : %l f \n” , l p x g e t c o l p r i m ( lp , 2 ) ) ;
lpx delete prob ( lp ) ;
return 1 ;
}
N’oubliez pas de compiler vos sources avec l’option -lglpk (sinon, ça marche pas).
Importation
Avant toute chose, n’oubliez pas
#include ’ ’ g l p k . h ’ ’
64
Création, suppression
GLPK met à votre disposition le type LPX, une variable de ce type est un programme linéaire. On crée un programme
linéaire avec la fonction lpx create prob(), on le détruit avec lpx delete prob(LPX*).
Vous remarquez que ce programme à n variables et à m contraintes est formé d’un grand tableau, à n + 1 colonnes,
et à m + 1 lignes. Dans la terminologie de GLPK,
– Une variable est une colonne (col)
– Une contrainte est une ligne (row)
La fonction lpx add rows(LPX*, int) spécifie le nombre de contraintes, lpx add cols(LPX*, int) spécifie le
nombre de variables.
La fonction objectif
Soyez très atentifs : les indices sous GLPK commençent à 1. La fonction lpx set obj coef(LPX*, int
numeroDeLigne, double coefficient) permet de préciser la valeur d’un coefficient de la fonction objectif. Par
exemple, pour affecter la valeur 3.0 à c2 dans le programme mylp, on utilise l’instruction lpx set obj coef(mylp,
2, 3.0). Selon le contexte, on cherche à minimiser ou à maximiser la fonction objectif, on le précise avec la fonction
lpx set obj dir(LPX*, int direction). Il existe deux directions : LPX MIN et LPX MAX.
65
Les domaines des variables
Il est possible d’ajouter des contraintes sur les valeurs des variables. Par exemple, les contraintes suivantes
x1 , x2 ≥ 0
font partie du programme linéaire donné en exemple. La fonction lpx set col bnds(LPX*, int indiceColonne,
int forme, double borneInf, double borneSup). Par exemple, si x est d’indice 4, et qu’on tient à l’empêcher de
prendre des valeurs négatives, on le spécifie avec l’instruction lpx set col bnds(mylp, 4, LPX LO, 0.0, 0.0).
L’algorithme du simplexe
lpx simplex(LPX*) exécute l’algorithme du simplexe sur le problème passé en paramètre. La fonction double
lpx get obj value(LPX*) retourne la valeur de la fonction objectif à l’optimum. double lpx get col primm(LPX*,
int indiceVariable) retourne la valeur de la indiceV ariable-ème variable à l’optimum.
66
1. Comment résoudre ce problème ? Utilisez GLPK pour résoudre l’instance
double n o t e s P a r t i e l [N] = { 1 0 , 1 3 , 2 , 4 . 5 , 9 , 1 2 , 1 6 , 8 , 5 , 1 2 } ;
double notesCC1 [N] = {11 , 16 , 11 , 8 , 10 , 11 , 11 , 6 , 4 , 13};
double notesCC2 [N] = { 9 , 18 , 7 , 8 , 11 , 3 , 13 , 10 , 7 , 19};
2. Que remarquez-vous ?
3. Le responsable pédagogique est en total désaccord, il considère que la note de partiel doit avoir un coefficient
au moins égal à 0.5 et que deux notes de contrôle continu doivent avoir des coefficients au moins égaux à 0.1.
Comment tenir compte de ces contraintes ?
4. En raison d’un petit nombre de notes très élevées à certains examens, la moyenne générale de la classe est bonne
malgré le fait que beaucoup d’élèves ont une moyenne très basse. L’enseignant décide donc de changer de critère
et de maximiser la moyenne la plus basse. Comment procéder ?
5. Vérifiez la solution de la question précédente en calculant les moyennes de tous les élèves avec les coefficients
donnés par GLPK (ne le calculez pas à la main, programmez-le...).
67
Chapitre 10
Théorie de la complexité
Certains problèmes combinatoires sont dits NP-Complets, cela signifie qu’il n’est possible de les résoudre qu’en
passant par une recherche exhaustive dans l’ensemble des solutions, ce qui est concrètement irréalisable. Le but de ce
cours est de vous montrer comment reconnaı̂tre qu’un problème est NP-Complets, et comment le prouver.
Le chapitre de [2] sur la NP-Complétude fournit un exposé clair de la théorie de la complexité, mais utilisant des
concepts de calculabilité que je n’utilise pas dans ce cours. La lecture de ce chapitre ne pourra cependant que vous
être bénéfique. L’ouvrage [8] est la bible de la théorie de la complexité. Bien qu’il ne soit disponible qu’en anglais et
relativement difficile à se procurer, la théorie y est expliquée de façon claire, détaillée, et sans excès de formalisme.
10.1.2 Instances
Une instance d’un problème s’obtient en précisant les valeurs des données. Par exemple,
– Données : un graphe G complet d’ordre 10, k = 9
– Question : G est-il k-colorable ?
On résout un problème de décision et décidant, pour toute instance I, si cette instance est à réponse oui ou à
réponse non. On dit plus généralement qu’un algorithme qui résout un problème de décision décide ce problème, et
toutes les instances de ce problème.
68
10.2.1 La classe P
Un problème appartient à la classe de problèmes P s’il existe un algorithme polynomial permettant de le résoudre.
Par exemple, le plus court chemin, l’arbre couvrant dans un graphe, etc.
10.2.2 La classe NP
Etant donné un problème de décision, ce problème est dans NP s’il est possible de vérifier une solution en temps
polynomial. Considérons par exemple le problème suivant :
– Données : un graphe G
– Question : existe-t-il un cycle hamiltonien dans G ?
Supposons que ce graphe contienne 100 sommets, et qu’un de vos camarade vous dise : ”cette instance est à réponse
oui”. Vous lui demanderez certainement : ”dans quel ordre parcourir les sommets pour former un cycle hamiltonien” ?
Notez bien que malgré le fait que résoudre le problème soit infaisable en pratique, vérifier qu’un chemin est effectivement
un chemin hamiltonien est très aisé. Un cycle permettant de vérifier en temps polynomial qu’une telle instance est une
instance à réponse oui s’appelle un certificat.
Plus généralement, étant donné une instance I d’un problème Π, un certificat c est une donnée permettant de
vérifier en temps polynomial que I est une instance de Π à réponse oui.
Théorème 10.2.1 P ⊂ N P
Soit I une instance d’un problème Π appartenant à P , alors il existe un algorithme polynomial permettant de
décider Π. De ce fait, si I est à réponse oui, même un certificat vide permet de le vérifier en temps polynomial.
La question suivante empêche la plupart des chercheurs en informatique de dormir : Est-ce que P = N P ? On sait
déjà que P ⊂ N P , pour répondre à la question, il faudrait montrer :
– N P ⊂ P , autrement dit, tout problème de N P peut être résolu en temps polynomial.
– N P \ P 6= ∅, autrement dit, il existe des problèmes de N P qui ne peuvent être résolus en temps polynomial.
Notez que le problème du cycle hamiltonien appartient à N P .
– Si P = N P , alors il existe un algorithme polynomial permettant de le décider.
– Si P 6= N P , alors il convient de se demander si ce problème n’est pas dans N P \ P , le cas échéant il n’existe
aucun algorithme polynomial permettant de le décider.
Etant donné le nombre de problèmes de N P pour lesquels on ne trouve aucun algorithme polynomial, il est fort
probable que P 6= N P . Notez bien que ceci n’est qu’une conjecture, elle n’est pas démontrée à ce jour.
10.3.1 Définition
Nous allons établir une relation d’ordre sur les problèmes, nous la noterons
Π ≤ Π′
ce qui signifie ”Π est moins difficile que Π′ ”. ≤ est définie comme suit
Définition 10.3.1 Π ≤ Π′ s’il existe une fonction f de complexité polynomiale qui à toute instance I de Π associe
une instance I ′ de Π′ telle que I est à réponse oui si et seulement si I ′ est à réponse oui.
69
10.3.2 Exemple
Montrons que le problème HC (cycle hamiltonien) est moins difficile que T SP (voyageur de commerce). Pour cela,
construisons une fonction f prenant en paramètre une instance du problème HC, et créant une instance I du problème
T SP . Il est très important de déterminer f de sorte que I soit à réponse oui si et seulement si f (I) est à réponse
oui. Rappelons la définition de HC dans un graphe non orienté :
– Données : un graphe G non orienté
– Question : existe-t-il un cycle hamiltonien dans G ?
Ainsi que la définition de T SP ,
– Données : un graphe G′ non orienté muni d’une valuation c, une constante K
– Question : existe-t-il dans un G un cycle hamiltonien de longueur inférieure ou égale à K ?
Nous définissons f de la sorte, f prend en paramètre les données de HC, à savoir le graphe G = (S, A), on définit
l’instance f (I) de la sorte
– G′ = (S, A′ ), A′ contient toutes les paires de sommets qu’il est possible de former avec les sommets de G.
Autrement dit, G′ est un graphe complet.
– c(e) = 1 si e ∈ A, c(e) = 2 si e 6∈ A. Autrement dit, les arêtes de A′ ont la valeur 1 si elle se trouvaient dans A,
et toutes les arêtes qui ont été ajoutées pour obtenir un graphe complet ont la valeur 2.
– K = |S|.
Il est maintenant nécessaire de montrer que I est une instance à réponse oui si et seulement si f (I) est une instance
à réponse oui.
– Soit I une instance de HC à réponse oui. Alors il existe un cycle hamiltonien dans G. La longueur de ce cycle
dans G est |S|, à savoir le nombre de sommets. La longueur de ce cycle est aussi |S| dans G′ , car les arêtes
empruntées dans G′ étaient toutes de valuation 1.
– Soit I une instance de HC telle que f (I) est à réponse oui. Comme f (I) est à réponse oui, alors il existe un
cycle hamiltonien de longueur K = |S|. Comme ce cycle passe par |S| arêtes, et que toutes les arêtes de G′ sont
de valuation 1 ou 2, alors ce cycle n’emprunte que des arêtes de valuation 1. Comme les arêtes de valuation 1 de
G′ sont aussi des arêtes de G, alors il existe un cycle hamiltonien dans G.
10.3.3 Application
Propriété 10.3.1 Si Π ≤ Π′ et Π′ ∈ P , alors Π ∈ P .
Soit I une instance de Π, comme Π ≤ Π′ , alors il existe f polynomiale telle que I est à réponse oui si et seulement si
f (I) est à réponse oui. Comme Π′ ∈ P , alors Π′ est décidé par un algorithme polynomial. En appliquant cet algorithme
à f (I), on décide I. L’algorithme qu’on obtient est donc
– Déterminer f (I) (polynomial)
– Décider f (I) (polynomial)
Comme les deux algorithmes considérés sont polynomiaux, alors I est décidé en temps polynomial. Donc Π ∈ P .
Il est important de retenir que Π ≤ Π′ implique que l’existence d’un algorithme polynomial décidant Π′ implique
l’existence d’un algorithme polynomial décidant Π.
10.4.2 3-SAT
La question que nous sommes amenés à nous poser maintenant est : existe-t-il un problème de N P au moins aussi
difficile que tous les problèmes de N P ? La réponse est oui.
70
Théorème 10.4.1 (Cook) Pour tout Π ∈ N P , Π ≤ 3 − SAT
Le problème SAT est défini dans la problèmethèque. 3 − SAT correspond au cas particulier dans lequel toutes les
clauses contiennent 3 littéraux. 3 − SAT est plus difficile que tous les problèmes de N P , cela signifie que s’il était
possible de décider 3 − SAT en temps polynomial, il serait alors possible de décider n’importe quel problème de N P
en temps polynomial.
Exercice 1 - 3-SAT/CLIQUE
3-SAT est défini de la façon suivante :
– Données : Un ensemble {Cj |j = 1, . . . , p} de clauses, un ensemble {xi |i = 1, . . . , n} de variables. Chaque clause
Cj contient 3 littéraux {lj1 , lj2 , lj3 } pouvant être de la forme xi ou ¬xi , ce que l’on notera avec une égalité pour
simplifier les notations.
– Question : Existe-t-il une valuation des variables satisfaisant au moins un littéral de chaque clause ?
Une clique est un sous-graphe complet. La taille d’une clique est le nombre de sommets qu’elle contient. On définit
le problème CLIQUE de la façon suivante :
– Données : Une graphe G non orienté, une constante K > 0
– Question : Existe-t-il dans G une clique de taille K ?
Nous considérons la réduction suivante :
– K=p
– A chaque clause Ci , on associe trois sommets s1j , s2j et s3j .
′
– Il existe une arête entre deux sommets sij et sij ′ si
71
– j 6= j ′
– si lij = x, alors lji ′ =
′
6 ¬x
3-SAT est connu pour être NP-Complet, montrez que CLIQUE est NP-Complet.
72
Exercice 6 - PARTITION/SUBSET SUM
Le problème PARTITION est défini comme suit :
– Données : un ensemble A = {pi |i ∈ {1, . . . , n}} de n valeurs, tel que
Σni=1 pi
est pair.
– Question : existe-t-il un sous-ensemble I de {1, . . . , n} tel que
Σi∈I pi = Σi6∈I pi
Montrez que SUBSET SUM est NP-Complet, utilisez le fait que PARTITION est NP-Complet.
Exercice 8 - Ordonnancement
1. Montrez que SCHEDULING ∈ NP.
2. Etant donné le problème PARTITION :
– Données : Un ensemble de m valeurs {v1 , . . . , vm }. X X
– Question : Existe-t-il un sous-ensemble I de {1, . . . , m} tel que vi = vi
i∈I i6∈I
Autrement dit, est-il possible de partitionner l’ensemble {v1 , . . . , vm } en deux sous-ensembles dont la somme des
valeurs est égale ? L’instance de PARTITION suivante, m = 7, (v1 , . . . , v7 ) = (1, 2, 3, 4, 5, 6, 7) est-elle à réponse
”oui” ? Vous démontrerez la justesse de votre réponse.
3. Nous savons que PARTITION est NP-Complet. Nous allons montrer à l’aide d’une réduction polynomiale f , que
PARTITION ≤ SCHEDULING. Nous construisons une fonction f qui à toute instance de PARTITION associe
une instance de SCHEDULING définie comme suit :
– n=m+1 Pn
– pour tout i ∈ {1, . . . , m}, di = vi , ri = 1, fi = j=1 vj + 1
n n
– dn = 1, rn = 21 j=1 vj + 1, fn = 12 j=1 vj + 1
P P
– M =0
Déterminer l’image de l’instance (1, 2, 3, 4, 5, 6, 7) par la fonction f . Vous présenterez votre solution sous forme
d’un tableau, vous préciserez les valeurs de toutes les données du problème.
4. L’image de cette instance est-elle à réponse ”oui” ? Vous démontrerez la justesse de votre réponse en donnant
les valeurs de début d’exécution si c’est le cas, ou bien une preuve d’impossibilité dans le cas contraire.
5. Montrez, sans excès de formalisme, que f est polynomiale.
6. Montrer que toute instance de PARTITION à réponse oui a une image par f à réponse oui.
7. Montrer que toute instance de PARTITION dont l’image est à réponse oui est à réponse oui.
8. SCHEDULING est-il NP-Complet ? Justifiez votre réponse.
73
Chapitre 11
Introduction la cryptographie
11.1 Définitions
Chiffrer une information revient à la transformer de sorte qu’elle ne puisse être intelligible que par la personne à
qui elle est destinée. La cryptologie est un terme générique regroupant deux disciplines :
– La cryptographie, qui est l’étude des méthodes de chiffrement et de déchiffrement.
– La cryptanalyse, qui est l’art de casser des messages chiffrés. Autrement dit, la cryptanalyse est l’étude des
techniques qui permettent à une personne non autorisée de décrypter (ce mot s’emploie uniquement dans ce
contexte) des messages chiffrés.
La cryptographie permet aussi de signer et d’authentifier des documents. En signant un document, on permet au
destinaire de vérifier la provenance du document, et l’authentification permet de vérifier que ce document n’a pas été
altéré.
Vous prendrez garde à ne pas confondre chiffrement et codage. Coder revient à remplacer chaque symbole (ou
suite de symboles) par un(e) autre. Cela peut servir en cryptographie, mais la réciproque est fausse.
Un chiffre est la donnée d’un algorithme de chiffrement (et/ou de signature) et de l’algorithme de déchiffrement
(et/ou de vérification et d’authentification). On utilise aussi le mot protocole, ou encore algorithme.
Nous appellerons tiers non autorisé toute personne à qui le message chiffré n’est pas destiné et qui pourrait,
pour des raisons qui lui appartiennent, être tentée de le lire.
Un canal non sécurisé est un moyen de transmission de l’information dont la sûreté n’est pas garantie, c’est-à-dire
sur lequel il est aisé pour un tiers non autorisés d’intercepter les messages. Les protocole de chiffrement trouve tout
leur intérêt lorsque l’on doit faire transiter par un canal non sécurisé des informations confidentielles.
Un message, avant le chiffrement est appelé message clair ou encore message en clair. Une fois chiffré, on
l’appelle message chiffré. Lorsqu’il a été déchiffré (a priori par son destinataire), on l’appelle message déchiffré.
11.2 La stéganographie
La stéganographie est l’art de dissimuler des messages, par exemple en utilisant les bits de poids faible d’une
image au format bmp [9], ou encore en plaçant des informations dans le slack [10]. La stéganographie n’est pas considéré
comme de la cryptographie, car le message doit pouvoir tomber entre les mains d’un tiers non autorisée
sans que celui-ci puisse le lire. Ce critère n’est évidemment pas satisfait par la stéganographie, bien que celle-ci
ait eu son heure de gloire pendant l’antiquité.
74
deuxième critère devant être satisfait est que même si des personnes non autorisées connaissent l’algorithme
chiffrement, elle ne doivent pas être capable de déchiffrer un message chiffré.
11.4.2 Enigma
Enigma est une machine à chiffrer utilisée par l’armée allemande pendant la deuxième guerre mondiale. Elle se
présentait comme une machine à écrire, mais écrivait d’autres lettres que celles qui étaient saisies. Un système de rotors
qui pivotaient à chaque pression de touche changeait la clé au fur et à mesure que l’on avançait dans l’écriture du
message. Cela ressemblait à un code de Vigenère dont la clé est aussi longue que le message, et comme les allemands
changeaient de clé chaque semaine, cela rendait irréaliste toute cryptanalyse basée sur une analyse des fréquences. La
clé utilisée était une disposition des rotors et une position initiale, ce qui faisait que même si une machine enigma
(l’algorithme) tombait entre les mains d’un ennemi de l’armée allemande, celui-ci ne pouvait déchiffrer les messages
sans connaı̂tre la disposition des rotors (la clé). Enigma a donné beaucoup de fil à retordre aux alliés, et était considéré
comme un moyen de chiffrement très efficace.
75
11.5.1 Un peu d’histoire[1]
Les allemands étaient obligés de faire circuler les clés en centaines d’exemplaires dans toute l’europe, en garantir
la sécurité était une tâche très difficile. Et ce qui devait arriver arriva : des anglais s’emparèrent de clés d’enigma sans
que les allemands le sachent. Comme ils disposaient de copies d’enigma depuis longtemps déjà et que les allemands
ne se savaient pas écoutés, ils purent tranquillement déchiffrer tous les messages allemands. Nombreux sont ceux qui
considèrent que cela a été décisif pour la victoire des alliés.
11.5.2 Le principe
Mettre des clés en circulation et garantir leur sécurité est considéré aujourd’hui comme un tâche impossible.
Comment échanger des clés sans prendre le risque qu’un message soit décrypé par un tiers non autorisé ? L’idée de la
réponse est d’utiliser deux clés : Ke pour chiffrer et Kd pour déchiffrer. Le destinataire du message est la seule personne
à détenir Kd , elle diffuse Ke librement. Un message M est chiffré avec une fonction f en un message C = f (M, Ke ).
Son destinataire déchiffre le message avec une fonction g telle que M = g(C, Kd ). Les deux fonctions f , g, et la clé
Ke doivent pouvoir être publiées et tomber entre les mains d’un tiers non autorisé sans qu’il puisse déchiffrer M .
Autrement dit, il doit être difficile de trouver Kd à partir de f , g, Ke et M .
On peut se représenter ce type de protocole de la façon suivante. Alice veut envoyer un message à Bob. Bob lui
envoie une boı̂te et un cadenas ouvert. Alice place le message dans la boı̂te et verrouille le cadenas. Maintenant, seul
le détenteur de la clé du cadenas peut ouvrir la boı̂te. S’il s’agit de Bob, lui seul pourra récupérer le message, même
Alice ne pourra pas le faire. Le principe le la cryptographie asymétrique est le même :
– Ke est la clé publique et permet à toute personne de chiffrer un message.
– Seule la clé privée Kd permet le déchiffrement du message.
Exercice 3 - SSH
Les chiffres à clé publique sont très gourmands en calculs, ils rendent inenvisageable le transfert de volumes importants
de données. Par contre les protocoles symétriques sont très rapides en pratique. Comment conjuguer les deux pour
communiquer de façon rapide et sécurisée à travers un canal non sécurisé.
76
Chapitre 12
GnuPG
12.1 Présentation
Gnu Privacy Guard[12] est un logiciel de chiffrement asymétrique et de gestion de clés. L’algorithme utilisé pour
signer et chiffrer est El Gamal, qui est d’une fiabilité comparable à celle d’RSA.
Il s’installe très simplement avec urpmi. Il existe sous forme de plugin pour Thunderbird, et est donc muni d’une
interface graphique. Nous l’utiliserons dans ce cours en ligne de commande, rassurez-vous il y en a très peu à apprendre.
GNU Privacy Guard est, comme son nom l’indique, sous licence GNU, vous pouvez donc en faire l’usage que vous
voulez - y compris commercial - sans risquer de vous retrouver un jour au tribunal.
12.2 Utilisation
12.2.1 Génération d’une clé privée
Avant toute utilisation du GPG, vous devez créer une clé privée. GPG vous la générera et la conservera en lieu
sûr... Pour générer votre clé privée, saisissez la commande :
gpg --gen-key
Plusieurs informations vous seront demandées, y compris un mot de passe pour déverouiller la clé privée, il est
impératif que ce mot de passe soit robuste, sinon un tiers non autorisé ayant un accès physique à votre machine aurait
accès à votre clé privée. Cette clé est stockée dans un répertoire de votre home, elle sera utilisé à chaque déchiffrement
et à chaque signature.
L’option --armor encode la clé dans un format affichable et pouvant être envoyé par mail. Vous pouvez donner ce
ficher à qui vous voulez et même le mettre sur votre page web, cette clé permet seulement de chiffrer des fichiers, seule
votre clé privée permettra leur déchiffrement.
12.2.3 Importation
Si vous souhaitez envoyer des fichiers chiffrée à un correspondant, vous aurez besoin de sa clé publique. Il lui suffit
de vous l’envoyer d’une façon similaire à celle dont vous lui aurez fourni votre clé publique. Une fois sa clé publique
entre vos mains, il ne vous reste plus qu’à saisir
77
gpg --import --armor nomdufichier
gpg --list-keys
12.2.5 Chiffrement
Une fois que vous detenez la clé publique d’un de vos correspondants, vous avez la possibilité de chiffrer des fichiers
que lui seul pourra déchiffrer.
destinataire est une sous-chaine permettant d’identifier la clé publique du destinataire du message chiffré,
fichierChiffré est le nom du fichier généré par cette commande, fichieràChiffrer est, comme son nom l’indique,
le nom du fichier à chiffrer.
12.2.6 Déchiffrement
Vous pouvez déchiffrer un fichier chiffré avec votre clé publique en utilisant la commande
12.2.7 Signature
Les messages sont automatiquement signés avec votre clé privée lors du chiffrement. La signature est vérifiée lors
du déchiffrement, à condition bien sûr, que le destinataire ait en sa possession la clé publique de l’émetteur.
12.2.8 Bref
Ces notes n’étaient qu’un survol de GnuPG, pour plus d’informations, ou en vue d’une utilisation professionnelle,
se référer à [13].
78
Exercice 4 - Elargissement de la toile de confiance
Je désignerai dorénavant votre binôme par la lettre B.
1. Trouvez un trinôme C (B devra aussi trouver un trinôme D).
2. Récupérez la clé publique PC de C, vous prendrez soin de vérifier son authenticité avec son fingerprint
3. Chiffrez la clé publique PB de B et envoyez-la à C.
4. C devra déchiffrer PB et envoyer sa clé publique chiffrée à B.
5. B devra déchiffrer la clé publique de C et envoyer un message chiffré de confirmation à vous et à C.
79
Chapitre 13
GMP
13.1 Présentation
GMP[14] est un package d’arithmétique multi-précision, c’est à dire permettant de représenter des entiers, des
rationnels et des flottants avec une précision arbitraire, et non pas celle préconisée par les normes de représentation
des entiers et des flottants. Les algorithmes de cryptographie manipulent des nombres de plusieurs dizaines, voire
centaines de chiffres, ce qui nécessite l’utilisation d’une telle bibliothèque.
Vous pouvez l’installer très simplement avec urpmi ou apt-get. Comme ce package est sous licence GNU, vous
pouvez en faire l’utilisation que vous voulez. La documentation est disponible en anglais et vous donne la liste détaillée
des fonctions. Le but de ce document est juste de vous faire comprendre le fonctionnement du package en quelques
minutes.
13.2.1 Compilation
N’ouliez pas d’importer gmp.h et d’ajouter l’option de compilation -lgmp. Sinon ça marche pas.
13.2.2 Initialisation
Le type mpz t vous est fourni avec la librairie, méfiez-vous de l’absence d’étoile, il y a nécessairement des pointeurs
derrière ce type. Des fonctions préfixées par mpz init vous permettent d’initialiser ces variables. N’oubliez jamais
l’initialisation, elle correspond à l’allocation dynamique, elle n’oubliez jamais la destruction, qui elle correspond à la
libération de la mémoire.
mpz t i ; // d e c l a r a t i o n
m p z i n i t ( i ) ; // a l l o c a t i o n
Les instructions ci-dessus déclarent un entier multiprécision i et effectuent l’allocation dynamique. La fonction
mpz init initialise i à 0. Ne pas confondre initialisation et affectation. Un fois la variable initialisée, vous pouvez
lui affecter toutes les valeurs que vous voulez. Par contre n’initialisez pas une variable déjà initialisée, vous devez
préalablement la détruire. On détruit un entier multiprécision (bref, on libère la mémoire) avec la fonction mpz clear.
mpz t i ; // d e c l a r a t i o n
m p z i n i t ( i ) ; // a l l o c a t i o n
m p z s e t u i ( i , 5 0 0 0 ) ; // a f f e c t a t i o n
/∗
U t i l i s a t i o n de i
80
∗/
m p z c l e a r ( i ) ; // l i b e r a t i o n de l a memoire
13.2.4 Affichage
Pour afficher ou ecrire dans un fichier la valeur d’un entier multiprécision, on utilise la fonction mpz out str (FILE
*stream, int base, mpz t op ). Si stream est égal à NULL, la valeur est ecrite dans stdout.
mpz t valeur ;
mpz init ( valeur ) ;
mpz set ui ( valeur , 1 7 ) ;
mpz o u t s t r (NULL, 1 0 , v a l e u r ) ;
mpz clear ( valeur ) ;
Les instructions ci-dessus affichent 17.
13.2.5 Exemple
Voici un petit exemple avec quelques calculs sur des entiers multi-précision.
#include<gmp . h>
#include<s t d i o . h>
/∗
P l a c e l a f a c t o r i e l l e de n dans r e s . r e s d o i t e t r e i n i t i a l i s e
∗/
81
{
mpz set ui ( res , 1 ) ;
}
else
{
m p z i n i t ( temp ) ;
f a c t o r i e l l e ( n−1 , temp ) ;
mpz mul si ( r e s , temp , n ) ;
m p z c l e a r ( temp ) ;
}
}
/∗
P l a c e b ˆn dans r e s . r e s d o i t e t r e i n i t i a l i s e
∗/
/∗
A f f i c h e l e s 100 p r e m i e r e s p u i s s a n c e s de 1 0 .
∗/
i nt main ( )
{
mpz t i ;
long i n d ;
mpz init ( i ) ;
for ( i n d = 0 ; i n d <= 100 ; i n d++)
{
p u i s s a n c e ( 1 0 , ind , i ) ;
m p z o u t s t r (NULL, 1 0 , i ) ;
p r i n t f ( ”\n” ) ;
}
mpz clear ( i ) ;
return 0 ;
}
Et voici, pour vous éviter de vous prendre la tête, le makefile.
a l l : testGMP . c
g c c −g −lgmp testGMP . c
82
run : a l l
. / a . out
83
Chapitre 14
Arithmétique
Les bases mathématiques permettant la compréhension des algorithmes asymétriques sont exposées dans ce cours.
Vous trouverez un exposé plus détaillé dans [2]. Notez aussi que ce cours se recoupe avec le programme de spé maths
de terminale S.
Sauf mention explicité du contraire, tous les nombres considérés ici sont des entiers relatifs, c’est-à-dire des nombres
entiers pouvant être positifs, négatifs ou nuls.
14.1 Divisibilité
Définition 14.1.1 a divise b, s’il existe k tel que ak = b
a divise b se note a|b. On dit alors que a est un diviseur de b, et que b est un multiple de a.
Exercice 1
Prouvez, en utilisant la définition de la divisibilité, que
– 3|21
– (−3)|6
Exercice 2
Prouvez les propriétés suivantes :
1. Si a|b et b|a, alors |a| = |b|
2. Si a|b et b|c, alors a|c
3. Si a|b et a|c, alors a|(b + c)
4. Si a|b et a|c, alors a|bc
5. Si a|b, alors ak |bk pour tout entier naturel k.
Exercice 3
Effectuez les divisions suivantes :
– 12 par 5
– 11 par 2
– 13 par 13
– 2 par 4
84
– (−6) par 2
– 0 par 3
– (−5) par 2
14.3 PGCD
Définition 14.3.1 Le plus grand commun diviseur de a et b, noté pgcd(a, b) est le plus grand nombre qui divise à la
fois a et b.
Exercice 4
Complétez le tableau suivant :
a b pgcd(a, b)
6 3
3 6
17 13
29 26
0 4
7 7
Exercice 5
Les nombres suivants sont-ils premiers ?
– 4
– 7
– 23
– 1
Exercice 6
Prouvez qu’il existe une infinité de nombres premiers.
Exercice 7
Les couples de nombres suivants sont-ils premiers entre eux ?
– 3 et 5
– 20 et 32
– 23 et 41
– 18 et 27
– 0 et 4
– 7 et 7
Existe-t-il des nombres premiers avec eux-mêmes ?
85
Exercice 8
Prouvez que deux nombres premiers distincts sont premiers entre eux.
Exercice 9
a b
Soient a et b deux entiers relatifs, p = pgcd(a, b), a′ = et b′ = . Prouvez que a′ et b′ sont premiers entre eux.
p p
Exercice 10
Décomposez chacun de ces nombres en produit de facteurs premiers.
– 21
– 286
– 51
– 1344
Exercice 11
Donnez les nombres correspondant aux décompositions en facteurs premiers suivantes.
– (0, 0, 1, 1, 0, . . . , 0, . . .)
– (1, 1, 2, 0, . . . , 0, . . .)
– (1, 0, 2, 0, 1, 0, . . . , 0, . . .)
– (0, 0, 1, 0, . . . , 0, . . .)
– (0, . . . , 0, . . .)
Exercice 12
Donnez la liste des diviseurs du nombre correspondant à la décomposition en facteurs premiers suivante :
(1, 0, 1, 0, 1, 0, . . . , 0, . . .)
Exercice 13
Soient x = pe11 pe22 . . . pei i . . . penn et y = pf11 pf22 . . . pfi i . . . pfnn . Donnez la décomposition en facteurs premiers de xy.
86
14.6.2 Application au calcul du PGCD
Propriété 14.6.3 Soient
a = pe11 pe22 . . . pei i . . . penn
et
b = pf11 pf22 . . . pfi i . . . pfnn
alors
min(e1 ,f1 ) min(e2 ,f2 ) min(ei ,fi )
pgcd(a, b) = p1 p2 . . . pi . . . pnmin(en ,fn )
Exercice 14
Calculez les PGCDs des couples de nombres dont les décompositions en facteurs premiers sont données :
– (0, 0, 2, 1, 0, . . . , 0, . . .) et (0, 0, 1, 2, 0, . . . , 0, . . .)
– (1, 1, 1, 0, . . . , 0, . . .) et (0, 2, 2, 2, 0, . . . , 0, . . .)
– (1, 0, 1, 0, . . . , 0, . . .) et (0, 1, 0, 1, 0, . . . , 0, . . .)
– (2, 2, 1, 1, 0, . . . , 0, . . .) et (0, 0, 1, 1, 0, . . . , 0, . . .)
Exercice 15
Soient x = pe11 p2e2 . . . pei i . . . penn et y = pf11 pf22 . . . pfi i . . . pfnn . Déterminer une condition nécessaire et suffisante sur les
suites e et f permettant de savoir si x et y sont premiers entre eux.
au + bv = pgcd(a, b)
Théorème 14.7.2 a et b sont premiers entre eux si et seulement s’il existe u et v relatifs tels que
au + bv = 1
Exercice 16
Appliquez l’algorithme d’Euclide aux couples de nombres suivants :
– 3 et 6
– 4 et 0
– 161 et 184
– 21 et 34
87
Exercice 17
On admet que le pgcd(a, b) est la plus petite combinaison linéaire strictement positive de a et b.
1. Montrer que pgcd(a, b)|pgcd(b, a mod b)
2. Montrer que pgcd(b, a mod b)|pgcd(a, b)
3. Montrer que l’algorithme d’Euclide se termine.
4. Soit Fn la suite définie par
– F0 = 0
– F1 = 1
– Fn = Fn−1 + Fn−2 , si n ≥ 2
On appelle Fn le n-ième nombre de Fibonacci. Montrez par récurrence que
1
Fn = √ (φn + ψ n )
5
avec √ √
1+ 5 1− 5
φ= ;ψ = ;
2 2
F est-elle croissante ?
5. Prouvez que pout tout n ≥ 2,
Fn mod Fn−1 = Fn−2
6. Prouvez par récurrence que
pgcd(Fn , Fn−1 ) = 1
7. Prouvez par récurrence que le calcul de
pgcd(Fn , Fn−1 )
nécessite n appels récursifs.
8. Prouvez par récurrence que si Fn ≥ k et Fn−1 ≥ k ′ , alors
pgcd(k, k ′ )
88
Comme, de plus,
pgcd(a, b) = pgcd(b, a mod b)
alors
a
v.a + (u − v⌊ ⌋)b = pgcd(a, b)
b
Donc, en posant u′ = v et v ′ = u − v⌊ ab ⌋, on a bien
u′ .a + v ′ .b = pgcd(a, b)
Exercice 18
Appliquez l’algorithme d’Euclide étendu aux couples de nombres suivants. Lesquels sont premiers entre eux ?
– 3 et 6
– 4 et 0
– 161 et 184
– 21 et 34
Exercice 19
Ecrivez en C l’algorithme d’Euclide étendu (passez u et v en paramètre par référence) sans GMP.
Exercice 20
Prouvez le théorème de Gauss
89
Exercice 26 - Expérimentation avec la suite de Fibonacci
Ecrivez une fonction retournant le n-ème nombre de Fibonacci en utilisant la relation de récurrence donnée dans
la section “algorithme d’Euclide”. Que remarquez-vous lorsque l’on calcule des valeurs de la suite de Fibonacci avec
de grandes valeurs de n (control-C pour interrompre l’exécution d’un programme :-) ? On considère, pour remédier à
ce petit problème la fonction φ définie comme suit
– φ(a, b, 0) = b
– φ(a, b, n) = φ(a + b, a, n − 1)
Prouvez par récurrence sur n que Fn+k = φ(Fk+1 , Fk , n), puis que Fn = φ(1, 0, n). Utilisez cette relation pour modifier
la fonction calculant le n-ème nombre de Fibonacci. Tester l’algorithme d’Euclide étendu avec des couples (Fn , Fn−1 )
(prenez de grandes valeurs de n).
90
Chapitre 15
Arithmétique modulaire
Les protocoles de chiffrement sont basés sur des opérations dans des espaces quotient, détaillés dans la dernière
partie de ce cours. Les définitions sont simplifiées au minimum nécessaire pour comprendre ce cours, et donc moins
précises que ce que vous pourriez trouver dans des ouvrages spécialisés.
La première section, sur les congruences, expose des points du programme de spé maths de terminale S, rédigés
toutefois de façon plus technique. Les deux sections suivantes abordent des éléments du programme de première année
de fac, ou de maths sup, seuls les points essentiels à la compréhension de la dernière section du cours sont exposées,
j’ai pris la liberté de simplifier quelques définitions. La dernière section expose des méthodes utilisées directement en
cryptographie asymétrique, elles sont aussi enseignées en première année de fac.
15.1 Congruences
Définition 15.1.1
a≡b (mod n)
si
n|(a − b)
On dit alors que a est congru à b modulo n.
Autrement dit, a est b congru à b modulo n si et seulement si a et b ont le même reste de la division par n. Plus
formellement,
kn = qn + r − (q ′ n + r′ )
ssi
kn = (q − q ′ )n + (r − r′ )
ssi
n(k + q ′ − q) = (r − r′ )
Donc
n|(r − r′ )
Or, |r − r′ | < n, donc n ne peut diviser (r − r′ ) que si r − r′ = 0. On a donc r = r′ , comme r = a mod n et r′ = b mod n,
alors a mod n = b mod n.
91
ssi
a − b = qn − q ′ n
ssi
a − b = (q − q ′ )n
Donc, n|(a − b).
Exercice 1
Pour chacune de ces propriétés,
– donnez un exemple numérique
– donnez une preuve
Exercice 2
Calculez les valeurs suivantes :
733 mod 10; 4.7 mod 9; 14 + 71 mod 83; 44 mod 12;
3.9 − 7.8 mod 11; 247349 mod 7; 21247 mod 17;
3457 − 1 mod 11; 951842 − 4 mod 5
32n+1 + 52n+1 mod 4; 6n + 13n+1 mod 7
Par exemple, l’ensemble des entiers naturels, noté N (ou (N, +, 0)), est un monoı̈de. En effet,
– il est toujours possible d’additionner deux entiers naturels
– et 0 est un élément neutre pour l’addition.
L’ensemble (B, ×, 1) des booléens, muni du produit est aussi un monoı̈de. Il est en effet toujours possible de multiplier
deux booléens, et on a 0.1 = 0, 1.1 = 1, donc 1 (vrai) est un élément neutre pour le produit booléen.
15.2.2 Groupes
Définition 15.2.2 (G, +, 0) est un groupe si
– (G, +, 0) est un monoı̈de
– pour tout élément x de G, il existe un élément −x appelé ”opposé de x”, tel que
x + (−x) = 0
Autrement dit, un groupe est un monoı̈de dans lequel il existe une soustraction. On remarque que N n’est pas un
groupe mais que l’ensemble des entiers relatifs Z (ou (Z, +, 0)) est bien un groupe. En effet,
– il est toujours possible d’additionner deux entiers relatifs
– 0 est bien un élément neutre pour l’addition.
– pour tout x ∈ Z, −x existe, ce qui n’est pas le cas dans N .
92
15.2.3 Anneaux
Définition 15.2.3 (A, +, ×, 0, 1) est un anneau si
– (A, +, 0) est un groupe
– on peut toujours multiplier deux éléments de A
– il existe un élément neutre 1 pour la multiplication
Par exemple, l’ensemble des entiers relatifs est un anneau, il suffit de prendre 1 comme élément neutre pour la
multiplication. L’ensemble des matrices carrées est un anneau.
15.2.4 Corps
Définition 15.2.4 (C, +, ×, 0, 1) est un corps si
– (G, +, ×, 0, 1) est un anneau
– pour tout élément x de C, sauf 0, il existe un élément x−1 appelé ”inverse de x”, tel que
x × (x−1 ) = 1
Autrement dit, C est un corps s’il est muni d’une division. Par exemple, l’ensemble des entiers relatifs n’est pas un
corps, mais l’ensemble des rationnels en est un. L’ensemble des matrices inversibles est un corps.
Exercice 3
On considère l’ensemble (F , +, ◦, f0 , f1 ) des fonctions linéaires (f (x) = ax + b) muni de l’addition ((f + g)(x) =
f (x) + g(x)) et de la composition ◦ ((f ◦ g)(x) = f (g(x))).
– Est-ce que (F , +, ◦, f0 , f1 ) est un monoı̈de ?
– un groupe ?
– un anneau ?
– un corps ?
– existe-t-il un sous-ensemble de F formant un corps ?
Exercice 4
On considère l’ensemble (P, +, ◦, f0 , f1 ) des polynômes à coefficients réels
n
X
P (x) = ai xi + a0
i=1
93
Exercice 5
Etant donné un entier relatif non nul n. Pour tous a, b entiers relatifs, on pose a ∼ b si a ≡ b (mod n). Prouver
que ∼ est une relation d’équivalence.
Définition 15.3.1 Soit n > 0, et k ∈ {0, . . . , n − 1}, alors on note [k]n = {e|e ∼ k}.
15.3.2 Z/nZ
Supposons qu’en calculant c = a + b mod n, on substitue à a et à b des éléments de même classe d’équivalence,
alors le résultat est-il de la même classe que c ? Vérifions : remplaçons a par a′ ∈ [a]n et b par b′ ∈ [b]n . Comme a ∼ a′
et b ∼ b′ , alors il existe k et k ′ tels que a′ = a + kn et b′ = b + k ′ n. Calculons
c′ = a′ + b ′
= a + kn + b + k ′ n
= a + b + (k + k ′ )n
= c + (k + k ′ )n
Donc c ∼ c′ et c′ ∈ [c]n . On déduit qu’il est possible d’étendre l’addition modulaire aux classes d’équivalences. Au lieu
d’additionner un élément de [a]n à un élément de [b]n , nous additionnerons directement ces deux classes d’équivalence.
Comme on remarque la même chose en calculant c = ab mod n (en exercice), nous pouvons définir les calculs modulo
n sur l’ensemble d’ensembles
{[0]n , . . . , [n − 1]n }
Définition 15.3.2 Soit n > 0, alors on note Z/nZ l’espace quotient {[k]n |0 ≤ k ≤ n − 1}
Lorsqu’il n’y a pas d’ambiguı̈té, on se permet d’enlever les crochets et de noter k au lieu de [k]n .
Exercice 6
Montrez qu’en substituant à a et à b des éléments de même classe d’équivalence dans c = ab mod n, on obtient un
élément de même classe d’équivalence que c.
Structure d’anneau
Propriété 15.3.1 Pour tout n > 0, Z/nZ est un monoı̈de.
Preuve en exercice.
94
15.4 Inverses modulaires
Supposons qu’il existe une fonction de chiffrement f définie comme suit, f (k) = k ∗ 7 mod 9. Calculons f (3) ≡
3 ∗ 7 ≡ 29 ≡ 0 (mod 9). Existe-t-il une fonction f ′ (k) = k ∗ p mod 9, inverse de f , telle que (f ◦ f ′ )(k) = k, en
particulier, existe-t-il p tel que 0 ∗ p mod 9 = 3 ?
On a multiplié [3]9 par [7]9 pour obtenir [0]9 , peut-on “revenir” à [3]9 , c’est-à-dire multiplier [0]9 par l’inverse, noté
[7]−1
9 de [7]9 ? Plus généralement, cela revient à se demander si Z/nZ est un corps. C’est-à-dire, est-ce que la “division”
existe dans Z/nZ. Voici la réponse :
µn = k.k ′ − 1
k.k ′ − µn = 1
Or, k ′ et µ n’existent que si k et n sont premiers entre eux. Comme Z/nZ est un corps, alors pour tout k ∈ {1, . . . , n−1},
k est premier avec n, donc aucun d’eux (sauf 1) ne peut diviser n, donc n est premier. La réciproque est basée sur le
même principe.
Définition 15.4.1 Pour tout n > 0, φ(n) est le nombre d’éléments inversibles de Z/nZ.
Prenons par exemple Z/10Z, les éléments inversibles de Z/10Z sont
{1, 3, 7, 9}
Notons qu’il s’agit des éléments premiers avec 10. Donc φ(10) = 4.
Exercice 7
– Z/11Z est-il un corps ?
– Quels sont les éléments inversibles de Z/11Z et leurs inverses ?
– Quelle est la valeur de φ(11) ?
Exercice 8
– Z/14Z est-il un corps ?
– Quels sont les éléments inversibles de Z/14Z et leurs inverses ?
– Quelle est la valeur de φ(14) ?
Notons que si n est premier, tous ses éléments, sauf 0 sont inversibles, nous admettrons donc que
95
15.4.2 Pratique de l’inversion
Comment, étant donné n > 0, et k ∈ Z/nZ, trouver l’inverse de k ? Si n est premier, le petit théorème de fermat
nous le donne :
Théorème 15.4.2 Si n est premier, alors pout tout k non congru à 0 modulo n,
k n−1 ≡ 1 (mod n)
.
Par exemple, si n = 5 et k = 3, alors 34 ≡ 81 ≡ 1 (mod 5), donc 3n−2 ≡ 33 ≡ 27 ≡ 2 (mod 5) est l’inverse
modulo 5 de 3. En effet, 3.2 ≡ 1 (mod 5).
k φ(n) ≡ 1 (mod n)
.
Par exemple, si n = 10, et k = 3, alors φ(10) = φ(2.5) = 1.4 = 4, on a bien
34 ≡ 92
≡ 81
≡ 1 (mod 10)
412 ≡ 166
≡ 2563
≡ 43
≡ 64
≡ 1 (mod 10)
96
Chapitre 16
RSA
16.0.3 Principe
Le chiffrement se fait à l’aide de la clé publique, le déchiffrement à l’aide de la clé privée. [2]
Chiffrement
La clé publique est un couple (C, N ) où
– N = P Q est le produit de deux nombres premiers P et Q
– C est un nombre premier avec (P − 1)(Q − 1).
On chiffre un message M en calculant
M′ ≡ MC (mod N )
Si par exemple on a P = 3, Q = 11, alors N = P Q = 33 et (P − 1)(Q − 1) = 2 × 10 = 20. Si par exemple on prend
C = 7, on remarque que 7 est bien premier avec 20, la clé publique est (7, 33). On chiffre le message M = 13 en
calculant M ′ ≡ M C ≡ 137 ≡ 7 (mod 33).
Déchiffrement
Notez qu’il n’est pas trivial de retrouver M à partir de M ′ et de (C, P Q). La clé privée est un couple (C ′ , N ) tel que
pour tout message M ,
′
(M C )C ≡ M (mod N )
Alors on déchiffre M ′ en calculant
′
M ≡ (M ′ )C (mod N )
′ 3
Ici on a C = 3. On constate que M ≡ 7 ≡ 13 (mod 33). La question que l’on est invité à se poser est : comment on
trouve C ′ ?
M φ(N ) ≡ 1 (mod N )
M kφ(N ) ≡ 1 (mod N )
97
et de ce fait
M kφ(N )+1 ≡ M (mod N )
Comme ′
M CC ≡ M (mod N )
′
il convient de déterminer C tel que
CC ′ = kφ(N ) + 1
ce qui s’écrit plus simplement comme une relation de Bezout
CC ′ − kφ(N ) = 1
Notez que la connaissance de φ(N ) est indispensable si on souhaite trouver C ′ . Etant donné N = P Q le produit de
nombres premiers P et Q, on a φ(N ) = (P − 1)(Q − 1). Donc pour connaı̂tre φ(N ), il est nécessaire de connaı̂tre la
décomposition de N en produit de facteurs premiers. Donc, retrouver C ′ à partir de C oblige le cryptanalyste à passer
par une factorisation de N , problème connu pour être difficile.
98
Annexe A
99
A.2 Fonctions récursives terminales
#include<s t d i o . h>
#include<s t d l i b . h>
long f a c t o r i e l l e ( long n )
{
return f a c t o r i e l l e R ( n , 1);
}
i n t main ( )
{
long a = 4 ;
p r i n t f ( ”%l d ! = %l d \n” , a , f ac tori ell e (a ));
getch ( ) ;
return 0 ;
}
100
A.3 Itérateurs et applications
#include<s t d i o . h>
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
typedef s tr u ct
{
unsigned long f i r s t ;
unsigned long s e c o n d ;
} couple ;
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
typedef s tr u ct
{
unsigned long 11 , 12 , 21 , 22 ;
} quadruplet ;
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
c o u p l e applyF ( c o u p l e ( ∗ f ) ( c o u p l e ) , i n t n , couple x)
{
i f ( n == 0 )
return x ;
return f ( applyF ( f , n − 1 , x ) ) ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
c o u p l e applyFT ( c o u p l e ( ∗ f ) ( c o u p l e ) , i n t n , couple x)
{
i f ( n == 0 )
return x ;
return applyF ( f , n−1 , f ( x ) ) ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
101
return 1 ;
if (n % 2)
return b ∗ f a s t P u i s s a n c e ( b∗b , n / 2 ) ;
return f a s t P u i s s a n c e ( b∗b , n / 2 ) ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
quadruplet fiboMat ( )
{
quadruplet q = {1 , 1 , 1 , 0};
return q ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
quadruplet i d e n t i t e ( )
{
quadruplet q = {1 , 0 , 0 , 1};
return q ;
}
102
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
q u a d r u p l e t multMat ( q u a d r u p l e t x , q u a d r u p l e t y )
{
q u a d r u p l e t xy ;
xy . 1 1 = x . 1 1 ∗y . 1 1 + x . 1 2 ∗y . 2 1 ;
xy . 2 1 = x . 2 1 ∗y . 1 1 + x . 2 2 ∗y . 2 1 ;
xy . 1 2 = x . 1 1 ∗y . 1 2 + x . 1 2 ∗y . 2 2 ;
xy . 2 2 = x . 2 1 ∗y . 1 2 + x . 2 2 ∗y . 2 2 ;
return xy ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
c o u p l e multMatVec ( q u a d r u p l e t x , c o u p l e y )
{
c o u p l e xy ;
xy . f i r s t = x . 1 1 ∗y . f i r s t + x . 1 2 ∗ y . s e c o n d ;
xy . s e c o n d = x . 2 1 ∗y . f i r s t + x . 2 2 ∗y . s e c o n d ;
return xy ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
i n t main ( )
{
int i ;
f o r ( i = 0 ; i <= 45 ; i ++)
{
p r i n t f ( ” F %d = %l d \n” , i , fastFibonacciIT( i ) ) ;
}
return 0 ;
}
103
A.4 Tours de Hanoı̈
#include<s t d i o . h>
#include<m a l l o c . h>
#include<s t d l i b . h>
/∗
On p l a c e r a dans l a p r e m ie r e c a se de chaque t a b l e a u l e nombre de d i s q u e s
p l a c e s su r l e s o c l e .
∗/
i n t max2 ( i n t i , i n t j )
{
return (i > j) ? i : j;
}
i n t max3 ( i n t i , i n t j , i n t k )
{
return max2 ( max2 ( i , j ) , k ) ;
}
void a f f i c h e S o c l e s ( i n t ∗∗ s )
{
i n t max = max3( ∗ ∗ s , ∗ ∗ ( s + 1 ) , ∗ ∗ ( s + 2 ) ) ;
int i ;
f o r ( i = max ; i > 0 ; i −−)
{
i f ( ∗ ∗ s >= i )
p r i n t f ( ”%3d ” , ∗ ( ∗ s + i ) ) ;
else
printf (” ” );
i f ( ∗ ∗ ( s + 1 ) >= i )
p r i n t f ( ”%3d ” , ∗ ( ∗ ( s +1) + i ) ) ;
else
printf (” ” );
i f ( ∗ ∗ ( s + 2 ) >= i )
p r i n t f ( ”%3d ” , ∗ ( ∗ ( s +2) + i ) ) ;
p r i n t f ( ” \n” ) ;
}
p r i n t f ( ”−−−−−−−−−−−−\n” ) ;
}
void d e p l a c e D i s q u e ( i n t ∗ s o c l e S o u r c e , i n t ∗ s o c l e D e s t i n a t i o n )
{
∗( s o c l e D e s t i n a t i o n + ∗ s o c l e D e s t i n a t i o n + 1) =
∗( s o c l e S o u r c e + ∗ s o c l e S o u r c e ) ;
( ∗ s o c l e D e s t i n a t i o n )++;
( ∗ s o c l e S o u r c e )−−;
}
i n t ∗ c r e e S o c l e ( i n t n b D i sq u e s )
{
i n t ∗ s = m a l l o c ( ( n b D i sq u e s + 1 ) ∗ s i z e o f ( i n t ) ) ;
i f ( s == NULL)
exit (0);
∗s = 0;
return s ;
}
void i n i t S o c l e ( i n t ∗ s , i n t n b D i sq u e s )
{
int i ;
f o r ( i = 1 ; i <= n b D i sq u e s ; i ++)
∗ ( s + i ) = n b D i sq u e s − i + 1 ;
∗ s = n b D i sq u e s ;
}
void c r e e S o c l e s ( i n t ∗∗ s , i n t n b D i sq u e s )
{
104
∗ s = c r e e S o c l e ( n b D i sq u e s ) ;
∗ ( s + 1 ) = c r e e S o c l e ( n b D i sq u e s ) ;
∗ ( s + 2 ) = c r e e S o c l e ( n b D i sq u e s ) ;
i n i t S o c l e ( ∗ s , n b D i sq u e s ) ;
}
i n t main ( )
{
int∗ s [ 3 ] ;
i n t n b D i sq u e s = 3 ;
c r e e S o c l e s ( s , n b D i sq u e s ) ;
afficheSocles (s );
d e p l a c e D i s q u e s ( n b D i sq u e s , s , 0 , 1 , 2 ) ;
f r e e (∗ s ) ;
f re e (∗( s + 1 ) ) ;
f re e (∗( s + 2 ) ) ;
return 1 ;
}
105
A.5 Suite de Fibonacci
#include<s t d i o . h>
#d ef i n e N 45
i n t main ( )
{
unsigned long l;
for ( l = 0 ; l <= N ; l ++)
p r i n t f ( ”%l u = %l u \n” , l , fibo ( l )) ;
for ( l = 0 ; l <= N ; l ++)
p r i n t f ( ”%l u = %l u \n” , l , fastFibo ( l ) ) ;
return 0 ;
}
106
A.6 Pgcd
#include<s t d i o . h>
i n t main ( )
{
unsigned long f 1 , f 2 , i ;
f2 = fibonacci (0);
f o r ( i = 0 ; i <= 40 ; i ++)
{
f1 = f2 ;
f 2 = f i b o n a c c i ( i +1);
p r i n t f ( ” pgcd(%l u , %l u ) = %l u \n” , f 1 , f 2 , pgcd ( f 1 , f2 ));
}
return 0 ;
}
107
A.7 Pavage avec des L
#include<s t d i o . h>
#include<s t d l i b . h>
#include<m a l l o c . h>
typedef s tr u ct
{
int l i g n e ;
int colonne ;
} coordonnees ;
typedef s tr u ct
{
char ∗ t a b ;
int n ;
coordonnees c a s e I n t e r d i t e ;
}grille ;
void e r r e u r M e m o i r e ( )
{
p r i n t f ( ” Pas de memoire \n” ) ;
exit (1);
}
char ∗ r e t o u r n e A d r e s s e C a s e ( g r i l l e g , c o o r d o n n e e s c )
{
int m i l i e u ;
i f ( g . n == 0 )
return g . t a b ;
milieu = puiss (2 , g . n − 1 );
i f ( c . l i g n e >= m i l i e u )
{
g . t a b += 2∗ m i l i e u ∗ m i l i e u ;
c . l i g n e −=m i l i e u ;
}
i f ( c . c o l o n n e >= m i l i e u )
{
g . t a b += m i l i e u ∗ m i l i e u ;
c . c o l o n n e−=m i l i e u ;
}
g . n −= 1 ;
return r e t o u r n e A d r e s s e C a s e ( g , c ) ;
}
char r e t o u r n e V a l e u r C a s e ( g r i l l e g , c o o r d o n n e e s c )
{
return ∗ r e t o u r n e A d r e s s e C a s e ( g , c ) ;
}
void a f f e c t e V a l e u r C a s e ( g r i l l e g , c o o r d o n n e e s c , char v a l e u r )
{
∗ retourneAdresseCase(g , c ) = valeur ;
}
108
void g r i l l e A f f i c h e ( g r i l l e g )
{
int l ar ge u r = p u i ss (2 , g . n ) ;
coordonnees c ;
f o r ( c . l i g n e = 0 ; c . l i g n e < l a r g e u r ; c . l i g n e ++)
{
f o r ( c . c o l o n n e = 0 ; c . c o l o n n e < l a r g e u r ; c . c o l o n n e++)
p r i n t f ( ”%c ” , r e t o u r n e V a l e u r C a s e ( g , c ) ) ;
p r i n t f ( ” \n” ) ;
}
}
void g r i l l e P a v a g e ( g r i l l e g , char c )
{
int l ar ge u r ;
char v a l e u r I n t e r d i t e ;
int nbPieces ;
g r i l l e hd , hg , bd , bg ;
i f ( g . n != 0 )
{
l a r g e u r = p u i s s ( 2 , g . n −1);
hg . t a b = g . t a b ;
hd . t a b = hg . t a b + l a r g e u r ∗ l a r g e u r ;
bg . t a b = hd . t a b + l a r g e u r ∗ l a r g e u r ;
bd . t a b = bg . t a b + l a r g e u r ∗ l a r g e u r ;
hg . n = g . n − 1 ;
hd . n = g . n − 1 ;
bg . n = g . n − 1 ;
bd . n = g . n − 1 ;
hg . c a s e I n t e r d i t e . l i g n e = l a r g e u r − 1 ;
hg . c a s e I n t e r d i t e . c o l o n n e = l a r g e u r − 1 ;
hd . c a s e I n t e r d i t e . l i g n e = l a r g e u r − 1 ;
hd . c a s e I n t e r d i t e . c o l o n n e = 0 ;
bg . c a s e I n t e r d i t e . l i g n e = 0 ;
bg . c a s e I n t e r d i t e . c o l o n n e = l a r g e u r − 1 ;
bd . c a s e I n t e r d i t e . l i g n e = 0 ;
bd . c a s e I n t e r d i t e . c o l o n n e = 0 ;
i f (g . caseInterdite . ligne < largeur )
i f ( g . c as e In t er d ite . colonne < largeur )
hg . c a s e I n t e r d i t e = g . c a s e I n t e r d i t e ;
else
{
hd . c a s e I n t e r d i t e . l i g n e = g . c a s e I n t e r d i t e . l i g n e ;
hd . c a s e I n t e r d i t e . c o l o n n e = g . c a s e I n t e r d i t e . c o l o n n e − l a r g e u r ;
}
else
i f ( g . c as e In t er d ite . colonne < largeur )
{
bg . c a s e I n t e r d i t e . l i g n e = g . c a s e I n t e r d i t e . l i g n e − l a r g e u r ;
bg . c a s e I n t e r d i t e . c o l o n n e = g . c a s e I n t e r d i t e . c o l o n n e − l a r g e u r ;
}
else
{
bd . c a s e I n t e r d i t e . l i g n e = g . c a s e I n t e r d i t e . l i g n e − l a r g e u r ;
bd . c a s e I n t e r d i t e . c o l o n n e = g . c a s e I n t e r d i t e . c o l o n n e − l a r g e u r ;
}
v a l e u r I n t e r d i t e = retourneValeurCase ( g , g . c a s e I n t e r d i t e ) ;
a f f e c t e V a l e u r C a s e ( hd , hd . c a s e I n t e r d i t e , c + 1 ) ;
a f f e c t e V a l e u r C a s e ( hg , hg . c a s e I n t e r d i t e , c + 1 ) ;
a f f e c t e V a l e u r C a s e ( bg , bg . c a s e I n t e r d i t e , c + 1 ) ;
a f f e c t e V a l e u r C a s e ( bd , bd . c a s e I n t e r d i t e , c + 1 ) ;
affecteValeurCase (g , g . c ase In te rd ite , vale u rIn t erd it e ) ;
g r i l l e P a v a g e ( hd , c + 1 ) ;
nbPieces = ( large ur ∗ large ur − 1)/3;
g r i l l e P a v a g e ( hg , c+n b P i e c e s + 1 ) ;
g r i l l e P a v a g e ( bg , c+2∗ n b P i e c e s + 1 ) ;
g r i l l e P a v a g e ( bd , c+3∗ n b P i e c e s + 1 ) ;
}
}
void g r i l l e D e t r u i t ( g r i l l e g )
{
f r e e ( g . tab ) ;
}
i n t main ( )
{
g r i l l e g = g r i l l e C r e e ( 4 , 5 , 1 2 , −1, ’ ! ’ ) ;
grillePavage (g , ’ ! ’ );
grilleAffiche (g );
109
grilleDetruit (g );
return 0 ;
}
110
A.8 Complexes
#include<s t d i o . h>
#include<s t d l i b . h>
#include<m a l l o c . h>
#include<math . h>
#include ” c o m p l e x e . h”
#include ” l i n k e d L i s t . h”
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Retourne l a p a r t i e reelle
∗/
double reComplexe ( c o m p l e x e c )
{
return c . r e ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Retourne l a p a r t i e i m a g i n a i r e
∗/
double imComplexe( c o m p l e x e c )
{
return c . im ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Retourne l e module
∗/
double modComplexe ( c o m p l e x e c )
{
return c . mod ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Retourne l ’ argument
∗/
double argComplexe ( c o m p l e x e c )
{
return c . a r g ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
A f f i c h e c so u s forme e x p o n e n t i e l l e
∗/
void printExpComplexe ( c o m p l e x e c )
{
p r i n t f ( ” %.10 l f e ˆ ( % . 1 0 l f i ) ” , c . mod , c . a r g ) ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Affiche l ’ a f f i x e de c
∗/
void p r i n t A f f C o m p l e x e ( c o m p l e x e c )
{
p r i n t f ( ” ( % . 1 0 l f + %.10 l f i ) ” , c . r e , c . im ) ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Cree un complexe a p a r t i r de son a f f i x e
∗/
111
c o m p l e x e makeAffComplexe ( double r e , double im )
{
c o m p l e x e c = { r e , im , s q r t ( r e ∗ r e + im∗im ) , 0 . 0 } ;
i f ( c . mod != 0 . 0 )
{
c . a r g = a c o s ( c . r e / c . mod) ∗ ( ( c . im >= 0 ) ? 1 : − 1 ) ;
}
return c ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Cree un complexe a p a r t i r de sa forme e x p o n e n t i e l l e
∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
pComplexe copyComplexe ( c o m p l e x e c )
{
pComplexe p = ( pComplexe ) m a l l o c ( s i z e o f ( c o m p l e x e ) ) ;
i f ( p == NULL)
exit (0);
p−>r e = c . r e ;
p−>im = c . im ;
p−>mod = c . mod ;
p−>a r g = c . a r g ;
return p ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Retourne l e c o nju g u e de c
∗/
c o m p l e x e c o n j u g u e Co m ple xe ( c o m p l e x e c )
{
return makeAffComplexe ( c . r e , −c . im ) ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
S o u s t r a i t c1 e t c2
∗/
c o m p l e x e subComplexe ( c o m p l e x e c1 , c o m p l e x e c 2 )
{
return makeAffComplexe ( c 1 . r e − c 2 . r e , c 1 . im − c 2 . im ) ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Ad d it io nne c1 e t c2
∗/
c o m p l e x e addComplexe ( c o m p l e x e c1 , c o m p l e x e c 2 )
{
return makeAffComplexe ( c 1 . r e + c 2 . r e , c 1 . im + c 2 . im ) ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
112
M u l t i p l i e c1 e t c2
∗/
c o m p l e x e multComplexe ( c o m p l e x e c1 , c o m p l e x e c 2 )
{
return makeAffComplexe ( c 1 . r e ∗ c 2 . r e − c 1 . im ∗ c 2 . im ,
c 1 . r e ∗ c 2 . im + c 1 . im ∗ c 2 . r e ) ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Multiplie c par l e reel d
∗/
c o m p l e x e multReelComplexe ( double d , c o m p l e x e c )
{
return makeExpComplexe( d ∗ c . mod , c . a r g ) ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
D i v i s e c2 par c1
∗/
c o m p l e x e divComplexe ( c o m p l e x e c1 , c o m p l e x e c 2 )
{
return makeExpComplexe( c 1 . mod / c 2 . mod , c 1 . a r g − c 2 . a r g ) ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Eleve c a l a puissane n
∗/
113
A.9 Listes chaı̂nées
#include ” l i n k e d L i s t . h”
#include<s t d i o . h>
#include<s t d l i b . h>
#include<m a l l o c . h>
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
void e r r o r ( )
{
printf (” error ” ) ;
exit (0);
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
int l i n k e d Li st Ge t S i z e ( l i n k e d L i s t ∗ l )
{
return l −>s i z e ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
linkedList ∗ linkedListCreate ()
{
linkedList ∗ l ;
l = ( l i n k e d L i s t ∗) malloc ( s i zeo f ( l i n k e d L i s t ) ) ;
i f ( l == NULL)
error ( ) ;
l −> f i r s t = NULL ;
l −>l a s t = NULL;
l −>s i z e = 0 ;
return l ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
l i n k ∗ l i n k e d L i s t C r e a t e L i n k ( void∗ x )
{
l i n k ∗ l k = ( l i n k ∗) malloc ( s i zeo f ( l i n k ) ) ;
i f ( l k == NULL) e r r o r ( ) ;
l k −>d a t a = x ;
l k −>n e x t = NULL ;
return l k ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
void l i n k e d L i s t A p p e n d L i n k ( l i n k e d L i s t ∗ l , link ∗ lk )
{
i f ( l −>l a s t == NULL)
{
l −> f i r s t = l k ;
l −>l a s t = l −> f i r s t ;
}
else
{
l −>l a s t −>n e x t = l k ;
l −>l a s t = l k ;
}
l k −>n e x t = NULL ;
l −>s i z e ++;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
void l i n k e d L i s t A p p e n d ( l i n k e d L i s t ∗ l , void∗ x )
{
link ∗ lk = linkedListCreateLink(x ) ;
linkedListAppendLink ( l , l k ) ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
void l i n k e d L i s t P u s h L i n k ( l i n k e d L i s t ∗ l , link ∗ lk )
114
{
if ( l −> f i r s t == NULL)
{
l −> f i r s t = l k ;
l −>l a s t = l −> f i r s t ;
}
else
{
l k −>n e x t = l −> f i r s t ;
l −> f i r s t = l k ;
}
l −>s i z e ++;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
void l i n k e d L i s t P u s h ( l i n k e d L i s t ∗ l , void∗ x )
{
link ∗ lk = linkedListCreateLink(x ) ;
linkedListPushLink ( l , lk ) ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
void l i n k e d L i s t C o n c a t ( l i n k e d L i s t ∗ b e g i n , l i n k e d L i s t ∗ end )
{
i f ( b e g i n −>s i z e != 0 )
b e g i n −>l a s t −>n e x t = end−> f i r s t ;
else
b e g i n −> f i r s t = end−> f i r s t ;
i f ( end−>s i z e != 0 )
b e g i n −>l a s t = end−>l a s t ;
end−> f i r s t = NULL;
end−>l a s t = NULL ;
b e g i n −>s i z e += end−>s i z e ;
end−>s i z e = 0 ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
l i n k e d L i s t ∗ l i n k e d L i s t M a p ( l i n k e d L i s t ∗ l , void∗ ( ∗ f ) ( void ∗ ) )
{
linkedList ∗ lBis = linkedListCreate ( ) ;
link ∗ lk = linkedListGetFirst( l ) ;
while ( l k !=NULL)
{
l i n k e d L i s t A p p e n d ( l B i s , f ( l k −>d a t a ) ) ;
l k = l k −>n e x t ;
}
return l B i s ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
115
link ∗ lk = linkedListGetFirst( l ) ;
while ( l k !=NULL)
{
f ( l k −>d a t a ) ;
l k = l k −>n e x t ;
}
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
void d e s t r o y I nt ( void ∗ i )
{
f r e e (( i n t ∗) i ) ;
}
void p r i nt I nt ( void ∗ i )
{
p r i n t f (”%d −> ” , ∗ ( ( i n t ∗ ) i ) ) ;
}
i n t main ( )
{
int i = 1;
int ∗ k ;
link e dL ist∗ l = linkedListCreate () ;
linkedList∗ lBis ;
f o r ( i = 0 ; i < 100 ; i ++)
{
k = ( i n t ∗) malloc ( s i z e o f ( i n t ) ) ;
∗k = i ;
linkedListAppend ( l , k ) ;
}
// l i n k e d L i s t A p p l y ( l , p r i n t I n t ) ;
l B i s = linkedListMap ( l , copyInt ) ;
// l i n k e d L i s t A p p l y ( l B i s , p r i n t I n t ) ;
linkedListConcat ( l , lBis );
linkedListApply ( l , printInt );
linkedListDestroy ( l , destroyInt );
linkedListDes tr oy ( lBis , d e s t r o y I nt ) ;
return 1;
}
∗/
116
A.10 Tri fusion
#include<s t d i o . h>
#include<s t d l i b . h>
#include<m a l l o c . h>
#include ” l i n k e d L i s t . h”
void s p l i t ( l i n k e d L i s t ∗ s o u r c e , l i n k e d L i s t ∗ d e s t 1 , l in k ed Li st ∗ dest2 )
{
li n k ∗ l = l i n k e d Li stUnl ink Fi rst ( source ) ;
i f ( l != NULL)
{
linkedListAppendLink ( dest1 , l ) ;
s p l i t ( source , dest2 , dest1 ) ;
}
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
i n t e s t I n f ( void∗ i , void∗ j )
{
return ( ∗ ( i n t ∗ ) i <= ∗ ( i n t ∗ ) j ) ? 1 : 0;
}
void d e s t r o y I n t ( void∗ i )
{
f r e e ( ( int ∗) i ) ;
}
i n t main ( )
{
int i = 1;
int∗ k ;
linkedList ∗ l = linkedListCreate ( ) ;
link ∗ lk ;
f o r ( i = 100 ; i > 0 ; i −−)
{
117
k = ( int ∗) malloc ( s i zeo f ( int ) ) ;
∗k = i ;
linkedListAppend ( l , k ) ;
}
lk = linkedListGetFirst( l ) ;
while ( l k !=NULL)
{
p r i n t f ( ”%d ” , ∗ ( ( i n t ∗ ) ( l k −>d a t a ) ) ) ;
l k = l k −>n e x t ;
}
p r i n t f ( ” \n” ) ;
triFusion ( l , estInf );
lk = linkedListGetFirst( l ) ;
while ( l k !=NULL)
{
p r i n t f ( ”%d ” , ∗ ( ( i n t ∗ ) ( l k −>d a t a ) ) ) ;
l k = l k −>n e x t ;
}
p r i n t f ( ” \n” ) ;
linkedListDestroy ( l , destroyInt ) ;
return 0 ;
}
118
A.11 Tri par insertion
#include<s t d i o . h>
#include<s t d l i b . h>
#include<m a l l o c . h>
#include ” l i n k e d L i s t . h”
l i n k ∗ t r i I n s e r t i o n ( l i n k ∗ l i s t , i n t ( ∗ e s t I n f ) ( void ∗ , void ∗ ) )
{
i f ( l i s t == NULL)
return NULL;
return i n s e r t ( t r i I n s e r t i o n ( l i s t −>next , e s t I n f ) , l i s t , e s t I n f ) ;
}
i n t e s t I n f ( void∗ i , void∗ j )
{
return ( ∗ ( i n t ∗ ) i <= ∗ ( i n t ∗ ) j ) ? 1 : 0;
}
void d e s t r o y I n t ( void∗ i )
{
f r e e ( ( int ∗) i ) ;
}
i n t main ( )
{
int i = 1;
int∗ k ;
linkedList ∗ l = linkedListCreate ( ) ;
f o r ( i = 100 ; i > 0 ; i −−)
{
k = ( int ∗) malloc ( s i zeo f ( int ) ) ;
∗k = i ;
linkedListAppend ( l , k ) ;
}
void p r i n t I n t ( void∗ i )
{
p r i n t f ( ”%d ” , ∗ ( ( i n t ∗ ) i ) ) ;
}
linkedListApply ( l , p ri n tIn t ) ;
p r i n t f ( ” \n” ) ;
linkedListSort ( l , estInf ) ;
linkedListApply ( l , p ri n tIn t ) ;
p r i n t f ( ” \n” ) ;
linkedListDestroy ( l , destroyInt ) ;
return 0 ;
}
119
A.12 Transformée de Fourier
#include<s t d i o . h>
#include<s t d l i b . h>
#include<m a l l o c . h>
#include<math . h>
#include ” c o m p l e x e . h”
#include ” f o u r i e r . h”
#include ” l i n k e d L i s t . h”
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Retourne l e s r a c i n e s n−eme de c , O( n)
∗/
l i n k e d L i s t ∗ r a c i n e s C o m p l e x e ( c o m p l e x e c , unsigned long n )
{
linkedList ∗ l = linkedListCreate ( ) ;
pComplexe p ;
unsigned long i ;
f o r ( i = 0 ; i < n ; i ++)
{
p = ( pComplexe) m a l l o c ( s i z e o f ( c o m p l e x e ) ) ;
i f ( p == NULL)
exit (1);
∗p = makeExpComplexe( pow ( c . mod , 1 . / n ) , ( c . a r g /n ) + ( i ) ∗ 2 ∗ M PI/n ) ;
linkedListAppend ( l , p ) ;
}
return l ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Retourne l e s r a c i n e s n−eme de 1 , O( n)
∗/
l i n k e d L i s t ∗ u n i t e R a c i n e s C o m p l e x e ( unsigned long n )
{
return r a c i n e s C o m p l e x e ( makeAffComplexe ( 1 . 0 , 0 . 0 ) , n ) ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Donne l ’ image de x par polynome . Les c o e f f i c i e n t s du polynome s o n t
r a ng e s par o r d r e de d e g r e c r o i s s a n t . O( n ) .
∗/
c o m p l e x e h o r n e r ( l i n k ∗ polynome , c o m p l e x e x )
{
i f ( polynome == NULL)
return makeAffComplexe ( 0 . 0 , 0 . 0 ) ;
return addComplexe ( ∗ ( pComplexe ) polynome−>data ,
multComplexe ( x ,
h o r n e r ( polynome−>next ,
x)));
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
D e t r u i t complexe p o i n t e par p .
∗/
void d e a l l o c a t e C o m p l e x e ( void∗ p )
{
f r e e ( ( pComplexe) p ) ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Retourne l a t r a n s f o r m e e d i s c r e t e de Fo u r ie r du v e c t e u r l ,
v e r s i o n i t e r a t i v e en O( nˆ2)
∗/
l i n k e d L i s t ∗ t r a n s f o r m e e F o u r i e r I t ( l i n k e d L i s t ∗ polynome )
{
l i n k e d L i s t ∗ FT = l i n k e d L i s t C r e a t e ( ) ;
120
l i n k e d L i s t ∗ W n = u n i t e R a c i n e s C o m p l e x e ( l i n k e d L i s t G e t S i z e ( polynome ) ) ;
void∗ e v a l u a t e ( void∗ w)
{
pComplexe p = ( pComplexe ) m a l l o c ( s i z e o f ( c o m p l e x e ) ) ;
i f ( p == NULL)
exit (0);
∗p = h o r n e r ( l i n k e d L i s t G e t F i r s t ( polynome ) ,
∗ ( pComplexe )w ) ;
return p ;
}
FT = l i n k e d L i s t M a p ( W n , e v a l u a t e ) ;
l i n k e d L i s t D e s t r o y (W n , d e a l l o c a t e C o m p l e x e ) ;
return FT ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Ne f a i t rien . . .
∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Retourne l a t r a n s f o r m e e d i s c r e t e de Fo u r ie r du v e c t e u r l ,
v e r s i o n r e c u r s i v e en O( n . l o g n )
∗/
l i n k e d L i s t ∗ FFT( l i n k e d L i s t ∗ polynome )
{
// c r e a t i o n d e s l i s t e s
l i n k e d L i s t ∗ FT = l i n k e d L i s t C r e a t e ( ) ; // r e s u l t a t
l i n k e d L i s t ∗ odd = l i n k e d L i s t C r e a t e ( ) ; // c o e f f i c i e n t s d ’ i n d i c e p a i r
l i n k e d L i s t ∗ e v e n = l i n k e d L i s t C r e a t e ( ) ; // c o e f f i c i e n t s d ’ i n d i c e im p a ir
l i n k e d L i s t ∗ a 0 = l i n k e d L i s t C r e a t e ( ) ; // TF de odd
l i n k e d L i s t ∗ a 1 = l i n k e d L i s t C r e a t e ( ) ; // TF de even
l i n k ∗ l ; // pour p a r c o u r i r FT
c o m p l e x e w = makeAffComplexe ( 1 . 0 , 0 . 0 ) ;
c o m p l e x e c = makeExpComplexe ( 1 . 0 , 2∗ M PI/ l i n k e d L i s t G e t S i z e ( polynome ) ) ;
int isEven = 1 ;
// c a s de b a se
i f ( l i n k e d L i s t G e t S i z e ( polynome ) == 1 )
{
l i n k e d L i s t A p p e n d (FT,
copyComplexe ( ∗ ( pComplexe )
( l i n k e d L i s t G e t F i r s t ( polynome)−>d a t a ) ) ) ;
return FT ;
}
// a u t r e s c a s
void s p l i t ( void∗ c o e f f )
{
i f ( isEven )
l i n k e d L i s t A p p e n d ( even , c o e f f ) ;
else
l i n k e d L i s t A p p e n d ( odd , c o e f f ) ;
isEven = ! isEven ;
}
// s e p a r a t i o n de polynome
l i n k e d L i s t A p p l y ( polynome , s p l i t ) ;
// a p p e l s r e c u r s i f s
a 0 = FFT( e v e n ) ;
a 1 = FFT( odd ) ;
void e v e n V a l u e s ( void∗ v )
{
l i n k e d L i s t A p p e n d (FT, copyComplexe ( ∗ ( pComplexe ) v ) ) ;
}
// a j o u t dans FT d e s v a l e u r s de a ˆ [ 0 ]
linkedListApply ( a 0 , evenValues ) ;
linkedListApply ( a 0 , evenValues ) ;
l = l i n k e d L i s t G e t F i r s t (FT ) ;
void o d d V a l u e s ( void∗ v )
{
pComplexe f t = ( pComplexe ) ( l −>d a t a ) ;
∗ f t = addComplexe ( ∗ f t , multComplexe (w, ∗ ( pComplexe ) v ) ) ;
w = multComplexe ( c , w ) ;
l = l −>n e x t ;
}
121
// a j o u t dans FT d e s w nˆp ∗ a ˆ [ 1 ] p
l i n k e d L i s t A p p l y ( a 1 , oddValues ) ;
l i n k e d L i s t A p p l y ( a 1 , oddValues ) ;
// l i b e r a t i o n de l a memoire
l i n k e d L i s t D e s t r o y ( odd , doNothing ) ;
l i n k e d L i s t D e s t r o y ( even , doNothing ) ;
l i n k e d L i s t D e s t r o y ( a 0 , deallocateComplexe ) ;
l i n k e d L i s t D e s t r o y ( a 1 , deallocateComplexe ) ;
return FT ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Retourne l a t r a n s f o r m e e d i s c r e t e de Fo u r ie r du v e c t e u r l ,
v e r s i o n r e c u r s i v e en O( n . l o g n )
∗/
l i n k e d L i s t ∗ i n v e r se F F T ( l i n k e d L i s t ∗ polynome )
{
l i n k e d L i s t ∗ FT = l i n k e d L i s t C r e a t e ( ) ;
l i n k e d L i s t ∗ odd = l i n k e d L i s t C r e a t e ( ) ;
l i n k e d L i s t ∗ even = l i n k e d L i s t C r e a t e ( ) ;
linkedList ∗ a 0 = linkedListCreate ( ) ;
linkedList ∗ a 1 = linkedListCreate ( ) ;
link ∗ l ;
c o m p l e x e w = makeAffComplexe ( 1 . 0 , 0 . 0 ) ;
c o m p l e x e c = makeExpComplexe ( 1 . 0 , −2.∗M PI/ l i n k e d L i s t G e t S i z e ( polynome ) ) ;
int isEven = 1 ;
i f ( l i n k e d L i s t G e t S i z e ( polynome ) == 1 )
{
l i n k e d L i s t A p p e n d (FT,
copyComplexe ( ∗ ( pComplexe )
( l i n k e d L i s t G e t F i r s t ( polynome)−>d a t a ) ) ) ;
return FT ;
}
void s p l i t ( void∗ c o e f f )
{
i f ( isEven )
l i n k e d L i s t A p p e n d ( even , c o e f f ) ;
else
l i n k e d L i s t A p p e n d ( odd , c o e f f ) ;
isEven = ! isEven ;
}
l i n k e d L i s t A p p l y ( polynome , s p l i t ) ;
a 0 = i n v e r se F F T ( e v e n ) ;
a 1 = i n v e r se F F T ( odd ) ;
void e v e n V a l u e s ( void∗ v )
{
l i n k e d L i s t A p p e n d (FT, copyComplexe ( ∗ ( pComplexe ) v ) ) ;
}
linkedListApply ( a 0 , evenValues ) ;
linkedListApply ( a 0 , evenValues ) ;
l = l i n k e d L i s t G e t F i r s t (FT ) ;
void o d d V a l u e s ( void∗ v )
{
pComplexe f t = ( pComplexe ) ( l −>d a t a ) ;
c o m p l e x e v a l u e = multComplexe (w, ∗ ( pComplexe ) v ) ;
v a l u e = multReelComplexe ( 1 . / 2 . , addComplexe ( ∗ f t , v a l u e ) ) ;
∗ f t = value ;
w = multComplexe ( c , w ) ;
l = l −>n e x t ;
}
l i n k e d L i s t A p p l y ( a 1 , oddValues ) ;
l i n k e d L i s t A p p l y ( a 1 , oddValues ) ;
void doNothing ( void∗ w) { }
l i n k e d L i s t D e s t r o y ( odd , doNothing ) ;
l i n k e d L i s t D e s t r o y ( even , doNothing ) ;
void d e a l l o c a t e C o m p l e x e ( void∗ p )
{
f r e e ( ( pComplexe) p ) ;
}
l i n k e d L i s t D e s t r o y ( a 0 , deallocateComplexe ) ;
l i n k e d L i s t D e s t r o y ( a 1 , deallocateComplexe ) ;
return FT ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Retourne l a t r a n s f o r m e e d i s c r e t e de Fo u r ie r i n v e r s e
122
du v e c t e u r l , v e r s i o n i t e r a t i v e en O( nˆ2)
∗/
l i n k e d L i s t ∗ t r a n s f o r m e e I n v e r s e F o u r i e r I t ( l i n k e d L i s t ∗ polynome )
{
l i n k e d L i s t ∗ FT = l i n k e d L i s t C r e a t e ( ) ;
i n t n = l i n k e d L i s t G e t S i z e ( polynome ) ;
l i n k e d L i s t ∗ W n = uniteRacinesComplexe(n ) ;
void c o n j u g u e ( void∗ w)
{
∗ ( pComplexe)w = c o n j u g u e Co mpl exe ( ∗ ( pComplexe )w ) ;
}
l i n k e d L i st A p p l y (W n, conjugue ) ;
void∗ e v a l u a t e ( void∗ w)
{
pComplexe p = ( pComplexe ) m a l l o c ( s i z e o f ( c o m p l e x e ) ) ;
i f ( p == NULL)
exit (0);
∗p = h o r n e r ( l i n k e d L i s t G e t F i r s t ( polynome ) ,
∗ ( pComplexe )w ) ;
return p ;
}
FT = l i n k e d L i s t M a p ( W n , e v a l u a t e ) ;
void d i v i s e ( void∗ w)
{
∗ ( pComplexe)w = multReelComplexe ( 1 . / n , ∗ ( pComplexe )w ) ;
}
l i n k e d L i s t A p p l y (FT, d i v i s e ) ;
void d e a l l o c a t e C o m p l e x e ( void∗ p )
{
f r e e ( ( pComplexe) p ) ;
}
l i n k e d L i s t D e s t r o y (W n , d e a l l o c a t e C o m p l e x e ) ;
return FT ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
l i n k e d L i s t ∗ si m p l e Li st ( int n)
{
i f ( n == 0 )
return l i n k e d L i s t C r e a t e ( ) ;
linkedList ∗ l = simpleList (n − 1) ;
l i n k e d L i s t A p p e n d ( l , copyComplexe ( makeAffComplexe ( n , 0.0)));
return l ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
i n t main ( )
{
i n t k = 512;
v o i d p r int C ( v o i d ∗ v )
{
p r int AffC o m p l e x e ( ∗ ( ( pComplexe) v ) ) ;
p r i n t f (”\ n ” ) ;
}
p r i n t f (” l i s t e \n ” ) ;
linkedListApply ( simpleList (k ) ,
p r int C ) ;
p r i n t f (”FFT de l i s t e \n ” ) ;
l i n k e d L i s t A p p l y (FFT( s i m p l e L i s t ( k ) ) ,
p r int C ) ;
p r i n t f (”FFT−1 o FFT de l i s t e \n ” ) ;
l i n k e d L i s t A p p l y ( inverseFFT (FFT( s i m p l e L i s t ( k ) ) ) ,
p r int C ) ;
return 0;
}
∗/
123
A.13 Polynômes
#include<s t d i o . h>
#include<s t d l i b . h>
#include<m a l l o c . h>
#include<math . h>
#include ” polynomes . h”
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Retourne un polynome v i d e .
∗/
l i n k e d L i s t ∗ makePolynome ( )
{
return l i n k e d L i s t C r e a t e ( ) ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
A l l o u e dynamiquement un emplacement pour une v a r i a b l e de t y p e
double , y a f f e c t e d e t retourne c e t t e adresse .
∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
A l l o u e dynamiquement un emplacement pour une v a r i a b l e de t y p e
double , y a f f e c t e d e t retourne c e t t e adresse .
∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
D e s a l l o u e une v a r i a b l e de t y p e d o u b l e .
∗/
void d e s t r o y D o u b l e ( void∗ v )
{
f r e e ( ( double ∗ ) v ) ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Retourne une c o p i e de l , c o p i e a u s s i les coefficients .
∗/
l i n k e d L i s t ∗ copyPolynome ( l i n k e d L i s t ∗ l )
{
return l i n k e d L i s t M a p ( l , makeDoubleWithVoid ) ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
D e t r u i t l e polynome l e t s e s c o e f f i c i e n t s .
∗/
void d e st r o y P o l y n o m e ( l i n k e d L i s t ∗ l )
{
l i n k e d L i st D e st r o y ( l , destroyDouble ) ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
124
/∗
A f f i c h e l e monome c o e f f ∗ x ˆ d e g r e proprement , f i r s t P r i n t e d
e s t v r a i s i e t se u l e m e nt s i ce monome e s t l e p r e m ie r a f f i c h e
dans l e polynome .
∗/
i n t printMonome ( double c o e f f , i n t d e g r e , i n t f i r s t P r i n t e d )
{
i f ( c o e f f != 0 . 0 )
{
i f ( f i r s t P r i n t e d && c o e f f > 0 . 0 )
printf (” + ” );
i f ( c o e f f <0.0)
printf (” − ” );
p r i n t f ( ” %4.2 l f ” , ( c o e f f >0)? c o e f f :− c o e f f ) ;
i f ( degre > 0)
p r i n t f ( ”x” ) ;
i f ( degre > 1)
p r i n t f ( ”ˆ” ) ;
i f ( degre > 1)
p r i n t f ( ”%d” , d e g r e ) ;
return 1 ;
}
return 0 ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
A f f i c h e polynome l e p l u s proprement p o s s i b l e .
∗/
void p r i n t P o l y n o m e ( l i n k e d L i s t ∗ polynome )
{
int degre = 0 , f i r s t P r i n t e d = 0;
void f ( void∗ c o e f f )
{
i f ( printMonome ( ∗ ( double ∗ ) c o e f f , d e g r e , firstPrinted ))
firstPrinted = 1;
d e g r e ++;
}
l i n k e d L i s t A p p l y ( polynome , f ) ;
p r i n t f ( ” \n” ) ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Supprime l e s O non s i g n i f i c a t i f s à l a f i n du polynôme .
∗/
void s k i p Z e r o s P o l y n o m e ( l i n k e d L i s t ∗ l )
{
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Retourne l e d e g r e de l .
∗/
int degreePolynome( l i n k e d L i s t ∗ l )
{
int n ;
skipZerosPolynome( l ) ;
n = linkedListGetSize ( l );
i f ( n != 1 )
return n ;
return ( ∗ ( double ∗ ) l i n k e d L i s t G e t F i r s t ( l )−>d a t a != 0 ) − 1 ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Ajo u t e un monome de c o e f f i c i e n t c o e f f a l a f i n du polynome , faisant
a i n s i c r o u t r e son d e g r e de 1 .
∗/
125
double∗ p = m a l l o c ( s i z e o f ( double ) ) ;
i f ( p == NULL)
exit (0);
∗p = c o e f f ;
l i n k e d L i s t A p p e n d ( polynome , p ) ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Cree e t r e t o u r n e l e polynome de d e g r e n−1 dont l e s
c o e f f i c i e n t s s o n t p a s s e s dans l e t a b l e a u d .
∗/
l i n k e d L i s t ∗ makeArrayPolynome( double∗ d , i n t n )
{
l i n k e d L i s t ∗ l = makePolynome ( ) ;
int i ;
f o r ( i = 0 ; i < n ; i ++)
appendCoeffPolynome ( l , ∗ ( d + i ) ) ;
return l ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Retourne l e polynome nu l .
∗/
l i n k e d L i s t ∗ z e r o P o l y n o me ( )
{
l i n k e d L i s t ∗ l = makePolynome ( ) ;
appendCoeffPolynome ( l , 0 . 0 ) ;
return l ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Retourne l e polynome u n i t e .
∗/
l i n k e d L i s t ∗ u n i t P o l y n o me ( )
{
l i n k e d L i s t ∗ l = makePolynome ( ) ;
appendCoeffPolynome ( l , 1 . 0 ) ;
return l ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Retourne l e polynome
0 + X + 2Xˆ2 + 3Xˆ3 + . . . + iXˆ i + . . . + nXˆn
∗/
l i n k e d L i s t ∗ simpleListPolynome ( int n)
{
linkedList ∗ l ;
i f ( n == 0 )
return z e r o P o l y n o m e ( ) ;
l = simpleListPolynome ( n − 1 ) ;
appendCoeffPolynome ( l , n ) ;
return l ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Ajo u t e l a c o n s t a n t e d au polynome l .
∗/
126
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Multiplie l e polynome l par l e reel d .
∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Multiplie l e polynome l par Xˆn
∗/
void multXNPolynome ( l i n k e d L i s t ∗ l , i n t n )
{
i f (n > 0)
{
l i n k e d L i s t P u s h ( l , makeDouble ( 0 . 0 ) ) ;
multXNPolynome ( l , n − 1 ) ;
}
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Multiplie l e polynome l par c o e f f ∗Xˆ exp
∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Ad d it io nne deux à deux t o u s l e s m a i l l o n s d e s deux l i s t e s la
e t l b . Concatene l e r e s u l t a t a l a l i s t e r e s u l t .
∗/
void a d d M a i l l o n s ( l i n k ∗ l a , l i n k ∗ l b , l i n k e d L i s t ∗ r e s u l t )
{
i f ( l a != NULL && l b != NULL)
{
appendCoeffPolynome ( r e s u l t , ∗ ( double ∗ ) l a −>d a t a
+ ∗ ( double ∗ ) l b −>d a t a ) ;
a d d M a i l l o n s ( l a −>next , l b −>next , r e s u l t ) ;
}
else
{
i f ( l a != NULL)
{
appendCoeffPolynome ( r e s u l t , ∗ ( double ∗ ) l a −>d a t a ) ;
a d d M a i l l o n s ( l a −>next , NULL, r e s u l t ) ;
}
i f ( l b != NULL)
{
appendCoeffPolynome ( r e s u l t , ∗ ( double ∗ ) l b−>d a t a ) ;
a d d M a i l l o n s (NULL, l b −>next , r e s u l t ) ;
}
}
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
A d d i t i o n e l e s deux polynomes a e t b , r e t o u r n e c e t t e somme.
∗/
l i n k e d L i s t ∗ addPolynome ( l i n k e d L i s t ∗ a , linkedList ∗ b)
{
l i n k e d L i s t ∗ r e s u l t = makePolynome ( ) ;
127
addMaillons ( l i n k e d L i s t G e t F i r s t ( a ) ,
linke dListGetFirst(b) ,
result );
return r e s u l t ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
M u l t i p l i e a e t b avec l a recurrence
( a 0 + a 1X + . . . + a nXˆn)Q(X)
= a 0 ∗ Q(X) + X ∗ ( a 1 + a 2 X. . . + a n Xˆ(n−1)) ∗ Q(X)
∗/
l i n k e d L i s t ∗ slowMultPolynome ( l i n k e d L i s t ∗ a , l i n k e d L i s t ∗ b )
{
l i n k e d L i s t ∗ temp1 = NULL;
l i n k e d L i s t ∗ r e s = zeroPolynome ( ) ;
int n = 0;
void a u x F u n c t i o n ( void∗ v )
{
l i n k e d L i s t ∗ temp2 = copyPolynome ( b ) ;
multMonomePolynome ( temp2 , ∗ ( double ∗ ) v , n ) ;
temp1 = addPolynome ( r e s , temp2 ) ;
d e st r o y P o l y n o m e ( r e s ) ;
d e st r o y P o l y n o m e ( temp2 ) ;
r e s = temp1 ;
n++;
}
l i n k e d L i s t A p p l y ( a , auxFunction ) ;
return r e s ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Fo nc t io n a u x i l i a i r e pour l e sous−programme c i −d e s s o u s .
∗/
void m u l t M a i l l o n s ( l i n k ∗ l a , l i n k ∗ l b , l i n k e d L i s t ∗ r e s u l t )
{
pComplexe p ;
i f ( l a != NULL)
{
p = copyComplexe (
multComplexe (
∗ ( pComplexe ) l a −>data ,
∗ ( pComplexe ) l b−>d a t a ) ) ;
linkedListAppend ( r e su l t , p ) ;
m u l t M a i l l o n s ( l a −>next , l b−>next , r e s u l t ) ;
}
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
M u l t i p l i e e n t r e eux t o u s l e s c o e f f i c i e n t s ( c o m p l e x e s ) d e s monomes de
meme d e g r e , par exemple :
(1 + 2X + 4Xˆ2) e t (3 + X − 2Xˆ2) donnent
(1 ∗ 3) + (2 ∗ 1)X + (4 ∗ −2)Xˆ2
a e t b s o n t n e c e s s a i r e m e n t de meme d e g r e .
∗/
l i n k e d L i s t ∗ multMonomesPolynome ( l i n k e d L i s t ∗ a , linkedList ∗ b)
{
l i n k e d L i s t ∗ l = makePolynome ( ) ;
multMaillons ( l i n k e d L i s t G e t F i r st ( a ) ,
linke dListGetFirst(b) ,
l );
return l ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
C o n v e r t i t un d o u b l e en p o i n t e u r su r complexe .
∗/
128
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
C o n v e r t i t un complexe en d o u b l e , supprime
l a p a r t i e imaginaire .
∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
D e t r u i t un nombre complexe .
∗/
void d e st r o y Co m p l e x e ( void∗ v )
{
f r e e ( ( pComplexe) v ) ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Retourne l a p r e m ie r p u i s a n c e de 2 s u p e r i e u r e ou e g a l a x .
∗/
i n t puiss2UpperThan ( i n t x )
{
int k = 2;
while ( k < x )
k ∗= 2 ;
return k ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Ajo u t e d e s z e r o s non s i g n i f i c a t i f s a l a f i n de l de s o r t e
que sa t a i l l e d e v ie nne k .
∗/
void r e s i z e L i s t ( l i n k e d L i s t ∗ l , i n t k )
{
while ( l i n k e d L i s t G e t S i z e ( l ) < k )
linkedListAppend ( l ,
copyComplexe ( makeAffComplexe ( 0 . 0 , 0.0)));
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
M o d ifie l e s t a i l l e s d e s deux l i s t e s de s o r t e
qu ’ on p u i s s e l e u r a p p l i q u e r une FFT
∗/
void c a l i b r a t e L i s t s ( l i n k e d L i s t ∗ l 1 , l i n k e d L i s t ∗ l 2 )
{
int k ;
int length = l i n k e d Li st Ge t S i z e ( l 1 ) +
linkedListGetSize ( l2 ) − 1;
k = puiss2UpperThan ( l e n g t h ) ;
r e s i z e L i s t ( l1 , k ) ;
r e s i z e L i s t ( l2 , k ) ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
M u l t i p l e a e t b en p a s s a n t par une t r a n s f o r m e e de f o u r i e r .
∗/
l i n k e d L i s t ∗ multPolynome ( l i n k e d L i s t ∗ a , l i n k e d L i s t ∗ b )
{
l i n k e d L i s t ∗ ca , ∗ cb , ∗ f f t a , ∗ f f t b , ∗ prodab , ∗ resComplexe , ∗ r e s ;
c a = l i n k e d L i s t M a p ( a , complexOfDouble ) ;
cb = l i n k e d L i s t M a p ( a , complexOfDouble ) ;
129
c a l i b r a t e L i s t s ( ca , cb ) ;
f f t a = FFT( c a ) ;
f f t b = FFT( cb ) ;
prodab = multMonomesPolynome ( f f t a , f f t b ) ;
r e sCo m p l e x e = i n v e r se F F T ( prodab ) ;
r e s = l i n k e d L i s t M a p ( resComplexe , doubleOfComplexe ) ;
l i n k e d L i s t D e s t r o y ( ca , d e st r o y Co m p l e x e ) ;
l i n k e d L i s t D e s t r o y ( cb , d e st r o y Co m p l e x e ) ;
l i n k e d L i s t D e s t r o y ( f f t a , d e st r o y Co m p l e x e ) ;
l i n k e d L i s t D e s t r o y ( f f t b , d e st r o y Co m p l e x e ) ;
l i n k e d L i s t D e s t r o y ( prodab , d e st r o y Co m p l e x e ) ;
l i n k e d L i s t D e s t r o y ( resComplexe , d e st r o y Co m p l e x e ) ;
return r e s ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
E v a l u e l e polynome l en x a v e c l a methode de Horner .
∗/
double h o r n e r L i n k ( l i n k ∗ l n k , double x )
{
i f ( l n k == NULL)
return 0 . 0 ;
return ∗ ( double ∗ ) l n k−>d a t a +
x∗ h o r n e r L i n k ( l n k−>next , x ) ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
E v a l u e l e polynome l en x a v e c l a methode de Horner .
∗/
double e v a l u a t e P o l y n o m e ( l i n k e d L i s t ∗ l , double x )
{
return h o r n e r L i n k ( l i n k e d L i s t G e t F i r s t ( l ) , x ) ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
i n t main ( )
{
l i n k e d L i s t ∗ l = simpleListPolynome ( 1 0 0 0 0 ) ;
// makeArrayPolynome ( d , 5 ) ;
l i n k e d L i s t ∗m, ∗n , ∗p ;
p r i n t f ( ” m u l t i p l i c a t i o n \n” ) ;
m = slowMultPolynome ( l , l ) ;
p r i n t f ( ” done\n” ) ;
// printPolynome (m) ;
p r i n t f ( ” m u l t i p l i c a t i o n \n” ) ;
n = multPolynome ( l , l ) ;
p r i n t f ( ” done\n” ) ;
// printPolynome (m) ;
multRealPolynome ( n , −1);
p = addPolynome (m, n ) ;
p r i n t f ( ” t e s t : % l f \n” , e v a l u a t e P o l y n o m e ( p , 1.0));
d e st r o y P o l y n o m e ( l ) ;
d e st r o y P o l y n o m e (m ) ;
d e st r o y P o l y n o m e ( n ) ;
return 0 ;
}
130
A.14 Tas binomiaux
Voici une implémentation des tas binomiaux, j’ai commencé par écrire quelques fonctions de gestion de listes chaı̂nées,
et j’ai crée deux classes pour représenter respectivement les arbres binomiaux et les tas binomiaux.
/∗ ∗
Implements a v e r y s i m p l e l i n k e d l i s t , each l i n k p o i n t s t o item
o f t y p e T and r e f e r e n c e s t h e n e x t l i n k . O( 1 ) o p e r a t i o n s a r e
g e t t i n g t h e f i r s t l i n k ’ s d a t a or t h e second ’ s l i n k r e f e r e n c e ,
or d e l e t i n g t h e f i r s t e l e m e nt . Each f u n c t i o n s m o d ifying t h e
l i n k i n g returns a pointer to the f i r s t l i n k of the l i s t .
∗/
public c l a s s L i n k e d L i s t <T>
{
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗/
p r i v a te T d a t a ;
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗/
p r i v a te L i n k e d L i s t <T> n e x t ;
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗/
/∗ ∗
C r e a t e s a one e l e m e nt list .
∗/
public L i n k e d L i s t (T d a t a )
{
this . data = data ;
}
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗/
/∗ ∗
C r e a t e s a one l i n k l i s t and appends t h e second
paramter t o t h i s l i s t .
∗/
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗/
/∗ ∗
Modifies the data .
∗/
public void s e t D a t a (T d a t a )
{
this . data = data ;
}
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗/
/∗ ∗
Appends a l i s t to the first l i n k of the current
list .
∗/
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗/
/∗ ∗
R e t r iv e s the data o f the first link .
∗/
public T g e t D a t a ( )
{
return d a t a ;
}
131
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗/
/∗ ∗
Returns t h e second item o f t h e l i s t , doesn ’ t change
the l i n k i n g
∗/
public L i n k e d L i s t <T> g e t N e x t ( )
{
return n e x t ;
}
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗/
/∗ ∗
D e l e t e from t h i s l i s t t h e l i n k which t h e a d r e s s i s l ,
returns the l i s t whithout l .
∗/
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗/
/∗ ∗
Returns a S t r i n g r e p r e s e n t a t i o n of the list .
∗/
public S t r i n g t o S t r i n g ( )
{
return ” −> ” + d a t a +
( ( n e x t != n u l l ) ? n e x t . t o S t r i n g ( ) : ”X” ) ;
}
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗/
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗/
/∗ ∗
Adds t h e l i n k l i n f r o n t o f t h i s l i s t , returns
the l i s t thus created .
∗/
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗/
/∗ ∗
Adds t h e item o i n f r o n t o f t h i s l i s t , returns
t h e new l i s t .
∗/
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗/
/∗ ∗
R e v e r se t h e o r d e r o f t h e it e m s o f t h e l i s t . Returns t h e
132
new l i s t .
∗/
public L i n k e d L i s t <T> r e v e r s e ( )
{
return r e v e r s e A c c ( th i s , n u l l ) ;
}
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗/
p r i v a te i n t o r d e r ;
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗/
p r i v a te T d a t a ;
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗/
p r i v a te L i n k e d L i s t <Bi n o m i a l Tr e e<T>> s o n s ;
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗/
public Bi n o m i a l Tr e e (T d a t a )
{
this . data = data ;
order = 0;
sons = null ;
}
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗/
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗/
public i n t g e t O r d e r ( )
{
return o r d e r ;
}
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗/
public T g e t D a t a ( )
{
return d a t a ;
}
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗/
public BinomialHeap<T> e x t r a c t S o n s ( )
{
return new BinomialHeap<T>(( s o n s == n u l l ) ?
null :
sons . r e v e r s e ( )
);
}
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗/
133
return 0 ;
return 1 ;
}
}
/∗ ∗
Implements a p r i o r i t y queue which a l l o w s t h e f o l l o w i n g o p e r a t i o n s ,
each one i n a i n O( l o g n ) time .
− i n s e r t i n g an item
− g e t t i n g t h e minimum k e y item
− d e l e t i n g t h e minimum k e y item
− merging two q u e u e s
I t has been implemented by a l e x a n d r e−m e sl e . com f o r j a v a 1 . 5
∗/
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗/
p r i v a te L i n k e d L i s t <Bi n o m i a l Tr e e<T>> b i n o m i a l T r e e s ;
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗/
/∗ ∗
C r e a t e s an empty queue .
∗/
public BinomialHeap ( )
{
binomialTrees = null ;
}
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗/
/∗ ∗
C r e a t e s a one item queue .
∗/
public BinomialHeap (T d a t a )
{
b i n o m i a l T r e e s = new L i n k e d L i s t <Bi n o m i a l Tr e e <T>>
(new Bi n o m i a l Tr e e <T>( d a t a ) ) ;
}
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗/
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗/
/∗ ∗
Returns t r u s i f and o n l y i f t h e queue doesn ’ t c o n t a i n
any item .
∗/
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗/
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗/
134
/∗ ∗
Returns t h e item wich has t h e minimum k e y .
∗/
public T getMin ( )
{
L i n k e d L i s t <Bi n o m i a l Tr e e<T>> minNode = f i n d M i n L i n k ( b i n o m i a l T r e e s ,
binomialTrees ) ;
i f ( minNode == n u l l )
return n u l l ;
return minNode . g e t D a t a ( ) . g e t D a t a ( ) ;
}
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗/
/∗ ∗
D e l e t e s t h e minimum k e y item .
∗/
public void d e l e t e M i n ( )
{
L i n k e d L i s t <Bi n o m i a l Tr e e<T>> minLink =
findMinLink ( binomialTrees , b i n o m i a l Tr e es ) ;
b i n o m i a l T r e e s = b i n o m i a l T r e e s . d e l e t e L i n k ( minLink ) ;
BinomialHeap<T> s o n s = minLink . g e t D a t a ( ) . e x t r a c t S o n s ( ) ;
f u si o n ( sons ) ;
}
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗/
/∗ ∗
D e l e t e s t h e minimum k e y item .
∗/
public void i n s e r t (T c )
{
f u s i o n (new BinomialHeap<T>(c ) ) ;
}
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗/
/∗ ∗
Adds t o t h e c u r r e n t queue a l l t h e item o f t h e queue b .
Use i t o n l y i f b doesn ’ t have t o used a g a in .
∗/
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗/
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗/
135
Bi n o m i a l Tr e e<K> f i r s t = l . g e t D a t a ( ) ;
Bi n o m i a l Tr e e<K> s e c o n d = l . g e t N e x t ( ) . g e t D a t a ( ) ;
i f ( f i r s t . g e t O r d e r ( ) != s e c o n d . g e t O r d e r ( ) )
{
l . setNext ( c l e a n ( l . getNext ( ) ) ) ;
return l ;
}
i f ( l . g e t N e x t ( ) . g e t N e x t ( ) == n u l l )
return new L i n k e d L i s t <Bi n o m i a l Tr e e<K>>
( f i r s t . f u si o n ( second ) ,
l . getNext ( ) . getNext ( ) ) ;
Bi n o m i a l Tr e e<K> t h i r d = l . g e t N e x t ( ) . g e t N e x t ( ) . g e t D a t a ( ) ;
i f ( f i r s t . g e t O r d e r ( ) == t h i r d . g e t O r d e r ( ) )
{
l . setNext ( c l e a n ( l . getNext ( ) ) ) ;
return l ;
}
else
return new L i n k e d L i s t <Bi n o m i a l Tr e e<K>>
( f i r s t . f u si o n ( second ) ,
l . getNext ( ) . getNext ( ) ) ;
}
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗/
/∗
p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s )
{
BinomialHeap<I n t e g e r > h = new BinomialHeap<I n t e g e r > ();
f o r ( i n t i = 1 ; i < 3000 ; i ++)
h . i n s e r t (new I n t e g e r ( ( i ∗ i ∗ i ∗ i ∗ i ∗ i ∗ i ) % 1 2 7 ) ) ;
w h i l e ( ! h . isEmpty ( ) )
{
System . o u t . p r i n t ( h . getMin ( ) + ” −> ” ) ;
h . deleteMin ( ) ;
}
}
∗/
136
A.15 AVL
#include<s t d i o . h>
#include<m a l l o c . h>
#include ” a v l . h”
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Noeud de l ’ABR.
∗/
typedef s tr u ct nd
{
/∗
k e y e s t l a c l e du noeud c o u r a nt .
∗/
i n t key ;
/∗
p o i n t e u r v e r s l ’ e l e m e nt de c l e k e y
∗/
void∗ d a t a ;
/∗
h a u t e u r du sous−a r b r e :
0 s i ce noeud e s t une f e u i l l e .
∗/
int height ;
/∗
P o int e u r v e r s l e sous−a r b r e d r o i t .
∗/
s tr u ct nd ∗ l e f t ;
/∗
P o int e u r v e r s l e sous−a r b r e gauche .
∗/
s tr u ct nd ∗ r i g h t ;
} node ;
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Retourne l a h a u t e u r de l ’ a r b r e de r a c i n e l ,
−1 s i l e s t v i d e .
∗/
i n t g e t H e i g h t ( node ∗ l )
{
i f ( l == NULL)
return −1;
return l −>h e i g h t ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Retourne l a p l u s grande d e s deux v a l e u r s i et j .
∗/
i n t max ( i n t i , i n t j )
{
if ( i < j )
return j ;
return i ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Met a j o u r l a h a u t e u r de l a r a c i n e l en f o n c t i o n d e s
h a u t e u r s d e s r a c i n e s d e s deux sous−a r b r e s .
∗/
void s e t H e i g h t ( node∗ l )
{
i f ( l != NULL)
{
l −>h e i g h t = 1 + max( g e t H e i g h t ( l −> l e f t ) , g e t H e i g h t ( l −>r i g h t ) ) ;
}
137
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Cree un noeud c o nt e na nt l a donnee data ,
a ya nt pour sous−a r b r e gauche l e t
pour sous−a r b r e d r o i t r .
∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Retourne un a v l v i d e
∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
F a i t de f r e e D a t a l a f o n c t i o n de d e s t r u c t i o n d e s donnees .
∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Affiche toutes l e s c l e s du sous−a r b r e de r a c i n e n dans
l ’ ordre c r o i s s a n t .
∗/
void n o d e P r i n t K e y s ( node ∗ n )
{
i f (n)
{
printf (”(” );
n o d e P r i n t K e y s ( n−> l e f t ) ;
p r i n t f ( ” , %d , ” , n−>key ) ;
n o d e P r i n t K e y s ( n−>r i g h t ) ;
printf (”)” );
}
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
A f f i c h e pour t o u s l e s noeuds du sous−a r b r e de r a c i n e n
l a d i f f e r e n c e e n t r e l e s h a u t e u r s du sous−a r b r e d r o i t e t
gauche .
∗/
void n o d e P r i n t L e v e l s ( node∗ n )
{
i f (n)
138
{
printf (”(” );
n o d e P r i n t L e v e l s ( n−> l e f t ) ;
p r i n t f ( ” , %d , ” , g e t H e i g h t ( n−> l e f t )− g e t H e i g h t ( n−>r i g h t ) ) ;
n o d e P r i n t L e v e l s ( n−>r i g h t ) ;
printf (”)” );
}
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
E f f e c t u e une r o t a t i o n d r o i t e de l ’ a r b r e de r a c i n e x ,
r e t o u r n e l a r a c i n e de l ’ a r b r e a p r e s r o t a t i o n .
∗/
node∗ r o t a t e R i g h t ( node ∗ x )
{
node∗ y = x−> l e f t ;
node∗ b = y−>r i g h t ;
y−>r i g h t = x ;
x−> l e f t = b ;
setHeight (x ) ;
setHeight (y ) ;
return y ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
E f f e c t u e une r o t a t i o n gauche de l ’ a r b r e de r a c i n e x ,
r e t o u r n e l a r a c i n e de l ’ a r b r e a p r e s r o t a t i o n .
∗/
node∗ r o t a t e L e f t ( node ∗ x )
{
node∗ y = x−>r i g h t ;
node∗ b = y−> l e f t ;
y−> l e f t = x ;
x−>r i g h t = b ;
setHeight (x ) ;
setHeight (y ) ;
return y ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
E f f e c t u e une r o t a t i o n gauche−d r o i t e de l ’ a r b r e de r a c i n e x ,
r e t o u r n e l a r a c i n e de l ’ a r b r e a p r e s r o t a t i o n .
∗/
node∗ r o t a t e L e f t R i g h t ( node ∗ x )
{
x−> l e f t = r o t a t e L e f t ( x−> l e f t ) ;
return r o t a t e R i g h t ( x ) ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
E f f e c t u e une r o t a t i o n d r o i t e −gauche de l ’ a r b r e de r a c i n e x ,
r e t o u r n e l a r a c i n e de l ’ a r b r e a p r e s r o t a t i o n .
∗/
node∗ r o t a t e R i g h t L e f t ( node ∗ x )
{
x−>r i g h t = r o t a t e R i g h t ( x−>r i g h t ) ;
return r o t a t e L e f t ( x ) ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
R e e q u i l i b r e l ’ a r b r e de r a c i n e x , r e t o u r n e l a r a c i n e de
l ’ a r b r e a p r e s r e e q u i l i b r a g e . On p a r t du p r i n c i p e
que l e s h a u t e u r s d e s sous−a r b r e s d r o i t e t gauche d i f f e r e n t
de au p l u s 1 .
∗/
node∗ b a l a n c e ( node∗ x )
139
{
if ( x != NULL)
{
setHeight (x ) ;
i f ( g e t H e i g h t ( x−> l e f t ) + 2 == g e t H e i g h t ( x−>r i g h t ) )
{
i f ( g e t H e i g h t ( x−> l e f t ) + 1 == g e t H e i g h t ( x−>r i g h t −>r i g h t ) )
return r o t a t e L e f t ( x ) ;
else
return r o t a t e R i g h t L e f t ( x ) ;
}
i f ( g e t H e i g h t ( x−> l e f t ) == g e t H e i g h t ( x−>r i g h t ) + 2 )
{
i f ( g e t H e i g h t ( x−>l e f t −> l e f t ) == g e t H e i g h t ( x−>r i g h t ) + 1 )
return r o t a t e R i g h t ( x ) ;
else
return r o t a t e L e f t R i g h t ( x ) ;
}
}
return x ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
I n s e r e l a donnee v dans l ’ a r b r e de r a c i n e n
e t r e e q u i l i b r e l ’ a r b r e , r e t o u r n e l a r a c i n e de
l ’ arbre apres inse rtion et re e q u i l i b r a g e .
∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
I n s e r e l a donnee v dans l ’ a r b r e a , O( l o g n ) .
∗/
void a v l I n s e r t ( a v l ∗ a , void∗ v )
{
a−>r o o t = n o d e I n s e r t ( a−>getKey , ( node ∗ ) a−>r o o t , v ) ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Affiche les c l e s de l ’AVL a dans l ’ o r d r e c r o i s s a n t , O(n )
∗/
void a v l P r i n t K e y s ( a v l ∗ a )
{
n o d e P r i n t K e y s ( ( node ∗ ) a−>r o o t ) ;
p r i n t f ( ” \n” ) ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
A f f i c h e pour chaque noeud l a d i f f e r e n c e e n t r e l e s hauteurs
d e s sous−a r b r e s d r o i t e t gauche de l ’AVL.
∗/
void a v l P r i n t L e v e l s ( a v l ∗ a )
{
n o d e P r i n t L e v e l s ( ( node ∗ ) a−>r o o t ) ;
p r i n t f ( ” \n” ) ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
140
/∗
Retourne l a donnee de c l e k s i elle s e t r o u v e dans l e sous−a r b r e
de r a c i n e n , NULL sino n .
∗/
void∗ f i n d N o d e ( node∗ n , i n t k )
{
i f ( n == NULL)
return NULL;
i f ( n−>key == k )
return n−>d a t a ;
i f ( k < n−>key )
return f i n d N o d e ( n−>l e f t , k ) ;
else
return f i n d N o d e ( n−>r i g h t , k ) ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Retourne l a donnee de c l e x s i elle s e t r o u v e dans l ’AVL a ,
NULL sinon , O( l o g n)
∗/
void∗ a v l F i n d ( a v l ∗ a , i n t x )
{
return f i n d N o d e ( ( node ∗ ) a−>r o o t , x ) ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
F a i t p o i n t e r ∗max v e r s l e noeud de c l e maximale dans
l e sous−a r b r e de r a c i n e n , d e t a c h e l e noeud ∗max de l ’ a r b r e
e t r e t o u r n e l a r a c i n e de l ’ a r b r e a p r e s s u p p r e s s i o n .
∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
F a i t p o i n t e r ∗min v e r s l e noeud de c l e minimale dans
l e sous−a r b r e de r a c i n e n , d e t a c h e l e noeud ∗min de l ’ a r b r e
e t r e t o u r n e l a r a c i n e de l ’ a r b r e a p r e s s u p p r e s s i o n .
∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Supprime l e noeud de c l e k du sous−a r b r e de r a c i n e n ,
141
a p p l i q u e l a f o n c t i o n de d e s t r u c t i o n a l a donnee de ce noeud ,
e t r e t o u r n e l a r a c i n e de l ’ a r b r e a p r e s l a s u p p r e s s i o n .
∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Supprime l e noeud de c l e k de l ’AVL a , a p p l i q u e l a f o n c t i o n
de d e s t r u c t i o n a l a donnee de c l e k , O( l o g n ) .
∗/
void avlRemove ( a v l ∗ a , i n t k )
{
a−>r o o t = removeNode ( ( node ∗ ) a−>r o o t , k , a−>f r e e D a t a ) ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
P l a c e dans l a l i s t e c h a i n e e l t o u t e s l e s donnees
du sous−a r b r e de r a c i n e n dans l ’ o r d r e c r o i s s a n t .
∗/
void n o d e To L i st ( node∗ n , l i n k e d L i s t ∗ l )
{
i f ( n != NULL)
{
n o d e To L i st ( n−>l e f t , l ) ;
l i n k e d L i s t A p p e n d ( l , n−>d a t a ) ;
n o d e To L i st ( n−>r i g h t , l ) ;
}
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Retourne une l i s t e c h a i n e e c o nt e na nt t o u t e s l e s donnees
de l ’AVL a d i s p o s e e s dans l ’ o r d r e c r o i s s a n t , O(n ) .
∗/
l i nk e dL i s t ∗ avlToList ( avl ∗ a )
{
linkedList ∗ l = linkedListCreate ( ) ;
n o d e To L i st ( ( node ∗ ) a−>r o o t , l ) ;
return l ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
D e t r u i t t o u s l e s noeuds du sous−a r b r e de r a c i n e n ,
a p p l i q u e l a f o n c t i o n de d e s t r u c t i o n f r a t o u t e s l e s
donnees du sous−a r b r e .
∗/
142
void n o d e D e st r o y ( node∗ n , void ( ∗ f r ) ( void ∗ ) )
{
i f ( n != NULL)
{
n o d e D e st r o y ( n−>l e f t , f r ) ;
n o d e D e st r o y ( n−>r i g h t , f r ) ;
f r ( n−>d a t a ) ;
free (n ) ;
}
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
D e t r u i t l ’AVL a , a p p l i q u e l a f o n c t i o n de d e s t r u c t i o n a
t o u t e s l e s donnees du sous−a r b r e , O(n ) .
∗/
void a v l D e s t r o y ( a v l ∗ a )
{
n o d e D e st r o y ( ( node ∗ ) a−>r o o t , a−>f r e e D a t a ) ;
free (a );
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Pour t e s t e r les algorithmes
∗/
void d e s t r o y I n t ( void∗ i )
{
f r e e ( ( int ∗) i ) ;
}
i n t g e t I n t K e y ( void∗ i )
{
return ∗ ( ( i n t ∗ ) i ) ;
}
void doNothing ( )
{
i n t main ( )
{
int i ;
int∗ d ;
linkedList ∗ l ;
l i n k ∗ m;
a v l ∗ a = a v l Cr e a t e ( getIntKey , d e s t r o y I n t ) ;
f o r ( i = 0 ; i < 40 ; i ++)
{
d = ( int ∗) malloc ( s i zeo f ( int ) ) ;
∗d = i ;
avlInsert (a , d ) ;
}
avlPrintKeys ( a ) ;
avlPrintLevels (a );
f o r ( i = 0 ; i < 40 ; i +=5)
avlRemove ( a , i ) ;
avlPrintKeys ( a ) ;
avlPrintLevels (a );
l = avlToList ( a ) ;
f o r (m = l i n k e d L i s t G e t F i r s t ( l ) ; m != NULL ; m = m−>n e x t )
p r i n t f ( ”%d −> ” , ∗ ( i n t ∗ ) (m−>d a t a ) ) ;
p r i n t f ( ” \n” ) ;
l i n k e d L i s t D e s t r o y ( l , doNothing ) ;
avlSetFreeFunction( a , de stroyInt ) ;
avlDestroy (a ) ;
return 0 ;
}
143
A.16 Knapsack par recherche exhaustive
#include ” l i n k e d L i s t . h”
#include<s t d i o . h>
#include<s t d l i b . h>
#include<m a l l o c . h>
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
I n s t a n c e d ’ un p r o b l e m e de knapSack
∗/
typedef s tr u ct
{
/∗
nombre t o t a l d ’ o b j e t s
∗/
long n b I t e m s ;
/∗
t a b l e a u de nombreObjets e l e m e n t s c o nt e na nt l e p o i d s de
chaque e l e m e nt
∗/
long ∗ w e i g h t s ;
/∗
t a b l e a u de nombreObjets e l e m e n t s c o nt e na nt l a v a l e u r de
chaque e l e m e nt
∗/
long ∗ v a l u e s ;
/∗
Poids maximum qu ’ i l est p o s s i b l e de p l a c e r dans l e sa c à dos .
∗/
long maxWeight ;
} knapSack ;
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
144
void i n c r V a l u e ( void∗ i )
{
r e s += ∗ ( i n s t a n c e −>w e i g h t s + ∗ ( ( long ∗ ) i ) ) ;
}
linkedListApply ( solution , incrValue ) ;
return r e s ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
i n t k n a p S a c k I s F e a s i b l e ( knapSack∗ i n s t a n c e , l i n k e d L i s t ∗ s o l u t i o n )
{
return knapSackWeight ( i n s t a n c e , s o l u t i o n )
<= i n s t a n c e −>maxWeight ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
void k n a p S a c k P r i n t I n s t a n c e ( knapSack∗ k )
{
long l = 0 ;
while ( l < k−>n b I t e m s )
{
p r i n t f ( ” ( i = %3l d , v = %3l d , w = %3 l d ) \ n” , l ,
∗ ( k−>v a l u e s + l ) , ∗ ( k−>w e i g h t s + l ) ) ;
l ++;
}
p r i n t f ( ”max w e i g h t = %l d \n” , k−>maxWeight ) ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
void k n a p S a c k D e st r o y ( knapSack∗ k )
{
f r e e ( k−>v a l u e s ) ;
f r e e ( k−>w e i g h t s ) ;
free (k );
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
void∗ l i n k e d L i s t C o p y ( void∗ l )
{
void∗ i d ( void∗ i )
{
return i ;
}
return l i n k e d L i s t M a p ( ( l i n k e d L i s t ∗ ) l , id ) ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
void k n a p S a c k P r i n t S o l u t i o n ( l i n k e d L i s t ∗ l )
{
void p r i n t I n d e x ( void∗ i )
{
p r i n t f ( ”%l d ” , ∗ ( ( long ∗ ) i ) ) ;
}
linkedListApply ( l , printIndex ) ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
l i n k e d L i s t ∗ k n a p S a c k L i s t I n i t ( long n )
{
linkedList ∗ l ;
i f ( n <= 0 )
l = linkedListCreate ( ) ;
else
{
l = knapSackListInit (n − 1);
long ∗ p = m a l l o c ( s i z e o f ( long ) ) ;
i f ( p == NULL)
exit (0);
∗p = n −1;
linkedListAppend ( l , p ) ;
}
return l ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
145
void k n a p S a c k P r i n t P a r t i e s ( l i n k e d L i s t ∗ l )
{
void k n a p S a c k P r i n t V o i d S o l u t i o n ( void∗ l )
{
printf (” [ ” );
k n a p S a c k P r in tSo lu ti on ( ( l i n k e d L i s t ∗) l ) ;
p r i n t f ( ” ] \ n” ) ;
}
linkedListApply ( l , knapSackPrintVoidSolution ) ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
void d e s t r o y I n t ( void∗ v )
{
f r e e ( ( int ∗) v ) ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
void k n a p S a c k D e s t r o y P a r t i e s ( l i n k e d L i s t ∗ l )
{
void d e s t r o y P a r t i e ( void∗ p )
{
l i n k e d L i s t D e s t r o y ( ( l i n k e d L i s t ∗ ) p , doNothing ) ;
}
linkedListDestroy ( l , destroyPartie );
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
l i n k e d L i s t ∗ k n a p S a c k B r u t e F o r c e S o l v e ( knapSack∗ k )
{
l i n k e d L i s t ∗ i n d e x e s = k n a p S a c k L i s t I n i t ( k−>n b I t e m s ) ;
linkedList ∗ a ll So l ut i on s = par ties ( indexes ) ;
l i n k e d L i s t ∗ b e s t S o l u t i o n S e e n = NULL;
linkedListGetFirst( allSolutions ) ;
p r i n t f ( ”−> s u b s e t s g e n e r a t e d . \ n Tr y i n g t o f i n d t h e b e s t s o l u t i o n \n” ) ;
void f i n d B e s t ( void∗ v )
{
l i n k e d L i s t ∗ l = ( l i n k e d L i s t ∗) v ;
i f ( knapSackIsFeasible (k , l )
&& ( b e s t S o l u t i o n S e e n == NULL | |
knapSackValue ( k , l ) > knapSackValue ( k , b e s t S o l u t i o n S e e n ) ) )
146
bestSolutionSeen = l ;
}
linkedListApply ( al l So lu ti ons , findBest ) ;
p r i n t f ( ” −> Done . \ n D e s t r o y i n g t h e s u b s e t s \n” ) ;
void∗ c o p y I n t ( void∗ i )
{
void∗ v = m a l l o c ( s i z e o f ( long ) ) ;
i f ( v == NULL)
exit (0);
∗ ( ( long ∗ ) v ) = ∗ ( ( long ∗ ) i ) ;
return v ;
}
b e st S o l u t i o nSeen = linkedListMap ( bestSolutionSeen , copyInt ) ;
void d e s t r o y T h e L i n k e d L i s t ( void∗ v )
{
l i n k e d L i s t D e s t r o y ( ( l i n k e d L i s t ∗) v , d e s t r o y I n t ) ;
}
l i n k e d Li st De st r oy ( a l l S o l u t i o n s , destroyTheLinkedList ) ;
p r i n t f ( ” −> Done . \ nThanks f o r y o u r p a t i e n c e . \ n” ) ;
return b e s t S o l u t i o n S e e n ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
i n t main ( )
{
long t = 2 1 ;
knapSack∗ k = knapSackMake ( t , 4 0 ) ;
linkedList ∗ s ;
long l ;
f o r ( l = 0 ; l < k−>n b I t e m s ; l ++)
k n a p S a c k S e t I t e m ( k , l , ( l ∗ l ∗ l )%10 + 1 , ( l ∗ l ∗ l ∗ l )%10 + 1 ) ;
knapSackPrintInstance ( k ) ;
s = knapSackBruteForceSolve( k ) ;
knapSackPrintSolution ( s ) ;
p r i n t f ( ” \n” ) ;
l i n k e d L i s t D e s t r o y ( s , doNothing ) ;
k n a p S a c k D e st r o y ( k ) ;
return 0 ;
}
147
A.17 Prise en main de GLPK
#include<s t d i o . h>
#include ” g l p k . h”
i n t main ( )
{
LPX∗ l p = l p x c r e a t e p r o b ( ) ;
double c o e f f s [ 1 0 ] ;
i n t c o l s [ 1 0 ] , rows [ 1 0 ] ;
int k = 1;
l p x s e t o b j d i r ( l p , LPX MAX ) ;
l p x a d d c o l s ( lp , 3 ) ;
l p x s e t o b j c o e f ( lp , 1 , 4 ) ;
l p x s e t o b j c o e f ( lp , 2 , 6 ) ;
l p x s e t o b j c o e f ( lp , 3 , 2 ) ;
l p x s e t c o l b n d s ( l p , 1 , LPX LO , 0 . 0 , 0 . 0 ) ;
l p x s e t c o l b n d s ( l p , 2 , LPX LO , 0 . 0 , 0 . 0 ) ;
l p x s e t c o l b n d s ( l p , 3 , LPX LO , 0 . 0 , 0 . 0 ) ;
l p x ad d rows ( lp , 3 ) ;
l p x s e t r o w b n d s ( l p , 1 , LPX UP , 0 . 0 , 1 2 . ) ;
l p x s e t r o w b n d s ( l p , 2 , LPX UP , 0 . 0 , 3 . ) ;
l p x s e t r o w b n d s ( l p , 3 , LPX UP , 0 . 0 , 6 . ) ;
c o e f f s [ k ] = 3 . ; rows [ k ] = 1 ; c o l s [ k ] = 1 ; k++;
c o e f f s [ k ] = 7 . ; rows [ k ] = 1 ; c o l s [ k ] = 2 ; k++;
c o e f f s [ k ] = 1 . ; rows [ k ] = 1 ; c o l s [ k ] = 3 ; k++;
c o e f f s [ k ] = 0 . 6 ; rows [ k ] = 2 ; c o l s [ k ] = 1 ; k++;
c o e f f s [ k ] = 3 ; rows [ k ] = 2 ; c o l s [ k ] = 2 ; k++;
c o e f f s [ k ] = 2 . 8 ; rows [ k ] = 2 ; c o l s [ k ] = 3 ; k++;
c o e f f s [ k ] = 9 . ; rows [ k ] = 3 ; c o l s [ k ] = 1 ; k++;
c o e f f s [ k ] = 0 . 0 8 ; rows [ k ] = 3 ; c o l s [ k ] = 2 ; k++;
c o e f f s [ k ] = 5 . ; rows [ k ] = 3 ; c o l s [ k ] = 3 ; k++;
l p x l o a d m a t r i x ( l p , 9 , rows , c o l s , c o e f f s ) ;
lpx simplex ( lp ) ;
p r i n t f ( ” f o n c t i o n o b e c t i f = %l f \n” , l p x g e t o b j v a l ( l p ) ) ;
f o r ( k = 1 ; k <= 3 ; k++)
p r i n t f ( ” x %d = % l f \n” , k , l p x g e t c o l p r i m ( l p , k ) ) ;
lpx delete prob ( lp ) ;
return 0 ;
}
148
A.18 Le plus beau métier du monde
#include<s t d i o . h>
#include ” g l p k . h”
#d ef i n e N 10
149
l p x s e t c o l b n d s ( l p , 1 , LPX FR , 0 . 0 , 0 . 0 ) ;
l p x s e t c o l b n d s ( l p , 2 , LPX DB , 0 . 5 , 1 . ) ;
l p x s e t c o l b n d s ( l p , 3 , LPX DB , 0 . 1 , 1 . ) ;
l p x s e t c o l b n d s ( l p , 4 , LPX DB , 0 . 1 , 1 . ) ;
l p x a d d r o w s ( l p , N+ 1 ) ;
f o r ( e l e v e I n d e x = 0 ; e l e v e I n d e x < N ; e l e v e I n d e x ++)
{
rows [ c o e f f I n d e x ]= e l e v e I n d e x + 1 ;
c o l s [ c oe f f I n d e x ]=1;
coeffs [ coeffIndex ] = 1.0 ;
c o e f f I n d e x ++;
rows [ c o e f f I n d e x ]= e l e v e I n d e x + 1 ;
c o l s [ c oe f f I n d e x ]=2;
c o e f f s [ c o e f f I n d e x ] = −∗( n o t e s P a r t i e l + e l e v e I n d e x ) ;
c o e f f I n d e x ++;
rows [ c o e f f I n d e x ]= e l e v e I n d e x + 1 ;
c o l s [ c oe f f I n d e x ]=3;
c o e f f s [ c o e f f I n d e x ] = −∗( notesCC1 + e l e v e I n d e x ) ;
c o e f f I n d e x ++;
rows [ c o e f f I n d e x ]= e l e v e I n d e x + 1 ;
c o l s [ c oe f f I n d e x ]=4;
c o e f f s [ c o e f f I n d e x ] = −∗( notesCC2 + e l e v e I n d e x ) ;
c o e f f I n d e x ++;
l p x s e t r o w b n d s ( l p , e l e v e I n d e x + 1 , LPX UP , 0 . 0 , 0.0);
}
f o r ( i = 2 ; i <= 4 ; i ++)
{
rows [ c o e f f I n d e x ] = N+1 ;
cols [ coeffIndex ] = i ;
coeffs [ coeffIndex ] = 1.0 ;
c o e f f I n d e x ++;
}
l p x s e t r o w b n d s ( l p , N+1 , LPX DB , 0 . 0 , 1 . 0 ) ;
l p x l o a d m a t r i x ( l p , c o e f f I n d e x − 1 , rows , c o l s , c o e f f s );
lpx simplex ( lp ) ;
l px g et o bj v al ( lp ) ;
f o r ( i = 2 ; i <= 4 ; i ++)
p r i n t f ( ” c o e f f %d i s %l f \n” , i −1 , l p x g e t c o l p r i m ( l p , i ));
l p x p r i n t p r o b ( lp , ” q u e sti on 3 . lpx ” ) ;
lpx delete prob ( lp ) ;
}
i n t main ( )
{
double n o t e s P a r t i e l [N ] = { 1 0 , 1 3 , 2 , 4.5 , 9 , 12 , 16 , 8 , 5 , 12};
double notesCC1 [ N] = {11 , 16 , 11 , 8, 10 , 11 , 11 , 6 , 4 , 13};
double notesCC2 [ N] = { 9 , 18 , 7, 8, 11 , 3 , 13 , 10 , 7 , 19 };
p r i n t f ( ”QUESTION 1\n−−−−−−−−−−\n” ) ;
q u e s t i o n 1 ( n o t e s P a r t i e l , notesCC1 , notesCC2 );
p r i n t f ( ”QUESTION 2\n−−−−−−−−−−\n” ) ;
q u e s t i o n 2 ( n o t e s P a r t i e l , notesCC1 , notesCC2 );
p r i n t f ( ”QUESTION 3\n−−−−−−−−−−\n” ) ;
q u e s t i o n 3 ( n o t e s P a r t i e l , notesCC1 , notesCC2 );
return 0 ;
}
150
A.19 Prise en main de GMP
#include<s t d i o . h>
#include<gmp . h>
/∗
A f f i c h e l a t a b l e de m u l t i p l i c a t i o n de n , de 1 a t o .
n doit etre i n i t i a l i s e .
∗/
/∗
P l a c e b ˆn dans r e s . r e s d o i t e t r e initialise
∗/
/∗
Fo nc t io n d ’ Ackermann. r e s d o i t e t r e i n i t i a l i s e .
A t t e n t i o n ! Ne d o i t e t r e u t i l i s e qu ’ a v e c d e s p e t i t e s valeurs !
∗/
151
mpz t un ;
m p z i n i t s e t u i ( un , 1 ) ;
ackermann ( mMoinsUn , un , res ) ;
m p z c l e a r ( un ) ;
}
else
{
mpz t nMoinsUn ;
mpz t a p p e l R e c u r s i f ;
m p z i n i t ( nMoinsUn ) ;
mpz init ( appelRecursif ) ;
m p z s u b u i ( nMoinsUn , n , 1 ) ;
ackermann (m, nMoinsUn , a p p e l R e c u r s i f ) ;
ackermann ( mMoinsUn , a p p e l R e c u r s i f , r e s ) ;
mpz clear ( appelRecursif ) ;
m p z c l e a r ( nMoinsUn ) ;
}
m p z c l e a r ( mMoinsUn ) ;
}
}
/∗
A f f i c h e t o u t e s l e s images par l a f o n c t i o n d ’ Ackermann d e s c o u p l e s
{ ( i , j ) | 0 <= i <= m, 0 <= j <= n}
∗/
i n t main ( )
{
mpz t v ;
mpz t d i x ;
mpz t v i n g t ;
mpz init (v ) ;
m p z i n i t s e t u i ( dix , 1 0 ) ;
m p z i n i t s e t u i ( vingt , 2 0 ) ;
p u i ssan c e ( dix , vingt , v ) ;
afficheTableMultiplication (v , 10);
afficheAckermann(4 , 1 5 ) ;
return 0 ;
}
152
A.20 Algorithme d’Euclide étendu
#include<s t d i o . h>
#include<gmp . h>
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
C a l c u l e u e t v t e l s que au + bv = pgcd , ou pgcd e s t l e pgcd de a e t b .
Toutes l e s v a r i a b l e s d o i v e n t e t r e i n i t i a l i s e e s .
∗/
153
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
Im p l e m e nt a t io n de l a f o n c t i o n p h i d e f i n i e dans l e s u j e t
p h i ( a , b , 0) = b e t p h i ( a , b , n ) = p h i ( a + b , b , n−1).
Tous l e s p a r a m e t r e s d o i v e n t e t r e i n i t i a l i s e s .
∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
P l a c e dans r e s l e n−eme nombes de F i b o n a c c i .
Tous l e s p a r a m e t r e s d o i v e n t e t r e i n i t i a l i s e s .
∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
i n t main ( )
{
mpz t u ;
mpz t v ;
mpz t p ;
mpz t c e n t ;
mpz t centUn ;
mpz t F c e n t ;
mpz t FcentUn ;
mpz init (u ) ;
mpz init (v ) ;
mpz init (p ) ;
m p z i n i t s e t u i ( cent , 1 0 0 ) ;
m p z i n i t s e t u i ( centUn , 1 0 1 ) ;
m p z i n i t ( Fcent ) ;
m p z i n i t ( FcentUn ) ;
f i b o ( cent , Fcent ) ;
f i b o ( centUn , FcentUn ) ;
b e z o u t ( FcentUn , Fcent , u , v , p ) ;
mpz clear (u ) ;
mpz clear (v ) ;
mpz clear (p ) ;
mpz clear ( cent ) ;
m p z c l e a r ( centUn ) ;
m p z c l e ar ( Fcent ) ;
m p z c l e a r ( FcentUn ) ;
return 0 ;
}
154
A.21 Espaces Quotients
#include<s t d i o . h>
#include<gmp . h>
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗
C a l c u l e u e t v t e l s que au + bv = pgcd , ou pgcd e s t l e pgcd de a e t b .
Toutes l e s v a r i a b l e s d o i v e n t e t r e i n i t i a l i s e e s .
∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
void e t u d i e E s p a c e Q u o t i e n t ( mpz t n )
{
mpz t i , phi , i n v e r s e I ;
mpz init ( i ) ;
mpz init ( phi ) ;
mpz init ( invers eI ) ;
mpz set ui ( i , 0) ;
m p z s e t u i ( phi , 0 ) ;
p r i n t f ( ”Z/ ” ) ;
m p z o u t s t r (NULL, 1 0 , n ) ;
p r i n t f ( ”Z : ” ) ;
while ( mpz cmp ( i , n ) )
{
p r i n t f ( ” \n” ) ;
155
m p z o u t s t r (NULL, 1 0 , i ) ;
i f ( trouveInverse ( i , n , inverseI ))
{
p r i n t f ( ” a pour i n v e r s e ” ) ;
m p z a d d u i ( phi , phi , 1 ) ;
mpz mod ( i n v e r s e I , i n v e r s e I , n ) ;
m p z o u t s t r (NULL, 1 0 , i n v e r s e I ) ;
}
else
p r i n t f ( ” ( non i n v e r s i b l e ) ” ) ;
mpz add ui ( i , i , 1 ) ;
}
p r i n t f ( ” \nOn a p h i ( ” ) ;
m p z o u t s t r (NULL, 1 0 , n ) ;
printf (”) = ” );
m p z o u t s t r (NULL, 1 0 , p h i ) ;
p r i n t f ( ” \n” ) ;
m p z a d d u i ( phi , phi , 1 ) ;
i f ( ! mpz cmp ( n , p h i ) )
p r i n t f ( ” Cet e n se m b l e e s t un c o r p s \n” ) ;
else
p r i n t f ( ” Cet e n se m b l e n e s t p a s un c o r p s \n” ) ;
}
/∗−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−∗/
i n t main ( )
{
mpz t t e s t ;
mpz init ( t es t ) ;
mpz init set ui ( test , 20);
etudieEspaceQuotient( t e s t ) ;
mpz clear ( te s t ) ;
return 0 ;
}
156
Annexe B
Rappels mathématiques
B.1 Sommations
Parmi les outils mathématiques permettant d’évaluer la complexité d’un algorithme se trouvent les sommations.
Commençons par rappeler quelques propriétés :
Xn
1. 1=n−p+1
i=p
n
X n−1
X n
X
2. ui = ( ui ) + un = up + ui
i=p i=p i=p+1
Xn n
X
3. (a.ui ) = a ui
i=p i=p
Xn Xn n
X Xn
4. (ai + b) = ai + b=( ai ) + (n − p + 1)b
i=p i=p i=p i=p
Xn Xn Xn
5. (ai + bi ) = ai + bi
i=p i=p i=p
n
X n+1
X n−1
X
6. ui = ui−1 = ui+1
i=p i=p+1 i=p−1
Xn Xm m X
X n
7. uij = uij
i=1 j=1 j=1 i=1
P
Bien que le soit prioritaire sur le + mais pas sur le ×, il usuel pour éviter toute confusion de rajouter des parenthèses,
même inutiles. Parmi les sommes que vous devez maı̂triser parfaitement figurent les deux suivantes :
n
X n(n + 1)
1. i= (série arithmétique)
i=1
2
n
X rn+1 − 1
2. ri = (série géométrique)
i=0
r−1
On se ramène souvent à ce type de formule en algorithmique.
B.1.1 Exercices
Calculer les sommes suivantes :
Xn
1. 2i + 1
i=1
157
n
X
2. (i + 1)2
i=1
n X
X i
3. ( j)
i=1 j=1
n X
X n
4. ( j)
i=1 j=i
n
X
5. i
i=p
n
X
6. ri
i=p
B.2 Ensembles
B.2.1 Définition
Définition B.2.1 Un ensemble est un regroupement en un tout d’objets. Etant donné un ensemble E, les objets
regroupés dans E sont appelés éléments de E.
On définit un ensemble notament en énumérant ses éléments et en les séparant par des virgules. Par exemple E =
{1, 2, 3, 4} définit un ensemble E contenant les éléments 1, 2, 3 et 4. Si e est un élément de E, on dit alors qu’il
appartient à E, noté e ∈ E.
x ∈ E ⇐⇒ P (x)
Ensemble vide
F est le prédicat constant prenant toujours la valeur ”faux”.
∅ = {i|F }
∅ est l’ensemble auquel n’appartient aucun élément. L’ensemble vide peut être défini par tout prédicat constant étant
toujours faux. Par exemple,
∅ = {i|(i ∈ N ) ∧ (i = i + 1)}
Définition B.2.4 L’union de deux ensembles A et B, notée ∪, est définie par A ∪ B = {x|(x ∈ A) ∨ (x ∈ B)}.
158
Un élément appartient à A ∪ B s’il appartient à A, ou s’il appartient à B. Par exemple,
Définition B.2.5 L’intersection de deux ensembles A et B, notée ∩, est définie par A ∩ B = {x|(x ∈ A) ∧ (x ∈ B)}.
Un élément appartient à A ∩ B s’il appartient à A, et s’il appartient à B. Par exemple,
Définition B.2.6 La différence de deux ensembles A et B, notée \ ou −, est définie par A \ B = {x|(x ∈ A) ∧ (x 6∈
B)}.
Un élément appartient à A \ B (ou A − B) s’il appartient à A, mais pas à B. Par exemple,
De même n
\
E1 ∩ E2 ∩ . . . ∩ En = Ei
i=1
B.2.3 Cardinal
Un ensemble est infini s’il contient un nombre infini d’éléments, sinon, on dit qu’il est fini.
Définition B.2.7 Le cardinal d’un ensemble fini E, noté |E| est le nombre d’éléments qu’il contient.
Par exemple, |∅| = 0, |{1, 2, 4}| = 3. Seul l’ensemble vide est de cardinal 0, un ensemble de cardinal 1 est appelé un
singleton, un ensemble de cardinal 2 est appelé une paire.
B.2.4 n-uplets
Un n-uplet est un regroupement ordonné de n éléments non nécessairement distincts. On note X = (x1 , . . . , xn ) le
n-uplet composé des éléments x1 , . . . , xn , on les appelle composantes des E. Par exemple, (4, 8) est un 2-uplet, dit
aussi couple, et ((3, 2), (6, 12), (0, 3)) est un triplet composé des trois couples (3, 2), (6, 12) et (0, 3).
159
Produit cartésien
Définition B.2.8 Le produit cartésien de n ensembles E1 , . . . , En , noté E1 × . . . × En est l’ensemble de tous les
n-uplets (x1 , . . . , xn ) tels que ∀i ∈ {1, . . . , n}, xi ∈ Ei .
Par exemple,
{1, 2} × {a, b, c} = {(1, a), (2, a), (1, b), (2, b), (1, c), (2, c)}
Formellement,
E1 × . . . × En = {(x1 , . . . , xn )|∀i ∈ {1, . . . , n}, xi ∈ Ei }
B.2.5 Parties
Inclusion
Définition B.2.9 A est contenu dans B, noté A ⊂ B si et seulement si ∀e ∈ A, e ∈ B,
En d’autres termes si tout élément de A est aussi un élément de B. On dit aussi que A est un sous-ensemble de B,
que A est inclus dans B, ou encore que A est une partie de B.
Parties de E
Définition B.2.10 L’ensemble P(E) des parties de E, est défini par
P(E) = {e|e ⊂ E}
P(E) est donc l’ensemble de tous les ensembles inclus dans E. Par exemple, P({1, 2, 3}) = {{1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, ∅, {1, 2, 3
on remarque que P(E) est un ensemble d’ensembles. Prennez note du fait que ∅ est un sous-ensemble de tous les en-
sembles, y compris de lui-même, et que le seul ensemble contenu dans ∅ est ∅. A votre avis, que vaut P(∅) ? Cette
question vous amènera à distinuer ∅ de {∅}, qui est l’ensemble qui contient l’ensemble vide.
Exercice
Calculer P(∅), P({1, 2}), P({∅}).
Autre exercice
Soit f la fonction qui a un ensemble d’ensembles F et un élément x associe f (F, x) = {e ∪ {x}|e ∈ F }. Montrer que
P(E) = f (P(E − {x}), x) ∪ P(E − {x}). En déduire un algorithme récursif calculant P(E).
B.2.6 Définition
Définition B.2.11 Une relation f entre deux ensembles A et B est un sous-ensemble de A × B.
Etant donné deux éléments x ∈ A et y ∈ B, si (x, y) ∈ f , alors on dit que f associe y à x. L’ensemble des éléments
qui sont associés à x est {y|(x, y) ∈ f }.
Définition B.2.12 Une relation f entre deux ensembles A et B est une application si ∀a ∈ A, |{b|(a, b) ∈ f }| = 1
Plus explicitement, f est une application si à tout élément de A est associé exactement un élément de B. On dit alors
que f est une application de A dans B, ce qui se note f : A −→ B. On dit par abus de langage que A est l’ensemble
de départ et B l’ensemble d’arrivée. Pour tout a ∈ A, on note f (a) l’élément de B qui lui est associé. On dit que f (a)
est l’image de a par f et a un antécédent de f (a) par f .
Etant donné un ensemble E, il existe une application, appelée identité, et notée id, telle que tout élément à pour
image lui-même. Autrement dit : id : E −→ E, x 7→ x. La succession de symboles a 7→ b signifie que b est l’image de
a, donc x 7→ x signifie que x a pour image lui-même.
160
B.2.7 Composition
Etant donnés f : A −→ B et g : B −→ C, on définit l’application composée de g et f , notée g ◦ f , dite ”g rond f ”, et
définie par g ◦ f : A −→ C, x 7→ g(f (x)). Autrement dit, g ◦ f est une application de A dans C, qui à tout élément x
de A, associe l’élément g(f (x)) de C.
f est injective si deux éléments distincts ne peuvent pas avoir la même image.
Théorème B.2.1 Il existe une unique fonction f −1 , appelée application réciproque de f, telle que pour tous x ∈ A,
y ∈ B tels que f (x) = y, on ait f −1 (y) = x.
On remarque que f ◦ f −1 = f −1 ◦ f = id.
161
B.3.2 Exemple
Montrons par récurrence sur n que “Quel que soit n ≥ 0, n2 − n est pair” :
– initialisation : , 02 − 0 est pair, c’est évident.
– hérédité : , supposons que n2 − n est pair, vérifions si (n + 1)2 − (n + 1) est pair lui aussi. Calculons
(n + 1)2 − (n + 1) = n2 + 2n + 1 − n − 1 = (n2 − n) + 2n
Comme (n2 −n) et 2n sont tous deux pairs, et que la somme de deux nombres pairs est paire, alors (n+1)2 −(n+1)
est pair.
Demandons-nous si 22 − 2 est pair, on sait d’après l’initialisation que 02 − 0 est pair. Posons n = 0, comme la propriété
est vérifiée au rang n, elle est, d’après l’hérédité, nécessairement vérifiée au rang n + 1, donc 12 − 1 est pair. Posons
n = 1, comme 12 − 1 est pair, la propriété est vérifiée au rang n, elle est, d’après l’hérédité, nécessairement vérifiée au
rang n + 1, donc 22 − 2 est pair. On peut généraliser ce raisonnement à n’importe quelle valeur de n.
B.3.3 Exercices
Exercice 10
Prouver par récurrence les propriétés suivantes :
1. Quel que soit n ≥ 0, n2 + n + 1 est impaire.
2. Soit (u) une suite définie par u0 = −2, un+1 = (1/2)un + 3, alors un < 6
8
3. Soit (u) une suite définie par u0 = −2, un+1 = (1/2)un + 3, alors un = 6 − (2n )
4. Soit (u) une suite définie par u0 = 2, un+1 = 2un − n, alors un = 2n + n + 1
n
X n(n + 1)
5. Pour tout n > 0, i=
i=1
2
n
X 1 − q n+1
6. Pour tout n ≥ 0, q 6= 1, qi =
i=0
1−q
n
X n(n + 1)(2n + 1)
7. Pour tout n > 0, i2 =
i=1
6
(f n )′ = nf ′ (f n−1 )
Formule de Leibniz
On note f (n) la dérivée n-ième de f . Prouvez par récurrence la formule de Leibniz : ∀n ∈ IN∗
n
X
(f g)n = Cni f (i) g (n−i)
i=0
ni=1 [fi ] = f1 ◦ . . . ◦ fn
la composition de ces fonctions. Démontrez par récurrence que
n
Y
(
ni=1 [fi ])′ = [fi′ ◦ (
nj=i+1 [fj ])]
i=1
162
B.4 Analyse combinatoire
B.4.1 Factorielles
Pour tout n ≥ 0, le nombre n!, appelé ”factorielle n”, est défini par récurrence à l’aide des relations suivantes :
– 0! = 1
– n! = n × (n − 1)!
Y n
On a donc n! = i avec le cas particulier 0! = 1.
i=1
B.4.2 Arrangements
Définition B.4.1 Soient n et p tels que 0 ≤ p ≤ n, on note Apn , et on lit ”A n p” le nombre
n!
(n − p)!
B.4.3 Combinaisons
Définition B.4.2 Soient n et p tels que 0 ≤ p ≤ n, on note Cnp , et on lit ”C n p” le nombre
n!
p!(n − p)!
Propriété B.4.1 Les égalités suivantes sont vérifiées pour tous k et n tels que 0 ≤ k ≤ n,
1
– Cni = Ain
p!
– Cn0 = 1
– Cn1 = n
– Cnp = Cnn−p
p−1
– pCnp = nCn−1
p p−1 p
– Cn = Cn−1 + Cn−1
Xn
– Cni = 2n
i=0
n
X
– (a + b)n = Cni ai bn−i
i=0
n−1
X
– Cip−1 = Cnp
i=p−1
163
Vous remarquez que la propriété Cn0 = 1 traduit le fait que la première colonne ne comporte que des 1. Comme chaque
ligne est symétrique alors Cnp = Cnn−p . Pour chaque ligne, le premier élément est 1, donc la symétrie fait que le dernier
p−1 p
est 1 aussi. La propriété Cnp = Cn−1 + Cn−1 traduit le fait que chaque élément Cnp ne se trouvant pas dans la première
p
colonne ou sur la diagonale est la somme de celui qui est au dessus Cn−1 et de celui qui est juste à gauche de ce dernier
p−1
Cn−1 . Si on somme les éléments sur chaque ligne, on obtient des puissances successives de 2 :
X n
(n, p) p= 0 1 2 3 4 5 6 ... Cnp
p=0
n= 0 1 20
1 1 1 21
2 1 2 1 22
3 1 3 3 1 23
4 1 4 6 4 1 24
5 1 5 10 10 5 1 25
6 1 6 15 20 15 6 1 26
... ... ... ... ... ... ... ... ... ...
n
X
Cette propriété se traduit Cni = 2n . L’identité remarquable (a + b)n s’écrit à l’aide des coefficients su triangle de
i=0
Pascal. Par exemple,
(a + b)3 = a3 + 3a2 b + 3ab2 + b3
Vous remarquez que le développement de (a+b)3 s’ecrit avec un polynome à deux variable dont la somme des exposants
de chaque terme est 3, chaque terme est donc de la forme ai b3−i . Les coefficients devant chaque termes sont issus de
la ligne d’indice 3 du triangle de Pascal, à savoir (1, 3, 3, 1), autrement dit (C30 , C31 , C32 , C33 ). Donc
3
X
(a + b)3 = C3i ai bn−i
i=0
On a plus généralement que
n
X
(a + b)n = Cni ai bn−i
i=0
Par exemple,
Propriété B.4.2 Le nombre de sous-ensembles à k éléments d’un ensemble E à n éléments, à savoir |{x|(x ⊂
E) ∧ (|x| = k)}| est donné par Cnk .
On le démontre par récurrence sur n,
– si n = 0, le seul ensemble à 0 éléments est ∅, son seul sous-ensemble est ∅, donc
|{x|(x ⊂ ∅) ∧ (|x| = 0)}| = |{∅}| = 1 = C00
– Supposons que pour tout ensemble E ′ à n − 1 ≥ 0 éléments, et tout k ′ ∈ {0, . . . , n − 1},
′
|{x|(x ⊂ E ′ ) ∧ (|x| = k ′ )}| = Cn−1
k
Considérons un ensemble E à n ≥ 1 éléments et une valeur k ∈ {0, . . . , n}, montrons que le cardinal de
P = {x|(x ⊂ E) ∧ (|x| = k)}
est Cnk
164
– Si k ∈ {1, . . . , n−1}, choisissons un élément arbitraire e ∈ E, cet élément existe nécessairement car |E| = n ≥ 1.
On décompose {x|(x ⊂ E) ∧ (|x| = k)} en deux ensembles P1 et P2 . P1 est l’ensemble des sous-ensembles de
E à k éléments qui contiennent e, défini par
Deux ensembles Pk (E) et Pk′ (E) tels que k 6= k ′ sont nécessairements disjoints(si ça vous semble pas évident, cherchez
un contre-exemple et vous comprendrez pourquoi...). Donc
n
[ n
X
| Pk (E)| = |Pk (E)|
k=0 k=0
165
Si cette propriété ne vous parle pas, démontrez-la par récurrence en utilisant le fait que si A ∩ B = ∅, alors |A ∩ B| =
Xn Xn
|A| + |B|. Nous avons démontré que ∀k ∈ {0, . . . , n}, |Pk (E)| = Cnk . Donc |Pk (E)| = Cnk = 2n . Le nombre
k=0 k=0
de parties d’un ensemble à n éléments est donc 2n . Il vous est possible, de vérifier ce résultat par récurrence, le
raisonnement est analogue à celui employé pour prouver que |{x|(x ⊂ E) ∧ (|x| = k)}| = Cnk , mais en plus facile.
En notant Ikn l’ensemble des sous-ensembles de {1, . . . , n} à k éléments, formellement : Ikn = {e ⊂ {1, . . . , n} tel que |e| =
k}
1. Réecrivez la formule de Poincaré avec n = 1
2. Réecrivez la formule de Poincaré avec n = 2
3. Soient A = {1, 3, 5, 6} et B = {1, 2, 3, 4}. Calculez |A ∪ B| en utilisant la propriété |A ∪ B| = |A| + |B| − |A ∩ B|.
4. Réecrivez la formule de Poincaré avec n = 3
5. Soit C = {6, 7, 8}, utilisez la formule de Poincaré pour calculer |A ∪ B ∪ C|.
6. On considère n+1 ensembles {E1 , . . . En+1 }. Supposons la formule de Poincaré vérifiée vérifiée au rang n. Donnez
alors une relation entre
n+1
[
| Ei |
i=1
et
n
X X \
(−1)i+1 ( |Ei |)
i=1 e∈Iin i∈e
7. Utilisez les résultats des questions précédentes pour prouver par récurrence la formule de Poincaré.
166
B.5.3 La moulinette à méninges
Soient A et B deux ensembles finis de cardinaux respectifs m et n.
1. Combien existe-t-il de relations entre A et B ? (Bijection avec les parties de l’ensemble A × B)
2. Combien existe-t-il d’applications de A dans B ? (Raisonnez par récurrence)
3. Combien existe-t-il d’applications bijectives de A dans B ? (une bijection)
4. Combien existe-t-il de k-uplets d’éléments de A ? (démerdez-vous)
5. Combien existe-t-il de k-uplets d’éléments distincts de A ?
6. Combien existe-t-il d’applications injectives de A dans B ? (raisonnez par récurrence)
7. Combien existe-t-il de façon de partitionner un ensemble E de cardinal n en 3 sous-ensembles ? C’est-à-dire de
déterminer 3 ensembles A, B et C tels que A ∪ B ∪ C = E, A ∩ B = ∅, A ∩ C = ∅ et B ∩ C = ∅. (bijection)
8. Une application est croissante au sens large si ∀x, y ∈ A, x < y =⇒ f (x) ≤ f (y). Combien existe-t-il d’applications
croissantes au sens large de A dans B (supposés ordonnés) ? (une bijection)
9. Une application est croissante au sens strict si ∀x, y ∈ A, x < y =⇒ f (x) < f (y). Combien existe-t-il d’applica-
tions croissantes au sens large de A dans B ? (plus difficile, bijection...)
10. Combien existe-t-il de façon de partitionner un ensemble E de cardinal n > 3 en 3 sous-ensembles non-vides ?
(bijections + poincaré)
11. Soit f : A −→ A, un point fixe de f est un élément x de A tel que f (x) = x. Combien existe-t-il de bijection
sans point fixe ? (vraiment difficile, utilisez la formule de Poincaré puis le binôme de Newton)
167
Bibliographie
[1] Simon Singh. The code book : the evolution of secrecy from Mary, Queen of Scots, to quantum cryptography. 1999.
[2] Thomas Cormen, Charles Leiserson, and Ronald Rivest. Introduction to algorithms. Dunod, 1992.
[3] Chrétienne P. Beauquier D., Berstel J. Eléments d’algorithmique. Masson, 1992.
[4] http://webpages.ull.es/users/jriera/Docencia/AVL/AVLtreeapplet.htm.
[5] Vasek Chvatal. Linear Programming. Freeman, 1983.
[6] http://www.gnu.org/software/glpk/.
[7] http://www.lmbe.seu.edu.cn/CRAN/doc/packages/glpk.pdf.
[8] Johnson D Garey M. Computers and Intractability. 1979.
[9] Hackademy Journal.
[10] Hackademy Journal.
[11] Hackademy Journal.
[12] http://www.gnupg.org/(fr)/documentation/guides.html.
[13] http://www.gnupg.org/gph/en/manual.pdf.
[14] http://gmplib.org/.
[15] http://gmplib.org/#DOC.
168