2017-10-18 19 views
3

J'ai une implémentation simple de LinkedList en python. Comment utiliser récursion dans une méthode? Je sais comment fonctionne la récursivité, mais comment utiliser moi-même avec la récursivité. Ce serait bien si quelqu'un peut corriger mon code mais je suis plus intéressé par l'explication afin que je puisse l'utiliser dans différentes méthodes.LinkedLists dans la récursivité python

Code LinkedList:

class Node: 
    def __init__(self, item, next): 
     self.item = item 
     self.next = next 

class LinkedList: 
    def __init__(self): 
     self.head = None 

    def add(self, item): 
     self.head = Node(item, self.head) 

    def remove(self): 
     if self.is_empty(): 
      return None 
     else: 
      item = self.head.item 
      self.head = self.head.next 
      return item 

    def is_empty(self): 
     return self.head == None 

Mon code est:

def count(self, ptr=self.head): 
    if ptr == None: 
     return '0' 
    else: 
     return 1 + self.count(ptr.next) 

Il me donne une erreur:

def count(self, ptr=self.head): 
NameError: name 'self' is not defined 

Toute aide est très appréciée.

+1

Je ne recommanderais pas d'utiliser la récursivité pour cela. Il est plus efficace de simplement mettre à jour 'ptr = ptr.next' et de faire une boucle alors que ce n'est pas' None'. – Blorgbeard

+1

Il semble que vous interprétez mal l'utilisation de '' 'self'''. Sans analyser votre code: que fait '' 'return 1 + count (ptr.next)' '' faire? Et pourquoi retourner une chaîne de 0 dans un cas et un nombre 1 dans l'autre ... – sascha

+1

Notez qu'il existe une [limite de récursivité] (https://stackoverflow.com/questions/3323001/what-is-the-maximum -recursion-depth-in-python-et-comment-augmenter-it) en python, donc votre liste ne peut pas être plus longue que ça, ou votre méthode de comptage récursive va planter! – Blorgbeard

Répondre

6

En Python arguments par défaut sont pas expressions qui sont évaluées lors de l'exécution. Ce sont des expressions qui sont évaluées lorsque le def lui-même est évalué. Donc, pour un class habituellement lorsque le fichier est lu pour la première fois. Par conséquent, à ce moment-là, il n'y a pas de self. self est un paramètre. Donc, ce n'est disponible que lorsque vous appelez la fonction.

Vous pouvez résoudre ce problème en utilisant par exemple None par défaut et effectuer une vérification. Mais ici, nous ne pouvons pas utiliser None, puisque vous y avez déjà attaché une signification particulière. Nous pouvons cependant construire un objet dummy, et utiliser celui-ci:

dummy = object() 

def count(self, ptr=dummy): 
    if ptr is dummy: ptr = self.head 
    if ptr == None: 
     return '0' 
    else: 
     return 1 + self.count(ptr.next)

Un autre problème avec votre code est que vous renvoyer une chaîne zéro. Puisque vous ne pouvez pas simplement ajouter un entier et une chaîne, cela provoquera une erreur. Donc, vous devez retourner un entier à la place:

dummy = object() 

def count(self, ptr=dummy): 
    if ptr is dummy: 
     ptr = self.head 
    if ptr == None: 
     return 0 # use an integer 
    else: 
     return 1 + self.count(ptr.next)
+0

Plus précisément, la valeur par défaut est évaluée lorsque l'instruction 'def' est elle-même. – chepner

+1

Oh, je vois, j'étais comme ça devrait fonctionner, pourquoi n'est-ce pas. Donc, le soi n'est pas connu jusqu'à ce que def soit exécuté. Merci beaucoup –

+1

@OmOWalker Dans 'def nombre (self, ptr = self.head) 'l'interpréteur doit définir la valeur par défaut de' ptr' alors qu'il compile cette ligne 'def', donc il doit évaluer' self.head'. Mais à ce moment-là il n'y a pas d'objet nommé 'self' dans la portée: aucune instance de la classe' LinkedList' n'existe encore, et en fait la classe elle-même n'existe pas encore. –

0

Vous pouvez également mettre l'appel purement récursif dans une méthode spécifique, et d'utiliser un emballage autour:

def count(self): 
    def count_rec(ptr): 
     if ptr == None: 
      return 0 
     else: 
      return 1 + count_rec(ptr.next) 
    return count_rec(self.head) 

OMI, c'est plus propre que d'utiliser un un objet fictif et/ou des paramètres par défaut (btw, spécifier un paramètre par défaut dans une fonction récursive est souvent un bon signe que vous devriez considérer une fonction récursive interne et l'appeler de votre méthode avec l'initialisation correcte).

+0

Il y a aussi un inconvénient à cette approche: la fonction interne est redéfinie chaque fois que la fonction externe est appelée, plutôt que d'être définie une fois, lorsque le script est initialement analysé. Le surcoût supplémentaire peut être significatif si 'count' est appelé souvent. Bien sûr, si l'on se soucie trop de l'efficacité, l'implémentation d'une liste chaînée dans Python n'est probablement pas une bonne idée. ;) –

+1

Si c'est un problème, vous pouvez mettre la fonction interne à l'extérieur et l'appeler de la bonne méthode (c'est en fait comment vous l'implémenteriez en Java, en le marquant private pour vous assurer que seule la méthode "proper" l'appelle). Mais je suis d'accord que faire des listes chaînées en Python, puis utiliser la récursivité en plus, est déjà très mauvais en termes d'efficacité. – pills

+0

Ne pouvez-vous pas simplement appeler 'self.next.count()' et supprimer la fonction interne et le paramètre 'ptr'? – Blorgbeard