刷题-01链表、栈、队列-LRU

链表:

LintCode:

134 · LRU缓存策略

public class LRUCache {
    /*
    * @param capacity: An integer
    
    */
    class DlinkedNode{
        int key;
        int value;
        DlinkedNode prev;
        DlinkedNode next;
        public DlinkedNode(){}
        public DlinkedNode(int _key, int _value){key = _key;value=_value;}
    }
    Map<Integer, DlinkedNode> cache = new HashMap<>();
    private int size;
    private int capacity;
    private DlinkedNode head, tail;

    
    public LRUCache(int capacity) {
        // do intialization if necessary
        this.size = 0;
        this.capacity = capacity;
        head = new DlinkedNode();
        tail = new DlinkedNode();
        head.next = tail;
        tail.prev = head;
    }

    /*
     * @param key: An integer
     * @return: An integer
     */
    public int get(int key) {
        // write your code here

        DlinkedNode node = cache.get(key);
        if(node==null){
            return -1;
        }
        moveToHead(node);
        return node.value;
    }

    /*
     * @param key: An integer
     * @param value: An integer
     * @return: nothing
     */
    public void set(int key, int value) {
        DlinkedNode node = cache.get(key);
        if(node==null){
            DlinkedNode newNode = new DlinkedNode(key,value);
            cache.put(key,newNode);
            addToHead(newNode);
            size++;
            if(size>capacity){
                DlinkedNode tail = removeTail();
                cache.remove(tail.key);
                size--;
            }
        }else{
            node.value = value;
            moveToHead(node);
        }
        // write your code here
    }

    private void addToHead(DlinkedNode node){
        node.prev = head;
        node.next = head.next;
        head.next.prev = node;
        head.next = node;
    }
    private void removeNode(DlinkedNode node){
        node.prev.next = node.next;
        node.next.prev = node.prev;
    }
    private void moveToHead(DlinkedNode node){
        removeNode(node);
        addToHead(node);

    }
    private DlinkedNode removeTail(){
        DlinkedNode res = tail.prev;
        removeNode(res);
        return res;
    }
}
 



1.建立双链表-这样子可以直接删除尾部节点(最近最少使用的)和删除并移到头部节点,因为时间复杂度为1所以需要使用hashmap来直接定位;

2.双链表需要存储key和value是因为删除节点之后还需要同时删除哈希表中的key,也就是key-value也需要建立双向的联系,通过节点存储的key直接定位到哈希表的key。

3.那么构造函数应该包含一个空置 的和一个包含key value的。如果没有空置的构造函数,就无法建立新的空节点。

4.不写关键字修饰符属于默认default,也就是同一类和包都可以访问,因为随时需要访问节点的值,所以选择默认。this. 和python的self一样,指的是当前的对象。在一个方法内,如果没有出现局部变量和实例变量重名的情况下,是否使用this关键字是没有区别的。那么因此可以直接使用key(实例变量)_key(局部变量)来区分,就不需要用this。使用this就会直接访问方法外的成员变量。

class DlinkedNode{
    int key;
    int value;
    DlinkedNode prev;
    DlinkedNode next;
    public DlinkedNode(){}
    public DlinkedNode(int _key, int _value){key=_key;value=_value;}
}

然后是LRUCache的类的成员变量和构造函数;

1. 需要有当前的size和capacity,因为超出了就需要删除最近最少使用的也就是尾部节点。

2.有一个哈希表。(使用map接口方便后续更改具体的实现,面向对象编程)

3.头尾节点互相指向对方作为初始状态,然后进行get和set操作;

4.只需要一个构造函数,因为没有空的。

[Java] 为什么推荐使用Map map = new HashMap() 而不是 HashMap map = new HashMap() ?_善若寺的博客-CSDN博客

public class LRUCache(){
    Map<Integer,DlinkedNode> cache = new HashMap<>();
    private int size;
    private int capacity;
    private DlinkedNode head, tail;
    public LRUCache(int capacity){
        this.size = 0;
        this.capacity = capacity;
        head  = new DlinkedNode();
        tail  = new DlinkedNode();
        head.next = tail;
        tail.prev = head;
    }
}

然后是方法----

get-为空返回-1,否则就是返回值+(移到头部节点指向的位置,代表最近使用的-调用方法moveToHead(node))

set-如果有就是赋值新的+移到头部节点(removeNode,删除原来的节点+moveToHead)(此时此刻不会超过容量)否则就是创建新的节点+移到头部节点+判断size是否超过节点,否则就是移除尾部节点(removeTail)。

所以有更新---moveToHead(node), removeNode(node),addToHead(node),removeTail()

moveToHead包含removeNode and addToHead

然后removeTail用于返回尾部节点-用来删除哈希表的key

public void moveToHead(DlinkedNode node){
    // remove and add to head
    removeNode(node);
    addToHead(node);
 
}

public void addToHead(DlinkedNode node){
    // directly add to head
    // double link to head.next
    head.next.prev = node;
    node.next = head.next;
    // double link to head
    head.next = node;
    node.prev = head;
}
    
public void removeNode(DlinkedNode node){
    node.next.prev = node.prev;
    node.prev.next = node.next;
}
 

public DlinkedNode removeTail(){
    DlinkedNode res = tail.prev;
    removeNode(res);
    return res;
}

get-为空返回-1,否则就是返回值+(移到头部节点指向的位置,代表最近使用的-调用方法moveToHead(node))

public int get(int key){
    DlinkedNode node = cache.get(key);

    if(node==null){
        return -1;
    }
    // 不用写else 因为已经有return了
    moveToHead(node);
    return node.value;
    
}

public void set(int key, int value){
    DlinkedNode node = cache.get(key);
    if(node==null){
        DlinkedNode newNode = new DlinkedNode(key,value);
        addToHead(node);
        cache.put(key,newNode);
        size++;
        if(size>capacity){
            DlinkedNode end = removeTail();
            cache.remove(end.key);
            size--;
        }
     }else{
        node.value = value;
        moveTohead(node);
     }
}
        
        

所以看着简单但是分为四部分,不熟悉太容易出错了;

再次

第一部分双链表-变量有key,value,prev and next; 两个构造函数;

第二部分LRUCache的类,hashmap cache, size和capacity,head and tail,构造函数一个,变量capacity, 然后赋值,头尾节点new一下和指向对方;

第三部分,一旦查询就是moveToHead,由removeNode和addToHead方法实现,最后删除并返回尾部节点removeTail,先removeNode再返回尾节点。

第四部分,get方法,返回key对应的节点,不为空就返回值并且moveToHead, 否则-1

set方法,返回对应节点,为空则创建新节点,addToHead,并且put key, newNode进入chache,然后size++, 然后判断容量,如果超过则removeTail,remove key from cache,然后size--, 否则就是更新value+moveToHead.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值