[英]Python recursive function to search a binary tree
Very new at Python and I'm trying to understand recursion over a binary tree.在 Python 上非常新,我正在尝试了解二叉树的递归。 I've implemented a very simple tree, which funnily enough maps English characters to binary (1's and 0's).
我已经实现了一个非常简单的树,它很有趣地将英文字符映射到二进制(1 和 0)。 I've only used a very simple structure because I am struggling to get my head round a more complex question that I've been set.
我只使用了一个非常简单的结构,因为我正在努力思考一个我已经设定好的更复杂的问题。 I figure if I can get my head round my example then I should be able to go away and look at the question I've been set myself.
我想如果我能理解我的例子那么我应该能够离开 go 并看看我自己设置的问题。
The following creates the class BinaryTree and an instance of this下面创建 class BinaryTree 和它的一个实例
class BinaryTree:
"""A rooted binary tree"""
def __init__(self):
self.root = None
self.left = None
self.right = None
def is_empty(testtree: BinaryTree) -> bool:
"""Return True if tree is empty."""
return testtree.root == testtree.left == testtree.right == None
def join(item: object, left: BinaryTree, right: BinaryTree) -> BinaryTree:
"""Return a tree with the given root and subtrees."""
testtree = BinaryTree()
testtree.root = item
testtree.left = left
testtree.right = right
return testtree
EMPTY = BinaryTree()
C = join('C',EMPTY,EMPTY)
D = join('D',EMPTY,EMPTY)
E = join('E',EMPTY,EMPTY)
F = join('F',EMPTY,EMPTY)
A = join('A',C,D)
B = join('B',E,F)
BINARY = join('START',B,A)
I visualise it as follows我将其可视化如下
Visualisation of the Binary tree二叉树的可视化
Now I'm trying to create a function that will take two inputs, a BinaryTree and a single character and the output will be the binary code for the corresponding letter (as an example, D = " 10 ").现在我正在尝试创建一个 function,它将接受两个输入,一个二叉树和一个字符,而 output 将是相应字母的二进制代码(例如,D =“10”)。 I'm outputting as a string rather than an integer. My function and test case as follows
我输出为字符串而不是 integer。我的 function 和测试用例如下
# global variable
result = ''
#Convert binary to letter
def convert_letter(testtree: BinaryTree, letter: str) -> str:
global result
if testtree == None:
return False
elif testtree.root == letter:
return True
else:
if convert_letter(testtree.left, letter) == True:
result += "1"
return result
elif convert_letter(testtree.right, letter) == True:
result += "0"
return result
#Test
test = 'D' #Return '10'
convert_letter(BINARY, test)
And unfortunately that's where I'm hitting a brick wall.不幸的是,这就是我碰壁的地方。 I had tried initialising an empty string within the function, but everytime it iterates over the function it overwrites the string.
我曾尝试在 function 中初始化一个空字符串,但每次迭代 function 时都会覆盖该字符串。 Any help greatly appreciated.
非常感谢任何帮助。
I took the liberty of simplfying your code a bit let me know if you have any questions about how this works.我冒昧地简化了您的代码,如果您对它的工作原理有任何疑问,请告诉我。
class node:
"""A rooted binary tree"""
def __init__(self, value = None, left = None, right = None):
self.value = value
self.left = left
self.right = right
C = node('C')
D = node('D')
E = node('E')
F = node('F')
A = node('A',C,D)
B = node('B',E,F)
BINARY = node('START',B,A)
def convert_letter(n,letter):
if n.value == letter:
return "1"+(convert_letter(n.left,letter) if not n.left is None else "")+(convert_letter(n.right,letter)if not n.right is None else "")
else:
return "0"+(convert_letter(n.left,letter) if not n.left is None else "")+(convert_letter(n.right,letter)if not n.right is None else "")
def walk(n):
return n.value+(walk(n.left) if not n.left is None else "")+(walk(n.right) if not n.right is None else "")
test = 'D'
print(convert_letter(BINARY, test))
print(walk(BINARY))
This is not how I would personally structure an answer, but I think it most closely follows what you are attempting.这不是我个人构建答案的方式,但我认为它最接近您的尝试。 The shortcoming of your answer only being that you are only returning one value, but kind of tracking two values.
你的答案的缺点只是你只返回一个值,但有点跟踪两个值。 Note, I have taken the liberty of correcting:
请注意,我冒昧地更正了:
BINARY = join('START',A,B)
Let's modify your method to return both a Boolean indicating if the letter was found as well as the indicator of the path.让我们修改您的方法以返回 Boolean 指示是否找到字母以及路径指示符。
def convert_letter2(testtree: BinaryTree, letter: str):
if not testtree:
return (False, "")
if testtree.root == letter:
return (True, "")
test, val = convert_letter2(testtree.left, letter)
if test:
return (True, "1" + val)
test, val = convert_letter2(testtree.right, letter)
if test:
return (True, "0" + val)
return (False, "")
Then if we:那么如果我们:
print(convert_letter2(BINARY, "D")[1])
We should get back "10"
我们应该找回
"10"
The problem is that your function will sometimes return a boolean, sometimes a string, and sometimes None
.问题是您的 function 有时会返回 boolean,有时是字符串,有时是
None
。 So with this code:所以用这段代码:
if convert_letter(testtree.left, letter) == True:
result += "1"
return result
elif convert_letter(testtree.right, letter) == True:
result += "0"
return result
... you are not capturing all successful searches, as a successful search would return the actual string of "0" and "1" which obviously is not True
. ...您没有捕获所有成功的搜索,因为成功的搜索将返回 "0" 和 "1" 的实际字符串,这显然不是
True
。 In that case the execution has no else
to go to and returns None
-- even when the letter was found in a deeper node.在那种情况下,执行没有
else
到 go 并返回None
- 即使在更深的节点中找到该字母。
Your function should not return a boolean -- that doesn't match the type hint either.您的 function 不应返回 boolean - 也不匹配类型提示。 It should be a string (the result).
它应该是一个字符串(结果)。 You could reserve
None
to indicate the letter was not found.您可以保留
None
以指示未找到该字母。
Some other problems:其他一些问题:
result += "0"
will append the digit, but since you already made the recursive call, you need to prepend the digit -- as you are higher up in the tree now. result += "0"
将为append数字,但由于您已经进行了递归调用,因此您需要在数字前面加上- 因为您现在在树中更高。
The initialisation of your tree makes a different tree than you put in the image: A
should be the left child, not the right child.树的初始化与您在图像中放置的树不同:
A
应该是左孩子,而不是右孩子。 So it should be join('START', A, B)
所以它应该是
join('START', A, B)
With those fixes, you'd have this code:通过这些修复,您将获得以下代码:
def convert_letter(testtree: BinaryTree, letter: str) -> str:
global result
if testtree is None:
result = None # Not found here
elif testtree.root == letter:
result = '' # Found! Start a path
elif convert_letter(testtree.left, letter) is not None:
result = "1" + result # Prepend
elif convert_letter(testtree.right, letter) is not None:
result = "0" + result # Prepend
else:
result = None # Not found here
return result
If you also correct to use join('START', A, B)
, then the output will be 10
.如果您还正确使用
join('START', A, B)
,则 output 将为10
。
There are some things you can do better:有些事情你可以做得更好:
Don't use a global variable for storing the function result.不要使用全局变量来存储 function 结果。 As you return it, you can capture the
result
you get from a recursive call as a local variable, prepend to it, and return it again.当您返回它时,您可以捕获从递归调用中获得的
result
作为局部变量,添加到它之前,然后再次返回它。
The definition of EMPTY
makes your tree unnecessarily big. EMPTY
的定义使你的树变得不必要的大。 Just use None
to denote an empty tree.只需使用
None
来表示一棵空树。
Don't call a node's value root
.不要调用节点的值
root
。 A rooted tree has only one root, and it is a node, not a value of a node.有根树只有一个根,它是一个节点,而不是节点的值。 So call that attribute
value
or data
, but not root
.因此调用该属性
value
或data
,而不是root
。
The join
function is nice, but why not use the constructor for that feature? join
function 很好,但为什么不使用该功能的构造函数呢? The constructor can take those arguments as optional and immediately initialise the left
and right
attributes with those arguments.构造函数可以将那些 arguments 作为可选值,并立即
right
left
。
The code-comment above the convert_letter
function describes the opposite from what the function does. convert_letter
function 上方的代码注释与 function 的作用相反。
Taking all that into account, your code could look like this:考虑到所有这些,您的代码可能如下所示:
class BinaryTree:
def __init__(self, value, left: 'BinaryTree'=None, right: 'BinaryTree'=None):
self.value = value
self.left = left
self.right = right
def convert_letter(tree: BinaryTree, letter: str) -> str:
if not tree:
return # Not found here, return None
if tree.value == letter:
return "" # Bingo: return an empty path
# No more global. path is a local variable
path = convert_letter(tree.left, letter)
if path is not None:
return "1" + path
path = convert_letter(tree.right, letter)
if path is not None:
return "0" + path
# Look how nice it is to create a tree using the constructor arguments
binary = BinaryTree("Start",
BinaryTree("A",
BinaryTree("C"), BinaryTree("D")
),
BinaryTree("B",
BinaryTree("E"), BinaryTree("F")
)
)
# Test
test = 'D'
print(convert_letter(binary, test)) # 10
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.