VOOZH about

URL: https://www.geeksforgeeks.org/dsa/lru-cache-implementation-using-double-linked-lists/

⇱ LRU Cache Implementation using Doubly Linked List - GeeksforGeeks


  • Courses
  • Tutorials
  • Interview Prep

LRU Cache Implementation using Doubly Linked List

Last Updated : 12 Jul, 2025

Design a data structure that works like a LRU(Least Recently Used) Cache. The LRUCache class has two methods get() and put() which are defined as follows.

  • LRUCache (Capacity c): Initialize LRU cache with positive size capacity c.
  • get(key): returns the value of the key if it already exists in the cache otherwise returns -1.
  • put(key, value): if the key is already present, update its value. If not present, add the key-value pair to the cache. If the cache reaches its capacity it should remove the key-value pair with the lowest priority.

Example:

Input: [LRUCache cache = new LRUCache(2) , put(1 ,1) , put(2 ,2) , get(1) , put(3 ,3) , get(2) , put(4 ,4) , get(1) , get(3) , get(4)]
Output: [1 ,-1, -1, 3, 4]
Explanation: The values mentioned in the output are the values returned by get operations.

  • Initialize LRUCache class with capacity = 2.
  • cache.put(1, 1): (key, pair) = (1,1) inserted and has the highest priority.
  • cache.put(2, 2): (key , pair) = (2,2) inserted and has the highest priority.
  • cache.get(1): For key 1, value is 1, so 1 returned and (1,1) moved to the highest priority.
  • cache.put(3, 3): Since cache is full, remove least recently used that is (2,2), (3,3) inserted with the highest priority.
  • cache.get(2): returns -1 (key 2 not found)
  • cache.put(4, 4): Since the cache is full, remove least recently used that is (1,1). (4,5) inserted with the highest priority.
  • cache.get(1): return -1 (not found)
  • cache.get(3): return 3 , (3,3) will moved to the highest priority.
  • cache.get(4): return 4 , (4,4) moved to the highest priority.

Thoughts about Implementation Using Arrays, Hashing and/or Heap

We use an array of triplets, where the items are key, value and priority

get(key) : We linearly search the key. If we find the item, we change priorities of all impacted and make the new item as the highest priority.
put(key): If there is space available, we insert at the end. If not, we linearly search items of the lowest priority and replace that item with the new one. We change priorities of all and make the new item as the highest priority.

Time Complexities of both the operations is O(n)

Can we make both operations in O(1) time? we can think of hashing. With hashing, we can insert, get and delete in O(1) time, but changing priorities would take linear time. We can think of using heap along with hashing for priorities. We can find and remove the least recently used (lowest priority) in O(Log n) time which is more than O(1) and changing priority in the heap would also be required.

Using Doubly Linked List and Hashing

The idea is to keep inserting the key-value pair at the head of the doubly linked list. When a node is accessed or added, it is moved to the head of the list (right after the dummy head node). This marks it as the most recently used. When the cache exceeds its capacity, the node at the tail (right before the dummy tail node) is removed as it represents the least recently used item.


Below is the implementation of the above approach: 


Output
1
-1
-1
3
4

Time Complexity : get(key) - O(1) and put(key, value) - O(1)
Auxiliary Space : O(capacity)

Using Inbuilt Doubly Linked List

The idea is to use inbuilt doubly linked list, it simplifies the implementation by avoiding the need to manually manage a doubly linked list while achieving efficient operations. Example - C++ uses a custom doubly linked list as std::list.

Note: Python's standard library does not include a built-in doubly linked list implementation. To handle use cases that typically require a doubly linked list, such as efficiently managing elements at both ends of a sequence, Python provides the collections.deque class. While deque stands for double-ended queue, it essentially functions as a doubly linked list with efficient operations on both ends.

Below is the implementation of the above approach: 


Output
1
-1
-1
3
4

Time Complexity : get(key) - O(1) and put(key, value) - O(1)
Auxiliary Space: O(capacity)

Comment
Article Tags: