计算无向图或有向图中从一个点到另一个点最少的边数

计算图中从一个点到另一个点最少的边数


前言:如果只是想查看计算图中从一个点到另一个点最少的边数的方法,请直接移步到代码部分查看getDistance函数。

问题描述

在这里我们模拟社交关系网络图,图中的一个顶点就是一个人,一条边就代表两个人相识。

图结构设计

一、Person类

public class Person {
    private final String name;

    public Person(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                '}';
    }
}

二、图结构类
在该类内部创建了两个静态内部类Node、Edge,分别代表图里的顶点。
Node声明如下:
Node类
Edge声明如下:
Edge类
Graph类两个关键属性如下:
Graph类
属性graph的每一个key为图里的一个结点,value为以该结点为起始结点的边的集合。
属性map每一个Person和Node的一一对应关系,通过它可以很方便的根据Person获取它在图中的对应Node。
三、代码实现

public class Graph {
    private final Map<Node, Set<Edge>> graph;  // 图
    private Map<Person, Node> map;  // person和node的映射关系

    private int min = Integer.MAX_VALUE;

    public Graph() {
        this.graph = new HashMap<>();
        this.map = new HashMap<>();
    }

    /**
     * 向图里添加一个结点
     * @param vertex
     */
    public void addVertex(Person vertex) {
        Node node = new Node(vertex);
        graph.put(node, new HashSet<>());
        map.put(vertex, node);
    }

    /**
     * 向图里添加一条边
     * @param start
     * @param end
     */
    public void addEdge(Person start, Person end) {
        //  获取Person所对应的Node
        Node startNode = map.get(start);
        Node endNode = map.get(end);
        if(startNode == null || endNode == null) {
            throw new RuntimeException("输入异常!");
        }
        //   创建一条边
        Edge edge = new Edge(startNode, endNode);
        Node node = map.get(start);
        if (node == null) {
            throw new RuntimeException("输入异常!");
        }
        //  向图里添加一条边
        graph.get(node).add(edge);
    }

    /**
     * 求两个结点间的最短距离
     * @param start
     * @param end
     * @return
     */
    public int getDistance(Person start, Person end) {
        if(start == end) {
            return 0;
        }
        min = Integer.MAX_VALUE;  // 将min初始化为Integer.MAX_VALUE
        Node startNode = map.get(start);  // 获取start对应的图结点
        startNode.setVisit(true);  // 设置startNode已经访问过
        getDistance(start, end, new Integer(1));
        return min == Integer.MAX_VALUE ? -1 : min-1;  // min此时为结点数,需要减一
    }
	
	//  curr代表当前的遍历路径已经走过几个结点
    private void getDistance(Person start, Person end, Integer curr) {
    	// 当start == end时说明找到了目标结点,需要去更新min
        if(start == end) {
            min = Math.min(min, curr);
            return;
        }
        Node startNode = map.get(start);
        Set<Edge> startEdges = graph.get(startNode);
        //  遍历与startNode 存在边的全部结点
        for(Edge edge: startEdges) {
            Node endNode = edge.getEnd();
            if(!endNode.isVisit) {
                curr++;
                endNode.setVisit(true);
                getDistance(endNode.getPerson(), end, curr);
                //  回溯的核心:恢复状态
                endNode.setVisit(false);
                curr--;
            }
        }
    }


    static class Edge {
        private Node start;
        private Node end;

        public Edge(Node start, Node end) {
            this.start = start;
            this.end = end;
        }

        public Node getStart() {
            return start;
        }

        public void setStart(Node start) {
            this.start = start;
        }

        public Node getEnd() {
            return end;
        }

        public void setEnd(Node end) {
            this.end = end;
        }

        @Override
        public String toString() {
            return "Edge{" +
                    "start=" + start +
                    ", end=" + end +
                    '}';
        }
    }

    static class Node {
        private final Person person;
        private boolean isVisit = false;

        public Node(Person person) {
            this.person = person;
        }

        public Person getPerson() {
            return person;
        }

        public boolean isVisit() {
            return isVisit;
        }

        public void setVisit(boolean visit) {
            isVisit = visit;
        }

        @Override
        public String toString() {
            return "Node{" +
                    "person=" + person +
                    ", isVisit=" + isVisit +
                    '}';
        }
    }
}

四、getDistance方法思想
使用回溯法来尝试每一种可能的结果,找出所有可能的结果中最小的路径长度。

如果你想了解更多我对编程和人生的思考,请关注公众号:青云学斋

公众号

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值