0
点赞
收藏
分享

微信扫一扫

什么是LRU缓存淘汰算法?JAVA在链表中使用指针简单实现

孟佳 2022-04-29 阅读 40

什么是LRU缓存淘汰算法?JAVA在链表中使用指针简单实现





什么是LRU缓存淘汰算法?

链表的三种策略

  • 先进先出策略 FIFO(First In,FirstOut)
  • 最少使用策略 LFU(Least Frequently Used)
  • 最近最少使用策略 LRU(LeastRecently Used)

也就是将最近最少使用的数据进行淘汰删除。

我们维护一个有序单链表,越靠近链表尾部的结点是越早之前访问的。当有一个新的数据被访问时,我们从链表头开始顺序遍历链表。

  1. 如果此数据之前已经被缓存在链表中了,我们遍历得到这个数据对应的结点,并将其从原来的位置删除,然后再插入到链表的头部。
  2. 如果此数据没有在缓存链表中,又可以分为两种情况:
    如果此时缓存未满,则将此结点直接插入到链表的头部;
    如果此时缓存已满,则链表尾结点删除,将新的数据结点插入链表的头部。

简单的一个实现

我在本地写了一个具有少量方法的简单实现,没有引入其他的jar,只是使用自定义的就可以完成。
当写一些底层代码的时候,最好不要有任何依赖,用数组,自定义类,引用指向的转换来解决问题,这样可以有效的提高时间效率。

package service.jmw.weekfour;

/**
 * 实现一个 LRU算法 链表
 *
 * @author JMWANG
 */
public class MyLinkedList<T> {

    //最大容量
    private transient static int capacity = 0;

    //真实容量
    private transient static int realTotal = 0;

    // ture 为 主动  (主动扩容的话,会处罚LRU算法标记垃圾 并且清除垃圾)
    // 默认false 被动扩容
    private transient static boolean expansionMode = false;

    //LRU算法删除标记位 从前往后删除
    private transient static int deleteLogo = 0;

    /**
     * 构造方法
     */
    public MyLinkedList(int capacity,boolean expansionMode) {
        this.capacity = capacity;
        this.expansionMode = expansionMode;
    }

    public MyLinkedList(int capacity) {
        this.capacity = capacity;
    }

    public MyLinkedList() {
        this.capacity = 16;
    }

    private static Node node = null;

    /**
     * 添加
     */
    public void add(T t) {
        Node temp = node;
        if (realTotal >= capacity) {
            if (!expansionMode) {
                passiveExpansion();
                while (temp.next != null) {
                    temp = temp.next;
                }
                Node<T> tNode = new Node<T>(null,null,t);
                temp.next = tNode;
            }else {
                //LRU Least Recently Used算法
                for (int j = 0; j < deleteLogo; j++) {
                    temp = temp.next;
                }
                node = temp;
            }
        } else {
            if (node == null) {
                Node<T> tNode = new Node<T>(null,null,t);
                node = tNode;
            } else {
                while (temp.next != null) {
                    temp = temp.next;
                }
                Node<T> tNode = new Node<T>(null,null,t);
                temp.next = tNode;
            }
        }

        realTotal++;
    }

    /**
     * 插入
     */
    public void insert(int i,T t) {
        Node temp = node;
        if (realTotal >= capacity) {
            if (!expansionMode) {
                passiveExpansion();
                int k = 1;
                while (temp.next!=null){
                    if (i == k){
                        Node<T> nodeT = new Node<T>(null,null,t);
                        nodeT.next = temp.next;  //.next
                        temp.next = nodeT;
                        realTotal++;
                        break;
                    }
                    temp = temp.next;
                    k++;
                }
            }else {
                //LRU Least Recently Used算法
                for (int j = 0; j < deleteLogo; j++) {
                    temp = temp.next;
                }
                node = temp;
            }
        } else {
            int k = 1;
            while (temp.next!=null){
                if (i == k){
                    Node<T> nodeT = new Node<T>(null,null,t);
                    nodeT.next = temp.next;  //.next
                    temp.next = nodeT;
                    realTotal++;
                    break;
                }
                temp = temp.next;
                k++;
            }
        }
    }


    /**
     * 删除
     */
    public void delete(T t) {
        Node temp = node;
        if (temp.value.equals(String.valueOf(t))){}else if (realTotal!=0){
            while (temp.next!=null){
                if (temp.next.value.equals(String.valueOf(t))){
                    temp.next = temp.next.next;
                    break;
                }
                temp = temp.next;
            }
        }
        if (expansionMode){
            node = new Node(node,null,t);
            deleteLogo++;
        }else {
            realTotal--;
        }
    }

    /**
     * 查询
     */
    public String get() {

        Node nodeTemp = new Node(null,null,null);
        Object[] ts = new Object[realTotal];
        ts[0] = node.value;
        nodeTemp = node.next;
        //循环处理
        for (int i = 1; i < realTotal; i++) {
            ts[i] = nodeTemp.value;
            nodeTemp = nodeTemp.next;
        }

        Object[] tsTemp = new Object[realTotal-deleteLogo];
        for (int i = deleteLogo,j=0; i < ts.length; i++,j++) {
            tsTemp[j] = ts[i];
        }

        //返回字符串
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < tsTemp.length; i++) {
            if (i == 0 && tsTemp.length == 1) {
                stringBuilder.append("[" + ts[i] + "]");
                break;
            }
            if (i == tsTemp.length - 1) {
                stringBuilder.append(tsTemp[i] + "]");
            } else if (i == 0) {
                stringBuilder.append("[" + tsTemp[i] + ",");
            } else {
                stringBuilder.append(tsTemp[i] + ",");
            }
        }
        return stringBuilder.toString();
    }

    /**
     * 主动扩容 随机数
     */
    public void capacityExpansion(int expansionMultiple) {
        capacity = capacity + expansionMultiple;
    }

    /**
     * 被动扩容 2倍
     */
    public void passiveExpansion() {
        capacity = capacity * 2;
    }

    /**
     * 长度
     */
    public int size(){
        return realTotal;
    }


    static class Node<T> {

        private Node next;
        private Node pri;
        private T value;



        public Node(Node next,Node pri,T value){
            this.next = next;
            this.pri = pri;
            this.value = value;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (!(o instanceof Node)) return false;

            Node<?> node = (Node<?>) o;

            return value != null ? value.equals(node.value) : node.value == null;
        }

        @Override
        public int hashCode() {
            return value != null ? value.hashCode() : 0;
        }

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

    public static void main(String[] args) {

        MyLinkedList linkedList = new MyLinkedList(5);
        linkedList.add("4");
        linkedList.add("5");
        linkedList.add("1");
        linkedList.add("5");
        System.out.println(linkedList.get());
        linkedList.insert(2,"9");
        System.out.println(linkedList.get());
        linkedList.delete(5);
        System.out.println(linkedList.get());
        linkedList.add("100");
        System.out.println(linkedList.get());
        linkedList.add("100");
        System.out.println(linkedList.get());
    }
}

总结

当然这并不是最好的方式,在空间时间等地方可以优化,并且这只是单项的链表,可以在功能上扩展修改为双向,甚至环。
继续优化这个实现思路,比如引入散列表(Hash table)来记录每个数据的位置,将缓存访问的时间复杂度降到 O(1)。






如有错误欢迎指正

举报

相关推荐

0 条评论