单向链表设计LRU缓存

LRU是Least Recently Used的缩写,即最近最久未使用,常用于页面置换算法,是为虚拟页式存储管理服务的。常见的实现是将最近访问过的资源【引用】放一个队列,每次将新访问的放在队首,这样最不常用的就被放到队尾,当达到一定数量后,队尾的对象就被清除。缓存的应用场景很多,尤其是高并发的环境中,可以用来控制request数量。现在以一个单项链表为例,解释下如何来实现一个LRU。

新建一个单向链表

public final class Node{
    String key;
    String value;
    Node next;
    public Node(){};

    public void deleteLastNode(Node previous) {
        if(this.next == null) {
            previous.next = this.next;
        }else{
            this.next.deleteLastNode(this);
        }       
    }
}

final修饰类,表示此类不能再被继承。

LRUCache的实现

一个LRU cacheList需要有一个长度和头节点,且需要实现get和set方法。对于set方法,每次添加一个元素的时候,除了将这个元素放在头节点,如果这个元素已经在cacheList里面,那么需要找出来并删除。

public class LRUCache{
    private int size;
    private Node cacheList;
    public LRUCache(int size){
        this.size = size;
    }

    public String get(String key){
        Node currentNode = cacheList;
        if(key.isEmpty()){
            return null;
        }
        while(currentNode.key != null){
            if(currentNode.key == key){
                return currentNode.value;
            }else{
                currentNode = currentNode.next;
            }
        }
        return null;
    }

    public void set(String key, String value){
        if(!key.isEmpty()){
            int count = 0;
            Node newNode = new Node();
            newNode.key = key;
            newNode.value = value;
            newNode.next = cacheList;
            cacheList = newNode;
            while(newNode.next != null){
                if(newNode.next.key == key){
                    newNode.next = newNode.next.next;
                    break;
                }else{
                    count ++;
                    newNode = newNode.next;
                }
            }       
            if(count >= size -1){
            this.cacheList.
            deleteLastNode(this.cacheList);
            }
        }
    }

    private void printkeys() {
        int count = 0;
        Node currentNode = this.cacheList;
        while(currentNode != null){
            System.out.println("Key-Value pair-" + count + ": " + currentNode.key + " " + currentNode.value);
            count ++;
            currentNode = currentNode.next;
        }       
    }
}

现在来测试一下:

public static void main(String[] args){
    LRUCache testcache = new LRUCache(5);
    testcache.set("A", "A-VALUE");
    testcache.set("B", "B-VALUE");
    testcache.set("B", "B-VALUE");
    testcache.set("C", "C-VALUE");
    testcache.set("D", "D-VALUE");
    testcache.set("E", "E-VALUE");
    testcache.set("F", "F-VALUE");
    testcache.printkeys();
}

结果如下:
screenshot

几个难点

  1. 理解链表的复制

    cacheList = newNode;

    cacheList被赋予了newNode的值,cacheList就记下了newNode的当前值,当newNode再次改变时,cacheList不会改变。

  2. 单向链表的节点删除
    巧妙利用this来遍历指定节点。注意,这个方法要定义在Node class里面而不是在LRUCache类中。

    public void deleteLastNode(Node previous) {
        if(this.next == null) {
            previous.next = this.next;
        }else{
            this.next.deleteLastNode(this);
        }       
    }

    另外一种方法可以用来删除任意节点的key:

    public void deleteNode(String key) { 
        if(cacheList.key.equals(key)) { 
            if(cacheList.next != null) {
                cacheList= cacheList.next;
            }else{
                cacheList = null;
            }
        }else {
            cacheList.next.delete(this.cacheList, key);
        }
    }

    在Node类里面就要定义这个方法:

    public void delete(Node previous, String key){
        if(this.key.equals(key)) {
            previous.next = this.next;
        }else {
            if(this.next != null) {
                this.next.delete(this, key);
            }
        }
    }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值