JAVA数据结构 DAY11-Set和Map

本系列可作为JAVA学习系列的笔记,文中提到的一些练习的代码,小编会将代码复制下来,大家复制下来就可以练习了,方便大家学习。

点赞关注不迷路!您的点赞、关注和收藏是对小编最大的支持和鼓励! 

系列文章目录

JAVA初阶---------已更完

JAVA数据结构 DAY1-集合和时空复杂度

JAVA数据结构 DAY2-包装类和泛型

JAVA数据结构 DAY3-List接口

JAVA数据结构 DAY4-ArrayList

JAVA数据结构 DAY5-LinkedList

JAVA数据结构 DAY6-栈和队列

JAVA数据结构 DAY7-二叉树

JAVA数据结构 DAY8-堆

JAVA数据结构 DAY9 equals、Comparable、Comparator 与 PriorityQueue 深度解析

JAVA数据结构 DAY10-排序

JAVA数据结构 DAY11-Set和Map


拓展目录

手把手教你用 ArrayList 实现杨辉三角:从逻辑推导到每行代码详解

链表高频 6 题精讲 | 从入门到熟练掌握链表操作

二叉树高频题精讲 | 从入门到熟练掌握二叉树操作

二叉树高频题精讲 | 从入门到熟练掌握二叉树操作2

二叉树高频题精讲 | 从入门到熟练掌握二叉树操作3

Java 中的 hashCode () 与 equals () 核心原理、契约规范、重写实践与面试全解

Set&Map高频题精讲 | 从入门到熟练掌握


目录

目录

系列文章目录

拓展目录

目录

前言

一、前置基础:二叉搜索树(BST)

1.1 二叉搜索树的核心性质

1.2 核心操作:查找、插入、删除

(1)查找

(2)插入

(3)删除(难点)

1.3 性能与问题

1.4 二叉搜索树的 Java 简易实现

二、Map 和 Set:动态查找的核心容器

2.1 两种核心模型

2.2 整体体系结构

三、Map 接口:Key-Value 键值对映射

3.1 核心内部类:Map.Entry

3.2 Map 的常用 API

3.3 TreeMap 与 HashMap 的核心区别

3.4 TreeMap 实战示例

四、Set 接口:纯 Key 的唯一集合

4.1 Set 的常用 API

4.2 TreeSet 与 HashSet 的核心区别

4.3 TreeSet 实战示例

五、HashMap/HashSet 底层:哈希表(散列表)

5.1 哈希表的核心概念

5.2 哈希冲突:不可避免的问题

(1)冲突定义

(2)冲突的必然性

5.3 降低冲突率:哈希函数设计 + 负载因子调节

(1)哈希函数设计原则

(2)常用哈希函数

(3)负载因子调节(重点)

① 负载因子定义

② 负载因子与冲突率的关系

③ Java 中的负载因子

5.4 解决哈希冲突:闭散列 vs 开散列

(1)闭散列(开放定址法)

(2)开散列(哈希桶 / 链地址法)【Java 采用】

① 核心思想

② 实现流程

③ 核心优势

④ 冲突严重的解决

5.5 哈希表的 Java 简易实现(哈希桶)

5.6 哈希表的性能分析

5.7 Java 中哈希表的核心注意事项

六、Map/Set 的核心总结与应用场景

6.1 核心总结

6.2 典型应用场景

6.3 经典 OJ 练习

七、总结

总结


前言

小编作为新晋码农一枚,会定期整理一些写的比较好的代码,作为自己的学习笔记,会试着做一下批注和补充,如转载或者参考他人文献会标明出处,非商用,如有侵权会删改!欢迎大家斧正和讨论!

在 Java 集合框架中,Map 和 Set 是处理动态查找场景的核心容器,与传统的数组、链表不同,它们针对高效搜索、插入、删除做了专门优化,底层分别基于红黑树哈希表实现,对应 TreeMap/TreeSet、HashMap/HashSet 两大核心系列。本文将从基础的二叉搜索树出发,逐步拆解 Map 和 Set 的设计思想、底层原理、常用 API 及实际应用,帮你彻底掌握这一核心知识点。

一、前置基础:二叉搜索树(BST)

TreeMap 和 TreeSet 的底层是红黑树(近似平衡的二叉搜索树),因此理解二叉搜索树是掌握这两个集合的前提。

1.1 二叉搜索树的核心性质

