You are on page 1of 35

Introduction l'Algorithmique ou Prceptes de programmation (ecace) Pascal CABAUD

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.

Fig. 1  Alan M. Turing (1912-1954), l'un des pres de l'Informatique.

TABLE DES MATIRES

Table des matires


1 Du problme au programme : l'algorithme
1.1 1.2 1.3 1.4 1.5 1.6 Dnition . . . . . . . . . . . Machines de Turing . . . . . . Intrt de cette dnition . . Appart mathmatique . . . . Retour sur les algorithmes . . Informatique : rappels . . . . 1.6.1 Architecture . . . . . . 1.6.2 Programme, systme . 1.6.3 Mmoire et processeur Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 5 7 8 9 10 10 11 12 13 13 14 15 16 17 18 19 19 19 21 21 22 22 22 23 23 24 24 25 26 26 27 28

1.7 2.1 2.2 2.3 3.1 3.2 3.3

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

3 Structuration des donnes

16

3.4 3.5 4.1 4.2 4.3 4.4 4.5 4.6

4 Divers algorithmes de tri

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . dnombrement . . . . . . . . .

22

5 Recherche de motifs
5.1 5.2

Premire approche . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Utilisation d'un hachage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

27

6 Conclusion
6.1 6.2

Pour nir. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Conseils bibliographiques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

30
30 30 31 31

A Manipulations numriques

A.1 Gnration de nombres alatoires . . . . . . . . . . . . . . . . . . . . . . . . . . A.2 Nombres premiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

31

Bibliographie Index

33 34

1 Du problme au programme : l'algorithme


Le mot  algorithme  vient du nom du mathmaticien persan Al Khwarizmi (environ 820 aprs J.C.) dont le trait d'arithmtique permis la diusion en Occident de rgles de calcul sur la reprsentation dcimale des nombres (dcouvertes par les Indiens)1 . Les premiers algorithmes connus remontent pourtant l'Antiquit : l'algorithme d'Euclide (IIIme sicle avant J.C) permettant de dterminer le PGCD de deux nombres, celui d'Archimde (IIIme sicle avant J.C) d'approximer , ceux de Diophante d'Alexandrie (IIIme sicle aprs J.C) de rsoudre des quations en nombres entiers, sans oublier les dirents algorithmes des grecs et des gyptiens permettant de calculer des surfaces. On le voit, l'algorithmique est la lle des Mathmatiques. Elle a beaucoup volu ces cinquante dernires annes du fait de l'mergence de sa petite sur l'Informatique et du boom de la recherche, tant en Mathmatiques qu'en Informatique. Dans toute la suite, la formalisation mathmatique ne dpasse pas le niveau de Mathmatiques xig au Baccalaurat dans les sections littraires mais la formalisation et l'abstraction pourront choquer au premier abord.

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.

1. Du problme au programme : l'algorithme concevable d'exploiter sans risque un ordinateur. 

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

Equation(a, b) Si b = 0, alors : Si a = 0, alors :


Les super-calculateurs actuels cotent plusieurs milliards d'euro, leur(s) processeur(s) tien(nen)t dicilement sur un terrain de tennis et se refroidi(ssen)t l'air liquide (-270 C). . .
3

1.2 - Machines de Turing

sinon :

x = 0. Si a = 0, alors : il y a une innit de solutions.


Si a = 0, alors : il y n'a pas de solution. sinon x = b/a.

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.

1.2 Machines de Turing


Dnition 1.2.1 On appelle alphabet un ensemble ni non vide. Ses lments sont appels lettres ou caractres. On note le mot vide (qui ne contient aucune lettre). On note || la longueur de , c'est le nombre de lettres de . On note l'ensemble des mots compos
partir de .
Une machine de Turing est un ordinateur imaginaire qui nous servira dnir la notion de complexit d'un algorithme : ce sera le nombre d'oprations lmentaires d'une machine de Turing.

Dnition 1.2.2 On appelle machine de

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.

Cf. 1.6.1, page 10.

1. Du problme au programme : l'algorithme

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.

Exercice 1.2.4 crire l'algorithme d'addition.

1.3 - Intrt de cette dnition

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.

