我有一棵树作为广度优先搜索的输入,我想知道算法在哪个级别进展?
# Breadth First Search Implementation
graph = {
'A':['B','C','D'],
'B':['A'],
'C':['A','E','F'],
'D':['A','G','H'],
'E':['C'],
'F':['C'],
'G':['D'],
'H':['D']
}
def breadth_first_search(graph,source):
"""
This function is the Implementation of the breadth_first_search program
"""
# Mark each node as not visited
mark = {}
for item in graph.keys():
mark[item] = 0
queue, output = [],[]
# Initialize an empty queue with the source node and mark it as explored
queue.append(source)
mark[source] = 1
output.append(source)
# while queue is not empty
while queue:
# remove the first element of the queue and call it vertex
vertex = queue[0]
queue.pop(0)
# for each edge from the vertex do the following
for vrtx in graph[vertex]:
# If the vertex is unexplored
if mark[vrtx] == 0:
queue.append(vrtx) # mark it as explored
mark[vrtx] = 1 # and append it to the queue
output.append(vrtx) # fill the output vector
return output
print breadth_first_search(graph, 'A')
它将树作为输入图,我想要的是,在每次迭代时它应该打印出正在处理的当前级别。
答案 0 :(得分:31)
您不需要使用额外的队列或进行任何复杂的计算来实现您想要的目标。这个想法很简单。
除了用于BFS的队列之外,这不会使用任何额外的空间。
我要使用的想法是在每个级别的末尾添加null
。因此,您遇到的空值数+1是您所处的深度。 (当然在终止后它只是level
)。
int level = 0;
Queue <Node> queue = new LinkedList<>();
queue.add(root);
queue.add(null);
while(!queue.isEmpty()){
Node temp = queue.poll();
if(temp == null){
level++;
queue.add(null);
if(queue.peek() == null) break;// You are encountering two consecutive `nulls` means, you visited all the nodes.
else continue;
}
if(temp.right != null)
queue.add(temp.right);
if(temp.left != null)
queue.add(temp.left);
}
答案 1 :(得分:4)
维护一个队列,在BFS队列中存储相应节点的深度。您的信息的示例代码:
queue bfsQueue, depthQueue;
bfsQueue.push(firstNode);
depthQueue.push(0);
while (!bfsQueue.empty()) {
f = bfsQueue.front();
depth = depthQueue.front();
bfsQueue.pop(), depthQueue.pop();
for (every node adjacent to f) {
bfsQueue.push(node), depthQueue.push(depth+1);
}
}
这种方法简单而幼稚,对于O(1)额外空间,您可能需要@stolen_leaves的答案帖。
答案 2 :(得分:3)
试试看这篇文章。它使用变量currentDepth
https://stackoverflow.com/a/16923440/3114945
对于您的实施,跟踪最左侧节点和深度变量。每当从队列中弹出最左边的节点时,你知道你达到了一个新的水平并且你增加了深度。
所以,你的根是0级的leftMostNode
。那么最左边的孩子就是leftMostNode
。一旦你点击它,它就变为1级。这个节点的最左边的孩子是下一个leftMostNode
,依此类推。
答案 3 :(得分:3)
如果您的树完全平衡(即每个节点具有相同数量的子节点),实际上这里有一个简单,优雅的解决方案,具有O(1)时间复杂度和O(1)空间复杂度。我发现这个有用的主要用例是遍历二叉树,尽管它可以很容易地适应其他树的大小。
这里要认识到的关键是二叉树的每个级别包含的节点数量与前一级别相比只有两倍。这允许我们在给定树的深度的情况下计算任何树中的节点总数。例如,请考虑以下树:
此树的总深度为3和7个节点。我们不需要计算节点数来解决这个问题。我们可以在O(1)时间内使用公式计算:2 ^ d - 1 = N,其中d
是深度,N
是节点的总数。 (在三元树中,这是3 ^ d - 1 = N,并且在树中,每个节点具有K个子节点,这是K ^ d - 1 = N)。所以在这种情况下,2 ^ 3 - 1 = 7。
要在进行广度优先搜索时跟踪深度,我们只需要反转此计算。鉴于以上公式允许我们解决给定N
的{{1}},我们实际上想要求d
给定d
。例如,假设我们正在评估第5个节点。为了确定第5个节点的深度,我们采用以下等式:2 ^ d - 1 = 5,然后简单求解N
,这是基本代数:
如果d
不是一个整数,那么只是向上舍入(一行中的最后一个节点总是一个整数)。考虑到这一点,我建议使用以下算法在广度优先遍历期间识别二叉树中任何给定节点的深度:
d
等于0。visited
递增1。visited
递增时,将节点的深度计算为visited
您还可以使用哈希表将每个节点映射到其深度级别,但这确实会将空间复杂度增加到O(n)。这是该算法的PHP实现:
depth = round_up(log2(visited + 1))
打印哪些:
<?php
$tree = [
['A', [1,2]],
['B', [3,4]],
['C', [5,6]],
['D', [7,8]],
['E', [9,10]],
['F', [11,12]],
['G', [13,14]],
['H', []],
['I', []],
['J', []],
['K', []],
['L', []],
['M', []],
['N', []],
['O', []],
];
function bfs($tree) {
$queue = new SplQueue();
$queue->enqueue($tree[0]);
$visited = 0;
$depth = 0;
$result = [];
while ($queue->count()) {
$visited++;
$node = $queue->dequeue();
$depth = ceil(log($visited+1, 2));
$result[$depth][] = $node[0];
if (!empty($node[1])) {
foreach ($node[1] as $child) {
$queue->enqueue($tree[$child]);
}
}
}
print_r($result);
}
bfs($tree);
答案 4 :(得分:1)
使用此Python代码,只有在队列中遇到新深度的节点之后,才可以通过增加深度来保持每个节点距根的深度。
queue = deque()
marked = set()
marked.add(root)
queue.append((root,0))
depth = 0
while queue:
r,d = queue.popleft()
if d > depth: # increase depth only when you encounter the first node in the next depth
depth += 1
for node in edges[r]:
if node not in marked:
marked.add(node)
queue.append((node,depth+1))
答案 5 :(得分:1)
在Java中将是这样。 想法是看父母决定深度。
//Maintain depth for every node based on its parent's depth
Map<Character,Integer> depthMap=new HashMap<>();
queue.add('A');
depthMap.add('A',0); //this is where you start your search
while(!queue.isEmpty())
{
Character parent=queue.remove();
List<Character> children=adjList.get(parent);
for(Character c:children)
{
depthMap.add(c,depthMap.get(parent)+1);//parent's depth + 1
}
}
答案 6 :(得分:1)
实际上,我们不需要额外的队列来存储深度,也不需要添加null
来告诉它是否是当前级别的结尾。我们只需要当前级别有多少个节点,就可以处理同一级别的所有节点,完成后将级别增加1。
int level = 0;
Queue<Node> queue = new LinkedList<>();
queue.add(root);
while(!queue.isEmpty()){
int level_size = queue.size();
while (level_size--) {
Node temp = queue.poll();
if (temp.right != null) queue.add(temp.right);
if (temp.left != null) queue.add(temp.left);
}
level++;
}
答案 7 :(得分:0)
我用python写了一个简单易读的代码。
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
class Solution:
def dfs(self, root):
assert root is not None
queue = [root]
level = 0
while queue:
print(level, [n.val for n in queue if n is not None])
mark = len(queue)
for i in range(mark):
n = queue[i]
if n.left is not None:
queue.append(n.left)
if n.right is not None:
queue.append(n.right)
queue = queue[mark:]
level += 1
用法
# [3,9,20,null,null,15,7]
n3 = TreeNode(3)
n9 = TreeNode(9)
n20 = TreeNode(20)
n15 = TreeNode(15)
n7 = TreeNode(7)
n3.left = n9
n3.right = n20
n20.left = n15
n20.right = n7
DFS().dfs(n3)
结果
0 [3]
1 [9, 20]
2 [15, 7]
答案 8 :(得分:0)
在浏览图形时,使用字典来跟踪每个节点的水平(距起点的距离)。
Python示例:
from collections import deque
def bfs(graph, start):
queue = deque([start])
levels = {start: 0}
while queue:
vertex = queue.popleft()
for neighbour in graph[vertex]:
if neighbour in levels:
continue
queue.append(neighbour)
levels[neighbour] = levels[vertex] + 1
return levels
答案 9 :(得分:0)
设置变量cnt
并将其初始化为队列cnt=queue.size()
的大小,现在每次弹出时递减cnt
。当cnt
变为0时,增加BFS的深度,然后再次设置cnt=queue.size()
。