Files
TermNSI/Recursivité/TP/TP_Recursivite.ipynb
T

11 KiB

TP : La Récursivité et le Diviser pour Régner

Objectifs :

  • Comprendre le principe de la récursivité.
  • Appliquer la récursivité pour résoudre des problèmes simples.
  • Approfondir la méthode du diviser pour régner à travers des exemples concrets.
  • Compléter un algorithme de tri fusion.

Rappel sur la récursivité :

La récursivité est une méthode où une fonction s'appelle elle-même pour résoudre un problème. Chaque appel de la fonction permet de simplifier le problème jusqu'à atteindre une condition de base (appelée cas de base) qui permet de terminer la récursion.

Exemple classique : Calcul de la factorielle d'un nombre entier positif n.

def factorielle(n):
    if n == 0:
        return 1  # Cas de base
    else:
        return n * factorielle(n-1)  # Appel récursif

Exercice 1 : Fonction récursive traduire_romain

But : Écrire une fonction récursive traduire_romain qui prend en paramètre une chaîne de caractères non vide représentant un nombre écrit en chiffres romains, et qui renvoie son écriture décimale.

Consignes :

  • Chaque chiffre romain a une valeur : I=1, V=5, X=10, L=50, C=100, D=500, M=1000.
  • Si un chiffre plus petit précède un chiffre plus grand (ex : IV), cela signifie qu'il faut soustraire la valeur du chiffre plus petit.

Exemple :

traduire_romain("IX")  # Renvoie 9
traduire_romain("MCMXCIV")  # Renvoie 1994

Indication : Utilisez la récursion pour traiter un caractère à la fois, et soustrayez ou ajoutez en fonction de la position relative des caractères.

In [7]:
def traduire_romain(chaine):
    pass


print(traduire_romain("IX"))  # Doit afficher 9
None

Exercice 2 : Compléter un Tri Fusion

But : Compléter l'algorithme du tri fusion.

Le tri fusion est un exemple typique de la méthode de diviser pour régner. L'idée est de diviser le tableau en deux, de trier chaque moitié, puis de fusionner les deux moitiés triées.

Voici un code partiellement écrit que vous devez compléter :

In [8]:
def tri_fusion(tab):
    if len(tab) <= 1:
        return tab  # Cas de base
    milieu = len(tab) // 2
    gauche = tri_fusion(tab[:milieu])  # Appel récursif
    droite = tri_fusion(tab[milieu:])  # Appel récursif
    return fusionner(gauche, droite)

def fusionner(gauche, droite):
    tableau_fusionne = []
    i, j = 0, 0
    # Complétez la fonction pour fusionner les deux sous-tableaux ici :
    # ---------------------------------------------

    # ---------------------------------------------
    # Ajoutez ici les éléments restants des sous-tableaux
    tableau_fusionne += gauche[i:]
    tableau_fusionne += droite[j:]
    return tableau_fusionne

# Test de la fonction tri_fusion
print(tri_fusion([38, 27, 43, 3, 9, 82, 10]))  # Doit afficher une liste triée
[38, 27, 43, 3, 9, 82, 10]

Exercice 3 : Diviser pour Régner — Recherche d'un élément dans un tableau

But : Implémenter la recherche d'un élément dans un tableau trié en utilisant la méthode de diviser pour régner (recherche dichotomique).

La recherche dichotomique consiste à diviser le tableau en deux parties à chaque étape :

  • Si l'élément recherché est au milieu, vous avez terminé.
  • Si l'élément est plus petit que l'élément du milieu, il se trouve dans la première moitié du tableau.
  • Sinon, il se trouve dans la deuxième moitié.

Voici un squelette à compléter :

In [9]:
def recherche_dichotomique(tab, element, debut=0, fin=None):
    if fin is None:
        fin = len(tab) - 1
    if debut > fin:
        return -1  # L'élément n'est pas dans le tableau
    milieu = (debut + fin) // 2
    if tab[milieu] == element:
        return   # L'élément est trouvé
    # Complétez ici avec les appels récursifs manquants :
    # --------------------------------------------------
    
    # --------------------------------------------------
    
# Test de la fonction
tab = [3, 9, 10, 27, 38, 43, 82]
element = 27
print(recherche_dichotomique(tab, element))  # Doit afficher l'index de l'élément trouvé
None

Exercice 4 :

On considère des tableaux de nombres dont tous les éléments sont présents exactement trois fois à la suite, sauf un élément qui est présent une unique fois et que l'on appelle « l'intrus ».

Voici quelques exemples :

In [10]:
tab_a = [3, 3, 3, 9, 9, 9, 1, 1, 1, 7, 2, 2, 2, 4, 4, 4, 8, 8, 8, 5,
5, 5]
#l'intrus est 7
tab_b = [8, 5, 5, 5, 9, 9, 9, 18, 18, 18, 3, 3, 3]
#l'intrus est 8
tab_c = [5, 5, 5, 1, 1, 1, 0, 0, 0, 6, 6, 6, 3, 8, 8, 8]
#l'intrus est 3

On remarque qu'avec de tels tableaux :

 pour les indices multiples de 3 situés strictement avant l'intrus, l'élément correspondant et son voisin de droite sont égaux,

 pour les indices multiples de 3 situés après l'intrus, l'élément correspondant et son voisin de droite - s'il existe - sont différents.

Ce que l'on peut observer ci-dessous en observant les valeurs des paires de voisins marquées par des caractères ^

[3, 3, 3, 9, 9, 9, 1, 1, 1, 7, 2, 2, 2, 4, 4, 4, 8, 8, 8, 5, 5, 5] ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ 0 3 6 9 12 15 18 21

Dans des listes comme celles ci-dessus, un algorithme récursif pour trouver l'intrus consiste alors à choisir un indice i multiple de 3 situé approximativement au milieu des indices parmi lesquels se trouve l'intrus.

Puis, en fonction des valeurs de l'élément d'indice i et de son voisin de droite, à appliquer récursivement l'algorithme à la moitié droite ou à la moitié gauche des indices parmi lesquels se trouve l'intrus.

Par exemple, si on s’intéresse à l’indice 12, on voit les valeurs 2 et 4 qui sont différentes : l’intrus est donc à gauche de l’indice 12 (indice 12 compris)

En revanche, si on s’intéresse à l’indice 3, on voit les valeurs 9 et 9 qui sont identiques : l’intrus est donc à droite des indices 3-4-5, donc à partir de l’indice 6.

Compléter la fonction récursive trouver_intrus proposée page suivante qui met en œuvre cet algorithme.

In [11]:
def trouver_intrus(tab, g, d):
 
 '''Renvoie la valeur de l'intrus situé entre les indices g et d dans la liste tab où :
 tab vérifie les conditions de l'exercice, g et d sont des multiples de 3.
 '''
 if g == d:
   return ...
 else:
   nombre_de_triplets = (d  g) // ...
   indice = g + 3 * (nombre_de_triplets // 2)
   if ... :
     return ...
   else:
     return ...
  Cell In[11], line 9
    nombre_de_triplets = (d – g) // ...
                            ^
SyntaxError: invalid character '–' (U+2013)

Exemples :

trouver_intrus([3, 3, 3, 9, 9, 9, 1, 1, 1, 7, 2, 2, 2, 4, 4, 4, 8, 8, 8, 5, 5, 5], 0, 21) 7 trouver_intrus([8, 5, 5, 5, 9, 9, 9, 18, 18, 18, 3, 3, 3], 0, 12) 8 trouver_intrus([5, 5, 5, 1, 1, 1, 0, 0, 0, 6, 6, 6, 3, 8, 8, 8], 0, 15) 3