LinkedHashMap&TreeMap

LinkedHashMap的特性

链接: link.
可以按照put的顺序读取存储的元素。

LinkedHashMap结构

LinkedHashMap继承于HashMap,即所有的节点还是存储到HashMap中,但是与HashMap中的Node节点不同的是,LinkedHashMap中的Entry节点继承于HashMap中的Node节点,而且还新增了Entry before和Entry after,这两个指针。这样LinkedHashMap中所有的节点构成了一个双向的链表。同时在LinkedhashMap中,维护了两个属性Entry head, Entry tail,指向链表的头和尾巴。
同时还维护了一个final boolean accessOrder;如果该字段为true,则调用get方法后,会将该节点放入尾巴。
在这里插入图片描述

维护双向链表

linkedhashmap维护了一个双向链表,这样在对linkedhashmap中的元素进行增加、删除、获取时就要新增额外的操作,维护这个链表。
afterNodeRemoval(Node<K,V> e)方法
当linkedhashmap中删除节点之后,调用该方法,将e从维护的双链表中删除。

/**
 * afterNodeRemoval此方法是将节点e从list中删除,而调用LinkedHashMap的remove方法实际调用的hashMap.remove方法已经将该节点从hashMap的桶中删除。
 * (注意看前面的LinkedHashMap数据结构示意图,有两套指针(双向链表和桶中的单链表),
 * 一套是HashMap中的hash桶内元素连接的黑色指针(即桶中的链表),只要把节点上下关系移除即可
 * 另外一套是有颜色的指针,它是维护list的指针,从hash桶中删除后,还有从list中删除)
 */
void afterNodeRemoval(Node<K,V> e) {
	// 标记节点e、e.before、e.after
    LinkedHashMap.Entry<K,V> p = (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
    
    b<--->p<--->a。p是要删除的节点,b是前驱,a是后一个节点。即在删除时,先将其的前驱和后继定位好。
    
    // 第一步:p的前后置空,选择e已经从链表中移除
    p.before = p.after = null;
    
    // 第二步:判断是否b为null,如果b为null,说明p是头节点,那么删除后,头节点就是a。如果b不为null,那么将b的后继指针指向a。
    if (b == null) //这里一定要注意判断b是空,即p是head的情况。
        head = a;
    else
    	// 否则更新e的前驱.after == e的后继节点
        b.after = a;
    
    // 第三步:将e的后继.before = e的前驱。同理也要考虑a为null即p为尾节点的情况。
    if (a == null)
    	// 如果没删除前e.after后继 == null,说明e处于list的尾部,将tail指向e的前驱节点
        tail = b;
    else
    	// 否则更新e的后继.before  = e的前驱
        a.before = b;
}

afterNodeInsertion方法
在向map中put节点后,会调用该方法。且重写了removeEldestEntry方法后,该方法才生效,该方法会将链表头节点删除。

/**
 * 按照之前的想法,插入一个节点后应该是将插入的节点放入tailde后面,但是这里并不是这样几的
 */
void afterNodeInsertion(boolean evict) { // possibly remove eldest
     LinkedHashMap.Entry<K,V> first;
     // LinkedHashMap中的removeEldestEntry方法永远返回false(方法体见下文),也就说这个本方法不会执行任何操作。。。
     if (evict && (first = head) != null && removeEldestEntry(first)) {
         K key = first.key;
         removeNode(hash(key), key, null, false, true);  //当removeEldestEntry返回为true时,会将第一个元素删除(会将最近被访问的放到链表尾巴,也就是说链表头的元素是最久的被访问的)
     }
}
/**
 * removeEldestEntry方法永远返回false,当重写了该方法后,即返回true时,afterNodeInsertion才有效
 */
protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
    return false;
}

afterNodeAccess方法
当执行linkedhashmap中的get操作或者put操作,即访问(包括修改)元素时候,且当accessOrder==true时,执行该方法,该方法将访问的节点放入末尾。

LinkedHashMap实现LRU

class LRUCache extends LinkedHashMap {

    private int capacity;

    public LRUCache(int capacity) {
        //accessOrder为true
        super(capacity, 0.75F, true);
        this.capacity = capacity;
    }

    public int get(int key) {
        return (int)super.getOrDefault(key, -1);
    }

    public void put(int key, int value) {
        super.put(key, value);
    }

    protected boolean removeEldestEntry(Map.Entry eldest) {
        return size() > capacity;
    }
}

TreeMap

维护了一颗红黑树(自平衡的二叉搜索树),即会对put进来的节点根据key进行排序,放入红黑树的某个位置。
每个节点Node的属性有:

    static final class Entry<K,V> implements Map.Entry<K,V> {
        K key;
        V value;
        Entry<K,V> left;  //左孩子
        Entry<K,V> right;  //右孩子
        Entry<K,V> parent;   //父节点
        boolean color = BLACK;  //该节点的颜色
    	.......
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值