1.3 Intrt de cette dnition


De telles machines de Turing permettent de dcrire de manire lmentaire tout problme de calcul ou de dcision. Ces machines ont une mmoire centrale, une unit de calcul, lisent des donnes et les traitent en consquence. En fait, les ordinateurs actuels rpondent cette dnition. On note que si l'on avait crit les nombres de gauche droite, le nombre de dplacements de la tte de lecture/criture auraient t beaucoup plus nombreux. De mme, si l'on n'avait
5

On note x le plus grand entier n tel que n = x x.

1. Du problme au programme : l'algorithme

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 :

n2 1002 = = 0.99 n2 + n + 1 1002 + 100 + 1

1.5 - Retour sur les algorithmes

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!)

1.5 Retour sur les algorithmes


On vient de voir qu'il existe dirents type d'algorithmes. On a aussi largement voqu le temps de calcul de ces algorithmes. Enn, on a vu que si l'entre est un entier n, on mesure la complexit par rapport log2 n. Ainsi, un algorithme qui s'eectue en O(n) instructions est-il exponentiel. Dans la pratique, il est des instructions plus rapides que d'autres : l'aectation, l'addition et la soustraction sont parmi les plus rapides ; la multiplication est assez lente, la division et l'exponentiation encore plus ; l'appel de fonction bat tous les records du fait des lectures/critures en mmoire centrale. Le test dpend des donnes.

10

1. Du problme au programme : l'algorithme

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).

1.6 Informatique : rappels


