【问题标题】:Recursion Error - Degrees of Separation递归误差 - 分离度
【发布时间】:2011-11-22 05:29:32
【问题描述】:

我试图找出电影数据库中任意两个演员之间的分离度。 当我达到我的基本情况时,我成功了,即 1 度分离(即演员与另一个演员在同一部电影中)但我使用递归来找到所有其他分离度,我得到:

runtime error: maximum recursion depth exceeded in cmp.
##gets file with movie information
f = open("filename.txt")
actedWith = {}
ActorList = []
movies = {}
actedIn = []
dos = 1

def getDegrees(target, base, dos):
    for actor in actedWith[base]:
        if target == actor:
            print base, "has ", dos, " degree(s) of separation from ", target
            return
    dos = dos+1
    for actor in actedWith[base]:
        getDegrees(target, actor, dos)


for l in f:
    ##strip of whitespace
    l = l.strip()
    ##split by where forward-slashes are
    l = l.split("/")
    ##add the first "word" on the line to the database of movie names
    movies = {l[0] : l[1:]}
    for e in l[1:]:
        if e in actedWith:
            actedWith[e] = actedWith[e]+movies[l[0]]
        else:
            actedWith[e] = movies[l[0]]

base = raw_input("Enter Actor Name (Last, First): ")
target = raw_input("Enter Second Actor Name (Last, First): ")
getDegrees(target, base, dos)

我使用的文本文件可以在http://www.mediafire.com/?qtryvkzmuv5jey3找到

为了测试基本情况,我使用:Bacon, KevinPitt, Brad

为了测试其他人,我使用 Bacon, KevinGamble, Nathan

【问题讨论】:

    标签: python database recursion


    【解决方案1】:

    两个建议(我没有查看文本文件,只是在这里介绍第一原则并快速阅读您的代码):

    1. 当您从 getDegrees 返回时,您仍在执行返回后的其余函数。您需要返回一个 True (或其他内容)以指示搜索结束并且应该回滚整个函数调用堆栈。第一个 return 将更改为“return True”,最后一行将更改为“if getDegrees(target, actor, dos): return True”。
    2. 跟踪已搜索过哪些演员。如果两个演员互相演戏,或者关系中有一个循环,你就会来回循环。

    此代码尝试修复返回和图形循环问题。但是,某处仍然存在逻辑错误; Kevin Bacon 和 James Belushi(分离度为 2)给出以下内容:

    Siravo, Joseph 与 Belushi, James 有 179 度的分离度

    编辑:通过添加“原始”参数修复。

    但是递归问题是固定的。

    ##gets file with movie information
    f = open("filename.txt")
    actedWith = {}
    ActorList = []
    movies = {}
    actedIn = []
    dos = 1
    
    def getDegrees(original, target, base, dos=0, seen=[]):
        dos = dos+1
        print "----> checking %s against %s" % (target, base)
        for actor in actedWith[base]:
            #print "\t" + actor
            if target == actor:
                print original, "has ", dos, " degree(s) of separation from ", target
                return True
        for actor in actedWith[base]:
            if actor in seen: continue
            seen = seen + [actor]
            if getDegrees(original, target, actor, dos, seen):
                return True
        return False
    
    
    for l in f:
        ##strip of whitespace
        l = l.strip()
        ##split by where forward-slashes are
        l = l.split("/")
        ##add the first "word" on the line to the database of movie names
        movies = {l[0] : l[1:]}
        for e in l[1:]:
            if e in actedWith:
                actedWith[e] = actedWith[e]+movies[l[0]]
            else:
                actedWith[e] = movies[l[0]]
    
    original = raw_input("Enter Actor Name (Last, First): ")
    target = raw_input("Enter Second Actor Name (Last, First): ")
    getDegrees(original, target, original)
    

    例子:

    Bacon, Kevin has  65  degree(s) of separation from  Kosaka, Masami
    

    【讨论】:

    • 不...递归问题仍然存在,不幸的是。我输入了一组不同的演员:Bacon、Kevin 和 Kosaka、Masami。相同的递归错误。返回不同名称的错误是由'print base,“has”,dos,“degree(s) from”,target'引起的通过创建一个新变量来存储原始base,问题得到了解决,虽然逻辑错误计数度数仍然存在。
    • @RMartin 请检查您的实施。我刚刚测试了这个名字,它工作正常。
    • 抱歉...试试约翰逊,切丽。我只是复制/粘贴您的代码以确保;它似乎搜索了许多,然后返回运行时错误。
    【解决方案2】:

    除非我没有看到 actedWith 的某些属性,否则您没有任何东西可以防止无限循环。例如,您的一个递归调用将是getDegrees("Gamble, Nathan", "Pitt, Brad", 2),那么由于凯文培根与布拉德皮特合作,当您更深入时,您将调用getDegrees("Gamble, Nathan", "Bacon, Kevin", 3)。看到问题了吗?

    【讨论】:

      【解决方案3】:

      这可能是无限递归。您正在搜索植根于目标的树;那棵树上的一些路径正在到达它们上游的点。您需要一种方法来识别这一点,并在它发生时停止往下看。

      一种方法是在路径上保留祖先列表。比如:

      def getDegrees(target, base, dos, ancestors):  # Also carry a list of "ancestors"
          for actor in actedWith[base]:
              if target == actor:
                  print base, "has ", dos, " degree(s) of separation from ", target
                  return
          dos = dos+1
          ancestors = ancestors + [base]  # Must be separate variable binding to avoid mutating the caller's copy
          for actor in actedWith[base]:
              if actor in ancestors: continue  # Check if on path, skip if so
              getDegrees(target, actor, dos, ancestors)
      
      ...
      
      getDegrees(target, base, dos, [target])
      

      请注意,“祖先”是指路径上的一个点,而不是演员可能与之相关的人。

      这并不能避免演员自己拥有actedWith 的情况(希望输入文件永远不会包含它),但只需稍作改动即可。

      【讨论】:

      • 我尝试实现这个...但是,我仍然遇到同样的错误。
      • @RMartin 此代码不正确;它不会将祖先传递给 getDegrees 递归,也不会解决返回问题。
      • 啊,真的。问题是我懒得运行它。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-28
      • 1970-01-01
      • 2016-12-10
      相关资源
      最近更新 更多