java數據結構之LinkedHashMap

1、LinkedHashMap源碼註釋java

public class LinkedHashMap<K,V>
    extends HashMap<K,V>
    implements Map<K,V>
    {
    
    /**
     * LinkedHashMap的節點類,在HashMap的節點的基礎上增長了指向前一個節點和後一個節點的屬性,來構成雙向鏈表
     */
    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);
        }
    }
    
    private static final long serialVersionUID = 3801124242820219131L;
    
    /**
     * 雙向鏈表的頭節點(鏈表中最早加入的節點)
     */
    transient LinkedHashMap.Entry<K,V> head;
    
    /**
     * 雙向鏈表的尾節點(鏈表中最後加入的節點)
     */
    transient LinkedHashMap.Entry<K,V> tail;
    
    /**
     * 用來肯定對LinkedHashMap中的節點的迭代順序,
     * 若是accessOrder爲true就是按照訪問順序,若是爲false就按照插入順序
     */
    final boolean accessOrder;
    
    // internal utilities
    
    // 將一個節點加入鏈表尾部
    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;
        }
    }
    
    // 用dst節點替換src節點
    private void transferLinks(LinkedHashMap.Entry<K,V> src,
                               LinkedHashMap.Entry<K,V> dst) {
        LinkedHashMap.Entry<K,V> b = dst.before = src.before;
        LinkedHashMap.Entry<K,V> a = dst.after = src.after;
        if (b == null)
            head = dst;
        else
            b.after = dst;
        if (a == null)
            tail = dst;
        else
            a.before = dst;
    }
    
    // 從新初始化
    void reinitialize() {
        super.reinitialize();
        head = tail = null;
    }
    //建立一個新的節點,並將節點加到雙向鏈表的結尾。這是對hashMap中的newNode方法的覆蓋
    //因此在LinkedHashMap中put方法添加節點的同時會將該節點加到雙向鏈表中
    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;
    }
    
    //建立並返回一個節點,並在雙向鏈表中用新的節點替換舊的節點
    //用在對
    Node<K,V> replacementNode(Node<K,V> p, Node<K,V> next) {
        LinkedHashMap.Entry<K,V> q = (LinkedHashMap.Entry<K,V>)p;
        LinkedHashMap.Entry<K,V> t =
            new LinkedHashMap.Entry<K,V>(q.hash, q.key, q.value, next);
        transferLinks(q, t);
        return t;
    }
    //建立一個樹結點,並添加到雙向鏈表的尾部
    //用於加入將樹節點加入Map中時建立節點
    TreeNode<K,V> newTreeNode(int hash, K key, V value, Node<K,V> next) {
        TreeNode<K,V> p = new TreeNode<K,V>(hash, key, value, next);
        linkNodeLast(p);
        return p;
    }
    //建立並返回一個樹結點,並用該節點替換原來的節點
    TreeNode<K,V> replacementTreeNode(Node<K,V> p, Node<K,V> next) {
        LinkedHashMap.Entry<K,V> q = (LinkedHashMap.Entry<K,V>)p;
        TreeNode<K,V> t = new TreeNode<K,V>(q.hash, q.key, q.value, next);
        transferLinks(q, t);
        return t;
    }
    //若是節點e被移除,那麼就在雙向鏈表中的解除先後接節點的關係
    void afterNodeRemoval(Node<K,V> e) { // unlink
        LinkedHashMap.Entry<K,V> p =
            (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
        p.before = p.after = null;
        if (b == null)
            head = a;
        else
            b.after = a;
        if (a == null)
            tail = b;
        else
            a.before = b;
    }
    //覆蓋HashMap中回調函數,在加入新的節點後調用,若是要實現添加新的節點後剔除最老的節點能夠經過覆蓋這個方法來實現
    //能夠實現LRU緩存策略
    void afterNodeInsertion(boolean evict) { // possibly remove eldest
        LinkedHashMap.Entry<K,V> first;
        if (evict && (first = head) != null && removeEldestEntry(first)) {
            K key = first.key;
            removeNode(hash(key), key, null, false, true);
        }
    }
    //若是accessOrder爲true,在訪問過某個節點以後,將該節點放到最後的位置,至關於做爲最新的節點
    void afterNodeAccess(Node<K,V> e) { // move node to last
        LinkedHashMap.Entry<K,V> last;
        if (accessOrder && (last = tail) != e) {
            LinkedHashMap.Entry<K,V> p =
                (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
            p.after = null;
            if (b == null)
                head = a;
            else
                b.after = a;
            if (a != null)
                a.before = b;
            else
                last = b;
            if (last == null)
                head = p;
            else {
                p.before = last;
                last.after = p;
            }
            tail = p;
            ++modCount;
        }
    }
    //僅從writeObject調用,以確保順序一致。
    void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException {
        for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after) {
            s.writeObject(e.key);
            s.writeObject(e.value);
        }
    }
    
    /**
     * 指定初始容量和加載因子的構造函數,而且指定迭代順序文爲插入順序
     */
    public LinkedHashMap(int initialCapacity, float loadFactor) {
        super(initialCapacity, loadFactor);
        accessOrder = false;
    }
    
    /**
     * 指定初始容量和加載因子0.75的構造函數,而且指定迭代順序文爲插入順序
     */
    public LinkedHashMap(int initialCapacity) {
        super(initialCapacity);
        accessOrder = false;
    }
    
    /**
     * 使用默認初始容量16和加載因子0.75的構造函數,而且指定迭代順序文爲插入順序
     */
    public LinkedHashMap() {
        super();
        accessOrder = false;
    }
    
    /**
     *  使用默認初始容量16和加載因子0.75的構造函數,而且指定迭代順序文爲插入順序
     *  將m中的鍵值對加入新的LinkedHashMap中
     */
    public LinkedHashMap(Map<? extends K, ? extends V> m) {
        super();
        accessOrder = false;
        putMapEntries(m, false);
    }
    
    /**
     * 指定初始容量、加載因子以及迭代順序的構造函數
     */
    public LinkedHashMap(int initialCapacity,
                         float loadFactor,
                         boolean accessOrder) {
        super(initialCapacity, loadFactor);
        this.accessOrder = accessOrder;
    }
    
    
    /**
     * 查詢是否包含value值
     */
    public boolean containsValue(Object value) {
        for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after) {
            V v = e.value;
            if (v == value || (value != null && value.equals(v)))
                return true;
        }
        return false;
    }
    
    /**
     * 經過key來獲取value,若是accessOrder爲true就將該鍵值對放在最後面
     */
    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;
    }
    
    /**
     * 經過key查找值,若是沒有值就返回defaultValue
     */
    public V getOrDefault(Object key, V defaultValue) {
       Node<K,V> e;
       if ((e = getNode(hash(key), key)) == null)
           return defaultValue;
       if (accessOrder)
           afterNodeAccess(e);
       return e.value;
    }
    
    /**
     * 清空整個Map,將頭節點和尾節點都設置爲null
     */
    public void clear() {
        super.clear();
        head = tail = null;
    }
    
    /**
     * 是否容許刪除最老的節點
     * 經過覆蓋這個方法能夠實現第一固定大小的緩存集合,當集合中的元素個數大於多少時刪除最老的元素
     */
    protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
        return false;
    }
    
    /**
     * 返回LinkedHashMap的key的集合視圖
     */
    public Set<K> keySet() {
        Set<K> ks = keySet;
        if (ks == null) {
            ks = new LinkedKeySet();
            keySet = ks;
        }
        return ks;
    }
    //LinkedHashMap key集合視圖,能夠對LinkedHashMap中的key進行迭代
    // LinkedHashMap和LinkedKeySet會相互影響
    final class LinkedKeySet extends AbstractSet<K> {
        public final int size()                 { return size; }
        public final void clear()               { LinkedHashMap.this.clear(); }
        public final Iterator<K> iterator() {
            return new LinkedKeyIterator();
        }
        public final boolean contains(Object o) { return containsKey(o); }
        public final boolean remove(Object key) {
            return removeNode(hash(key), key, null, false, true) != null;
        }
        public final Spliterator<K> spliterator()  {
            return Spliterators.spliterator(this, Spliterator.SIZED |
                                            Spliterator.ORDERED |
                                            Spliterator.DISTINCT);
        }
        public final void forEach(Consumer<? super K> action) {
            if (action == null)
                throw new NullPointerException();
            int mc = modCount;
            for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after)
                action.accept(e.key);
            if (modCount != mc)
                throw new ConcurrentModificationException();
        }
    }
    
    /**
     * LinkedHashMap的value集合視圖,存有LinkedHashMap中的全部value值,
     * Map的值變更會影響到values這個集合中的值
     */
    public Collection<V> values() {
        Collection<V> vs = values;
        if (vs == null) {
            vs = new LinkedValues();
            values = vs;
        }
        return vs;
    }
    //LinkedHashMap的value集合視圖
    final class LinkedValues extends AbstractCollection<V> {
        public final int size()                 { return size; }
        public final void clear()               { LinkedHashMap.this.clear(); }
        public final Iterator<V> iterator() {
            return new LinkedValueIterator();
        }
        public final boolean contains(Object o) { return containsValue(o); }
        public final Spliterator<V> spliterator() {
            return Spliterators.spliterator(this, Spliterator.SIZED |
                                            Spliterator.ORDERED);
        }
        public final void forEach(Consumer<? super V> action) {
            if (action == null)
                throw new NullPointerException();
            int mc = modCount;
            for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after)
                action.accept(e.value);
            if (modCount != mc)
                throw new ConcurrentModificationException();
        }
    }
    
    /**
     * LinkedHashMap鍵值對集合視圖
     * LinkedHashMap和LinkedEntrySet的變更也是會相互影響的
     */
    public Set<Map.Entry<K,V>> entrySet() {
        Set<Map.Entry<K,V>> es;
        return (es = entrySet) == null ? (entrySet = new LinkedEntrySet()) : es;
    }
    
    final class LinkedEntrySet extends AbstractSet<Map.Entry<K,V>> {
        public final int size()                 { return size; }
        public final void clear()               { LinkedHashMap.this.clear(); }
        public final Iterator<Map.Entry<K,V>> iterator() {
            return new LinkedEntryIterator();
        }
        public final boolean contains(Object o) {
            if (!(o instanceof Map.Entry))
                return false;
            Map.Entry<?,?> e = (Map.Entry<?,?>) o;
            Object key = e.getKey();
            Node<K,V> candidate = getNode(hash(key), key);
            return candidate != null && candidate.equals(e);
        }
        public final boolean remove(Object o) {
            if (o instanceof Map.Entry) {
                Map.Entry<?,?> e = (Map.Entry<?,?>) o;
                Object key = e.getKey();
                Object value = e.getValue();
                return removeNode(hash(key), key, value, true, true) != null;
            }
            return false;
        }
        public final Spliterator<Map.Entry<K,V>> spliterator() {
            return Spliterators.spliterator(this, Spliterator.SIZED |
                                            Spliterator.ORDERED |
                                            Spliterator.DISTINCT);
        }
        public final void forEach(Consumer<? super Map.Entry<K,V>> action) {
            if (action == null)
                throw new NullPointerException();
            int mc = modCount;
            for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after)
                action.accept(e);
            if (modCount != mc)
                throw new ConcurrentModificationException();
        }
    }
    
    // 重寫map的方法
    
    //遍歷LinkedHashMap中的鍵值對,而後作相關的操做
    public void forEach(BiConsumer<? super K, ? super V> action) {
        if (action == null)
            throw new NullPointerException();
        int mc = modCount;
        for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after)
            action.accept(e.key, e.value);
        if (modCount != mc)
            throw new ConcurrentModificationException();
    }
    //遍歷LinkedHashMap中的鍵值對,並計算出新的value
    public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
        if (function == null)
            throw new NullPointerException();
        int mc = modCount;
        for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after)
            e.value = function.apply(e.key, e.value);
        if (modCount != mc)
            throw new ConcurrentModificationException();
    }
    
    // Iterators迭代器
    
    abstract class LinkedHashIterator {
        LinkedHashMap.Entry<K,V> next;
        LinkedHashMap.Entry<K,V> current;
        int expectedModCount;
    
        LinkedHashIterator() {
            next = head;
            expectedModCount = modCount;
            current = null;
        }
    
        public final boolean hasNext() {
            return next != null;
        }
    
        final LinkedHashMap.Entry<K,V> nextNode() {
            LinkedHashMap.Entry<K,V> e = next;
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            if (e == null)
                throw new NoSuchElementException();
            current = e;
            next = e.after;
            return e;
        }
    
        public final void remove() {
            Node<K,V> p = current;
            if (p == null)
                throw new IllegalStateException();
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            current = null;
            K key = p.key;
            removeNode(hash(key), key, null, false, false);
            expectedModCount = modCount;
        }
    }
    //key迭代器
    final class LinkedKeyIterator extends LinkedHashIterator
        implements Iterator<K> {
        public final K next() { return nextNode().getKey(); }
    }
    //value迭代器
    final class LinkedValueIterator extends LinkedHashIterator
        implements Iterator<V> {
        public final V next() { return nextNode().value; }
    }
    //鍵值對迭代器
    final class LinkedEntryIterator extends LinkedHashIterator
        implements Iterator<Map.Entry<K,V>> {
        public final Map.Entry<K,V> next() { return nextNode(); }
    }
    

}
View Code

 

