
在处理复杂数据结构时,我们常会遇到需要按层级或深度遍历的情况。考虑以下场景:给定一个字典my_dict,它表示一个有向图的邻接列表,其中键是节点,值是其直接邻居的列表。我们还拥有一个起始节点列表source_list和一个目标节点列表target_list。我们的目标是从source_list中的节点开始,逐层遍历my_dict,收集每个层级的节点及其邻居,直到我们遇到的邻居节点包含target_list中的元素。最终输出应是一个字典,其键为遍历的层级(迭代次数),值为该层级中所有被访问节点及其邻居的子字典。
例如,给定以下数据:
source_list = ['a', 'b']
target_list = ['x', 'y', 'z']
my_dict = {
    'a': ['e'],
    'b': ['f', 'd'],
    'e': ['g'],
    'f': ['t', 'h'],
    'd': ['x'],
    'g': ['x'],
    't': ['y'],
    'h': ['z']
}期望的输出是:
{0: {'a': ['e'], 'b': ['f', 'd']},
 1: {'e': ['g'], 'f': ['t', 'h'], 'd': ['x']},
 2: {'g': ['x'], 't': ['y'], 'h': ['z']}}广度优先搜索(BFS)是一种用于遍历或搜索树或图的算法。它从图的根(或任意源节点)开始,首先访问其所有邻居节点,然后访问这些邻居的邻居,依此类推。这种“层层推进”的特性使其非常适合解决按层级遍历的问题。
BFS通常使用队列(Queue)数据结构来实现。基本步骤如下:
立即学习“Python免费学习笔记(深入)”;
在我们的问题中,我们需要扩展BFS以记录每个节点的层级,并在遇到目标节点时停止进一步探索。
我们将构建一个bfs函数来解决这个问题。该函数将接收source(起始节点列表)、target(目标节点列表)和graph(表示图的字典)作为参数。
from collections import deque
def bfs(source, target, graph):
    """
    使用广度优先搜索(BFS)按层级提取字典数据。
    Args:
        source (list): 起始节点列表。
        target (list): 目标节点列表。当邻居节点中包含目标节点时,停止进一步探索。
        graph (dict): 表示图的字典,键是节点,值是其邻居列表。
    Returns:
        dict: 结构化输出,键为层级(迭代次数),值为该层级中所有被访问节点及其邻居的子字典。
    """
    # 初始化队列,存储 (层级, 节点) 对
    queue = deque((0, node) for node in source)
    # 将目标列表转换为集合,以便进行O(1)的快速查找
    target_set = set(target)
    # 记录已访问过的节点,防止循环和重复处理
    seen = set(source) # 初始时,source_list中的节点已被视为“已访问”
    result = {} # 存储最终结果
    while queue:
        level, node = queue.popleft() # 取出当前层级和节点
        # 确保当前节点在图中存在,避免KeyError
        if node not in graph:
            continue
        neighbors = graph[node] # 获取当前节点的邻居
        # 将当前节点及其邻居添加到结果字典中对应层级
        # setdefault确保如果层级不存在,则创建一个空字典
        result.setdefault(level, {})[node] = neighbors.copy()
        # 遍历当前节点的邻居
        for neighbor in neighbors:
            # 如果邻居节点已访问过,或者邻居节点是目标节点,则不将其加入队列
            # 这样可以在达到目标节点时停止进一步探索,并避免循环
            if neighbor in seen or neighbor in target_set:
                continue
            # 标记邻居节点为已访问
            seen.add(neighbor)
            # 将邻居节点及其下一层级加入队列
            queue.append((level + 1, neighbor))
    return result
# 示例数据
source_list = ['a', 'b']
target_list = ['x', 'y', 'z']
my_dict = {
    'a': ['e'],
    'b': ['f', 'd'],
    'e': ['g'],
    'f': ['t', 'h'],
    'd': ['x'],
    'g': ['x'],
    't': ['y'],
    'h': ['z']
}
# 运行BFS函数
output = bfs(source_list, target_list, my_dict)
print(output)输出:
{0: {'a': ['e'], 'b': ['f', 'd']}, 1: {'e': ['g'], 'f': ['t', 'h'], 'd': ['x']}, 2: {'g': ['x'], 't': ['y'], 'h': ['z']}}上述BFS实现每次从队列中取出一个节点就处理。对于某些场景,如果希望在处理完一个完整层级的所有节点后再统一构建该层级的结果,可以采用一种略微不同的方法。这种方法通过在一个内部循环中处理当前层级的所有节点,从而更明确地按层级组织数据。
from collections import deque
def solution(source, target, graph):
    """
    优化版BFS,按层级构建结果。
    Args:
        source (list): 起始节点列表。
        target (list): 目标节点列表。
        graph (dict): 表示图的字典。
    Returns:
        dict: 结构化输出,键为层级,值为该层级中所有被访问节点及其邻居的子字典。
    """
    target_set = set(target)
    result = {}
    # seen集合在初始化时就包含所有source节点,避免重复添加到队列
    seen = set(source)
    # 队列初始化为所有source节点,不带层级信息,层级在外部循环中管理
    queue = deque(source)
    level = 0
    while queue:
        # 调用辅助函数构建当前层级的结果
        result[level] = build_level_dict(graph, queue, seen, target_set)
        level += 1
    return result
def build_level_dict(graph, queue, seen, target_set):
    """
    辅助函数,用于构建当前层级的字典。
    在内部循环中处理队列中当前层级的所有节点。
    """
    # 记录当前层级队列的末尾节点,用于判断何时结束当前层级的处理
    # 注意:如果queue为空,此操作会报错。在solution函数中已确保queue非空。
    tail = queue[-1] 
    level_dict = {} # 存储当前层级的节点及其邻居
    while True:
        node = queue.popleft() # 取出当前节点
        # 确保当前节点在图中存在
        if node not in graph:
            # 如果节点不存在,但它在当前层级被处理,我们仍然需要记录它为空
            # 或者选择跳过,取决于具体需求。这里选择跳过。
            if node == tail: # 如果是当前层级的最后一个节点,需要跳出循环
                return level_dict
            continue # 跳过不存在的节点
        neighbors = graph[node] # 获取邻居
        level_dict[node] = neighbors.copy() # 添加到当前层级结果
        for neighbor in neighbors:
            # 如果邻居已访问或为目标节点,则不入队
            if neighbor in seen or neighbor in target_set:
                continue
            seen.add(neighbor) # 标记为已访问
            queue.append(neighbor) # 加入队列等待下一层级处理
        # 如果当前节点是本层级的最后一个节点,则完成本层级处理
        if node == tail:
            return level_dict
# 示例数据 (与之前相同)
source_list = ['a', 'b']
target_list = ['x', 'y', 'z']
my_dict = {
    'a': ['e'],
    'b': ['f', 'd'],
    'e': ['g'],
    'f': ['t', 'h'],
    'd': ['x'],
    'g': ['x'],
    't': ['y'],
    'h': ['z']
}
# 运行优化版函数
output_optimized = solution(source_list, target_list, my_dict)
print(output_optimized)输出:
{0: {'a': ['e'], 'b': ['f', 'd']}, 1: {'e': ['g'], 'f': ['t', 'h'], 'd': ['x']}, 2: {'g': ['x'], 't': ['y'], 'h': ['z']}}通过以上两种广度优先搜索的实现,我们可以高效地从复杂的字典结构中,按照指定的层级和停止条件提取所需的数据,这在图遍历、网络分析等领域具有广泛的应用价值。
以上就是使用广度优先搜索(BFS)按层级提取Python字典数据的详细内容,更多请关注php中文网其它相关文章!
                        
                        每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
                Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号