Professional Documents
Culture Documents
Rsum
Ce document se propose de donner quelques rudiments d'algorithmique un public littraire. Pour relever ce d, on commence par une longue introduction dnissant la notion d'algorithme et prsentant les dirents outils dont nous auront besoin pour la suite. Aprs quelques notes sur la rcursivit, on prsente les structures de donnes fondamentales et quelques algorithmes incontournables pour le public vis. Des annexes compltent ce polycopi et pourront tre rserves une seconde lecture.
2 Rcursivit
Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Contre exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ranements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Tableaux . . . . . . . . . . . . . . . . . . . . . Listes . . . . . . . . . . . . . . . . . . . . . . Arbres . . . . . . . . . . . . . . . . . . . . . . 3.3.1 Parcours d'un arbre . . . . . . . . . . 3.3.2 Arbres de recherche . . . . . . . . . . 3.3.3 Des arbres particuliers : les tas . . . . Hachages . . . . . . . . . . . . . . . . . . . . 3.4.1 O l'on retrouve les listes chanes . . 3.4.2 Tables de hachages adressage ouvert Piles & les . . . . . . . . . . . . . . . . . . . Tri par insertion . . . . Tri bulle . . . . . . . . . Tri par tas ou heapsort . Tri par fusion . . . . . . Tri rapide ou quicksort . Tris linaires . . . . . . 4.6.1 Tri par comptage 4.6.2 Tri par base . . . . . . . . . . . . . . . . . . . . . . . . . . . ou par . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
13
16
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . dnombrement . . . . . . . . .
22
5 Recherche de motifs
5.1 5.2
27
6 Conclusion
6.1 6.2
30
30 30 31 31
A Manipulations numriques
31
Bibliographie Index
33 34
1.1 Dnition
Dans la prface de l'dition franaise de [CLR94], la bible de Cormen et al., on peut lire2 : [L'algorithmique] est le cur de l'informatique. Pour tous ceux qui doivent [. . .] faire travailler un ordinateur, il est essentiel de comprendre ses principes fondamentaux et de connatre ses lments de base. Une formule 1 ne se conduit pas comme une voiture pdales. De mme un ordinateur ne s'utilise pas comme un boulier. L'algorithmique est le permis de conduire de l'informatique. Sans elle, il n'est pas
1 Ainsi 2
parle-t-on tort des nombres arabes tandis que l'on devrait dire nombres sanscrits. [CLR94], page xiii.
Un algorithme reprsente ce que doit faire un morceau de programme informatique dans les grandes lignes. Il y a beaucoup de manires de reprsenter un algorithme, la meilleure tant probablement l'utilisation d'un pseudo-langage de programmation, ce que nous ferons. Le grand problme de l'algorithmique est de mettre au point des algorithmes ecaces en terme de temps de calcul (mesur en oprations lmentaires) et d'espace mmoire requis, ces deux contraintes tant incompressibles et fortement lies ; si l'espace requis diminue, c'est au dtriment du temps de calcul et rciproquement. En eet, si un programme est trop lourd en terme de temps de calcul et/ou d'espace mmoire requis, son utilisation ncessitera un supercalculateur3 et non un simple poste de travail. La mesure du temps de calcul et de l'espace mmoire mobilis sont donc fondamentaux pour valuer et comparer des algorithmes. Pour cela, l'unit de mesure est la taille des donnes du problme. Ainsi, la bonne question se poser est : que se passe-t-il si je double la taille des donnes ? Nous voil mme de donner une dnition d'un algorithme :
Dnition 1.1.1 Un algorithme est une suite nie d'instructions lmentaires qui, tant donn
des paramtres typs, renvoie la solution d'un problme donn.
Il nous faut donc dnir les termes instruction lmentaire, paramtres typs, problme et prciser suite nie. Commenons par suite nie : il faut non seulement que la suite d'instructions soit nie mais aussi et surtout qu'elle s'execute un nombre ni de fois (on dit que l'algorithme termine ). Il faut toujours s'assurer qu'un algorithme termine. Par problme , on entend toute question dont la rponse est true ou false ou le rsultat d'un calcul (numrique ou non). Par paramtre typ , on entend cette donne est un entier, cette autre une chane de caractres ; autrement dit, une donne d'une nature particulire : entier, ottant, caractre, chane de caractres, etc. Le type inue videmment sur le traitement. Imaginons que l'on dispose d'une calculatrice programmable proposant les oprations +, , , et . Ce sera donc le nombre d'appels de ces oprations lmentaires que l'on comptera pour valuer la complexit d'un algorithme implment sur cette calculatrice. Un problme est par exemple rsoudre ax + b = 0 . L'algorithme est le suivant :
Algorithme 1.1.2
sinon :
La terminaison est triviale. Ici, outre des tests, on note une multiplication 1 et une division. Ainsi, le matriel son importance. En eet, quand bien mme on manipule des algorithmes et des donnes abstraites, il n'en demeure pas moins que ce n'est pas (que) pour la gloire mais bien en vue d'une utilisation dans la vraie vie. Il faudra donc toujours garder l'esprit que l'implmentation d'un algorithme dpend troitement de la machine sur laquelle le programme en rsultant sera excut : il sera dicile d'utiliser une calculette 2 francs 6 sous pour trier un gros tableau de donnes. Il existe plusieurs modles thoriques pour aborder la suite, en particulier celui des machines de Turing, que nous suivrons, et celui des machines RAM 4 (Random Access Machines, trs proches de nos machines actuelles, issus des travaux de von Neumann). On peut dmontrer que, quelque soit le modle retenu, les caractristiques des algorithmes sont les mmes, ce qui est moral.
Turing,
la donne de
M = Q, , q0 , , F
4
Q est l'ensemble (ni) des tats de la machine, est l'alphabet de la machine (avec lequel elle code ses donnes), q0 Q est l'tat initial, est la fonction de transition de M dnie par : Q Q {1, 0, 1}, F l'ensemble des tats naux, F Q.
Une machine de Turing dispose d'un ruban de longueur nie gauche, innie droite, divis en cases. Chaque case ne comporte qu'un unique symbole. La premire case contient l'tat initial q0 et la machine dispose d'un symbole qF ou (yF , nF ) de n, selon que le problme envisag est un calcul ou un problme de dcision. Outre cette bande (gurant la mmoire), la machine dispose d'une tte de lecture/criture actionne par un mcanisme (gurant le processeur). Ce mcanisme est entirement dtermin par la fonction (les circuits imprims dans le silicium). On rappelle que Q est l'ensemble form des couples (q, ) avec q Q et . De mme, Q {1, 0, 1} est-il l'ensemble des triplets (q, , ) o q Q, et {1, 0, 1}. Ainsi associe-t-elle un couple (q, ) un triplet (q , , ). Sur la bande, immdiatement la droite de q0 , un certain nombre de cases sont occupes par des symboles (un par case), ces symboles reprsentant les donnes du problme. 0 gure le blanc. chaque instant, l'tat de la machine est entirement dtermin par et les donnes initiales. Ainsi, (q, ) = (q , , ) signie que quand on est dans l'tat q et que l'on lit , on doit se dplacer de (1 vers la gauche, 0 ne pas bouger, 1 vers la droite), passer dans l'tat q , remplacer par . On prend les conventions : q0 ne peut tre eac, on ne peut pas aller plus gauche quand on lit q0 , l'instant initial, il n'y a qu'un nombre ni de symboles dirents de 0 , la machine s'arrte quand l'un des tats de F est atteint, le contenu nal de la bande correspond alors au rsultat du calcul quand la machine est dans l'tat qF , l'tat yF correspond une rponse positive au problme de dcision, l'tat nF correspond une rponse ngative. Avant le lancement de la machine, les donnes ont t crites sur la bande immdiatement droite de q0 et la tte de lecture positionne sur q0 . C'est l'tat initial. Il y a un ou artistique (dans la pratique seulement) sur l'tat nal. En eet, ce peut tre un symbole de l'alphabet que l'on crira donc sur la bande (typiquement pour un problme de dcision qF ou qN ) ou quelque chose de plus abstrait dni par (typiquement dans le cadre d'un calcul).
Exemple 1.2.3 Soit l'alphabet = {0, 1, #, q0 }. On va dnir une machine de Turing addi-
tionnant deux entiers. Outres les conventions prcdentes, on dcide de coder un entier par son criture en binaire suivi de #. Je vous rappelle qu'un entier a s'crit en binaire :
a = n ai .2i i=0
o ai {0, 1} et n = log2 a (n est le plus grand entier tel que a 2n ) soit :
a = a0 + a1 21 + . . . + an 2n
Ainsi, 5 s'crit-il 101 (1.22 + 1.20 ), 8 1000 (1.23 ), etc. Si vous regardez bien, en remplaant 2 par 10, vous devriez vous rappeler les paroles de votre instituteur lorsque vous appreniez l'addition entire.
Pour simplier, plutt qu'une unique bande, on va utiliser une machine trois bandes : une pour chaque entre, une autre pour le rsultat. Pour initialiser la machine, on copie les entiers a et b sur les deux premires en commenant par la droite. Aprs chaque entier, on inscrit un #. Pour additionner a et b, la formule (attention aux retenues, 1 + 1 = 10 et 1 + 1 + 1 = 11 !) est : s = n si .2i = n ai .2i + n bi .2i i=0 i=0 i=0 o m = max(log2 a, log2 b) (m est donc le plus grand entier5 vriant 2m max(a, b)) et si ai + bi + ri mod 2 avec r dnit par : r0 = 0 et ri+1 = 0 si (ai + bi + ri ) 1, 1 sinon. On suppose que les trois ttes de lecture sont solidaires et que les deux premires bandes sont accessibles en lecture seule, la dernire en lecture criture. En listant les cas possibles, on voit vite qu'il nous faut deux tats principaux q0 et qr . En dtails, on a une fonction : Q Q {0, 1} dont voici les principaux tats : (q0 , q0 , q0 , q0 ) = (q0 , 1, q0 ) (q0 , 1, #, 0) = (q0 , 1, 1) (q0 , #, 1, 0) = (q0 , 1, 1) (q0 , 0, #, 0) = (q0 , 1, 0) (q0 , #, 0, 0) = (q0 , 1, 0) (q0 , 0, 0, 0) = (q0 , 1, 0) (q0 , 1, 1, 0) = (qr , 1, 0) (qr , 1, 0, 0) = (qr , 1, 0) (qr , 0, 1, 0) = (qr , 1, 0) (qr , 1, #, 0) = (qr , 1, 0) (qr , #, 1, 0) = (qr , 1, 0) (qr , 1, 1, 0) = (qr , 1, 1) (qr , 0, 0, 0) = (q0 , 1, 1) (qr , #, 0, 0) = (q0 , 1, 1) (qr , 0, #, 0) = (q0 , 1, 1)
Exercice 1.2.5 Complter cette table pour faire apparatre qF et s'assurer ainsi de la terminaison.
Remarque 1.2.6 Il faudra me croire (si a n'est pas dj trivial) quand je dis qu'utiliser une
bande ou en utiliser trois comme ici revient au mme.
utilis qu'une unique bande. On retiendra que la structure des donnes est fondamentale et fortement lie l'algorithme (comprendre si l'on choisit une mauvaise reprsentation, l'algorithme de traitement ne pourra pas tre ecace). Si l'on rchit plus de cinq secondes, on note que le calcul a demand m + 3 dplacements de la tte (un pour quitter l'tat initial, m + 1 pour remplir les cases de la somme, une dernire pour marquer la n du calcul) et 3m + 1 cases mmoires (m pour chacune des deux donnes, m+1 pour le rsultat). On remarque donc que le nombre d'tapes de calcul est li l'occupation mmoire (par un facteur 3). Ici, les oprations lmentaires sont les dplacements de la tte. En fait, c'est qui dnit ces oprations lmentaires. La complexit d'un algorithme est mesure par le nombre d'oprations lmentaires ncssaires au calcul de la solution sur une machine. On retiendra de tout cela que : pour un mme problme, il y a plusieurs machines de Turing dont certaines sont plus ecaces que d'autres, pour un mme problme, si l'on fait baisser l'occupation de la mmoire, on augmente le nombre d'oprations lmentaires, une machine implmente un algorithme et donc, il existe plusieurs algorithmes pour un mme problme, certains tant moins coteux que d'autres (du point de vue de l'occupation de la mmoire ou du point de vue du nombre d'oprations lmentaires).
1.4 Appart : la notation O(x), polynmes, exponentielles, logarithmes, partie entire et congruences
Un polynme est une expression an xn + . . . + a2 x2 + a1 x + a0 . Le terme intressant est an xn ; an tant une constante, on la nglige aussi. Finalement, dans l'expression prcdente, seule nous intresse xn car c'est le terme qui crot le plus vite : on dit que l'expression est de l'ordre de xn , ce que l'on note :
an xn + . . . + a2 x2 + a1 x + a0 = O(xn )
Pour s'en convaincre, regardons la contribution de chacun des termes : soit le polynme n2 + n + 1. Si n = 10, 102 n2 = 2 = 0.90 n2 + n + 1 10 + 10 + 1 n 10 = 2 = 0.09 2+n+1 n 10 + 10 + 1 Je ne pense pas avoir besoin de poursuivre l'exprience avec le malheureux texte constant. Si maintenant on prend n = 100, la contribution du terme quadratique est encore bien suprieure :
Une fonction exponentielle est de la forme k x (k une constante donne). On a toujours, pour x susamment grand et n un entier donn, que k x est beaucoup plus grand que xn d'o :
xn + k x = O(k x )
Ici, pour reprendre l'exemple prcdent, voyons la contribution des dirents termes : soit l'expression n2 + 2n . On a : n2 102 = = 0.08 n2 + 2n 100 + 1024 1024 2n = = 0.91 2 + 2n n 100 + 1024 Dans tout les cas, seul nous intresse le terme dont la croissance est la plus rapide. Attention toutefois, l'arithmtique des O n'est pas conforme l'arithmtique usuelle et O(n) O(n) n'est pas nul. Pour ceux que la notation log2 laisse rveur, on peut dnir trs grossirement la fonction logarithme comme tant celle telle que pour R+ \ {0}, si = log2 alors 2 = . Autrement dit, log2 2 = . On a dj rencontr la notation . Elle reprsente l'entier immdiatement infrieur : 2.1 = 2 et videmment 3 = 3. Complexit O(1) O(log n) O(n) O(n log n) O(n2 ) Type accder au premier lment d'un ensemble de donnes couper un ensemble en deux puis chacun en deux, etc. parcourir un ensemble de n donnes couper rptitivement un ensemble en deux et parcourir chacune des parties parcourir un ensemble de donnes une fois par lment d'un autre ensemble de mme taille gnrer tous les sous-ensembles possibles d'un ensemble de donnes gnrer toutes les permutations possibles d'un ensemble de donnes
O(2n ) O(n!)
10
Aussi, la bonne question poser est que se passe-t-il lorsque la taille des donnes est multiplie par 2 ? Si n est la taille des donnes (de taille quivalente) du problme6 , disons qu'un algorithme qui s'excute en : O(log n) est quasi-instantan (algorithme sub-linaire ), O(n) ou O(n log n) est trs rapide (algorithme linaire ), O(n2 ) ou O(n3 ) commence tre lent, O(nk ) pour k > 3 devient trs lent et souvent impraticable.
La qualit d'un algorithme se mesure sa complexit mais aussi sa clart et sa simplicit. Un algorithme complexe sera sources d'erreurs de programmation (dures dceler et qui prennent donc plus de temps au programmeur). De plus, on mesure la complexit en ngli geant les constantes multiplicatives aussi un algorithme en O(n n) pourra tre meilleur qu'un concurrent en O(n 2 ) (par exemple si ce dernier est alambiqu et si sa constante multiplicative est trs grande).
11
Fig. 2 Johann von Neumann (1903 - 1957) devant le premier ordinateur de l'Institute
of
L'innovation de von Neumann tient en cette numrisation de l'algorithme. Ds lors, donnes et algorithmes rsident en mmoire, cte cte et l'UAL est capable de beaucoup plus que de simple calculs : elle interprte l'algorithme sous sa forme numrise.
12
assez barbare, on programme dans des langages plus volus (plus proches du langage humain), dits langages de haut niveau qui sont ensuite traduits en assembleur puis le rsultat est traduit en langage machine. Une autre forme de cette stratication se retrouve dans la notion de fonction et dans celle de bibliothque. Plutt que de rcrire chaque fois les mmes squences de code pour faire telle ou telle tche usuelle (enregistrer un chier sur le disque, le monter en mmoire, etc.), des bibliothques de fonctions ont t mises au point. Une fonction est un morceau de programme que l'on peut appeler par un nom en fournissant ventuellement des paramtres, la manire d'une fonction mathmatique. Une autre forme encore de stratication se retrouve dans l'architecture des systmes d'exploitations ; les systmes bien conus fonctionnent comme suit : le noyau est l'interface entre le matriel et le reste du monde, les programmes sont des processus part, qui font appel au noyau pour les tches fondamentales (accs au matriel par exemple). Les programmes orent en particulier l'interface utilisateur (interface graphique, shell, . . .).
1.7 - Conclusion
13
1.7 Conclusion
Le paysage est le suivant : un programmeur doit rsoudre un problme donn. Sa premire raction sera de s'aranchir de l'environnement pour se demander comment le rsoudre dans l'absolu. Il mettra donc au point un algorithme puis il en valuera les performances. Pour cette dernire tche, il a sa dispoition un cadre thorique que l'on vient d'esquisser. Ceci fait, il devra implmenter son algorithme pour obtenir un programme excutable qu'il livrera l'usager aprs moult tests et au moins autant de corrections (ventuellement de l'algorithme lui-mme). La qualit du produit ni, le programme, dpendra fortement des machines sur lesquelles ce dernier sera utilis et surtout des ressources dont elles disposent. Il ne viendrait l'ide de personne (sauf des constructeurs informatiques) de livrer des programmes utilisables uniquement sur des machines dernier cri, gves de RAM et quipes d'un CPU on ne peut plus puissant.
2 Rcursivit
2.1 Exemple
Un algorithme rcursif s'appelle lui-mme. Considrons la fonction factorielle : elle associe un entier positif n le nombre n! = 1.2. . . . .(n 1).n.
Ici, pour calculer n!, on calcule n.(n 1)!. Le calcul de (n 1)! est le mme que celui de n!, seules les donnes ont changes. Comme elles diminuent chaque fois et que l'on dispose des conditions initiales 1! = 1 et 0! = 1 (par dnition), l'algorithme termine videmment. Notez que ce type d'algorithme se dcompose en deux phases : une phase descendante pour dterminer chacun des termes valuer puis une remonte pour assembler ces rsultats. La phase de descente s'arrte parce que l'on dispose d'une condition d'arrt. Cet exemple est particulirement simple et on ne voit gure o peut apparatre un quelconque problme. En fait, il est trs lent du fait qu'il ncessite n appels Factorielle-rec et 2n tests. De
14
2. Rcursivit
plus, il demande beaucoup de mmoire. Souvenons-nous que chaque appel de fonction demande de crer une zone dans la pile et d'y enregistrer direntes valeurs. En eet, aprs avoir eectu tous les appels pour arriver la condition d'arrt, il faut renvoyer les dirents rsultats pour chacun des appels. Il y a donc une phase de descente puis une phase de remonte consistant essentiellement vider la pile.
22
= 65536 donc :
2
.2 ..
65536
Finalement, A(5, 1) est normment plus grand que le nombre d'atomes de l'Univers ( seulement 1080 ). Le lecteur sceptique pourra tenter d'excuter ack.c (cf. gure 3) non sans oublier que sa machine fonctionne en arithmtique entire modulo 232 (voire 264 ).
Exercice 2.2.3 Pourquoi A(5, 1) ne peut-il pas tre calcul sur un ordinateur ? Exercice 2.2.4 crire l'algorithme de calcul de A(4, n). Remarque 2.2.5 Ces algorithmes rcursifs sont mauvais du fait, on l'a dit, du cot des appels
de fonctions. En eet, lorsqu'un programme appelle une fonction, cela ncessite de nombreux accs la mmoire (qui est trs lente par rapport au processeur) pour y enregistrer entre autres les variables et l'adresse de retour de la fonction. Il faut voir l'espace mmoire du programme comme une pile. chaque appel de fonction, on empile dessus. Pour obtenir le rsultat, il faut donc dpiler. La machine doit donc empiler un certain nombre de fois, puis dpiler autant de
2.3 - Ranements
15
#include <stdlib.h> #include <limits.h> #include <stdio.h> long compteur; unsigned long ack (unsigned long m, unsigned long n) { compteur++; if (0 == m) { return n + } else if (0 == n) return ack } else { return ack }
int main (int argc, char *argv[]) { unsigned long i, j; i = strtoul (argv[1], (char**)NULL, 10); j = strtoul (argv[2], (char**)NULL, 10); compteur = 0; printf ("A(%u,%u) = %u\n", i, j, ack (i, j)); printf ("Appels a ack() : %u\n", compteur); exit(EXIT_SUCCESS);
fois. On se mera comme de la peste des fonctions qui s'appellent plusieurs fois elles-mmes (ici 2).
Remarque 2.2.6 La terminaison d'un algorithme rcursif n'a rien de triviale. Pour vous en
2.3 Ranements
Voici une manire bien meilleure d'implmenter la fonction factorielle :
Algorithme 2.3.1
16
Factorielle-iter(n) 1 i 1, m 1. 2 si n = 0 ou n = 1, aller en [4]. 3 i i + 1, m m.i. 4 si i < n aller en [3]. Sinon renvoyer m. Nous utiliserons dsormais la forme suivante, plus proche des langages de programmation actuels : Factorielle-iter(n) m=1 Si n = 0 et n = 1, alors : Pour i = 2 jusqu' i = n, faire : m = m.i renvoyer m
Certains algorithmes rcursifs sont pourtant bons. Il s'agit des cas o la phase de remonte est inutile. Ces cas apparaissent quand l'appel rcursif est l'instruction nale d'une fonction et si le rsultat n'est terme d'aucune expression. On dit que tout appel est rcursif terminal. Soit la fonction : : N N N avec (n, m) = m si n = 0 ou n = 1 et (n, m) = (n 1, nm) sinon. La relation : (n, 1) = n! est vidente et permet par l'entremise de une rcursion terminale bien plus ecace.
Exercice 2.3.2 Se convaincre du gain par rapport Factorielle-iter. crire au besoin l'algorithme dtaill. Que vaut (5, 1) ?
3.1 Tableaux
Un tableau est une suite indexe de donnes de mme type9 , stocke de manire contige en mmoire. Par exemple, on rencontrera souvent des tableaux de chanes de caractres et des tableaux d'entiers. C'est un type simple que l'on utilise souvent et il tient plus de l'outil de base que de la structure de donnes avance.
Remarque 3.1.1 Malheureusement (heureusement ?), les langages dirent aussi me faut-il
m'arrter un instant sur certaines spcicits des langages.
9
La notion de type est vidente : les donnes sont soient des entiers, soient des caractres, etc.
3.2 - Listes
17
Certains langages de programmation n'orent pas de type chane de caractres. Ainsi, en C, on utilise un tableau de caractres pour reprsenter une chane tandis qu'en Pascal on dispose du type string, en Java des objets String, etc. Selon le langage utilis on peut ou non redimensionner la vole un tableau au cours de l'excution d'un programme. Il se peut donc que l'on doive dterminer l'avance (lors de l'criture du programme) de combien de mmoire on aura besoin. Selon les langages, les tableaux commencent 0 (C, C++, Java, Perl) ou 1 (Pascal, Fortran). Ici, ils commenceront 0.
Remarque 3.1.2 Lorsque l'on dclare un tableau, il faut indiquer sa taille. Certains langages
permettent de redimensionner la vole un tableau (realloc() en C) mais ce n'est pas le cas gnral. Une ide qui ne marche pas trop mal est d'estimer ses besoins au plus juste (ie. 2 lments) dans un premier temps quitte crer chaque fois que le besoin s'en fait sentir un tableau de taille double pour y recopier les donnes du prcdent. Cette opration est coteuse en temps de calcul (on se souvient que les accs la mmoire sont lents) et en quantit de mmoire mais demeure la fois simple et pas trop mauvaise statistiquement10 mais vite de trop nombreuses recopies. videmment, il faut librer le vieux tableau chaque fois, sans quoi la consommation mmoire devient gargantuesque. tri T, en utilisant la mthode propose dans la remarque 3.1.2. Soit n le plus petit entier vriant : lenght(T) 2n . Que se passe-t-il lorsque l'on ne libre pas la mmoire des tableaux intermdiaires au fur et mesure que l'on ajoute des lments ? Quelle place mmoire mobiliset-on ? Si l'on veut dterminer si un lment est prsent ou non dans tableau, soit on sait que le tableau n'est pas tri auquel cas on en est rduit le parcourir squentiellement.
Exercice 3.1.3 crire le algorithme Add-tab qui ajoute un lment e dans un tableau non-
Exercice 3.1.4 crire un algorithme (dterministe) rcursif pour trouver un lment dans un
tableau tri, oprant en O(log n).
3.2 Listes
Une liste s'apparente un tableau. Outre une donne, un lment d'une liste contient aussi l'adresse de son successeur pour les listes simplement chanes, les adresses de son successeur et de son prdcesseur pour les listes doublement chanes. Enn, on pourra rencontrer des listes circulaires. Elles sont construites comme des listes simplement chanes mais le dernier lment pointe sur le premier. Ces listes permettent de rduire le temps de parcours d'une liste.
Remarque 3.2.1 Le lecteur attentif aura dj not que les listes simplement chanes peuvent
10 Cette remarque est valable pour des manipulations de maillages en deux et trois dimensions. Je ne sais pas ce qu'elle donne statistiquement dans le cas gnral.
ncssiter plus d'oprations lors de la recherche d'un lment que les autres types de listes mais moins d'instructions pour insrer ou supprimer un lment.
18
Ici, les donnes sont alloues dynamiquement : on initialise la liste puis on insre des lments un un. Les lments tant parpills dans la mmoire, il faut savoir au moins o se trouve l'lment suivant. Si l'on perd l'adresse d'un lment, on perd la n de la liste. . . videmment, ce type de structure de donnes ncssite de pouvoir grer la mmoire sa guise, ce que tous les langages ne permettent pas.
Remarque 3.2.2 Le lecteur attentif se demande comment on stocke une adresse. Le plus
souvent par un pointeur. Il s'agit d'un type de donnes particulier qui contient l'adresse d'un mot mmoire. La gestion de ce type de donnes est toujours dlicate ; elle demande toujours soin et rigueur, parfois beaucoup d'expertise. Dans le cadre des listes simplement chanes, on a besoin de marquer la n d'une liste et dans tous les cas, il faudra que l'on sache initialiser correctement une liste. On utilise alors le pointeur nul, sa reprsentation dpend du langage : par exemple en C et C++, sa valeur est NULL, en Pascal NIL, en Java null.
Sous les yeux du public bahi, je vais montrer comment utiliser astucieusement des tableaux et leurs indices. Imaginons la liste doublement chane suivante : {5, 1, 4, 7}. On a d'une part : 5 1, 1 4, 4 7, 7 1 et d'autre part : 7 4, 4 1, 1 5. Considrons trois tableaux de mme taille, le premier contient les donnes, le second les pointeurs suivants et le dernier les elem succ prec 0 5 1 1 pointeurs prcdents, soit : 1 1 4 5 2 4 7 1 3 7 1 4 Ici, on a reprsent le pointeur nul par 1. Une autre mthode consiste n'utiliser qu'un unique tableau. On reprsente alors la valeur et les deux pointeurs par des cases contiges : 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 tab 7 15 1 5 1 9 1 3 15 4 9 0 Le premier lment est tab[3] = 5, le dernier tab[0] = 7. Le suivant de tab[3] = 5 est tab[tab[5]] = tab[9] = 1 tandis que le prcdent est tab[4] = 1.
Exercice 3.2.4 tant donn des fonctions d'allocation Malloc (prend en argument une taille de donnes et renvoie un pointeur sur la zone alloue, NULL en cas d'erreur) de libration Free (prend en argument un pointeur sur une zone alloue), crire les algorithmes : New-lst qui cre une liste simplement chane vide, Dele-lst qui dtruit une liste simplement chane vide, Add-lst-item qui ajoute un lment e dans une liste non-trie, Dele-lst-item qui supprime un lment e d'une liste, Get-lst-next qui renvoie l'lment suivant d'une liste. Reprendre ces algorithmes avec les mthodes indiques dans les remarques 3.1.2 et 3.2.3.
3.3 Arbres
C'est une structure fondamentale, largement utilise en informatique. Les arbres informatiques sont particuliers : leur racine est place en haut et ils poussent vers le bas. Pour le reste,
3.3 - Arbres
19
ils sont comme les vrais : ils ont des nuds et des feuilles. Ici, le facteur de classement est la hirarchie. Chaque lment est appel noeud. Il en est un particulier, plac au sommet de la hirarchie : la racine. Les nuds placs immdiatement dessous dans la hirarchie sont les ls de la racine, lesquels ont pour pre ladite racine. Ces ls ont leurs propres ls et ainsi de suite. Les nuds sans descendance sont aussi appels feuilles. On dnit la profondeur d'un nud comme tant le nombre de nuds (hormis lui-mme) le sparant de la racine. Un nud dans un arbre est, en gnral, reprsent par l'lment lui-mme et un tableau de pointeurs, pour stocker un pointeur vers le pre, un autre vers le ls gauche et un dernier vers le frre droit. Dans la suite de ce paragraphe, je ne considrerai plus que des arbres binaires (chaque nud a au plus deux ls). Plutt que le frre droit, on stockera donc l'adresse du ls droit.
Exercice 3.3.1 Imaginons un arbre binaire dont le dernier niveau est plein ; soit n le nombre
de feuilles. Que dire de n ? Combien l'arbre a-t-il de nuds ? Quelle est sa hauteur (profondeur maximale d'une feuille) ?
Remarque 3.3.2 On note que la recherche dans un arbre est tributaire du nombre de nuds
mais aussi et surtout de sa hauteur.
20
est quilibr gauche. On les stocke en gnral dans un tableau, disons T, dans le mme ordre que lors d'un parcours par niveaux. Autrement dit T[i] a pour ls gauche T[2i + 1], pour ls droit T[2i + 2] et pour pre T[ i1 ]. 2
Exercice 3.3.3 crire les algorithmes Read-heap-pre (resp. Read-heap-in et Read-hep-suf) qui
parcoure un tas par parcours prxe (resp. inxe, suxe). crire un algorithme Read-heap-lev qui parcoure un tas par niveau. Ici, la structure est assez complexe prserver. Voici comment arranger un arbre en tas. Dans un premier temps, il faut, tant donn un tableau T et un indice i (tels que le sous-arbre Tg[i] (resp. Td[i]) ayant pour racine le ls gauche (resp. droit) de T[i] soit un tas) faire en sorte que le sous-arbre de T, de racine T[i], soit un tas.
Entasser(T, i) g Tg[i] d Td[i] Si g Length(T) et T[g] > T[i], alors : max g sinon : max i Si d Length(T) et T[d] > T[max], alors : max r Si max = i, alors : T[i] T[max] Entasser(T,max)
Algorithme 3.3.4
Exercice 3.3.5 Quel est le temps de calcul requis par Entasser pour traiter n lments ?
Pour construire un tas partir d'un tableau, il ne reste plus qu' trier tout le tableau :
Make-tas(T) Pour i = (Length(T)1) jusqu' i = 0, faire : 2 Entasser(T, i)
Algorithme 3.3.6
Exercice 3.3.7 Quel est le temps de calcul requis par Make-tas pour traiter n lments ?
Enn, insrons un lment e dans un tas :
Ins-tas(T,e) Length(T) Length(T) + 1 i Length(T) Tant que i > 0 et T[ i1 ] < e, faire : 2 T[i] T[ i1 ] 2 i i1 2
Algorithme 3.3.8
Exercice 3.3.9 Quel est le temps de calcul requis par Ins-tas pour traiter n lments ?
3.4 - Hachages
21
3.4 Hachages
Le principe d'un hachage est de pouvoir accder n'importe quel lment d'une table en temps constant (ie. en O(1)), y compris si ce dernier se trouve la n. Cette structure permettra des recherches et des tris trs ecaces. Elle gnralise la notion de tableau et utilise des listes chanes. Pour cela, on se donne des clefs et une fonction qui fait correspondre chaque clef un entier. Cet entier sera le code de hachage de la clef et il est calcul l'aide de la fonction de hachage. Le type des clefs est indirent mais la fonction doit toujours renvoyer un entier (qui est un indice dans un tableau).
Remarque 3.4.1 Ce type de structures de donnes est tellement pratique que certains langages Exemple 3.4.2 Considrons l'alphabet = {a, b, . . . , z} et donnons-nous plusieurs mots : fonction, table, hachage et tri. Considrons la fonction a : {0, . . . , 25} qui associe l'initiale son ordre alphabtique. On choisit la fonction de hachage : {0, . . . , 25} dnie par : () = a(0 ). Ainsi, fonction aura pour code 5, hachage 7, table et tri 19 ; on dit que table et tri entrent en collision.
de programmation, comme Perl ou Java, fournissent un type de donnes et/ou des outils pour les manipuler plus aisment, sans avoir rinventer la roue chaque fois.
Le choix d'une fonction de hachage doit donc minimiser les collisions. Pour cela, il vaut mieux choisir un espace de clefs de taille comparable au nombre d'lments. Lorsqu'il n'y a aucune collision possible, on dit que la table est adressage direct mais c'est dicile dans la pratique, pour des raisons videntes d'espace mmoire. mots franais commenant par un c sont trs nombreux, tandis que ceux ayant un z l'initiale sont rares. Elle ne distribuera donc pas les mots de manire uniforme sur l'espace des clefs.
Remarque 3.4.3 La fonction de l'exemple 3.4.2 est mauvaise : en eet, chacun sait que les
22
fonction de hachage est-il fondamental pour approcher l'uniformit. Dans la littrature, toutes les fonctions de hachages prennent des entiers pour argument ; en eet, il est facile de se ramener ce cas et le traitement d'un entier est simple. Par exemple, si l'on a des chanes de caractres manipuler, l'usage du code ASCII ou de l'ordre alphabtique sera probablement la solution. Quant aux fonctions de hachage proprement dites, elles s'inspirent des PRNG11 uniformes classiques bases sur les congruences. Ainsi, une fonction classique est (c) c mod m o m est un entier premier assez loign d'une puissance de 2.
23
Algorithme 4.1.2
Tri-insert(T) Pour j 1, . . . , length(T) 1, faire : temp T[j] ij1 Tant que i > 0 et T[i] > temp, faire : T[i + 1] T[i] ii1 T[i + 1] temp
Dans la boucle sur j , on insre T[j] dans le tableau, tri entre 0 et j 1. La variable temp permet de ne pas perdre la valeur que l'on change.
a peut paratre trivial de le dire mais je vous rappelle que pour changer i et j , ce que j'ai not jusqu'ici i j , les instructions i j , j i ne sauraient convenir. Quelque chose du genre : temp i, i j , j temp donnera de biens meilleurs rsultats ;-)
Exercice 4.1.4 Montrer que le tri par insertion s'excute en O(n2 ) o n = Length(T).
Algorithme 4.3.1
Tri-tas(T) Make-Tas(T) Pour i = Length(T) jusqu' i = 1, faire : T[0] T[i] Length(T) Length(T) 1 Entasser(T)
20) et de Make-tas (cf. l'algortihme 3.3.6, page 20), valuer le temps de calcul de cet algorithme. Fonctionne-t-il sur place ?
Exercice 4.3.2 tant donn le calcul de la complxit de Entasser (cf. l'algortihme 3.3.4, page
24
Un algorithme diviser pour rgner est rcursif. Il dcoupe le problme initial en sousproblmes similaires mais plus petits ( diviser ), rsoud ces sous-problmes ( rgner ) puis combine les rsultats pour obtenir la solution cherche ( combiner ).
Algorithme 4.4.2
o Fusion est laiss la sagacit du lecteur. On dmontre par un calcul assez simple que cet algorithme est en O(n log n). et T[k + 1, . . . , j] avec i k < j soient tris, fusionne ces deux sous-tableaux en un tableau tri T[i, . . . , j]. Fusion devrait tre en O(j i + 1).
Exercice 4.4.3 crire un algorithme Fusion qui, tant donn un tableau T, tel que T[i, . . . , k] Exercice 4.4.4 Comment trier T avec Tri-fusion ? Fonctionne-t-il sur place ?
Algorithme 4.5.1
Reste calculer k . . . Pour cela, on se donne deux sous-tableaux (vides pour commencer) de T[i, . . . , j] (il s'agit de T[i, . . . , n] et T[j, . . . , m] ci-dessous) et un pivot p (on choisit T[i]). On construit les deux sous-tableaux petit petit de sorte que les lments du premier soient plus petits que le pivot et ceux du second plus grand. Au fur et mesure, n croit et m dcrot et l'on
25
doit parfois changer des lments entre les deux sous-tableaux. la n, m vaut le k recherch ci-dessus.
Pivot(T, i, j ) p T[i], n i 1, m j + 1 Tant que VRAI faire : Rpter : mm1 jusqu' ce que T[m] p Rpter : nn+1 jusqu' ce que T[n] p Si n < m, alors : T[n] T[m] Sinon : renvoyer m
Algorithme 4.5.2
Pour amliorer cet algorithme, on le randomise : soit Alea un algorithme qui renvoie un nombre alatoire 0 Alea(r) r (cf. A.1, page 31).
Quicksort-rand(T, i, j ) Si i < j , alors : k Pivot-rand(T, i, j ) Quicksort-rand(T, i, k) Quicksort-rand(T, k + 1, j)
Algorithme 4.5.3
Algorithme 4.5.4
Qu'apporte donc le terme choix stochastique de k ? Dans la version dterministe, il peut arriver qu' chaque itration on ait un sous-tableau d'un unique lment (le tableau de dpart est tri l'envers). Pour obtenir un cas moyen, il faut supposer que les lments sont distribus alatoirement. Le choix stochastique du pivot rtabli cette hypothse. L'algorithme stochastique est en O(n log n). On peut encore l'amliorer en prenant pour pivot p une moyenne12 entre trois valeurs choisies au hasard, c'est la mthode de la mdiane de trois .
26
Algorithme 4.6.1
Exercice 4.6.3 (Trivial) Combien d'oprations faut-il pour trier un tableau de taille donne ?
Quel est l'espace mmoire requis ?
Remarque 4.6.4 L'intrt de ce tri est que l'on ne fait aucune comparaison. Par contre, les Remarque 4.6.5 Stabilit du tri par comptage Soient deux lments gaux dans le tableau
hypthses sur le type de donnes tries sont trs contraignantes mais c'est ce prix que l'on a rduit le nombre d'oprations. Ce sera toujours le cas avec les tris linaires. d'entre T. Si l'on fait bien attention, ils apparraissent dans Tt dans le mme ordre que dans T. Si la dernire boucle est croissante (Pour j = 0 jusqu' j = Length(T) 1. . .), alors l'ordre est invers.
27
5 Recherche de motifs
On prsente ici les techniques lmentaires de recherche de motifs. On pourra poursuivre par l'tude de l'annexe ??, page ?? qui dveloppe des mthodes beaucoup plus abouties et bien moins coteuses. On se souvient que l'on appelle alphabet un ensemble ni non vide. Ses lments s sont des lettres ou des caractres. On note le mot vide (qui ne contient aucune lettre). On note |s| la longueur de s : c'est le nombre de lettres de s.
Algorithme 5.1.2
Rech-motif-naif(m, t) Pour i = 0 jusqu' i = |t| |m|, faire : j 0. Tant que ti+j = mj et j < |m|, faire : j j + 1. Si j = |m|, alors : rpondre i. Rpondre |t|.
C'est simple mais inecace ds que t est peu long. Ici, si une tentative choue, on dcale m vers la droite d'un cran. Lors de chaque tentative, on compare une une chaque lettre de m avec sa correspondante sur la largeur de la fentre dans t. Au pire, on excute la premire boucle |t| |m| + 1 fois et chaque itration, on fait |m| 1 comparaisons.
13
28
5. Recherche de motifs
Exercice 5.1.3
1. Quelle est la complexit (utilisez la notion O(n)) de Rech-motif-naif ? 2. Faire tourner Rech-motif-naif avec y = 1011010110010100101 et x = 1010.
une complexit en moyenne de O(|t| |m|). Comprendre : il n'est pas si mauvais que a dans la pratique.
Horner
t0 .
Il reste un dernier problme de taille : il se peut que et ts deviennent trs grands auquel cas, notre bel dice tombera l'eau. En eet nos machines ont la triste particularit d'tre nies aussi ne calculent-elles que sur 32 ou 64 bits soient au mieux la possibilit de reprsenter un nombre dcimal de 19 chires. . . Plutt que de se lancer dans l'arithmtique des grands entiers qui prend un temps considrable, on va travailler modulo q o q sera choisi de telle sorte que 10q tienne juste dans un mot machine (pour limiter les calculs ncssaires). Dans le cas gnral on a donc : ts+1 q(ts hts+1 ) + ts+|m|+1 mod q avec h 10|m|1 mod q . C'est joli, mais rien ne va plus : avec cette nouvelle formule, ts mod q ne signie pas que ts = . Oui, mais on sait tout de mme que si ts mod q alors ts = . On vitera donc nombre de comparaisons inutiles mais pas toutes. Dans la pratique, on choisit q premier.
Remarque 5.2.2 Le lecteur attentif n'aura pas manqu de noter que le titre de ce paragraphe
a dj pris tout son sel. En fait, on a repris l'algorithme Rech-motif-naif en vitant les dcalages srement inutiles. Il en reste quelques uns qui s'apparentent des collisions et qu'il faut encore traiter.
29
Karp-Rabin(t, m, d, q ) h d|m|1 mod q 0 0 Pour i = 0 jusqu' i = |m|, faire : d + mi mod q d + ti mod q Pour s = 0 jusqu' s = Length(t) Length(m), faire : Si = , alors : Si m0 . . . m|m|1 = ts . . . ts+|m| , alors : Renvoyer s Si s < Length(t) Length(m), alors : q( hts+1 ) + ts+|m|+1 mod q
Algorithme 5.2.3
Remarque 5.2.4 On a vit de stocker inutilement tous les ts en ne manipulant qu'une seule
variable . L'algorithme Karp-Rabin est simple avec la construction qui prcde. On commence par des initialisations : celle de la constante h et celles des variables et . On calcule ensuite et t0 (stock dans par la mthode de Horner rappele la remarque 5.2.1, page 28). Enn, on parcoure le texte t la recherche de possibles occurences de m, en ne vriant que si l'on a l'galit modulo q : = .
Exercice 5.2.5 Quelle est la complexit de Karp-Rabin ? Mzalors, n'aurait-on travaill que
pour la gloire ?
30
6. Conclusion
6 Conclusion
6.1 Pour nir. . .
Les algorithmes sont les outils de base du programmeur. S'il les utilise intelligement, il pourra tirer toute la puissance de sa machine. Pour reprendre l'exemple de Comer et al.14 , imaginons deux programmeurs, l'un amricain riche millions et l'autre, russe, travaillant avec des bouts de celles. Le premier dispose d'une machine ultra-puissante un million de MIPS15 et l'autre d'un vieux coucou peinant un MIPS. Tous deux doivent trier un tableau d'un million d'lments. Le buveur de bourbon utilise un bte tri par insertion tandis que l'amateur de vodka 62 12 prfre le tri par fusion. Finalement, l'excution, l'amricain attend 1012 = 1012 = 1 seconde 10 10
log tandis que le russe patiente 10 106 10 = 6 secondes. Si maintenant ils veulent trier un tableau d'un milliard d'lments, l'amricain a le temps d'cluser les troquets alentours : il lui faudra 2 109 1018 6 secondes (11 jours et demi), tandis que le russe aura son rsultat au bout 12 = 1012 = 10 10 log de 10 106 10 = 9000 secondes (deux heures et demi) soit quelques chopines seulement, pourtant avec un ordinateur bien moins puissant.
9 9 6 6
31
A Manipulations numriques
A.1 Gnration de nombres alatoires
Le sujet est vaste et dlicat, certaines applications critiques reposant sur la qualit d'ala de nombres gnrs par des machines parfaitement dterministes. Dans la majorit des langages de programmation utiliss, on aura sa disposition une source alatoire uniforme (fournie par le systme et/ou le langage) que l'on aura intrt utiliser. Les gnrateurs la fois pas trop mauvais et simples sont des suites entires de congruences linaires : n+1 an + c mod m et on conseille en gnral c = 0, a = 75 et m = 231 117 ; on utilise en gnral une fonction de temps pour gnrer 0 qui doit videmment tre non-nul. Knuth (cf. [Knu97]) propose une plthore d'autres gnrateurs.
/* Crible d'Erathostene * argument : M * resultat : fichier primes.txt contenant les nb premiers < 2*M+1 */ #include <stdlib.h> #include <stdio.h> #include <time.h> #define TRUE ((char)(1==1)) #define FALSE ((char)(!TRUE)) typedef char BOOL; #define setfalse(Tab,i) Tab[i/8] |= (0x01 << (i%8)) ; #define istrue( Tab,i) (!((Tab[i/8] >> (i%8)) &0x01)) int main (int argc, char *argv[]) { if (argc == 1) { printf ("Pas d'arguments... Tchao !\n"); return EXIT_FAILURE; } else { unsigned long M; BOOL *pp = 0; M = atol (argv[1]); pp = calloc (M/8 + 1, sizeof *pp);
Standard minimal de Park et Miller ; pour bien faire, il vaut mieux choisir m premier et assez loin d'une puissance de 2.
17
32
A. Manipulations numriques
printf ("Memoire requise : %ld KB\n", M * sizeof (*pp)/1024); if (!pp) { perror ("\nMemoire insuffisante... exit(1)...\n\n"); } else { unsigned long j, p, q, i; FILE* file = 0; memset (pp, 0, M / 8 + 1); /* True */ j = 0; i = 1; p = 3; q = 4; while (q <= M) { if (istrue (pp, i)) { /* True */ j = q; /* on vire ses multiples */ while (j <= M) { setfalse (pp, j); /* False */ j += p; } } i++; p = 2 * i + 1; q += 2 * p - 2; } file = fopen("primes.txt","w"); if (file == NULL) { fprintf(stderr,"## Erreur : impossible d'ouvrir le fichier ##\n"); return EXIT_FAILURE; } else { for (j = 0; j < M; j++) { if (istrue (pp, j)) fprintf(file,"%lu\n",2*j+1); } } fclose(file); free(pp);
} return EXIT_SUCCESS;
BIBLIOGRAPHIE
33
Bibliographie
[B&M77] [CLR94] [CHL01] [Hoa61] [K&R81]
Boyer R. S. & Moore J. S., (1977), A fast string-searching algorithm, Communications of the ACM, vol. 20, n 10, pp. 762-772. Cormen T., Leiserson C., Rivest R. (1994), Introduction l'Algorithmique, Dunod, Paris.
bert, Paris.
n 7,
pp. 321-322.
Ecient randomized pattern matching algorithms, Technical Report n TR-31-81, Aiken Computation Laboratory, Harvard University.
Kernighan B. W. & Pike R. (1999), The Practice of Programming, Addison Wesley, Reading, Massachusetts. Knuth D. E. (1997), The
Massachusetts.
n 2,
pp. 323-350.
Loudon K. (1999),
Data Structures and Ecient Algorithms, Vol. 1 : Sorting and Searching, EATCS Monographs, Springer Verlag, Berlin.
Mehlhorn K. (1984), Polya G. (1945),
sey.
Numerical Recipes in C, The Art of Scientic Computing, Cambridge University Press, Cambridge. Algorithmes en langage C, Interditions, Paris. Cryptography, Theory and Practice, CRC Press, Boca Raton, Architecture de l'ordinateur, Dunod, Paris.
Florida.
Tanenbaum A. (2001),
Index
Ackermann
fonction, 14 Adressage ouvert, voir Hachage Adresse, 12 Al Khwarizmi, 3 Algorithme, 4 complexit, 8 diviser pour rgner, 24 rcursif, 13 rcursif terminal, 16 terminaison, 4 Alphabet, 5 Arbre, 1820 binaire, 19 de recherche, 19 parcours inxe, 19 parcours prxe, 19 parcours suxe, 19 tas, 1920 Archimde, 3 Binaire, 6 arbre, voir Arbre Caractre, 5 Clef de hachage, voir Hachage Code de hachage, voir Hachage Collision, voir Hachage Cormen, 3
Diophante d'Alexandrie, 3
FIFO, voir File File, 22 Fils, 18 Fonction de hachage, voir Hachage de transition d'une machine de Turing, 5 Hachage, 20, 21 adressage direct, 21 adressage ouvert, 22 clef, 21 collision, 21 facteur de charge, 21 fonction, 21 Hauteur, voir Noeud Heapsort, voir Tri Hoare, 24
Horner
Lettre, 5 LIFO, voir Pile Liste chane, 17 Logarithme, 9 Machine de Turing, voir Turing Miller, 31 MIPS, 30 Mot, 5 longueur, 5 mmoire, 10 vide, 27
Neumann, voir von Neumann
tat d'une machine de Turing, 5 nal d'une machine de Turing, 5 initial d'une machine de Turing, 5 Euclide, 3 Exponentielle, 8 Facteur de charge, voir Hachage Factorielle, 13 Feuille, 18 34
Nud, 18 hauteur, 19
Partie entire infrieure, 7, 9 Pre, 18 Pile, 12, 22 Pointeur, 12, 18 Polynme, 8 Prxe parcours, voir Arbre PRNG, 22 Processus, 12
Pour les autres termes anglais non rpertoris, voir http://wall.jussieu.fr/foldoc/ et http://www.tuxedo.org/ esr/jargon/ Pour les autres termes franais non rpertoris, voir http://sysadmin.eila.jussieu.fr/jargon/