04Java学习之浅尝TreeMap

TreeMap是使用红黑二叉树来实现的,底层实现较麻烦,暂时学会使用,待后续再深入研究。

TreeMap的关键源码:

    private transient Entry<K,V> root;

其中root用来存储整个树的根节点。进入Entry(是TreeMap的内部类)的代码:

/**
 * Node in the Tree.  Doubles as a means to pass key-value pairs back to
 * user (see Map.Entry).
 */

static final class Entry<K,V> implements Map.Entry<K,V> {
    
    
    K key;
    V value;
    Entry<K,V> left;
    Entry<K,V> right;
    Entry<K,V> parent;
    boolean color = BLACK;
    ......
    }

这是树上的一个节点,里面存储了本身数据、左节点、右节点、父节点、以及节点颜色。

TreeMap和HashMap实现了同样的接口Map。HashMap效率高于TreeMap;在需要排序的Map时才选用TreeMap。

HashMap与HashTable的区别

  1. HashMap: 线程不安全,效率高。允许key或value为null。

  2. HashTable: 线程安全,效率低。不允许key或value为null。

下面直接看实现TreeMap的程序:

package myhashmap;

import java.util.Map;
import java.util.TreeMap;

/**
 * 测试TreeMap的使用
 *
 * @author 发达的范
 * @date 2020/11/16 22:17
 */
public class TestTreeMap01 {
    
    
    public static void main(String[] args) {
    
    
        Map<Integer, String> treeMap = new TreeMap<>();
        treeMap.put(15, "唐僧");
        treeMap.put(06, "孙悟空");
        treeMap.put(19, "猪八戒");
        treeMap.put(23, "沙和尚");
        //TreeMap内部自动按照key递增的方式排序
        for (Integer key : treeMap.keySet()) {
    
    
            System.out.println(key + ":" + treeMap.get(key));
        }
    }
}

运行结果:在这里插入图片描述

可见,向TreeMap中put数据时是乱序的,输出是按照V升序排序。排序是TreeMap内部基于红黑二叉树自动实现。回想一下上一节中测试HashMap的程序,并未排序按照输入的顺序输出。

我们知道容器是可以放置包含任何对象的键值对,上面只是实现了放置Integer类型的键,下面测试使用自定义的实现类存入TreeMap中:

package myhashmap;

import java.util.Map;
import java.util.TreeMap;

/**
 * 测试TreeMap的使用
 *
 * @author 发达的范
 * @date 2020/11/17 21:00
 */
public class TestTreeMap02 {
    
    
    public static void main(String[] args) {
    
    
        Map<Student, String> studentTreeMap = new TreeMap<>();
        studentTreeMap.put(new Student(001, "唐三藏", 175), "我是唐三藏");//向TreeMap中put键值对
        studentTreeMap.put(new Student(002, "孙悟空", 170), "我是孙悟空");
        studentTreeMap.put(new Student(003, "猪八戒", 185), "我是猪八戒");
        studentTreeMap.put(new Student(004, "沙和尚", 165), "我是沙和尚");
        studentTreeMap.put(new Student(005, "白龙马", 165), "我是白龙马");
		//使用增强for循环遍历TreeMap
        for (Student key : studentTreeMap.keySet()) {
    
    
            System.out.println(key + ":" + studentTreeMap.get(key));
        }
    }
}

class Student implements Comparable<Student> {
    
    

    int id;
    String name;
    double height;

    public Student(int id, String name, double height) {
    
    
        this.id = id;
        this.name = name;
        this.height = height;
    }

    //实现了Comparable接口,就需要实现Comparable接口的所有方法(只有一个comparaTo方法)
    @Override
    public int compareTo(Student o) {
    
    
        if (this.height > o.height) {
    
    
            return 1;
        } else if (this.height < o.height) {
    
    
            return -1;
        } else {
    
    
            if (this.id > o.id) {
    
    
                return 1;
            } else if (this.id < o.id) {
    
    
                return -1;
            } else {
    
    
                return 0;
            }
        }
    }

    //需要重写toString方法才能正确输出
    @Override
    public String toString() {
    
    
        return "id:" + id + " name:" + name + " height:" + height;
    }
}

运行结果:在这里插入图片描述

从运行结果可以看出,所有对象按照height升序排列,如果height相同就按照id升序排列。

由于TreeMap的底层原理是使用红黑二叉树实现的,我还没有学习,所以对TreeMap的底层实现以及节点的存储方式还不熟悉。下面说一下我对TreeMap的理解:

在这里插入图片描述

红框里面是键值对,我不管你是怎么存储的,你在TreeMap的内存中就是一个整体,只是按照键Integer进行排序的,所以也就有了:

在这里插入图片描述

在这里插入图片描述

红框里面都是键值对,是一个整体,只是现在使用自定义的一个类作为键key(K),TreeMap内部需要在树上进行自动排序,我指定了它的排序规则(重写compareTo()方法)。

猜你喜欢

转载自blog.csdn.net/fada_is_in_the_way/article/details/109756598