【问题标题】:LinkedLists in python recursionpython递归中的链表
【发布时间】:2018-03-30 13:23:51
【问题描述】:

我在 python 中有一个简单的 LinkedList 实现。如何在方法中使用递归?我知道递归是如何工作的,但我如何在递归中使用 self 。如果有人可以修复我的代码,那就太好了,但我对解释更感兴趣,所以我可以在不同的方法中使用它。

链表代码:

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 

我的代码是:

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

它给了我一个错误:

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

非常感谢任何帮助。

【问题讨论】:

  • 我不建议为此使用递归。只更新ptr = ptr.next 并在不是None 时循环更有效。
  • 您似乎误解了 self 的用途。在不分析您的代码的情况下:return 1 + count(ptr.next) 做了什么?为什么在一种情况下返回一个字符串 0 而在另一种情况下返回一个数字 1...
  • 注意python中有一个recursion limit,所以你的列表不能超过这个,否则你的递归计数方法会崩溃!
  • @Blorgbeard 不幸的是,我不得不为此使用递归。

标签: python recursion linked-list


【解决方案1】:

在 Python 中,默认参数是不是在运行时计算的表达式。这些是在评估 def 本身时评估的表达式。所以对于class,通常是在第一次读取文件时。

结果,在那一刻,没有selfself 是一个参数。所以只有当你调用这个函数时才可用。

您可以通过使用例如None 作为默认值并执行检查来解决该问题。但是这里我们不能使用None,因为你已经给它附加了一个特殊的含义。然而,我们可以构造一个dummy 对象,并使用它:

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)

您的代码的另一个问题是您返回一个字符串为零。由于您不能简单地将整数和字符串相加,因此会出错。所以你应该返回一个整数:

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)

【讨论】:

  • 更准确地说,默认值是在def 语句本身时计算的。
  • 哦,我明白了,我觉得这应该可以,为什么不呢。所以 self 在 def 执行之前是未知的。非常感谢
  • @OmOWalker 在def count(self, ptr=self.head) 中,解释器在编译def 行时必须为ptr 设置默认值,因此它必须评估self.head。但在那个时间点,范围内还没有一个名为 self 的对象:LinkedList 类的实例尚不存在,实际上该类本身还不存在。
【解决方案2】:

您还可以将纯递归调用放在特定方法中,并在其周围使用包装器:

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

IMO,这比使用虚拟对象和/或默认参数更干净(顺便说一句,在递归函数中指定默认参数通常是一个好兆头,表明您应该考虑使用内部递归函数并使用正确初始化)。

【讨论】:

  • 这种方法也有一个缺点:每次调用外部函数时都会重新定义内部函数,而不是在最初扫描脚本时重新定义一次。如果经常调用count,额外的开销可能会很大。当然,如果过分关注效率,那么在 Python 中实现链表可能不是一个好主意。 ;)
  • 如果这是一个问题,您可以将内部函数放在外面并从正确的方法调用它(例如,这实际上是您在 Java 中实现它的方式,将其标记为私有以确保只有“正确的”方法调用它)。但我同意在 Python 中做链表,然后在此之上使用递归,在效率方面已经很糟糕了。
  • 你能不能只调用self.next.count() 并取消内部函数和ptr 参数?
  • @Blorgbeard:这是我最初的想法,但self.next 不是LinkedList,而是Node。这意味着为Node 定义count(),这实际上没有意义,并且当您尝试为空列表调用它时可能会中断(其中nextNone)。
猜你喜欢
  • 1970-01-01
  • 2021-03-25
  • 2015-05-06
  • 2021-12-22
  • 2017-04-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多