Java HashMaps和putAll()方法的问题

Java HashMaps和putAll()方法的问题,java,hashmap,Java,Hashmap,大家好, 我正在编写一个程序,比较各种Dijkstra实现的运行时间。我解析文本文件中的相关信息并将其输入哈希表。在我当前的实现中,我有一个保存节点信息的“主”哈希表,该信息被复制到一个临时哈希表中,然后传递到不同的Dijkstra类 public class Router { public static Map <Integer, Node> nodes = new HashMap<Integer, Node>(); public static Map

大家好, 我正在编写一个程序,比较各种Dijkstra实现的运行时间。我解析文本文件中的相关信息并将其输入哈希表。在我当前的实现中,我有一个保存节点信息的“主”哈希表,该信息被复制到一个临时哈希表中,然后传递到不同的Dijkstra类

public class Router
{
    public static Map <Integer, Node> nodes = new HashMap<Integer, Node>();
    public static Map <Integer, Node> temp = new HashMap<Integer, Node>();
    public static int target = 2;
    public static int start = 0;

    public static void main(String[] args) throws IOException
    {
        Parser p3 = new Parser(args[0], nodes, p);
        temp.putAll(nodes);

        // Test 1
        DijkstraFib fb = new DijkstraFib(temp, start, target, p);
        temp.clear();
        temp.putAll(nodes);

        //Test 2
        DijkstraBinary d = new DijkstraBinary(temp, start, target, p);
        temp.clear();
        temp.putAll(nodes);

        // Test 3
        Dijkstra b = new Dijkstra(temp, start, target, p);
    }
下面是我打印从目标节点开始的路径的方法:

 void print_path(Map <Integer, Node> visited, int i)
{
    ArrayList<Node> path = new ArrayList<Node>();

    for (Node target = visited.get(i); target != null; target = target.previous)
    {
        path.add(target);
    }
    System.out.println("Simple Dijkstra took " + this.time_taken + " ms");
    System.out.print("Min dist from " + this.source + " to " + this.target + " = " + path.get(0).distance + " : ");

    Collections.reverse(path);

    System.out.print(path.get(0).name);
    p.append(Integer.toString(path.get(0).name));
    for (int k = 1; k < path.size(); k++)
    {
        System.out.print(" -> " + path.get(k).name);
    }
    System.out.println();
}
下面是控制台输出:

Edges: 948464
Fibonacci Dijkstra took 340 ms
Min dist from 0 to 2 = 89.0 : 0 -> 195 -> 5523 -> 5504 -> 5870 -> 5835 -> 3076 -> 15319 -> 5588 -> 5911 -> 2

Binary Dijkstra took 302292 ms
Min dist from 0 to 2 = 89.0 : 0 -> 195 -> 5523 -> 5504 -> 5870 -> 5835 -> 3076 -> 15319 -> 5588 -> 5911 -> 2

Simple Dijkstra took 0 ms
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
   at java.util.ArrayList.rangeCheck(ArrayList.java:571)
   at java.util.ArrayList.get(ArrayList.java:349)
   at Dijkstra.print_path(Dijkstra.java:115)
   at Dijkstra.<init>(Dijkstra.java:25)
   at Router.main(Router.java:33)

在没有看到更多代码的情况下,我无法确定,但当您将所有内容放入新映射时,似乎正在传递相同的对象。也就是说,从一个调用到另一个调用引用相同的节点,而temp不是节点中值的副本。如果您的方法正在修改最短路径算法的路径权重,即,如果节点是可变的,您将遇到问题


一种选择是通过创建新节点并填充所有相关信息来为节点编写深度复制方法。然后,对于每次新运行的算法,您都会有一个节点的“新”副本

,而不会看到更多的代码,我不能确定,但当您将所有内容放入新映射时,看起来您正在传递相同的对象。也就是说,从一个调用到另一个调用引用相同的节点,而temp不是节点中值的副本。如果您的方法正在修改最短路径算法的路径权重,即,如果节点是可变的,您将遇到问题


一种选择是通过创建新节点并填充所有相关信息来为节点编写深度复制方法。然后,对于每次新运行的算法,您都会有一个节点的“新”副本

异常java.lang.IndexOutOfBoundsException意味着您试图获取数组中超出范围的元素

方法打印路径中的115行中存在问题:

at Dijkstra.print_path(Dijkstra.java:115)
尝试使用调试器了解遇到异常时变量的状态。为此,在115行的方法print_path中设置断点,并检查为什么要从不存在的索引中获取元素

编辑:
问题是,当您调用putAll时,您将引用放在了主节点上,之后,您的算法将修改节点HashMap中的节点,这将在下一个测试中传播

异常java.lang.IndexOutOfBoundsException意味着您试图获取数组中超出范围的元素

方法打印路径中的115行中存在问题:

at Dijkstra.print_path(Dijkstra.java:115)
尝试使用调试器了解遇到异常时变量的状态。为此,在115行的方法print_path中设置断点,并检查为什么要从不存在的索引中获取元素

编辑:
问题是,当您调用putAll时,您将引用放在了主节点上,之后,您的算法将修改节点HashMap中的节点,这将在下一个测试中传播

是否提出了例外情况?如果是的话,你能把它也贴出来吗?哦,在我把它贴在这里之前忘了把它去掉。“p”是不在上面的PrintStream变量代码。我正在将算法运行时间记录到一个txt文件中以备将来使用。是否引发了异常?如果是的话,你能把它也贴出来吗?哦,在我把它贴在这里之前忘了把它去掉。“p”是不在上面的PrintStream变量代码。我正在将算法的运行时间记录到一个txt文件中,以备将来使用。与深度复制不同,每次返回具有相同数据的新映射的方法可能更容易。感谢您的回复。我将如何编写一个返回具有相同数据的新映射的方法?从上面的答案中,我推断temp包含的不是我节点的副本,而是实际的节点。@Jeremy-那么,像hashmap的深度副本一样@user283188-问题源于使用putAll时对象是相同的。您需要编写一个方法1创建一个新的hashmap 2使用@Jeremy提到的相同数据填充该hashmap。按原样传递键应该没问题,但需要复制节点对象,例如,创建一个新节点,并将节点中的每个变量设置为现有变量的值。@spin_plate听起来像是对我认为是一个简单问题/愚蠢错误的过度处理。我知道问题出在哪里,非常感谢你。让我问你这个问题——如果你看前两个算法运行的输出路径,路径距离保持不变,即使每个人都指出每个算法运行直接修改主节点距离。你认为这是为什么?与深度复制相比,每次返回具有相同数据的新映射的方法可能更容易。谢谢你的回复。我将如何编写一个返回具有相同数据的新映射的方法?根据上面的答案,我收集到temp包含
实际节点。@Jeremy-那么,像hashmap的深度副本一样@user283188-问题源于使用putAll时对象是相同的。您需要编写一个方法1创建一个新的hashmap 2使用@Jeremy提到的相同数据填充该hashmap。按原样传递键应该没问题,但需要复制节点对象,例如,创建一个新节点,并将节点中的每个变量设置为现有变量的值。@spin_plate听起来像是对我认为是一个简单问题/愚蠢错误的过度处理。我知道问题出在哪里,非常感谢你。让我问你这个问题——如果你看前两个算法运行的输出路径,路径距离保持不变,即使每个人都指出每个算法运行直接修改主节点距离。您认为这是为什么?第115行是:System.out.printMin dist from+this.source+to+this.target+=+path.get0.distance+:;对于所有三个Dijkstra类,print_path方法都是相同的,但每当其中一个类第三次运行时,它总是失败。因此path.get0.distance会导致问题,因为在这种情况下,path数组有0个元素。我认为路径数组是空的,因为在for循环的第三次调用中,您访问了。geti==nullYeah,我不明白为什么会发生这种情况。每个Dijkstra类都有自己的“publicmap visted=newhashmap;”我的“route”方法会在其中添加节点,所以我不明白为什么它在第三次调用时会出现错误。这就是为什么使用静态变量的坏主意:你是说在节点和临时哈希表前面使用静态变量吗?第115行是:System.out.printMin dist from+this.source+to+this.target+=+path.get0.distance+:;对于所有三个Dijkstra类,print_path方法都是相同的,但每当其中一个类第三次运行时,它总是失败。因此path.get0.distance会导致问题,因为在这种情况下,path数组有0个元素。我认为路径数组是空的,因为在for循环的第三次调用中,您访问了。geti==nullYeah,我不明白为什么会发生这种情况。每个Dijkstra类都有自己的“publicmap visted=newhashmap;”我的“route”方法向它添加了节点,所以我不明白为什么它在第三次调用时会出现错误。这就是为什么使用静态变量是个坏主意:你是说在节点和临时哈希表前面使用静态变量吗?