本文目录导读:

我来提供一个完整的LFU(Least Frequently Used)缓存实现案例:
LFU缓存实现
import java.util.*;
/**
* LFU (Least Frequently Used) 缓存实现
* 支持get和put操作,时间复杂度O(1)
*/
public class LFUCache<K, V> {
// 缓存容量
private final int capacity;
// 存储key对应的节点
private Map<K, Node<K, V>> cache;
// 存储频率对应的双向链表
private Map<Integer, LinkedHashSet<Node<K, V>>> frequencyMap;
// 当前最小频率
private int minFrequency;
// 当前缓存大小
private int size;
/**
* 节点类
*/
private static class Node<K, V> {
K key;
V value;
int frequency = 1;
public Node(K key, V value) {
this.key = key;
this.value = value;
}
}
/**
* 构造函数
*/
public LFUCache(int capacity) {
this.capacity = capacity;
this.cache = new HashMap<>();
this.frequencyMap = new HashMap<>();
this.minFrequency = 0;
this.size = 0;
}
/**
* 获取缓存值
*/
public V get(K key) {
if (!cache.containsKey(key)) {
return null;
}
Node<K, V> node = cache.get(key);
// 更新频率
updateFrequency(node);
return node.value;
}
/**
* 放入缓存
*/
public void put(K key, V value) {
if (capacity <= 0) {
return;
}
// 如果key已存在,更新值并增加频率
if (cache.containsKey(key)) {
Node<K, V> node = cache.get(key);
node.value = value;
updateFrequency(node);
return;
}
// 如果缓存已满,需要淘汰
if (size >= capacity) {
evict();
}
// 创建新节点
Node<K, V> newNode = new Node<>(key, value);
cache.put(key, newNode);
addToFrequencyMap(newNode);
minFrequency = 1;
size++;
}
/**
* 更新节点频率
*/
private void updateFrequency(Node<K, V> node) {
// 从当前频率的链表中移除节点
LinkedHashSet<Node<K, V>> currentSet = frequencyMap.get(node.frequency);
currentSet.remove(node);
// 如果当前频率的链表为空,且是最小频率,更新最小频率
if (currentSet.isEmpty()) {
frequencyMap.remove(node.frequency);
if (minFrequency == node.frequency) {
minFrequency++;
}
}
// 增加频率并添加到新的频率链表
node.frequency++;
addToFrequencyMap(node);
}
/**
* 添加到频率映射
*/
private void addToFrequencyMap(Node<K, V> node) {
frequencyMap.computeIfAbsent(node.frequency,
k -> new LinkedHashSet<>()).add(node);
}
/**
* 淘汰最不经常使用的节点
*/
private void evict() {
// 获取最小频率的链表
LinkedHashSet<Node<K, V>> set = frequencyMap.get(minFrequency);
if (set != null && !set.isEmpty()) {
// 移除链表中的第一个元素(最久未使用)
Node<K, V> evictNode = set.iterator().next();
set.remove(evictNode);
// 从缓存中移除
cache.remove(evictNode.key);
size--;
// 如果链表为空,移除该频率的映射
if (set.isEmpty()) {
frequencyMap.remove(minFrequency);
}
}
}
/**
* 获取缓存大小
*/
public int size() {
return size;
}
/**
* 清空缓存
*/
public void clear() {
cache.clear();
frequencyMap.clear();
size = 0;
minFrequency = 0;
}
/**
* 是否包含key
*/
public boolean containsKey(K key) {
return cache.containsKey(key);
}
/**
* 获取所有键
*/
public Set<K> keySet() {
return cache.keySet();
}
/**
* 打印缓存内容
*/
public void printCache() {
System.out.println("========= LFU Cache =========");
for (Map.Entry<Integer, LinkedHashSet<Node<K, V>>> entry :
frequencyMap.entrySet()) {
System.out.print("频率 " + entry.getKey() + ": ");
for (Node<K, V> node : entry.getValue()) {
System.out.print("[" + node.key + "=" + node.value + "] ");
}
System.out.println();
}
System.out.println("============================");
}
// 测试代码
public static void main(String[] args) {
// 创建容量为3的LFU缓存
LFUCache<String, Integer> cache = new LFUCache<>(3);
System.out.println("=== 测试基本操作 ===");
cache.put("A", 1);
cache.put("B", 2);
cache.put("C", 3);
cache.printCache();
// 访问A两次,增加A的频率
cache.get("A");
cache.get("A");
System.out.println("\n访问A两次后:");
cache.printCache();
// 访问B一次
cache.get("B");
System.out.println("\n访问B一次后:");
cache.printCache();
// 添加新元素D,应该淘汰频率最低的C
cache.put("D", 4);
System.out.println("\n添加D后(淘汰C):");
cache.printCache();
System.out.println("\n=== 测试键值更新 ===");
cache.put("A", 10);
System.out.println("更新A的值后:");
cache.printCache();
// 测试缓存淘汰策略
System.out.println("\n=== 测试复杂淘汰策略 ===");
LFUCache<Integer, String> testCache = new LFUCache<>(2);
testCache.put(1, "one");
testCache.put(2, "two");
System.out.println("初始状态:");
testCache.printCache();
// 访问1两次,增加1的频率
testCache.get(1);
testCache.get(1);
// 添加3,应该淘汰2(频率最低)
testCache.put(3, "three");
System.out.println("\n添加3后(应该淘汰2):");
testCache.printCache();
// 验证缓存内容
System.out.println("\n=== 验证结果 ===");
System.out.println("是否包含1: " + testCache.containsKey(1));
System.out.println("是否包含2: " + testCache.containsKey(2));
System.out.println("是否包含3: " + testCache.containsKey(3));
System.out.println("缓存大小: " + testCache.size());
// 测试清空操作
System.out.println("\n=== 测试清空操作 ===");
testCache.clear();
System.out.println("清空后大小: " + testCache.size());
System.out.println("是否包含1: " + testCache.containsKey(1));
}
}
使用示例
// 更实际的使用示例
public class LFUCacheExample {
public static void main(String[] args) {
// 创建一个缓存最近访问数据的LFU
LFUCache<String, String> userSessionCache =
new LFUCache<>(100); // 最多缓存100个用户会话
// 模拟用户访问
String userId = "user123";
String sessionData = "session_data_for_user";
// 存储用户会话
userSessionCache.put(userId, sessionData);
// 获取用户会话
String data = userSessionCache.get(userId);
if (data != null) {
System.out.println("Session found: " + data);
} else {
System.out.println("Session expired or not found");
}
}
}
实现要点
- 时间复杂度:get和put操作均为O(1)
- 数据结构:
HashMap存储键值对HashMap+LinkedHashSet维护频率到节点的映射
- 淘汰策略:当缓存满时,淘汰频率最低且最久未使用的元素
- 频率更新:每次访问(get/put)都会增加元素的访问频率
- 线程安全:如果需要线程安全,可以在方法上添加
synchronized或使用ConcurrentHashMap
这个实现可以处理各种复杂场景,是生产级别的LFU缓存实现。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播