Récursivité
Algorithmique & Programmation
Cours 1 : Introduction à la récursivité
Présentation
La récursivité est un concept général qui peut être illustré dans
(quasiment) tous les langages de programmation, et qui peut être utile
dans de nombreuses situations.
La définition la plus simple d'une fonction récursive est la suivante :
C’est une fonction qui s'appelle elle-même.
Si dans le corps (le contenu) de la fonction, vous l'utilisez elle-même,
alors elle est récursive.
Récursivité
Premier exemple : fonction factorielle
La factorielle de n notée n! est le produit de tous les entiers de 1 à n. Une
méthode vue en première année consiste à programmer cette fonction de
manière itérative. Voici ce que donne le programme écrit en langage Python :
def fac_iterative(n):
res=1
for k in range(n):
res=res*(k+1)
return res
>>> fac_iterative(10)
3628800
Pour montrer l'intérêt de la récursivité, nous allons maintenant coder cette
fonction en utilisant une propriété de la factorielle. On a effectivement :
n! = n.(n-1)! Cette propriété est très intéressante, car elle permet de calculer n! à
partir de (n-1)!. Or (n-1)! Peut être calculé de la même manière à partir de (n-2)!
Etc
Récursivité
Cependant, si on ne fait que répéter à l'infini cette méthode, le calcul ne donnera
jamais de résultat. Pour cela, il faut définir un cas pour lequel on obtient le résultat.
Dans notre exemple ce cas est : 1!=1
A partir de ce résultat, on peut calculer n! pour tout n≥1.
Ainsi, de manière
récursive :
def fac_recursive(n):
if n==0:
return 1
return(n*fac_recursive(n-1))
En pratique, l’appel fac_recursive(10) entraîne
l’appel fac_recursive(9), qui entraîne lui-même
l’appel fac_recursive(8) etc… et ainsi de suite,
jusqu’à l’appel fac_recursive(0) qui renvoie 1.
En conclusion de cette introduction, on dira qu’une
fonction f est récursive si son exécution peut
provoquer un ou plusieurs appels de f elle-même.
Récursivité
Qu’est-ce qui se passe?
Récursivité
Récursivité
Récursivité
Récursivité
Récursivité
Récursivité
Récursivité
Récursivité
Récursivité
Récursivité
Récursivité
Récursivité
Récursivité
Récursivité
Récursivité
Récursivité
Récursivité
Récursivité
Récursivité
Récursivité
Récursivité
Récursivité
Récursivité
Récursivité
Récursivité
La récursivité plus en détails
Pourquoi écrire une fonction récursive ?
Un programmeur doit écrire une fonction
récursive quand c'est la solution la plus
adaptée à son problème. La question peut
donc se reformuler ainsi : à quels problèmes
les fonctions récursives sont-elles adaptées ?
Les fonctions récursives sont des fonctions qui
s'appellent elles-mêmes. Elles doivent donc
résoudre des problèmes qui "s'appellent eux-
mêmes".
Exemples :
On dispose d'une liste de joueurs d'un jeu à deux joueurs (échecs, ping-pong,
etc.), et je veux créer une liste de matches, de telle sorte que chaque joueur joue
contre tous les autres joueurs une seule fois (pas de phase retour).
On peut remarquer que si l’on a une liste de 4 joueurs, on peut résoudre le problème en
connaissant une liste de matchs pour les 3 premiers joueurs seulement : on prend cette
liste, et on y ajoute un match entre le quatrième joueur et chacun des trois autres. Ainsi,
on peut ramener le problème (obtenir une liste des matchs entre tous les joueurs) à un
sous-problème plus simple : obtenir une liste des matchs entre tous les joueurs, sauf un.
Récursivité
def matches(joueurs):
""" Fonction récursive qui renvoie une liste de matches à partir d'une liste de joueurs
"""
#s'il n'y a qu'un seul joueur, on n'organise aucun match
if len(joueurs)==1:
return [ ]
#on enleve le dernier joueur de la liste, et on demande les matchs sans lui
dernier_joueur = joueurs.pop()
vs=matches(joueurs) #on rajoute un match entre lui et tous les autres joueurs
for j in joueurs:
vs.append([j,dernier_joueur]) #on le remet dans la liste des joueurs, et on
renvoie la liste des match
joueurs.append(dernier_joueur)
return vs
Comprendre à la
maison+ questions
Récursivité
Méthode structurelle et principe fondamental
Une fois qu'on a repéré que le problème que l'on doit résoudre se prête bien à
l'utilisation d'une fonction récursive, il faut écrire la fonction.
 D'abord, on gère le cas simple, c'est-à-dire celui qui ne nécessite pas de rappeler
