java實現LRU算法


簡介

LRU(Least recently used),即最近最少使用,核心思想是如果數據最近被訪問過,那么將來被訪問的幾率也更高。

代碼實現1

import java.util.LinkedHashMap;
import java.util.Map.Entry;

class LRUCache<K, V> {

  private LinkedHashMap<K, V> map;

  public LRUCache(int capacity) {
    map = new LinkedHashMap<>(capacity, 0.75f, true) {
      @Override
      protected boolean removeEldestEntry(Entry<K, V> eldest) {
        return size() > capacity;
      }
    };
  }

  public V get(K key) {
    return map.get(key);
  }

  public void put(K key, V value) {
    map.put(key, value);
  }

  public static void main(String[] args) {
    LRUCache<Integer, Integer> lRUCache = new LRUCache<>(2);
    lRUCache.put(1, 1); // 緩存是 {1=1}
    lRUCache.put(2, 2); // 緩存是 {1=1, 2=2}
    System.out.println(lRUCache.get(1));//返回 1 緩存是 {2=2,1=1}
    lRUCache.put(3, 3); // 該操作會使得關鍵字 2 作廢,緩存是 {1=1, 3=3}
    System.out.println(lRUCache.get(2));// 返回 null (未找到)
    lRUCache.put(4, 4); // 該操作會使得關鍵字 1 作廢,緩存是 {3=3,4=4}
    System.out.println(lRUCache.get(1));//返回 null (未找到)
    System.out.println(lRUCache.get(3));//返回 3
    System.out.println(lRUCache.get(4));//返回 4
  }
}

LRU算法主要有兩種操作添加put和獲取get,需要使用到哈希表和雙向鏈表兩種數據結構,java內置的LinkedHashMap結合了這兩種。訪問一個元素之后就會將該元素移動到鏈表的末尾,如果添加元素之后發現超出容量,刪除鏈表頭部的元素。

代碼實現2

import java.util.HashMap;

class LRUCache2<K, V> {

  private HashMap<K, Node<K, V>> cache;
  private Node<K, V> head;
  private Node<K, V> tail;
  private int capacity;

  public LRUCache2(int capacity) {
    this.capacity = capacity;
    cache = new HashMap<>(capacity);
  }

  public V get(K key) {
    Node<K, V> node = cache.get(key);
    if (node == null) {
      return null;
    }
    moveToTail(node);
    return node.value;
  }

  public void put(K key, V value) {
    Node<K, V> node = cache.get(key);
    if (node != null) {
      node.value = value;
      moveToTail(node);
    } else {
      Node<K, V> newNode = new Node<>(key, value);
      cache.put(key, newNode);
      addToTail(newNode);
      //如果超出容量,刪除鏈表頭結點
      if (cache.size() > capacity) {
        cache.remove(head.key);
        removeNode(head);
      }
    }
  }

  /**
   * 將e節點移動到鏈表尾部
   */
  private void moveToTail(Node<K, V> e) {
    removeNode(e);
    addToTail(e);
  }

  private void addToTail(Node<K, V> e) {
    //將e鏈接到tail后面
    if (tail == null) {
      head = e;
    } else {
      tail.next = e;
      e.prev = tail;
    }
    tail = e;
  }

  private void removeNode(Node<K, V> e) {
    Node<K, V> prev = e.prev;
    Node<K, V> next = e.next;
    //刪除e節點
    e.prev = e.next = null;
    if (prev == null) {
      head = next;
    } else {
      prev.next = next;
    }
    if (next == null) {
      tail = prev;
    } else {
      next.prev = prev;
    }
  }

  static class Node<K, V> {

    K key;
    V value;
    Node<K, V> prev;
    Node<K, V> next;

    Node(K key, V value) {
      this.key = key;
      this.value = value;
    }
  }

  public static void main(String[] args) {
    LRUCache2<Integer, Integer> lRUCache = new LRUCache2<>(2);
    lRUCache.put(1, 1); // 緩存是 {1=1}
    lRUCache.put(2, 2); // 緩存是 {1=1, 2=2}
    System.out.println(lRUCache.get(1));//返回 1 緩存是 {2=2,1=1}
    lRUCache.put(3, 3); // 該操作會使得關鍵字 2 作廢,緩存是 {1=1, 3=3}
    System.out.println(lRUCache.get(2));// 返回 null (未找到)
    lRUCache.put(4, 4); // 該操作會使得關鍵字 1 作廢,緩存是 {3=3,4=4}
    System.out.println(lRUCache.get(1));//返回 null (未找到)
    System.out.println(lRUCache.get(3));//返回 3
    System.out.println(lRUCache.get(4));//返回 4
  }
}

通過自己實現的雙向鏈表和java的哈希表來實現LRU算法。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM