算法与数据结构——图表示与搜索

图表示

无向图表示

无向图与两种表示.png

有向图表示

有向图与两种表示.png
 ; 个人偏向于邻接链表表示法,比较简单方便,占用空间也不大。

图遍历

广度优先搜索

  每个结点初始颜色为白色,被发现后,变为灰色,并将其插入队列,其邻接链表扫描完成后变为黑色;
BFS在无向图上的运行过程.png

深度优先搜索

  与广度优先基本相同,只是不再使用队列保存未扫描结点,而改为递归深度扫描。
DFS在有向图上的运行过程.png
#代码(包括图表示、BFS、DFS)


import java.util.*;

public class Graph {

    private enum Color {

        WHITE(0, "white"),
        GRAY(1, "gray"),
        BLACK(2, "black");

        private int value;
        private String desc;

        Color(int value, String desc) {
            this.value = value;
            this.desc = desc;
        }
    }

    static class Node {
        public Node pre;
        public List<Node> next;
        public Color color;
        // BFS中作为与指定节点的度数,DFS中作为首次访问该节点的时间
        public int d;
        // 深度优先遍历中使用,节点深度遍历访问完成的时间,与其连接的结点都已经访问过
        public int f;
        public int value;
    }

    /**
     * 生成无向图,结点数量为count
     * 使用邻接链表表示图
     * @param count
     * @return
     */
    private static List<Node> generateUndirectedGraph(int count) {

        // 控制结点与其他结点连接的概率
        int p = 3;
        int bound = 10;

        List<Node> allNode = new ArrayList<>();

        for (int i = 0; i < count; i++) {
            Node node = new Node();
            node.value = i;
            allNode.add(node);
        }

        Random random = new Random();

        for (int i = 0; i < count - 1; i++) {
            for (int j = 1; j < count; j++) {

                if (random.nextInt(bound) < p) {
                    List<Node> iNextList = allNode.get(i).next;
                    if (iNextList == null) {
                        iNextList = new ArrayList<>();
                        allNode.get(i).next = iNextList;
                    }
                    iNextList.add(allNode.get(j));

                    List<Node> jNextList = allNode.get(j).next;
                    if (jNextList == null) {
                        jNextList = new ArrayList<>();
                        allNode.get(j).next = jNextList;
                    }
                    jNextList.add(allNode.get(i));
                }
            }
        }

        return allNode;
    }

    /**
     * 生成有向图,结点数量为count
     * 使用邻接链表表示图
     *
     * @param count
     * @return
     */
    private static List<Node> generateDirectedGraph(int count) {

        // 控制结点与其他结点连接的概率
        int p = 3;
        int bound = 10;

        List<Node> allNode = new ArrayList<>();

        for (int i = 0; i < count; i++) {
            Node node = new Node();
            node.value = i;
            allNode.add(node);
        }

        Random random = new Random();

        for (int i = 0; i < count; i++) {
            for (int j = 0; j < count; j++) {

                if (random.nextInt(bound) < p) {
                    List<Node> iNextList = allNode.get(i).next;
                    if (iNextList == null) {
                        iNextList = new ArrayList<>();
                        allNode.get(i).next = iNextList;
                    }
                    iNextList.add(allNode.get(j));
                }
            }
        }

        return allNode;
    }

    private static void printGraph(List<Node> allNode) {
        for (Node node : allNode) {
            if (node.next != null && node.next.size() != 0) {
                StringBuilder next = new StringBuilder();
                for (Node n : node.next) {
                    next.append(n.value);
                    next.append(",");
                }

                StringBuilder printString =
                        new StringBuilder("node : " + node.value + ", next : " + next.toString() +
                                " d : " + node.d + ", f : " + node.f);
                if (node.color != null) {
                    printString.append(", color : " + node.color.desc);
                }
                System.out.println(printString.toString());
            } else {
                System.out.println("node : " + node.value + ", no next");
            }
        }
    }

    /**
     * 每个结点初始颜色为白色,被发现后,变为灰色,并将其插入队列,其邻接链表扫描完成后变为黑色;
     * 队列管理灰色结点集合
     *
     * @param allNode
     * @param s
     */
    private static void bfs(List<Node> allNode, Node s) {

        if (!allNode.contains(s)) {
            return;
        }

        int count = allNode.size();
        for (Node node : allNode) {
            if (node.equals(s)) {
                continue;
            }
            node.color = Color.WHITE;
            node.d = count + 1;
            node.pre = null;
        }

        s.color = Color.GRAY;
        s.d = 0;
        s.pre = null;

        Queue<Node> q = new LinkedList<>();
        q.add(s);

        Node u;
        while (!q.isEmpty()) {
            u = q.poll();

            if (u.next != null && u.next.size() != 0) {
                for (Node v : u.next) {
                    if (v.color == Color.WHITE) {
                        v.color = Color.GRAY;
                        v.d = u.d + 1;
                        v.pre = u;

                        q.add(v);
                    }
                }
            }

            u.color = Color.BLACK;
        }
    }

    private static int time = 0;

    /**
     * 每个结点初始颜色为白色,被发现后,变为灰色,其邻接链表扫描完成后变为黑色;
     * 深度优先搜索完成后,前驱子图构成的深度优先搜索树构成深度优先搜索森林
     * @param allNode
     */
    private static void dfs(List<Node> allNode) {
        for (Node node : allNode) {
            node.color = Color.WHITE;
            node.pre = null;
        }

        for (Node node : allNode) {
            if (node.color.equals(Color.WHITE)) {
                dfsVisit(allNode, node);
            }
        }
    }

    private static void dfsVisit(List<Node> allNode, Node u) {
        time++;
        u.d = time;
        u.color = Color.GRAY;
        if (u.next != null && u.next.size() != 0) {
            for (Node v : u.next) {
                if (v.color == Color.WHITE) {
                    v.pre = u;
                    dfsVisit(allNode, v);
                }
            }
        }

        u.color = Color.BLACK;
        time++;
        u.f = time;
    }

    public static void main(String[] args) {
        int count = 10;
        List<Node> undirectedGraph = generateUndirectedGraph(count);
        System.out.println("=====================undirectedGraph====================");
        printGraph(undirectedGraph);
        bfs(undirectedGraph, undirectedGraph.get(0));
        System.out.println("=====================BFS start with 0====================");
        printGraph(undirectedGraph);

        List<Node> directedGraph = generateDirectedGraph(count);
        System.out.println("=====================directedGraph====================");
        printGraph(directedGraph);
        dfs(directedGraph);
        System.out.println("=====================DFS====================");
        printGraph(directedGraph);

    }

}

参考文档

《算法导论》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值