手撕LRU算法O(1)的时间复杂度(最近最少使用淘汰算法,常用于缓存)

LRU算法O(1)的复杂度实现:
如果不是不要求时间复杂度,可以采用链表加时间戳的形式实现
O(1)的时间复杂度,单单采用双向链表的数据结构是不够的,虽然删除和添加的时间复杂度为O(1)的,但是我们想要定位到要删除的元素,还是需要从头开始依次遍历才可以,如何O(1)定位到想要的节点,可以采用散列表,所以最终我们采用散列表+双向链表的形式实现。
当然如果不要求手撕的话,可以直接使用LinkedHashMap。
我这里直接手撕了:

public class LRUCache {
    private int capacity;
    private HashMap<Integer,DLikedNode> map = new HashMap<>();
    private DLikedNode head;
    private DLikedNode tail;
    class DLikedNode{
        int key;
        int value;
        DLikedNode pre;
        DLikedNode next;
    }
    public LRUCache(int capacity) {
        this.capacity = capacity;
        head = new DLikedNode();
        tail = new DLikedNode();
        head.next = tail;
        tail.pre = head;
    }
    private void addNode(DLikedNode node){
        map.put(node.key,node);
        tail.pre.next = node;
        node.pre = tail.pre;
        node.next = tail;
        tail.pre = node;
    }
    private void removeNode(DLikedNode node){
        map.remove(node.key);
        node.pre.next = node.next;
        node.next.pre = node.pre;
    }

    public int get(int key) {
        DLikedNode temp = map.get(key);
        if(null == temp){
            return -1;
        }else{
            //将temp移到尾部
            this.removeNode(temp);
            this.addNode(temp);
            return temp.value;
        }
    }

    public void put(int key, int value) {
        // 先判断是否是已经纯在的了
        DLikedNode temp = map.get(key);
        if(temp !=null) {
            temp.value = value;
            this.removeNode(temp);
            this.addNode(temp);
            return;
        }
        temp = new DLikedNode();
        temp.key = key;
        temp.value = value;
        if(capacity<=0){
            //删除头部数据,在尾部新增一个node
            this.removeNode(head.next);
        }
        this.addNode(temp);
        this.capacity--;
    }
}

此题,手写第一版,感觉并不是很美,过两天有时间,看看国外大神的代码,再优化一下。
大致思路就是head节点是最不常用的,如果超出存储数据个数,先删除head,再在tail前加入新节点,对于get的节点,删除当前位置,在tail前新增一个节点。
对应leetcode,146题,很多缓存中,都采用这个算法,另外在linux系统中,对于进程的内存管理,采用虚拟内存,以及分页加载,其中分页加载,也用到了LRU算法。

你可能感兴趣的:(数据结构与算法)