数据结构与算法 — LRU缓存器实现

利用数据结构和算法实现LRU(least recently used)

为什么使用缓存器LRU?

我的理解,CPU内核中存在多级的缓存机制,L1 cache, L2 cache, L3 cache,以及内存memory。
其中CPU读取缓存区cache数据速度比从内存中读取的速度要快近百倍,因此此时在缓存中进行修改,等全部修改完毕以后再写入内存,比每次都从内存中读取,修改完再往内存中写入的速度要更高。

LRU的算法思想

LRU的字面意思为最近最少使用(Least Recently Used)。
其就是将先访问的数据存放到cache头部位置,将不经常使用的数据存放到cache队尾位置,当cache缓存区满时,同时需要新加入元素的时候,就将区尾元素删除,然后将新数据插入到区头位置。

LRU的实现原理

LRU底层是由HashMap + 双向链表组成。
HashMap可以存放键值对,便于快速的定位到需要修改的节点处。查找某节点的时间复杂度为O(1)。
双向链表可以在任意节点处更改此节点前后节点的数据。
算法实现的重点在于
1. 利用HashMap存储键值对,值代表双向链表中的数据节点,键代表每一个数据节点在map中存储的方式
2. 利用双向链表对节点数据进行排序和存储,先进入的数据排于链表头,当数据数值 = 默认数据总量capacity的时候,每新插入一个数据就要删除一个数据。
LRUCache类
	1. 包含存储Node节点键值对的HashMap
	2. 建立存储Node节点的双向链表(带头节点)
	3. 实现方法put(int key, int value); value是存储在Node的数据,key是此Node节点在map中的键。每次put进来数据就需要新建Node节点以及新建HashMap映射。其次判断cache中容量是否越界
	4. 实现方法get(int key); 利用key值寻找map映射对应的数据。同时将此Node节点移动至cache头部。

代码实现

包1 主文件

public class Main {
    public static void main(String[] args) {
        LRUCache cache = new LRUCache(4);
        cache.put(1, "A"); // butt
        cache.put(2, "B");
        cache.put(3, "C");
        cache.put(4, "D"); // head

        cache.get(1); // A D C B
        cache.put(5, "E"); // E A D C
        cache.get(2); // 无此数据···
    }
}

包2 LRUCache文件

public class LRUCache {
    private final int initCapcity;
    private final Node<String> cache;
    private final HashMap<Integer, Node<String>> map = new HashMap<>();
    public LRUCache(int initCapcity){
        this.initCapcity = initCapcity;
        cache = new Node<String>();
    }
    // 缓存将数据存储到双向链表中,并将节点位置信息存储到hashmap中
    public void put(int key, String  data){
        Node<String> value = new Node<>(data);
        // 如果cache内部超过了能够容纳的数据量则删除LRU元素! -- 链表尾部元素
        if(map.size() == initCapcity){
            Node<String> delNode = cache;
            while (delNode.getNext() != null)
                delNode = delNode.getNext();
            delNode.getPrior().setNext(null);
            delNode.setPrior(null);
            // 此处的map根本没有删除掉元素一开始的Node!
            for(Integer delKey : map.keySet()){
                if(map.get(delKey).equals(delNode)) {
                    map.remove(delKey);
                    break;
                }
            }
        }
        // 添加元素,添置到链表头上
        map.put(key, value);
        // 新元素插入,需要设置四条线!
        value.setPrior(cache);
        value.setNext(cache.getNext());
        if(value.getNext() != null)
            value.getNext().setPrior(value);
        cache.setNext(value);
    }

    // 利用key以及map函数快速得到节点位置信息,获取数据的时候将其设置到存储链表头部
    public void get(int key){
        Node<String> modifyNode = map.get(key);
        if (modifyNode == null){
            System.out.println("没有此数据···");
            return;
        }
        // 修改 此节点需要修改的条数,modify的next 和 prior , 下一个节点的prior 上一个节点的next
        // cache节点的next 以及 原首节点的prior
        if(modifyNode.getNext() != null)
            modifyNode.getNext().setPrior(modifyNode.getPrior());
        modifyNode.getPrior().setNext(modifyNode.getNext());
        modifyNode.setNext(cache.getNext());
        modifyNode.setPrior(cache);
        if(modifyNode.getNext() != null)
            modifyNode.getNext().setPrior(modifyNode);
        cache.setNext(modifyNode);
        System.out.println("数据为:" + modifyNode.getData());
    }
}

包3 基础组件文件

public class Node<T> {
    private T data;
    private Node<T> prior;
    private Node<T> next;
    public Node(T data) {
        this.data = data;
        this.next = null;
    }
    public Node() {
        this.data = null;
        this.next = null;
        this.prior = null;
    }
    public Node(T data, Node<T> prior) {
        this.data = data;
        this.next = null;
        this.prior = prior;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public Node<T> getPrior() {
        return prior;
    }

    public void setPrior(Node<T> prior) {
        this.prior = prior;
    }

    public Node<T> getNext() {
        return next;
    }

    public void setNext(Node<T> next) {
        this.next = next;
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值