数据结构 - LinkedHashMap(二)

1. 基本结构

java 复制代码
public class LinkedHashMap<K,V> extends HashMap<K,V> {
    // 双向链表的头尾节点
    transient LinkedHashMap.Entry<K,V> head;    // 头节点
    transient LinkedHashMap.Entry<K,V> tail;    // 尾节点
    
    // 节点定义
    static class Entry<K,V> extends HashMap.Node<K,V> {
        Entry<K,V> before, after;  // 双向链表的前后指针
        Entry(int hash, K key, V value, Node<K,V> next) {
            super(hash, key, value, next);
        }
    }
}

2. 数据结构图解

graph LR A[HashMap数组] --> B[链表/红黑树] C[双向链表] --> D[按插入顺序] subgraph "HashMap结构" A --> E[桶0] A --> F[桶1] A --> G[桶2] end subgraph "双向链表" H[头节点] --> I[节点1] I --> J[节点2] J --> K[尾节点] K --> J J --> I I --> H end

3. 插入过程

java 复制代码
// 1. 继承自HashMap的put方法
public V put(K key, V value) {
    return putVal(hash(key), key, value, false, true);
}

// 2. 在节点插入后,会调用afterNodeInsertion方法
void afterNodeInsertion(boolean evict) {
    LinkedHashMap.Entry<K,V> first;
    // 维护插入顺序
    if (evict && (first = head) != null) {
        removeEldestEntry(first);
    }
}

4. 实际例子

java 复制代码
LinkedHashMap<String, String> map = new LinkedHashMap<>();

// 1. 插入元素
map.put("A", "1");  // 第一个
map.put("B", "2");  // 第二个
map.put("C", "3");  // 第三个

// 2. 遍历 - 会按插入顺序输出
for (Map.Entry<String, String> entry : map.entrySet()) {
    System.out.println(entry.getKey() + ":" + entry.getValue());
}
// 输出:
// A:1
// B:2
// C:3

5. 两种结构的配合

graph TD A[LinkedHashMap] --> B[HashMap结构] A --> C[双向链表] B --> D[快速查找] C --> E[维护顺序] subgraph "职责分工" D --> F[O1时间复杂度访问] E --> G[记录插入/访问顺序] end

6. 特殊功能

6.1 按访问顺序排序

java 复制代码
// 创建按访问顺序排序的LinkedHashMap
LinkedHashMap<String, String> accessMap = 
    new LinkedHashMap<>(16, 0.75f, true);

accessMap.put("A", "1");
accessMap.put("B", "2");
accessMap.put("C", "3");

accessMap.get("A");  // 访问A
// 现在A会移到最后

// 遍历顺序:B -> C -> A

7. LRU缓存实现

java 复制代码
class LRUCache<K,V> extends LinkedHashMap<K,V> {
    private final int capacity;
    
    public LRUCache(int capacity) {
        super(capacity, 0.75f, true);  // 按访问顺序
        this.capacity = capacity;
    }
    
    @Override
    protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
        return size() > capacity;  // 超过容量则移除最老的
    }
}

8. 实际应用场景

java 复制代码
// 1. 需要记录插入顺序
LinkedHashMap<String, User> userMap = new LinkedHashMap<>();
userMap.put("user1", new User("张三"));
userMap.put("user2", new User("李四"));
// 遍历时保证按插入顺序

// 2. LRU缓存
LRUCache<String, Data> cache = new LRUCache<>(100);
cache.put("key1", data1);
cache.get("key1");  // 访问会更新顺序

9. 性能特点

markdown 复制代码
1. 查找性能:O(1),继承自HashMap
2. 插入性能:O(1),但比HashMap略慢(需要维护链表)
3. 内存消耗:比HashMap大(额外的链表指针)

10. 总结配合方式

  1. HashMap 负责:

    • 存储节点
    • 快速查找
    • 哈希计算
  2. 双向链表负责:

    • 维护顺序
    • 快速插入/删除
    • 迭代顺序

就像是:

  • HashMap是一个仓库(负责存储)
  • 双向链表是一个记录本(负责记录顺序)
  • 两者配合提供了"有序的Map"功能

这种组合让 LinkedHashMap 既拥有了 HashMap 的高效查找,又能维护元素的顺序,是一个非常精妙的设计。

相关推荐
消失的旧时光-19437 分钟前
Kotlin 高阶函数在回调设计中的最佳实践
android·开发语言·kotlin
AI科技星42 分钟前
接近光速运动下的光速不变性:基于张祥前统一场论的推导与验证
数据结构·人工智能·经验分享·算法·计算机视觉
scx201310042 小时前
20251025 分治总结
数据结构·c++·算法
AI智能架构工坊2 小时前
提升AI虚拟健康系统开发效率:架构师推荐10款低代码开发平台
android·人工智能·低代码·ai
百锦再2 小时前
低代码开发的约束性及ABP框架的实践解析
android·开发语言·python·低代码·django·virtualenv·rxjava
那我掉的头发算什么2 小时前
【数据库】navicat的下载以及数据库约束
android·数据库·数据仓库·sql·mysql·数据库开发·数据库架构
while(1){yan}3 小时前
数据结构之堆
数据结构·python·算法
明道源码3 小时前
Android Studio 应用运行到真机设备
android·ide·android studio
生莫甲鲁浪戴3 小时前
Android Studio新手开发第二十五天
android·ide·android studio
Varpb3 小时前
android studio-设置android模拟器屏幕自动旋转
android·android studio