Java Comparator doesn't compare each object

user3667111 :

I'm having a few complications with the Java Comparator. So I have a parent node that has a list of children. I want to sort those children, seems pretty simple on the face of it, however when the Comparator does the sorting it only checks certain objects against certain objects, then I suppose it infers the positions of objects, as to say if a is before d, f is after d, b is before d which means b is before f.

Below is an example of my current setup. I have a parent node a with 4 children nodes b, e, l, g. When I sort these children, I would expect the order to be b, g, l, e, so sorting by alphabet and always making sure a parent node comes first.

(Excuse the shoddy drawing)

enter image description here

Very simple, I have a Node class, it contains an ID, so it's letter and then a list of children.

public class Node {

    private char id;
    private Node parent;
    private List<Node> children = new ArrayList<>();


    public Node(char id) {
        this.id = id;
    }

    public void addChild(Node child) {
        this.children.add(child);
    }

    public List<Node> getChildren() {
        return children;
    }

    public char getId() {
        return id;
    }

    public void setParent(Node parent) {
        this.parent = parent;
    }

    public Node getParent() {
        return parent;
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }

    @Override
    public boolean equals(Object obj) {
        return ((Node) obj).getId() == this.id;
    }
}

I then have the NodeComparator class which first checks if the nodes are your children and then if they are you go first, vice versa, then orders by alphabet.

    @Override
    public int compare(Node o1, Node o2) {
        if (o1.getChildren().contains(o2)) {
            return -1;
        }

        if (o2.getChildren().contains(o1)) {
            return 1;
        }

        String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

        int firstNodeIndex = -10;
        int secondNodeIndex = -10;
        for (int i = 0; i < alphabet.length(); i++) {
            if (alphabet.charAt(i) == o1.getId()) {
                firstNodeIndex = i;
            }
            if (alphabet.charAt(i) == o2.getId()) {
                secondNodeIndex = i;
            }
        }
        if (firstNodeIndex > secondNodeIndex) {
            return 1;
        } else if (firstNodeIndex == secondNodeIndex) {
            return 0;
        }else {
            return -1;
        }
    }
}

The issue is that when the sorting is done it checks:

E against B
G against E
L against G

So it never check L against E so it has no way of knowing that should come first.

Eran :

Your ordering violates Comparator's contract:

The implementor must also ensure that the relation is transitive: ((compare(x, y)>0) && (compare(y, z)>0)) implies compare(x, z)>0.

compare('G','E') > 0 // since 'G' comes after 'E' in the alphabet

and

compare('E','L') > 0 // since 'E' is a child of 'L'

but

compare('G','L') < 0 // since 'G' comes before 'L' in the alphabet

Since your Comparator is not a valid Comparator, it is likely to yield either an exception or unexpected results.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=116589&siteId=1