-1

I am new in programming in general and in Java in particular. I want to implement an LRU cache and would like to have O(1) complexity.

I have seen some implementations in the Internet using a manually implemented doubly linked list for the cache (two arrays, a Node class, previous, next etc.) and a HashMap where Key is the item to be cached and Value is the timestamp.

I really don't see the reason to use timestamps: the inserted item goes to the head of the manually-implemented LinkedList, the evicted item is the cached item located at the tail, and in every insertion the previously cached items are shifted one position towards the tail.

The only problems that I see are the following:

  1. For the cache lookup (to find if we have a cache hit or miss for the requested item), we have to "scan" the cache list, which implies a for loop of some type (conventional, for-each etc., I don't really care much at this point). Obviously, we don't want that. I believe this issue can be solved easily by using an array of boolean variables to indicate whether an item is in the cache or not (1: in, 0: out) - let's call it lookupArray - as following: Let's say that the items are distinguished by some numeric ID, i.e. an integer between 1 and N. Then, this lookupArray of booleans will have size N+1 (because array indexing starts from zero) and it will be initialized at all zero values. When the item with numeric ID k, where 1<=k<=N, enters the cache, we set the boolean value at index k of lookupArray to 1. That way, cache lookup does not need any search in the cache: in order to check whether the item with numeric ID k is in the cache or not, we simply check whether the value of lookupArray at index k is 1 or 0, respectively. (We already have the index, i.e. we know where to look, thus there is no need to use a for loop.)

  2. The second problem, though, is not easilly solvable. Let's say that we have a cache hit for an item. Then, if this item is not located at the head (i.e. if it is not the most recently used item), we have to locate it in the cache list and then put it at the head. As far as I understand, this implies searching in the cache list, i.e. a for loop. Then, we can't achieve the O(1) objective.

Am I right about (2)? Is any way to do this without using a HashMap and timestamps?

Due to the fact that I am relatively new in programming as I stated at the beginning of the post, I would really appreciate the use, if possible, of any code snippets demonstrating the implementation with a manually implemented doubly linked list.

Sorry for the long message, I hope it is not only detailed but also clear.

Thank you!

  • Read the source code of [LinkedHashMap](http://docs.oracle.com/javase/8/docs/api/java/util/LinkedHashMap.html), and you'll see how O(1) is achieved. – Ben Manes Apr 04 '15 at 00:29

1 Answers1

0

Consider using a queue. It allows you to remove an object and insert it at the beginning. It also has a size and can be used for caching.

http://docs.oracle.com/javase/7/docs/api/java/util/Queue.html

O, maybe you should not implement it yourself. There is an LRUMap available in the Apache Commons Collections library.

https://commons.apache.org/proper/commons-collections/javadocs/api-3.2.1/org/apache/commons/collections/map/LRUMap.html

Stefaan Neyts
  • 2,054
  • 1
  • 16
  • 25
  • Thanks for the suggestion. I have two questions though: 1) How does a queue solves the issue of updating cache contents in a cache hit, where the relevant item originally placed at index k should be placed at the top of the cache list and all items from the top up to index k-1 should be down-shifted by one position? 2) Is it better to implemented manually a doubly linked list or a queue or I can't do anything faster and more scalable than the already given structures? – CacheUser Apr 03 '15 at 16:26
  • Pseudo code: if queue contains object, remove object from queue; add object to queue. – Stefaan Neyts Apr 03 '15 at 16:30
  • There is also a double ended queue available, called a deque. – Stefaan Neyts Apr 03 '15 at 16:31
  • OK, I will try that, sounds good since it is circular as far as I understand! Thanks! – CacheUser Apr 03 '15 at 16:38