如何在迭代其entrySet时修改映射

时间:2014-12-07 10:00:26

标签: java algorithm loops map hashmap

我在面试时遇到过这个问题:

给定一个无向图(由相应边描述),我如何找到可能的三角形数?

实施例: for:{(0,1),(2,1),(0,2),(4,1)}答案是:1。

我想到了一个算法,但在途中遇到了Java技术问题(而且我知道可能有更高效的其他算法,我的算法的正确性和有效性不是重点,技术问题在路上是)。

我的算法是这样的: 定义一个Hashmap:Map<夫妇,整数取代。地图的关键是Couple,它基本上包含两个点:起点(比如顶点'0')和出点(比如顶点'1')。地图的整数值是我从起始顶点到终点顶点的边数。 即对于边缘(0,1),地图中将有一个条目表示:( new Couple(0,1),1); 对于这两个边(0,1),(1,2),地图中会有一个条目,如:( new couple(0,2),2)因为我们可以通过遍历这两个从0到2边缘。

我的想法是开始在地图上迭代,并为每个顶点检查它是否可以连接(意味着它的出口点与其他顶点的起点相匹配,反之亦然)。如果是这样,请创建一个合适的新entrey,其边缘数为+ 1。最后,我想计算有多少对夫妇以相同的数字开头和结尾,大小为3(意味着创建一个三角形)。

问题在于,当我在地图上迭代时,我也改变了它(添加新条目,每次我找到连接到另一个的新边缘)。这导致我得到一个“java.util.ConcurrentModificationException”。

我想知道是否有人有办法解决这个问题,此外有人可以解释如何在将来克服这样的问题。 非常感谢!

public static int NumberOfTriangles(Couple[] nodes) {
    Map<Couple, Integer> map = new HashMap<>();
    int x1 = 0, y1 = 0, counter = 0;
    int x2 = 0, y2 = 0;
    for (int i = 0; i < nodes.length; i++) {
        x1 = nodes[i].getStart();
        y1 = nodes[i].getEnd();
        map.put(new Couple(x1, y1), 1);
        map.put(new Couple(y1, x1), 1);
    }
    for (int i = 0; i < nodes.length; i++) {
        x1 = nodes[i].getStart();
        y1 = nodes[i].getEnd();
        Iterator<Entry<Couple, Integer>> entries = map.entrySet()
                .iterator();
        while (entries.hasNext()) {
            Entry<Couple, Integer> thisEntry = (Entry<Couple, Integer>) entries
                    .next();
            x2 = thisEntry.getKey().getStart();
            y2 = thisEntry.getKey().getEnd();
            if (y1 == x2) {
                int value = map.get(new Couple(x1, y1));
                if (value < 3) {
                    value++;
                    if ((value == 3) && (x1 == y1)) {
                        counter++;
                    }
                    map.put(new Couple(x1, y2), value + 1);
                }
            }
            if (x1 == y2) {
                int value = map.get(new Couple(x2, y1));
                if (value < 3) {
                    value++;
                    if ((value == 3) && (x1 == y1)) {
                        counter++;
                    }
                    map.put(new Couple(y1, x2), value + 1);
                }
            }
            if (y1 == y2) {
                int value = map.get(new Couple(x1, x2));
                if (value < 3) {
                    value++;
                    if ((value == 3) && (x1 == y1)) {
                        counter++;
                    }
                    map.put(new Couple(x1, x2), value + 1);
                }
            }
            if (x1 == x2) {
                int value = map.get(new Couple(y1, y2));
                if ((value == 3) && (y1 == y2)) {
                    value++;
                    if (value == 3) {
                        counter++;
                    }
                    map.put(new Couple(y1, y2), value + 1);
                }
            }
        }
    }
    return counter;
}

情侣

    public class Couple {
    private int start;
    private int end;

    public Couple(int start, int end) {
        this.start = start;
        this.end = end;
    }

    public int getStart() {
        return start;
    }

    public int getEnd() {
        return end;
    }

    @Override
    public boolean equals(Object other) {
        if (other == this) {
            return true;
        } else {
            return ((((Couple) other).getStart() == start) && ((Couple) other)
                    .getEnd() == end);
        }
    }

    @Override
    public int hashCode() {
        return (start + end);
    }
}

