我一直在玩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中的函数。任何人都可以提出比我迄今为止所做的更好的替代方案吗?
答案 0 :(得分:1)
将列表作为参数传递:将列表作为参数传递可能是一种很好的做法,如果使函数尾递归。否则它毫无意义。对于BST,有两个潜在的递归函数调用要做,这有点高。
否则你可以返回列表。我没有看到变量i
的必要性。无论如何,如果你绝对需要返回多个值,你总是可以使用像return i, stack
和i, 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