Java实现无向图深搜确定任意两点间最短距离

软件构造lab1实验中编写的Problem3部分,在此处做个记录

涉及的数据类,方法

  1. Graph类
    表示无向图。其下有几个重要变量:
    persons:为ArrayList,用于保存graph中的节点。其定义为:

    public List<Person> persons = new ArrayList<Person>();
    

    relationships:为嵌套的Vector,保存节点间的关系矩阵。若两节点直接相连,则对应位置为1;若两节点不直接相连,则对应位置为0。其定义为:

    public Vector<Vector<Integer>> relationships = new Vector<Vector<Integer>>();
    
  2. Person类
    表示图中的顶点。具有nameindex两个私有变量,name为String类型,表示名称,是顶点的标识;index为int型,代表顶点在关系矩阵中对应第index行与第index列。若顶点不在图中,则index为默认值-1。

  3. getDistance方法
    输入参数为两个Person顶点,返回值为两顶点间的最短距离。为了方便说明,规定相连两点间距为1。方法声明为:

    public int getDistance(Person p1, Person p2) 
    

算法基本思想

  1. 首先对异常情况进行判断,若输入两顶点相同 / 有不在图中的顶点,则直接返回-1。实现方法为具体根据person的index与name成员判断。

  2. 进行BFS深搜。具体的实现如下:
    首先构造以下三个变量:

    int distance =0; // 起始点到终点的距离,初始为0
    Queue<Person> queue = new LinkedList<Person>(); // 队列,用于BFS搜索
    int[] visit = new int[persons.size()]; // visit数组(visit为标志是否访问过的数组,访问过为1,否则为0)
    boolean[] isQueueEnd = new boolean[persons.size()];  // isQueueEnd标志节点i是否是某轮bfs深搜的终点,若是,其为true,,需要使distance++
    

    在我们的算法中,先将初始顶点p1加入队列,因为其访问过,且为第0轮深搜的终点,故设置visit[]isQueueEnd[]对应位为1。然后弹出该顶点,依次搜索与该顶点直接相连的顶点入队,将这些顶点的visit[]位均设置为1,且设置当前轮最后一个入队顶点的isQueueEnd[]对应位为1,由此,便完成了一轮BFS搜索。

  3. 终结情况判断:
    当队首为终结顶点p2时,正常结束,返回distance
    当检测到队空时,说明没有从p1p2的通路,返回-1

以下图为例来解释我们的算法:
在这里插入图片描述
假设计算从P1到P6的距离:
1. 先将P1入队
在这里插入图片描述
2.弹出P1,加入P2,P3,P4,并标记P4为当前轮终点,distance++。
在这里插入图片描述
3.之后按顺序依次进行:
在这里插入图片描述
直到队首为P6,返回此时的distance值。
在这里插入图片描述

具体实现

person类

public class Person {
    private String name;
    private int index = -1;

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

    public String getName() {
        return name;
    }

    public int getIndex() {
        return index;
    }

    public void setIndex(int index) {
        this.index = index;
    }
}

getDistance()方法

