前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >LRU算法的实现

LRU算法的实现

作者头像
用户6055494
发布2019-10-31 17:45:56
5990
发布2019-10-31 17:45:56
举报
文章被收录于专栏:AVAJ

LRU算法全称为Least Recently Used,也就是最近最少使用,操作系统的页面置换算法中就有LRU算法,用来将内存中的页换出,下面我们用JAVA代码来实现这样一个算法,其实在JDK中已经有LinkedHashMap集合来实现LRU算法。本文也是使用链表+HashMap来实现。使用链表来实现如下:

单单使用链表来实现·的话有个很明显的问题就是:获取元素的效率实在太低了,所以在链表的基础上,每次都将链表的节点加入到HashMap中,这样就解决了获取元素效率问题了。

以下为代码:

代码语言:javascript
复制
// LRU算法的实现
public class LRU<K,V> {
    // 集合中元素的个数
    private int currentCacheSize;
    // 集合容量
    private int cacheCapcity;
    // 用HashMap是为了获取更快
    private HashMap<K,Node> caches;
    // 记录头部
    private Node head;
    // 记录尾部
    private Node tail;

    // 构造方法
    public LRU(int size) {
        currentCacheSize = 0;
        cacheCapcity = size;
        caches = new HashMap<K,Node>(size);
    }
    // 增加一个元素
    public void put(K k,V v) {
        // 先获取看看有没有
        Node node = caches.get(k);
        // 没有
        if (node == null) {
            // 看看容量是否满了
            if (caches.size() >= cacheCapcity) {
                // 满了就将最后一个元素移出HashMap集合
                caches.remove(tail.key);
                // 移除map还不够 还要从链表中移除
                removetail();
            }
            // 如果集合还没满,那么就构造这样一个节点
            node = new Node();
            node.key = k;
        }
        // 设置node的值 这里注意:如果集合中存在node 以下操作就是覆盖value
        // 不存在的话就是赋值
        node.value = v;
        // 将这个node放到链表队头
        moveTohead(node);
        // 放入HashMap
        caches.put(k,node);
    }

    public Object get(K k){
        Node node = caches.get(k);
        if (node == null) {
            return null;
        }
        // 获取命中后要放到链表头部去
        moveTohead(node);
        return node.value;
    }

    private void moveTohead(Node node) {
        // 如果是第一个节点 那么就直接返回了
        if (head == node) {
            return;
        }
        // 接下来俩次操作就是为了把该节点移除
        if (node.next != null) {
            node.next.pre = node.pre;
        }
            node.pre.next = node.next;

        if (node == tail) {
            tail = tail.pre;
        }
        // 如果头节点和尾节点都没有设置 那么就设置为当前的节点
        if (head == null || tail == null) {
            head = tail = node;
            return;
        }
        // 将头节点赋值新的节点为头节点
        node.next = head;
        // 先将当前节点放到头节点前面
        head.pre = node;
        // 再将当前节点赋值为头节点
        head = node;
        // 再将头节点的前驱置空
        head.pre = null;
    }

    // 如果满了 那就将最后一个清理掉
    private void removetail() {
        if (tail != null) {
            // 将尾指针向前挪一位
            tail = tail.pre;
            if (tail == null) {
                head = null;
            } else {
                tail.next = null;
            }
        }
    }

    // 清空
    public void clear() {
        // 将指向链表的指针置空
        head = null;
        tail = null;
        // 调用HashMap的清空
        caches.clear();
    }

    class Node{
        Node pre;
        Node next;
        Object key;
        Object value;
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-10-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员面试鸭 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档