Programmation & Algorithmique

Complexite algorithmique, recursivite, structures de donnees fondamentales et algorithmes de tri – Tout le programme d'algorithmique pour reussir les examens a l'ISEP.

Algorithmique Niveau : Debutant → Avance ~4h de lecture ISEP Info
Retour aux cours

Sommaire du Cours

  1. Complexite Algorithmique – Big-O, Omega, Theta
  2. Recursivite – Factorielle, Fibonacci, Tours de Hanoi
  3. Structures de Donnees – Tableaux, listes, piles, files, ABR, hachage
  4. Algorithmes de Tri – Bulle, insertion, fusion, rapide
  5. Tableaux & Chaines – Manipulation, pattern matching
  6. Exercices Corriges – Mise en pratique
  7. QCM – Teste tes connaissances

1. Complexite Algorithmique

La complexite algorithmique mesure les ressources (temps, memoire) consommees par un algorithme en fonction de la taille $n$ de l'entree. On utilise les notations asymptotiques pour decrire le comportement quand $n \to \infty$.

1.1 Notations Asymptotiques

NotationNomDefinition intuitiveExemple
$O(g(n))$ Grand O (pire cas) Borne superieure asymptotique. $f(n)$ ne croit pas plus vite que $g(n)$. Tri bulle : $O(n^2)$
$\Omega(g(n))$ Grand Omega (meilleur cas) Borne inferieure asymptotique. $f(n)$ croit au moins aussi vite que $g(n)$. Tri insertion (deja trie) : $\Omega(n)$
$\Theta(g(n))$ Theta (cas moyen) Borne exacte. $f(n)$ croit exactement comme $g(n)$. Recherche dichotomique : $\Theta(\log n)$

1.2 Classes de Complexite – Echelle

ClasseNotation$n=100$$n=10^6$Exemple typique
Constante$O(1)$11Acces tableau par indice
Logarithmique$O(\log n)$~7~20Recherche dichotomique
Lineaire$O(n)$100$10^6$Parcours de tableau
Linearithmique$O(n \log n)$~664~$2 \times 10^7$Tri fusion, tri rapide
Quadratique$O(n^2)$10 000$10^{12}$Tri bulle, double boucle
Exponentielle$O(2^n)$~$10^{30}$infaisableFibonacci naif

1.3 Regles de Calcul

Simplification du Grand O

  • Constantes multiplicatives ignorees : $O(3n) = O(n)$, $O(n/2) = O(n)$
  • Termes dominants seulement : $O(n^2 + n) = O(n^2)$, $O(2^n + n^{100}) = O(2^n)$
  • Boucles imbriquees : $k$ boucles de taille $n \Rightarrow O(n^k)$
  • Boucles successives : $O(f(n)) + O(g(n)) = O(\max(f,g))$

2. Recursivite

Une fonction recursive s'appelle elle-meme. Elle doit avoir un cas de base (condition d'arret) et un cas recursif (appel sur un sous-probleme plus petit).

2.1 Factorielle

def factorielle(n):
    # Cas de base
    if n <= 1:
        return 1
    # Cas recursif
    return n * factorielle(n - 1)

Complexite : $O(n)$ – $n$ appels recursifs, $O(1)$ par appel.

2.2 Suite de Fibonacci

def fibonacci(n):
    if n <= 1:
        return n
    return fibonacci(n - 1) + fibonacci(n - 2)

Complexite naive : $O(2^n)$ – explosion exponentielle ! Avec memoisation : $O(n)$.

2.3 Tours de Hanoi

def hanoi(n, depart, arrivee, auxiliaire):
    if n == 1:
        print(f"Deplacer disque 1 de {depart} vers {arrivee}")
        return
    hanoi(n - 1, depart, auxiliaire, arrivee)
    print(f"Deplacer disque {n} de {depart} vers {arrivee}")
    hanoi(n - 1, auxiliaire, arrivee, depart)

Complexite : $O(2^n)$ – $2^n - 1$ deplacements. Pour $n=64$ disques, c'est environ 585 milliards d'annees !


3. Structures de Donnees

Une structure de donnees organise et stocke les donnees pour un acces et une modification efficaces. Le choix de la structure impacte directement la performance des algorithmes.

3.1 Comparatif des Structures Fondamentales

