算法7-2:图论接口

本节介绍如何在程序中表示一张图。

顶点

在程序中,顶点用整数表示就可以了。因为整数可以作为数组的下标,也可以作为哈希表的键。所以用整数是最方便的。

当然,在一张图中可能会出现一些异常情况,比如自己连接自己,两个顶点之间存在多个边。这些异常情况也是要考虑的。

接口

为了表示一张图,就要创建专门的对象来保存图。这个对象起名叫做Graph好了。它的接口是下面这样的。

public class Graph {
    // 创建一个带有V个顶点的图
    Graph(int V);

    // 从输入流创建一张图,输入流的格式下文有介绍
    Graph(In in);

    // 在两个顶点之间创建一条边。
    void addEdge(int v, int w);

    // 获取一个顶点的邻居顶点
    Iterable<Integer> adj(int v);

    // 获取这张图中顶点的数量
    int V();

    // 获取这张图中边的数量
    int E();

    // 将这张图表示成一个字符串,用于显示
    String toString();
}

输入格式

接口中提到了可以从一个输入流创建一张图。那么这个输入流的格式应该怎样呢?首先第一行是一个整数,表示这个图顶点的数量,第二行是一个整数,表示边的数量,后面的每一行中都有两个整数,表示两个顶点之间有一条边。

设施

图论中有一些简单的操作,比如计算一个顶点的度(邻居节点数量),自连接的数量等。这些操作在后面的算法中都会用到。它们的代码如下:

public static int degree(Graph G, int v) {
    int count = 0;
    for (Integer e : G.adj(v)) count++;
    return count;
}

public static int maxDegree(Graph G) {
    int max = 0;
    for (int v = 0; v < G.V(); v++) {
        int d = degree(G, v);
        if (d > max) max = d;
    }
    return max;
}

public static int averageDegree(Graph G) {
    return G.E() * 2 / G.V();
}

public static int numberOfSelfLoops(Graph G) {
    int count = 0;
    for (int v = 0; v < G.V(); v++) {
        for (int w : G.adj(v)) {
            if (v == w) {
                count++;
            }
        }
    }
    return count;
}

数据结构

图主要有两种表示方法,一种是邻接矩阵,一种是邻接表。同学们别被这样的怪名字吓到,其实它们的本质都是数组或者链表。

邻接矩阵

邻接矩阵就是一个很大的二维数组a,它的维度和顶点数量相同。如果顶点数量是V,那么这个二维矩阵就是V×V大小。其中a[v][w]就表示了顶点v和顶点w是否相连,0表示没有连接,1表示相连。

邻接表

邻接表其实就是一个数组,数组中的每个元素都用来记录某个顶点有哪些邻居。

邻接表表示法的代码如下:

public class Graph {
    private List<Integer>[] adj;

    public Graph(int V) {
        adj = new LinkedList[V];
        for (int i = 0; i < V; i++) {
            adj[i] = new LinkedList<Integer>();
        }
    }

    public void addEdge(int v, int w) {
        adj[v].add(w);
        adj[w].add(v);
    }

    public Iterable<Integer> adj(int v) {
        return adj[v];
    }

    public int V() {
        return adj.length;
    }

    public int E() {
        int result = 0;
        for (List<Integer> each : adj) {
            result += each.size();
        }
        return result;
    }

    @Override
    public String toString() {
        String result = "";
        for (int i = 0; i < adj.length; i++) {
            result += i + ":";
            for (int v : this.adj(i)) {
                result += " " + v;
            }
            result += "\n";
        }
        return result;
    }
}

实际应用中一般使用最多的就是邻接表,因为一般的应用顶点多而边数少。如果用邻接矩阵,内存浪费会很严重,因此实际应用中更加偏向于使用邻接表。

算法7-2:图论接口,布布扣,bubuko.com

时间: 2024-12-19 07:40:26

算法7-2:图论接口的相关文章

算法7-6:图论中的难题

二部图 难度:★★ 二分图是图论中的一种特殊模型,指顶点可以分成两个不相交的集使得在同一个集内的顶点不相邻(没有共同边)的图. 下图是一个二分图的例子,红点之间不会相邻,白点之间不会相邻. 判断图中是否存在环 难度:★★ 通过深搜就可以解决了. 欧拉环 难度:★★ 从一个顶点出发,所有的边都只经过一次,最后回到起点.判断一张图中是否存在这样的路径. 哈密尔顿环 难度:★★★★ 从一个顶点出发,所有的顶点都经过一次,最后回到起点.判断一张图中是否存在这样的路径. 这个是一个经典的NP完全问题,目前