/**
     * Add a new edge from p1 to p2.
     *
     * @param p1 The starting vertex of the new edge
     * @param p2 The ending vertex of the new edge
     * @return The shortest distance between p1 and p2. If there are no any paths between them, return -1.
     */
    public int getDistance(Person p1, Person p2) {
        // 异常情况处理
        // p1与p2有其一不在关系图中
        if (p1.getIndex() == -1) {
            System.out.print(p1.getName() + "不在关系图中");
            return -1;
        }
        if (p2.getIndex() == -1) {
            System.out.print(p2.getName() + "不在关系图中");
            return -1;
        }
        // p1与p2相等
        if (p1.getIndex() == p2.getIndex()) {
            return 0;
        }
        Queue<Person> queue = new LinkedList<Person>(); // 队列,用于BFS搜素
        int distance = 0;
        Person temp = new Person("");
        Person queueEnd = new Person("");
        Vector<Integer> tempCol = new Vector<Integer>();
        // visit数组(visit为标志是否访问过的数组,访问过为1,否则为0)
        int[] visit = new int[persons.size()];
        // isQueueEnd标志节点i是否是某轮bfs深搜的终点,若是,其为true,,需要使distance++
        boolean[] isQueueEnd = new boolean[persons.size()];


        // 初始化,对p1进行设定
        queue.add(p1);
        visit[p1.getIndex()] = 1;
        isQueueEnd[p1.getIndex()]=true;

        while (queue.peek() != p2) {
            temp = queue.poll(); // 弹出并保存queue的头元素
            // 将与queue头元素直接相连,且未访问过的元素入队
            tempCol = relationships.get(temp.getIndex()); // tempCol保存头元素对应的关系矩阵行
            for (int i = 0; i < tempCol.size(); i++) { // 头元素对应的关系矩阵行,遍历此行中的所有元素,找到与头元素直接相邻的元素
                if (tempCol.get(i) == 1) {
                    // 查找index为i的person,并将其加入队列,同时把其标记为访问过
                    for (Person t : persons) {
                        if (t.getIndex() == i && visit[i] == 0) {
                            queue.add(t);
                            visit[i] = 1;
                            queueEnd = t; // 记录当前队尾
                            break;
                        }
                    }
                }
            }

            // 最后队列空,说明没有p1到p2的直接通路
            if (queue.isEmpty())
                return -1;

            // 记录当前队尾,并使distance++
            if (isQueueEnd[temp.getIndex()]) {
                isQueueEnd[queueEnd.getIndex()]=true;
                distance++;
            }
        }
        return distance;
    }
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是一个示例代码,演示如何使用Geotools读取shp文件,并计算任意两点的最短路径: ```java import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.geotools.data.DataStore; import org.geotools.data.DataStoreFinder; import org.geotools.data.DefaultTransaction; import org.geotools.data.Transaction; import org.geotools.data.simple.SimpleFeatureIterator; import org.geotools.data.simple.SimpleFeatureSource; import org.geotools.factory.CommonFactoryFinder; import org.geotools.feature.FeatureIterator; import org.geotools.feature.simple.SimpleFeatureBuilder; import org.geotools.feature.simple.SimpleFeatureTypeBuilder; import org.geotools.geometry.jts.JTSFactoryFinder; import org.geotools.graph.build.GraphBuilder; import org.geotools.graph.build.line.BasicLineGraphGenerator; import org.geotools.graph.path.DijkstraShortestPathFinder; import org.geotools.graph.structure.Edge; import org.geotools.graph.structure.Graph; import org.geotools.graph.structure.Node; import org.geotools.graph.structure.basic.BasicEdge; import org.geotools.graph.structure.basic.BasicNode; import org.geotools.referencing.CRS; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.filter.FilterFactory2; import org.opengis.geometry.Geometry; import org.opengis.geometry.primitive.Point; import org.opengis.referencing.crs.CoordinateReferenceSystem; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Envelope; import com.vividsolutions.jts.geom.GeometryFactory; public class ShpFileShortestPath { public static void main(String[] args) throws Exception { // 读取shp文件 File file = new File("path/to/shapefile.shp"); DataStore dataStore = DataStoreFinder.getDataStore(file); String typeName = dataStore.getTypeNames()[0]; SimpleFeatureSource featureSource = dataStore.getFeatureSource(typeName); // 创建图形数据 GraphBuilder graphBuilder = new GraphBuilder(JTSFactoryFinder.getGeometryFactory()); SimpleFeatureIterator featureIterator = featureSource.getFeatures().features(); try { while (featureIterator.hasNext()) { SimpleFeature feature = featureIterator.next(); Geometry geometry = (Geometry) feature.getDefaultGeometry(); // 添加节点 Coordinate[] coordinates = geometry.getCoordinates(); for (Coordinate coordinate : coordinates) { Node node = new BasicNode(); node.setObject(coordinate); graphBuilder.addNode(node); } // 添加边 for (int i = 0; i < coordinates.length - 1; i++) { Coordinate start = coordinates[i]; Coordinate end = coordinates[i + 1]; double weight = start.distance(end); Edge edge = new BasicEdge(graphBuilder.getNode(start), graphBuilder.getNode(end)); edge.setObject(weight); graphBuilder.addEdge(edge); } } } finally { featureIterator.close(); } Graph graph = graphBuilder.getGraph(); // 计算最短路径 DijkstraShortestPathFinder finder = new DijkstraShortestPathFinder(graph); Node startNode = graph.getNode(new Coordinate(起点经度, 起点纬度)); Node endNode = graph.getNode(new Coordinate(终点经度, 终点纬度)); List<Node> path = finder.getPath(startNode, endNode); // 输出最短路径 System.out.println("最短路径:"); for (Node node : path) { Coordinate coordinate = (Coordinate) node.getObject(); System.out.println(coordinate.x + "," + coordinate.y); } } } ``` 其中,需要根据实际情况替换以下代码: - ``path/to/shapefile.shp``:shp文件的路径。 - ``起点经度``、``起点纬度``、``终点经度``、``终点纬度``:起点和终点的经纬度坐标。 请注意,这只是一个简单的示例,实际应用中需要根据具体情况进行适当调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值