• 数据结构(三十一)图的邻接表存储结构


      一、图的邻接表结构Java语言代码实现:

    • 图的四种类型枚举类:
    package bigjun.iplab.adjacencyList;
    /**
     * 图的四种主要类型的枚举类
     */
    public enum GraphKind {
    
        UDG,    // 无向图
        DG,        // 有向图
        UDN,    // 无向网
        DN,        // 有向网
    }
    • 图的邻接表存储结构的顶点结点类:
    package bigjun.iplab.adjacencyList;
    /**
     * 图的邻接表存储结构中的顶点结点类
     */
    public class VexNode {
        
        public Object data;            // 顶点的信息
        public ArcNode firstArc;    // 指向第一条依附于该顶点的弧
        
        public VexNode() {
            this(null, null);
        }
        
        public VexNode(Object data) {
            this(data, null);
        }
        
        public VexNode(Object data, ArcNode firstArc) {
            this.data = data;
            this.firstArc = firstArc;
        }
    
        public Object getData() {
            return data;
        }
    
        public ArcNode getFirstArc() {
            return firstArc;
        }
        
        
    }
    • 图的邻接表存储结构的边(或弧)结点类:
    package bigjun.iplab.adjacencyList;
    /**
     * 图的邻接表存储结构中的边(或弧)结点类
     */
    public class ArcNode {
    
        public int adjVex;            // 该弧所指向的顶点在顶点数组中的下标
        public int weight;            // 边或弧的权值
        public ArcNode nextArc;        // 指向下一条表示边或弧的结点类
        
        public ArcNode() {
            this(-1, 0, null);
        }
        
        public ArcNode(int adjVex) {
            this(adjVex, 0, null);
        }
        
        public ArcNode(int adjVex, int weight) {
            this(adjVex, weight, null);
        }
        
        public ArcNode(int adjVex, int weight, ArcNode nextArc) {
            this.adjVex = adjVex;
            this.weight = weight;
            this.nextArc = nextArc;
        }
        
        
        
    }
    • 图的邻接表存储结构接口类:
    package bigjun.iplab.adjacencyList;
    /**
     * 图的邻接矩阵存储结构接口类
     */
    public interface AdjacencyListGraphINF {
        
        // 创建一个图
        public void createGraph();
        // 返回图中的顶点数
        public int getVexNum();
        // 返回图中的边数
        public int getArcNum();
        // 给定顶点的位置v,返回其对应的顶点值
        public Object getVex(int x) throws Exception;
        // 给定顶点的值vex,返回其在图中的位置
        public int locateVex(Object vex);
        // 返回顶点v的第一个邻接点
        public int firstAdjvex(int v) throws Exception;
        // 返回v相对于w的下一个邻接点
        public int nextAdjvex(int v, int w) throws Exception;
        // 在图中插入有权重的边或弧结点
        public void addArc(int v, int u, int weight);
        // 在图中插入没有权值的边或弧结点
        public void addArc(int v, int u);
        
    }
    • 图的邻接表存储结构实现类:
    package bigjun.iplab.adjacencyList;
    
    import java.util.Scanner;
    
    public class AdjListGraph implements AdjacencyListGraphINF{
        
        private GraphKind kind;            // 图的种类标志
        private int vexNum, arcNum;        // 顶点数,边数
        private VexNode[] vexs;            // 顶点结点组成的顶点数组
        
        public GraphKind getKind() {
            return kind;
        }
    
        public Object[] getVexs() {
            return vexs;
        }
    
        // 构造方法1: 构造一个空图
        public AdjListGraph() {
            this(null, 0, 0, null);
        }
        
        // 构造方法2: 构造一个非空图
        public AdjListGraph(GraphKind kind, int vexNum, int arcNum, VexNode[] vexs) {
            this.kind = kind;
            this.vexNum = vexNum;
            this.arcNum = arcNum;
            this.vexs = vexs;
        }
    
        // 创建图的四种类型中的一种
        public void createGraph() {
            @SuppressWarnings("resource")
            Scanner scanner = new Scanner(System.in);
            System.out.println("请输入图的类型代号(UDG(无向图)、DG(有向图)、UDN(无向网)、DN(有向网)):");
            GraphKind kind = GraphKind.valueOf(scanner.next());
            switch (kind) {
            case UDG:
                createUnDirecedGraph();
                return;
            case DG:
                createDirectedGraph();
                return;
            case UDN:
                createUnDirectedNet();
                return;
            case DN:
                createDirectedNet();
                return;
            }
            System.out.println("图已创建完成!");
        }
        
        // 创建无向图
        private void createUnDirecedGraph() {
            @SuppressWarnings("resource")
            Scanner sc = new Scanner(System.in);
            System.out.println("请分别输入图的顶点数,图的边数: ");
            vexNum = sc.nextInt();
            arcNum = sc.nextInt();
            vexs = new VexNode[vexNum];                        // 创建顶点结点数组
            System.out.println("请分别输入图的各个顶点: ");
            for (int i = 0; i < vexNum; i++) {                // 初始化顶点一维数组
                vexs[i] = new VexNode(sc.next());
            }
            System.out.println("请输入各个边的两个顶点(第一个输入是弧尾,第二个输入是弧头): ");
            for (int k = 0; k < arcNum; k++) {                // 填入对应的权值
                int v = locateVex(sc.next());                
                int u = locateVex(sc.next());
                addArc(v, u);                        
                addArc(u, v);                                // 无向图是双向的弧
            }
        }
        
        // 创建有向图
        private void createDirectedGraph() {
            @SuppressWarnings("resource")
            Scanner sc = new Scanner(System.in);
            System.out.println("请分别输入图的顶点数,图的边数: ");
            vexNum = sc.nextInt();
            arcNum = sc.nextInt();
            vexs = new VexNode[vexNum];                        // 创建顶点结点数组
            System.out.println("请分别输入图的各个顶点: ");
            for (int i = 0; i < vexNum; i++) {                // 初始化顶点一维数组
                vexs[i] = new VexNode(sc.next());
            }
            System.out.println("请输入各个边的两个顶点(第一个输入是弧尾,第二个输入是弧头): ");
            for (int k = 0; k < arcNum; k++) {                // 填入对应的权值
                int v = locateVex(sc.next());                
                int u = locateVex(sc.next());
                addArc(v, u);                        
            }
        }
        
        // 创建无向网
        private void createUnDirectedNet() {
            @SuppressWarnings("resource")
            Scanner sc = new Scanner(System.in);
            System.out.println("请分别输入图的顶点数,图的边数: ");
            vexNum = sc.nextInt();
            arcNum = sc.nextInt();
            vexs = new VexNode[vexNum];                        // 创建顶点结点数组
            System.out.println("请分别输入图的各个顶点: ");
            for (int i = 0; i < vexNum; i++) {                // 初始化顶点一维数组
                vexs[i] = new VexNode(sc.next());
            }
            System.out.println("请输入各个边的两个顶点及其权值(第一个输入是弧尾,第二个输入是弧头): ");
            for (int k = 0; k < arcNum; k++) {                // 填入对应的权值
                int v = locateVex(sc.next());                
                int u = locateVex(sc.next());
                int weight = sc.nextInt();                    
                addArc(v, u, weight);                        
                addArc(u, v, weight);                                // 无向网是双向的弧
            }
        }
        
        // 创建有向网
        private void createDirectedNet() {
            @SuppressWarnings("resource")
            Scanner sc = new Scanner(System.in);
            System.out.println("请分别输入图的顶点数,图的边数: ");
            vexNum = sc.nextInt();
            arcNum = sc.nextInt();
            vexs = new VexNode[vexNum];                        // 创建顶点结点数组
            System.out.println("请分别输入图的各个顶点: ");
            for (int i = 0; i < vexNum; i++) {                // 初始化顶点一维数组
                vexs[i] = new VexNode(sc.next());
            }
            System.out.println("请输入各个边的两个顶点及其权值(第一个输入是弧尾,第二个输入是弧头): ");
            for (int k = 0; k < arcNum; k++) {                // 填入对应的权值
                int v = locateVex(sc.next());                
                int u = locateVex(sc.next());
                int weight = sc.nextInt();                    
                addArc(v, u, weight);
            }
        }
    
        // 返回顶点数
        public int getVexNum() {
            return vexNum;
        }
    
        // 返回边数
        public int getArcNum() {
            return arcNum;
        }
    
        // 返回v表示结点的值
        public Object getVex(int x) throws Exception{
            if (x < 0 && x >= vexNum ) 
                throw new Exception("给定的顶点不存在");
            return vexs[x].data;
        }
    
        // 返回顶点的值为vex的顶点在顶点数组的位置下标,如果图中不包含值为vex的顶点,则返回-1,例如,顶点名称为V0
        public int locateVex(Object vex) {
            for (int v = 0; v < vexNum; v++) {
                if (vexs[v].data.equals(vex)) {
                    return v;
                }
            }
            return -1;
        }
    
        // 返回下标为v的顶点的第一个邻接点,即遍历邻接矩阵的第v行,找到之后,返回第v行对应的下标
        public int firstAdjvex(int v) throws Exception {
            if (v < 0 && v >= vexNum ) 
                throw new Exception("给定的顶点不存在");
            VexNode vex = vexs[v];
            if (vex.firstArc != null) {
                return vex.firstArc.adjVex;
            } else {
                return -1;
            }
        }
    
        // 返回下标为v的顶点相对于下标为w的顶点的下一个邻接点,若w是v的最后一个邻接点,则返回-1
        public int nextAdjvex(int v, int w) throws Exception {
            if (v < 0 && v >= vexNum ) 
                throw new Exception("给定的顶点不存在");
            VexNode vex = vexs[v];
            ArcNode arcvTOw = null;
            for (ArcNode arc = vex.firstArc; arc != null; arc = arc.nextArc) {
                if (arc.adjVex == w) {
                    arcvTOw = arc;
                    break;
                }
            }
            if (arcvTOw != null && arcvTOw.nextArc != null) {
                return arcvTOw.nextArc.adjVex;
            } else {
                return -1;
            }
        }    
        
        // 在位置为v、u的顶点之间,添加一条弧,权值为weight
        public void addArc(int v, int u, int weight) {
            ArcNode arc = new ArcNode(u, weight);
            arc.nextArc = vexs[v].firstArc;
            vexs[v].firstArc = arc;
        }
        
        // 在位置为v、u的顶点之间,添加一条没有权重的弧
        public void addArc(int v, int u) {
            ArcNode arc = new ArcNode(u);
            arc.nextArc = vexs[v].firstArc;
            vexs[v].firstArc = arc;
        }
        
        public static void main(String[] args) throws Exception {
            AdjListGraph aListGraph = new AdjListGraph();
            aListGraph.createGraph();
            System.out.println("该类型的图已经创建完成!");
            System.out.println("顶点数组下标为2的第一个邻接点的数组下标是: " + aListGraph.firstAdjvex(2));
            int numOfV2 = aListGraph.firstAdjvex(2);
            System.out.println("顶点V2的第一个邻接点是: " + aListGraph.getVex(numOfV2));
            System.out.println("顶点数组下标为2的相对于顶点数组下标为0的下一个邻接点的数组下标是: " + aListGraph.nextAdjvex(2, 0));
            int numOfV2toV0next = aListGraph.nextAdjvex(2, 0);
            System.out.println("顶点V2相对于V0的邻接点是: " + aListGraph.getVex(numOfV2toV0next));
        }
    }
    • 以下面的例子为例:

      

    • 输出:
    请输入图的类型代号(UDG(无向图)、DG(有向图)、UDN(无向网)、DN(有向网)):
    DN
    请分别输入图的顶点数,图的边数: 
    5 6
    请分别输入图的各个顶点: 
    V0 V1 V2 V3 V4
    请输入各个边的两个顶点及其权值(第一个输入是弧尾,第二个输入是弧头): 
    V0 V4 6
    V1 V2 3
    V1 V0 9
    V2 V3 5
    V2 V0 2
    V3 V4 1
    该类型的图已经创建完成!
    顶点数组下标为2的第一个邻接点的数组下标是: 0
    顶点V2的第一个邻接点是: V0
    顶点数组下标为2的相对于顶点数组下标为0的下一个邻接点的数组下标是: 3
    顶点V2相对于V0的邻接点是: V3

      

      二、图的邻接表结构C语言代码实现:

    #include "stdio.h"    
    #include "stdlib.h"   
    #include "io.h"  
    #include "math.h"  
    #include "time.h"
    
    #define OK 1
    #define ERROR 0
    #define TRUE 1
    #define FALSE 0
    #define MAXVEX 100 /* 最大顶点数,应由用户定义 */
    
    typedef int Status;    /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
    typedef char VertexType; /* 顶点类型应由用户定义 */
    typedef int EdgeType; /* 边上的权值类型应由用户定义 */
    
    typedef struct EdgeNode /* 边表结点  */
    {
        int adjvex;    /* 邻接点域,存储该顶点对应的下标 */
        EdgeType info;        /* 用于存储权值,对于非网图可以不需要 */
        struct EdgeNode *next; /* 链域,指向下一个邻接点 */
    }EdgeNode;
    
    typedef struct VertexNode /* 顶点表结点 */
    {
        VertexType data; /* 顶点域,存储顶点信息 */
        EdgeNode *firstedge;/* 边表头指针 */
    }VertexNode, AdjList[MAXVEX];
    
    typedef struct
    {
        AdjList adjList; 
        int numNodes,numEdges; /* 图中当前顶点数和边数 */
    }GraphAdjList;
    
    /* 建立图的邻接表结构 */
    void  CreateALGraph(GraphAdjList *G)
    {
        int i,j,k;
        EdgeNode *e;
        printf("输入顶点数和边数:
    ");
        scanf("%d,%d",&G->numNodes,&G->numEdges); /* 输入顶点数和边数 */
        for(i = 0;i < G->numNodes;i++) /* 读入顶点信息,建立顶点表 */
        {
            scanf(&G->adjList[i].data);     /* 输入顶点信息 */
            G->adjList[i].firstedge=NULL;     /* 将边表置为空表 */
        }
        
        
        for(k = 0;k < G->numEdges;k++)/* 建立边表 */
        {
            printf("输入边(vi,vj)上的顶点序号:
    ");
            scanf("%d,%d",&i,&j); /* 输入边(vi,vj)上的顶点序号 */
            e=(EdgeNode *)malloc(sizeof(EdgeNode)); /* 向内存申请空间,生成边表结点 */
            e->adjvex=j;                    /* 邻接序号为j */                         
            e->next=G->adjList[i].firstedge;    /* 将e的指针指向当前顶点上指向的结点 */
            G->adjList[i].firstedge=e;        /* 将当前顶点的指针指向e */               
            
            e=(EdgeNode *)malloc(sizeof(EdgeNode)); /* 向内存申请空间,生成边表结点 */
            e->adjvex=i;                    /* 邻接序号为i */                         
            e->next=G->adjList[j].firstedge;    /* 将e的指针指向当前顶点上指向的结点 */
            G->adjList[j].firstedge=e;        /* 将当前顶点的指针指向e */               
        }
    }
    
    int main(void)
    {    
        GraphAdjList G;    
        CreateALGraph(&G);
        
        return 0;
    }
    创建无向图的邻接表存储结构
  • 相关阅读:
    四、MYSQL的数据类型
    一、InnoDB引擎
    Spring源码分析(一)
    ActiveMQ 的安装与使用(springboot版本)
    12、JAVA内存模型与线程
    9、虚拟机字节码执行引擎
    8、类加载机制
    7、Class文件的格式
    6、使用jconsole+VisualVM分析JVM
    5、JVM的监控与分析工具
  • 原文地址:https://www.cnblogs.com/BigJunOba/p/9247721.html
Copyright © 2020-2023  润新知