LFU的基本原理与实现
解释:上面这个图就是一个LRU的简单实现思路,在链表的开始插入元素,然后每插入一次计数一次,接着按照次数重新排序链表,如果次数相同的话,按照插入时间排序,然后从链表尾部选择淘汰的数据~
二:LRU实现
2.1 定义Node节点
Node主要包含了key和value,因为LFU的主要实现思想是比较访问的次数,如果在次数相同的情况下需要比较节点的时间,越早放入的越快 被淘汰,因此我们需要在Node节点上加入time和count的属性,分别用来记录节点的访问的时间和访问次数。其他的版本实现方式里有新加个内部类来记录 key的count和time,但是我觉得不够方便,还得单独维护一个map,成本有点大。还有一点注意的是这里实现了comparable接口,覆写了compare方法,这里 的主要作用就是在排序的时候需要用到,在compare方法里面我们首先比较节点的访问次数,在访问次数相同的情况下比较节点的访问时间,这里是为了 在排序方法里面通过比较key来选择淘汰的key
/** * 节点 */ public static class Node implements Comparable<Node>{ //键 Object key; //值 Object value; /** * 访问时间 */ long time; /** * 访问次数 */ int count; public Node(Object key, Object value, long time, int count) { this.key = key; this.value = value; this.time = time; this.count = count; } public Object getKey() { return key; } public void setKey(Object key) { this.key = key; } public Object getValue() { return value; } public void setValue(Object value) { this.value = value; } public long getTime() { return time; } public void setTime(long time) { this.time = time; } public int getCount() { return count; } public void setCount(int count) { this.count = count; } @Override public int compareTo(Node o) { int compare = Integer.compare(this.count, o.count); //在数目相同的情况下 比较时间 if (compare==0){ return Long.compare(this.time,o.time); } return compare; } }
2.2:定义LFU类
定义LFU类,这里采用了泛型,声明了K和V,还有总容量和一个Map(caches)用来维护所有的节点。在构造方法里将size传递进去,并且创建了一个LinkedHashMap,采用linkedHashMap的主要原因是维护key的顺序