DFS(Depth-First Search)和BFS(Breadth-First Search)是两种用于访问图(graph)中节点最普遍的两种方法。在我的日常编程中,使用的graph的绝大部分都是树(tree). Tree是一种connected acyclic graph - 连通(即从一个节点一定有路径到其他任何节点)的无循环图.
本文所述内容仅限于tree, 不适用于graph.
DFS 深度优先
假设右边的树代表一个公司的组织架构,每个node是一个部门。若要计算部门c的总收入,我们必须先知道e和f的,而要知道e的总收入我们必须先知道g和h,这就是典型的深度优先。深度优先通过递归来实现,代码如下:
visitDFS(a); // visit from the root
// performs DFS from the given node public void visitDFS(Node nodeStart) { // (1) Entering node - pre-order walk for(Node child : nodeStart.children) { visitDFS(child); // recursive call } // (2) Leaving node - post-order walk System.out.println("DFS: " + nodeStart.nodeName); }
|
在代码中,我做了两个标记(1)和(2). 在(1)处,当前节点的所有下属节点尚未被访问,而在(2)处,其所有下属节点均被处理完毕。若要计算部门收入,很明显是在(2)处。上面代码打印结果是:d b g h e f c a
BFS 广度优先
假设我们要打印各部门收入报表给CEO,因为每个部门收入数据较多,CEO倾向先看各大部门(只有对某部门数据有疑惑时,才看小部门), 这样情况下是先打印大部门,再打印小部门,低等级部门后打印,这就是广度优先的情况。graph的BFS算法较繁琐,但tree的BFS就非常简单了:
visitBFS(a); // visit from the root // performs BFS from the given node public void visitBFS(Node nodeStart) { List<NODE> pendingExplore = new ArrayList<NODE>(); // list of nodes pending exploration pendingExplore.add(nodeStart); while(pendingExplore.size() > 0) { Node currentNode = pendingExplore.remove(0); System.out.println("BFS: " + currentNode.nodeName); pendingExplore.addAll(currentNode.children); // (3) } }
|
上面代码打印结果: a b c d e f g h. 有时同级部门之间还有顺序,譬如重要产品部门比技术支持部门往往排序靠前,要实现这个非常简单,在(3)处,将子节点添加到pendingExplore之前进行sort即可。
附:测试程序的完整代码:
public class TestTree { public Node a;
@SuppressWarnings("unused") public TestTree() { // Construct the tree.
a = new Node("a"); Node b = a.createChildNode("b"); Node c = a.createChildNode("c"); Node d = b.createChildNode("d"); Node e = c.createChildNode("e"); Node f = c.createChildNode("f"); Node g = e.createChildNode("g"); Node h = e.createChildNode("h"); }
public void testDFS() { System.out.println("Testing DFS"); visitDFS(a); // visit from the root
}
// performs DFS from the given node
public void visitDFS(Node nodeStart) { // Entering node - pre-order walk
for (Node child : nodeStart.children) { visitDFS(child); // recursive call
} // Leaving node - post-order walk
System.out.println("DFS: " + nodeStart.nodeName); }
public void testBFS() { System.out.println("Testing BFS"); visitBFS(a); // visit from the root
}
// performs BFS from the given node
public void visitBFS(Node nodeStart) { List<Node> pendingExplore = new ArrayList<Node>(); // list of nodes
// pending
// exploration
pendingExplore.add(nodeStart); while (pendingExplore.size() > 0) { Node currentNode = pendingExplore.remove(0); System.out.println("BFS: " + currentNode.nodeName); pendingExplore.addAll(currentNode.children); } }
// Application entry point
public static void main(String[] args) { TestTree testTree = new TestTree(); testTree.testBFS(); testTree.testDFS(); }
// Node class
public static class Node { public Node parent; public List<Node> children = new ArrayList<Node>();
public String nodeName;
public Node(String nodeName) { this.nodeName = nodeName; }
public Node createChildNode(String childNodeName) { Node child = new Node(childNodeName); child.parent = this; children.add(child); return child; } } }
|
阅读(6146) | 评论(0) | 转发(0) |