打赏
Fork me on GitHub

LRU

LRU是什么

  按照英文的直接原义就是Least Recently Used,最近最久未使用法,它是按照一个非常著名的计算机操作系统基础理论得来的:最近使用的页面数据会在未来一段时期内仍然被使用,已经很久没有使用的页面很有可能在未来较长的一段时间内仍然不会被使用。基于这个思想,会存在一种缓存淘汰机制,每次从内存中找到最久未使用的数据然后置换出来,从而存入新的数据!它的主要衡量指标是使用的时间,附加指标是使用的次数。在计算机中大量使用了这个机制,它的合理性在于优先筛选热点数据,所谓热点数据,就是最近最多使用的数据!因为,利用LRU我们可以解决很多实际开发中的问题,并且很符合业务场景。

利用双向链表实现

  双向链表有一个特点就是它的链表是双路的,我们定义好头节点和尾节点,然后利用先进先出(FIFO),最近被放入的数据会最早被获取。其中主要涉及到添加、访问、修改、删除操作。首先是添加,如果是新元素,直接放在链表头上面,其他的元素顺序往下移动;访问的话,在头节点的可以不用管,如果是在中间位置或者尾巴,就要将数据移动到头节点;修改操作也一样,修改原值之后,再将数据移动到头部;删除的话,直接删除,其他元素顺序移动;

基本的链表操作节点

public class Node {
    //键
    Object key;
    //值
    Object value;
    //上一个节点
    Node pre;
    //下一个节点
    Node next;

    public Node(Object key, Object value) {
        this.key = key;
        this.value = value;
    }
}

 具体的实现

  1 import java.util.HashMap;
  2 
  3 public class LRU<K, V> {
  4     private int currentSize;    //当前的大小
  5     private int capcity;    //总容量
  6     private HashMap<K, Node> caches;    //所有的node节点
  7     private Node first;     //头节点
  8     private Node last;      //尾节点
  9 
 10     public LRU(int size) {
 11         currentSize = 0;
 12         this.capcity = size;
 13         caches = new HashMap<K,Node>(size);
 14     }
 15 
 16     /**
 17      * 放入元素
 18      *
 19      * @param key
 20      * @param value
 21      */
 22     public void put(K key, V value) {
 23         Node node = caches.get(key);
 24         //如果新元素
 25         if (node == null) {
 26             //如果超过元素容纳量
 27             if (caches.size() >= capcity) {
 28                 //移除最后一个节点
 29                 caches.remove(last.key);
 30                 removeLast();
 31             }
 32             //创建新节点
 33             node = new Node(key, value);
 34         }
 35         //已经存在的元素覆盖旧值
 36         node.value = value;
 37         //把元素移动到首部
 38         moveToHead(node);
 39         caches.put(key, node);
 40     }
 41 
 42     /**
 43      * 通过key获取元素
 44      *
 45      * @param key
 46      * @return
 47      */
 48     public Object get(K key) {
 49         Node node = caches.get(key);
 50         if (node == null) {
 51             return null;
 52         }
 53         //把访问的节点移动到首部
 54         moveToHead(node);
 55         return node.value;
 56     }
 57 
 58     /**
 59      * 根据key移除节点
 60      *
 61      * @param key
 62      * @return
 63      */
 64     public Object remove(K key) {
 65         Node node = caches.get(key);
 66         if (node != null) {
 67             if (node.pre != null) {
 68                 node.pre.next = node.next;
 69             }
 70             if (node.next != null) {
 71                 node.next.pre = node.pre;
 72             }
 73             if (node == first) {
 74                 first = node.next;
 75             }
 76             if (node == last) {
 77                 last = node.pre;
 78             }
 79         }
 80         return caches.remove(key);
 81     }
 82 
 83     /**
 84      * 清除所有节点
 85      */
 86     public void clear() {
 87         first = null;
 88         last = null;
 89         caches.clear();
 90     }
 91 
 92     /**
 93      * 把当前节点移动到首部
 94      *
 95      * @param node
 96      */
 97     private void moveToHead(Node node) {
 98         if (first == node) {
 99             return;
100         }
101         if (node.next != null) {
102             node.next.pre = node.pre;
103         }
104         if (node.pre != null) {
105             node.pre.next = node.next;
106         }
107         if (node == last) {
108             last = last.pre;
109         }
110         if (first == null || last == null) {
111             first = last = node;
112             return;
113         }
114         node.next = first;
115         first.pre = node;
116         first = node;
117         first.pre = null;
118     }
119 
120     /**
121      * 移除最后一个节点
122      */
123     private void removeLast() {
124         if (last != null) {
125             last = last.pre;
126             if (last == null) {
127                 first = null;
128             } else {
129                 last.next = null;
130             }
131         }
132     }
133 
134     @Override
135     public String toString() {
136         StringBuilder sb = new StringBuilder();
137         Node node = first;
138         while (node != null) {
139             sb.append(String.format("%s:%s ", node.key, node.value));
140             node = node.next;
141         }
142         return sb.toString();
143     }
144 
145 
146     public static void main(String[] args) {
147         LRU<Integer, String> lru = new LRU<Integer, String>(5);
148         lru.put(1, "a");
149         lru.put(2, "b");
150         lru.put(3, "c");
151         lru.put(4, "d");
152         lru.put(5, "e");
153         System.out.println("原始链表为:" + lru.toString());
154 
155         lru.get(4);
156         System.out.println("获取key为4的元素之后的链表:" + lru.toString());
157 
158         lru.put(6, "f");
159         System.out.println("新添加一个key为6之后的链表:" + lru.toString());
160 
161         lru.remove(3);
162         System.out.println("移除key=3的之后的链表:" + lru.toString());
163     }
164 }
View Code

 

posted @ 2020-10-18 14:37  l-coil  阅读(191)  评论(1编辑  收藏  举报