récursivement la fonction. Pour la factorielle, c'est le cas où n vaut 1. Pour la liste
des joueurs, c'est le cas où il y a un seul joueur (car il n'y a aucun match à
organiser).
 Ensuite, on gère le ou les sous-problèmes récursifs, en rappelant la fonction
récursive pour chaque sous-problème à résoudre.
On peut énoncer le principe fondamental suivant, concernant les fonctions récursives :
Comme une fonction récursive fait appel à elle-même, il est indispensable de s’assurer
que le nombre d’appels à cette fonction sera fini.
nombre maximal
d’appels récursifs (de
l’ordre de 1000)
>>> fac_recursive_erreur(10)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "E:/Exemples/Factorielle.py", line 21, in
fac_recursive_erreur
return(n*fac_recursive_erreur(n-1))
. . .
RuntimeError: maximum recursion depth exceeded
Récursivité
Suites numériques et comparaison entre itératif et récursif
Définition explicite
Une suite numérique peut dans certains cas être définie de manière explicite : u0=f(n).
La détermination du nième
terme est alors aisée. Il suffit d’évaluer f(n).
Exemple 1 : Puissances de 2
Problème : évaluer le nombre 2 à la puissance n de manière explicite, n.
On définit de manière explicite la suite : un = 2n
par le
code Python suivant :
def Pow2_explicite(n):
return 2**n
Récursivité
Relation de récurrence
Dans une suite définie de manière récurrente, il est possible de calculer le terme un
de la suite en connaissant les termes précédents.
Les égalités de la forme un = f(un-1), un = f(un-1, un-2), etc. s’appellent des relations de
récurrence. Les égalités qui définissent les premiers termes d’une suite sont
appelées des conditions de départ. Une suite récursive est donc définie par une
relation de récurrence et une(des) condition(s) de départ.
Premier exemple
On reprend l’Exemple 1 : puissances de 2.
On définit de manière récursive la suite :
0
1
1
2.
n n
u
u u 





On demande de définir un algorithme récursif
avec le langage Python (Noté Pow2_recursive).
def Pow2_recursive(n):
if n==0:
return 1
return 2*Pow2_recursive(n-1)
Récursivité
Il est aussi possible de proposer un algorithme itératif permettant d’aboutir au
même résultat…
def Pow2_iterative(n):
res=1
for k in range(n):
res=res*2
return res
Récursivité
Deuxième exemple La suite de Fibonacci.
Cette suite est définie de la façon suivante :
0
1
2 1
0
1
n n n
F
F
F F F
 





  

On se propose de définir une
procédure récursive FibR, qui à partir
d’un seul argument d’entrée (un
entier n) retourne la valeur de Fn en
sortie :
def FibR(n):
if n<=1:
return n
return FibR(n-1)+FibR(n-2)
Récursivité
On propose maintenant une version itérative, que l’on nommera FibI :
def FibI(n):
if n==0:
return 0
a=0; b=1 #Premiers termes
for k in range(1,n):
a,b=b,a+b
return b
0
1
2 1
0
1
n n n
F
F
F F F
 





  

Que peut-on conclure si on compare ces deux
fonctions ? On voit que si on demande un n
très grand, le nombre d’appels de FibR devient
vite très important
Comparaison des méthodes récursives et itératives
Fib(1) est calculé 5 fois
def FibR(n):
if n<=1:
return n
return FibR(n-1)+FibR(n-2)
Récursivité
Analyse des programmes récursifs
Lorsque nous aurons à écrire ou analyser des
programmes récursifs, nous serons amenés à
nous poser un certain nombre de questions :  Le programme se termine-t-il ?
 Est-il conforme à sa spécification ?
 Quelle est sa complexité (temps et
mémoire) ?
Complexité d’une fonction récursive
Prenons par exemple la suite (un) qui permet de calculer une approximation de 3
0
1
1
2
1 3
( )
2





 

 
 

 

