常见问题 (FAQ)
Q: 如何创建图?
Section titled “Q: 如何创建图?”// 有向图let g = @storage.new_directed()
// 无向图let g = @storage.new_undirected()
// 有向矩阵(预分配容量)let g = @storage.new_directed_matrix(1000)Q: 如何添加节点和边?
Section titled “Q: 如何添加节点和边?”// 添加节点(返回 NodeId)let n0 = @core.GraphWritable::add_node(g, 0.0)let n1 = @core.GraphWritable::add_node(g, 1.0)
// 添加边(权重)let _ = @core.GraphWritable::add_edge(g, n0, n1, 1.0)
// 批量添加边let edges = [(n0, n1, 1.0), (n1, n2, 2.0)]let _ = @storage.DirectedAdjList::add_edges_batch(g, edges)Q: 如何遍历图?
Section titled “Q: 如何遍历图?”// 遍历所有节点for nid in @core.GraphReadable::node_ids(g) { println("Node: \{nid}")}
// 遍历所有边for (from, to, weight) in @core.GraphReadable::edges(g) { println("\{from} -> \{to}: \{weight}")}
// 获取邻居let neighbors = @core.GraphReadable::neighbors(g, node_id)for nid in neighbors { // 处理邻居}Q: 如何选择最短路径算法?
Section titled “Q: 如何选择最短路径算法?”| 场景 | 算法 | 代码 |
|---|---|---|
| 非负权图 | Dijkstra | @shortest_path.dijkstra(g, source) |
| 有负权图 | Bellman-Ford | @shortest_path.bellman_ford(g, source) |
| 全源最短路径 | Floyd-Warshall | @shortest_path.floyd_warshall(g) |
| 启发式搜索 | A* | @shortest_path.a_star(g, start, goal, h) |
Q: 如何检测环?
Section titled “Q: 如何检测环?”// 自动选择有向/无向检测let has_cycle = @traversal.has_cycle(g)
// 明确指定let has_cycle = @traversal.has_directed_cycle(g) // 有向图let has_cycle = @traversal.has_undirected_cycle(g) // 无向图Q: 如何进行拓扑排序?
Section titled “Q: 如何进行拓扑排序?”// Kahn 算法(BFS)match @traversal.topo_sort_kahn(g) { Ok(order) => println("Topological order: \{order}") Err(msg) => println("Graph has cycle: \{msg}")}
// DFS 算法match @traversal.topo_sort_dfs(g) { Ok(order) => // 处理 Err(msg) => // 有环}Q: 如何选择存储类型?
Section titled “Q: 如何选择存储类型?”通用场景 → DirectedAdjList / UndirectedAdjList稠密图 → DirectedMatrix大规模静态图 → CSR入边查询 → CSCMST 算法 → EdgeListQ: 如何转换存储类型?
Section titled “Q: 如何转换存储类型?”// 动态 → 静态let csr = @storage.to_csr(g)
// 有向 → 无向let ug = @storage.as_undirected(g)
// 无向 → 有向(双向)let dg = @storage.as_directed(ug)Q: CSR 有什么优势?
Section titled “Q: CSR 有什么优势?”- 内存连续,缓存友好
- 支持批量查询
batch_neighbors - 适合大规模静态图
- 构建后不可修改(保证纯函数语义)
Q: 添加边失败怎么办?
Section titled “Q: 添加边失败怎么办?”match @core.GraphWritable::add_edge(g, n0, n1, 1.0) { Ok(()) => println("Success") Err(@core.GraphError::NodeNotFound(nid)) => { println("Node \{nid} not found") // 先添加节点 } Err(@core.GraphError::EdgeAlreadyExists(f, t)) => { println("Edge \{f}->\{t} already exists") // 跳过或更新 } Err(e) => println("Other error: \{e}")}Q: 如何处理不可达节点?
Section titled “Q: 如何处理不可达节点?”let sp = @shortest_path.dijkstra(g, source)
// 检查可达性if sp.is_reachable(target) { let path = sp.path_to(target) // 处理路径} else { println("Target not reachable")}
// 获取距离(不可达返回 infinity)let dist = sp.distance_to(target)Q: 如何提升性能?
Section titled “Q: 如何提升性能?”- 选择合适的存储: AdjList vs Matrix vs CSR
- 预计算: Floyd-Warshall 预计算后 O(1) 查询
- 批量操作: 使用
add_edges_batch和batch_neighbors - 避免转换: 减少不必要的存储类型转换
Q: 大规模图怎么处理?
Section titled “Q: 大规模图怎么处理?”// 1. 使用 CSR 存储let csr = @storage.to_csr(g)
// 2. 使用批量查询let neighbors = @core.GraphBatchReadable::batch_neighbors(csr, node_ids)
// 3. 选择高效算法let result = @pagerank.pagerank(csr, 0.85, 100, 1e-6)Q: 为什么算法不修改输入图?
Section titled “Q: 为什么算法不修改输入图?”mbtgraph 所有算法保证输入不可变:
let g = @storage.new_directed()// ... 构建图let original_edges = @core.GraphReadable::edge_count(g)
let result = some_algorithm(g, ...)
// g 不变let current_edges = @core.GraphReadable::edge_count(g)assert(original_edges == current_edges)Q: 如何修改图?
Section titled “Q: 如何修改图?”// 显式调用可写方法let _ = @core.GraphWritable::add_node(g, data)let _ = @core.GraphWritable::add_edge(g, from, to, weight)let _ = @core.GraphWritable::remove_node(g, node_id)let _ = @core.GraphWritable::remove_edge(g, from, to)Q: 如何验证图结构?
Section titled “Q: 如何验证图结构?”// 基本统计let stats = @io.basic_stats(g)println("Nodes: \{stats.node_count}")println("Edges: \{stats.edge_count}")println("Density: \{stats.density}")
// 连通性let cc = @connectivity.connected_components(g)println("Components: \{cc.count()}")
// 度分布let dist = @io.degree_distribution(g)println("Max degree: \{dist.max_degree}")Q: 如何导出图?
Section titled “Q: 如何导出图?”// DOT 格式let dot = @io.write_dot(g, "my_graph")println(dot)
// JSON 格式let json = @io.graph_to_json(g, true) // true = 格式化println(json)