图的关键算法

一、概念

图(Graph)是用于表示物体与物体之间存在某种关系的结构。数学抽象后的“物体”称作节点或顶点(Vertex,node或point),节点间的相关关系则称作。在描绘一张图的时候,通常用一组点或小圆圈表示节点,其间的边则使用直线或曲线。

1、有向图和无向图

图中的边可以是有方向或没有方向的。

例如在一张图中,如果节点表示聚会上的人,而边表示两人曾经握手,则该图就是没有方向的,因为甲和乙握过手也意味着乙一定和甲握过手。相反,如果一条从甲到乙的边表示甲欠乙的钱,则该图就是有方向的,因为“曾经欠钱”这个关系不一定是双向的。前一种图称为无向图,后一种称为有向图

同时,无向图也可以认为是有向图,即可以想象成两个节点之间有从A到B的边,也有B到A的边,所以从宽泛的角度可以认为所有图都是有向图

二、图的表示

教材上的表示法:邻接表、邻接矩阵

1、邻接表

在这里插入图片描述

2、邻接矩阵

如果图G有n个节点,则邻接矩阵是一个 n*n 的矩阵,定义为:

G[ i ][ j ] = 1(或权重值),若<Vi, Vj>是G中的边;否则G[ i ][ j ] = 无穷大。对于对角线的设置,视情况具体设置。

在这里插入图片描述

3、常见的表示法

以上两种表示法在实际刷题的过程中几乎不会遇到

更多的是给你一个 n*3 的矩阵[ [weight, fromNode, toNode] ],例如[ [3, A, B], [2, B, M], [5, A, R] ],第一个值表示权重,第二个值表示from节点,第三个值表示to节点。也就是一条边一条边的直接表示。

三、图的解决思路

图的算法都不算难,只不过coding的代价比较高

(1)先用自己最熟练的方式,实现图结构的表达

(2)在自己熟悉的结构上,实现所有常用的图算法作为模板

(3)把面试题提供的图结构转化为自己熟悉的图结构,再调用模板或改写即可

图的表示方法这么多种,并且每次给你的形式还可能不同,所以就有必要抽象一个自己的表示方法,以后对于不同的形式,写一个能转换为自己定义形式的方法即可(有种适配器的感觉),这样才能以不变应万变,把不熟悉的表示方法转换为自己熟悉的方法

/**
 * 自定义图的信息
 *
 * @author Java和算法学习:周一
 */
public class Graph {
   

    /**
     * 点集,Key:用户给的点,Value:自定义点信息
     */
    public HashMap<Integer, Node> nodes;

    /**
     * 边集
     */
    public HashSet<Edge> edges;

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

    /**
     * 将用户输入的表示边的 N*3 的矩阵转换为自定义的图
     *
     * @param matrix N*3 的矩阵,[3, 0, 5], [2, 2, 5]
     */
    public static Graph createGraph(int[][] matrix) {
   
        Graph graph = new Graph();
        for (int[] m : matrix) {
   
            // 拿到用户给的边的权重信息、边的from、to节点
            int weight = m[0];
            int from = m[1];
            int to = m[2];

            // 添加图的点集信息
            if (!graph.nodes.containsKey(from)) {
   
                graph.nodes.put(from, new Node(from));
            }
            if (!graph.nodes.containsKey(to)) {
   
                graph.nodes.put(to, new Node(to));
            }

            // 根据点生成边的信息
            Node fromNode = graph.nodes.get(from);
            Node toNode = graph.nodes.get(to);
            Edge edge = new Edge(weight, fromNode, toNode);

            // 节点信息处理
            // 添加 从当前节点出发直接连接的节点、从当前节点出发直接连接的边
            fromNode.nexts.add(toNode);
            fromNode.edges.add(edge);
            // 入度、出度修改
            fromNode.out++;
            toNode.in++;

            // 添加图的边集信息
            graph.edges.add(edge);
        }
        return graph;
    }

}

四、图的宽度优先和深度优先遍历

1、宽度优先遍历

(1)准备一个队列,一个Set(存放遍历过的节点,登记表),出发节点为A,把A放到队列和Set中

(2)弹出队列的顶点M,打印M的值。获取M的所有邻居节点next,查看Set中有没有这些next节点,无则放到Set和队列中,有则跳过此next节点

(3)一直执行第2步,直到队列为空


                
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值