Algorithme 24 novembre. - Montefiore Institute ULg

publicité
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 :')
Téléchargement