1.6.1 Architecture
Lorsque Johann von Neumann (1903-1957) se lana dans l'Informatique, il comprit assez vite que les machines de l'poque n'taient que des calculateurs et non pas des machines autonomes. Leur autonomie vient de ce que von Neumann comprit que donnes et algorithmes doivent tout deux rsider en mmoire et non pas tre entrs la main par un oprateur. Pour cela, il fallait reprsenter un algorithme sous forme numrise (Proposition de von Neumann). De plus, les premiers calculateurs travaillaient tous en systme dcimal, ncessitant ainsi un grand nombre de composants et donc d'oprations. Il conut donc (1946, l'EDSAC) la premire machine calculant en binaire et programme enregistr, base de presque toutes les machines actuelles. Elle tait compos de cinq lments :  la mmoire,  l'unit arithmtique et logique,  l'unit de contrle,  l'entre,  la sortie. La mmoire tait dcoupe en mots de n bits (en l'occurence 40), chaque mot disposant d'une adresse. Un mot pouvait contenir un entier ou deux instructions ; chaque instruction contenait un type et une adresse mmoire. Enn, l'UAL contenait un registre (l'accumulateur ). Une instruction permettait ainsi par exemple d'ajouter le contenu d'un mot celui du registre, d'enregistrer le registre dans la mmoire, de charger un mot dans le registre, etc (via leur adresses). L'unit de contrle se chargeait de lire dans la mmoire les instructions et les donnes pour les transmettre l'UAL qui les traitait. Tant l'unit de contrle que l'UAL sont dsormais partie intgrante du processeur.
Ce qui revient au mme ou presque que de considrer le logarithme en base 2 de la longueur des donnes exprimes en binaire. . .
6

1.6 - Informatique : rappels

11

Fig. 2  Johann von Neumann (1903 - 1957) devant le premier ordinateur de l'Institute

Advanced Studies de Princeton.

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.

1.6.2 Programme, systme


Depuis que les ordinateurs sont construits sur le modle de von Neumann, ce sont des machines autonomes. ce titre, elles sont capables de se grer sans intervention humaine pour beaucoup de tches. On a vu apparatre assez vite les premiers langages de programmation. Ces derniers permettent de traduire un code source comprhensible par un humain en une suite de mots machine excutables par la machine (je vous rappelle qu'il s'agit de suites de bits). C'est la mme poque que la notion de systme d'exploitation est apparue. Il s'agit d'un ensemble de programmes permettant une (plus) grande autonomie la machine. Dans ce cadre, l'informatique s'est  stratie  : on n'crit plus de programme directement en binaire mais on utilise le langage assembleur qui est plus comprhensible. Comme c'est encore

12

1. Du problme au programme : l'algorithme

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.6.3 Mmoire et processeur


Il faut voir la RAM 7 comme une bande de cases contenant des entiers, un gros tableau d'entiers. Chaque case a une taille xe. Une case contient un octet8 et est adressable. Par adressable on entend que l'on peut dire la machine d'aller chercher la valeur contenue dans telle ou telle case. Cette dernire y accdera par un pointeur. Un programme est un chier sur le disque. Un processus est le rsultat de l'excution d'un programme. Un processus dispose d'un espace mmoire contenant son code machine, une pile et un tas. Le tas est en bas, la pile en haut ; le tas monte et la pile descend mesure que le programme a besoin de mmoire. La pile contient les informations relatives chaque appel de fonction (qu'il s'agisse d'une fonction du programme ou d'une fonction d'une des bibliothques). La machine y stockera les paramtres passs en argument ladite fonction, de la place pour le rsultat et encore d'autres choses. L'adressage de la mmoire permet des sauts dans les suites d'instructions. En principe le processeur excute les instructions de manire squentielle. Des structures comme

if (condition) instruction else autre_instruction fi


ou
Access Memory. Un octet correspond la taille d'un caractre soit 8 bits sur la majorit des machines actuelles. Il existe des architectures sur lesquelles les octets sont cods sur 7 ou 9 bits. Une autre dnition d'octet est :  unit lmentaire de mmoire  ou  plus petite quantit de mmoire adressable .
7 Random 8

1.7 - Conclusion

13

for i = 0 .. n do instruction(i) done


ncessitent de pouvoir accder tout instant n'importe quel mot machine, qu'il s'agisse d'instructions ou de donnes. Les mots mmoire codant des instructions correspondent des circuits imprims dans le silicium du processeur. Il peut s'agir d'oprations arithmtiques, d'oprations de lecture/criture dans la mmoire, d'instructions de saut, etc.

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.

Algorithme 2.1.1 Problme : Calcul de n! tant donn n.


Factorielle-rec(n) si n = 0 ou n = 1, alors : renvoyer 1 sinon : renvoyer n.Factorielle-rec(n 1)

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.

2.2 Contre exemple


Exemple 2.2.1 Soit la fonction d'Ackermann A : N N N dnie par les relations suivantes :  A(m, n) = A(m 1, A(m, n 1)) si m > 0 et n > 0,  A(m, 0) = A(m 1, 1) si m > 0,  A(0, n) = n + 1 si n > 0.

Exercice 2.2.2 Se convaincre que cette fonction est parfaitement dnie.


Trivialement, A(0, 1) = 2. Que vaut A(1, 1) ? A(1, 1) = A(0, A(1, 0)) = A(0, A(0, 1)) = 2, ce qui a demand quatre appels de fonctions, 6 tests. Hum. . . que vaut A(5, 1) ? On dmontre et nous admettrons que :

A(0, n) = n + 1, A(1, n) = n + 2, A(2, n) = 2n, A(3, n) = 2n , A(4, n) = 22


.2 ..

On a A(5, 1) = A(4, A(5, 0)) or A(5, 0) = A(4, 1) = 22

22

= 65536 donc :
2
.2 ..

A(5, 1) = A(4, 65536) = 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 }

1; { (m - 1, 1); (m - 1, ack (m, n - 1));

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);

Fig. 3  Implmentation en C de la fonction d'Ackermann.

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

convaincre, lisez cette dmonstration de Robert Cori et Jean-Michel Lvy : http://www.enseignement.polytechnique.fr/informatique/TC/polycopie-1.6/main006.html#toc5.

2.3 Ranements
Voici une manire bien meilleure d'implmenter la fonction factorielle :

Algorithme 2.3.1

16

3. Structuration des donnes

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 Structuration des donnes


On a vu que la manire de reprsenter les donnes (en machine ou dans l'abstrait) inue sur l'algorithme. Nous allons maintenant nous attacher tudier quelques structures de donnes classiques. Durant tout ce paragraphe, il faut garder l'esprit que pour chacune des structures suivantes, il faudra savoir crer une structure vide puis y insrer des lments, en eacer, en dplacer, etc. Selon les structures, ces oprations n'auront pas le mme cot en terme de temps de calcul et d'espace mmoire. Souvent, l'implmentation de ces oprations dpendra de l'environnement de programmation (langage, systme).

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

3. Structuration des donnes

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.

Remarque 3.2.3 Comment procder sans pointeurs ?

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) ?

3.3.1 Parcours d'un arbre


Il y a quatre manires de parcourir un arbre. La premire est dite parcours par niveaux et consiste explorer un un tous les nuds de mme profondeur, de gauche droite. Les trois autres sont dnis rcursivement sur l'arbre lui-mme : parcours prxe : on parcoure la racine, puis le sous-arbre de gauche et enn le sous-arbre de droite ; parcours inxe : on parcoure le sous-arbre de gauche, puis le nud racine et enn le sousarbre de droite ; parcours postxe : on parcoure le sous-arbre de gauche, puis celui de droite et enn la racine.

3.3.2 Arbres de recherche


Pour faire une recherche ecace dans un arbre, il faut des informations prcises sur la hirarchie utilise. Dans un arbre de recherche, on utilise une relation d'ordre (ordre numrique, alphabtique, lexicographique, etc.). Quand on rencontre un nud suprieur, on suit le ls gauche et pour un nud infrieur, le ls droit. videmment, il faut avoir enregistr les nuds de sorte que cette hirarchie soit respecte (ou il faut trier l'arbre, suivre. . .).

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.