StructureAccesRechercheInsertionSuppression
Tableau (Array) $O(1)$$O(n)$$O(n)$$O(n)$
Liste Chainee $O(n)$$O(n)$$O(1)$$O(1)$
Pile (Stack) $O(n)$$O(n)$$O(1)$$O(1)$
File (Queue) $O(n)$$O(n)$$O(1)$$O(1)$
ABR (BST) $O(\log n)$$O(\log n)$$O(\log n)$$O(\log n)$
Table de Hachage$O(1)$$O(1)$$O(1)$

* Moyennes ; cas pire : ABR non equilibre → $O(n)$, table de hachage avec collisions → $O(n)$.

3.2 Pile et File – Principe LIFO / FIFO

Pile (Stack) – LIFO

Last In, First Out. Comme une pile d'assiettes. Operations : push() (empiler), pop() (depiler).

Utilisations : annulation (Ctrl+Z), parcours DFS, evaluation d'expressions, pile d'appels.

File (Queue) – FIFO

First In, First Out. Comme une file d'attente. Operations : enqueue() (enfiler), dequeue() (defiler).

Utilisations : parcours BFS, buffer de messages, files d'impression, ordonnancement.

3.3 Arbre Binaire de Recherche (ABR / BST)

Propriete fondamentale de l'ABR

Pour tout noeud $x$ : toutes les cles du sous-arbre gauche sont $\lt x$, et toutes les cles du sous-arbre droit sont $\gt x$.

8 / \ 3 10 / \ \ 1 6 14 / \ / 4 7 13

Parcours infixe (gauche → racine → droite) donne les elements tries : 1, 3, 4, 6, 7, 8, 10, 13, 14.

Parcours prefixe (racine → gauche → droite) : 8, 3, 1, 6, 4, 7, 10, 14, 13.

Parcours suffixe (gauche → droite → racine) : 1, 4, 7, 6, 3, 13, 14, 10, 8.

3.4 Table de Hachage

Principe du Hachage

Une fonction de hachage $h(k)$ transforme une cle $k$ en un indice de tableau. Idealement $O(1)$ pour insertion/recherche/suppression.

Gestion des collisions :

  • Chainage : chaque case contient une liste chainee des elements en collision
  • Adressage ouvert : sondage lineaire, quadratique ou double hachage pour trouver une case libre

En Python : dict, en Java : HashMap. Facteur de charge $\alpha = n/m$ (n cles, m cases) – si $\alpha > 0.7$, redimensionner.


4. Algorithmes de Tri

Trier est l'une des operations les plus fondamentales en informatique. Voici les 4 algorithmes incontournables, du plus simple au plus efficace.

Tri a Bulles (Bubble Sort)

Compare et echange les elements adjacents. Les plus grands "remontent" comme des bulles.

Meilleur : $O(n)$ | Moyen : $O(n^2)$ | Pire : $O(n^2)$

Stable : Oui | En place : Oui | Utilise : Rarement (pedagogique)

Tri par Insertion

Insere chaque element a sa place dans la partie deja triee. Efficace sur petites donnees ou quasi-triees.

Meilleur : $O(n)$ | Moyen : $O(n^2)$ | Pire : $O(n^2)$

Stable : Oui | En place : Oui | Utilise : Petits tableaux, TimSort

Tri Fusion (Merge Sort)

Divise recursivement en deux moities, trie chacune, puis fusionne. Paradigme "diviser pour regner".

Meilleur/Moyen/Pire : $O(n \log n)$

Stable : Oui | En place : Non ($O(n)$ aux.) | Utilise : Donnees volumineuses, externe

Tri Rapide (Quick Sort)

Choisit un pivot, partitionne (elements ≤ pivot a gauche, ≥ a droite), trie recursivement. Le plus utilise en pratique.

Meilleur/Moyen : $O(n \log n)$ | Pire : $O(n^2)$

Stable : Non | En place : Oui | Utilise : Tri standard dans la plupart des langages

4.1 Tableau Comparatif des Tris

AlgorithmeMeilleur casCas moyenPire casMemoireStable
Tri Bulle$O(n)$$O(n^2)$$O(n^2)$$O(1)$Oui
Tri Insertion$O(n)$$O(n^2)$$O(n^2)$$O(1)$Oui
Tri Selection$O(n^2)$$O(n^2)$$O(n^2)$$O(1)$Non
Tri Fusion$O(n \log n)$$O(n \log n)$$O(n \log n)$$O(n)$Oui
Tri Rapide$O(n \log n)$$O(n \log n)$$O(n^2)$$O(\log n)$Non

