广度优先搜索加权有向图

Breadth first search for weighted directed graph

我需要帮助为我的 BFS 算法添加边成本。我不知道如何为添加到路径中的每个顶点添加边成本。我将post代码供大家参考。给我一些建议。

Graph.java

package algo;
import java.util.*;


public class Graph 
{
    private static Map<String, LinkedHashSet<HashMap<String, Double>>> map;
    private ArrayList<String> nodes = new ArrayList<String>();
    private static ArrayList<String> shortestPath = new ArrayList<String>();
    public Graph()
    {

    }

    public Graph(String[] nodes)
    {
        map = new HashMap<String,LinkedHashSet<HashMap<String, Double>>>();
        for(int i=0;i<nodes.length;++i)
            map.put(nodes[i], new LinkedHashSet<HashMap<String, Double>>());
    }

    public void addNeighbor(String node1,String node2, Double edgeCost)
    {
        LinkedHashSet<HashMap<String, Double>> adjacent = map.get(node1);
        HashMap<String, Double> innerMap = new HashMap<String, Double>();
        if(map.get(node1)==null)
        {
            adjacent = new LinkedHashSet<HashMap<String, Double>>();                       
            map.put(node1, adjacent);
        }
        innerMap.put(node2, edgeCost);
        adjacent.add(innerMap);
    }

    public boolean memberOf(String node) {
        return nodes.contains(node);
    }

    public LinkedList<HashMap<String, Double>> getNeighbours(String node) {
        LinkedHashSet<HashMap<String, Double>> adjacent = map.get(node);
        if(adjacent==null) {
            return new LinkedList<HashMap<String, Double>>();
        }
        return new LinkedList<HashMap<String, Double>>(adjacent);
    }

    protected void storeNodes(String source, String destination) 
    {
        if (!source.equals(destination)) 
        {
            if (!nodes.contains(destination)) 
            {
                nodes.add(destination);
            }
        }
        if (!nodes.contains(source)) {
            nodes.add(source);
        }
    }

    public void getKeyValuePairs()
    {
        Iterator<String> iterator = map.keySet().iterator();

        while (iterator.hasNext()) 
        {
           String key = iterator.next().toString();
           LinkedHashSet<HashMap<String, Double>> value = map.get(key); 
           System.out.println(key + " " + value);
        }
    }
}

Main.java

package algo;
import java.io.*;

public class Main {

    public static void main(String[] args) throws IOException
    {
        File file = new File("city.txt");
        FileReader fr = new FileReader(file);
        BufferedReader br = new BufferedReader(fr);
        String line = br.readLine();
        String [] tokens = line.split("\s+");
        String [] nodes = new String[tokens.length];

        for (int i = 0; i < nodes.length; ++i) {
            nodes[i] = tokens[i];
         }
        Graph g = new Graph(nodes);
        String var_1 = tokens[0];
        String var_2 = tokens[1];
        Double var_3 = Double.parseDouble(tokens[2]);
        g.addNeighbor(var_1, var_2,var_3);
        while((line = br.readLine())!=null)
        {
            tokens = line.split("\s+");
            nodes = new String[tokens.length];
            for (int i = 0; i < nodes.length; ++i) {
                nodes[i] = tokens[i];
            }

            //Graph g = new Graph(nodes);
            var_1 = tokens[0];
            var_2 = tokens[1];
            var_3 = Double.parseDouble(tokens[2]);
            g.addNeighbor(var_1, var_2,var_3);
            g.storeNodes(var_1, var_2);
        }
        g.getKeyValuePairs();
        br.close();
     }

}

city.txt

city1  city2  5.5
city1  city3  6 
city2  city1  16  
city2  city3  26
city2  city4  15.5
city2  city5  7
city3  city4  9
city3  city5  5
city4  city1  3.6
city4  city2  4
city5  city2  7.9
city5  city3  5

这是我的代码的 bfs 部分,我在没有添加任何 edgecost 的情况下进行了测试

public static ArrayList<String> breadthFirstSearch(Graph graph, 
            String source,
            String destination) 
    {
        shortestPath.clear();

        // A list that stores the path.
        ArrayList<String> path = new ArrayList<String>();

        // If the source is the same as destination, I'm done.
        if (source.equals(destination) && graph.memberOf(source)) 
        {
            path.add(source);
            return path;
        }
         // A queue to store the visited nodes.
        ArrayDeque<String> queue = new ArrayDeque<String>();

        // A queue to store the visited nodes.
        ArrayDeque<String> visited = new ArrayDeque<String>();

        queue.offer(source);
        while (!queue.isEmpty()) {
            String vertex = queue.poll();
            visited.offer(vertex);

            ArrayList<String> neighboursList = (ArrayList<String>) graph.getNeighbours(vertex);
            int index = 0;
            int neighboursSize = neighboursList.size();
            while (index != neighboursSize) {
                String neighbour = neighboursList.get(index);

                path.add(neighbour);
                path.add(vertex);

                if (neighbour.equals(destination)) {
                    return processPath(source, destination, path);
                } else {
                    if (!visited.contains(neighbour)) {
                        queue.offer(neighbour);
                    }
                }
                index++;
            }
        }
        return null;
    }

    public static ArrayList<String> processPath(String src,
                                                String destination,
                                                ArrayList<String> path) 
    {

        // Finds out where the destination node directly comes from.
        int index = path.indexOf(destination);
        String source = path.get(index + 1);

        // Adds the destination node to the shortestPath.
        shortestPath.add(0, destination);

        if (source.equals(src)) {
        // The original source node is found.
        shortestPath.add(0, src);
        return shortestPath;
        } else {
        // We find where the source node of the destination node
        // comes from.
        // We then set the source node to be the destination node.
        return processPath(src, source, path);
        }
    }

我的问题是如何将 edgecost 添加到 bfs 部分的代码中,并在执行时提供从源到目的地的路径成本。

到 return 路径和成本,您需要创建一个 class 来保存这两个值:

class CostedPath {
    private final List<String> path = new ArrayList<>();
    private double cost = 0.0;

    public CostedPath(String start) {
        path.add(start);
    }

    public CostedPath addNode(String node, Graph graph) {
        this.cost += graph.getCost(path.get(0), node);
        path.add(0, node);
        return this;
    }
}

您的搜索应该 return 来自 processPathCostedPath

private CostedPath processPath(String start, String end, List<String> path, Graph graph) {
{
    String previous = path.get(path.indexOf(end) + 1);
    if (previous.equals(start))
        return new CostedPath(start);
    else
        return processPath(start, previous, path, graph).addNode(end, graph);
}

如果您将 class 拆分得更多,您的代码将更具可读性。

class Vertex {
    private final String name;
    private final Set<Edge> edges;
}

class Edge {
    private final Vertex end;
    private final double cost;
}

class Graph {
    private final Set<Vertex> vertices;
}

class Path {
    private final Vertex start;
    private final List<Edge> edges;
}

完成后,您会发现在何处添加与特定 class 相关的逻辑变得更加明显,并且您需要的数据将在您需要时可用。例如,现在可以轻松地将 Path 转换为总成本:

public double getCost() {
    return edges.stream().mapToDouble(Edge::getCost).sum();
}

与必须四处传递原始图形以查找边的成本相比,这是更简洁的代码。