3.3.3 Des arbres particuliers : les tas


Il s'agit d'arbres de recherche tris de sorte que le plus grand lment soit aisment accessible. Ce type d'arbres,  est tel que chaque nud a une valeur infrieure celle de son pre,

20

3. Structuration des donnes

 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

3.4.1 O l'on retrouve les listes chanes


On stocke les lments dans un tableau de listes chanes. Chaque case du tableau est appel conteneur, c'est une liste chane d'lments stocker. L'indice dans le tableau correspond au code de hachage. La recherche de la position d'un lment ncessite donc le calcul de son code, puis le parcours du conteneur. Si un code est sujet un grand nombre de collisions, il y aura beaucoup d'lments dans la liste et le parcours de cette dernire prendra du temps. On cherche donc distribuer uniformment les lments dans les conteneurs, de sorte qu'ils soient tous de taille comparable et raisonnable. videmment, s'il y a peu de conteneurs et beaucoup d'lments, les listes sont longues. On dnit le facteur de charge par = e/c o e est le nombre d'lments et c le nombre de conteneurs o les lments peuvent tre distribus. Il s'agit en fait du nombre moyen d'lments par conteneur. Comme de bien entendu, on ne parviendra que rarement une distribution uniforme dans les conteneurs et ce facteur de charge n'est qu'une moyenne, aussi le choix d'une

22

4. Divers algorithmes de tri

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.

3.4.2 Tables de hachages adressage ouvert


Il est dicile de redimensionner la vole un tableau, de part sa nature statique. Dans quelques cas il peut tre indispensable d'avoir sa disposition une table de taille xe. Il n'est alors plus question de liste chane ni de conteneur et on est contraint stocker les lments mme un tableau. On a alors un srieux problme avec les collisions. On va donc utiliser une fonction de hachage donnant un facteur de charge < 1. On note dores et dj que cela implique une consommation de mmoire importante d'autant plus que certaines cases du tableau seront vides.

3.5 Piles & les


Une pile permet de traiter les donnes d'une source (votre programme, un autre, un chier, etc.) dans l'ordre LIFO (Last In, First Out ou  dernier arriv, premier parti ). Une le permet de traiter les donnes d'une source dans l'ordre FIFO (First In, First Out, autrement dit dans l'ordre o les donnes ont t transmises). On peut utiliser des listes simplement chanes ou tout btement des tableaux pour reprsenter ces structures.

4 Divers algorithmes de tri


Il est un algorithme que les Shadocks n'auraient pas reni : le bogo -tri. Prenez un jeu de cartes et regardez s'il est tri. S'il ne l'est pas, jettez le par terre et recommencez. La probabilit de le ramasser tri approche de un mesure que le temps de calcul approche de cinq fois l'ge de l'Univers, aussi conviendrez vous que le temps de calcul est inacceptable. Notez au passage que ce n'est pas un algorithme au sens de la dnition 1.1.1.

4.1 Tri par insertion


C'est un algorithme assez bon sur de petits ensembles de donnes. Il s'agit d'un tri sur place autrement dit, on ne manipule qu'une seule structure. Il formalise la manire dont un joueur de cartes trie une donne : il prend un tas de cartes en vrac et, de gauche droite, les range par ordre croissant.

Exercice 4.1.1 Quel est l'intrt d'un tri sur place ?


11

Pseudo-Random Number Generator, cf. A.1 page 31.

4.2 - Tri bulle

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.

Remarque 4.1.3 changer deux valeurs

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).

