TreeSet与TreeMap

TreeSet

TreeSet 是一个有序集合,它扩展了 AbstractSet 类并实现了 NavigableSet 接口

特点

  • 元素唯一性:它存储唯一的元素,不允许重复值
  • TreeSet不允许null值。
  • TreeSet中的对象必须实现Comparable 接口或者提供自定义的 Comparator
  • TreeMap中不允许键为null,但是值可以为null
  • 无序存储:不保留元素的插入顺序
  • 自动排序:按升序对元素进行排序,对象根据其自然顺序以升序排序和存储。若元素本身没有自然顺序,或者需要自定义排序规则,可以使用 Comparator 来定义排序顺序
  • 底层结构:该实现中使用平衡树,更具体的是红黑树。作为自平衡二叉搜索树,二叉树的每个节点包括一个额外的位,用于识别节点的颜色(红色或黑色)。在随后的插入和删除期间,这些颜色位有助于确保树保持或多或少的平衡
  • TreeSet 的底层数据结构是红黑树,这是一种自平衡的二叉查找树,能够保证插入、删除和查找操作的时间复杂度为 O(log n)
  • 非线程安全:TreeSet 不是线程安全的
  • 支持序列化:实现了 java.io.Serializable 接口,意味着它支持序列化

TreeSet去重机制

  • 如果元素实现了 Comparable 接口,调用 compareTo 方法进行比较
  • 如果提供了 Comparator,调用 compare 方法进行比较
  • 从根节点开始,递归地比较新元素与当前节点的大小
  • 如果比较结果为 0,说明新元素与当前节点相等,不会插入重复元素,如果比较结果不为 0,将新元素插入到合适的位置

构造函数

  1. TreeSet()

    • 构造一个空的树集,该树集将根据元素的自然顺序按升序排序。这就要求元素必须实现 java.lang.Comparable 接口,否则会抛出 ClassCastException 异常

      import java.util.TreeSet;  
       
      public class TreeSetExample { 
          public static void main(String[] args) { 
              // 创建一个使用自然排序的 TreeSet 
              TreeSet<Integer> treeSet = new TreeSet<>(); 
              treeSet.add(3);  
              treeSet.add(1);  
              treeSet.add(2);  
              // 输出结果将按自然顺序排序:[1, 2, 3] 
              System.out.println(treeSet);  
          } 
      } 
      
  2. TreeSet(Comparator<? super E> comparator)

    • 构造一个空的树集,该树集将根据给定的比较器进行排序。当元素没有自然顺序或者需要自定义排序规则时,可以使用这个构造函数

      import java.util.Comparator;  
      import java.util.TreeSet;  
       
      class Person { 
          String name; 
          int age; 
       
          public Person(String name, int age) { 
              this.name  = name; 
              this.age  = age; 
          } 
       
          @Override 
          public String toString() { 
              return "Person{name='" + name + "', age=" + age + "}"; 
          } 
      } 
       
      public class TreeSetComparatorExample { 
          public static void main(String[] args) { 
              // 自定义比较器,按年龄排序 
              Comparator<Person> ageComparator = Comparator.comparingInt(p  -> p.age);  
              TreeSet<Person> treeSet = new TreeSet<>(ageComparator); 
              treeSet.add(new  Person("Alice", 25)); 
              treeSet.add(new  Person("Bob", 20)); 
              treeSet.add(new  Person("Charlie", 30)); 
              // 输出结果将按年龄排序 
              System.out.println(treeSet);  
          } 
      } 
      
  3. TreeSet(Collection<? extends E> c)

    • 构造一个包含指定集合中所有元素的新树集,该树集将根据元素的自然顺序进行排序。同样,集合中的元素必须实现 Comparable 接口

    • 从语法层面来看,只要是实现了 Collection 接口的类的实例都可以作为参数传递给这个构造函数

    • 当使用 TreeSet(Collection<? extends E> c) 构造方法时,会将传入集合中的所有元素插入到 TreeSet 的红黑树结构中 ,TreeSet(Collection<? extends E> c) 会创建一个新的红黑树结构来存储传入集合中的数据

      import java.util.ArrayList;  
      import java.util.Collection;  
      import java.util.TreeSet;  
       
      public class TreeSetCollectionExample { 
          public static void main(String[] args) { 
              // 创建一个 ArrayList 并添加元素 
              Collection<Integer> collection = new ArrayList<>(); 
              collection.add(5);  
              collection.add(3);  
              collection.add(7);  
              // 使用包含集合元素的构造函数创建 TreeSet 
              TreeSet<Integer> treeSet = new TreeSet<>(collection); 
              // 输出结果将按自然顺序排序:[3, 5, 7] 
              System.out.println(treeSet);  
          } 
      } 
      
  4. TreeSet(SortedSet sortedSet)

    • 创建一个包含指定 SortedSet 中所有元素的 TreeSet,并使用 SortedSet 的排序规则
    • sortedSet:包含要添加到 TreeSet 中的元素的有序集合
    • SortedSet的子类有TreeSet、ConcurrentSkipListSet等

