Programme de révision n°2 sur «programmation et algorithmique»
1 Cours
1.1 Programme précédent
Instructions de base, affectation, structures conditionnelles, structures itératives.
1.2 Notion de tableau
1. Un tableau est une suite finie de valeurs d’un même type (entier, flottant, booléen ...), stockées dans des cases mémoires contigües. On parle de liste en Python. On obtient sa longueur avec la fonction len (diminutif de lenght). Par exemple t = [4,6,5,8,7] est un tableau d’entiers de longueur 5.
On peut accéder aux éléments d’un tableau et les modifier (contrairement par exemple à une chaîne de caractère que l’on ne peut pas modifier). Ceux-ci sont repérés par leur indice : attention le premier élément est celui d’indice 0, (penser à un ascenceur). Par exemple, t[0]vaut 4, et le dernier élément t[4] vaut 7. Si l’on tape t[2] = 14, la liste t est modifiée et vaut t = [4,6,14,8,7].
2. Comment construire des listes ?
(a) la méthode append : on peut ajouter un élément à la fin d’une liste à l’aide de la méthodeappend. L’instructiont.append(4)ne renvoie pas une nouvelle liste, elle modifie la liste existante (une liste Python est un objet dynamique). A privilégier par rapport à la concaténation.
(b) les comprehension list : l’instruction ci-dessous crée la liste t = [1,9,25,49,81] : t= [k**2 for k in range(10): if k % 2 ==1]
(c) Le tableau vide est noté [], et on peut créer un tableaut longueur n (ne contenant par exemple que des 0) à l’aide det = [0] * n(concaténation) ou de t = [0 for i in range(n)] (comprehension list).
3. Quelques pythonneries :
(a) on peut itérer une liste : for element in liste:.
(b) le slicing
4. Attention aux «copies» d’un tableau On considère le script suivant : t = [4,5,6]
t2 = t
t3 = t[ : ] # shallow copy t[0] = 7
Alors l’élementt2[0]vaudra aussi 7 au lieu de 4. Ceci provient de la nature de l’affectation en Python. L’affectation t2 = t n’a pas réalisé de copie de la liste [4,5,6]. On a juste rajouté dans l’espace des noms un nouveau nomt2 associé. Les noms t ett2 sont deux étiquettes d’un même objet la liste [4,5,6], ce qui est confirmé en demandant id(t) et id(t2) qui sont les mêmes. En revanche, le tableau t3 n’aura pas été modifié. Un autre objet a été créé en mémoire, et on lui a associé le nom t3.id(t3) est différente.
5. Tableaux à deux dimensions ou matrices
On peut modéliser une matrice comme une liste de listes. Par exemple, pour écrire la matrice A= 4 5 8
2 1 7
!
, on peut écrire la liste de ses lignes : A = [ [4,5,8], [2,1,7]
].
AinsiA[0][1]est l’élément de la ligne d’indice 0 et de la colonne d’indice 1, soit le nombre 5. De même, A[1][2] vaut 7.
Les comprehension list sont utiles pour construire des matrices. Par exemple, pour la matrice nulle à 3 lignes et 4 colonnes, M= [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]on écrira :
M = [ [ 0 for j in range(4)] for i in range(3)]
Attention, à ne pas utiliser M = [ [0]*4 ] *3 , car il y a contamination si l’on effectue par exemple la modification M[0][1] = 5.
1.3 Complexité et preuves en algorithmique
Ce qu’il faut savoir faire :
1. Indiquer la complexité temporelle d’un algorithme (souvent dans le pire des cas) : loga- rithmique, linéaire, quadratique, exponentielle...
2. Prouver la terminaison d’un algorithme (dans le cas d’une boucle «tant que»). On pourra souvent raisonner par l’absurde en supposant que l’algorithme boucle indéfiniment et exhiber par exemple une suite d’entiers positifs strictement décroissante ce qui n’existe pas.
3. Prouver un algorithme à l’aide d’un invariant de boucle : c’est une propriété qui si elle est vraie en début de boucle, reste vraie en fin de boucle.
4. Connaître le principe d’une méthode de dichotomie, prouver sa terminaison et calculer sa complexité qui est logarithmique.
2 Exercices modèles
2.1 Quelques algorithmes modèles
1. Écrire une fonction maximumqui renvoie le plus grand élément d’un tableau.
def maxi(t):
"""Données: t un tableau d’entiers non vide Résultat: le maximum des éléments de t"""
n =len(t) # la longueur du tableau t maximum = t[0]
for k in range(1,n):
if t[k] > maximum:
maximum = t[k]
return maximum
2. Programmer des suites récurrentes d’ordre 1 mais aussi d’ordre 2 :
Exemple : fonction fibo prenant en entréen∈Net renvoyant le nombre de Fibonacci d’in- dicen. Complexité temporelle linéaire :n−1 additions et complexité spatiale constante : 3 variables.
def fibo(n):
if n == 0 or n == 1:
return n f1 = 0
f2 = 1
for i in range(0,n-1): # n-1 itérations temp = f1 + f2
f1 = f2 f2 = temp return(f2)
3. Programmer une suite récurrente du type suite de Catalan : les nombres de Catalan Cn sont définies parC0 = 1 et
∀n∈N∗, Cn=
n−1
X
k=0
CkCn−1−k
def catalan(n):
c = [0]*(n+1) # tableau de longueur n+1 c[0]= 1
for i in range(1, n+1):
# calcul de c[i]
s = 0
for k in range(0, i): # pour k de 0 à i-1 s = s + c[k]*c[i-1-k]
# on met à jour la valeur dans le tableau la valeur de c_i c[i] = s
return(c[n])
4. Construire une matrice pour calculer les termes d’une suite à deux variables :
Exemple : triangle de Pascal, on construit le tableau constituée des lignes de n à 0 à 10, et on affiche la ligne d’indice 10.
n = 10
pascal = [ [0 for j in range(n+1)] for i in range(n+1)]
for i in range(n+1): # on remplit la première colonne de 1 pascal[i][0] = 1
for i in range(1, n+1):
for j in range(1, i+1): # si j > i le coeff binomial j parmi i vaut 0 pascal[i][j] = pascal[i-1][j-1] + pascal[i-1][j]
print(pascal[10])
Cela renvoie [1, 10, 45, 120, 210, 252, 210, 120, 45, 10, 1]
5. Connaître le principe d’une méthode de dichotomie et calculer sa complexité logarith- mique.
2.2 Exos modèles
1. Déterminer en fonction de npour chaque script le nombre de fois où les instructionstruc etbidule sont exécutées.
# script 1
for i in range(n):
truc
for j in range(n):
bidule
# script 2
for i in range(n):
truc
for j in range(n):
bidule
# script 3
for i in range(n):
truc
for j in range(i,n):
bidule 2. Démontrer la terminaison et déterminer la complexité des algorithmes suivants :
n = 256 while n>0:
n = n-2
n = 256 while n>0:
n = n//2 # quotient de n par 2
3. Prouver l’algorithme d’exponentiation rapide, en utilisant l’invariant de bouclepae =xn def expo_rapide(x,n):
"""Données: x un entier et n un entier naturel Résultat: l’entier x puissance n"""
p = 1 # p comme produit
a = x # nombre que l’on exponentie e = n # e comme exposant
while e != 0:
if e % 2 == 1:
p = p * a
e = e-1 e = e // 2 a = a * a return p
4. Calcul de complexité lors d’une dichotomie, exemple du juste prix from random import randint
n = 100000
justeprix = randint(1,n) a = 1
b = n
nbre_reponses = 0
# on va maintenir invariant que le justeprix est compris au sens large entre a et b
# on va faîre décroître strictement la quantité b-a pour sortir de la boucle.
while b-a >=0: # tant qu’il y a une réponse possible rep = (a+b)//2
if rep == justeprix:
print("la bonne réponse est:", rep)
break # # on est tombé sur la bonne réponse, on sort de la boucle elif rep > justeprix:
b = rep - 1 else:
a = rep + 1 nbre_reponses += 1
# arrivé ici, il n’y a plus de réponse possible, on a donc trouvé le juste prix print("le nbre de réponses est:", nbre_reponses)
print(justeprix)
A chaque itération, la quantité b−a+ 1 est au moins divisée par 2, donc au bout de k itérations, elle est inférieure à n/2k donc inférieure à 1 dès que 2k dépasse n, donc pour k >log2(n). Dans ce cas, b−a+ 1<1, ie b−a <0. L’algo s’arrête. On effectue donc au plus log2(n) + 1 itérations.