4.2 Tri bulle


Il s'agit d'un autre algorithme inecace en O(n2 ). Il consiste changer deux deux les lments voisins pour les classer. Le nom de cet algorithme rappelle des bulles remontant la surface d'un verre d'une quelconque boisson base de houblon ou de malt.

Exercice 4.2.1 crire l'algorithme du tri bulle. Fonctionne-t-il sur place ?

4.3 Tri par tas ou heapsort


On se donne un tableau T que l'on veut trier. On peut utiliser une structure de tas comme on va le voir. On commence par transformer le tableau en tas. On sait alors que le plus grand lment est T[0] que l'on change avec le dernier et l'on dcrmente la taille du tableau en s'assurant que c'est encore en tas ; en itrant, le tour est jou :

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

4. Divers algorithmes de tri

4.4 Tri par fusion


Ce type de tri s'applique aux tableaux. Le tri par fusion est le prototype des algorithmes de type  diviser pour rgner .

Remarque 4.4.1 Diviser pour rgner

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

Tri-fusion(T,i,j ) Si i < j , alors : k i+j 2 Tri-fusion(T, i, k ) Tri-fusion(T, k + 1, j ) Fusion(T, i, j , k )

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 ?

4.5 Tri rapide ou quicksort


Il est d C.A.R. Hoare (1960). Il n'est pas trs bon dans le pire des cas (O(n2 )), mais il s'avre souvent le meilleur dans la pratique. C'est encore un algorithme  diviser pour rgner . Soit un sous-tableau non-vide T[i, . . . , j]. Le principe est :  diviser  : de partitionner T[i, . . . , j] en deux sous-tableaux T[i, . . . , k] et T[k + 1, . . . , j] non-vides et tels que chaque lment du premier soit plus petit que tout lment du second ;  rgner  : de trier les deux sous-tableaux par le mme algorithme ;  combiner  : de. . . ne rien faire : T[i, . . . , j] est tri puisque les deux sous-tableaux le sont !

Algorithme 4.5.1

Quicksort(T, i, j ) Si i < j , alors : k Pivot(T, i, j ) Quicksort(T, i, k ) Quicksort(T, k + 1, j )

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

4.6 - Tris linaires

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

Pivot-rand(T, i, j ) l Alea(j i) + i T[i] T[l] Retourner Pivot(T, i, j )

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 .

Remarque 4.5.5 En C, on utilisera qsort(), dclar dans <stdlib.h>.

4.6 Tris linaires


Ces algorithmes amliorent encore la limite O(n log n) mais ne sont malheureusement pas applicables tout type de donnes. En eet, on dmontre que les prcedents algorithmes qui
12

Moyenne arithmtique videmment.

26

4. Divers algorithmes de tri

utilisent tous des comparaisons eectuent au pire O(n log n) oprations.

4.6.1 Tri par comptage ou par dnombrement


Soit un tableau de n entiers compris entre 0 et k 1. Pour chaque lment e, l'algorithme dtermine le nombre d'lments qui lui sont infrieurs et place e en fonction.
Tri-compt(T, Tt, k ) Pour i = 0 jusqu' i = k 1, faire : Ttemp[i] 0 Pour j = 0 jusqu' j = Length(T) 1, faire : Ttemp[T[j]] Ttemp[T[j]] + 1 Pour i = 1 jusqu' i = k 1, faire : Ttemp[i] Ttemp[i] + Ttemp[i 1] Pour j = Length(T) 1 jusqu' j = 0, faire : Tt[Ttemp[T[j]]] T[j] Ttemp[T[j]] Ttemp[T[j]]