二叉搜索树(又称二叉排序树)满足:

  • 左子树所有节点值小于根节点值;
  • 右子树所有节点值大于根节点值;
  • 左右子树也分别为二叉搜索树;
  • 树中节点的 key 唯一,无重复。

1.2 核心操作:查找、插入、删除

(1)查找

从根节点开始,若目标 key 等于根节点 key 则找到;若小于则遍历左子树,大于则遍历右子树,直到节点为空(未找到)。时间复杂度:最优 O (log₂N)(完全二叉树),最差 O (N)(单支树)。

(2)插入
  1. 树为空时,直接将新节点作为根节点;
  2. 树非空时,按查找逻辑找到插入位置(父节点),若 key 已存在则插入失败,否则根据 key 大小插入到父节点的左 / 右子节点。
(3)删除(难点)

设待删除节点为cur,其父节点为parent,分三种情况处理:

  1. cur 左子树为空:直接将 cur 的右子树接在 parent 的对应位置(cur 为根则根更新为 cur.right);
  2. cur 右子树为空:直接将 cur 的左子树接在 parent 的对应位置(cur 为根则根更新为 cur.left);
  3. cur 左右子树均存在:采用替换法,在 cur 的右子树中找中序第一个节点(key 最小),用其值覆盖 cur,再删除该最小节点。

1.3 性能与问题

  • 最优情况(完全二叉树):平均查找长度 O (log₂N);
  • 最差情况(单支树):退化为链表,平均查找长度 O (N/2);
  • 核心问题:插入次序会导致树的结构失衡,性能骤降。红黑树通过颜色标记 + 旋转规则解决了这一问题,保证树的高度始终为 O (log₂N),是 TreeMap/TreeSet 的底层实现。

1.4 二叉搜索树的 Java 简易实现

public class BinarySearchTree {
    public static class Node {
        int key;
        Node left;
        Node right;
        public Node(int key) {
            this.key = key;
        }
    }

    private Node root = null;

    // 查找
    public Node search(int key) {
        Node cur = root;
        while (cur != null) {
            if (key == cur.key) return cur;
            else if (key < cur.key) cur = cur.left;
            else cur = cur.right;
        }
        return null;
    }

    // 插入
    public boolean insert(int key) {
        if (root == null) {
            root = new Node(key);
            return true;
        }
        Node cur = root;
        Node parent = null;
        while (cur != null) {
            if (key == cur.key) return false;
            else if (key < cur.key) {
                parent = cur;
                cur = cur.left;
            } else {
                parent = cur;
                cur = cur.right;
            }
        }
        Node node = new Node(key);
        if (key < parent.key) parent.left = node;
        else parent.right = node;
        return true;
    }

    // 删除(需补充具体逻辑)
    public boolean remove(int key) {
        Node cur = root;
        Node parent = null;
        while (cur != null) {
            if (key == cur.key) break;
            else if (key < cur.key) {
                parent = cur;
                cur = cur.left;
            } else {
                parent = cur;
                cur = cur.right;
            }
        }
        if (cur == null) return false;
        // 补充三种删除情况的逻辑
        return true;
    }
}

二、Map 和 Set:动态查找的核心容器

Map 和 Set 是为动态查找设计的集合(支持随时插入、删除、查找),区别于静态查找的二分查找(要求序列有序,不适合频繁修改),适用于 “通讯录查询”“单词去重”“键值对映射” 等场景。

2.1 两种核心模型

Map 和 Set 的设计基于两种数据模型,也是二者的核心区别:

  1. 纯 Key 模型(Set):仅存储唯一的 Key,核心功能是去重 + 查找,例如 “判断单词是否在词典中”;
  2. Key-Value 模型(Map):存储键值对,Key 唯一,Value 可重复,核心功能是根据 Key 查找 Value,例如 “姓名对应考试成绩”。

2.2 整体体系结构

  • Map:独立接口,不继承 Collection,实现类为 TreeMap(红黑树)、HashMap(哈希表);
  • Set:继承 Collection 接口,底层基于 Map 实现(将 Key 作为 Set 元素,Value 为默认空对象),实现类为 TreeSet(红黑树)、HashSet(哈希表)、LinkedHashSet(哈希表 + 双向链表,保留插入顺序)。

三、Map 接口:Key-Value 键值对映射

Map 是存储<K,V>键值对的接口,Key 唯一且不可直接修改,Value 可重复、可修改,核心实现类为 TreeMap 和 HashMap。

3.1 核心内部类:Map.Entry<K,V>

Map 内部用Map.Entry<K,V>封装单个键值对,提供键值对的获取和修改方法,无设置 Key 的方法(Key 不可直接修改):

