-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathLRUCache.java
More file actions
163 lines (136 loc) · 4.65 KB
/
LRUCache.java
File metadata and controls
163 lines (136 loc) · 4.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
import java.util.HashMap;
import java.util.Map;
/**
* LRUCache 实现
* 题目:设计并实现一个 LRU (Least Recently Used) 缓存机制,支持 get 和 put 操作。
*
* 说明:
* - get(key): 如果缓存中存在该键,则返回对应的值,并将该键移动到最近使用的位置。
* - put(key, value): 如果缓存已满,则移除最久未使用的键值对,并插入新的键值对。
*/
public class LRUCache {
private final int capacity;
private final Map<Integer, Node> map;
private final Node head, tail;
private static class Node {
int key, val;
Node prev, next;
Node(int k, int v) {
key = k;
val = v;
}
}
public LRUCache(int capacity) {
this.capacity = capacity;
map = new HashMap<>(capacity);
head = new Node(0, 0);
tail = new Node(0, 0);
head.next = tail;
tail.prev = head;
}
public int get(int key) {
Node node = map.get(key);
if (node == null)
return -1;
moveToHead(node);
return node.val;
}
public void put(int key, int value) {
Node node = map.get(key);
if (node != null) {
node.val = value;
moveToHead(node);
} else {
if (map.size() == capacity) {
Node lru = tail.prev;
removeNode(lru);
map.remove(lru.key);
}
Node newNode = new Node(key, value);
addNode(newNode);
map.put(key, newNode);
}
}
private void addNode(Node node) {
node.next = head.next;
node.prev = head;
head.next.prev = node;
head.next = node;
}
private void removeNode(Node node) {
node.prev.next = node.next;
node.next.prev = node.prev;
}
private void moveToHead(Node node) {
removeNode(node);
addNode(node);
}
public static void main(String[] args) {
System.out.println("=== LRU Cache 测试 ===");
// 创建容量为2的LRU缓存
LRUCache lruCache = new LRUCache(2);
System.out.println("1. 测试put操作:");
lruCache.put(1, 1);
System.out.println("put(1, 1) - 缓存内容: " + getCacheContent(lruCache));
lruCache.put(2, 2);
System.out.println("put(2, 2) - 缓存内容: " + getCacheContent(lruCache));
System.out.println("\n2. 测试get操作:");
int result1 = lruCache.get(1);
System.out.println("get(1) = " + result1 + " - 缓存内容: " + getCacheContent(lruCache));
System.out.println("\n3. 测试缓存满时的LRU淘汰:");
lruCache.put(3, 3);
System.out.println("put(3, 3) - 缓存内容: " + getCacheContent(lruCache));
System.out.println("注意: 键2被淘汰,因为键1最近被访问过");
int result2 = lruCache.get(2);
System.out.println("get(2) = " + result2 + " (应该返回-1,因为键2已被淘汰)");
System.out.println("\n4. 测试更新已存在的键:");
lruCache.put(1, 10);
System.out.println("put(1, 10) - 缓存内容: " + getCacheContent(lruCache));
System.out.println("\n5. 测试访问顺序影响淘汰:");
lruCache.put(4, 4);
System.out.println("put(4, 4) - 缓存内容: " + getCacheContent(lruCache));
System.out.println("注意: 键3被淘汰,因为键1最近被更新过");
System.out.println("\n=== 测试完成 ===");
}
// 辅助方法:获取缓存内容的字符串表示(仅用于测试)
private static String getCacheContent(LRUCache cache) {
try {
// 通过反射获取map的内容(仅用于测试)
java.lang.reflect.Field mapField = LRUCache.class.getDeclaredField("map");
mapField.setAccessible(true);
@SuppressWarnings("unchecked")
Map<Integer, Node> map = (Map<Integer, Node>) mapField.get(cache);
StringBuilder sb = new StringBuilder();
sb.append("{");
boolean first = true;
for (Map.Entry<Integer, Node> entry : map.entrySet()) {
if (!first) sb.append(", ");
sb.append(entry.getKey()).append(":").append(entry.getValue().val);
first = false;
}
sb.append("}");
return sb.toString();
} catch (Exception e) {
return "[无法显示缓存内容]";
}
}
}
/**
jarry@Mac map % java LRUCache.java
=== LRU Cache 测试 ===
1. 测试put操作:
put(1, 1) - 缓存内容: {1:1}
put(2, 2) - 缓存内容: {1:1, 2:2}
2. 测试get操作:
get(1) = 1 - 缓存内容: {1:1, 2:2}
3. 测试缓存满时的LRU淘汰:
put(3, 3) - 缓存内容: {1:1, 3:3}
注意: 键2被淘汰,因为键1最近被访问过
get(2) = -1 (应该返回-1,因为键2已被淘汰)
4. 测试更新已存在的键:
put(1, 10) - 缓存内容: {1:10, 3:3}
5. 测试访问顺序影响淘汰:
put(4, 4) - 缓存内容: {4:4, 1:10}
注意: 键3被淘汰,因为键1最近被更新过
=== 测试完成 ===
*/