zoukankan      html  css  js  c++  java
  • 数据结构之无向图

    前言:  

          我们所讨论的图模型中,边仅仅是两个顶点之间的连接。一般使用0-(V-1)来表示一张含有V个顶点的图中的各个顶点。用v-w的记法表示v点和w点之间的边(又可以写成w-v)。

          特殊的两种图:

             自环:  一条连接一个顶点和其自身的边。

             平行边: 连接同一对顶点的两条边。

         以下所说的图两个顶点之间仅含有一条边。

    相关术语:

      

    当边连接两个顶点时,我们说顶点彼此 相邻。

    顶点的度数为依附于他的边的总数。

    子图是一幅图所有被边的一个子集(包括他们所依附的顶点)。

    路径是由边连接的顶点序列,没有重复的边。

    简单路径是没有重复顶点的路径。

    是一条至少含有一条边且起点和终点相同的路径。

    简单环是一条(除了起点和终点必须相同之外)不含重复顶点和边的环。

    路径或环的长度为其包含的边数。

    如果从任意一个顶点都存在一条路径到达另一个任意顶点,则称这幅图是连通图

    一个非连通图由若干连通图组成,它们都是极大连通子图

    无环图是一个不包含环的图。

    是一副无环连通图。互不相连的树组成森林。连通图的生成树是他的一副子图,它含有图中的所有顶点且是一颗树。图的生成森林是他的所有连通子图的生成树的集合。

    关于树的定义,以下五种说法是等价的:(一副含有V个顶点的图G)

    1:G有V-1条边并且不含环。

    2:G有V-1条边并且是联通的

    3:G是连通的且删除任意一条边都会使他不连通。

    4:G是无环图且添加任意一条边都会使他产生一条环。

    5:G中任意一对顶点间仅存在一条简单路径。

    我们定义以下图的基本操作API:

    Public  class   Graph

                     Graph(int V)   //创建一个含有V个顶点但不含边的图

                     Graph(InputStream in) //从标准输入流中读取一个图

              int     V()    //顶点数

              int     E()    //边数

              void addEdge(int v,int w)  //添加边V-W

        Iterable<Integer> adj(int v)   //遍历与v相邻的顶点

               String toString()      // @Override

    相关实现:

    计算V的度数:

           public static int degree(Graph g,int v)

    {    int  degree=0;

        for(int w: g.adj(v)) degree++;

       return degree;

    }

    计算所有顶点的最大度数:

       public static int maxDegree(Graph g)

    {    int  max=0;

         for(int v=0;v<g.v();v++)

                 if(degree(g,v)>max)

                       max=degree(g,v);

              return  max;   }

    计算自环的个数:

    public static int numberOfSefLoops(Graph g)

    {   int count=0;

           for(int v=0;v<g.v();v++)

               for(int w:g.adj(v))

                if(w==v)  count++;

           return count/2;

    }

    //覆写toString方法@Override

      public String toString()

    {

        String s=V+”vertices”+E+” edges ”;//建议你用StringBuilder

           for(int v=0;v<g.v();v++)

            {   s+=v+”:  ”;

                  for(int w:this.adj(v))

                     s+=“ ”;

    }

       return  s;

    }

    图的几种表示方法:

    要求:  1、必须为各种情况下遇到的图预留足够空间。

                 2、快。

      邻接矩阵:

          用一个V * V的Boolean矩阵表示,1代表相连。

           //不满足第一种要求。

      边的数组:

           使用一个Edge类,含有两个int变量。

           /不满足第二个要求,比如调用adj方法。

      邻接表数组:(推荐)

          使用以顶点为索引的列表数组,其中每个元素都是和该顶点相连的顶点列表。如下图:

         

    要连接一条v到w的边,我们要将w添加到v的邻接表中并把v添加到w的临界表中。因此这种结构中每条边都会出现两次。

      代码实现:

    //我们使用前面介绍过的Bag,Stack实现,相关代码请看数据结构之队列、栈

     1 public class Graph {
     2 
     3     private final int V;
     4     private int E;
     5     private Bag<Integer> adj[];
     6     
     7     @SuppressWarnings("unchecked")
     8     public Graph(int V)
     9     {   if (V < 0) throw new IllegalArgumentException("Number of vertices must be nonnegative");
    10         this.V=V;
    11         this.E=0;
    12         adj= (Bag<Integer>[])new Bag[V];
    13         for(int i=0;i<V;i++)
    14         {
    15             adj[i]=new Bag<Integer>();
    16         }
    17     }
    18     
    19     public Graph(Graph G) {
    20         this(G.V());
    21         this.E = G.E();
    22         for (int v = 0; v < G.V(); v++) {
    23          
    24             Stack<Integer> reverse = new Stack<Integer>();
    25             for (int w : G.adj[v]) {
    26                 reverse.push(w);
    27             }
    28             for (int w : reverse) {
    29                 adj[v].add(w);
    30             }
    31         }
    32     }
    33     
    34     public int V()
    35     {
    36         return this.V;
    37     }
    38     
    39     public int E()
    40     {
    41         return this.E;
    42     }
    43     
    44     private void validateVertex(int v) {
    45         if (v < 0 || v >= V)
    46             throw new IllegalArgumentException("vertex " + v + " is not between 0 and " + (V-1));
    47     }
    48     
    49     public void addEdge(int v,int w)
    50     {  validateVertex(v);
    51        validateVertex(w);
    52      adj[v].add(w);    
    53      adj[w].add(v);
    54      E++;
    55     }
    56     
    57      public Iterable<Integer> adj(int v) {
    58             validateVertex(v);
    59             return adj[v];
    60         }
    61      
    62       public int degree(int v) {
    63             validateVertex(v);
    64             return adj[v].size();
    65         }
    66       
    67        public String toString() {
    68             StringBuilder s = new StringBuilder();
    69             s.append(V + " vertices, " + E + " edges " );
    70             for (int v = 0; v < V; v++) {
    71                 s.append(v + ": ");
    72                 for (int w : adj[v]) {
    73                     s.append(w + " ");
    74                 }
    75                 s.append("
    ");
    76             }
    77             return s.toString();
    78         }
    79 
    80 }
    View Code
  • 相关阅读:
    Ubuntu 指令汇总
    ROS环境下Pointgrey相机的配置方法
    BUG战斗史 —— 日期格式与字符串之间的转换
    Effective Java —— 使类和成员的可访问性最小化
    JDBC和桥接模式
    Effective Java —— 覆盖equals时总要覆盖hashCode
    AutoValue —— Generated immutable value classes
    Effective Java —— 覆盖equals时遵守通用约定
    Effective Java —— try-with-resources 优先于 try-finally
    Effective Java —— 消除过期的对象引用
  • 原文地址:https://www.cnblogs.com/lls101/p/11187916.html
Copyright © 2011-2022 走看看