-
Notifications
You must be signed in to change notification settings - Fork 23
Expand file tree
/
Copy pathLRUCache
More file actions
147 lines (122 loc) · 4.24 KB
/
LRUCache
File metadata and controls
147 lines (122 loc) · 4.24 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
/*
* Source of Explanation which explains why we NEED both:
* 1. HashMap = for O(1) operations
* 2. DLL = for maintaining FIFO structure (i.e. DLL can easily be used as a Queue.
* Also since we are using DLL instead of simple LL hence traversing is simple since traversal is
* possible in BOTH directions)
*
* Explanation Source: https://alaindefrance.wordpress.com/2014/10/05/lru-cache-implementation/
* Implementation Source: http://www.programcreek.com/2013/03/leetcode-lru-cache-java/
* This implementation source gives the actual code for implementing LRU Cache
*
*/
package LRUCache;
import java.util.HashMap;
class DoublyLinkedList{
int key;
int value;
DoublyLinkedList prev;
DoublyLinkedList next;
public DoublyLinkedList(int key, int value){
this.key = key;
this.value = value;
}
}
public class LRUCache {
private HashMap<Integer,DoublyLinkedList> map = new HashMap<Integer,DoublyLinkedList>();
private DoublyLinkedList head;
private DoublyLinkedList tail;
private int capacity;
private int length;
/*
We define 4 operations for LRU cache
1. getNode (NOTE: this method returns value of the node and NOT the node itself)
2. removeNode
3. setNode
4. setHeadAndTail
*/
public LRUCache(int capacity){
this.capacity = capacity;
this.length=0;
}
// search operation in LRUCache
public int getNode(int key){
if(map.containsKey(key)){ // if key is present then return the key and replace the head with this node
DoublyLinkedList hitNode = map.get(key);
removeNode(hitNode);
setHeadAndTail(hitNode);
return hitNode.value;
}
else{ // if the node is not present then return -1 as value
return -1;
}
}
public void removeNode(DoublyLinkedList node){
//DoublyLinkedList curr = node;
DoublyLinkedList prev=node.prev;
DoublyLinkedList post=node.next;
/*
Since we are removing node from already built DLL, hence we can safely conclude that head and tail are NOT NULL
Hence we need to check for other 2 conditions while removing.
1. prevNode is null
2. postNode is null
*/
if(prev==null)
head = post;
else
prev.next=post;
if(post==null)
tail=prev;
else
post.prev=prev;
}
public void setHeadAndTail(DoublyLinkedList node){
DoublyLinkedList curr = node;
/*
check 2 conditions while setting head.
1. If the head is already null
2. if the end is already null
*/
curr.next = head; // even if head is null at this point, it doesn't matter
curr.prev = null;
if(head==null)
head=curr;
else{
head.prev = curr;
head = curr;
}
if(tail==null)
tail=curr;
}
public void setNode(int key, int value){
if(map.containsKey(key)){
DoublyLinkedList oldNode = map.get(key);
oldNode.value=value; // set the new value
removeNode(oldNode);
setHeadAndTail(oldNode);
}
else{
// Create a new DLL
DoublyLinkedList newNode = new DoublyLinkedList(key,value);
/*
Add this node to the map. Two conditions exists
1. length<capacity
2. length=capacity
*/
if(length<capacity){
length++;
}
else{
// remove from HashMap
map.remove(tail.key);
//remove from DLL
tail=tail.prev;
if(tail==null){} // check if DLL is null do nothing else set next of end as null
else
tail.next=null;
}
map.put(key,newNode);
setHeadAndTail(newNode);
}
}
}