Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TreeSet doesn't work, what's wrong with the following code?

The following code should print 3 persons, but it actually print 4 persons, why? Person("a", 1) and Person("a", 4) should be treated as the same, but they are not.


import java.util.TreeSet;
public class Person implements Comparable<Person>{
    public Person(String name, int age){
        this.name = name;
        this.age = age;
    }
    public String name;
    public int age;

    @Override
    public int compareTo(Person o) {
        if(this.name.equals(o.name)){
            return 0;
        }else if(this.age <= o.age){
            return -1;
        }else {
            return 1;
        }
    }
    @Override public boolean equals(Object other) {
        return name.equals(((Person)other).name);
    }

    @Override public int hashCode() {
        return age * 31; 
    }
    public static void main(String[] args) {
        TreeSet<Person> persons = new TreeSet<Person>();
        persons.add(new Person("a", 1));
        persons.add(new Person("b", 3));
        persons.add(new Person("c", 2));
        persons.add(new Person("a", 4));//This should be ignored.

        /*Here should print the first 3 persons, but it prints 4 persons*/
        for(Person h: persons){
            System.out.println(h.name + ":" +h.age);
        }
    }
}

Result:
a:1
c:2
b:3
a:4

like image 302
ruchun huang Avatar asked Dec 20 '22 11:12

ruchun huang


1 Answers

The problem is the compareTo method, which performs comparisons based on age, but determines equality based on the Person's name, making it inconsistent with itself.

After inserting the first 3 Persons, the tree looks something like this (forgive the poor ASCII art):

    (c,2)
      |
     /\
 (a,1) (b,3)

Then (a,4) is inserted, it's compared to (c,2) based on the age. The age (4) is bigger than (2), so we go to the right. The next comparison is with (b,3). (a,4) is again bigger, so it's added as a new node to the tree (since there's nothing else to compare to). If instead of adding (a,4) you'd add (a,0), then there would be a comparison with (a,1), and the result would be:

a:1
c:2
b:3
like image 133
Malt Avatar answered Jan 04 '23 16:01

Malt