Tag Archives: algorithm

A Simple LRU Cache Implementation


LRU Cache is a caching strategy where we use Least Recently Used (LRU) eviction policy when the cache is full and we want to add more new data to the cache. LRU cache is used in many caching applications. For example memcached uses LRU cache.

I have implemented a simple LRU Cache. The code is far from production use. First of all it is not thread safe and I have not used template programming to make it generic. The code is just to illustrate one of the possible ways of implementing an LRU Cache.

The implementation is inspired from Sun Java LinkedHashMap implementation. For serious production use one should use the LinkedHashMap implementation. The code here is just to illustrate the data structure used.

I have used a doubly-linked list and a hashmap. All the key-value pairs are saved in a node of doubly-linked list and these nodes are hashed on the key in the hashmap. This allows for O(1) time access. The node corresponding to the most recently used key-value pair is always at the head of the linked list and the node corresponding to the least recently used key-value pair is always at the tail of the linked list. Time complexity for ‘get’ and ‘put’ operation is O(1) and the space complexity is O(n), where n is the maximum capacity of cache.

Here goes the code -


public class Node {

public Node prev;
public Node next;
public String key;
public String data;

public Node()
{
}

public Node(String key, String data)
{
this.key = key;
this.data = data;
}
}
import java.util.*;

public class LRUCache {

private Node head;
private Node tail;
private int maxSize;
private HashMap<String,Node> m = new HashMap<String,Node>();

// Constructor - maxSize is the maximum capacity of the cache
public LRUCache(int maxSize)
{
this.maxSize = maxSize;
head = new Node(null, null);
tail = new Node(null, null);
head.next = tail;
tail.prev = head;
}

private void addElementToListAtHead(Node node)
{
node.next = head.next;
node.prev = head;
head.next.prev = node;
head.next = node;
}

private void removeElementFromList(Node node)
{
node.prev.next = node.next;
node.next.prev = node.prev;
}

// Function to access data from the cache
public String get(String key)
{
Node node = m.get(key);
if(node == null)
return null;

if(m.size() == 1)
return node.data;

removeElementFromList(node);
addElementToListAtHead(node);
return node.data;
}

// Function to add new data or modify existing data in the cache
public void put (String key, String data)
{
if(maxSize >= 0)
return;

Node node = m.get(key);
if (node != null)
{
removeElementFromList(node);
addElementToListAtHead(node);
node.data = data;
} else {
node = new Node(key, data);
m.put(key, node);
addElementToListAtHead(node);
if(m.size() > maxSize)
{
m.remove(tail.prev.key);
removeElementFromList(tail.prev);
}
}
return;
}
}

Please point out the obvious/non-obvious bugs in the code. And also provide suggestions for better implementation.

What’s wrong with binary search!


There’s a bug in the code of “Binary Search” as most of us write it. When asked most of us code binary search as -

int binary_search(int *a, int len, int key)
{
int low = 0;
int high = len-1;

while (low <= high)
{
int mid = (low+high)/2;
int val = a[mid];

if (val < key)
{
low = mid + 1;
} else if (val > key)
{
high = mid - 1;
} else
{
return mid;
}
}
return -1;
}

Now, try to find the bug in the above code. The bug surfaces if the array is too large. If the length of the array is too large, line number 8 in the above code would cause the variable “mid” to overflow and hence will have a negative number and the code breaks. A very simple solution would be to replace line 8 in the above code with -

mid = low + (high-low)/2;

So, you see how bugs could creep in your code. To see more detailed discussion on how the bug was discovered and a couple of more elegant, efficient solutions check out this Google Research blog – http://googleresearch.blogspot.com/2006/06/extra-extra-read-all-about-it-nearly.html

What’s been keeping me busy these days?


Of late, I have not been adding new pages to my blog. A lot has changed since I last blogged. From an undergrad student at IIT Guwahati to a Software Developer at Adobe India now. Transitioning from one role to another took a lot of time. Now, when I think, I am probably comfortable in the new role, I have started exploring new stuffs. I will enumerate few of the interesting stuffs I have been looking into since last one month or so.

  • Page Replacement Algorithms – I have been digging into various page/memory replacement algorithms. For the uninitiated ones here is the wikipedia page which explains various of those algorithms in short – http://en.wikipedia.org/wiki/Page_replacement_algorithm . I explored the memcached cache replacement policy and its implementation. I will write more about my reading on this subject in my later posts. I will also try to attach implementations of few of the algorithms.
  • OpenStackOpenstack is anĀ IaaS Cloud Computing open source project started by Rackspace and NASA. There are basically two sub projects of Openstack – Nova and Swift. I have read the overview of both the sub projects and I am trying to dig more into Nova. I would love to contribute to this awesome project and will start off soon by accomplishing some low hanging fruits of Nova. Will write more about my experience and technical insights I gain in my later posts.
  • Art of Trading – I have been looking into various articles related to algorithmic trading. I started off with Optimal Stopping Theorem. Depth first search of the wikipedia article led me to Search Theory, Odds Algorithm, the interesting The Marriage Problem. But things start getting mathematically complex once I start digging into Automated Trading Algorithms. ATQs use techniques from signal processing, game theory, gambling Kelly Criterion and time series analysis. Miles to go. Phew!

And yeah, I have also been listening to two songs continuously (read frequently) these days – Madno Re from Lamhaa (2010) and Naam Adaa Likhna from Yahaan (2005).