Algorithmique et programmation
Une version article du chapitre pour comprendre l'essentiel rapidement, vérifier si le niveau correspond, puis basculer vers Wilo pour la pratique guidée et le suivi.
Lecture
6 chapitres
Un parcours éditorialisé et navigable.
Pratique
12 questions
Quiz et cartes mémoire à ouvrir après la lecture.
Objectif
Terminale générale
Format rapide pour vérifier si le chapitre correspond.
Chapitre 1
Introduction à l'Algorithmique
Qu'est-ce qu'un algorithme ?
Un algorithme est une séquence finie et non ambiguë d'instructions qui, une fois exécutées, permettent de résoudre un problème donné ou d'accomplir une tâche spécifique. Imaginez une recette de cuisine : c'est un algorithme pour préparer un plat !
Caractéristiques principales d'un algorithme :
- Fini : Il doit toujours se terminer après un nombre fini d'étapes. Pas de boucles infinies !
- Déterministe : Pour les mêmes entrées, il doit toujours produire les mêmes sorties. Le résultat est prévisible.
- Clair et non ambigu : Chaque instruction doit être comprise sans interprétation possible.
- Efficace : Il doit résoudre le problème en un temps raisonnable et avec des ressources limitées (même si ce n'est pas toujours le plus rapide ou le plus court).
Exemples d'algorithmes du quotidien :
- Suivre un itinéraire GPS.
- Préparer une tasse de café.
- Trier des cartes par ordre croissant.
- Rechercher un mot dans un dictionnaire.
Représentation d'un algorithme
Pour exprimer un algorithme, on peut utiliser différentes méthodes :
- Langage naturel : C'est la manière la plus simple, mais elle peut manquer de précision. Utile pour une première ébauche.
- Exemple : "Pour trouver le plus grand nombre dans une liste, je parcours chaque nombre, et si je trouve un nombre plus grand que le plus grand que j'ai vu jusqu'à présent, je le retiens."
- Pseudo-code : C'est un langage intermédiaire entre le langage naturel et un langage de programmation. Il utilise des structures de contrôle (SI... ALORS, TANT QUE, POUR) mais sans se soucier de la syntaxe exacte d'un langage précis. Il est très utilisé pour concevoir des algorithmes.
- Exemple :
FONCTION trouver_max(liste_nombres) : max_actuel = premier élément de liste_nombres POUR CHAQUE nombre DANS liste_nombres : SI nombre > max_actuel ALORS : max_actuel = nombre RETOURNER max_actuel
- Exemple :
- Organigrammes : Ce sont des représentations graphiques de l'algorithme, utilisant des symboles standards pour les opérations, les décisions, etc. Ils sont moins utilisés en Terminale mais la notion est utile.
- Symboles de base :
- Ovale : Début/Fin
- Parallélogramme : Entrée/Sortie (lecture/affichage)
- Rectangle : Traitement/Opération
- Losange : Décision (condition SI... ALORS)
- Flèches : Sens d'exécution
- Symboles de base :
Variables et types de données
En programmation, une variable est un espace de stockage nommé en mémoire qui peut contenir une valeur. Cette valeur peut changer au cours de l'exécution du programme.
Définition d'une variable : On peut voir une variable comme une boîte étiquetée. L'étiquette est le nom de la variable, et la boîte contient une valeur.
Types de données courants : Le type d'une variable détermine la nature des valeurs qu'elle peut stocker et les opérations que l'on peut effectuer dessus.
- Entier (
int) : Nombres entiers (positifs, négatifs, zéro).- Exemples :
5,-10,0
- Exemples :
- Flottant (
float) : Nombres décimaux (à virgule).- Exemples :
3.14,-0.5,1.0
- Exemples :
- Chaîne de caractères (
str) : Séquences de caractères (texte). Elles sont toujours entourées de guillemets simples ou doubles.- Exemples :
"Bonjour",'Python',"123"(c'est du texte, pas un nombre !)
- Exemples :
- Booléen (
bool) : Représente une valeur de vérité, soitTrue(vrai), soitFalse(faux).- Exemples :
True,False
- Exemples :
Affectation de valeurs :
L'opérateur d'affectation est =. Il permet de donner une valeur à une variable.
age = 18 # age est un entier
taille = 1.75 # taille est un flottant
nom = "Alice" # nom est une chaîne de caractères
est_majeur = True # est_majeur est un booléen
Opérateurs et expressions
Les opérateurs sont des symboles qui réalisent des opérations sur des opérandes (valeurs ou variables). Une expression est une combinaison d'opérateurs et d'opérandes qui produit une valeur.
Opérateurs arithmétiques : Pour les calculs numériques.
| Opérateur | Description | Exemple Python | Résultat |
|---|---|---|---|
+ | Addition | 5 + 3 | 8 |
- | Soustraction | 10 - 4 | 6 |
* | Multiplication | 2 * 6 | 12 |
/ | Division | 15 / 3 | 5.0 |
// | Division entière | 15 // 4 | 3 |
% | Modulo (reste) | 15 % 4 | 3 |
** | Puissance | 2 ** 3 | 8 |
Opérateurs de comparaison : Pour comparer des valeurs. Ils retournent un booléen (True ou False).
| Opérateur | Description | Exemple Python | Résultat |
|---|---|---|---|
<mark> | Égal à | 5 </mark> 5 | True |
!= | Différent de | 5 != 3 | True |
< | Inférieur à | 5 < 3 | False |
> | Supérieur à | 5 > 3 | True |
<= | Inférieur ou égal à | 5 <= 5 | True |
>= | Supérieur ou égal à | 5 >= 3 | True |
Opérateurs logiques : Pour combiner des expressions booléennes.
and(ET) :Truesi toutes les conditions sont vraies.- Exemple :
(age > 18) and (permis <mark> True)
- Exemple :
or(OU) :Truesi au moins une des conditions est vraie.- Exemple :
(jour </mark> "Samedi") or (jour == "Dimanche")
- Exemple :
not(NON) : Inverse la valeur de vérité.- Exemple :
not (est_majeur)(siest_majeurestTrue,not est_majeurestFalse)
- Exemple :
Chapitre 2
Structures de Contrôle Fondamentales
Séquence d'instructions
La séquence d'instructions est la structure la plus simple : les instructions sont exécutées les unes après les autres, dans l'ordre où elles apparaissent dans le code, du haut vers le bas. C'est l'exécution linéaire par défaut.
- Ordre des opérations : L'ordre est crucial. Changer l'ordre peut modifier le résultat.
a = 10 b = 5 somme = a + b # Instruction 1 a = 20 # Instruction 2 print(somme) # Affiche 15, car somme a été calculée avant que 'a' ne change - Blocs d'instructions : En Python, les blocs d'instructions sont définis par l'indentation (espaces ou tabulations au début de la ligne). Toutes les instructions d'un même bloc doivent avoir le même niveau d'indentation.
Structures conditionnelles (Si... Alors... Sinon)
Les structures conditionnelles permettent d'exécuter différentes parties du code en fonction de la véracité d'une condition.
- Condition simple (
if) :age = 20 if age >= 18: print("Vous êtes majeur.") # Ce bloc est exécuté si la condition est vraie print("Fin du programme.") - Condition avec alternative (
if... else) :temperature = 25 if temperature > 30: print("Il fait très chaud !") else: print("La température est agréable.") # Ce bloc est exécuté si la condition est fausse - Conditions multiples (
if... elif... else) : Pour gérer plusieurs cas.elifest l'abréviation de "else if".note = 12 if note >= 16: print("Très bien") elif note >= 12: # Cette condition est testée SEULEMENT si la première est fausse print("Bien") elif note >= 10: print("Passable") else: print("Insuffisant") - Imbrication de conditions : On peut placer une structure conditionnelle à l'intérieur d'une autre. L'indentation est essentielle.
heure = 14 ouvert = True if ouvert: if heure >= 9 and heure <= 18: print("Le magasin est ouvert.") else: print("Le magasin est fermé (en dehors des heures d'ouverture).") else: print("Le magasin est fermé.")
Boucles bornées (Pour)
Les boucles bornées (ou boucles for) sont utilisées lorsque l'on sait à l'avance combien de fois une suite d'instructions doit être répétée.
-
Itération sur une plage de valeurs : En Python, la fonction
range()est très utile pour générer des séquences de nombres.range(n): génère des nombres de0àn-1.range(début, fin): génère des nombres dedébutàfin-1.range(début, fin, pas): génère des nombres dedébutàfin-1avec un certainpas.
-
Exemple avec
range():# Compter de 0 à 4 for i in range(5): print(i) # Affiche 0, 1, 2, 3, 4 # Compter de 1 à 5 for j in range(1, 6): print(j) # Affiche 1, 2, 3, 4, 5 # Compter de 0 à 10 par pas de 2 for k in range(0, 11, 2): print(k) # Affiche 0, 2, 4, 6, 8, 10 -
Compteur de boucle : La variable
i(ouj,kdans les exemples ci-dessus) est le compteur de boucle. Elle prend successivement chaque valeur de la séquence générée.
Boucles non bornées (Tant que)
Les boucles non bornées (ou boucles while) sont utilisées lorsque l'on ne sait pas à l'avance combien de fois la boucle doit s'exécuter. La répétition continue tant qu'une certaine condition est vraie.
- Condition de continuation : La boucle s'exécute tant que la condition spécifiée est
True. Dès qu'elle devientFalse, la boucle s'arrête.compteur = 0 while compteur < 5: # La boucle continue tant que compteur est inférieur à 5 print(compteur) compteur = compteur + 1 # Incrémentation essentielle pour que la condition devienne fausse un jour print("Boucle terminée.") - Risque de boucle infinie : Si la condition de continuation ne devient jamais fausse, la boucle ne s'arrête jamais. C'est une erreur logique courante !
# Exemple de boucle infinie (NE PAS EXÉCUTER SANS SAVOIR COMMENT L'ARRÊTER !) # x = 0 # while x < 5: # print(x) # x ne change jamais, donc x < 5 est toujours vrai - Utilisation de
whileen Python :mot_de_passe_correct = "secret" mdp_saisi = "" while mdp_saisi != mot_de_passe_correct: mdp_saisi = input("Veuillez saisir le mot de passe : ") if mdp_saisi != mot_de_passe_correct: print("Mot de passe incorrect. Réessayez.") print("Accès autorisé !")
Chapitre 3
Fonctions et Modularité
Définition et appel de fonctions
Une fonction est un bloc de code réutilisable qui effectue une tâche spécifique. Elle permet de découper un programme complexe en parties plus petites et gérables, améliorant la lisibilité et la maintenance.
-
Rôle d'une fonction :
- Réutilisabilité : Éviter de répéter le même code.
- Modularité : Diviser un problème en sous-problèmes.
- Lisibilité : Rendre le code plus facile à comprendre.
- Maintenance : Simplifier les modifications (un bug corrigé à un seul endroit).
-
Syntaxe de définition (déclaration) en Python : On utilise le mot-clé
def, suivi du nom de la fonction, de parenthèses (pour les paramètres) et d'un double point:. Le corps de la fonction est indenté.def saluer(): # Définition de la fonction saluer sans paramètres print("Bonjour !") print("Bienvenue.") -
Appel de fonction : Pour exécuter le code d'une fonction, il faut l'appeler par son nom, suivi de parenthèses.
saluer() # Appel de la fonction saluer # Affiche : # Bonjour ! # Bienvenue.
Paramètres et arguments
-
Paramètres : Ce sont les variables définies dans la déclaration de la fonction, entre les parenthèses. Ils agissent comme des placeholders pour les valeurs que la fonction recevra.
-
Arguments : Ce sont les valeurs réelles que l'on passe à la fonction lors de son appel. Ces valeurs sont affectées aux paramètres correspondants.
-
Passage de paramètres :
def afficher_message(nom): # 'nom' est un paramètre print(f"Bonjour, {nom} !") afficher_message("Alice") # "Alice" est l'argument passé au paramètre 'nom' afficher_message("Bob") # "Bob" est un autre argument -
Arguments par position et par mot-clé :
- Par position : Les arguments sont appariés aux paramètres dans l'ordre où ils sont définis.
def addition(a, b): return a + b resultat = addition(5, 3) # 5 est pour 'a', 3 est pour 'b' print(resultat) # Affiche 8 - Par mot-clé : On spécifie le nom du paramètre lors de l'appel. L'ordre n'a alors pas d'importance.
def afficher_info(nom, age): print(f"{nom} a {age} ans.") afficher_info(age=30, nom="Carla") # L'ordre des arguments n'importe plus # Affiche : Carla a 30 ans.
- Par position : Les arguments sont appariés aux paramètres dans l'ordre où ils sont définis.
-
Valeurs par défaut des paramètres : On peut définir une valeur par défaut pour un paramètre. Si l'argument correspondant n'est pas fourni lors de l'appel, la valeur par défaut est utilisée.
def saluer_personne(nom="invité"): # 'invité' est la valeur par défaut pour 'nom' print(f"Bonjour, {nom} !") saluer_personne("David") # Affiche : Bonjour, David ! saluer_personne() # Affiche : Bonjour, invité !
Valeurs de retour
Une fonction peut calculer un résultat et le renvoyer à l'endroit où elle a été appelée.
- Instruction
return: Utilisée pour spécifier la valeur que la fonction doit renvoyer. Dès qu'unreturnest exécuté, la fonction s'arrête et renvoie la valeur.def carre(nombre): return nombre * nombre # La fonction renvoie le carré du nombre resultat_carre = carre(4) # La valeur 16 est renvoyée et stockée dans resultat_carre print(resultat_carre) # Affiche 16 print(carre(5)) # Affiche 25 - Fonctions sans retour explicite : Si une fonction ne contient pas d'instruction
return, elle renvoie implicitementNone.def afficher_bonjour(): print("Bonjour") valeur = afficher_bonjour() print(valeur) # Affiche "Bonjour", puis "None" - Retour de plusieurs valeurs (tuple) : En Python, une fonction peut renvoyer plusieurs valeurs en les regroupant dans un tuple.
def obtenir_coordonnees(): x = 10 y = 20 return x, y # Renvoie un tuple (10, 20) pos_x, pos_y = obtenir_coordonnees() # Déballage du tuple dans deux variables print(f"X: {pos_x}, Y: {pos_y}") # Affiche : X: 10, Y: 20
Portée des variables (locale et globale)
La portée d'une variable détermine où elle est accessible dans un programme.
- Variables locales : Une variable définie à l'intérieur d'une fonction est locale à cette fonction. Elle n'est accessible qu'à l'intérieur de celle-ci. Elle est créée lorsque la fonction est appelée et détruite lorsque la fonction se termine.
def ma_fonction(): variable_locale = 10 # Variable locale print(variable_locale) ma_fonction() # Affiche 10 # print(variable_locale) # Générerait une erreur : NameError, variable_locale n'est pas définie ici - Variables globales : Une variable définie en dehors de toute fonction (au niveau principal du script) est globale. Elle est accessible de partout dans le programme, y compris à l'intérieur des fonctions.
variable_globale = 100 # Variable globale def ma_fonction_globale(): print(variable_globale) # Accès à la variable globale ma_fonction_globale() # Affiche 100 print(variable_globale) # Affiche 100 - Impact sur la modularité et la lisibilité :
- Il est généralement préférable d'utiliser des variables locales et de passer les données nécessaires aux fonctions via des paramètres, et de récupérer les résultats via
return. Cela rend les fonctions plus indépendantes (modulaires) et plus faciles à tester. - L'utilisation excessive de variables globales peut rendre le code difficile à suivre et à déboguer, car n'importe quelle partie du programme peut modifier une variable globale, ce qui peut avoir des effets inattendus.
- Il est généralement préférable d'utiliser des variables locales et de passer les données nécessaires aux fonctions via des paramètres, et de récupérer les résultats via
Chapitre 4
Structures de Données Simples
Listes (tableaux dynamiques)
Une liste est une collection ordonnée et modifiable d'éléments. Les éléments d'une liste n'ont pas besoin d'être du même type.
- Définition et création d'une liste : Les listes sont définies par des crochets
[]et les éléments sont séparés par des virgules.ma_liste = [10, 20, 30, 40] noms = ["Alice", "Bob", "Charlie"] melange = [1, "deux", 3.0, True] liste_vide = [] - Accès aux éléments (indexation) : Les éléments d'une liste sont indicés à partir de
0pour le premier élément. On utilise les crochets[]pour accéder à un élément.ma_liste[0]: premier élémentma_liste[len(ma_liste) - 1]ouma_liste[-1]: dernier élément
fruits = ["pomme", "banane", "cerise"] print(fruits[0]) # Affiche "pomme" print(fruits[2]) # Affiche "cerise" print(fruits[-1]) # Affiche "cerise" (le dernier élément) - Opérations courantes :
- Ajout (
append(),insert()) :fruits.append("datte") # Ajoute à la fin : ["pomme", "banane", "cerise", "datte"] fruits.insert(1, "orange") # Insère à l'index 1 : ["pomme", "orange", "banane", "cerise", "datte"] - Suppression (
remove(),pop(),del) :fruits.remove("banane") # Supprime la première occurrence de "banane" dernier_fruit = fruits.pop() # Supprime et renvoie le dernier élément (par défaut) del fruits[0] # Supprime l'élément à l'index 0 - Modification :
fruits[0] = "abricot" # Remplace "pomme" par "abricot" - Longueur (
len()) :print(len(fruits)) # Affiche le nombre d'éléments
- Ajout (
Parcours de listes
Parcourir une liste signifie accéder à chacun de ses éléments, généralement pour effectuer une opération sur eux.
- Boucle
foravec index : Utile si on a besoin de l'index de l'élément.nombres = [10, 20, 30] for i in range(len(nombres)): print(f"L'élément à l'index {i} est {nombres[i]}") - Boucle
forsur les éléments : Plus idiomatique en Python, simple et élégant quand on n'a pas besoin de l'index.noms = ["Alice", "Bob", "Charlie"] for nom in noms: print(f"Bonjour, {nom} !") - Méthodes de parcours (
enumerate) : Si on a besoin à la fois de l'index et de l'élément.couleurs = ["rouge", "vert", "bleu"] for index, couleur in enumerate(couleurs): print(f"La couleur {couleur} est à la position {index}.")
Chaînes de caractères
Une chaîne de caractères est une séquence ordonnée et immuable de caractères. "Immuable" signifie qu'une fois créée, une chaîne ne peut pas être modifiée. Toute opération qui semble la modifier crée en fait une nouvelle chaîne.
- Définition et propriétés :
message = "Hello World!" print(message[0]) # Accès par index : Affiche 'H' print(len(message)) # Longueur : Affiche 12 # message[0] = 'h' # Erreur ! TypeError: 'str' object does not support item assignment (immuabilité) - Opérations courantes :
- Concaténation (
+) :prenom = "Jean" nom = "Dupont" nom_complet = prenom + " " + nom print(nom_complet) # Affiche "Jean Dupont" - Découpage (slicing) : Permet d'extraire une sous-chaîne.
[début:fin:pas]message[0:5]: du début jusqu'à l'index 4 (exclut l'index 5)message[6:]: de l'index 6 jusqu'à la finmessage[:5]: du début jusqu'à l'index 4message[::2]: tous les deux caractèresmessage[::-1]: inverse la chaîne
phrase = "Python est amusant" print(phrase[0:6]) # Affiche "Python" print(phrase[10:]) # Affiche "amusant" print(phrase[::-1]) # Affiche "tnasuma tse nohtyP"
- Concaténation (
- Méthodes de chaînes : Python offre de nombreuses méthodes intégrées pour manipuler les chaînes.
str.upper(),str.lower(): convertir en majuscules/minusculesstr.strip(): supprimer les espaces blancs en début et finstr.split(separateur): diviser une chaîne en une liste de sous-chaînesstr.replace(ancien, nouveau): remplacer des occurrencesstr.find(sous_chaine): trouver l'index de la première occurrence (retourne -1 si non trouvé)str.count(sous_chaine): compter le nombre d'occurrences
texte = " Hello Python " print(texte.strip().upper()) # Affiche "HELLO PYTHON" mots = texte.strip().split(" ") print(mots) # Affiche ['Hello', 'Python']
Tuples
Un tuple est une collection ordonnée et immuable d'éléments. La principale différence avec les listes est l'immuabilité : une fois créé, un tuple ne peut pas être modifié (ajout, suppression, modification d'éléments).
-
Définition et propriétés : Les tuples sont définis par des parenthèses
()(souvent optionnelles si les virgules sont présentes).mon_tuple = (1, 2, 3) couleurs_rgb = (255, 0, 0) # Un tuple pour représenter une couleur RGB point = 5, 10 # Les parenthèses sont souvent omises tuple_un_element = (42,) # VIRGULE ESSENTIELLE pour un tuple à un seul élément- Accès par index : Comme les listes.
mon_tuple[0]->1 - Longueur :
len(mon_tuple)->3 - Immuabilité : On ne peut pas faire
mon_tuple[0] = 5.
- Accès par index : Comme les listes.
-
Cas d'utilisation :
- Lorsque la collection d'éléments ne doit pas changer (ex: coordonnées d'un point, date de naissance).
- Pour retourner plusieurs valeurs d'une fonction (comme vu précédemment).
- Comme clés dans des dictionnaires (les listes ne peuvent pas être des clés de dictionnaire car elles sont modifiables).
-
Différences avec les listes :
| Caractéristique | Liste ([]) | Tuple (()) |
|---|---|---|
| Mutabilité | Modifiable (mutable) | Non modifiable (immuable) |
| Syntaxe | Crochets [] | Parenthèses () |
| Performance | Légèrement plus lent | Généralement plus rapide |
| Utilisation | Collections d'éléments variables | Collections d'éléments fixes |
Chapitre 5
Algorithmes de Traitement et de Recherche
Algorithmes de tri (introduction)
Les algorithmes de tri permettent d'organiser les éléments d'une liste (ou d'un tableau) selon un certain ordre (croissant, décroissant).
-
Principe du tri par sélection :
- Trouver le plus petit élément de la partie non triée de la liste.
- L'échanger avec le premier élément de la partie non triée.
- Répéter l'opération sur la partie restante non triée jusqu'à ce que toute la liste soit triée.
- Idée : Sélectionner le minimum et le placer au bon endroit.
def tri_selection(liste): n = len(liste) for i in range(n): # Trouver l'indice du minimum dans la partie non triée min_idx = i for j in range(i + 1, n): if liste[j] < liste[min_idx]: min_idx = j # Échanger le minimum trouvé avec l'élément courant liste[i], liste[min_idx] = liste[min_idx], liste[i] return liste -
Principe du tri par insertion :
- On considère que le premier élément est déjà trié.
- Pour chaque élément suivant (à partir du deuxième) :
- On le compare avec les éléments déjà triés, en reculant.
- On décale les éléments plus grands que lui vers la droite.
- On insère l'élément à sa place correcte dans la partie déjà triée.
- Idée : Construire la liste triée un élément à la fois.
def tri_insertion(liste): for i in range(1, len(liste)): cle = liste[i] # L'élément à insérer j = i - 1 # Déplacer les éléments plus grands que 'cle' vers la droite while j >= 0 and cle < liste[j]: liste[j + 1] = liste[j] j -= 1 liste[j + 1] = cle # Insérer 'cle' à sa bonne place return liste -
Comparaison de l'efficacité (notions) :
- L'efficacité d'un algorithme est souvent mesurée par le nombre d'opérations qu'il effectue en fonction de la taille de l'entrée (). C'est ce qu'on appelle la complexité algorithmique.
- Pour les tris par sélection et par insertion, dans le pire des cas, la complexité est en (prononcé "grand O de n carré"). Cela signifie que si la taille de la liste double, le temps d'exécution peut quadrupler. Ils sont efficaces pour de petites listes mais deviennent lents pour de grandes listes.
Recherche séquentielle
La recherche séquentielle (ou linéaire) est l'algorithme de recherche le plus simple.
- Principe : Il consiste à parcourir tous les éléments d'une liste un par un, du début à la fin, jusqu'à ce que l'élément recherché soit trouvé ou que toute la liste ait été parcourue.
def recherche_sequentielle(liste, element): for i in range(len(liste)): if liste[i] == element: return i # Renvoie l'indice si l'élément est trouvé return -1 # Renvoie -1 si l'élément n'est pas trouvé - Cas favorable et défavorable :
- Cas favorable (meilleur cas) : L'élément recherché est le premier de la liste. L'algorithme effectue une seule comparaison.
- Cas défavorable (pire cas) : L'élément recherché est le dernier de la liste, ou il n'est pas présent du tout. L'algorithme doit parcourir toute la liste, effectuant comparaisons (où est la taille de la liste).
- Implémentation en Python : (voir ci-dessus)
Recherche dichotomique (sur liste triée)
La recherche dichotomique est un algorithme de recherche beaucoup plus efficace que la recherche séquentielle, mais elle a une précondition essentielle : la liste doit être triée.
-
Principe de division :
- On compare l'élément recherché avec l'élément du milieu de la liste.
- Si l'élément du milieu est celui recherché, on l'a trouvé.
- S'il est plus petit, on sait que l'élément (s'il existe) se trouve dans la première moitié de la liste.
- S'il est plus grand, l'élément se trouve dans la deuxième moitié.
- On répète le processus sur la moitié pertinente de la liste jusqu'à trouver l'élément ou jusqu'à ce que la sous-liste devienne vide.
- Idée : Diviser par deux le problème à chaque étape.
-
Précondition : La liste doit impérativement être triée (croissant ou décroissant).
-
Implémentation et efficacité :
def recherche_dichotomique(liste_triee, element): gauche = 0 droite = len(liste_triee) - 1 while gauche <= droite: milieu = (gauche + droite) // 2 # Division entière if liste_triee[milieu] == element: return milieu # Élément trouvé elif liste_triee[milieu] < element: gauche = milieu + 1 # L'élément est dans la moitié droite else: droite = milieu - 1 # L'élément est dans la moitié gauche return -1 # Élément non trouvé- L'efficacité de la recherche dichotomique est en (logarithmique). Cela signifie que le nombre d'opérations augmente très lentement avec la taille de la liste. Pour une liste de 1 million d'éléments, il ne faut qu'environ 20 comparaisons au maximum ! C'est beaucoup plus rapide que la recherche séquentielle pour de grandes listes.
Algorithmes sur les chaînes de caractères
Les chaînes de caractères sont des séquences, et on peut y appliquer des algorithmes similaires à ceux sur les listes, en tenant compte de leur immuabilité.
- Comptage de caractères : Compter le nombre d'occurrences d'un caractère ou d'une sous-chaîne.
texte = "abracadabra" compte_a = texte.count('a') # Utilisation de la méthode intégrée print(compte_a) # Affiche 5 # Algorithme manuel : compteur = 0 for char in texte: if char == 'b': compteur += 1 print(compteur) # Affiche 2 - Recherche de sous-chaînes : Vérifier si une chaîne contient une autre chaîne.
phrase = "Le chat et la souris" if "chat" in phrase: # Opérateur 'in' print("Le mot 'chat' est présent.") pos = phrase.find("souris") # Méthode find() if pos != -1: print(f"Le mot 'souris' commence à l'index {pos}.") - Manipulation de chaînes : (Voir section sur les chaînes de caractères, méthodes
replace,split, etc.)- Un algorithme peut consister à nettoyer une chaîne (supprimer des caractères indésirables, normaliser la casse), extraire des informations (parser une date), ou formater du texte.
date_brute = " 25/12/2023 " date_nettoyee = date_brute.strip() parties_date = date_nettoyee.split('/') print(f"Jour : {parties_date[0]}, Mois : {parties_date[1]}, Année : {parties_date[2]}")
Chapitre 6
Débogage et Bonnes Pratiques
Types d'erreurs
Comprendre les différents types d'erreurs est la première étape pour les corriger.
-
Erreurs de syntaxe (
SyntaxError) : Ce sont des erreurs de grammaire du langage Python. Le programme ne peut même pas démarrer. L'interpréteur Python les détecte avant l'exécution.- Exemples : Oubli d'un
:après unifoudef, parenthèse non fermée, mot-clé mal orthographié.
# if True # Manque le ':' # print("Vrai")- Le message d'erreur indique souvent la ligne et la nature de l'erreur.
- Exemples : Oubli d'un
-
Erreurs d'exécution (exceptions) : Ces erreurs se produisent pendant l'exécution du programme. Le code est syntaxiquement correct, mais une opération invalide est tentée.
- Exemples :
NameError: Utilisation d'une variable non définie.TypeError: Opération effectuée sur un type de données incompatible (ex: ajouter un nombre à une chaîne).IndexError: Accès à un index de liste ou de chaîne qui n'existe pas.ZeroDivisionError: Division par zéro.
# print(x) # NameError: name 'x' is not defined # "hello" + 5 # TypeError: can only concatenate str (not "int") to str # ma_liste = [1, 2] ; print(ma_liste[2]) # IndexError: list index out of range- Ces erreurs arrêtent l'exécution du programme et affichent une traceback (pile d'appels) qui indique où l'erreur s'est produite.
- Exemples :
-
Erreurs logiques : Ce sont les plus difficiles à détecter. Le programme s'exécute sans erreur, mais il ne produit pas le résultat attendu. Le code fait ce qu'on lui a dit, mais ce n'est pas ce qu'on voulait qu'il fasse.
- Exemples :
- Une condition de boucle
whilen'est jamais fausse (boucle infinie). - Un calcul est incorrect (
a + bau lieu dea - b). - Un algorithme de tri ne trie pas correctement une liste.
- Une condition de boucle
- Pour les trouver, il faut comprendre la logique de l'algorithme et vérifier chaque étape.
- Exemples :
Techniques de débogage
Le débogage est le processus de recherche et de correction des erreurs dans un programme.
- Affichage de variables (
print) : La technique la plus simple et la plus courante. Insérer des instructionsprint()à des points clés du code pour afficher les valeurs des variables et vérifier le flux d'exécution.def calculer_moyenne(notes): somme = 0 print(f"Début du calcul. Somme initiale : {somme}") for note in notes: somme += note print(f"Note ajoutée : {note}, Somme actuelle : {somme}") moyenne = somme / len(notes) print(f"Moyenne calculée : {moyenne}") return moyenne - Débogueur pas à pas (notions) : Les environnements de développement intégrés (IDE) comme PyCharm, VS Code, ou même des outils en ligne, incluent des débogueurs. Ils permettent :
- De mettre des points d'arrêt (breakpoints) pour suspendre l'exécution à une ligne spécifique.
- D'exécuter le code pas à pas (instruction par instruction).
- D'inspecter les valeurs des variables à chaque étape.
- De suivre la pile d'appels des fonctions.
- C'est une technique très puissante pour comprendre le déroulement exact du programme et identifier les erreurs logiques.
- Tests unitaires (introduction) : Écrire de petits tests automatisés pour vérifier que des parties spécifiques (unités) de votre code (souvent des fonctions) fonctionnent comme prévu. Si un test échoue, vous savez exactement quelle partie du code est en faute.
(En Python, des modules comme# Exemple très simple de test "manuel" assert carre(2) <mark> 4, "Test 1 échoué : carre(2) devrait être 4" assert carre(0) </mark> 0, "Test 2 échoué : carre(0) devrait être 0" print("Tous les tests passés !")unittestoupytestsont utilisés pour des tests plus structurés.)
Commentaires et documentation
Un code bien commenté est plus facile à comprendre, à maintenir et à déboguer.
- Utilité des commentaires :
- Expliquer la logique complexe : Pourquoi une décision a été prise, pas seulement comment.
- Clarifier des sections de code : Rendre le code compréhensible pour d'autres développeurs (ou pour vous-même dans 6 mois !).
- Indiquer des TODOs ou des améliorations futures.
- En Python, les commentaires commencent par
#.
# Cette fonction calcule la factorielle d'un nombre entier positif def factorielle(n): if n == 0: return 1 # Cas de base pour la récursivité else: return n * factorielle(n-1) # Appel récursif - Docstrings en Python : Ce sont des chaînes de caractères multilignes utilisées pour documenter les modules, les classes et les fonctions. Elles sont placées juste après la définition et sont accessibles via
help()ou.__doc__.def addition(a, b): """ Cette fonction prend deux nombres en entrée et renvoie leur somme. Args: a (int/float): Le premier nombre. b (int/float): Le deuxième nombre. Returns: int/float: La somme des deux nombres. """ return a + b # help(addition) # Affichera la docstring - Lisibilité du code : Un code lisible est un code bien structuré, avec des noms de variables et fonctions clairs, et une indentation cohérente.
Bonnes pratiques de programmation
Adopter de bonnes pratiques rend votre code plus professionnel, robuste et facile à travailler.
- Nommage des variables et fonctions :
- Utiliser des noms descriptifs et explicites.
nombre_utilisateursest mieux quenu. - Respecter les conventions :
- Variables et fonctions :
snake_case(ex:mon_compteur,calculer_moyenne). - Constantes :
ALL_CAPS(ex:TAUX_TVA). - Classes :
CamelCase(ex:MaClasse).
- Variables et fonctions :
- Utiliser des noms descriptifs et explicites.
- Indentation et formatage du code :
- Python impose l'indentation. Utiliser 4 espaces par niveau d'indentation (convention PEP 8).
- Lignes courtes (max 79 caractères selon PEP 8).
- Espaces autour des opérateurs (
a = b + cplutôt quea=b+c). - Outils comme
Blackouautopep8peuvent formater le code automatiquement.
- Modularité et réutilisabilité :
- Découper le programme en fonctions (ou classes) qui font une chose et la font bien.
- Éviter la répétition de code (DRY - Don't Repeat Yourself). Si vous copiez-collez du code, c'est probablement le moment de créer une fonction.
- Les fonctions doivent être aussi indépendantes que possible des variables globales.
- Gestion des erreurs : Anticiper les erreurs possibles (par exemple, ce que fait le programme si l'utilisateur entre du texte au lieu d'un nombre). Utiliser des blocs
try-exceptpour gérer les exceptions de manière élégante.try: nombre = int(input("Entrez un nombre : ")) resultat = 10 / nombre print(f"Le résultat est {resultat}") except ValueError: print("Erreur : Ce n'est pas un nombre valide.") except ZeroDivisionError: print("Erreur : Division par zéro impossible.") except Exception as e: # Capture toutes les autres erreurs print(f"Une erreur inattendue est survenue : {e}")
Après la lecture
Passe à la pratique avec deux blocs bien visibles
Une fois le cours lu, ouvre soit le quiz pour vérifier la compréhension, soit les flashcards pour mémoriser les idées importantes. Les deux s'ouvrent dans une fenêtre dédiée.
Suite naturelle
Tu veux aller plus loin que l'article ?
Retrouve le même chapitre dans Wilo avec la suite des questions, la répétition espacée, les corrigés complets et une progression suivie dans le temps.