LinkedHashMap 如何实现排序

一、LinkedHashMap

    LinkedHashMap 是 Java 中的一个集合类,它是 HashMap 的一个子类,继承了 HashMap 的所有特性,并且在此基础上增加了一个双向链表来维护元素的插入顺序或者访问顺序。LinkedHashMap 通常用于需要保持插入顺序或者访问顺序的场合。

在这里插入图片描述
    
以下是 LinkedHashMap 的一些特点:

  • 顺序性:可以按照插入顺序或者访问顺序来迭代映射中的元素。
  • 性能:与 HashMap 类似,LinkedHashMap 在大多数情况下也提供了常数时间的性能。
  • 内存消耗:相比于 HashMap,LinkedHashMap 会消耗更多的内存,因为它需要额外的内存来维护双向链表。
  • LinkedHashMap 可以通过构造函数来指定是否按照插入顺序或者访问顺序来迭代:

默认情况下,LinkedHashMap 按照插入顺序来迭代。
如果在构造函数中传入 accessOrder 参数为 true,则按照访问顺序来迭代。
    

二、排序实现

    LinkedHashMap继承自HashMap并添加了一个双向链表来维护元素的插入顺序或访问顺序。以下是LinkedHashMap` 实现排序的原理和方法:

  1. 插入顺序排序:LinkedHashMap 默认按照元素的插入顺序进行排序。当元素被插入到 LinkedHashMap中时,它们会按照插入的顺序排列在双向链表中。即使后续元素的值被更新,它们在链表中的位置也不会改变,除非手动调用 remove 方法或者通过迭代器显式地删除元素。

  2. 访问顺序排序:可以通过在创建 LinkedHashMap实例时设置 accessOrder 参数为 true 来启用访问顺序排序。在这种模式下,每次通过 get 方法访问一个元素时,该元素会被移动到双向链表的末尾,从而保证最近访问的元素在链表的末尾。

  3. 按值排序:如果需要按照值对 LinkedHashMap 进行排序,可以使用 Collections.sort 方法或者 Java 8 引入的 Stream API。例如,可以使用 entrySet().stream().sorted(Map.Entry.comparingByValue()) 来对元素进行排序,然后通过 forEachOrderedcollect 方法将排序后的元素放入一个新的 LinkedHashMap 中。

  4. 自定义排序:如果 LinkedHashMap中的值不实现 Comparable 接口,可以通过提供一个自定义的 Comparator 来实现排序。例如,使用 Map.Entry.comparingByValue(Comparator.comparing(Player::getScore)) 来对包含自定义对象的 LinkedHashMap`进行排序。
        

三、代码片段分析

LinkedHashMap 按照元素的插入顺序进行排序的代码实现主要依赖于其内部的双向链表结构。以下是一些关键的代码片段,展示了 LinkedHashMap 如何维护插入顺序:

  1. 内部类 EntryLinkedHashMap 定义了一个内部类 Entry,继承自 HashMap.Node,并添加了两个新的引用 beforeafter 用于维护双向链表。

    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. 构造方法LinkedHashMap 提供了一个构造方法,允许设置 accessOrder 参数,默认为 false,表示按照插入顺序排序。

    public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) {
        super(initialCapacity, loadFactor);
        this.accessOrder = accessOrder;
    }
    
  3. 插入操作:在 put 方法中,LinkedHashMap 调用 newNode 方法创建新的 Entry,并通过 linkNodeLast 方法将其添加到双向链表的末尾。

    Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {
        LinkedHashMap.Entry<K,V> p = new LinkedHashMap.Entry<K,V>(hash, key, value, e);
        linkNodeLast(p);
        return p;
    }
    
  4. 维护链表linkNodeLast 方法将新节点添加到双向链表的末尾,并更新 headtail 指针。

    private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {
        LinkedHashMap.Entry<K,V> last = tail;
        tail = p;
        if (last == null)
            head = p;
        else {
            p.before = last;
            last.after = p;
        }
    }
    
  5. 迭代顺序LinkedHashMap 重写了 get 方法,在返回值之前,如果 accessOrderfalse(即按照插入顺序),则不需要调整链表。

    public V get(Object key) {
        Node<K,V> e;
        if ((e = getNode(hash(key), key)) == null)
            return null;
        if (accessOrder)
            afterNodeAccess(e);
        return e.value;
    }
    
  6. 迭代器LinkedHashMap 的迭代器会根据双向链表的顺序遍历元素,从而保证了迭代顺序与插入顺序相同。

    通过这些代码实现,LinkedHashMap能够按照元素的插入顺序进行排序。当 accessOrder 设置为 true 时,LinkedHashMap会转变为按照访问顺序排序,这通常是通过 afterNodeAccess 方法实现的,该方法会在访问元素时将其移动到链表的末尾。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值