方法解释
K getKey()返回当前 Entry 的 Key
V getValue()返回当前 Entry 的 Value
V setValue(V value)修改当前 Entry 的 Value,返回旧值

3.2 Map 的常用 API

Map 的核心方法围绕 Key 的增删改查和键值对遍历展开,所有方法均为接口方法,由实现类实现:

方法解释
V get(Object key)根据 Key 获取 Value,Key 不存在返回 null
V getOrDefault(Object key, V defaultValue)根据 Key 获取 Value,Key 不存在返回默认值
V put(K key, V value)插入 / 修改键值对:Key 不存在则插入,返回 null;Key 存在则修改 Value,返回旧值
V remove(Object key)删除 Key 对应的键值对,返回该 Key 的 Value
Set<K> keySet()返回所有 Key 的 Set 集合(Key 唯一)
Collection<V> values()返回所有 Value 的 Collection 集合(Value 可重复)
Set<Map.Entry<K,V>> entrySet()返回所有键值对的 Set 集合,用于遍历
boolean containsKey(Object key)判断是否包含指定 Key
boolean containsValue(Object value)判断是否包含指定 Value

3.3 TreeMap 与 HashMap 的核心区别

TreeMap 基于红黑树实现,HashMap 基于哈希表实现,二者特性差异显著,决定了各自的应用场景:

特性TreeMapHashMap
底层结构红黑树哈希桶(数组 + 链表 / 红黑树)
时间复杂度插入 / 删除 / 查找均为 O (log₂N)插入 / 删除 / 查找均为 O (1)(理想情况)
Key 是否有序按 Key 的自然顺序 / 自定义比较器排序无序(JDK8 后为插入顺序,非排序)
空值支持Key 不可为 null,Value 可为 nullKey 和 Value 均可为 null
核心要求Key 必须实现 Comparable 接口或自定义比较器,否则抛 ClassCastException自定义类型 Key 必须覆写 equals () 和 hashCode ()
核心区别基于比较器实现元素排序和查找基于哈希函数计算地址,实现快速查找
应用场景需按 Key 有序遍历的场景无需 Key 有序,追求极致查找性能的场景

3.4 TreeMap 实战示例

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

public class TreeMapTest {
    public static void main(String[] args) {
        Map<String, String> heroMap = new TreeMap<>();
        // 插入键值对
        heroMap.put("林冲", "豹子头");
        heroMap.put("鲁智深", "花和尚");
        heroMap.put("武松", "行者");
        heroMap.put("李逵", "黑旋风");
        System.out.println("集合大小:" + heroMap.size()); // 4
        System.out.println("原始集合:" + heroMap); // 按Key自然排序

        // 修改Value
        String oldValue = heroMap.put("李逵", "铁牛");
        System.out.println("李逵旧绰号:" + oldValue); // 黑旋风

        // 获取Value
        System.out.println(heroMap.get("鲁智深")); // 花和尚
        System.out.println(heroMap.getOrDefault("史进", "九纹龙")); // 九纹龙

        // 判断包含
        System.out.println(heroMap.containsKey("林冲")); // true
        System.out.println(heroMap.containsValue("九纹龙")); // false

        // 遍历Key
        for (String key : heroMap.keySet()) {
            System.out.print(key + " ");
        }
        System.out.println();

        // 遍历Value
        for (String value : heroMap.values()) {
            System.out.print(value + " ");
        }
        System.out.println();

        // 遍历键值对(推荐)
        for (Map.Entry<String, String> entry : heroMap.entrySet()) {
            System.out.println(entry.getKey() + "---->" + entry.getValue());
        }
    }
}

四、Set 接口:纯 Key 的唯一集合

Set 继承自 Collection 接口,仅存储唯一的 Key,核心功能是去重查找,底层基于 Map 实现(将 Key 作为 Set 元素,Value 为一个固定的空 Object),核心实现类为 TreeSet 和 HashSet。

4.1 Set 的常用 API

Set 的方法与 Collection 接口基本一致,无新增方法,核心围绕元素的增删改查和去重:

方法解释
boolean add(E e)添加元素,元素已存在则添加失败,返回 false
boolean remove(Object o)删除指定元素,元素不存在则返回 false
boolean contains(Object o)判断集合是否包含指定元素
int size()返回集合元素个数
boolean isEmpty()判断集合是否为空
Iterator<E> iterator()返回迭代器,用于遍历元素
void clear()清空集合
boolean addAll(Collection<? extends E> c)将集合 c 的元素添加到 Set 中,实现去重

