图 Graph

1. 图的相关术语

  1. 阶(Order)
    图的顶点数。

  2. 子图(Sub-Graph)
    如果一个图的顶点集包含于另一个图的顶点集,并且边集也包含于另一个图的边集,那么这个图就是另一个图的子图。

  3. 度(Degree)
    与这个顶点关联的边的条数。

  4. 入度(In-Degree)和出度(Out-Degree)
    所有邻接到这个顶点的边的个数叫入度;所有邻接于这个顶点的边的个数叫出度。

  5. 自环(Loop)
    一条边的两个顶点是一个节点。

  6. 路径(Path)

  7. 桥(Bridge)
    如果去掉一条边使整个图不连通,那么这条边叫做桥。

2. 图的分类

图分为无向图(Undirected Graph)和有向图(Directed Graph)。

3. 图的表示与存储方式

3.1 邻接矩阵

/**
 * 邻接矩阵表示法
 */
public class MatrixGraph {
    // 下标与实际值的映射
    private int[]   mapping;
    //图的二维数组
    private int[][] matrix;

    /**
     * 初始化图
     */
    public MatrixGraph(int[] vertexes) {
        int length = vertexes.length;
        mapping = new int[length];
        matrix = new int[length][length];
        for (int i = 0; i < length; i++) {
            mapping[i] = vertexes[i];
        }
    }

    public void addEdge(int start, int end) {
        int x = -1;
        int y = -1;
        //寻找坐标
        for (int i = 0; i < mapping.length; i++) {
            if (x != -1 && y != -1) {
                //上一轮已给x y赋值
                break;
            }

            if (start == mapping[i]) {
                x = i;
            }

            if (end == mapping[i]) {
                y = i;
            }
        }

        //判断顶点是否存在
        if (x == -1 || y == -1 || x > mapping.length - 1 || y > mapping.length - 1) {
            return;
        }
        //赋值
        matrix[x][y] = 1;
    }


    public void printMatrix() {
        for (int i = 0; i < matrix.length; i++) {
            for (int i1 = 0; i1 < matrix[i].length; i1++) {
                System.out.print(matrix[i][i1]);
                System.out.print(" ");
            }
            System.out.println();
        }
    }

    /**
     * DFS 深度优先遍历
     * 使用栈的方式
     */
    public void depthFirstTravel() {
        Stack<Integer> stack = new Stack();
        //初始化访问状态数组
        int[] visited = new int[mapping.length];
        //从未访问的顶点中选择一个作为起始顶点
        int unvisited = getUnvisited(visited);
        while (unvisited >= 0) {
            //标记起始顶点已被访问
            visited[unvisited] = 1;
            //入栈
            stack.push(unvisited);
            System.out.print(mapping[unvisited] + ",");

            while (!stack.isEmpty()) {
                //获取栈顶元素,并不出栈
                int index = stack.peek();
                //遍历矩阵此行,找到未被访问的邻接节点
                boolean found = false;
                for (int i = 0; i < mapping.length; i++) {
                    if (index != i && visited[index] == 0 && matrix[index][i] > 0) {
                        //非自己 未被访问 邻接顶点
                        visited[i] = 1;
                        stack.push(i);
                        System.out.print(mapping[i]+",");
                        found = true;
                        break;
                    }
                }

                if (!found){
                    stack.pop();
                }
            }

            unvisited = getUnvisited(visited);
        }
    }

    /**
     * BFS 广度优先遍历
     *
     */
      public void breadthFirstTravel() {
        Queue<Integer> queue = new LinkedList<>();

        int[] visited = new int[mapping.length];
        int unvisited = getUnvisited(visited);
        while (unvisited >= 0) {
            queue.add(unvisited);
            while (!queue.isEmpty()) {
                //顶点出队
                int index = queue.poll();
                if (visited[index] == 1) {
                    //访问过了,继续
                    continue;
                }

                System.out.print(mapping[index] + ",");

                visited[index] = 1;

                for (int i = 0; i < mapping.length; i++) {
                    //非自己 未被访问 可到达
                    if (index != i && visited[i] == 0 && matrix[index][i] > 0) {
                        queue.add(i);
                    }
                }
            }
            unvisited = getUnvisited(visited);

        }
        System.out.println();
    }

    private int getUnvisited(int[] visited) {
        int index = -1;
        for (int i = 0; i < visited.length; i++) {
            if (visited[i] == 0) {
                index = i;
                break;
            }
        }

        return index;
    }

}

测试用例

public class MatrixGraphTest {

    MatrixGraph graph;

    @Before
    public void setup() {
        int[] vertexes = {1, 2, 3, 4};
        graph = new MatrixGraph(vertexes);
        graph.addEdge(1, 2);
        graph.addEdge(1, 3);
        graph.addEdge(1, 4);
        graph.addEdge(2, 3);
        graph.addEdge(4, 3);

    }

    @Test
    public void main() {
        graph.printMatrix();
    }

    @Test
    public void dfs(){
        graph.depthFirstTravel();
    }

    @Test
    public void bfs(){
        graph.breadthFirstTravel();
    }
}

3.2 邻接表

类似散列表,同样有一个数组,每个元素为一个链表。 数组的每个元素是顶点,也是链表的头结点,而链表的每个元素是这个顶点邻接的顶点。

(待补充)

4. 深度优先遍历与广度优先遍历

4.1 时间复杂度

深度优先遍历:
邻接矩阵表示法为O(n^2),邻接表表示法为O(n+e)

广度优先遍历:
与DFS没有区别,邻接矩阵表示法为O(n^2),邻接表表示法为O(n+e)

转载于:https://my.oschina.net/mythss/blog/3011132

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值