【图】认识与表达

一、图的基本构成

地图上有很多的建筑,每个建筑之间有着四通八达的道路连接着,如果想要使用数据结构来表示建筑和建筑之间的道路,就应该选择图。

在这里插入图片描述

树是由节点构成的,存在一对多的关系,并且节点之间有着父节点、子节点的划分。图是比树结构更加复杂的数据结构

树里面的节点放在图中指的是顶点,是图中最基本的单元,存在着多对多的关系,顶点之间都是平等的,没有父顶点、子顶点这样的说法

连接各个顶点的是边,对于带权图来说,边并不是一样的,有各自的权重,就像是城市之间的道路有各自的长短一样。并且边是存在方向的,对于有向图来说,顶点A能够到达顶点B,但是顶点B没有办法到达顶点A,对于无向图来说,顶点A、B之间就是互通的

在这里插入图片描述

二、图的表达方式

关于图的表达方式有很多种,常见的有邻接矩阵、邻接表、数组 …

1)邻接矩阵

邻接矩阵是用来表达顶点之间关联关系的矩阵,就是通过一个 n * n 的数组将图表述出来

在这里插入图片描述

如上图所示,由于有5个顶点,因此创建 5 * 5 的二维数组,数组的行代表着起始顶点,列代表着终止顶点,元素值代表着从起始顶点到终止顶点的权重。

顶点 A 可以通向顶点 B ,权重为 9,数组元素 arr[0][1] 就是 9。当然像顶点 A 到顶点 A 这样的情况,对应的值必然是 0

如果这个图是一个无向图,最后得到的二维数组一定是一个对称的数组,顶点 A 和顶点 B 有关联,顶点 B 必然和顶点 A 有关联

2)邻接表

邻接矩阵的缺点就在于空间占用量太大,如果有 N 个顶点,意味着需要使用到 N * N 的二维数组,N 非常大时,太浪费空间,邻接表法就是一个相对来说更加节省空间的表示图的方法

在这里插入图片描述

在邻接表中,图的每个顶点都会是链表的头节点,一共有 5 个顶点,表示有 5 个链表,头节点后面依次连接着该顶点可以到达的相邻顶点。链表节点由三部分组成:顶点值,到目标顶点的权重,指向下一个节点的地址

如果想要知道顶点 C 是否可以到达顶点 D,只需要对以顶点 C 为链表头节点的链表进行遍历即可,若存在,表示可达,否则不可达

当然如果想要有多少顶点可以到达顶点 D,我们可以选择将所有的链表都进行遍历操作,但是会有一点浪费时间,因此我们可以使用逆邻接表来解决

在这里插入图片描述

逆邻接表每个顶点也作为链表的头节点,链表后面依次跟着的节点是可以到达该顶点的临近顶点,想要找可以到达顶点 D 的顶点都有哪些,直接找到以顶点 D 为头节点的链表进行遍历即可

3)数组

数组也是一种很常见的表达图的方式,使用一个二维数组,其中每一行有三个元素:起点顶点值,目标顶点值,两顶点间的权重

在这里插入图片描述

4)综合

表达图的方式有太多种,在写相关题目的时候,就需要根据题目提供的图的模型来解决问题。为了能够更加快速的解决问题,就需要准备一个图的标准模板,只需要掌握了标准模板解决问题的方法,将题目提供的图的模型转换成标准模板即可

顶点:

public class Node {
    //顶点的值
    public Integer value;
    //顶点的出度(有多少条边以该顶点为起点)
    public int out;
    //顶点的入度(有多少条边以该顶点为终点)
    public int in;
    //有这个顶点发散出去的相邻顶点有哪些
    public ArrayList<Node> nextNodes;
    //由这个顶点发散出去的边有哪些
    public ArrayList<Edge> borderEdges;

    public Node(Integer value) {
        this.value = value;
        out = 0;
        in = 0;
        nextNodes = new ArrayList<>();
        borderEdges = new ArrayList<>();
    }
}

边:

public class Edge {
    //边的起点
    public Node from;
    //边的终点
    public Node to;
    //边的权值
    public int weight;

    public Edge(Node from,Node to,int weight) {
        this.from = from;
        this.to = to;
        this.weight = weight;
    }
}

图:

//图所包含的两大要素,顶点和边
public class Graph {
    //图中所有的顶点,key是顶点的值,value是对应的顶点的具体信息
    public HashMap<Integer,Node> nodes;
    //图中的边
    public HashSet<Edge> edges;

    public Graph() {
        nodes = new HashMap<>();
        edges = new HashSet<>();
    }
}

例如:将通过数组表达的图转换成标准模板

public class ChangeGraph {
    //提供一个二维数组,其中的每一个一维数组由三个元素组成[原点,终点,权值]
    public Graph ChangeCase(int[][] array) {
        Graph graph = new Graph();//创建一个新的图
        for (int i = 0;i < array.length;i ++) {
            int from = array[i][0];
            int to = array[i][1];
            if(!graph.nodes.containsKey(from)) {
                //没有包含起始点,就创建一个新点
                Node fromNode = new Node(from);
                fromNode.out++;//出度加一
                graph.nodes.put(from,fromNode);//添加到图的模型中
            }else {
                //已经包含起始点,那就单纯出度加一
                graph.nodes.get(from).out++;
            }
            if (!graph.nodes.containsKey(to)) {
                //没有包含终点,就创建一个终点
                Node toNode = new Node(to);
                toNode.in++;//入度加一
                graph.nodes.put(to,toNode);//添加到图的模型中
            }else {
                //已经包含终点,就单纯入度加一
                graph.nodes.get(to).in++;
            }
            Node node1 = graph.nodes.get(from);
            Node node2 = graph.nodes.get(to);

            node1.nextNodes.add(node2);//新添加临近点
            Edge newEdge = new Edge(node1,node2,array[i][2]);//创建新边
            graph.edges.add(newEdge);//添加到图的模型中
            node1.borderEdges.add(newEdge);//新添加临近边
        }
        return graph;
    }
}
  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

富春山居_ZYY(已黑化)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值