4.2 TreeSet 与 HashSet 的核心区别

与 TreeMap/HashMap 的区别对应,TreeSet 基于红黑树,HashSet 基于哈希表,LinkedHashSet 是 HashSet 的子类,在哈希表基础上维护了双向链表,保留元素的插入顺序

特性TreeSetHashSetLinkedHashSet
底层结构红黑树哈希桶哈希桶 + 双向链表
时间复杂度O(log₂N)O(1)O(1)
Key 是否有序自然排序 / 自定义排序无序按插入顺序排序
空值支持Key 不可为 nullKey 可为 nullKey 可为 null
核心要求Key 需实现 Comparable 接口自定义 Key 需覆写 equals () 和 hashCode ()同 HashSet
应用场景需有序遍历的去重场景无需有序,追求性能的去重场景需保留插入顺序的去重场景

4.3 TreeSet 实战示例

import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;

public class TreeSetTest {
    public static void main(String[] args) {
        Set<String> fruitSet = new TreeSet<>();
        // 添加元素
        fruitSet.add("apple");
        fruitSet.add("orange");
        fruitSet.add("peach");
        fruitSet.add("banana");
        System.out.println("集合大小:" + fruitSet.size()); // 4
        System.out.println("原始集合:" + fruitSet); // 按自然排序

        // 重复添加,返回false
        boolean isAdd = fruitSet.add("apple");
        System.out.println("是否添加成功:" + isAdd); // false

        // 判断包含
        System.out.println(fruitSet.contains("apple")); // true
        System.out.println(fruitSet.contains("watermelon")); // false

        // 删除元素
        fruitSet.remove("apple");
        System.out.println("删除后集合:" + fruitSet); // [banana, orange, peach]

        // 迭代器遍历
        Iterator<String> it = fruitSet.iterator();
        while (it.hasNext()) {
            System.out.print(it.next() + " ");
        }
    }
}

五、HashMap/HashSet 底层:哈希表(散列表)

HashMap 和 HashSet 的底层是哈希表,是实现 O (1) 时间复杂度查找的核心,也是 Java 集合中最常用的容器,其设计围绕哈希函数、冲突解决、负载因子三大核心展开。

5.1 哈希表的核心概念

哈希表的核心思想是:通过哈希函数(hashFunc) 让元素的Key存储位置建立一一映射,实现一次计算直接找到元素,无需比较。

  • 哈希函数:将 Key 转换为哈希表数组下标的函数,例如hash(key) = key % 数组长度
  • 哈希表:根据哈希函数构造的存储结构,底层为数组(哈希桶),每个数组元素对应一个链表 / 红黑树(解决冲突);
  • 核心优势:插入、删除、查找的时间复杂度均为 O (1)(理想情况,无冲突)。

5.2 哈希冲突:不可避免的问题

(1)冲突定义

两个不同的 Key(ki ≠ kj),通过哈希函数计算得到相同的哈希地址(hash(ki) = hash(kj)),该现象称为哈希冲突 / 哈希碰撞,这两个 Key 称为同义词

(2)冲突的必然性

哈希表底层数组的容量是有限的,而待存储的 Key 数量是无限的,根据鸽巢原理,冲突必然发生,我们能做的是降低冲突率

5.3 降低冲突率:哈希函数设计 + 负载因子调节

(1)哈希函数设计原则
  1. 定义域包含所有待存储 Key,值域在0 ~ 数组长度-1之间;
  2. 计算出的地址均匀分布在数组中,减少冲突;
  3. 函数计算简单,提升效率。
(2)常用哈希函数
函数名称实现方式适用场景
直接定制法Hash(Key) = A*Key + B(线性函数)Key 范围小且连续的场景
除留余数法Hash(Key) = Key % p(p 为≤数组长度的质数)最常用,通用场景
平方取中法将 Key 平方后抽取中间几位作为地址未知 Key 分布,Key 位数较少的场景
折叠法将 Key 分割为若干部分,叠加求和后取后几位Key 位数较多的场景
随机数法Hash(Key) = random(Key)Key 长度不固定的场景
数学分析法抽取 Key 中分布均匀的几位作为地址已知 Key 分布的场景(如手机号)

Java 中哈希函数:自定义类型需覆写hashCode()方法,JDK 会对hashCode()的结果进行二次哈希,减少哈希冲突。

(3)负载因子调节(重点)
① 负载因子定义