Algorithme 4.6.1

Exercice 4.6.2 (Trivial) Est-ce un tri sur place ?


Dans la premire boucle sur i, on initialise le tableau temporaire Ttemp. Puis, on comptabilise dans Ttemp[i] le nombre d'lments gaux i (premire boucle sur j ). Dans la boucle suivante (sur i), on comptabilise maintenant les lments infrieurs ou gaux i dans Ttemp[i]. Enn, il ne reste plus qu' placer les lments dans Tt, qui sera tri quand on aura ni. T[i] va dans Tt[Ttemp[T[i]]] (car il y a alors Ttemp[T[i]] lments infrieurs ou gaux i). Pour trater le cas o tous les lments ne sont pas distincts, on dcrmente Ttemp[i].

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.

4.6.2 Tri par base


Le tri par base est un hritage des trieuses de cartes perfores d'aprs Cormen et al. (cf. [CLR94], paragraphe 9.3, page 174). On considre ici encore des entiers c chires stocks dans un tableau T. On se donne une base d < c et on considre les entiers du tableau comme des nombres exprims dans la base d.

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.

5.1 Premire approche


Exercice 5.1.1 crire un algorithme Length qui prend en argument une chane de caractres et renvoie sa longueur.
On veut rechercher un mot m dans un texte t13 . On note |m| la longueur de m et |t|, la longueur de |t|. On utilise la technique dite des fentres glissantes Il s'agit de faire glisser m le long de t vers la droite. Il existe de nombreuses variantes. En eet, l'algorithme peut calculer lors de chaque tentative la longueur du prochain dcalage (pour rduire le nombre de tentatives) et/ou de mmoriser certaines informations (pour rduire le nombre de tests). On fera au plus |t| |m| tentatives.

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

t n'est rien de plus qu'un mot.

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.

Remarque 5.1.4 On dmontre et nous admettrons que l'algorithme 5.1.2 Rech-motif-naif a

une complexit en moyenne de O(|t| |m|). Comprendre : il n'est pas si mauvais que a dans la pratique.

5.2 Utilisation d'un hachage


On se donne un alphabet et des mots sur cet alphabet. On interprte ces derniers comme des entiers reprsents en base d = ||. Pour simplier, prenons = {0, . . . , 9} mais ce qui suit reste valable pour tout alphabet. On va noter la reprsentation dcimale de m et ts celle du sous-mot ts . . . ts+|m|1 . videmment, ts = si m est un sous-mot de t la position s. On peut crire un polynme P sous la forme : P (x) = a0 +x(a1 +x(a2 +. . .+x(an1 +xan ) . . .)). L'avantage est que le calcul de P (x0 ) se fera aprs O(n) additions et mulitplications et vite les exponentiations. On a que = m0 + 10(m1 + . . . + 10(m|m|2 + 10m|m|1 ) . . .) et une formule similaire donne En regardant attentivement cette formule pour ts , on note que le calcul de ts+1 se dduit de celui de ts : en eet, ts+1 = 10(ts 10|m|1 ts+1 ) + ts+|m|+1 . De plus, 10|m|1 est une constante que nous rutiliserons aussi n'est-il pas indispensable de la recalculer chaque itration mais on la stockera l'aide d'une constante. Par quel miracle cela fonctionne-t-il ? Avec le terme 10|m|1 ts+1 on fait disparatre le chire de gauche de ts , en multipliant par 10, on dcale le tout vers la gauche et en ajoutant ts+|m|+1 on remplace le 0 insr par la multiplication par 10 par le chire suivant, ie. ts+|m|+1 ; il n'y a donc rien de divin l-dedans.

Remarque 5.2.1 Rgle de

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.

5.2 - Utilisation d'un hachage

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

6.2 Conseils bibliographiques


