LRU(缓存淘汰算法)-基于哈希链表的方式

基于哈希链表的方式实现的LRU算法,通过Hash表存储加快数据的访问效率

节点类

package demo.LRU2;

/**
 * @author koala
 * @ClassName Node
 * @date 2019/9/17 09:24
 * @Description
 * @Version V1.0
 */

public class Node {

    String key;
    Object value;


    /**
     * 上一个节点
     */
    Node preNode;

    /**
     * 下一个节点
     */
    Node nextNode;

    /**
     * 构造方法
     * @param key
     * @param value
     */
    Node(String key,Object value){
        this.key = key;
        this.value = value;

        this.preNode = null;
        this.nextNode = null;
    }



    @Override
    public String toString() {
        return super.toString();
    }
}

双向链表类

这里的双向链表只存储头部节点和尾部节点;

package demo.LRU2;

/**
 * @author koala
 * @ClassName DoublyLinkedList
 * @date 2019/9/17 10:09
 * @Description 双向链表
 * @Version V1.0
 */

public class DoublyLinkedList {

    public Node head;
    public Node tail;


    DoublyLinkedList(){
        this.head = null;
        this.tail = null;
    }


    /**
     * 移动到头部节点去
     * @param node
     */
    public void moveToHead(Node node){


        if(node == null || node == head){
            return ;
        }

        // 如果当前节点是尾节点;
        if(tail == node){
            // 把当前节点添加到头部去
            addToHead(node);
            // 移除尾部的节点
            removeTail();
        }else{


            // 当前节点前后节点交换
            Node curNextNode =  node.nextNode;
            curNextNode.preNode = node.preNode;

            Node curPreNode = node.preNode;
            curPreNode.nextNode = curNextNode;



            // 节点交换
            head.preNode = node;

            node.nextNode = head;

            node.preNode = null;

            head = head.preNode;
        }

    }


    /**
     *  删除尾部节点
     */
    public Node removeTail(){
        if(tail == null){
            return null;
        }

        /**
         * 获取当前尾部节点;
         */
        Node n = tail;
        if(head == tail){
            head = null;
            tail = null;
        }else{
            // 当前尾部节点的上一个节点就为新的尾节点
             tail =  n.preNode;
             // 尾节点的下一个节点置空
             tail.nextNode = null;
        }
        //
        return n;
    }


    /**
     *
     * @param node
     */
    public void addToHead(Node node){

        if(node == null){
            return ;
        }

        /**
         * 如果没有上一级节点,证明是第一个节点,那假定前一个和后一个节点都是当前节点
         */
        if(head == null){
            head = node;
            tail = node;
        }else{
            // 把当前节点放到链表最前面
            node.nextNode = head;
            head.preNode = node;

            // 重新指定头部节点
            head = node;
        }
    }


    @Override
    public String toString() {
        return super.toString();
    }
}


缓存类

package demo.LRU2;

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

/**
 * @author koala
 * @ClassName Cache
 * @date 2019/9/17 09:23
 * @Description
 * 最近最少使用算法 。 最近最少使用的元素,在接下来一段时间内,被访问的概率也很低。
 *  * 即最近被使用的元素,在接下来一段时间内,被访问概率较高。
 *  * <p>
 *  * 用链表的结构:
 *  * 链表头部表示最后实现的数据,越靠近最后表示没有使用的数据;
 *  * <p>
 *    插入一个元素,如果没有达到阈值,就放到最前面;如果超过最大的阈值,移除链表尾部的数据;
 *  *
 *  * 访问一个元素,如果存在,则将该元素放到最前面;如果不存在;则返回空
 *  * <p>
 *
 *  * 为提高效率,采用hash表存储数据
 * @Version V1.0
 */

public class Cache {


    private HashMap<String, Node> map;

    /**
     * 双向链接实现LRU顺序
     */
    private DoublyLinkedList list;

    /**
     * 当前节点的大小
     */
    private int size = 0;


    /**
     * 最大容量
     */
    private int capacity = 10;


    /**
     * 初始化、并且赋值最大的容量
     * @param capacity
     */
    Cache(int capacity){
        this.list = new DoublyLinkedList();
        this.map = new HashMap<>();
        this.capacity = capacity;
    }

    Cache(){
        this.list = new DoublyLinkedList();
        this.map = new HashMap<>();
    }

    /**
     * 插入一个数据
     * @param key
     */
    public void put(String key,Object value){

     if(!map.containsKey(key)){

         Node n = new Node(key,value);

         map.put(key,n);

         list.addToHead(n);

         // 如果超过最大的容量、移除最后一个数据
         if(map.size() > capacity){
             Node node =  list.removeTail();
             map.remove(node.key);
         }

     }else{
       // 如果存在,就覆盖value的值
       Node node =  map.get(key);
       node.value = value;
       list.moveToHead(node);
     }
    }


    /**
     * 根据键获取值
     * @param key
     * @return
     */
    public Object get(String key){

        if(map.containsKey(key)){

         Node node = map.get(key);
         list.moveToHead(node);
         return node.value;
        }else{
            return null;
        }

    }


    public DoublyLinkedList getAllList(){
        return list;
    }

    public Map getAllDataMap(){
        return this.map;
    }
}

测试类

package demo.LRU2;


/**
 * @author koala
 * @ClassName test
 * @date 2019/9/17 10:55
 * @Description
 * @Version V1.0
 */

public class test {


    public static void main(String[] args) {



        Cache cache = new Cache(5);

        cache.put("1","hello1");
        cache.put("2","hello2");
        cache.put("3","hello3");
        cache.put("4","hello4");
        cache.put("5","hello5");
        cache.put("6","hello6");

        cache.get("3");


        for (Object map:cache.getAllDataMap().entrySet()) {
            System.out.println(map.toString());
        }

        DoublyLinkedList doublyLinkedList =   cache.getAllList();

        System.out.println(doublyLinkedList.head.preNode);
        System.out.println(doublyLinkedList.tail);

        System.out.println("头部节点, key:"+doublyLinkedList.head.key+";" +
                "头部节点上级节点:"+doublyLinkedList.head.preNode+"" +
                "头部节点下级节点:"+doublyLinkedList.head.nextNode.key);

        System.out.println("尾部节点, key:"+doublyLinkedList.tail.key+";" +
                "尾部节点上级节点:"+doublyLinkedList.tail.preNode.key+"" +
                "尾部节点下级节点:"+doublyLinkedList.tail.nextNode);

    }
}

计算结果

在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章