TreeMap

TreeMap 是一个有序的 key - value 集合,非同步,基于红黑树(Red - Black Tree)实现,每个 key - value 作为红黑树的一个节点。它继承于 AbstractMap,实现了 NavigableMap、Cloneable 和 java.io.Serializable 接口,意味着它支持一系列的导航方法、能被克隆以及支持序列化

特点

  • 有序性:TreeMap 中的元素是按照键的自然顺序(即实现 Comparable 接口)或通过提供的 Comparator 进行排序的。对于字符串类型的键,自然顺序是按照字典序排序;对于数字类型的键,自然顺序是按照数字大小排序。如果使用自定义的 Comparator,则会按照自定义规则进行排序
  • 红黑树实现:TreeMap 底层基于红黑树实现,红黑树是一种自平衡二叉搜索树。在红黑树中,插入和删除操作的时间复杂度为 O(logn),而查找操作也能在 O(logn) 时间内完成
  • 自动排序:TreeMap 自动根据键的顺序对元素进行排序。插入新元素后,会自动维护元素的顺序
  • 元素唯一:TreeMap 中的键是唯一的,因此相同的键只能存储一个元素。如果在 TreeMap 中插入一个已经存在的键,则新的值会覆盖原有的值
  • TreeMap 不允许存储 null 键,否则会抛出 NullPointerException。但允许值为 null
  • 与 HashMap 类似,TreeMap 也是线程不安全的,如果在多线程环境下使用,需要进行同步处理,例如使用 Collections.synchronizedSortedMap 方法获得一个同步的 TreeMap,或者使用 ConcurrentSkipListMap
  • TreeMap 的基本操作(如 containsKey、get、put 和 remove)的时间复杂度是 O(logn),因此它具有较好的性能表现,适合处理大量的键值对
  • 由于 TreeMap 内部采用红黑树数据结构,需要维护指向父节点、子节点的引用,因此它的内存占用比 HashMap 稍微大一些

常用方法

  • put(K key, V value):用于将一个键值对插入 TreeMap,并维护红黑树的平衡。先从根节点开始,根据键的大小找到插入的位置,比较逻辑通过 Comparator 或键的自然顺序来实现;然后在找到正确的位置后,将新节点插入到红黑树中,并维护其父子关系
  • get(Object key):从根节点开始,通过比较键的大小查找对应的节点。如果找到节点,返回其值;如果未找到,返回 null
  • firstKey():返回 TreeMap 中最小的键
  • lastKey():返回 TreeMap 中最大的键
  • remove(Object key):根据键删除对应的键值对,并维护红黑树的平衡

注意点

TreeMap<Object, Object> map = new TreeMap<>();
map.put(1, "123"); // 添加一个 Integer 类型的键
map.put("2", 123); // 添加一个 String 类型的键
//报错java.lang.ClassCastException
  • 需要注意的是由于TreeSet和TreeMap需要对值进行比较,当插入一个 Integer 类型的键(1)和一个 String 类型的键("2")时,TreeMap 会尝试比较这两个键。由于 Integer 和 String 之间没有自然的比较规则,因此会抛出 ClassCastException
  • 尽量避免在 TreeMap 中使用混合类型的键,因为这会导致代码的可读性和可维护性变差。通常建议使用统一的键类型
posted @   QAQ001  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
点击右上角即可分享
微信分享提示