LRU Cache(Least Recent Used缓存)

在有限内存空间中,抛弃距当前时间最远被使用(访问)的元素的缓存的数据结构,能够添加元素,读取元素。这个数据结构在操作系统中经常被使用到,见wikipedia链接https://en.wikipedia.org/wiki/Cache_replacement_policies#Least_recently_used_(LRU)

使用一个双端链表和一个HashMap可以在O(1)时间、O(n)空间内完成插入和查询操作。

双端链表数据结构定义如下:

private class DLinkedListNode<Key,Value>
    {
        Key key;
        Value val;
        DLinkedListNode pre;
        DLinkedListNode next;

        public DLinkedListNode(Key key,Value val)
        {
            this.key=key;
            this.val=val;
            this.pre=null;
            this.next=null;
        }
    }

LRU Cache数据结构定义如下:

public class LRUCache<Key,Value> {

    private HashMap<Key,DLinkedListNode> hashmap;
    private int capacity;      //缓存容量
    private DLinkedListNode head;   //双端链表头结点
    private DLinkedListNode tail;   //双端链表尾节点

    public LRUCache(int capacity)
    {
        this.hashmap=new HashMap<>();
        this.capacity=capacity;
        this.head=null;
        this.tail=null;
    }
}

很基础的链表操作,但是边界条件的处理很恶心!!!泛型编程的详细代码实现如下:

import java.util.HashMap;

public class LRUCache<Key,Value> {

    private HashMap<Key,DLinkedListNode> hashmap;
    private int capacity;      //缓存容量
    private DLinkedListNode head;   //双端链表头结点
    private DLinkedListNode tail;   //双端链表尾节点


    private class DLinkedListNode<Key,Value>
    {
        Key key;
        Value val;
        DLinkedListNode pre;
        DLinkedListNode next;

        public DLinkedListNode(Key key,Value val)
        {
            this.key=key;
            this.val=val;
            this.pre=null;
            this.next=null;
        }
    }

    public LRUCache(int capacity)
    {
        this.hashmap=new HashMap<>();
        this.capacity=capacity;
        this.head=null;
        this.tail=null;
    }

    public Value get(Key key)
    {
        DLinkedListNode node= hashmap.get(key);
        if(node==null)                //当hashmap中不存在这个key时,返回null
            return null;
        if(node!=this.tail)           //存在这个key时,检查是否是尾节点:如果是尾节点,则该节点位置不动;如果不是尾节点,则需要移动位置。
        {
            if(node==this.head)       //如果是头结点,则将头结点放在双端链表尾部
                head=head.next;
            else                      //如果不是头节点,则将该节点从双端链表中移到尾部
            {
                node.pre.next=node.next;
                node.next.pre=node.pre;
            }
            tail.next=node;
            node.pre=tail;
            node.next=null;
            tail=node;
        }
        return (Value)node.val;
    }

    public void put(Key key, Value value)
    {
        DLinkedListNode node=hashmap.get(key);
        if(node!=null)
        {
            node.val=value;
            if(node==this.head)
            {
                if(this.size()==1)
                    return;
                head=head.next;
            }
            else if(node==this.tail)
                return;
            else
            {
                node.pre.next=node.next;
                node.next.pre=node.pre;
            }
            tail.next=node;
            node.pre=tail;
            node.next=null;
            tail=node;
        }
        else
        {
            DLinkedListNode newNode=new DLinkedListNode(key,value);
            if(this.size()==this.capacity)
            {
                DLinkedListNode tmp=this.head;
                this.head=this.head.next;
                this.hashmap.remove(tmp.key);
            }

            if(head==null && tail==null)
            {
                this.head = newNode;
                this.tail = newNode;
            }
            else
            {
                this.tail.next=newNode;
                newNode.pre=this.tail;
                newNode.next=null;
            }
            this.tail=newNode;
            this.hashmap.put(key,newNode);
        }
    }

    public int size()
    {
        return this.hashmap.size();
    }


    //单元测试
    public static void main(String[] args)
    {
        LRUCache<Integer,Integer> lru=new LRUCache<>(2);
        lru.get(2);
        lru.put(2,6);
        lru.get(1);
        lru.put(1,5);
        lru.put(1,2);
        lru.get(1);
        lru.get(2);
    }
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值