算法8-7:最短路径接口

最短路径问题就是给定一个图,这个图中的边是有方向和权重的.求s到t的最短路径. 最短路径问题其实分为很多种.按照起点和终点来分,可以分为: 从一个顶点到另一个顶点 从一个顶点到其他所有顶点 从所有顶点到所有顶点 按照边的权重来分可以分为: 非负权 任意权 欧几里德权 按照是否有环可以分为 无环最短路径 无负环最短路径 类的定义 在实现最短路径算法之前,需要先在程序中定义有向权重图. 有向权重边的定义如下: public class DirectedEdge { private int v; pr

算法7-1:图论简介

无向图 无向图由顶点和边组成,边用于连接两个顶点.下面这张地图就是无向图的一个例子. OPTE工程 OPTE工程的目标就是绘制整个互联网的样子.下图是2010年的互联网.互联网也是无向图的一个例子.这张图是用LGL软件进行绘制的.有兴趣的同学可以研究一下:http://www.opte.org/ 术语 在图论中,有些术语是必须要知道的,不然没办法学习. 顶点:图中最基本的元素 边:连接两个顶点的线就是边 路径:由一个顶点到另一个顶点所经过的边 环:从一个顶点出发,经过一些边,最后到达原先的顶点,

【算法总结】图论-并查集

[算法总结]图论-并查集 一.概念:并查集 并查集,在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中.这一类问题近几年来反复出现在信息学的国际国内赛题中,其特点是看似并不复杂,但数据量极大,若用正常的数据结构来描述的话,往往在空间上过大,计算机无法承受:即使在空间上勉强通过,运行的时间复杂度也极高,根本就不可能在比赛规定的运行时间(1-3秒)内计算出试题需要的结果,只能用并查集来

【算法总结】图论-最短路径

[算法总结]图论-最短路径 一.概念 最短路径问题.即寻找图中某两个特定结点间最短的路径长度.所谓图上的路径,即从图中一个起始结点到一个终止结点途中经过的所有结点序列,路径的长度即所经过的边权和. 二.Floyd算法 用邻接矩阵保存原图,那么此时邻接矩阵中 edge[i][j]的值即表示从结点 i 到 结点j,中间不经过任何结点时距离的最小值(若它们之间有多条边,取最小权值保存至邻接矩阵:也可能为无穷,即不可达).假设结点编号为 1 到 N,我们再考虑从结点i 到结点j中间只能经过编号小于等于1

Android中设计模式--策略模式(封装会变化的算法部分,面向接口不针对实现)

策略模式:定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户. 理解: 把代码中类似,但又有差异的算法部分,提取出来,定义一个借口,不同的算法来进行不同的实现,但调用算法的客户可以进行统一的调用,因为实现了共同的借口,客户不需要知道具体的实现,而是知道怎么用,即针对接口编程,而不针对实现编程. 总结: 找出代码中可能需要变换之处,把它们独立出来,不要和那些不需要变化的代码混在一起. 例子 private TextClickInterface mClickI

算法提高课——图论

图论难点:问题的转化和抽象(可看成特殊的某一类DP) 图论与DP的联系: DP问题(从集合角度分析最优化问题)可以看成从F(0,0).F(0,1).F(1,2)......F(0,m)到F(n,m)的最长路.因此DP问题可以转化为拓扑图(一般DP问题的状态间无环)上的最短(长)路. 当DP依赖关系不具有拓扑序时(即存在环时),可以将其转化为最短路,也可以用高斯消元. //TLE的原因常常是没有memsert //st数组在不同算法中的用法: 单源最短路的建图方式 AcWing 1129. 热浪

算法笔记_149:图论之桥的应用(Java)

目录 1 问题描述 2 解决方案   1 问题描述 1310 One-way traffic In a certain town there are n intersections connected by two- and one-way streets. The town is very modern so a lot of streets run through tunnels or viaducts. Of course it is possible to travel between

【算法总结】图论相关

[最近公共祖先] [模板代码] [倍增算法] 1 void dfs(int k) 2 { 3 for(int i=1;(1<<i)<=deep[k];i++) 4 x[k][i]=x[x[k][i-1]][i-1]; 5 for(int i=head[k];i;i=e[i].next) 6 { 7 if(deep[e[i].to])continue; 8 x[e[i].to][0]=k; 9 deep[e[i].to]=deep[k]+1; 10 di[e[i].to]=di[k]+e[