TreeMap of Java Basics

1. Introduction to TreeMap

TreeMap is a direct implementation class of the NavigableMap interface. Its underlying data structure is a red-black tree structure (and HashMap is a direct implementation class of the Map interface). However, because the NavigableMap interface also indirectly inherits the Map interface, Map has the same characteristics as TreeMap. have. And TreeMap basically has no own characteristics, we can directly think that the characteristics of Map are the characteristics of TreeMap.

Please add a picture description

Map is used to save a data set with a mapping relationship. It has the characteristics of dual-column storage, that is, two elements must be added at a time. Such two elements are called key-value pairs ==><Key,Value>. Among them, the value of Key cannot be repeated (when the value of Key is repeated, the object inserted later will overwrite the previously inserted object with the same Key value, that is, the value of Value will be updated); for different Key values, its Value The value of is repeatable. The same is true for the characteristics of TreeMap.

The <Key, Value> key-value pair is also called Entry or entry in the Java language. Map.Entry is equivalent to Student.name. If the data type of name is String, then the data type of Student.name is String; similarly, if the data type of key in <key,value> is Integer, and the data type of value is String, then the data type of Map.Entry is < Integer, String>. Both HashMap and TreeMap can use Map.Entry to obtain the data type of the key-value pair.

其中在HashMap的方法中可以直接使用HashMap.Entry,但在TreeMap中不可以使用TreeMap.Entry,因为TreeMap.Entry它是私有的,我们无法通过创建TreeMap对象来直接使用TreeMap.Entry,因此TreeMap只能使用Map.Entry。

insert image description here

Next, we will combine the code to learn the relevant knowledge of TreeMap.


1.1 The underlying principle of TreeMap (red-black tree)

Hash table and red-black tree based on Java


Two, the basic operation of TreeMapTreeMap入门

2.1, Value value can be repeated

首先我们来讨论对于不同的Key值,Value的值可重复这一问题
Key data type is Integer type, Value data type is TreeMap of String type

public static void main(String[] args) {
    
    
        //创建一个Key为Integer数据类型,Value为String数据类型的TreeMap对象
        //若要使用TreeMap,则需要导入import java.util.TreeMap;
        TreeMap<Integer,String> treeMap=new TreeMap<>();

        //使用put()方法添加Entry元素
        treeMap.put(18,"xiaoming");//第一对象
        treeMap.put(19,"xiaoming");//第二对象
        treeMap.put(20,"wangwu");//第三对象

        //普通打印
        System.out.println(treeMap);
    }

operation result:From the running results, we found that for different Key values, the Value value can be repeated
insert image description here


2.2. Key value cannot be repeated

接下来我们探讨Key的值不可重复(当Key的值重复的时候,后面插入的对象会将之前插入的具有相同的Key值的对象覆盖掉,即更新Value的值)此问题

Key data type is Integer type, Value data type is TreeMap of String type

Wherein, the Key value of the third object and the fourth object are the same, and the Value value is different.

public static void main(String[] args) {
    
    
        //创建一个Key为Integer数据类型,Value为String数据类型的TreeMap对象
        //若要使用TreeMap,则需要导入import java.util.TreeMap;
        TreeMap<Integer,String> treeMap=new TreeMap<>();

        //使用put()方法添加元素
        treeMap.put(18,"xiaoming");//第一对象
        treeMap.put(19,"xiaoming");//第二对象
        treeMap.put(20,"wangwu");//第三对象
        treeMap.put(20,"lisi");//第四对象

        //普通打印
        System.out.println(treeMap);
    }

operation result:From the running results, we found that the fourth object inserted later overwrote the third object inserted before, that is, the Value value was updated

insert image description here


Three, TreeMap traversalTreeMap基础

TreeMap traversal is divided into calling keySet() method traversal and entrySet() method traversal

3.1, TreeMap calls the keySet() method to traverse

