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);

    }
}

計算結果

在這裏插入圖片描述

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