Java 数据结构详解

Java 数据结构是 Java 编程中存储和组织数据的方式,就像现实生活中 “书架”“抽屉”“字典” 等工具 —— 不同的结构适合存放不同类型的数据,也决定了 “存、取、查” 的效率。Java 内置了一套完善的集合框架(Collection Framework),把常用数据结构封装成了易用的类,我们不需要从零实现,直接拿来用就行。

一、先搞懂:Java 集合框架的 “家谱”

Java 集合框架就像一个大家族,主要分为两大分支:

  • 单值集合(Collection):每个元素是单个值(如数字、字符串),包括 List(有序可重复)、Set(无序不可重复);
  • 键值对集合(Map):每个元素是 “键 - 值” 对(如字典中的 “单词 - 解释”),代表是 Map 接口。

它们的关系可以简单理解为:
集合框架
├─ Collection(单值集合)
│  ├─ List(有序、可重复)
│  │  ├─ ArrayList(数组实现)
│  │  └─ LinkedList(链表实现)
│  └─ Set(无序、不可重复)
│     ├─ HashSet(哈希表实现)
│     └─ TreeSet(红黑树实现,有序)
└─ Map(键值对集合)
   ├─ HashMap(哈希表实现)
   └─ TreeMap(红黑树实现,键有序)
 

二、单值集合(Collection)详解

1. List:有序可重复的 “数组增强版”

List 就像一排有编号的抽屉,每个抽屉有固定位置(索引),可以放相同的东西(可重复)。你可以通过编号快速找到某个抽屉,也可以在任意位置添加 / 删除抽屉。

常用实现类:

  • ArrayList:底层是动态数组(长度可变的数组)。
    • 优点:通过索引(如 get(0))访问元素极快(时间复杂度 O (1));
    • 缺点:在中间插入 / 删除元素慢(需要移动后面的元素,时间复杂度 O (n));
    • 类比:像一本书,查第 100 页很快,但在第 50 页插入一页,后面的页码都要变。
    代码示例:
     
    import java.util.ArrayList;
    import java.util.List;
    
    public class Test {
        public static void main(String[] args) {
            List<String> list = new ArrayList<>();
            // 添加元素
            list.add("苹果");
            list.add("香蕉");
            list.add("苹果"); // 允许重复
            
            // 按索引访问(0 开始)
            System.out.println(list.get(1)); // 输出:香蕉
            
            // 遍历
            for (String fruit : list) {
                System.out.println(fruit); // 输出:苹果、香蕉、苹果(顺序和添加一致)
            }
        }
    }
    
     
  • LinkedList:底层是双向链表(每个元素像 “铁链” 一样连在一起,每个节点记录前后节点的位置)。
    • 优点:在中间插入 / 删除元素快(只需改前后节点的链接,时间复杂度 O (1));
    • 缺点:通过索引访问慢(需要从头遍历到目标位置,时间复杂度 O (n));
    • 类比:像一串项链,拆中间的珠子只需解开两边的线,但要找第 100 颗珠子,得从第一颗开始数。

2. Set:无序不可重复的 “去重神器”

Set 就像一个没有编号的袋子,里面的元素没有固定顺序,且不能有重复(比如 “黑名单” 里不能有重复的名字)。

常用实现类:

  • HashSet:底层是哈希表(通过 “哈希值” 快速定位元素)。
    • 特点:无序(遍历顺序和添加顺序可能不同)、去重(依赖元素的 hashCode() 和 equals() 方法);
    • 优点:添加、删除、查询速度极快(时间复杂度 O (1));
    • 类比:像一本字典,通过拼音首字母(哈希值)快速找到单词,且不会有重复的单词。
    代码示例:
     
    import java.util.HashSet;
    import java.util.Set;
    
    public class Test {
        public static void main(String[] args) {
            Set<String> set = new HashSet<>();
            set.add("苹果");
            set.add("香蕉");
            set.add("苹果"); // 重复元素,会被自动过滤
            
            // 遍历(顺序不确定)
            for (String fruit : set) {
                System.out.println(fruit); // 输出:苹果、香蕉(无重复)
            }
        }
    }
    
     
  • TreeSet:底层是红黑树(一种自平衡的排序树)。
    • 特点:自动按元素大小排序(如数字从小到大、字符串按字典序)、去重;
    • 优点:适合需要 “排序 + 去重” 的场景(如排行榜);
    • 缺点:添加 / 查询速度比 HashSet 稍慢(时间复杂度 O (log n))。

