使用广度优先搜索查找节点路径
Finding path to node using Breadth First Search
我有一棵二叉树,我想实现广度优先搜索算法来搜索树中的一个节点。我设法做了某种树,我想为 BFS 创建一个函数,它打印出到选定节点的路径。如何实现这样的功能?
class Node:
# A utility function to create a new node
def __init__(self, key):
self.data = key
self.left = None
self.right = None
root = Node('A')
root.left = Node('B')
root.left.left = Node('D')
root.left.right = Node('E')
root.left.left.left = Node('G')
root.left.left.right = Node('H')
root.left.right.right = Node('K')
root.left.right.left = Node('I')
root.left.right.left.left = Node('K')
您可以使用队列执行标准 BFS,但将该节点的路径添加为队列中状态的一部分。
from collections import deque
class Node:
def __init__(self, key):
self.data = key
self.left = None
self.right = None
def path_from_to(root, target):
queue = deque([(root, [root.data])])
while queue:
node, path = queue.popleft()
if node == target:
return path
if node.left:
queue.append((node.left, path + [node.left.data]))
if node.right:
queue.append((node.right, path + [node.right.data]))
if __name__ == "__main__":
root = Node('A')
root.left = Node('B')
root.left.left = Node('D')
root.left.right = Node('E')
root.left.left.left = Node('G')
root.left.left.right = Node('H')
root.left.right.right = Node('K')
root.left.right.left = Node('I')
target = Node('K')
root.left.right.left.left = target
print(path_from_to(root, target))
输出:
['A', 'B', 'E', 'I', 'K']
因为它是一棵树,我们不需要保留以前访问过的节点的列表。
请注意,DFS 通常更适合在树中搜索。
或者,您可以使用需要更多处理但内存更少(比队列)的方法:
节点 class 本身可以提供迭代器,这些迭代器将以自上而下或自下而上的广度优先顺序遍历节点。
class Node:
def __init__(self, value):
self.value = value
self.left = None
self.right = None
@property
def maxLevel(self):
return max(self.left.maxLevel+1 if self.left else 0,
self.right.maxLevel+1 if self.right else 0)
def topDown(self):
for depth in range(self.maxLevel+1):
for node in self.nodesAtLevel(depth): yield node
def bottomUp(self):
for depth in range(self.maxLevel,-1,-1):
for node in self.nodesAtLevel(depth): yield node
def nodesAtLevel(self,depth,level=0):
if level == depth:
yield self # output node when at requested depth
return
for subNode in (self.left,self.right): # reach deeper
if not subNode: continue
for node in subNode.nodesAtLevel(depth,level+1):
yield node
输出:
root = Node('A') # level 0
B = root.left = Node('B') # level 1
D = B.left = Node('D') # level 2
E = B.right = Node('E') # level 2
G = D.left = Node('G') # level 3
H = D.right = Node('H') # level 3
K = root.right = Node('K') # level 1
I = K.left = Node('I') # level 2
for node in root.topDown(): print(node.value)
# A B K D E I G H
for node in root.bottomUp(): print(node.value)
# G H D E I B K A
您还可以进一步扩展 class 以添加其他类型的遍历迭代器:
def leftToRight(self):
if self.left:
for node in self.left.leftToRight(): yield node
yield self
if self.right:
for node in self.right.leftToRight(): yield node
def rightToLeft(self):
if self.right:
for node in self.right.rightToLeft(): yield node
yield self
if self.left:
for node in self.left.rightToLeft(): yield node
要使用广度优先搜索实现路径功能,您应该使用自下而上的功能并在找到父项时附加它们(因为父项将按此顺序出现在子项之后):
def BFPath(self,node):
path = [node]
for parent in self.bottomUp():
if path[-1] in [parent.left,parent.right]:
path.append(parent)
return path[::-1]
使用示例:
print([n.value for n in root.BFPath(H)])
# ['A', 'B', 'D', 'H']
我有一棵二叉树,我想实现广度优先搜索算法来搜索树中的一个节点。我设法做了某种树,我想为 BFS 创建一个函数,它打印出到选定节点的路径。如何实现这样的功能?
class Node:
# A utility function to create a new node
def __init__(self, key):
self.data = key
self.left = None
self.right = None
root = Node('A')
root.left = Node('B')
root.left.left = Node('D')
root.left.right = Node('E')
root.left.left.left = Node('G')
root.left.left.right = Node('H')
root.left.right.right = Node('K')
root.left.right.left = Node('I')
root.left.right.left.left = Node('K')
您可以使用队列执行标准 BFS,但将该节点的路径添加为队列中状态的一部分。
from collections import deque
class Node:
def __init__(self, key):
self.data = key
self.left = None
self.right = None
def path_from_to(root, target):
queue = deque([(root, [root.data])])
while queue:
node, path = queue.popleft()
if node == target:
return path
if node.left:
queue.append((node.left, path + [node.left.data]))
if node.right:
queue.append((node.right, path + [node.right.data]))
if __name__ == "__main__":
root = Node('A')
root.left = Node('B')
root.left.left = Node('D')
root.left.right = Node('E')
root.left.left.left = Node('G')
root.left.left.right = Node('H')
root.left.right.right = Node('K')
root.left.right.left = Node('I')
target = Node('K')
root.left.right.left.left = target
print(path_from_to(root, target))
输出:
['A', 'B', 'E', 'I', 'K']
因为它是一棵树,我们不需要保留以前访问过的节点的列表。
请注意,DFS 通常更适合在树中搜索。
或者,您可以使用需要更多处理但内存更少(比队列)的方法:
节点 class 本身可以提供迭代器,这些迭代器将以自上而下或自下而上的广度优先顺序遍历节点。
class Node:
def __init__(self, value):
self.value = value
self.left = None
self.right = None
@property
def maxLevel(self):
return max(self.left.maxLevel+1 if self.left else 0,
self.right.maxLevel+1 if self.right else 0)
def topDown(self):
for depth in range(self.maxLevel+1):
for node in self.nodesAtLevel(depth): yield node
def bottomUp(self):
for depth in range(self.maxLevel,-1,-1):
for node in self.nodesAtLevel(depth): yield node
def nodesAtLevel(self,depth,level=0):
if level == depth:
yield self # output node when at requested depth
return
for subNode in (self.left,self.right): # reach deeper
if not subNode: continue
for node in subNode.nodesAtLevel(depth,level+1):
yield node
输出:
root = Node('A') # level 0
B = root.left = Node('B') # level 1
D = B.left = Node('D') # level 2
E = B.right = Node('E') # level 2
G = D.left = Node('G') # level 3
H = D.right = Node('H') # level 3
K = root.right = Node('K') # level 1
I = K.left = Node('I') # level 2
for node in root.topDown(): print(node.value)
# A B K D E I G H
for node in root.bottomUp(): print(node.value)
# G H D E I B K A
您还可以进一步扩展 class 以添加其他类型的遍历迭代器:
def leftToRight(self):
if self.left:
for node in self.left.leftToRight(): yield node
yield self
if self.right:
for node in self.right.leftToRight(): yield node
def rightToLeft(self):
if self.right:
for node in self.right.rightToLeft(): yield node
yield self
if self.left:
for node in self.left.rightToLeft(): yield node
要使用广度优先搜索实现路径功能,您应该使用自下而上的功能并在找到父项时附加它们(因为父项将按此顺序出现在子项之后):
def BFPath(self,node):
path = [node]
for parent in self.bottomUp():
if path[-1] in [parent.left,parent.right]:
path.append(parent)
return path[::-1]
使用示例:
print([n.value for n in root.BFPath(H)])
# ['A', 'B', 'D', 'H']