zoukankan      html  css  js  c++  java
  • 数据结构(三十一)图的邻接表存储结构

      一、图的邻接表结构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;
    }
    创建无向图的邻接表存储结构
  • 相关阅读:
    LeetCode Path Sum II
    LeetCode Longest Palindromic Substring
    LeetCode Populating Next Right Pointers in Each Node II
    LeetCode Best Time to Buy and Sell Stock III
    LeetCode Binary Tree Maximum Path Sum
    LeetCode Find Peak Element
    LeetCode Maximum Product Subarray
    LeetCode Intersection of Two Linked Lists
    一天一个设计模式(1)——工厂模式
    PHP迭代器 Iterator
  • 原文地址:https://www.cnblogs.com/BigJunOba/p/9247721.html
Copyright © 2011-2022 走看看