Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1480980
  • 博文数量: 187
  • 博客积分: 10375
  • 博客等级: 上将
  • 技术积分: 3127
  • 用 户 组: 普通用户
  • 注册时间: 2006-03-07 10:58
文章分类

全部博文(187)

文章存档

2013年(1)

2012年(8)

2011年(28)

2010年(36)

2009年(47)

2008年(67)

我的朋友

分类: Java

2010-05-19 18:26:45

DFS(Depth-First Search)和BFS(Breadth-First Search)是两种用于访问图(graph)中节点最普遍的两种方法。在我的日常编程中,使用的graph的绝大部分都是树(tree). Tree是一种connected acyclic graph - 连通(即从一个节点一定有路径到其他任何节点)的无循环图. 本文所述内容仅限于tree, 不适用于graph.

tree

 

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) |
给主人留下些什么吧!~~