146. LRU缓存机制

leetcode刷题

LRU算法–最近最少使用算法

**解题思路:这道题综合性很强,很多大厂都作为备考题!!!
首先:最近最少使用,它采用的是双向链表+哈希表来实现的。在java中,LinkedHashMap正是这种结构,有兴趣的同学可以去读一下源码~这里就不介绍了。

我们首先要定义一个双向链表DoubleList和节点Node
1.定义Node节点

//由于是双向链表,所以每个Node节点有prev和next两个指针;
//我们存入key和value,因为我们是要put和get的,我们存入到map当中的
class Node{
        int key,value;
        Node next;
        Node prev;
        public Node(int key,int value){
            this.key = key;
            this.value = value;
        }
    }

2.定义DoubleList双向链表
(1)定义head和tail首尾虚拟节点
(2)定义一个size,来计算节点的个数,因为增加和删除的时候要统计的
(3)因为LRU是最近最少未使用算法,所以我们需要把:每次更改的节点放入到队首,所以我们定义一个addFirst(Node node)方法,!!!不要忘记size++
(4)因为LRU涉及到删除最久未使用的Node,所以我们在定义一个removeLast()方法和remove(Node node)方法
!!!不要忘记size–

 class DoubleList{
        Node tail;
        Node head;
        int size;
      public DoubleList(){
            head = new Node(0,0);//分别对head和tail进行初始化
            tail = new Node(0,0);
            head.next = tail;
            tail.prev = head;
            size = 0;
       }
		//添加第一个节点Node
        private void addFirst(Node node){
            node.next = head.next;
            node.prev = head;
            head.next.prev = node;//注意这个位置!!!
            head.next = node;//注意这个位置!!!
            size++;
        }
		//删除一个节点Node
        private void remove(Node node){
            node.prev.next = node.next;
            node.next.prev = node.prev;
            size--;
        }
		//删除最后一个节点Node
        private Node removeLast(){
        //如果当前没有元素,直接返回null即可。
            if(tail.prev==head){
                return null;
            }
            Node last = tail.prev;
            remove(last);
            return last;
        	}
        private int size(){
            return size;
        }
  }

3.定义一个HashMap,存放的是key和value,value存放的是Node节点;在定义一个容量capacity;然后对它们进行初始化

    DoubleList cache;
    Map<Integer,Node>;
    int capacity;

    public LRUCache(int capacity) {
        cache = new DoubleList();
        cache = new HashMap<>();
        this.capacity = capacity;
    }

4.定义完之后,我们久可以开始写get和put方法了!!
get(int key):分为2种情况
1.如果map中不存在key,则返回-1;
2.如果map种存在key的话,通过get(key).val方法得到值即可。
[我们首先需要把之前的cache的Node删除掉,然后把当前的这个key对应的Node通过addFirst()添加到队首,]==通过put()方法实现

 public int get(int key) {
        if(!Map.containsKey(key)){
            return -1;
        }    
        int value = map.get(key).val;//注意!!!.val因为get(key)得到的是Node
        //put方法中存在加入到addFirst方法,所以把key和value都存进去
        put(key,value);
        return value;
    }

4.put(int key,int value)方法
(1)我们首先要把key和value封装为一个Node节点
(2)如果已经存在key了,久是覆盖
(3)如果不存在key,就是插入;但是再插入之前需要判断当前的容量是否够,如果不够要删除最后一个,然后再插入;如果够,久直接插入

 public void put(int key, int value) {
        Node x  = new Node(key,value);
        if(map.containsKey(key)){
            //cache删除那个key对应的node节点即可。key还是要留着的
            cache.remove(map.get(key));
            //cache存放的是一个完整的node
            cache.addFirst(x);
            map.put(key,x);
        }else{
            if(cache.size()==capacity){
                //如果不够了,就要删除cache中的最后一个
                map.remove(cache.removeLast().key);
            }
            //把新的节点x加入到链表头部
            cache.addFirst(x);
            //把key和节点x加入到map中
            map.put(key,x);
        }
    }

**
完整代码

package 左神.leetcode;

import java.util.HashMap;
import java.util.Map;

public class main10_LRU {
    Map<Integer,Node> map;
    DoubleLinked cache;
    int cap;
    public static void main(String[] args) {
        main10_LRU lru = new main10_LRU(1);
        lru.put_(1,1);
        lru.put_(2,2);
        int x = lru.get_(1);
        System.out.println(x);

    }
    public  main10_LRU(int capacity){
        this.cap = capacity;
        map = new HashMap<>();
        cache = new DoubleLinked();
    }

    private int get_(int key){
        if(!map.containsKey(key)){
            return -1;
        }
        int val = map.get(key).val;
        put_(key,val);
        return val;
    }

    private void put_(int key,int value){
        Node x = new Node(key,value);

        if(map.containsKey(key)){//如果重复了,就把原来的删掉。新的增加到开头
            cache.remove(map.get(key));
            cache.addFirst(x);
            map.put(key,x);
        }else{
            if (cap==cache.size()){
                //map中删除,cache中的最后一个
                map.remove(cache.removeLast().key);
            }
            cache.addFirst(x);
            map.put(key,x);
        }
    }

    //构造一个双向链表类
    class DoubleLinked{
        Node head,tail;
        int size;

        public DoubleLinked(){
            head = new Node(0,0);
            tail = new Node(0,0);
            head.next = tail;
            tail.prev = head;
            size  = 0;
        }
        //表头添加一个元素
        public void addFirst(Node x){
            x.next = head.next;
            x.prev = head;
            head.next.prev = x;
            head.next = x;
            size++;
        }
        //删除链表最后一个元素
        public Node removeLast(){
            if(tail.prev==head){
                return  null;
            }
            Node last = tail.prev;
            remove(last);
            return last;
        }
        //删除链表中的x结点
        public void remove(Node x){
            x.prev.next = x.next;
            x.next.prev = x.prev;
            size--;
        }
        public int size(){
            return size;
        }
    }

    //双向链表的node结点
    class Node{
        int key,val;
        Node next,prev;
        public Node(int key,int val){
            this.key = key;
            this.val = val;
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值