Algorithme 24 novembre. # Stack def newStack(): return [] def push(stack, elem): stack.append(elem) def pop(stack): return stack.pop() def top(stack): return stack[-1] import sys import stack parens = {'(':')', '[':']', '{':'}'} leftParens = stack.newStack() string = sys.argv[1] for char in string: if char in parens: stack.push(leftParens, char) elif char in parens.values(): if len(leftParens) == 0: print "No left parenthesis corresponding to",char break elif parens[stack.top(leftParens)] == char: stack.pop(leftParens) else: print stack.top(leftParens), "does not match", char break else: if len(leftParens) > 0: print "No right parentheses for:", leftParens import sys permet d’accéder aux arguments de ligne de commandes. Temps de calcul du programme. Fonction push.append est probablement implémentée pour tourner en temps constant. Ex : si on a un tableau, à chaque nouvelle insertion dans le tableau, on devrait recopier tous les éléments précédents, donc à chaque ajout, le temps de calcul serait proportionnel à la longueur du tableau. Temps constant pour : 1. Append 2. Pop 3. Indexation 4. Parens. Un dictionnaire n’est pas symétrique, on peut consulter ses clés d’une manière efficace mais si on cherche un élément ( pas une clé) alors il n’est pas efficace. Pour consulter une clé, on le fait avec un temps constant indépendamment des valeurs stockées dans un dico ; ce qui est remarquable. La performance d’un programme est définie en fonction de la taille de l’entrée ; ici, une chaîne de caractères. « Parens » contient 3 paires de parenthèses et ne variera donc jamais donc temps constant. Une pile c’est une liste ; pour savoir le temps que prend Python pour calculer sa longueur , il faut consulter la documentation de Python mais Constant. En conclusion, le programme tourne avec un temps linéaire en fonction de la taille de la chaîne de caractères introduits par l’utilisateur. Exemples de récursions. Factoriel En math : n ! = { 1 si n=0 { n.(n-1) ! sinon En Python : def factorial (n) : if n ==0 : Return 1 Return n*factorial (n-1) => condition d’arrêt donc n ≥ 0 import sys print factorial (int(sys.argv[1])) Explications : Factorial (3) Factorial (3) 3* factorial (2) 3* factorial (2) 3.2 Factorial (2) 2*factorial (1) 2.1 Factorial (1) 1*factorial (0) Factorial (0) = 1 1.1 1 Nous pouvons remarquer que le programme se répartit en diverses instances pour pour pouvoir calculer le factoriel demandé. Chaque instance a ses propres variables. En fait, c’est l’instance factorial (0) = 1 qui permet au programme de calculer le factoriel. Comme on connaît le résultat de factorial (0) on connaît celui de factorial (1),… Le nombre d’instances est limité car chaque instance prend un peu de mémoire à l’ordinateur, après un certain nombre d’instance, l’ordinateur n’a plus de mémoire et refuse donc d’effectuer le factoriel. De plus, vu que la profondeur de récursion dans la vie réelle reste normalement limitée, Python impose une limite à la profondeur permise en supposant qu’un dépassement constitue évidence d’un bogue. Factorial(100) fonctionne au contraire de factorial (1000) Plus grand commun diviseur En math : pgcd (a, b) = { b si a = 0 { pgcd (b%a, a) sinon En Python : def gcd (a, b) : if a ==0 : return b return gcd (b%a, a) import sys print gcd (int( sys.argv[1]), int( sys.argv[2])) Le programme fonctionne tout aussi bien si a<b ou si a>b. Fibonnaci En math : fib (k) = {k si k {0,1} { fib (k-2) + fib (k-1) sinon En Python : def fib (k) : if k <= 1 : return k return fib (k-2) + fib (k-1) import sys for k in range (int( sys.argv[1])) : print fib (k) Mais il subsiste un manque grave d’efficacité car la profondeur de recursion ici est de plus ou moins , il y a donc beaucoup trop de répètitions. fib (4) fib(2) fib(0) + fib(1) + fib (3) fib (1) + fib (2) fib (0) + fib (1) On remarque ici que l’arbre s’agrandirait de plus en plus si k était très grand et l’on remarque qu’il y a beaucoup de répéètitions. Cela prouve que la récursion n’est pas toujours efficace. Graphique récursif En Python : # Graphique récursif import turtle def drawH (x, y, radius): turtle.goto (x - radius, y) turtle.down () turtle.goto (x + radius, Y) turtle.up () turtle.goto (x - radius, y - radius) turtle.down () turtle.goto (x - radius, y + radius) turtle.up () turtle.goto (x + radius, y - radius) turtle.down () turtle.goto (x + radius, y + radius) turtle.up () def htree (x, y, radius, depth, maxDepth): if depth < maxDepth : drawH (x, y, radius) htree (x - radius, y - radius, radius/2, depth + 1, maxDepth) htree (x + radius, y - radius, radius/2, depth + 1, maxDepth) htree (x - radius, y + radius, radius/2, depth + 1, maxDepth) htree (x + radius, y + radius, radius/2, depth + 1, maxDepth) import sys turtle.up() turtle.speed ('fastest') htree (0,0,150, int(sys.argv [1])) raw_input ('Hit return to quit :')