2、LinkedHashMap源碼解釋node

  一、LinkedHashMap繼承了HashMap,其方法和HashMap大致上差很少。可是LinkedHashMap是有序的,因此LinkedHashMap的節點在HashMap的基礎上新增了before和after來分別指向前一個節點和後一個節點。在結構上構成雙向鏈表,來實現有序。算法

  二、LinkedHashMap經過accessOrder字段來肯定集合中的節點的排序。若是accessOrder == false 那麼就按照添加的前後順序來進行排序,先加入的排在前面;若是accessOrder == true 那麼就經過訪問的順序來進行排序,最近訪問的排在後面。緩存

  

3、LRU算法及其實現app

  一、 LRU是Least Recently Used的縮寫,即最近最少使用。該算法基於的思想是若是一個數據最近沒有被使用,那它未來被使用到的機率會比最近使用過的數據機率小。這樣咱們在進行緩存的時候在空間不足時就剔除一些較少使用的數據,來達到釋放空間的目的。ide

  二、經過LinkedHashMap中的accessOrder 字段可知,若將構建LinkedHashMap時將該字段設置爲true,那麼其內部將經過訪問順序來進行排序。這樣咱們就能實現LRU算法函數

  三、使用LinkedHashMap來實現LRU算法具體代碼測試

//繼承LinkedHashMap來實現LRU緩存
public class LRULinkedHashMap<K,V> extends LinkedHashMap<K,V>{

