算法模拟题——设计LRU缓存结构

设计LRU缓存结构

核心思想

当缓存满时执行淘汰算法, 删除缓存中最久未使用的key-value

解决思路

定义一个Node节点,包含前向和后向指针,使用map存储key-node,同时每次操作数据,插入新数据和更新数据,都将数据放置双向链表的头部,保证链表尾部的节点为最久未使用的数据,缓存满时就从表位删除节点。

具体代码

1 定义Node

class Node {
    
    
        int key;
        int val;
        //前向指针
        Node pre;
        //后继指针
        Node next;
        public Node(int key, int val,Node prev, Node next) {
    
    
            this.key = key;
            this.val = val;
            this.pre = pre;
            this.next = next;
        }
    }

2 初始化

	//哈希表
    private Map<Integer,Node> map = new HashMap<>();
    //设置一个头节点
    private Node  head;
    //设置一个尾节点
    private Node tail;
    //设置容量
    private int capacity;
    //记录已使用的容量
    private int used;

3 set(int key, int val)

public void set(int key, int value) {
    
    
        //如果 key 已存在,直接修改值,并移动到链表头部
        if(map.containsKey(key)){
    
    
            map.get(key).val = value;
            //更新节点的状态。将节点移动到头部
            makeRecently(key);
            return;
        }
        //如果达到容量上限,就移除尾部节点,注意HashMap要remove
        if(used == capacity){
    
    
        	//删除尾部节点
            map.remove(tail.key);
            //尾节点更新
            tail = tail.pre;
            tail.next = null;
            //已使用容量减一
            used--;
        }
        //头结点为空,单独处理
        if(head == null){
    
    
            head = new Node(key, value, null,null);
            tail = head;
        }else{
    
    
        	//头节点不为空,将节点插入头部
            Node t = new Node(key, value, null, head);
            head.pre = t;
            head = t;
        }
        //所以map 存的永远是头节点
        map.put(key, head);
        used++;

    }

4 get(int key)

 public int get(int key) {
    
    
        // 判断是有
        if(!map.containsKey(key)){
    
    
        	//没有值返回-1
            return -1;
        }
        //有就返回值,但是get操作也需要更新节点状态
        makeRecently(key);
        return map.get(key).val;
    }

5 重头戏,更新节点状态的函数 makeRecantly(int key),可以看图理解

 private void makeRecently(int key){
    
    
 		//获取节点,将节点移动到头部
        Node t = map.get(key);
        //更新的节点不是头节点
        if(t != head){
    
    
        	//如果是尾节点,更新尾部节点
            if(t == tail){
    
    
                tail = tail.pre;
                tail.next = null;
            }
            else{
    
    
            //不是尾部节点,更新前后指针,具体看图理解
                t.pre.next = t.next;
                t.next.pre = t.pre;
            }
            //因为t移动到了头部,所以前指针为空,后指针为旧的头节点
            t.pre = null;
            t.next = head;
            head.pre = t;
            head = t;
        }
    }

在这里插入图片描述
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/YuannaY/article/details/130477136
今日推荐