图论——图的邻接表实现——Java语言(完整demo)

一、图的实现方式概述

1、图的简单实现方法——邻接矩阵

表示图的一种简单的方法是使用一个一维数组和一个二维数组,称为领接矩阵(adjacent matrix)表示法。
对于每条边(u,v),置A[u,v]等于true;否则,数组的元素就是false。如果边有一个权,那么可以置A[u][v]等于该权,而使用一个很大或者很小的权来标记不存在的边。虽然这样表示非常简单,但是,它的空间需求则为θ(|V|2),如果图的边不是很多,那么这种表示的代价就太大了。若图是稠密(dense)的:|E|=θ(|V|2),则领接矩阵是合适的表示方法。但大多数情况下并非如此。无向图用邻接矩阵表示会浪费一半的空间,稀疏的有向图用邻接矩阵表示会浪费大部分空间,稠密的有向图适合用邻接矩阵表示。

2、图的优化实现方法——邻接表

如果图是稀疏的(sparse),那么更好的解决方法是使用邻接表(adjacency list)表示。邻接表是一个二维容器,第一维是一个数组,存储所有顶点,第二维是链表,存储所有与这个点领接的点集。此时的空间需求为O(|E|+|V|),它相对于图的大小而言是线性的。
邻接表是表示图的标准方法。无向图可以以类似的方法表示,但每条边将会出现在两个表中,造成空间的双倍冗余。
实现邻接表的方法有很多,基本的选择有两个:一、使用一个映射,在这个映射下,关键字是顶点,值是那些邻接表。二、关键字是顶点,值是一个包含链的类Vertex。

图的邻接矩阵实现比较简单,这里我们只展示图的邻接表实现方式。

二、图的邻接表实现

图的邻接表实现总共有3个类,它们分别是:

  • 图的顶点的类:Vertex.java
  • 图的边类:Edge.java
  • 图类:Graph.java

此外,还有一个测试类Test,以方便验证图的构建是否成功,下面是完整的实现代码。

顶点类Vertex:

package dataStructure.graph.graph_ve;

/**
 * 图的节点类
 */
public class Vertex {
    /**
     * 节点存储的内容
     */
    String verName;
    /**
     * 顶点的边链
     */
    Edge edgeLink;

}

边类Edge

package dataStructure.graph.graph_ve;


/**
 * 图的边类
 */
public class Edge {
    /**
     * 边的尾部节点名称
     */
    String tailName;
    /**
     * 边的权值
     */
    int weight;
    /**
     * 头节点的其他边
     */
    Edge broEdge;
}

图类Graph:

package dataStructure.graph.graph_ve;

import java.util.Scanner;

/**
 * 图类,在构造方法中完成图的构造
 */
public class Graph {
    /**
     * 图的节点个数
     */
    int verNum;
    /**
     * 图的边的条数
     */
    int edgeNum;
    /**
     * 图的邻接表中存储节点的数组
     */
    Vertex[] verArray;

    /**
     * Graph类的构造方法,依次读取节点、边等信息,完成图的构建。
     */
    public Graph() {
        Scanner scan = new Scanner(System.in);
        System.out.println("请输入节点个数和边的个数:");
        verNum = scan.nextInt();
        edgeNum = scan.nextInt();
        verArray = new Vertex[verNum];

        System.out.println("请依次输入节点的名称:");
        for (int i=0;inew Vertex();
            vertex.verName = scan.next();
            vertex.edgeLink = null;
            verArray[i] = vertex;
        }

        System.out.println("请按‘头节点 权值 尾节点 回车’的形式依次输入边的信息");
        for (int i=0;iint weight = scan.nextInt();
            String folName = scan.next();

            Vertex preV = getVertex(preName);
            Vertex folV = getVertex(folName);
            if (preV == null || folV == null){
                System.out.println("输入错误,输入了不存在的顶点!请重新输入");
                i--;
                continue;
            }

            Edge edge = new Edge();
            edge.tailName = folName;
            edge.weight = weight;

            //将边加入到节点的链表中去
            edge.broEdge = preV.edgeLink;
            preV.edgeLink = edge;

//            如果加上下面这段,则创建的是无向图,不加则是有向图
//            edge.tailName = preName;
//            edge.broEdge  = folV.edgeLink;
//            folV.edgeLink = edge;
        }
    }

    /**
     * 根据节点名称获取该节点
     * @param verName 节点的名称
     * @return 节点或null
     */
    public Vertex getVertex(String verName){
        for (int i=0;iif (verArray[i].verName.equals(verName))
                return verArray[i];
        }
        return null;
    }
}

测试类Test:

package dataStructure.graph.graph_ve;


public class Test {
    public static void main(String[] args) {
        Graph graph = new Graph();
        System.out.println("该图的邻接表为:");
        outputGraph(graph);
    }

    /**
     * 输出图的邻接表的方法。
     * @param graph 要输出的图
     */
    public static void outputGraph(Graph graph){
        for (int i=0;iwhile (current != null){
                System.out.print("--"+current.weight+"-->"+current.tailName);
                current = current.broEdge;
            }
            System.out.println();
        }
    }
}

测试结果:

/* 测试结果:
请输入节点个数和边的个数:
4 5
请依次输入节点的名称:
V0 V1 V2 V3
请按‘头节点 权值 尾节点 回车’的形式依次输入边的信息
V0 5 V3
V1 3 V0
V2 9 V0
V1 6 V2
V2 7 V1
该图的邻接表为:
V0--5-->V3
V1--6-->V2--3-->V0
V2--7-->V1--9-->V0
V3
 */

上述实例已经同步到Github,遇到问题的同学可以克隆下来直接运行,链接是:https://github.com/Dodozhou/Algorithm/tree/master/src/main/java/dataStructure/graph/graph_ve

你可能感兴趣的:(算法——数据结构)