Pour poursuivre l'tude de l'algorithmique, on pourra se plonger dans [CLR94] pour une solide introduction ou dans LA rfrence : [Knu97]16 . [CHL01] ore une tude approfondie des principaux algorithmes de manipulation de textes : index, recherches de motifs, . . . Dans [NR2.1], la lecture du chapitre 7.1 pourra tre utile pour choisir un PRNG. On trouvera normment de ressources sur Internet dont en particulier l'annuaire du NIST : http://www.nist.gov/dads/ qui recense tous les algorithmes connus. De plus, sur le site personnel de Thierry Lecroq on trouvera l'annuaire Exact string matching algorithms (avec des animations en Java) de Thierry Lecroq et Christian Charras. On peut consulter [NR2.1] en ligne : http://www.nr.com/. Plus gnralement, on trouve des dizaines de cours, de polycopis, etc. sur le Web. Citons :  le cours de Jean-Jacques Lvy et Robert Cori l'cole Polytechnique : http://www.enseignement.polytechnique.fr/informatique/TC/polycopie-1.6/,  une liste des liens divers concernants l'algorithmique, tous plus fabuleux les uns que les autres : http://brassens.upmf-grenoble.fr/IMSS/limass/algoprog/algoref.html,  de nombreux cours d'informatique rpertoris et classs : http://dept-info.labri.u-bordeaux.fr/ dicky/EXOS/,  le serveur du SPEDAGO : http://spedago.unice.fr (apparemment teint en ce moment).

14 [CLR94], pp. 15-16. 15 Millions of Instructions 16

Per Second.  Je vois qu'on a sorti le vitriol ! 

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.

A.2 Nombres premiers


Le programme suivant donne les premiers nombres premiers.

/* 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.

Crochemore M., Hancart C., Lecroq T. (2001),

Algorithmique du texte, VuiCommu-

nications of the ACM, vol. 4,

Hoare C. A. R. (1961), Algorithm 63 (partition) and algorithm 65 (nd),

n 7,

pp. 321-322.

Karp R. M., Rabin M. O. (1981),

Ecient randomized pattern matching algorithms, Technical Report n TR-31-81, Aiken Computation Laboratory, Harvard University.

[K&P99] [Knu97] [KMP77] [Lou99] [Meh84] [Pol45] [NR2.1]

Kernighan B. W. & Pike R. (1999), The Practice of Programming, Addison Wesley, Reading, Massachusetts. Knuth D. E. (1997), The

Massachusetts.

Art of Computer Programming, Addison-Wesley, Reading, SIAM

Knuth D. E., Morris J. H., Pratt, V. R. (1977), Fast pattern in strings,

Journal of Computing, vol. 6,

n 2,

pp. 323-350.

Loudon K. (1999),

Mastering Algorithms with C, O'Reilly, Sebastopol, California.

Data Structures and Ecient Algorithms, Vol. 1 : Sorting and Searching, EATCS Monographs, Springer Verlag, Berlin.
Mehlhorn K. (1984), Polya G. (1945),

sey.

How to Solve It, Princeton University Press, Princeton, New Jer-

Press W. H., Teukolsky S. A., Vetterling W. T. & Flannery B. P. (1992),

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.

[Seg91] [Sti95] [Ta01]

Sedgewick R. (1991), Stinson D. (1995),

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

mthode, 28 Inxe parcours, voir Arbre


Karp, 29

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

INDEX Octet, 12 Opration lmentaire d'une machine de Turing, 8


Park, 31

35 machine de, 5 Type, 4


von Neumann, 10

Partie entire infrieure, 7, 9 Pre, 18 Pile, 12, 22 Pointeur, 12, 18 Polynme, 8 Prxe parcours, voir Arbre PRNG, 22 Processus, 12

machine de, 10 proposition de, 10

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/

Quicksort, voir Tri


Rcursion terminale, voir Algorithme Rabin, 29 Racine, 18 Randomiser, 25 Recherche, voir Arbre Recherche de motif, 2629 Suxe parcours, voir Arbre Table de hachage, voir Hachage Tableau, 16 Tas, 12, voir Arbre Tri, 2226 bogo, 22 bulle, 23 linaire, 25 par base, 26 par comparaisons, 25 par comptage, 26 par dnombrement, 26 par fusion, 23 par insertion, 22 par tas, 23 rapide, 24 stable, 26 sur place, 22 Turing, 1

You might also like