负载因子α = 填入表中的元素个数 / 哈希表数组长度,是哈希表装满程度的标志。

② 负载因子与冲突率的关系

α越大,哈希表中元素越多,冲突率越高;α越小,元素越少,冲突率越低,但空间利用率也越低。

③ Java 中的负载因子

Java 中 HashMap 的默认负载因子为0.75,当实际负载因子超过 0.75 时,会触发数组扩容(扩容为原长度的 2 倍),通过降低负载因子变相降低冲突率。

注意:开放定址法的负载因子需控制在 0.7~0.8 以下,否则 CPU 缓存不命中率会指数级上升。

5.4 解决哈希冲突:闭散列 vs 开散列

当哈希冲突发生时,有两种核心解决方式,Java 中 HashMap 采用开散列(哈希桶)

(1)闭散列(开放定址法)

当发生冲突时,在哈希表中寻找下一个空位置存放元素,常用两种探测方式:

  1. 线性探测:从冲突位置开始,依次向后查找空位置,例如Hi = (H0 + i) % 数组长度(i=1,2,3...);
    • 缺陷:容易产生数据堆积,冲突位置附近的位置被连续占用,进一步提高冲突率;
    • 删除:不能直接物理删除,需采用伪删除(标记为已删除),否则会影响后续查找。
  2. 二次探测:从冲突位置开始,按平方数查找空位置,例如Hi = (H0 ± i²) % 数组长度(i=1,2,3...);
    • 优势:解决了数据堆积问题,冲突分布更均匀;
    • 要求:数组长度为质数,且负载因子≤0.5,否则可能找不到空位置。

闭散列整体缺陷:空间利用率低,是哈希表的次要解决冲突方式。

(2)开散列(哈希桶 / 链地址法)【Java 采用】
① 核心思想

哈希表底层为数组(哈希桶),每个数组元素对应一个单链表(JDK8 后,当链表长度≥8 且数组长度≥64 时,转为红黑树);发生冲突的 Key,被放入同一个数组元素对应的链表 / 红黑树中。

② 实现流程
  1. 通过哈希函数计算 Key 的哈希地址,得到数组下标;
  2. 若该下标对应的桶为空,直接将元素作为链表头节点存入;
  3. 若该桶已存在元素,将元素添加到链表尾部(JDK8)/ 头部(JDK7);
  4. 查找时,先计算下标,再在对应桶的链表 / 红黑树中查找 Key。
③ 核心优势
  1. 空间利用率高,无需预留大量空位置;
  2. 无数据堆积问题,冲突仅影响单个桶;
  3. 支持物理删除,不影响其他元素查找。
④ 冲突严重的解决

若单个桶的冲突过于严重(链表过长),可将桶的底层结构从链表改为哈希表红黑树,将大集合的搜索问题转化为小集合的搜索问题。

5.5 哈希表的 Java 简易实现(哈希桶)

public class HashBucket {
    // 哈希桶节点:存储Key-Value
    private static class Node {
        private int key;
        private int value;
        Node next;
        public Node(int key, int value) {
            this.key = key;
            this.value = value;
        }
    }

    private Node[] array; // 哈希桶底层数组
    private int size; // 已存储元素个数
    private static final double LOAD_FACTOR = 0.75; // 负载因子阈值

    // 构造方法:初始化数组长度为8
    public HashBucket() {
        array = new Node[8];
        size = 0;
    }

    // 插入/修改键值对
    public int put(int key, int value) {
        int index = key % array.length;
        // 遍历链表,若Key存在则修改Value
        for (Node cur = array[index]; cur != null; cur = cur.next) {
            if (cur.key == key) {
                int oldValue = cur.value;
                cur.value = value;
                return oldValue;
            }
        }
        // Key不存在,头插法插入新节点
        Node node = new Node(key, value);
        node.next = array[index];
        array[index] = node;
        size++;
        // 负载因子超过阈值,扩容
        if (loadFactor() >= LOAD_FACTOR) {
            resize();
        }
        return -1;
    }

    // 扩容:数组长度翻倍,重新哈希所有元素
    private void resize() {
        Node[] newArray = new Node[array.length * 2];
        for (int i = 0; i < array.length; i++) {
            Node cur = array[i];
            while (cur != null) {
                Node next = cur.next; // 保存下一个节点
                // 重新计算哈希地址
                int index = cur.key % newArray.length;
                // 头插法插入新数组
                cur.next = newArray[index];
                newArray[index] = cur;
                cur = next;
            }
        }
        array = newArray; // 替换为新数组
    }