5. Tableaux et Chaines de Caracteres

Manipuler efficacement tableaux et chaines est essentiel. Voici les techniques classiques et la recherche de motifs.

5.1 Techniques Classiques sur Tableaux

Technique des Deux Pointeurs

Un pointeur a gauche, un a droite. Se rapprochent tant que condition satisfaite. Ideal pour tableaux tries.

Complexite : $O(n)$. Exemples : inversion de tableau, somme de deux elements = cible, verification palindrome.

Fenetre Glissante (Sliding Window)

Maintenir une fenetre de taille fixe ou variable qui "glisse" sur le tableau. Optimise les sous-tableaux.

Complexite : $O(n)$. Exemples : somme maximale de k elements consecutifs, plus longue sous-chaine sans repetition.

5.2 Recherche de Motifs (Pattern Matching)

Algorithmes de recherche de sous-chaine

AlgorithmeComplexitePrincipe
Naif$O(n \cdot m)$Compare le motif a chaque position
KMP (Knuth-Morris-Pratt)$O(n + m)$Precalcule un tableau de prefixes pour eviter les retours
Boyer-Moore$O(n)$ (meilleur)Compare de droite a gauche, saute des blocs entiers
Rabin-Karp$O(n + m)$ (moyen)Utilise une fonction de hachage glissante

$n$ = longueur du texte, $m$ = longueur du motif.


6. Exercices Corriges

Mets en pratique les concepts avec ces 4 exercices, du niveau debutant a avance.

#1 Analyse de Complexite Classique

Analysez la complexite temporelle (pire cas) du code suivant :

def mystere(arr, n):
    for i in range(n):
        j = 1
        while j < n:
            print(arr[i] * j)
            j = j * 2

Complexite : $O(n \log n)$

La boucle for s'execute $n$ fois. La boucle while double j a chaque iteration jusqu'a $n$, soit $\log_2(n)$ iterations. Total : $n \times \log n = O(n \log n)$.

#2 Recursivite – Somme des chiffres Classique

Ecrivez une fonction recursive somme_chiffres(n) qui retourne la somme des chiffres d'un entier positif. Exemple : somme_chiffres(12345) → 15.

def somme_chiffres(n):
    # Cas de base : un seul chiffre
    if n < 10:
        return n
    # Dernier chiffre + appel sur le reste
    return (n % 10) + somme_chiffres(n // 10)

Complexite : $O(\log_{10} n) = O(d)$ ou $d$ est le nombre de chiffres.

#3 ABR – Insertion et Recherche Intermediaire

On insere successivement les valeurs suivantes dans un ABR initialement vide : 15, 10, 20, 8, 12, 17, 25, 6, 11, 16, 19.

(a) Dessinez l'ABR obtenu.
(b) Quelle est la hauteur de l'arbre ?
(c) Combien de comparaisons pour trouver 16 ?

15 / \ 10 20 / \ / \ 8 12 17 25 / / / \ 6 11 16 19

(b) Hauteur = 3 (15 → 10 → 8 → 6).

(c) 16 : 15→20→17→16 = 4 comparaisons. Chemin : 15 (aller a droite), 20 (gauche), 17 (gauche), 16 (trouve !).

#4 Tri – Application comparative Expert

On dispose d'un tableau de $10^6$ entiers. Pour chaque scenario, quel algorithme de tri recommandez-vous ? Justifiez.

(a) Le tableau est deja presque trie (moins de 10 elements mal places).
(b) La memoire disponible est tres limitee.
(c) La stabilite est requise (elements egaux conservent leur ordre relatif).

(a) Tri par insertion – excellent sur donnees quasi-triees : $\approx O(n)$ avec tres peu d'echanges.

(b) Tri rapide – tri en place avec $O(\log n)$ de memoire pour la pile de recursion. Le tri fusion necessiterait $O(n)$ memoire auxiliaire.

(c) Tri fusion – stable par conception (fusion preserve l'ordre). Tri rapide n'est pas stable (partitionnement melange).


QCM – Teste tes Connaissances

5 questions pour evaluer ta maitrise du cours de programmation et algorithmique. Propulse par le moteur QCM de NESTI STUDIO.