五、宽度优先搜索(BFS)

用处:

树是图的特殊状态

图的遍历 Traversal in Graph

  • 层级遍历 Level Order Traversal

   • 由点及面 Connected Component

  • 拓扑排序 Topological Sorting

最短路径 Shortest Path in Simple Graph

   • 仅限简单图求最短路径

   • 即,图中每条边长度都是1,且没有方向

 

用queue去存每一层,queue的实现LinkedList<>或ArrayDeque,不能是ArrayList会浪费时间

queue.offer() 加入队列,queue.poll()删除并取出first元素,不用add和pop异常处理不同。

DFS:模板

一、二叉树上的bfs

1、Binary Tree Level Order Traversal : 树的层级遍历  http://www.lintcode.com/problem/binary-tree-level-order-traversal/

not ac :queue.isEmpty() 写错,results 写错,level.add加节点值

Deque LinkedList<>

public class Solution {
    /**
     * @param root: The root of binary tree.
     * @return: Level order a list of lists of integer
     */
    public ArrayList<ArrayList<Integer>> levelOrder(TreeNode root) {
        // write your code here
        ArrayList<ArrayList<Integer>> results = new ArrayList<>();
        if (root == null) {
            return results;
        }
        Deque<TreeNode> queue = new LinkedList<TreeNode>();
        queue.offer(root);
        while(!queue.isEmpty()) {
            ArrayList<Integer> level = new ArrayList<>();
            int size = queue.size();
            for (int i = 0; i < size; i++) {
                TreeNode head = queue.poll();
                level.add(head.val);
                if (head.left != null) {
                    queue.offer(head.left);
                }
                if (head.right != null) {
                    queue.offer(head.right);
                }
            }
            results.add(level);
        }
        return results;
    }
}
View Code

2、序列化: 将“内存”中结构化的数据变成“字符串”的过程 序列化:object to string 反序列化:string to object

什么时候需要序列话:

1. 将内存中的数据持久化存储时 内存中重要的数据不能只是呆在内存里,这样断电就没有了,所需需要用一种方式写入硬盘,在需要的 时候,能否再从硬盘中读出来在内存中重新创建

2. 网络传输时 机器与机器之间交换数据的时候,不可能互相去读对方的内存。只能讲数据变成字符流数据(字符串)后 通过网络传输过去。接受的一方再将字符串解析后到内存中。

常用的一些序列化手段: • XML • Json • Thrift (by Facebook) • ProtoBuf (by Google)

3、序列化算法设计考虑:

 • 压缩率。对于网络传输和磁盘存储而言,当然希望更节省。 • 如 Thrift, ProtoBuf 都是为了更快的传输数据和节省存储空间而设计的。

• 可读性。我们希望开发人员,能够通过序列化后的数据直接看懂原始数据是什么。 • 如 Json,LintCode 的输入数据

 

4、二叉树序列话

任何法进行序列化,只要保证能够解析回来即可。

LintCode 采用的是 BFS 的方式对二叉树数据进行序列化,这样的好处是,你可以更为容易的自己画出 整棵二叉树。

1) http://www.lintcode.com/en/problem/binary-tree-serialization/

class Solution {
    /**
     * This method will be invoked first, you should design your own algorithm 
     * to serialize a binary tree which denote by a root node to a string which
     * can be easily deserialized by your own "deserialize" method later.
     */
    public String serialize(TreeNode root) {
        // write your code here
        if (root == null) {
            return "{}";
        }
        ArrayList<TreeNode> queue = new ArrayList<TreeNode>();
        queue.add(root);
        for (int i = 0; i < queue.size(); i++) {
            TreeNode node = queue.get(i);
            if (node == null) {
                continue;
            }
            queue.add(node.left);
            queue.add(node.right);
        }
        while (queue.get(queue.size() - 1) == null) {
            queue.remove(queue.size() - 1);
        }
        StringBuilder sb = new StringBuilder();
        sb.append("{");
        sb.append(queue.get(0).val);
        for (int i = 1; i < queue.size(); i++) {
            if (queue.get(i) == null) {
                sb.append(",#");
            } else {
                sb.append(",");
                sb.append(queue.get(i).val);
            }
        }
        sb.append("}");
        return sb.toString();
    }
    
    /**
     * This method will be invoked second, the argument data is what exactly
     * you serialized at method "serialize", that means the data is not given by
     * system, it's given by your own serialize method. So the format of data is
     * designed by yourself, and deserialize it here as you serialize it in 
     * "serialize" method.
     */
    public TreeNode deserialize(String data) {
        // write your code here
        if (data.equals("{}")) {
            return null;
        }
        String[] vals = data.substring(1,data.length() - 1).split(",");
        ArrayList<TreeNode> queue = new ArrayList<TreeNode>();
        TreeNode root = new TreeNode(Integer.parseInt(vals[0]));
        queue.add(root);
        int index = 0;
        boolean isLeft = true;
        for (int i = 1; i < vals.length; i++) {
            if (!vals[i].equals("#")) {
                TreeNode node = new TreeNode(Integer.parseInt(vals[i]));
                if (isLeft) {
                    queue.get(index).left = node;
                } else {
                    queue.get(index).right = node;
                }
                queue.add(node);
            }
            if (!isLeft) {
                index++;
            }
            isLeft = !isLeft;
        }
        return root;
    }    
}
View Code

5、图的序列化

如何表示图的邻接表:Map<Integer, Set<Integer>> 点 -- 和该点相邻的节点

如何判断图是树:1、边比点数少1

        2、判断连通性:是否有一个点没和任何点相连,从一点能访问任何一点

1)Graph Valid Tree   http://www.lintcode.com/problem/graph-valid-tree/

