DFS & BFS

来源:互联网 发布:淘宝达人是怎么赚钱的 编辑:程序博客网 时间:2024/05/16 13:00

DFS (Depth First Search) and BFS (Breadth First Search) are search algorithms used for graphs and trees. When you have an ordered tree or graph, like a BST, it’s quite easy to search the data structure to find the node that you want. But, when given an unordered tree or graph, the BFS and DFS search algorithms can come in handy to find what you’re looking for. The decision to choose one over the other should be based on the type of data that one is dealing with.

In a breadth first search, you start at the root node, and then scan each node in the first level starting from the leftmost node, moving towards the right. Then you continue scanning the second level (starting from the left) and the third level, and so on until you’ve scanned all the nodes, or until you find the actual node that you were searching for. In a BFS, when traversing one level, we need some way of knowing which nodes to traverse once we get to the next level. The way this is done is by storing the pointers to a level’s child nodes while searching that level. The pointers are stored in FIFO (First-In-First-Out) queue. This, in turn, means that BFS uses a large amount of memory because we have to store the pointers.

Subscribe to our newsletter for more free interview questions.

An example of BFS

Here’s an example of what a BFS would look like. The numbers represent the order in which the nodes are accessed in a BFS:

In a depth first search, you start at the root, and follow one of the branches of the tree as far as possible until either the node you are looking for is found or you hit a leaf node ( a node with no children). If you hit a leaf node, then you continue the search at the nearest ancestor with unexplored children.

An example of DFS

Here’s an example of what a DFS would look like. The numbers represent the order in which the nodes are accessed in a DFS:

Differences between DFS and BFS


Comparing BFS and DFS, the big advantage of DFS is that it has much lower memory requirements than BFS, because it’s not necessary to store all of the child pointers at each level. Depending on the data and what you are looking for, either DFS or BFS could be advantageous.

For example, given a family tree if one were looking for someone on the tree who’s still alive, then it would be safe to assume that person would be on the bottom of the tree. This means that a BFS would take a very long time to reach that last level. A DFS, however, would find the goal faster. But, if one were looking for a family member who died a very long time ago, then that person would be closer to the top of the tree. Then, a BFS would usually be faster than a DFS. So, the advantages of either vary depending on the data and what you’re looking for.






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;
        }
    }
}


0 0
原创粉丝点击