三、键值对集合(Map):像字典一样 “通过键找值”

Map 存储的是 “键(Key)- 值(Value)” 对,就像字典中 “单词(键)- 解释(值)” 的对应关系。键不能重复(一个单词只能有一个解释),但值可以重复(多个单词可以有相同解释)。

常用实现类:

  • HashMap:底层是哈希表(数组 + 链表 / 红黑树)。
    • 特点:键无序、键唯一;
    • 优点:根据键查询值的速度极快(O (1)),适合频繁的 “存、取” 操作;
    • 类比:像手机通讯录,通过姓名(键)快速找到电话(值),姓名不能重复。
    代码示例:
     
    import java.util.HashMap;
    import java.util.Map;
    
    public class Test {
        public static void main(String[] args) {
            Map<String, Integer> scoreMap = new HashMap<>();
            // 存键值对
            scoreMap.put("张三", 90);
            scoreMap.put("李四", 85);
            scoreMap.put("张三", 95); // 键重复,会覆盖之前的值
            
            // 查值(通过键)
            System.out.println(scoreMap.get("李四")); // 输出:85
            
            // 遍历所有键值对
            for (Map.Entry<String, Integer> entry : scoreMap.entrySet()) {
                System.out.println(entry.getKey() + ":" + entry.getValue()); 
                // 输出:张三:95、李四:85(顺序不确定)
            }
        }
    }
    
     
  • TreeMap:底层是红黑树
    • 特点:键会自动按大小排序(如数字键从小到大);
    • 适合场景:需要按键排序的场景(如按学号排序的成绩表)。

四、其他常用数据结构

除了上述核心集合,Java 中还有一些特殊结构:

  • Queue(队列):“先进先出”(FIFO)的结构,像排队买票,先到先得。常用实现 LinkedList(因为链表适合频繁添加 / 删除)。
     
    Queue<String> queue = new LinkedList<>();
    queue.offer("第一个人"); // 入队
    queue.offer("第二个人");
    System.out.println(queue.poll()); // 出队:第一个人(先入先出)
    
     
  • Stack(栈):“后进先出”(LIFO)的结构,像叠盘子,最后放的先拿走。Java 中常用 Deque 替代(LinkedList 实现)。
     
    Deque<String> stack = new LinkedList<>();
    stack.push("第一层盘子"); // 入栈
    stack.push("第二层盘子");
    System.out.println(stack.pop()); // 出栈:第二层盘子(后入先出)
    
     
  • 数组(Array):最基础的线性结构,长度固定,通过索引访问快,但不能动态扩容(ArrayList 是对数组的 “动态扩容” 封装)。

五、如何选择合适的数据结构?

记住几个核心场景:

  1. 有序 + 可重复 + 频繁查:用 ArrayList
  2. 有序 + 可重复 + 频繁增删中间元素:用 LinkedList
  3. 去重 + 无序:用 HashSet
  4. 去重 + 排序:用 TreeSet
  5. 键值对 + 无序:用 HashMap
  6. 键值对 + 键排序:用 TreeMap
  7. 先进先出:用 QueueLinkedList 实现);
  8. 后进先出:用 Deque 当栈(LinkedList 实现)。

总结

Java 数据结构的核心是集合框架,它把复杂的底层实现(数组、链表、哈希表、红黑树等)封装成简单的类,我们只需关注 “用什么结构” 和 “怎么用”。

posted on 2025-08-29 09:10  coding博客  阅读(4)  评论(0)    收藏  举报