zoukankan      html  css  js  c++  java
  • 1.图的基本介绍

    图是一种数据结构,其中节点可以具有零个或多个相邻元素,两个节点之间的连接称为边,结点称为顶点。如图

    2.图的常用概念:

    无向图:顶点之间连接没有方向,比如A-B,既可以A-B也可以B-A.

    路径:比如从D -> C的路径又

    1)D -> B -> C

    2)D -> A -> B -> C

    有向图:顶点之间链接有方向,比如A->B,只能A->B;

    带权图:这种边带权值的图也叫网;

    3.图的表示方式

    图的表示方式有两种:二位数组表示(邻接矩阵),链表表示(邻接表)。

    邻接矩阵是表示图形中顶点之间相邻关系的矩阵,对于n个顶点的图而言,矩阵是row和col表示的是1.....n个点。

    邻接表:邻接矩阵需要为每个顶点都分配n个边的空间,其实很多边都是不存在,会造成空间的一定损失。

    邻接表实际只关心存在的边,不关心不存在的边,因此没有空间浪费,邻接表由数组+链表组成。

    4.图的创建以及实现

    5.图的遍历

    图的遍历是对结点的访问,一个图有那么多个结点,如何遍历这些节点,需要特定的策略,一般有两种方法:深度优先遍历和广度优先遍历。

    1. 图的深度优先遍历

    每次都在访问完一个当前节点后首先访问当前结点的下一个结点。是优先往纵向挖掘深入,而不是对一个结点的所有邻接结点进行横向访问。它是一个递归的过程。

    深度优先遍历的算法步骤:

    1)访问初始节点v,并标记结点v为已访问。

    2)查找结点v的第一个邻接结点w。

    3)若w存在,则继续执行4,如果w不存在,则回到第一步,将从v的下一个结点继续。

    4)若w未被访问,对w进行深度优先优先遍历递归(即把w当作另一个v,然后进行步骤123)。

    5)查找结点v的w邻接结点的下一个邻接结点,转到步骤三。
    2.广度优先遍历

    类似于分层搜索的过程,广度优先遍历需求使用一个队列以保持访问过的结点的顺序,以便按这个顺序来访问这些节点的邻接结点。

    广度优先遍历的算法步骤:

    1)访问初始节点v并标记结点v已访问。

    2)结点v入队。

    3)当队列非空时,继续执行,否则算法结束。

    4)出队列,取得队头结点u.

    5)查找结点u的第一个邻接结点w.

    6)若节点u的邻接w不存在,则转移到步骤3:否则循环一下三个步骤。

    6.1 若结点w尚未被访问,则访问结点w并标记未已访问。

    6.2 结点w入队

    6.3 最后查找结点u的继w邻接结点后的下一个邻接结点w,转到步骤6

    package com.sratct.graph;
    
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.LinkedList;
    import java.util.List;
    
    public class Graph {
        // 存储结点的集合
        private List<String> vertexList;
        // 创建二位数组,存储邻接矩阵
        private int[][] edges;
        private int numOfEdges; // 图的边的数量
        private boolean[] isVisited;  // 记录每个结点是否被访问过
    
        public static void main(String[] args) {
            int n = 8;
            Graph graph = new Graph(8);
            String[] arr = {"1", "2", "3", "4", "5", "6", "7", "8"};
            for (int i = 0; i < arr.length; i++) {
                graph.insertVertex(arr[i]);
            }
            graph.insertEdge(0, 1, 1);
            graph.insertEdge(0, 2, 1);
            graph.insertEdge(1, 3, 1);
            graph.insertEdge(1, 4, 1);
            graph.insertEdge(3, 7, 1);
            graph.insertEdge(4, 7, 1);
            graph.insertEdge(2, 5, 1);
            graph.insertEdge(2, 6, 1);
            graph.insertEdge(5, 6, 1);
            graph.dfs();  // 1=>2=>4=>8=>5=>3=>6=>7
          //  graph.bfs(); // 1=>2=>3=>4=>5=>6=>7=>8
    
        }
    
        public Graph(int n) {
            edges = new int[n][n];
            vertexList = new ArrayList<>(n);
            numOfEdges = 0;
            isVisited = new boolean[n];
        }
    
        // 返回当前结点的第一个邻接结点的下标
        public int getFirstNeighbor(int index) {
            for (int j = 0; j < vertexList.size(); j++) {
                if (edges[index][j] > 0) {
                    return j;
                }
            }
            return -1;
        }
    
        // 根据前一个结点的下标得到下一个结点的下标
        public int getNextNeighbor(int v1, int v2) {
            for (int j = v2 + 1; j < vertexList.size(); j++) {
                if (edges[v1][j] > 0) {
                    return j;
                }
            }
            return -1;
        }
    
        /**
         * 深度遍历
         *
         * @param isVisited 是否被访问过
         * @param i         结点下标
         */
        public void dfs(boolean[] isVisited, int i) {
            // 输出当前节点
            System.out.print(getValueByIndex(i) + "=>");
            // 设置此节点已被访问过
            isVisited[i] = true;
            // 找到结点i的第一个邻接结点w
            int w = getFirstNeighbor(i);
            // 如果w存在
            while (w != -1) {
                // 未被访问,递归继续遍历
                if (!isVisited[w]) {
                    dfs(isVisited, w);
                }
                // 被访问过则找到前一个结点的下一个结点
                w = getNextNeighbor(i, w);
            }
        }
    
        /**
         * 广度优先遍历
         *
         * @param isVisited
         * @param i
         */
        public void bfs(boolean[] isVisited, int i) {
            int u; // 队列头元素
            int w; // 邻接结点下标
            // 访问初始结点i
            System.out.print(getValueByIndex(i) + "=>");
            // 标记为已访问
            isVisited[i] = true;
            // 创建一个队列,用来存储结点的下标
            LinkedList<Integer> queue = new LinkedList<>();
            // 将结点入队
            queue.offer(i);
            // 如果队列不为空
            while (!queue.isEmpty()) {
                // 队头元素出队
                u = queue.removeFirst();
                // 查找u对应的第一个邻接点下标
                w = getFirstNeighbor(u);
                // 判断w是否存在
                while (w != -1) {
                    // 判断w是否被访问过
                    if (!isVisited[w]) {
                        // 没有被访问过,访问该结点
                        System.out.print(getValueByIndex(w) + "=>");
                        // 设置为被访问
                        isVisited[w] = true;
                        // w入队
                        queue.offer(w);
                    }
                    // 然后查找w邻接结点的下一个邻接结点下标
                    w = getNextNeighbor(u, w);
                }
            }
        }
    
        public void bfs() {
            for (int i = 0; i < getNumOfVertex(); i++) {
                if (!isVisited[i]) {
                    bfs(isVisited, i);
                }
            }
        }
    
        public void dfs() {
            for (int i = 0; i < vertexList.size(); i++) {
                if (!isVisited[i]) {
                    dfs(isVisited, i);
                }
            }
        }
    
        // 返回结点的个数
        public int getNumOfVertex() {
            return vertexList.size();
        }
    
        // 返回边的个数
        public int getNumOfEdges() {
            return numOfEdges;
        }
    
        // 返回结点i对应的值
        public String getValueByIndex(int i) {
            return vertexList.get(i);
        }
        //返回v1和v2的权值
    
        public int getWeight(int v1, int v2) {
            return edges[v1][v2];
        }
    
        // 显示图对于的矩阵
        public void showGraph() {
            for (int[] edge : edges) {
                System.out.println(Arrays.toString(edge));
            }
        }
    
        // 插入结点
        public void insertVertex(String vertex) {
            vertexList.add(vertex);
        }
    
        //添加边
        public void insertEdge(int v1, int v2, int weight) {
            edges[v1][v2] = weight;
            edges[v2][v1] = weight;
            numOfEdges++;  // 边的数量增加
        }
    }
    
    
  • 相关阅读:
    Android动态加载jar/dex
    aiXcoder安装&使用
    笨办法学python 13题:pycharm 运行
    python2.7安装numpy、pandas、matplotlib库
    win10在文件夹下打开powershell
    SpringCloud:(一)服务注册与发现
    pycharm2018.2安装
    Python2.7安装&配置环境变量
    centos7配置NTP时间服务器
    centos7:Zookeeper集群安装
  • 原文地址:https://www.cnblogs.com/cqyp/p/14771935.html
Copyright © 2011-2022 走看看