public static void main(String[] args) {
    
    
        //创建一个Key为Integer数据类型,Value为String数据类型的TreeMap对象
        //若要使用TreeMap,则需要导入import java.util.TreeMap;
        TreeMap<Integer,String> treeMap=new TreeMap<>();

        //使用put()方法添加元素
        treeMap.put(18,"xiaoming");//第一对象
        treeMap.put(19,"xiaoming");//第二对象
        treeMap.put(20,"wangwu");//第三对象

        //调用keySet()方法遍历
        //在TreeMap遍历中Key占据着主导地位,可以通过Key值找到对应的Value值
        //调用keySet()方法,Set<>泛型约束应与Key的数据类型一致
        //例如在本代码中,TreeMap<Integer, String>,Key的数据类型为Integer,因此Set<>泛型约束也应当为Integer
        //Set<Integer> set=treeMap.keySet();代码的意思为将TreeMap中所有Key值存入Set集合(18,19,20)
        //那么set即为Key值集合
        Set<Integer> set=treeMap.keySet();
        //使用forEach()语句遍历,Integer为set的数据类型,i为set的复用名(相当于set)
        //那么i就成为了Key值
        for(Integer i:set){
    
    
            //在TreeMap遍历中Key占据着主导地位,可以通过Key值找到对应的Value值
            //接下来我们要根据Key值来查找各个Key值对应的Value值,即treeMap.get(i)来获取key对应的value
            //Value数据类型为String,设置一个String变量str来存储Value
            //treeMap.get(i);代码意思为根据i(Key值)找到相对应的Value值
            String str=treeMap.get(i);
            //打印输出
            System.out.println("Key的值为:"+i+"    "+"Value的值为:"+str);
        }
    }

operation result:

insert image description here


3.2. TreeMap calls entrySet() method to traverse

public static void main(String[] args) {
    
    
        //若要使用TreeMap,我们需要导入import java.util.TreeMap;
        //创建一个Key为Integer数据类型,Value为String数据类型的TreeMap对象
        TreeMap<Integer,String> treeMap=new TreeMap<>();
        //通过put()方法来添加数据
        treeMap.put(18,"xiaoming");
        treeMap.put(19,"xiaoming");
        treeMap.put(20,"wangwu");
        //TreeMap通过调用entrySet()方法遍历
        //这时我们需要导入Map的包:import java.util.Map;和Set的包:import java.util.Set;
        //调用entrySet()方法,Set<>泛型约束应与Map.Entry的数据类型一致,即<Integer, String>
        //<Key,Value>键值对,在Java语言中又被称之为Entry/entry,Map.Entry就相当于Student.name,若name的数据类型为String,则Student.name的数据类型为String,同理若<key,value>中key的数据类型为Integer,value的数据类型为String,则Map.Entry的数据类型为<Integer,String>,在这里就是<Integer, String>。
        //Set<Map.Entry<Integer, String>> set=treeMap.entrySet();代码的意思为将TreeMap中所有(Key,Value)值存入Set集合[(18,"xiaoming"),(19,“xiaoming”),(20,“wangwu”)]
        //那么set即为(Key,Value)值集合
        Set<Map.Entry<Integer,String>> set=treeMap.entrySet();
        //使用forEach()语句遍历,Map.Entry<Integer,String>为set的数据类型,i为set的复用名(相当于set)
        //那么i就成为了(Key,Value)值
        for(Map.Entry<Integer,String> i:set){
    
    
            //打印输出,直接调用getKey()方法得到Key值,直接调用getValue()得到Value值
            System.out.println("Key的值为:"+i.getKey()+"    "+"Value的值为:"+i.getValue());
        }
    }

operation result:

insert image description here


Four, TreeMap collection traverses the classic bug of custom type dataTreeMap经典bug

Requirement: Create a TreeMap collection, the Key key is the student object (Student), and the Value value is the hometown (String).

Requirements: Store three key-value pair elements (Entry), traverse, and sort the traverse by student age, if the age is the same, sort by name.

4.1, TreeMap classic bug recurrence

The original Student class

public class Student {
    
    
    private String name;
    private int age;

    public Student() {
    
    
    }

