读书笔记——漫画算法(8) LRU缓存的实现

LRU,Least Recently Used,最近最少使用;一种资源管理算法

按照字面的意思,也可以理解为缓存淘汰算法:最近最少访问的资源,我们就从缓存中淘汰出去,以免长时间占用内存且不经常访问;

首先,我们定义基础的数据结构:

public class LRUCache {

    // 自定义链表节点
	private static class Node {
        String key;
        String value;
        Node pre;
        Node next;

        Node(String key, String value) {
            this.key = key;
            this.value = value;
        }
    }
	
	// 用于高效访问的HashMap
    private Map<String, Node> map = new HashMap<>();

    // 阈值,限制资源在内存中的数量
    private int limit;
    
    // ------------- 维护一个双向链表
    // 链表头节点
    private Node head;
    // 链表尾节点
    private Node tail;

    public LRUCache(int limit) {
        this.limit = limit;
    }
}

下面我们定义外界访问的基础方法:

// 对外调用的put函数,用来向缓存中存入数据(或者更新)
public void put(String key, String value);

// 外部调用函数,获取以key为键的值
public String get(String key);

// 外部调用的函数,用来移除给定的key节点
public void remove(String key);

下面是方法的实现:

/**
* 对外调用的put函数,用来向缓存中存入数据(或者更新)
* @param key
* @param value
*/
public void put(String key, String value) {
   Node node = map.get(key);
   if(node == null) {
       // 如果节点不存在
       node = new Node(key, value);
       if(map.size() >= limit) {
           // 如果size要超出容量限制了,先移除,再添加
           removeNode(head);
       }
   } else {
       // 如果节点存在,则更新
       node.value = value;
       removeNode(node);
   }
   addNode(node);
}

/**
* 外部调用函数,获取以key为键的值
* @param key
* @return
*/
public String get(String key) {
   Node node = map.get(key);
   if(node == null) {
       return null;
   }

   String value = node.value;
   removeNode(node);
   addNode(node);
   return value;
}

/**
* 外部调用的函数,用来移除给定的key节点
* @param key
*/
public void remove(String key) {
   Node node = map.get(key);
   removeNode(node);
}

其中涉及到几个子方法:
removeNode(node); 从链表中删除节点
addNode(node); 添加节点到链表尾部

private void removeNode(Node node) {
    if(head == null || tail == null) {
        throw new RuntimeException("Cache is empty...");
    }

    if(node == head) {
        // 如果是移除头节点
        head = head.next;
        if(head != null) {
            head.pre.next = null;
            head.pre = null;
        }
    } else if(node == tail) {
        // 如果是移除尾节点
        tail = tail.pre;
        if(tail != null) {
            tail.next.pre = null;
            tail.next = null;
        }
    } else {
        Node tmp = head;
        while(tmp != null) {
            if(node == tmp) {
                Node pre = node.pre;
                Node next = node.next;
                node.pre = null;
                node.next = null;
                pre.next = next;
                next.pre = pre;
                break;
            }
            tmp = tmp.next;
        }
    }
    map.remove(node.key);
}

private void addNode(Node node) {
    if(head == null || tail == null) {
        head = tail = node;
    } else {
        node.pre = tail;
        tail.next = node;
        tail = node;
    }
    map.put(node.key, node);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章