n n
n
u
u u
u
def u(n):
if n==0:
return 2.
else:
x=u(n-1)
return 0.5*(x+3./x)
Récursivité
def u(n):
if n==0:
return 2.
else:
x=u(n-1)
return 0.5*(x+3./x)
Si n désigne la valeur de son argument, on
note C(n) ce nombre d’opérations. En suivant la
définition de la fonction u, on obtient les deux
équations suivantes : C(0)=0
C(n)= C(n-1)+3
En effet, dans le cas n=0, on ne fait aucune opération
arithmétique. Et dans le cas n>0, on fait d’une part un appel
récursif sur la valeur n-1, d’où C(n-1) opérations, puis trois
opérations arithmétiques (une multiplication , une addition et
une division). Il s’agit d’une suite arithmétique de raison 3,
dont le terme général est :
C(n)=3n
Le nombre d’opérations arithmétiques effectuées par la fonction u est donc
proportionnel à n .
Récursivité
Si en revanche, on avait écrit la fonction u de manière plus naïve, avec deux appels
récursifs u(n-1) :
def u(n):
if n==0:
return 2.
else:
return 0.5*(u(n-1)+3./u(n-1))
Alors les équations définissant C(n) seraient les suivantes :
C(0)=0
C(n)= C(n-1)+ C(n-1)+3
En effet, il convient de prendre en compte le coût C(n-1) des deux appels à u(n-1). Il s’agit
maintenant d’une suite arithmético-géométrique, dont le terme général est :
C(n)=3(2n
-1)
Récursivité
Récursivité imbriquée et croisée
Récursivité imbriquée
La récursivité imbriquée consiste à faire un appel récursif à l'intérieur d'un autre
appel récursif. Un exemple permettant de bien illustrer le concept est la suite
d’Ackermann, définie de la manière suivante sur 
 
def Ackermann(m,n):
if m==0:
return n+1
elif n==0:
return Ackermann(m-1,1)
else:
return Ackermann(m-1, Ackermann(m,n-1))
Question : Que vaut Ackermann(2,2) ?
Réponse : 7
Récursivité
Récursivité croisée ou mutuelle
La possibilité de déclarer une fonction sans la définir prend tout son intérêt à propos de la
récursivité croisée. En effet, une fonction ne peut être utilisée qu’à condition qu’elle ait été
définie (ou déclarée) or, dans le cas de la récursivité croisée, on ne pourrait pas s’en sortir
juste à l’aide des définitions. La récursivité croisée consiste à écrire des fonctions qui
s’appellent l’une l’autre.
Prenons l’exemple simple suivant qui consiste à connaître la parité d’un entier naturel.
def estPair(n):
"""Cette fonction renvoie True si l'entier n est pair False sinon (on suppose
que n>=0)"""
if n==0:
return True
return estImpair(n-1)
def estImpair(n):
"""Cette fonction renvoie True si l'entier n est pair False sinon (on suppose
que n>=0)"""
if n==0:
return False
return estPair(n-1)
Récursivité
Récursivité terminale et non terminale
Une fonction récursive est dite non terminale si le résultat de l'appel récursif est utilisé
pour réaliser un traitement (en plus du retour d'une valeur).
Reprenons la forme récursive non
terminale de la fonction factorielle,
que l’on notera facNT.
def facNT(n):
if n==0:
return 1
return(n*facNT(n-1))
Récursivité
Une fonction récursive est dite terminale si aucun traitement n'est effectué à la remontée
d'un appel récursif (sauf le retour d'une valeur). Concrètement il n’y a pas de calcul entre
l’appel récursif et l’instruction return.
def facT(n,acc=1):
if n==0:
return acc
return facT(n-1,n*acc)
Cette fois-ci, les calculs se font à la descente,
comme c’est illustré ci-dessous, pour facT(3):
facT(0,6)
facT(2,3)
facT(1,6)
facT(3,1)
Récursivité
Exemple de la suite de Syracuse
La suite de Syracuse d’un nombre entier N est définie par récurrence de la façon
suivante :
def syracuse(n):
if n == 1:
print 1 # on affiche 1 et on ne fait rien d ’ autre
else :
print n
if n % 2 == 0:
syracuse(n/2)
else :
syracuse(3 n + 1)
∗
def syracuse_tail_recursive(n, t=1):
if n == 1:
return t - 1
return Syracuse(3*n+1 if n%2 else n/2, t+1)
n=3
while n!=1:
print(n)
if n%2==0:
n=n//2
else:
n=3*n+1
print(1)

