1. 程式人生 > 實用技巧 >LRU演算法的實現

LRU演算法的實現

緣由:看到redis的快取淘汰機制,便自己實現了一下

程式碼實現(雙向連結串列+HashMap)

package com.jarjune.jdalao.framework.algorithm;

import java.util.*;

/**
 * LRU
 * @author jarjune
 * @version 1.0.1
 * @date 2020/11/19
 */
public class LRUCache<K, V> {

    // 快取Node
    private Map<K, Node<K, V>> cache;

    // 雙向連結串列首結點
    private Node<K, V> first;

    // 雙向連結串列尾結點
    private Node<K, V> last;

    // 最大快取容量
    private int capacity;

    public LRUCache(int capacity) throws Exception {
        if(capacity < 2) {
            throw new Exception("capacity小於2就沒啥意義了...");
        }
        this.cache = new HashMap<>((int) (capacity / 0.75f + 1));
        this.capacity = capacity;
    }

    private class Node<K, V> {
        K k;
        V v;
        Node<K, V> prev;
        Node<K, V> next;

        Node(K k, V v) {
            this.k = k;
            this.v = v;
        }

        @Override
        public String toString() {
            return "Node{" +
                    "k=" + k +
                    ", v=" + v +
                    '}';
        }
    }

    public int size() {
        return cache.size();
    }

    public void put(K k, V v) {

        Node<K, V> node = cache.get(k);
        if(null == node) {
            node = new Node<>(k, v);

            // 大於等於capacity容量最大值時
            if(cache.size() >= capacity) {

                if(null != last) {
                    // 移除最後一個元素的快取
                    cache.remove(last.k);

                    last = last.prev;
                    if(null == last) {
                        first = null;
                    } else {
                        last.next = null;
                    }
                }
            }
            cache.put(k, node);
        } else {
            node.v = v;
        }

        moveToFirst(node);
    }

    /**
     *  1(first)
     * ↑  ↓
     *  2(node)
     * ↑  ↓
     *  3
     * ↑  ↓
     *  4(last)
     */
    private void moveToFirst(Node<K, V> node) {

        if(first == null || last == null) {
            first = last = node;
            return;
        }

        // 如果是頭結點就結束
        if(node == first) {
            return;
        }

        // 如果是尾結點,尾結點就等於當前結點的上一個結點
        if(node == last) {
            last = node.prev;
        }

        if(null != node.next) {
            node.next.prev = node.prev;
        }

        if(null != node.prev) {
            node.prev.next = node.next;
        }

        node.next = first;
        first.prev = node;
        node.prev = null;
        first = node;
    }

    class LRUIterable implements Iterable<Node<K, V>> {

        @Override
        public Iterator<Node<K, V>> iterator() {
            return new Iterator<Node<K, V>>() {

                private Node<K, V> node = first;

                @Override
                public boolean hasNext() {
                    return node != null;
                }

                @Override
                public Node<K, V> next() {
                    Node<K, V> tmp = node;
                    node = node.next;
                    return tmp;
                }
            };
        }
    }

    public Iterator<Node<K, V>> iterator() {
        return new LRUIterable().iterator();
    }

    public Set<K> keySet() {
        Iterator<Node<K, V>> iterator = iterator();
        Set<K> keys = new LinkedHashSet<>();
        while(iterator.hasNext()) {
            keys.add(iterator.next().k);
        }
        return keys;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        for (Node<K, V> node: new LRUIterable()) {
            sb.append(node);
        }
        return sb.toString();
    }
}

搞定