    public Student(String name, int age) {
    
    
        this.name = name;
        this.age = age;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public int getAge() {
    
    
        return age;
    }

    public void setAge(int age) {
    
    
        this.age = age;
    }

    @Override
    public String toString() {
    
    
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

TreeMap traversal output bug

public static void main(String[] args) {
    
    
        //若要使用TreeMap,我们需要导入import java.util.TreeMap;
        //创建一个TreeMap空参构造器(new TreeMap<>()此即为引用空参构造创建一个对象),同时使用泛型来约束treeMap的数据类型,Key的数据类型为Student,Value的数据类型为String
        TreeMap<Student,String> treeMap=new TreeMap<>();
        //创建Student对象
        Student student=new Student("zhangsan",18);
        Student student1=new Student("lisi",19);
        Student student2=new Student("wangwu",20);
        Student student3=new Student("zhaoliu",18);
        通过put()方法来添加数据
        treeMap.put(student,"北京");
        treeMap.put(student1,"深圳");
        treeMap.put(student2,"上海");
        treeMap.put(student3,"广州");
        //调用keySet方法遍历
        //这时我们需要导入Set的包:import java.util.Set;
        //在TreeMap遍历中Key占据着主导地位,可以通过Key值找到对应的Value值
        //调用keySet()方法,Set<>泛型约束应与Key的数据类型一致
        //例如在本代码中,TreeMap<Student, String>,Key的数据类型为Student,因此Set<>泛型约束也应当为Student
        //Set<Student> set=treeMap.keySet();代码的意思为将treeMap中所有Key值存入Set集合(student,student1,student2,student3)
        //那么set即为Key值集合
        Set<Student> set=treeMap.keySet();
        //使用forEach()语句遍历,Student为set数据类型,i为set的复用名(相当于set)
        //那么i就成为了Key值
        for(Student stu:set){
    
    
            //在TreeMap遍历中Key占据着主导地位,可以通过Key值找到对应的Value值
            //接下来我们要根据Key值来查找各个Key值对应的Value值
            //Value数据类型为String,设置一个String变量来存储Value
            //treeMap.get(i);代码意思为根据i(Key值)找到相对应的Value值
            String str=treeMap.get(stu);
            //打印输出
            System.out.println("Key的值为:"+stu+"    "+"Value的值为:"+str);
        }

    }

operation result:From the running results, we found a bug. The information displayed by the bug is that the Student class does not override the Comparable method.
insert image description here


4.2, TreeMap classic bug solution

When traversing and outputting custom classes in TreeMap or TreeSet, if we want normal output, there are two methods: ① Override the compareTo() method in Comparable in the custom class; ② In the TreeMap constructor in the main method Write anonymous inner class and override compare() method using Comparator comparator.

4.2.1. The custom class overrides the compareTo() method of the Comparable interface

The Student class that overrides the compareTo() method in Comparable

public class Student implements Comparable<Student>{
    
    
    private String name;
    private int age;
    @Override
    public int compareTo(Student o) {
    
    
    	//在这里我们定义排序规则:主要根据age进行排序
    	/**
         * 例如我们首先插入了一个("zhangsan",18),那么毫无疑问它会排在第一位
         * 然后我们插入("lisi",19),那么此时this.age=18;o.getAge()=19,那么("lisi",19)就要插入到("zhangsan",18)之后
         * 随后我们插入("zhaoliu",19),那么它会先于("zhangsan",18).age进行比较,那么("zhaoliu",19)就要插入到("zhangsan",18)后面,之后它再与("lisi",19).age进行比较,age相同,比较name,zhaoliu排在lisi之后
         * 因此最后排序结果为("zhangsan",18),("lisi",19),("zhaoliu",19)
         * */
        int result=this.getAge()-o.getAge();
        //如果两个对象的年龄相同,我们再根据姓名进行排序
        result=result==0?this.getName().compareTo(o.getName()):result;
        return result;
    }
    public Student() {
    
    
    }
    public Student(String name, int age) {
    
    
        this.name = name;
        this.age = age;
    }
    public String getName() {
    
    
        return name;
    }
    public void setName(String name) {
    
    
        this.name = name;
    }
    public int getAge() {
    
    
        return age;
    }
    public void setAge(int age) {
    
    
        this.age = age;
    }
    @Override
    public String toString() {
    
    
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

TreeMap traversal output

public static void main(String[] args) {
    
    
        //若要使用TreeMap,我们需要导入import java.util.TreeMap;
        //创建一个TreeMap空参构造器(new TreeMap<>()此即为引用空参构造创建一个对象),同时使用泛型来约束treeMap的数据类型,Key的数据类型为Student,Value的数据类型为String
        TreeMap<Student,String> treeMap=new TreeMap<>();
        //创建Student对象
        Student student=new Student("zhangsan",18);
        Student student1=new Student("lisi",19);
        Student student2=new Student("wangwu",20);
        Student student3=new Student("zhaoliu",18);
        通过put()方法来添加数据
        treeMap.put(student,"北京");
        treeMap.put(student1,"深圳");
        treeMap.put(student2,"上海");
        treeMap.put(student3,"广州");
        //调用keySet方法遍历
        //这时我们需要导入Set的包:import java.util.Set;
        //在TreeMap遍历中Key占据着主导地位,可以通过Key值找到对应的Value值
        //调用keySet()方法,Set<>泛型约束应与Key的数据类型一致
        //例如在本代码中,TreeMap<Student, String>,Key的数据类型为Student,因此Set<>泛型约束也应当为Student
        //Set<Student> set=treeMap.keySet();代码的意思为将treeMap中所有Key值存入Set集合(student,student1,student2,student3)
        //那么set即为Key值集合
        Set<Student> set=treeMap.keySet();
        //使用forEach()语句遍历,Student为set数据类型,i为set的复用名(相当于set)
        //那么i就成为了Key值
        for(Student stu:set){
    
    
            //在TreeMap遍历中Key占据着主导地位,可以通过Key值找到对应的Value值
            //接下来我们要根据Key值来查找各个Key值对应的Value值
            //Value数据类型为String,设置一个String变量来存储Value
            //treeMap.get(i);代码意思为根据i(Key值)找到相对应的Value值
            String str=treeMap.get(stu);
            //打印输出
            System.out.println("Key的值为:"+stu+"    "+"Value的值为:"+str);
        }
    }

Running result: (successful output!!!)
insert image description here


4.2.2. The TreeMap constructor uses the Comparator comparator to rewrite the compare() method

The original Student class

public class Student{
    
    
    private String name;
    private int age;

    public Student() {
    
    
    }

    public Student(String name, int age) {
    
    
        this.name = name;
        this.age = age;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public int getAge() {
    
    
        return age;
    }

    public void setAge(int age) {
    
    
        this.age = age;
    }

    @Override
    public String toString() {
    
    
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

Write an anonymous inner class in the TreeMap constructor in the main method and override the TreeMap traversal output of the compare() method

public static void main(String[] args) {
    
    
        //若要使用TreeMap,我们需要导入import java.util.TreeMap;
        //编写此匿名内部类,我们需要导入import java.util.Comparator;
        //创建一个TreeMap空参构造器(new TreeMap<>()此即为引用空参构造创建一个对象),同时使用泛型来约束treeMap的数据类型,Key的数据类型为Student,Value的数据类型为String
        TreeMap<Student,String> treeMap=new TreeMap<>(new Comparator<Student>() {
    
    
            @Override
            public int compare(Student o1, Student o2) {
    
    
                //在这里我们定义排序规则:主要根据age进行排序
                /**
                 * 例如我们首先插入了一个("zhangsan",18),那么毫无疑问它会排在第一位
                 * 然后我们插入("lisi",19),那么此时o1.getAge()=18;o2.getAge()=19,那么("lisi",19)就要插入到("zhangsan",18)之后
                 * 随后我们插入("zhaoliu",19),那么它会先于("zhangsan",18).getAge()进行比较,那么("zhaoliu",19)就要插入到("zhangsan",18)后面,之后它再与("lisi",19).getAge()进行比较,age相同,比较name,zhaoliu排在lisi之后
                 * 因此最后排序结果为("zhangsan",18),("lisi",19),("zhaoliu",19)
                 * */
                int result=o1.getAge()-o2.getAge();
                //如果两个对象的年龄相同,我们再根据姓名进行排序
                result= result==0 ? o1.getName().compareTo(o2.getName()) : result;
                return result;
            }
        });
        //创建Student对象
        Student student=new Student("zhangsan",18);
        Student student1=new Student("lisi",19);
        Student student2=new Student("wangwu",20);
        Student student3=new Student("zhaoliu",18);
        通过put()方法来添加数据
        treeMap.put(student,"北京");
        treeMap.put(student1,"深圳");
        treeMap.put(student2,"上海");
        treeMap.put(student3,"广州");
        //调用keySet方法遍历
        //这时我们需要导入Set的包:import java.util.Set;
        //在TreeMap遍历中Key占据着主导地位,可以通过Key值找到对应的Value值
        //调用keySet()方法,Set<>泛型约束应与Key的数据类型一致
        //例如在本代码中,TreeMap<Student, String>,Key的数据类型为Student,因此Set<>泛型约束也应当为Student
        //Set<Student> set=treeMap.keySet();代码的意思为将treeMap中所有Key值存入Set集合(student,student1,student2,student3)
        //那么set即为Key值集合
        Set<Student> set=treeMap.keySet();
        //使用forEach()语句遍历,Student为set数据类型,i为set的复用名(相当于set)
        //那么i就成为了Key值
        for(Student stu:set){
    
    
            //在TreeMap遍历中Key占据着主导地位,可以通过Key值找到对应的Value值
            //接下来我们要根据Key值来查找各个Key值对应的Value值
            //Value数据类型为String,设置一个String变量来存储Value
            //treeMap.get(i);代码意思为根据i(Key值)找到相对应的Value值
            String str=treeMap.get(stu);
            //打印输出
            System.out.println("Key的值为:"+stu+"    "+"Value的值为:"+str);
        }

    }

Running result: (successful output!!!)
insert image description here


OK! ! ! TreeMap introduction is over! ! !

Guess you like

Origin blog.csdn.net/qq_45344586/article/details/129727558