zoukankan      html  css  js  c++  java
  • 图论

    一、图的常用概念

      1、顶点(vertex)

      2、边(edge)

      3、路径

      4、无向图:顶点之间的连接没有方向

      

       5、有向图:有方向

      

       6、带全图

      

    二、图的表示方式

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

      1、邻接矩阵

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

      

       2、邻接表

      邻接矩阵需要为每个顶点都分配n个边的空间,其实很多边都是不存在,会造成空间的浪费

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

      

    三、深度优先遍历(Depth First Search)

      深度优先遍历基本思想:

    1. 深度优先遍历,从初始访问结点出发,初始访问结点可能有多个邻接结点,深度优先遍历的策略就是首先访问第一个邻接结点,然后再以这个被访问的邻接结点作为初始结点,访问它的第一个邻接结点, 可以这样理解:每次都在访问完当前结点后首先访问当前结点的第一个邻接结点。
    2. 我们可以看到,这样的访问策略是优先往纵向挖掘深入,而不是对一个结点的所有邻接结点进行横向访问。
    3. 显然,深度优先搜索是一个递归的过程

      深度优先遍历步骤:

    1. 访问初始结点v,并标记结点v为已访问。
    2. 查找结点v的第一个邻接结点w。
    3. 若w存在,则继续执行4,如果w不存在,则回到第1步,将从v的下一个结点继续。
    4. 若w未被访问,对w进行深度优先遍历递归(即把w当做另一个v,然后进行步骤123)。
    5. 查找结点v的w邻接结点的下一个邻接结点,转到步骤3

      

       代码实现:

      

     1     private void dfs() {
     2         isVisited = new boolean[vertexList.size()];
     3         for (int i = 0; i < vertexList.size(); i++) {
     4             if (!isVisited[i]){
     5                 dfs(isVisited,i);
     6             }
     7         }
     8     }
     9     //深度优先遍历算法
    10     //i 第一次就是 0
    11     private void dfs(boolean[] isVisited, int i) {
    12         //输出,访问的结点
    13         System.out.println(vertexList.get(i)+"->");
    14         //将结点设置为已访问过
    15         isVisited[i] = true;
    16         //查找结点i的第一个领结节点w
    17         int w = getFirstNeighbor(i);
    18         while (w!=-1){
    19             if (!isVisited[w]){
    20                 dfs(isVisited,w);
    21             }
    22             //如果w结点已经被访问过
    23             w=getNextNeighbor(i,w);
    24         }
    25     }

    四、广度优先遍历(Broad First Search)

      广度优先遍历基本思想:

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

       深度优先遍历顺序为 1->2->4->8->5->3->6->7
      广度优先算法的遍历顺序为:1->2->3->4->5->6->7->8

      广度优先遍历步骤:

    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。

      代码:

      

     1  private void bfs() {
     2         isVisited = new boolean[vertexList.size()];
     3         for (int i = 0; i < vertexList.size(); i++) {
     4             if (!isVisited[i]){
     5                 bfs(isVisited,i);
     6             }
     7         }
     8     }
     9 
    10     private void bfs(boolean[] isVisited, int i) {
    11         int u;//表示队列的头结点对应下标
    12         int w;//邻接节点w
    13 
    14         //记录节点的访问顺序
    15         LinkedList queue = new LinkedList();
    16         System.out.println(vertexList.get(i)+"=>");
    17         isVisited[i] = true;
    18         queue.addLast(i);
    19 
    20         while (!queue.isEmpty()){
    21             //取出队列的头结点下标
    22             u= (int) queue.removeFirst();
    23             //得到第一个邻接点的下标w
    24             w=getFirstNeighbor(u);
    25             while (w!=-1){//找到
    26                 if(!isVisited[w]){
    27                     System.out.println(vertexList.get(w)+"=>");
    28                     isVisited[w] = true;
    29                     queue.addLast(w);
    30                 }
    31                 //以u为前驱点,找w后面的下一个邻接点
    32                 w=getNextNeighbor(u,w);
    33             }
    34         }
    35     }

    五、完整代码

      

      1 public class Graph {
      2 
      3     //存储顶点集合
      4     private ArrayList<String> vertexList;
      5     //存储图对应的邻接矩阵
      6     private int[][] edges;
      7     //表示边的数目
      8     private int numOfEdges;
      9     //定义给数组boolean【】,记录某个结点是否被访问过
     10     private boolean[] isVisited;
     11 
     12     public Graph(int n) {
     13         edges = new int[n][n];
     14         vertexList = new ArrayList<>(n);
     15         numOfEdges = 0;
     16     }
     17 
     18     public static void main(String[] args) {
     19 
     20         int n = 5;//结点个数
     21 //        String vertexs[] = {"1", "2", "3", "4", "5", "6", "7", "8"};
     22         String vertexs[] = {"A", "B", "C", "D", "E"};
     23         //创建图对象
     24         Graph graph = new Graph(n);
     25         for (String vertex : vertexs) {
     26             graph.insertVertex(vertex);
     27         }
     28         //更新边的关系
     29 //        graph.insertEdge(0, 1, 1);
     30 //        graph.insertEdge(0, 2, 1);
     31 //        graph.insertEdge(1, 3, 1);
     32 //        graph.insertEdge(1, 4, 1);
     33 //        graph.insertEdge(3, 7, 1);
     34 //        graph.insertEdge(4, 7, 1);
     35 //        graph.insertEdge(2, 5, 1);
     36 //        graph.insertEdge(2, 6, 1);
     37 //        graph.insertEdge(5, 6, 1);
     38         graph.insertEdge(0, 1, 1);
     39         graph.insertEdge(0, 2, 1);
     40         graph.insertEdge(1, 3, 1);
     41         graph.insertEdge(1, 2, 1);
     42         graph.insertEdge(1, 4, 1);
     43         graph.showGraph();
     44 
     45         System.out.println("深度遍历");
     46         graph.dfs();
     47         System.out.println("广度优先");
     48         graph.bfs();
     49     }
     50 
     51     private void dfs() {
     52         isVisited = new boolean[vertexList.size()];
     53         for (int i = 0; i < vertexList.size(); i++) {
     54             if (!isVisited[i]){
     55                 dfs(isVisited,i);
     56             }
     57         }
     58     }
     59     //深度优先遍历算法
     60     //i 第一次就是 0
     61     private void dfs(boolean[] isVisited, int i) {
     62         //输出,访问的结点
     63         System.out.println(vertexList.get(i)+"->");
     64         //将结点设置为已访问过
     65         isVisited[i] = true;
     66         //查找结点i的第一个领结节点w
     67         int w = getFirstNeighbor(i);
     68         while (w!=-1){
     69             if (!isVisited[w]){
     70                 dfs(isVisited,w);
     71             }
     72             //如果w结点已经被访问过
     73             w=getNextNeighbor(i,w);
     74         }
     75     }
     76 
     77     //得到第一个邻接节点的下标w
     78     //如果存在就返回对应的下标,否则返回-1
     79     private int getFirstNeighbor(int i) {
     80         for (int j = 0; j < vertexList.size(); j++) {
     81             if (edges[i][j]>0){
     82                 return j;
     83             }
     84         }
     85         return -1;
     86     }
     87     //根据前一个邻接结点的下标来获取下一个邻接结点
     88     public int getNextNeighbor(int v1, int v2) {
     89         for (int i = v2+1; i < vertexList.size(); i++) {
     90             if (edges[v1][i]>0){
     91                 return  i;
     92             }
     93         }
     94         return  -1;
     95     }
     96 
     97 
     98     private void bfs() {
     99         isVisited = new boolean[vertexList.size()];
    100         for (int i = 0; i < vertexList.size(); i++) {
    101             if (!isVisited[i]){
    102                 bfs(isVisited,i);
    103             }
    104         }
    105     }
    106 
    107     private void bfs(boolean[] isVisited, int i) {
    108         int u;//表示队列的头结点对应下标
    109         int w;//邻接节点w
    110 
    111         //记录节点的访问顺序
    112         LinkedList queue = new LinkedList();
    113         System.out.println(vertexList.get(i)+"=>");
    114         isVisited[i] = true;
    115         queue.addLast(i);
    116 
    117         while (!queue.isEmpty()){
    118             //取出队列的头结点下标
    119             u= (int) queue.removeFirst();
    120             //得到第一个邻接点的下标w
    121             w=getFirstNeighbor(u);
    122             while (w!=-1){//找到
    123                 if(!isVisited[w]){
    124                     System.out.println(vertexList.get(w)+"=>");
    125                     isVisited[w] = true;
    126                     queue.addLast(w);
    127                 }
    128                 //以u为前驱点,找w后面的下一个邻接点
    129                 w=getNextNeighbor(u,w);
    130             }
    131         }
    132     }
    133 
    134     //显示图对应的矩阵
    135     public void showGraph() {
    136         for (int[] link : edges) {
    137             System.out.println(Arrays.toString(link));
    138         }
    139     }
    140 
    141     /**
    142      * @param v1     表示点的下标即使第几个顶点  "A"-"B" "A"->0 "B"->1
    143      * @param v2     第二个顶点对应的下标
    144      * @param weight 表示
    145      */
    146     private void insertEdge(int v1, int v2, int weight) {
    147         edges[v1][v2] = weight;
    148         edges[v2][v1] = weight;
    149         numOfEdges++;
    150     }
    151 
    152     private void insertVertex(String vertex) {
    153         vertexList.add(vertex);
    154     }
    155 }
  • 相关阅读:
    linux引导系统
    Android开发面试经——2.常见Android基础笔试题
    Android开发面试经——1.常见人事面试问题
    Android面试题整理【转载】
    android设置软键盘搜索键以及监听搜索键点击时发生两次事件的问题解决
    Android软键盘弹出时把布局顶上去的解决方法
    Android入门:绑定本地服务
    Android aidl Binder框架浅析
    Android LayoutInflater深度解析 给你带来全新的认识
    Android RecyclerView 使用完全解析 体验艺术般的控件
  • 原文地址:https://www.cnblogs.com/hyunbar/p/11574217.html
Copyright © 2011-2022 走看看