Python递归 - 如何提前退出

时间:2015-09-30 08:39:36

标签: python recursion binary-search-tree exit

我一直在玩BST(二叉搜索树),我想知道如何提前退出。以下是我写的代码,以找到第k个最小的代码。它以递归方式调用子节点的find_smallest_at_k,stack只是传递给函数的列表,用于按顺序添加所有元素。目前,此解决方案按顺序遍历所有节点,然后我必须从此函数外的“堆栈”中选择第k项。

def find_smallest_at_k(self, k, stack, i):
    if self is None:
        return i

    if (self.left is not None): 
        i = self.left.find_smallest_at_k(k, stack, i) 

    print(stack, i)
    stack.insert(i, self.data)
    i += 1
    if i == k: 
        print(stack[k - 1]) 
        print "Returning" 

    if (self.right is not None): 
        i = self.right.find_smallest_at_k(k, stack, i) 

    return i 

这就像这样,

our_stack = []
self.root.find_smallest_at_k(k, our_stack, 0) 
return our_stack[k-1] 

我不确定是否可以提前退出该功能。如果我的k说1,我真的不必走所有节点然后找到第一个元素。从外部函数传递列表也感觉不对 - 感觉就像是将指针传递给C中的函数。任何人都可以提出比我迄今为止所做的更好的替代方案吗?

3 个答案:

答案 0 :(得分:1)

将列表作为参数传递:将列表作为参数传递可能是一种很好的做法,如果使函数尾递归。否则它毫无意义。对于BST,有两个潜在的递归函数调用要做,这有点高。

否则你可以返回列表。我没有看到变量i的必要性。无论如何,如果你绝对需要返回多个值,你总是可以使用像return i, stacki, stack = root.find_smallest_at_k(k)这样的元组。

快进:对于快进,请注意BST父节点的正确节点始终大于父节点。因此,如果你总是在正确的孩子身上下树,你最终会得到越来越多的价值观。因此,该序列的第一个k值必然是最小的,因此在序列中右k次或更长时间是没有意义的。

即使在你下降的中间,你有时会向左走,在右边超过k次也没有意义。 BST属性确保如果您正确,层次结构中下面的所有后续数字将大于父级。因此,正确k次或更长时间是无用的。

代码:这是一个快速制作的伪python代码。它没有经过测试。

def findKSmallest( self, k, rightSteps=0 ):
    if rightSteps >= k: #We went right more than k times
        return []
    leftSmallest = self.left.findKSmallest( k, rightSteps ) if self.left != None else []
    rightSmallest = self.right.findKSmallest( k, rightSteps + 1 ) if self.right != None else []
    mySmallest = sorted( leftSmallest + [self.data] + rightSmallest )
    return mySmallest[:k]

编辑其他版本,跟随我的评论。

def findKSmallest( self, k ):
    if k == 0:
        return []
    leftSmallest = self.left.findKSmallest( k ) if self.left != None else []
    rightSmallest = self.right.findKSmallest( k - 1 ) if self.right != None else []
    mySmallest = sorted( leftSmallest + [self.data] + rightSmallest )
    return mySmallest[:k]

请注意,如果k==1,这确实是对最小元素的搜索。任何向右移动,都会立即返回[],这对任何事都没有贡献。

答案 1 :(得分:0)

正如Lærne所说,你必须要关心将你的功能变成一个尾递归的功能;那么你可能会对使用延续传递风格感兴趣。因此,您的函数可以调用自身或“转义”函数。我写了一个名为tco的模块来优化尾调用;见https://github.com/baruchel/tco 希望它可以提供帮助。

答案 2 :(得分:0)

这是另一种方法:它不会提前退出递归,而是在不需要时阻止其他函数调用,这实际上是您要实现的目标。

class Node:
    def __init__(self, v):
        self.v = v
        self.left = None
        self.right = None

def find_smallest_at_k(root, k):
    res = [None]
    count = [k]

    def helper(root):
        if root is None:
            return

        helper(root.left)
        count[0] -= 1
        if count[0] == 0:
            print("found it!")
            res[0] = root
            return

        if count[0] > 0:
            print("visiting right")
            find(root.right)

    helper(root)
    return res[0].v