
在处理某些数据结构时,我们可能面临从一个表示图或树的字典中,根据一组起始键(source_list)和一组目标值(target_list),逐层提取相关联的键值对。具体来说,给定一个字典 my_dict,其中键是节点,值是其直接相邻的节点列表,我们需要从 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']}}最初的尝试可能未能完全实现预期,通常是因为在处理层级关系和终止条件时存在逻辑缺陷。例如,如果仅根据当前层级构建 next_dict 并检查 target_list,可能导致过早终止或未能正确追踪所有路径。关键在于需要一种系统性的方法来探索所有可达节点,并确保按层级进行。
广度优先搜索(BFS)是一种图遍历算法,它从起始节点开始,逐层探索所有相邻节点,非常适合解决此类分层数据提取问题。
立即学习“Python免费学习笔记(深入)”;
以下是一个基于BFS的解决方案,它能正确地按层级提取数据:
from collections import deque
def bfs_fetch_levels(source_nodes, target_nodes, graph_dict):
"""
使用广度优先搜索从字典(图)中分层提取数据。
Args:
source_nodes (list): 起始节点列表。
target_nodes (list): 目标节点列表。
graph_dict (dict): 表示图的字典,键是节点,值是其邻居列表。
Returns:
dict: 一个字典,键是层级(迭代次数),值是该层级提取到的键值对。
"""
# 初始化队列,每个元素是 (层级, 节点)
queue = deque((0, node) for node in source_nodes)
# 将目标节点转换为集合,以便O(1)时间复杂度进行查找
target_set = set(target_nodes)
# 记录已访问的节点,防止重复和循环
seen = set(source_nodes) # 初始节点也被视为已访问
# 存储最终结果
result = {}
while queue:
level, current_node = queue.popleft()
# 获取当前节点的邻居
neighbors = graph_dict.get(current_node, [])
# 将当前节点及其邻居添加到结果字典的对应层级中
# 使用 setdefault 确保层级键存在
result.setdefault(level, {})[current_node] = neighbors[:] # 复制邻居列表
# 遍历当前节点的所有邻居
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']
}
output = bfs_fetch_levels(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']}}代码解释:
另一种稍微优化或结构化更清晰的实现方式是,在每个层级处理完所有节点后再进入下一个层级。这可以通过在每次循环中处理队列中当前层级的所有节点来实现。
from collections import deque
def build_level_dict(graph, queue, seen, target_set):
"""
辅助函数:构建当前层级的字典,并将下一层级的节点加入队列。
"""
level_dict = {}
# 记录当前层级队列的末尾,以便知道何时完成当前层级的处理
# 注意:这里假设queue在调用前已经包含了当前层级的所有节点
# 并且在处理过程中,新节点会被添加到queue的末尾,不会干扰当前层级的判断
current_level_size = len(queue)
for _ in range(current_level_size): # 遍历当前层级的所有节点
node = queue.popleft()
neighbors = graph.get(node, [])
level_dict[node] = neighbors[:] # 复制邻居列表
for neighbor in neighbors:
if neighbor in seen or neighbor in target_set:
continue
seen.add(neighbor)
queue.append(neighbor) # 新节点加入队列末尾
return level_dict
def bfs_fetch_levels_optimized(source_nodes, target_nodes, graph_dict):
"""
优化版的广度优先搜索,分层提取数据。
在每一轮循环中处理整个层级。
"""
target_set = set(target_nodes)
result = {}
# 初始节点被视为已访问,并加入队列
seen = set(source_nodes)
queue = deque(source_nodes)
level = 0
while queue:
# 调用辅助函数处理当前层级的所有节点
# build_level_dict 会返回当前层级的字典,并将下一层级的节点加入queue
result[level] = build_level_dict(graph_dict, queue, seen, target_set)
level += 1
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']
}
output_optimized = bfs_fetch_levels_optimized(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字典分层数据提取与广度优先搜索(BFS)应用实践的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号