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算法。

原文地址:https://www.cnblogs.com/strongmore/p/14460307.html