思路: 判断条件1

   初始化图:表示邻接表

   判断条件2

    public boolean validTree(int n, int[][] edges) {
        // Write your code here
        //判断条件1:边和点数
        if (n == 0) {
            return false;
        }
        if (edges.length != n - 1) {
            return false;
        }
        //初始化
        Map<Integer, Set<Integer>> graph = initializeGraph(n, edges);
        //判断条件2:连通性
        Deque<Integer> queue = new LinkedList<Integer>();
        HashSet<Integer> hash = new HashSet<>();
        queue.offer(0);
        hash.add(0);
        while (!queue.isEmpty()) {
            int node = queue.poll();
            for (Integer neighour : graph.get(node)) {
                if (hash.contains(neighour)) {
                    continue;
                }
                hash.add(neighour);
                queue.offer(neighour);
            }
        }
        return hash.size() == n;
    }
    public Map<Integer, Set<Integer>> initializeGraph(int n, int[][] edges) {
        Map<Integer, Set<Integer>> graph = new HashMap<>();
        for (int i = 0; i < n; i++) {
            graph.put(i, new HashSet<Integer>());
        }
        for (int i = 0; i < edges.length; i++) {
            int u = edges[i][0];
            int v = edges[i][1];
            graph.get(u).add(v);
            graph.get(v).add(u);
        }
        return graph;
    }
}
View Code

2)Clone Graph (F) http://www.lintcode.com/problem/clone-graph/  克隆无相图

***3步

1、得到所有的点 ArrayList<节点> nodes =   

    bfs: queue 和 hashmap

2、克隆点,old -> new映射关系

3、克隆边

记得对空检查

public class Solution {
    /**
     * @param node: A undirected graph node
     * @return: A undirected graph node
     */
    public UndirectedGraphNode cloneGraph(UndirectedGraphNode node) {
        // write your code here
        // 1.use bfs algorithm to traverse the graph and get all nodes.
        if (node == null) {
            return node;
        }
        ArrayList<UndirectedGraphNode> nodes = getNodes(node);
        //2. copy nodes, store the old->new mapping information in a hash map
        HashMap<UndirectedGraphNode, UndirectedGraphNode> map = new HashMap<>();
        for (UndirectedGraphNode n : nodes) {
            map.put(n, new UndirectedGraphNode (n.label));
        }
        //3.copy neighbors(edges)
        for (UndirectedGraphNode n : nodes) {
            UndirectedGraphNode  newNode = map.get(n);
            for (UndirectedGraphNode neighbor : n.neighbors) {
                UndirectedGraphNode newNeighbor = map.get(neighbor);
                newNode.neighbors.add(newNeighbor);
            }
        }
        return map.get(node);
    }
    private ArrayList<UndirectedGraphNode> getNodes(UndirectedGraphNode node) {
        Deque<UndirectedGraphNode> queue = new LinkedList<UndirectedGraphNode>();
        HashSet<UndirectedGraphNode> set = new HashSet<>();
        queue.offer(node);
        set.add(node);
        while (!queue.isEmpty()) {
            UndirectedGraphNode head = queue.poll();
            for (UndirectedGraphNode neighbor : head.neighbors) {
                if (!set.contains(neighbor)) {
                    set.add(neighbor);
                    queue.offer(neighbor);
                }
            }
        }
        return new ArrayList<UndirectedGraphNode>(set);
    }
}
View Code

 

 

3)Topological Sorting http://www.lintcode.com/problem/topological-sorting/ 拓扑排序

**1找根节点:没有指向它的节点---用hashmap<邻居节点,该邻接节点被指向的个数>,根节点没存在这个map里

 2.将该节点加入结果,依次从此节点开始访问

  

public class Solution {
    /**
     * @param graph: A list of Directed graph node
     * @return: Any topological order for the given graph.
     */    
    public ArrayList<DirectedGraphNode> topSort(ArrayList<DirectedGraphNode> graph) {
        // write your code here
        ArrayList<DirectedGraphNode> results = new ArrayList<>();
        HashMap<DirectedGraphNode,Integer> map = new HashMap<>();
        //用map记录 所有  被指向的节点 和 被指向的次数
        for (DirectedGraphNode node : graph) {
            for (DirectedGraphNode neighbor: node.neighbors) {
                if (map.containsKey(neighbor)) {
                    map.put(neighbor, map.get(neighbor) + 1);
                } else {
                    map.put (neighbor, 1);
                }
            }
        }
        Deque<DirectedGraphNode> queue = new LinkedList<DirectedGraphNode>();
        //找到未被指向的根节点,用queue记录根节点,并把该节点加入results
        for (DirectedGraphNode node : graph) {
            if (!map.containsKey(node)) {
                queue.offer(node);
                results.add(node);
            }
        }
        //从根节点遍历
        while (!queue.isEmpty()) {
            DirectedGraphNode node = queue.poll();
            for (DirectedGraphNode n : node.neighbors) {
                map.put(n,map.get(n) - 1);
                if (map.get(n) == 0) {
                    results.add(n);
                    queue.offer(n);
                }
            }
        }
        return results;
    }
}
View Code

***矩阵和图的对比

图 Graph N个点,M条边 M最大是 O(N^2) 的级别

图上BFS时间复杂度 = O(M) 所以最坏情况可能是 O(N^2)

 

矩阵 Matrix N行M列 N*M个点,N*M*2 条边(每个点上下左右4条边,每条边被2个点共享)。

矩阵中BFS时间复杂度 = O(N * M)

 

6、矩阵中的BFS

转载于:https://www.cnblogs.com/lingli-meng/p/6557349.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值