java实现LFU算法

简介

LFU(Least Frequently Used),即最不经常使用,淘汰一定时期内访问次数最少的元素,如果访问次数相同,则比较最新一次的访问时间。

代码实现1

import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

public class LFUCache<K, V> {

  private int capacity;
  private Map<K, CacheObject<V>> cache;

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

  public V get(K key) {
    CacheObject<V> cacheObject = cache.get(key);
    if (cacheObject == null) {
      return null;
    }
    return cacheObject.getValue();
  }

  public void put(K key, V value) {
    if (capacity == 0) {
      return;
    }
    CacheObject<V> cacheObject = cache.get(key);
    if (cacheObject == null) {
      if (cache.size() >= capacity) {
        //删除最少使用的键,使用次数相等,删除最久未使用的
        cache.entrySet().stream()
            .min(Comparator.comparing(Entry::getValue))
            .ifPresent(e -> {
              cache.remove(e.getKey());
            });
      }
      cacheObject = new CacheObject<>(value);
    } else {
      cacheObject.setValue(value);
    }
    cache.put(key, cacheObject);
  }

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

  static class CacheObject<V> implements Comparable<CacheObject<V>> {

    private V value;
    private long lastAccessTime;
    private int accessCount;

    CacheObject(V value) {
      setValue(value);
    }

    V getValue() {
      lastAccessTime = System.nanoTime();
      accessCount++;
      return value;
    }

    public void setValue(V value) {
      this.value = value;
      lastAccessTime = System.nanoTime();
      accessCount++;
    }

    @Override
    public String toString() {
      return value + ":" + accessCount;
    }

    @Override
    public int compareTo(CacheObject<V> o) {
      int res = Integer.compare(this.accessCount, o.accessCount);
      return res != 0 ? res : Long.compare(this.lastAccessTime, o.lastAccessTime);
    }
  }
}

存储被缓存对象的访问次数和最后访问时间,当缓存已经达到最大容量时,删除最少访问次数的数据,如果两个数据访问次数相等,删除最后访问时间久的数据。

代码实现2

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

class LFUCache2<K, V> {

  private int capacity;
  private Map<K, CacheObject<K, V>> cache;
  private TreeSet<CacheObject<K, V>> treeSet;

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

  public V get(K key) {
    CacheObject<K, V> cacheObject = cache.get(key);
    if (cacheObject == null) {
      return null;
    }
    treeSet.remove(cacheObject);
    V value = cacheObject.getValue();
    treeSet.add(cacheObject);
    return value;
  }

  public void put(K key, V value) {
    if (capacity == 0) {
      return;
    }
    CacheObject<K, V> cacheObject = cache.get(key);
    if (cacheObject == null) {
      if (cache.size() >= capacity) {
        //删除最少使用的键,使用次数相等,删除最久未使用的
        cache.remove(treeSet.first().key);
        treeSet.pollFirst();
      }
      cacheObject = new CacheObject<>(key, value);
    } else {
      treeSet.remove(cacheObject);
      cacheObject.setValue(value);
    }
    treeSet.add(cacheObject);
    cache.put(key, cacheObject);
  }

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

  static class CacheObject<K, V> implements Comparable<CacheObject<K, V>> {

    private K key;
    private V value;
    private long lastAccessTime;
    private int accessCount;

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

    V getValue() {
      lastAccessTime = System.nanoTime();
      accessCount++;
      return value;
    }

    public void setValue(V value) {
      this.value = value;
      lastAccessTime = System.nanoTime();
      accessCount++;
    }

    @Override
    public String toString() {
      return value + ":" + accessCount;
    }

    @Override
    public int compareTo(CacheObject<K, V> o) {
      int res = Integer.compare(this.accessCount, o.accessCount);
      return res != 0 ? res : Long.compare(lastAccessTime, o.lastAccessTime);
    }
  }
}

相比第一种,使用TreeSet存储访问次数的顺序关系,可以很快的得到最不经常使用的数据。

posted @ 2021-03-05 19:45  strongmore  阅读(767)  评论(0编辑  收藏  举报