牛客网新手入门130_94-100题_20260120

0 阅读5分钟

【Java 集合实战】从基础到进阶:多重集合 / 缓存 / 队列 / 栈核心知识点总结

最近系统学习了 Java 集合相关的实战场景,涵盖缓存模拟、队列栈实现、有序集合 / 多重集合维护等核心场景,整理了从基础语法到进阶用法的全知识点,适合新手查漏补缺~

一、基础语法:变量 / 方法 / 作用域核心规则

1.1 大小写区分:基本类型 vs 类 / 接口

类型分类命名规则示例核心说明
基本数据类型全小写int/char/booleanJava 底层值类型,直接存储简单数据
类 / 接口大驼峰Stack/TreeSet/TreeMap引用类型,需new创建对象才能使用
包装类首字母大写Integer/Character基本类型的 “类版本”,可存入集合

核心区别

  • 基本类型(小写):像 “螺丝钉”,基础且直接用;
  • 类 / 接口(大写):像 “工具箱”,需组装(new)后使用。

1.2 作用域规则:局部变量 vs 静态成员变量

public class Main {
    // 静态成员变量:整个类的方法都能访问
    private static TreeMap<Integer, Integer> map = new TreeMap<>();
    
    public static void main(String[] args) {
        // 局部变量:仅main方法内可访问,其他方法(如insertValue)无法直接使用
        int num = 10; 
    }
}

易错点:不要在 main 方法内定义需要被其他静态方法访问的变量,需提升为类的静态成员变量。

1.3 循环控制语句:continue vs break

语句核心作用示例场景
continue跳过当前轮循环剩余代码,直接进入下一轮缓存命中时,跳过后续更新逻辑
break终止整个循环,后续轮次不再执行找到目标元素后,终止遍历

示例

// 打印1-5的奇数(用continue跳过偶数)
for (int i = 1; i <= 5; i++) {
    if (i % 2 == 0) continue; // 偶数直接跳过,不执行打印
    System.out.println(i); // 仅打印1/3/5
}

二、集合核心 API:从基础到进阶

2.1 基础集合:Queue/Stack/HashSet

集合类型核心特性常用 API典型场景
Queue(队列)先进先出(FIFO)offer()/poll()/isEmpty()缓存淘汰(最早进入先删)
Stack(栈)后进先出(LIFO)push()/pop()/size()用两个栈实现队列
HashSet无序、元素唯一add()/remove()/contains()快速判断元素是否存在

实战场景:用 Queue+HashSet 模拟缓存

Queue<Integer> cacheQueue = new LinkedList<>(); // 记录缓存顺序
Set<Integer> cacheSet = new HashSet<>(); // 快速判断命中
int missCount = 0; // 缓存未命中次数
// 缓存命中逻辑
if (cacheSet.contains(word)) {
    continue; // 命中则跳过后续逻辑
}
missCount++; // 未命中,次数+1

2.2 有序集合:TreeSet/TreeMap(红黑树底层)

2.2.1 核心优势
  • 有序性:底层红黑树保证元素按大小排序,支持前驱 / 后继查询;
  • 高效性:插入 / 删除 / 查询均为 O (logn),适配 n≤10⁵的大规模数据。
2.2.2 TreeMap 核心 API(多重集合核心)
API 方法作用对应场景
getOrDefault(x, 0)查 x 的值,无则返回默认值 0统计元素重复次数
put(x, value)存入键值对,覆盖已有值更新元素重复次数
lowerKey(x)返回小于 x 的最大键(前驱)找前驱元素
higherKey(x)返回大于 x 的最小键(后继)找后继元素
containsKey(x)判断键 x 是否存在删除元素前的存在性检查

核心语法:map.put(x, map.getOrDefault(x, 0) + 1)

  • 拆解逻辑:
    1. map.getOrDefault(x, 0):查 x 的当前次数,无则返回 0(default= 兜底值);
    1. +1:插入一个 x,次数 + 1;
    1. put(x, ...):将新次数存入 map。
  • 等价手写逻辑(更易理解):
if (map.containsKey(x)) {
    int count = map.get(x);
    map.put(x, count + 1);
} else {
    map.put(x, 1);
}

三、实战场景:完整业务实现

3.1 场景 1:机器翻译缓存模拟

需求:维护固定容量缓存,统计未命中次数(淘汰最早进入的元素)。

核心逻辑

  1. Queue 记录缓存顺序,保证 “先进先出” 淘汰;
  1. HashSet 快速判断缓存命中,避免遍历 Queue;
  1. 缓存满时,删除 Queue 队首元素,同时从 HashSet 移除。

3.2 场景 2:多重集合维护

需求:支持插入重复元素、删除单个元素、查次数、找前驱 / 后继。

核心实现

// 全局变量:TreeMap(键=元素值,值=重复次数)+ 总元素数
private static TreeMap<Integer, Integer> map = new TreeMap<>();
private static int totalSize = 0;
// 1. 插入元素
public static void insertValue(int x) {
    map.put(x, map.getOrDefault(x, 0) + 1);
    totalSize++;
}
// 2. 删除单个元素
public static void eraseValue(int x) {
    if (!map.containsKey(x)) return;
    int count = map.get(x);
    if (count == 1) map.remove(x);
    else map.put(x, count - 1);
    totalSize--;
}
// 3. 找前驱(小于x的最大数)
public static int getPre(int x) {
    Integer preKey = map.lowerKey(x);
    return preKey == null ? -1 : preKey;
}

3.3 场景 3:两个栈实现队列

核心逻辑

  • 栈 1(stack1):负责入队(push),新元素直接压入;
  • 栈 2(stack2):负责出队(pop),为空时将 stack1 元素全部转移过来(反转顺序)。
public int pop() {
    if (stack2.isEmpty()) {
        while (!stack1.isEmpty()) stack2.push(stack1.pop());
    }
    return stack2.pop();
}

四、核心易错点 & 避坑指南

  1. 空指针异常
    • 不要直接用int count = map.get(x),若 x 不存在会返回 null,拆箱报错;
    • 优先用map.getOrDefault(x, 0)兜底。
  1. 集合选择错误
    • 需有序 / 找前驱后继 → 用 TreeSet/TreeMap(红黑树);
    • 仅需快速判重 → 用 HashSet;
    • 需记录顺序 → 用 Queue/LinkedList。
  1. 性能问题
    • 统计总元素数时,用全局变量totalSize,避免遍历 TreeMap 求和;
    • 大规模数据(n≥10⁴)避免用 List 遍历判重(O (n)),优先用 Set(O (1))。

五、知识点关联:底层逻辑

  • 红黑树:TreeSet/TreeMap 的底层实现,自平衡二叉查找树,保证插入 / 查询 / 删除效率为 O (logn);
  • 哈希表:HashSet/HashMap 的底层实现,查询效率 O (1),但无序,无法找前驱 / 后继;
  • LRU 缓存思想:Queue 的 “先进先出” 特性,对应缓存淘汰策略中 “最早进入先淘汰”。

写在最后:Java 集合的核心是 “选对结构 + 用对 API”,新手先掌握每种集合的核心特性和典型场景,再通过实战理解底层逻辑,就能少踩坑、写高效代码~