    // 计算当前负载因子
    private double loadFactor() {
        return size * 1.0 / array.length;
    }

    // 根据Key获取Value
    public int get(int key) {
        int index = key % array.length;
        Node cur = array[index];
        while (cur != null) {
            if (cur.key == key) {
                return cur.value;
            }
            cur = cur.next;
        }
        return -1; // Key不存在
    }
}

5.6 哈希表的性能分析

在实际使用中,哈希表的冲突率被控制在较低水平,每个桶的链表 / 红黑树长度为常数,因此:

  • 插入、删除、查找的平均时间复杂度为 O (1);
  • 当冲突严重时(如哈希函数设计不合理),时间复杂度会退化为 O (log₂N)(红黑树)或 O (N)(链表)。

5.7 Java 中哈希表的核心注意事项

自定义类型作为 HashMap 的 Key 或 HashSet 的元素时,必须同时覆写 equals () 和 hashCode () 方法,且满足:

  1. equals () 相等的对象,hashCode () 必须相等:保证相同的对象映射到同一个哈希桶;
  2. hashCode () 相等的对象,equals () 不一定相等:允许哈希冲突,冲突后通过 equals () 判断是否为同一对象。

若仅覆写 equals (),未覆写 hashCode (),会导致相同的对象生成不同的哈希地址,无法正确去重和查找。

六、Map/Set 的核心总结与应用场景

6.1 核心总结

  1. Tree 系列(TreeMap/TreeSet)

    • 底层:红黑树(平衡二叉搜索树);
    • 特性:Key 有序,时间复杂度 O (log₂N),Key 不可为 null(TreeMap/TreeSet);
    • 要求:Key 需实现 Comparable 接口或自定义比较器。
  2. Hash 系列(HashMap/HashSet)

    • 底层:哈希桶(数组 + 链表 / 红黑树);
    • 特性:Key 无序,时间复杂度 O (1),Key/Value 可为 null(HashMap/HashSet);
    • 要求:自定义 Key 需覆写 equals () 和 hashCode ()。
  3. LinkedHashSet

    • 底层:哈希桶 + 双向链表;
    • 特性:保留插入顺序,时间复杂度 O (1),兼具 HashSet 的性能和有序性。

6.2 典型应用场景

场景推荐容器原因
按姓名 / 学号有序查询信息TreeMap/TreeSet需 Key 有序遍历
通讯录快速查询(姓名→电话)HashMap无需有序,追求 O (1) 查找性能
数组 / 集合去重HashSet/LinkedHashSet高效去重,LinkedHashSet 可保留插入顺序
统计单词出现次数HashMap<String, Integer>Key 为单词,Value 为次数,快速统计和查询
缓存系统(Key→数据)HashMap高速存取,符合缓存的性能要求

6.3 经典 OJ 练习

掌握 Map/Set 后,可解决以下经典算法题,巩固知识点:

  1. 只出现一次的数字:利用 HashSet 的去重特性;
  2. 宝石与石头:利用 HashSet 存储宝石,快速判断石头是否为宝石;
  3. 坏键盘打字:利用 HashSet 存储正常按键,筛选坏键;
  4. 前 K 个高频单词:利用 HashMap 统计频率,结合排序 / 堆实现;
  5. 复制带随机指针的链表:利用 HashMap 建立原节点→新节点的映射。

注:这里将会更新一个链接,包含OJ练习的记录和联系网址链接。

七、总结

Map 和 Set 是 Java 集合框架中处理动态查找的核心,其设计分别基于红黑树哈希表两大数据结构,对应 Tree 系列和 Hash 系列,二者各有优劣:

  • 若需要Key 有序,选择 TreeMap/TreeSet,牺牲一点性能换取有序性;
  • 若追求极致性能,无需有序,选择 HashMap/HashSet,是日常开发的首选;
  • 若需要保留插入顺序且高效,选择 LinkedHashSet/LinkedHashMap。

掌握 Map/Set 的关键,不仅要熟记 API,更要理解其底层原理(二叉搜索树、红黑树、哈希表),尤其是哈希表的哈希函数、冲突解决、负载因子,这也是面试的高频考点。只有理解底层,才能在实际开发中选择合适的容器,写出高效、健壮的代码。


总结

以上就是今天要讲的内容,本文简单记录了java数据结构,仅作为一份简单的笔记使用,大家根据注释理解,您的点赞关注收藏就是对小编最大的鼓励!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Yvonne爱编码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值