Skip to content

Commit 38297dd

Browse files
committed
LRU cache
1 parent 49c086f commit 38297dd

File tree

1 file changed

+133
-133
lines changed

1 file changed

+133
-133
lines changed

src/main/java/joshua/leetcode/cache/LRUCacheImpl.java

Lines changed: 133 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -5,152 +5,152 @@
55
* Since java doesn't have pointers or random access based on pointer move.
66
* so we still use HashMap-like design to support quick access, and augment it by another header pointer.
77
* the header pointers record the element of least accessed and the eldest element.
8-
*
9-
* @Author joy
108
*
9+
* @Author joy
1110
*/
1211
public class LRUCacheImpl extends LRUCache {
1312

14-
transient Entry[] table;
13+
transient Entry[] table;
14+
15+
int capacity;
16+
17+
int size;
1518

16-
int capacity;
19+
Entry header;
1720

18-
int size;
21+
public LRUCacheImpl(int capacity) {
22+
super(capacity);
23+
this.capacity = capacity;
24+
header = new Entry(-1, -1, -1, null);
25+
header.after = header.before = header;
26+
// Find a power of 2 >= initialCapacity
27+
int capa = 1;
28+
while (capa < capacity)
29+
capa <<= 1;
30+
table = new Entry[capacity];
31+
}
1932

20-
Entry header;
33+
/**
34+
* 1) find the entry with given key,if not found, return;
35+
* 2) remove the entry out from the doubly linked list(but the not hash bucket,namely next field remains unchanged.);
36+
* 3) insert it before the header, so that header's "before" field always
37+
*/
38+
@Override
39+
public int get(int key) {
40+
// 1.find the entry
41+
int bucketIndx = key % (table.length);
42+
Entry value = null;
43+
for (Entry e = table[bucketIndx]; e != null; e = e.next) {
44+
int k;
45+
if (e.hash == bucketIndx && ((k = e.key) == key)) {
46+
value = e;
47+
break;
48+
}
49+
}
50+
if (value == null)
51+
return -1;
52+
// 2. remove the entry from the doubly linked list
53+
value.after.before = value.before;
54+
value.before.after = value.after;
55+
// 3. insert in before the header.
56+
value.insertBefore(this.header);
57+
return value.value;
58+
}
2159

22-
public LRUCacheImpl(int capacity) {
23-
super(capacity);
24-
this.capacity = capacity;
25-
header = new Entry(-1, -1, -1, null);
26-
header.after = header.before = header;
27-
// Find a power of 2 >= initialCapacity
28-
int capa = 1;
29-
while (capa < capacity)
30-
capa <<= 1;
31-
table = new Entry[capacity];
32-
}
60+
/**
61+
* @param key
62+
* @param value
63+
*/
64+
@Override
65+
public void set(int key, int value) {
66+
// 1.find the entry
67+
int bucketIndx = key % (table.length);
68+
Entry exist = null;
69+
for (Entry e = table[bucketIndx]; e != null; e = e.next) {
70+
int k;
71+
if (e != null && e.hash == bucketIndx && ((k = e.key) == key)) {
72+
exist = e;
73+
break;
74+
}
75+
}
76+
// 2. if not exist, insert the entry.
77+
if (exist == null) {
78+
Entry newEntry = new Entry(bucketIndx, key, value,
79+
table[bucketIndx]);
80+
size++;
81+
exist = table[bucketIndx] = newEntry;
82+
} else {
83+
/* if exist, update the value and remove from the doubly linked list*/
84+
exist.value = value;
85+
exist.before.after = exist.after;
86+
exist.after.before = exist.before;
87+
}
88+
// 3. insert the least accessed entry before the header.
89+
exist.insertBefore(this.header);
90+
//4. if size exceeds the capacity,remove the eldest entry.
91+
if (size > capacity) {
92+
removeEntry(header.after);
93+
header.after = header.after.after;
94+
header.after.before = header;
95+
size--;
96+
}
97+
}
3398

34-
/**
35-
* 1) find the entry with given key,if not found, return;
36-
* 2) remove the entry out from the doubly linked list(but the not hash bucket,namely next field remains unchanged.);
37-
* 3) insert it before the header, so that header's "before" field always
38-
*/
39-
@Override
40-
public int get(int key) {
41-
// 1.find the entry
42-
int bucketIndx = key % (table.length);
43-
Entry value = null;
44-
for (Entry e = table[bucketIndx]; e != null; e = e.next) {
45-
int k;
46-
if (e.hash == bucketIndx && ((k = e.key) == key)) {
47-
value = e;
48-
break;
49-
}
50-
}
51-
if (value == null)
52-
return -1;
53-
// 2. remove the entry from the doubly linked list
54-
value.after.before = value.before;
55-
value.before.after = value.after;
56-
// 3. insert in before the header.
57-
value.insertBefore(this.header);
58-
return value.value;
59-
}
99+
private void removeEntry(Entry entry) {
100+
Entry prev = table[entry.hash];
101+
Entry e = prev;
102+
while (e != null) {
103+
Entry en = e.next;
104+
if (e.key == entry.key) {
105+
if (prev == e)
106+
table[entry.hash] = en;
107+
else
108+
prev.next = e.next;
109+
break;
110+
}
111+
prev = e;
112+
e = en;
113+
}
114+
}
60115

61-
/**
62-
*
63-
* @param key
64-
* @param value
65-
*/
66-
@Override
67-
public void set(int key, int value) {
68-
// 1.find the entry
69-
int bucketIndx = key % (table.length);
70-
Entry exist = null;
71-
for (Entry e = table[bucketIndx]; e != null; e = e.next) {
72-
int k;
73-
if (e!=null&& e.hash == bucketIndx && ((k = e.key) == key)) {
74-
exist = e;
75-
break;
76-
}
77-
}
78-
// 2. if not exist, insert the entry.
79-
if (exist == null) {
80-
Entry newEntry = new Entry(bucketIndx, key, value,
81-
table[bucketIndx]);
82-
size++;
83-
exist = table[bucketIndx] = newEntry;
84-
} else {
85-
/* if exist, update the value and remove from the doubly linked list*/
86-
exist.value = value;
87-
exist.before.after = exist.after;
88-
exist.after.before = exist.before;
89-
}
90-
// 3. insert the least accessed entry before the header.
91-
exist.insertBefore(this.header);
92-
//4. if size exceeds the capacity,remove the eldest entry.
93-
if(size>capacity){
94-
removeEntry(header.after);
95-
header.after=header.after.after;
96-
header.after.before=header;
97-
size--;
98-
}
99-
}
100-
101-
private void removeEntry(Entry entry){
102-
Entry prev=table[entry.hash];
103-
Entry e=prev;
104-
while(e!=null){
105-
Entry en=e.next;
106-
if(e.key==entry.key){
107-
if(prev==e)
108-
table[entry.hash]=en;
109-
else
110-
prev.next=e.next;
111-
break;
112-
}
113-
prev=e;
114-
e=en;
115-
}
116-
}
116+
static class Entry {
117+
int hash;
118+
int key;
119+
int value;
120+
// 和 hashmap一样,每个bucket自身的单链表
121+
Entry next;/*pointing to next element in the same hash bucket.*/
122+
// 用来做LRU判断的双向循环链表所需要
123+
Entry after, before;/*use to record access order*/
117124

118-
static class Entry {
119-
int hash;
120-
int key;
121-
int value;
122-
Entry next;/*pointing to next element in the same hash bucket.*/
123-
Entry after, before;/*use to record access order*/
125+
public Entry(int hash, int key, int value, Entry next) {
126+
this.hash = hash;
127+
this.key = key;
128+
this.value = value;
129+
this.next = next;
130+
}
124131

125-
public Entry(int hash, int key, int value, Entry next) {
126-
this.hash = hash;
127-
this.key = key;
128-
this.value = value;
129-
this.next = next;
130-
}
132+
public Entry(int hash, int key, int value, Entry next, Entry after,
133+
Entry before) {
134+
this.hash = hash;
135+
this.key = key;
136+
this.value = value;
137+
this.next = next;
138+
this.after = after;
139+
this.before = before;
140+
}
131141

132-
public Entry(int hash, int key, int value, Entry next, Entry after,
133-
Entry before) {
134-
this.hash = hash;
135-
this.key = key;
136-
this.value = value;
137-
this.next = next;
138-
this.after = after;
139-
this.before = before;
140-
}
142+
public void insertBefore(Entry existingEntry) {
143+
after = existingEntry;
144+
before = existingEntry.before;
145+
before.after = this;
146+
after.before = this;
147+
}
141148

142-
public void insertBefore(Entry existingEntry) {
143-
after = existingEntry;
144-
before = existingEntry.before;
145-
before.after = this;
146-
after.before = this;
147-
}
149+
@Override
150+
public String toString() {
151+
return "Entry [hash=" + hash + ", key=" + key + ", value=" + value
152+
+ "]";
153+
}
148154

149-
@Override
150-
public String toString() {
151-
return "Entry [hash=" + hash + ", key=" + key + ", value=" + value
152-
+ "]";
153-
}
154-
155-
}
155+
}
156156
}

0 commit comments

Comments
 (0)