基于NetworkX的有向交易网络递归查找节点入邻居的问询
解决NetworkX有向图递归追溯入邻居的问题
嘿,我懂你要做的事儿——从指定的银行账户节点出发,一层层往上找所有给它(或者给它的上游账户)转账的节点,直到挖完所有源头为止对吧?这在交易溯源这类场景里太常见了,我给你两种靠谱的实现方式:
方法1:递归实现(适合较浅的网络)
递归的思路特别直观:先找当前节点的所有直接转账方(入邻居),再对每个转账方递归找他们的上游,同时要记录已经处理过的节点,避免重复遍历甚至遇到循环时无限递归。
import networkx as nx def recursive_find_in_neighbors(G, current_node, visited=None): # 初始化已访问集合 if visited is None: visited = set() # 如果当前节点已经处理过,直接返回 if current_node in visited: return visited # 标记当前节点为已处理 visited.add(current_node) # 获取当前节点的所有入邻居(也就是给它转账的账户) in_neighbors = G.predecessors(current_node) # 递归遍历每个入邻居的上游 for neighbor in in_neighbors: recursive_find_in_neighbors(G, neighbor, visited) return visited # 示例使用 # 先模拟一个交易图:A转B,B转C,D转C,E转A,F转E G = nx.DiGraph() G.add_edges_from([("A", "B"), ("B", "C"), ("D", "C"), ("E", "A"), ("F", "E")]) start_node = "C" # 我们要追溯所有给C(或其上游)转账的节点 all_source_nodes = recursive_find_in_neighbors(G, start_node) print(f"所有向{start_node}(或其上游)转账的节点:{all_source_nodes}") # 输出结果:{'C', 'B', 'A', 'E', 'F', 'D'}
代码细节说明:
G.predecessors(current_node):这比G.in_edges()更直接,它会直接返回当前节点的所有入邻居(转出方),不用手动从边里提取节点。visited集合:核心作用是去重和防循环,比如如果存在A→B→A的闭环,不会让递归无限跑下去。- 最终返回的集合包含了起始节点本身,以及所有能通过转账路径到达它的节点。
方法2:迭代实现(适合深网络,避免栈溢出)
如果你的交易网络特别深,递归可能会触发Python的递归深度限制,这时候用迭代(栈/队列)的方式更稳妥:
def iterative_find_in_neighbors(G, start_node): visited = set() stack = [start_node] while stack: current_node = stack.pop() if current_node not in visited: visited.add(current_node) # 把当前节点的所有入邻居加入栈,继续追溯 in_neighbors = G.predecessors(current_node) stack.extend(in_neighbors) return visited # 示例使用 all_source_nodes = iterative_find_in_neighbors(G, start_node) print(f"所有向{start_node}(或其上游)转账的节点:{all_source_nodes}")
代码细节说明:
- 用栈模拟递归的过程,每次取出一个节点处理,再把它的上游加入栈。
- 如果想按层级顺序遍历(先看直接给起始节点转账的,再看间接的),可以把栈改成队列(比如用
collections.deque的popleft()),这样就是广度优先遍历(BFS),上面的栈实现是深度优先遍历(DFS)。
额外小提示
- 如果你只想获取所有上游转账节点(不含起始节点本身),可以最后从结果里移除起始节点:
all_source_nodes.remove(start_node)。 - 要是需要追踪具体的转账路径(比如谁转给谁最终到起始节点),可以修改函数用字典记录每个节点的前驱,最后回溯就能得到完整路径。
内容的提问来源于stack exchange,提问作者lotrss
相关产品推荐
相关产品推荐

