根据性质,图可以分为无向图和有向图。本文先介绍无向图,后文再介绍有向图。之所以要研究图,是因为图在生活中应用比较广泛。

  图是若干个顶点(Vertices)和边(Edges)相互连接组成的。边仅由两个顶点连接,并且没有方向的图称为无向图。在研究图之前,有一些定义需要明确,下图中表示了图的一些基本属性的含义,这里就不多说明。

无向图的基本算法

 图的API表示

  在研究图之前,我们需要选用适当的数据结构来表示图,有时候,我们常被我们的直觉欺骗,如下图,这两个其实是一样的,这其实也是一个研究问题,就是如何判断图的形态。

无向图的基本算法

   要用计算机处理图,我们可以抽象出以下的表示图的API: 无向图的基本算法   Graph的API的实现可以由多种不同的数据结构来表示,最基本的是维护一系列边的集合,

无向图的基本算法

  如下:还可以使用邻接矩阵来表示:

无向图的基本算法

  也可以使用邻接列表来表示: 

无向图的基本算法

  由于采用如上方式具有比较好的灵活性,采用邻接列表来表示的话,可以定义如下数据结构来表示一个Graph对象。

public class Graph
{
    private readonly int verticals;//顶点个数
    private int edges;//边的个数
    private List<int>[] adjacency;//顶点联接列表
 
    public Graph(int vertical)
    {
        this.verticals = vertical;
        this.edges = 0;
        adjacency=new List<int>[vertical];
        for (int v = 0; v < vertical; v++)
        {
            adjacency[v]=new List<int>();
        }
    }
 
    public int GetVerticals ()
    {
        return verticals;
    }
 
    public int GetEdges()
    {
        return edges;
    }
 
    public void AddEdge(int verticalStart, int verticalEnd)
    {
        adjacency[verticalStart].Add(verticalEnd);
        adjacency[verticalEnd].Add(verticalStart);
        edges++;
    }
 
    public List<int> GetAdjacency(int vetical)
    {
        return adjacency[vetical];
    }
}
View Code

  采用以上三种表示方式的效率如下:

无向图的基本算法   在讨论完图的表示之后,我们来看下在图中比较重要的一种算法,即深度优先算法:

深度优先算法

  在谈论深度优先算法之前,我们可以先看看迷宫探索问题。下面是一个迷宫和图之间的对应关系:迷宫中的每一个交会点代表图中的一个顶点,每一条通道对应一个边。 迷宫探索可以采用Trémaux绳索探索法。即:

  • 在身后放一个绳子
  • 访问到的每一个地方放一个绳索标记访问到的交会点和通道
  • 当遇到已经访问过的地方,沿着绳索回退到之前没有访问过的地方:

  图示如下:

无向图的基本算法

  下面是迷宫探索的一个小动画:

无向图的基本算法

  深度优先搜索算法模拟迷宫探索。在实际的图处理算法中,我们通常将图的表示和图的处理逻辑分开来。所以算法的整体设计模式如下:

  • 创建一个Graph对象
  • 将Graph对象传给图算法处理对象,如一个Paths对象
  • 然后查询处理后的结果来获取信息

  下面是深度优先的基本代码,我们可以看到,递归调用dfs方法,在调用之前判断该节点是否已经被访问过。

public class DepthFirstSearch {
    private boolean[] marked;    // marked[v] = is there an s-v path?
    private int count;           // number of vertices connected to s

   
    public DepthFirstSearch(Graph G, int s) {
        marked = new boolean[G.V()];
        dfs(G, s);
    }

    //depth first search from v
    private void dfs(Graph G, int v) {
        count++;
        marked[v] = true;
        for (int w : G.adj(v)) {
            if (!marked[w]) {
                dfs(G, w);
            }
        }
    }

    public boolean marked(int v) {
        return marked[v];
    }

    public int count() {
        return count;
    }
}
View Code

相关文章:

  • 2021-05-09
  • 2022-12-23
  • 2021-11-23
  • 2021-07-01
猜你喜欢
  • 2021-08-18
  • 2022-12-23
  • 2021-06-15
  • 2022-12-23
  • 2021-09-07
  • 2021-07-20
  • 2021-12-15
相关资源
相似解决方案