双端链表实现LRUCache

本文介绍了一种基于双端链表实现的LRU缓存算法,并提供了完整的Java代码示例。该LRU缓存采用单例模式,通过HashMap和自定义双向链表节点来维护缓存项,支持基本的获取和设置操作。
Memcached的实现核心就是一个LRU算法,它使用双端链表实现。
下面也是一个简单的用双端链表实现的单例LRU Cache,大家可以根据自己的需要添加一些方法。
package lruCache;

import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

public class LRUCache {
private static Map<Object, DoubleLinkedListNode> map = new HashMap<Object, DoubleLinkedListNode>();
private DoubleLinkedListNode head;
private DoubleLinkedListNode end;
private int len;
private int capacity;

private static LRUCache singleton = null;

public static LRUCache getInstance(int capacity){
if(null == singleton){
singleton = new LRUCache(capacity);
}
return singleton;
}

private LRUCache(int capacity) {
this.capacity = capacity;
len = 0;
}

public Object get(Object key) {
if(map.containsKey(key)){
DoubleLinkedListNode latest = map.get(key);
removeFromList(latest);
setHead(latest);
return latest.val;
}
else{
return null;
}
}

public void set(Object key, Object value) {
if (map.containsKey(key)) {
DoubleLinkedListNode oldNode = map.get(key);
oldNode.val = value;
removeFromList(oldNode);
setHead(oldNode);
} else {
DoubleLinkedListNode newNode =
new DoubleLinkedListNode(key, value);
if (len < capacity) {
setHead(newNode);
map.put(key, newNode);
len++;
} else {
map.remove(end.key);
end = end.pre;
if (end != null) {
end.post = null;
}

setHead(newNode);
map.put(key, newNode);
}
}
}

private void removeFromList(DoubleLinkedListNode node){
if(node.pre != null){
node.pre.post = node.post;
}
else{
head = node.post;
}
if(node.post != null){
node.post.pre = node.pre;
}
else{
end = node.pre;
}
}

private void setHead(DoubleLinkedListNode node){
node.post = head;
node.pre = null;
if (head != null) {
head.pre = node;
}

head = node;
if (end == null) {
end = node;
}
}

//返回当前Cache中key的集合
public Set<Object> keySet(){
Set<Object> res = new LinkedHashSet<Object>();
DoubleLinkedListNode cur = head;
while(null != cur){
res.add(cur.key);
cur = cur.post;
}
return res;
}

private class DoubleLinkedListNode{
Object key;
Object val;
DoubleLinkedListNode pre;
DoubleLinkedListNode post;
DoubleLinkedListNode(Object key, Object value){
this.key = key;
val = value;
}
}
}


测试类:
package lruCache;

import java.util.Set;

public class LRUCacheDemo {
public static void main(String[] args){
//新建一个容量为5的LRUCache
LRUCache lruCache = LRUCache.getInstance(5);
lruCache.set("1", "yi");
lruCache.set("1", "yiyi");
Set<Object> keySet = lruCache.keySet();
lruCache.set("2", "er");
lruCache.set("3", "san");
lruCache.set("4", "si");
lruCache.set("5", "wu");
lruCache.set("6", "liu");
Set<Object> keySet2 = lruCache.keySet();
}
}

### C++ 中链表的实际应用场景 链表作为一种重要的数据结构,在实际开发中有许多具体的应用场景。以下是几个常见的应用案例: #### 1. **操作系统中的内存管理** 在现代操作系统中,链表被用于管理内存页或块。例如,空闲内存块可以通过链表组织起来,这样可以方便地进行内存分配和回收[^4]。 ```cpp struct MemoryBlock { size_t size; bool isFree; struct MemoryBlock* next; }; // 创建一个新的内存块并加入到链表中 MemoryBlock* addMemoryBlock(MemoryBlock* head, size_t size) { MemoryBlock* newBlock = new MemoryBlock(); newBlock->size = size; newBlock->isFree = true; newBlock->next = head; return newBlock; } ``` #### 2. **文件系统中的目录和文件管理** 文件系统通常会使用链表来表示目录和文件之间的层次关系。特别是当文件或目录的数量和位置不确定时,链表能够灵活适应这种变化。 ```cpp struct FileNode { std::string name; FileType type; // 文件类型:文件或目录 struct FileNode* next; }; ``` #### 3. **编译器和解析器中的符号表管理** 编译器和解析器常常需要维护一个符号表,其中存储程序中的变量名、函数名以及其他标识符的信息。链表可以用来实现这个符号表,特别是在简单情况下或者作为更复杂数据结构的基础。 ```cpp struct SymbolTableEntry { std::string identifierName; TypeIdentifier type; struct SymbolTableEntry* next; }; ``` #### 4. **数据库管理系统中的记录管理** 在某些数据库系统中,链表可用于管理记录,尤其是在需要频繁插入和删除记录的情况下。这种方式允许高效的动态调整。 ```cpp struct Record { int id; char data[100]; struct Record* next; }; ``` #### 5. **缓存机制(如 LRU 缓存)** 最近最少使用(LRU)缓存策略常常用双端链表实现。在这种设计中,每次访问某个条目都会将其移动到链表头部,而淘汰则从链表尾部移除最久未使用的条目。 ```cpp class LRUCache { private: list<pair<int, int>> cacheList; unordered_map<int, list<pair<int, int>>::iterator> cacheMap; public: void put(int key, int value); int get(int key); }; ``` #### 6. **多任务调度中的就绪队列** 操作系统中的进程调度模块可能会用到链表来管理就绪队列和等待队列。这些队列中的每一个节点代表一个正在运行或等待资源的任务。 ```cpp struct Process { int pid; Priority priorityLevel; State currentState; struct Process* next; }; ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值