2 个答案:

答案 0 :(得分:0)

使用另一个Vector来存储要修改的值,并在迭代器循环

之后执行

答案 1 :(得分:0)

您可以通过将 HashMap 更改为 ConcurrentHashMap 来修复该异常。 并改变每一个

int value = map.get(new Couple(x1, y1));
if (value < 3) {

Integer value = map.get(new Couple(x1, y1));
if (value != null && value < 3) {

这不会抛出ConcurentModificationException,但它不会找到任何三角形,因为我认为你的算法有误。 这是一个有用的新算法:

夫妇:

public class Couple {
    private int start;
    private int end;

    public Couple(int start, int end) {
        this.start = start;
        this.end = end;
    }

    public int getStart() {
        return start;
    }

    public int getEnd() {
        return end;
    }
}

节点

import java.util.HashSet;
import java.util.Set;

public class Node {

    private int value;
    private Set<Node> adjacentNodes = new HashSet<Node>();

    public Node(int x) {
        value = x;
    }
    public void addAdjacentNode(Node node) {
        adjacentNodes.add(node);
    }
    public int getValue() {
        return value;
    }

    public void setValue(int values) {
        this.value = values;
    }

    public Set<Node> getNodes() {
        return adjacentNodes;
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + value;
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Node other = (Node) obj;
        if (value != other.value)
            return false;
        return true;
    }
}
三角

public class Triangle {

    private Set<Integer> nodes = new HashSet<Integer>();
    public Triangle(Node... node ) {
        for (Node node2 : node) {
            nodes.add(node2.getValue());
        }
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((nodes == null) ? 0 : nodes.hashCode());
        return result;
    }
    @Override
    public String toString() {
        return "Triangle [nodes=" + nodes + "]";
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Triangle other = (Triangle) obj;
        if (nodes == null) {
            if (other.nodes != null)
                return false;
        } else if (!nodes.equals(other.nodes))
            return false;
        return true;
    }
}

主要

import java.text.MessageFormat;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class Main {

    public static void main(String[] args) {
        Set<Triangle> foundTriangles = new HashSet<Triangle>();
        Map<Integer, Node> graph = new HashMap<Integer, Node>();
        Couple[] a = new Couple[] { new Couple(0, 1), 
                                    new Couple(2, 1), 
                                    new Couple(0, 2), 
                                    new Couple(4, 1) };
        // build graph
        for (Couple couple : a) {
            int start = couple.getStart();
            Node node1 = graph.get(start);
            if (node1 == null) {
                node1 = new Node(start);
                graph.put(start, node1);
            }
            int end = couple.getEnd();
            Node node2 = graph.get(end);
            if (node2 == null) {
                node2 = new Node(end);
                graph.put(end, node2);
            }
            node1.addAdjacentNode(node2);
            node2.addAdjacentNode(node1);
        }
        // search for triangles in the graph
        for (Node root : graph.values()) {
            Set<Node> nodes = root.getNodes(); // A
            for (Node root2 : nodes) { // B
                if (!root2.equals(root)) { // prevent going back
                    Set<Node> nodes2 = root2.getNodes();
                    for (Node root3 : nodes2) { // C
                        if (!root3.equals(root2)) { 
                            Set<Node> nodes3 = root3.getNodes();
                            for (Node node4 : nodes3) {// A
                                if (!node4.equals(root3)) { 
                                    if (node4.equals(root)) { 
//                                      String message = 
//                                      MessageFormat.format(
//                                          "Found triangle: {0}{1}{2}",
//                                          root.getValue(),
//                                          root2.getValue(), 
//                                          root3.getValue());
//                                      System.out.println(message);
                                        Triangle t = new Triangle(root,
                                                                  root2, 
                                                                  root3);
                                        foundTriangles.add(t);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        System.out.println(foundTriangles);
    }
}

输出就像

[Triangle [nodes=[0, 1, 2]]]

如果使用MessageFormat删除对行的注释,将会看到更详细的输出

Found triangle: 012
Found triangle: 021
Found triangle: 120
Found triangle: 102
Found triangle: 210
Found triangle: 201
[Triangle [nodes=[0, 1, 2]]]

这是因为算法找到了相同的三角形6次。