Récursivité en Algorithme et structure.pptx

  • 1.
    Récursivité Algorithmique & Programmation Cours1 : Introduction à la récursivité Présentation La récursivité est un concept général qui peut être illustré dans (quasiment) tous les langages de programmation, et qui peut être utile dans de nombreuses situations. La définition la plus simple d'une fonction récursive est la suivante : C’est une fonction qui s'appelle elle-même. Si dans le corps (le contenu) de la fonction, vous l'utilisez elle-même, alors elle est récursive.
  • 2.
    Récursivité Premier exemple :fonction factorielle La factorielle de n notée n! est le produit de tous les entiers de 1 à n. Une méthode vue en première année consiste à programmer cette fonction de manière itérative. Voici ce que donne le programme écrit en langage Python : def fac_iterative(n): res=1 for k in range(n): res=res*(k+1) return res >>> fac_iterative(10) 3628800 Pour montrer l'intérêt de la récursivité, nous allons maintenant coder cette fonction en utilisant une propriété de la factorielle. On a effectivement : n! = n.(n-1)! Cette propriété est très intéressante, car elle permet de calculer n! à partir de (n-1)!. Or (n-1)! Peut être calculé de la même manière à partir de (n-2)! Etc
  • 3.
    Récursivité Cependant, si onne fait que répéter à l'infini cette méthode, le calcul ne donnera jamais de résultat. Pour cela, il faut définir un cas pour lequel on obtient le résultat. Dans notre exemple ce cas est : 1!=1 A partir de ce résultat, on peut calculer n! pour tout n≥1. Ainsi, de manière récursive : def fac_recursive(n): if n==0: return 1 return(n*fac_recursive(n-1)) En pratique, l’appel fac_recursive(10) entraîne l’appel fac_recursive(9), qui entraîne lui-même l’appel fac_recursive(8) etc… et ainsi de suite, jusqu’à l’appel fac_recursive(0) qui renvoie 1. En conclusion de cette introduction, on dira qu’une fonction f est récursive si son exécution peut provoquer un ou plusieurs appels de f elle-même.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
    Récursivité La récursivité plusen détails Pourquoi écrire une fonction récursive ? Un programmeur doit écrire une fonction récursive quand c'est la solution la plus adaptée à son problème. La question peut donc se reformuler ainsi : à quels problèmes les fonctions récursives sont-elles adaptées ? Les fonctions récursives sont des fonctions qui s'appellent elles-mêmes. Elles doivent donc résoudre des problèmes qui "s'appellent eux- mêmes". Exemples : On dispose d'une liste de joueurs d'un jeu à deux joueurs (échecs, ping-pong, etc.), et je veux créer une liste de matches, de telle sorte que chaque joueur joue contre tous les autres joueurs une seule fois (pas de phase retour). On peut remarquer que si l’on a une liste de 4 joueurs, on peut résoudre le problème en connaissant une liste de matchs pour les 3 premiers joueurs seulement : on prend cette liste, et on y ajoute un match entre le quatrième joueur et chacun des trois autres. Ainsi, on peut ramener le problème (obtenir une liste des matchs entre tous les joueurs) à un sous-problème plus simple : obtenir une liste des matchs entre tous les joueurs, sauf un.
  • 30.
    Récursivité def matches(joueurs): """ Fonctionrécursive qui renvoie une liste de matches à partir d'une liste de joueurs """ #s'il n'y a qu'un seul joueur, on n'organise aucun match if len(joueurs)==1: return [ ] #on enleve le dernier joueur de la liste, et on demande les matchs sans lui dernier_joueur = joueurs.pop() vs=matches(joueurs) #on rajoute un match entre lui et tous les autres joueurs for j in joueurs: vs.append([j,dernier_joueur]) #on le remet dans la liste des joueurs, et on renvoie la liste des match joueurs.append(dernier_joueur) return vs Comprendre à la maison+ questions
  • 31.
    Récursivité Méthode structurelle etprincipe fondamental Une fois qu'on a repéré que le problème que l'on doit résoudre se prête bien à l'utilisation d'une fonction récursive, il faut écrire la fonction.  D'abord, on gère le cas simple, c'est-à-dire celui qui ne nécessite pas de rappeler récursivement la fonction. Pour la factorielle, c'est le cas où n vaut 1. Pour la liste des joueurs, c'est le cas où il y a un seul joueur (car il n'y a aucun match à organiser).  Ensuite, on gère le ou les sous-problèmes récursifs, en rappelant la fonction récursive pour chaque sous-problème à résoudre. On peut énoncer le principe fondamental suivant, concernant les fonctions récursives : Comme une fonction récursive fait appel à elle-même, il est indispensable de s’assurer que le nombre d’appels à cette fonction sera fini. nombre maximal d’appels récursifs (de l’ordre de 1000) >>> fac_recursive_erreur(10) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "E:/Exemples/Factorielle.py", line 21, in fac_recursive_erreur return(n*fac_recursive_erreur(n-1)) . . . RuntimeError: maximum recursion depth exceeded
  • 32.
    Récursivité Suites numériques etcomparaison entre itératif et récursif Définition explicite Une suite numérique peut dans certains cas être définie de manière explicite : u0=f(n). La détermination du nième terme est alors aisée. Il suffit d’évaluer f(n). Exemple 1 : Puissances de 2 Problème : évaluer le nombre 2 à la puissance n de manière explicite, n. On définit de manière explicite la suite : un = 2n par le code Python suivant : def Pow2_explicite(n): return 2**n
  • 33.
    Récursivité Relation de récurrence Dansune suite définie de manière récurrente, il est possible de calculer le terme un de la suite en connaissant les termes précédents. Les égalités de la forme un = f(un-1), un = f(un-1, un-2), etc. s’appellent des relations de récurrence. Les égalités qui définissent les premiers termes d’une suite sont appelées des conditions de départ. Une suite récursive est donc définie par une relation de récurrence et une(des) condition(s) de départ. Premier exemple On reprend l’Exemple 1 : puissances de 2. On définit de manière récursive la suite : 0 1 1 2. n n u u u       On demande de définir un algorithme récursif avec le langage Python (Noté Pow2_recursive). def Pow2_recursive(n): if n==0: return 1 return 2*Pow2_recursive(n-1)
  • 34.
    Récursivité Il est aussipossible de proposer un algorithme itératif permettant d’aboutir au même résultat… def Pow2_iterative(n): res=1 for k in range(n): res=res*2 return res
  • 35.
    Récursivité Deuxième exemple Lasuite de Fibonacci. Cette suite est définie de la façon suivante : 0 1 2 1 0 1 n n n F F F F F            On se propose de définir une procédure récursive FibR, qui à partir d’un seul argument d’entrée (un entier n) retourne la valeur de Fn en sortie : def FibR(n): if n<=1: return n return FibR(n-1)+FibR(n-2)
  • 36.
    Récursivité On propose maintenantune version itérative, que l’on nommera FibI : def FibI(n): if n==0: return 0 a=0; b=1 #Premiers termes for k in range(1,n): a,b=b,a+b return b 0 1 2 1 0 1 n n n F F F F F            Que peut-on conclure si on compare ces deux fonctions ? On voit que si on demande un n très grand, le nombre d’appels de FibR devient vite très important Comparaison des méthodes récursives et itératives Fib(1) est calculé 5 fois def FibR(n): if n<=1: return n return FibR(n-1)+FibR(n-2)
  • 37.
    Récursivité Analyse des programmesrécursifs Lorsque nous aurons à écrire ou analyser des programmes récursifs, nous serons amenés à nous poser un certain nombre de questions :  Le programme se termine-t-il ?  Est-il conforme à sa spécification ?  Quelle est sa complexité (temps et mémoire) ? Complexité d’une fonction récursive Prenons par exemple la suite (un) qui permet de calculer une approximation de 3 0 1 1 2 1 3 ( ) 2                 n n n u u u u def u(n): if n==0: return 2. else: x=u(n-1) return 0.5*(x+3./x)
  • 38.
    Récursivité def u(n): if n==0: return2. else: x=u(n-1) return 0.5*(x+3./x) Si n désigne la valeur de son argument, on note C(n) ce nombre d’opérations. En suivant la définition de la fonction u, on obtient les deux équations suivantes : C(0)=0 C(n)= C(n-1)+3 En effet, dans le cas n=0, on ne fait aucune opération arithmétique. Et dans le cas n>0, on fait d’une part un appel récursif sur la valeur n-1, d’où C(n-1) opérations, puis trois opérations arithmétiques (une multiplication , une addition et une division). Il s’agit d’une suite arithmétique de raison 3, dont le terme général est : C(n)=3n Le nombre d’opérations arithmétiques effectuées par la fonction u est donc proportionnel à n .
  • 39.
    Récursivité Si en revanche,on avait écrit la fonction u de manière plus naïve, avec deux appels récursifs u(n-1) : def u(n): if n==0: return 2. else: return 0.5*(u(n-1)+3./u(n-1)) Alors les équations définissant C(n) seraient les suivantes : C(0)=0 C(n)= C(n-1)+ C(n-1)+3 En effet, il convient de prendre en compte le coût C(n-1) des deux appels à u(n-1). Il s’agit maintenant d’une suite arithmético-géométrique, dont le terme général est : C(n)=3(2n -1)
  • 40.
    Récursivité Récursivité imbriquée etcroisée Récursivité imbriquée La récursivité imbriquée consiste à faire un appel récursif à l'intérieur d'un autre appel récursif. Un exemple permettant de bien illustrer le concept est la suite d’Ackermann, définie de la manière suivante sur    def Ackermann(m,n): if m==0: return n+1 elif n==0: return Ackermann(m-1,1) else: return Ackermann(m-1, Ackermann(m,n-1)) Question : Que vaut Ackermann(2,2) ? Réponse : 7
  • 41.
    Récursivité Récursivité croisée oumutuelle La possibilité de déclarer une fonction sans la définir prend tout son intérêt à propos de la récursivité croisée. En effet, une fonction ne peut être utilisée qu’à condition qu’elle ait été définie (ou déclarée) or, dans le cas de la récursivité croisée, on ne pourrait pas s’en sortir juste à l’aide des définitions. La récursivité croisée consiste à écrire des fonctions qui s’appellent l’une l’autre. Prenons l’exemple simple suivant qui consiste à connaître la parité d’un entier naturel. def estPair(n): """Cette fonction renvoie True si l'entier n est pair False sinon (on suppose que n>=0)""" if n==0: return True return estImpair(n-1) def estImpair(n): """Cette fonction renvoie True si l'entier n est pair False sinon (on suppose que n>=0)""" if n==0: return False return estPair(n-1)
  • 42.
    Récursivité Récursivité terminale etnon terminale Une fonction récursive est dite non terminale si le résultat de l'appel récursif est utilisé pour réaliser un traitement (en plus du retour d'une valeur). Reprenons la forme récursive non terminale de la fonction factorielle, que l’on notera facNT. def facNT(n): if n==0: return 1 return(n*facNT(n-1))
  • 43.
    Récursivité Une fonction récursiveest dite terminale si aucun traitement n'est effectué à la remontée d'un appel récursif (sauf le retour d'une valeur). Concrètement il n’y a pas de calcul entre l’appel récursif et l’instruction return. def facT(n,acc=1): if n==0: return acc return facT(n-1,n*acc) Cette fois-ci, les calculs se font à la descente, comme c’est illustré ci-dessous, pour facT(3): facT(0,6) facT(2,3) facT(1,6) facT(3,1)
  • 44.
    Récursivité Exemple de lasuite de Syracuse La suite de Syracuse d’un nombre entier N est définie par récurrence de la façon suivante : def syracuse(n): if n == 1: print 1 # on affiche 1 et on ne fait rien d ’ autre else : print n if n % 2 == 0: syracuse(n/2) else : syracuse(3 n + 1) ∗ def syracuse_tail_recursive(n, t=1): if n == 1: return t - 1 return Syracuse(3*n+1 if n%2 else n/2, t+1) n=3 while n!=1: print(n) if n%2==0: n=n//2 else: n=3*n+1 print(1)