    private static final long serialVersionUID = 7164699172329853931L;
    
    //最多緩存的個數
    private int limitCapacity;
    
    public LRULinkedHashMap(){
        this(1024,0.75f);
    }
    //指定緩存個數
    public LRULinkedHashMap(int limitCapacity){
        this(limitCapacity,0.75f);
    }
    
    //指定緩存容量大小和加載因子 
    public LRULinkedHashMap(int limitCapacity, float loadFactor){
        //經過計算獲得容量的大小,以避免發生resize浪費時間和空間
        super((int)Math.ceil(limitCapacity/loadFactor) +1,loadFactor,true);
        this.limitCapacity = limitCapacity;
        
    }

    //只有當前map中的數據大於limitCapacity時才返回true
    protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
        return size() > limitCapacity;
    }
    
}

//測試
public class TestLRU {

    public static void main(String[] args) {
        LRULinkedHashMap<String,Integer> cacheMap = new LRULinkedHashMap<>(3);
        cacheMap.put("1", 1);
        cacheMap.put("2", 2);
        cacheMap.put("3", 3);
        cacheMap.put("4", 4);
        cacheMap.put("5", 6);
        cacheMap.put("1", 2);
        cacheMap.get("4");
        System.out.println(cacheMap);
    }

}
相關文章
相關標籤/搜索