Kiedyś na uniwersytecie musiałem napisać zadanie sortowania rosnąco nazwisk, które były kluczami do osobistych teczek moich kolegów z klasy, i spędziłem nad tym dużo czasu. Ale gdybym wtedy znał klasę TreeMap , zrobiłbym to znacznie szybciej.

Co to jest TreeMap ? Jest to podobna do słownika struktura danych, która umożliwia przechowywanie elementów jako klucz-wartość przy użyciu sortowania według klucza.

Gdzie i jak można go wykorzystać? Na przykład w tej samej sprawie z kolegami z klasy. Jeśli potrzebuję przechowywać wartości w porządku rosnącym, zamiast pisać własne algorytmy sortowania, wystarczy stworzyć TreeMap i umieścić tam wartości.

W przypadku typów, takich jak Integer i String, używana jest rosnąca kolejność sortowania. Ale jeśli chcesz umieścić swój własny typ w TreeMap , potrzebujesz swojej klasy do implementacji interfejsu Comparable , metody CompareTo() do zaimplementowania w klasie i należy określić, w jaki sposób mają być sortowane wartości tej klasy .

public class Person implements Comparable<Person> {

    private String firstName;
    private String lastName;

    public Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }@Override
    public int compareTo(Person person) {
        return person.getFirstName().compareTo(firstName);
    }

    @Override
    public String toString() {
        return "Person{" +
                "firstName='" + firstName + '\'' +
                ", lastName='" + lastName + '\'' +
                '}';
    }
}

Zaimplementujmy ponownie metodę CompareTo() w celu posortowania wartości w malejącej kolejności alfabetycznej nazwy:

TreeMap map = new TreeMap<Person, String>();

map.put(new Person("AA","BB"), "aa");
map.put(new Person("BB","BB"), "aa");
map.put(new Person("DD","BB"), "aa");
map.put(new Person("CC","BB"), "aa");

Wartości będą przechowywane w następującej kolejności:

Person{firstName='DD', lastName='BB'}
Person{firstName='CC', lastName='BB'}
Person{firstName='BB', lastName='BB'}
Person{firstName='AA', lastName='BB'}

Klasa TreeMap implementuje interfejs NavigableMap , który z kolei rozszerza SortedMap . Dzięki temu klasa TreeMap może przechowywać drzewa i przechowywać wartości w posortowanej kolejności.

Drzewo, jak mówi Wikipedia, jest samobalansującą binarną strukturą wyszukiwania do przechowywania danych, która wykorzystuje węzły do ​​przechowywania, najpierw porównując wartości.

Mówiąc najprościej, czerwono-czarne drzewo to struktura danych, która przechowuje wartości po prawej stronie, które są większe niż korzeń, a po lewej te, które są mniejsze. Implementacja ta pomaga szybko wyszukać wartości w strukturze.

Czerwono-czarne drzewo samo się równoważy, więc przy każdym nowym wstawieniu będzie zmieniać swoją strukturę w miarę dodawania nowych wartości. Pierwiastek jest wartością dodaną jako pierwszą, ale podczas procesu równoważenia pierwiastkiem może stać się inna wartość.

Więc teraz wiesz, czym jest TreeMap i jak działa.

Należy pamiętać, że tylko te, które zaimplementowały interfejs Comparable i zastąpiły metodę CompareTo() , mogą być przechowywane w TreeMap .

Ale co, jeśli użyjemy klas innych firm, które są ładowane z innych bibliotek i nie możemy w nich zaimplementować Comparable ? Na takie przypadki istnieje rozwiązanie: napisz własny Comparator .

Comparator to interfejs, który ma metodę Compare(). Dzięki niemu możemy porównywać obiekty i przechowywać je w TreeMap .

Comparator<Person> comparator = new Comparator<Person>() {

    @Override
    public int compare(Person person1, Person person2) {
        return person1.getFirstName().compareTo(person2.getFirstName());
    }
};


TreeMap map = new TreeMap<Person, String>(comparator);

W tym przykładzie utworzyliśmy niestandardowy Comparator i przekazaliśmy TreeMap do klasy.

Od wersji Java 8 można to zapisać za pomocą wyrażenia lambda:

TreeMap map = new TreeMap<Person, String>((Person person1, Person person2) -> person1.getFirstName().compareTo(person2.getFirstName()));

Oznacza to, że aby przechowywać wartości w TreeMap , musisz określić sposób ich sortowania. Można to zrobić na dwa sposoby: zaimplementuj Comparable lub zaimplementuj swój własny Comparator .

Ale co, jeśli musimy umieścić wartość null w TreeMap jako klucz? HashMap pozwala to zrobić. Ale jak to działa z tą mapą TreeMap ?

TreeMap map = new TreeMap<Person, String>();
map.put (null, "Person");

Uruchamiając ten kod, otrzymujemy błąd:

Wyjątek w wątku „main” java.lang.NullPointerException w java.base/java.util.TreeMap.put(TreeMap.java:561)

Problem polega na tym, że wewnątrz klasy TreeMap wartości są porównywane za pomocą metody CompareTo() . Oczywiście możesz umieścić tam wartość null i skompiluje się, ale w czasie wykonywania pojawi się błąd, ponieważ metoda zostanie wywołana na wartości null i zostanie zgłoszony wyjątek NullPointerException .

Porównanie HashMap i TreeMap

W przeciwieństwie do TreeMap , HashMap może przechowywać wartość null jako klucz. Wszystkie klucze zerowe mają przydzielone określone miejsce w strukturze. Przechowywanie kluczy zerowych w HashMap jest możliwe, ponieważ lokalizacja tutaj jest określana przez wartość skrótu, a do tego nie trzeba porównywać wartości z innymi. Dlatego wszystkie klucze zerowe mają swoje miejsce.

Więc teraz wiesz, czego użyć, gdy musisz przechowywać wartości w posortowanej kolejności oraz jak ustawić reguły i kolejność sortowania.