Table of Contents
LRU Cache
- LRU Cache using a combination of a map and a doubly linked list
package main
import "fmt"
// Node represents a doubly linked list node
type Node struct {
key, value int
prev, next *Node
}
// LRUCache represents the LRU Cache
type LRUCache struct {
capacity int
cache map[int]*Node
head *Node
tail *Node
}
// Constructor initializes the LRUCache with a given capacity
func Constructor(capacity int) *LRUCache {
head := &Node{}
tail := &Node{}
head.next = tail
tail.prev = head
return &LRUCache{
capacity: capacity,
cache: make(map[int]*Node),
head: head,
tail: tail,
}
}
// Get retrieves the value of the key if it exists in the cache
func (lru *LRUCache) Get(key int) int {
if node, exists := lru.cache[key]; exists {
lru.moveToHead(node)
return node.value
}
return -1
}
// Put inserts a key-value pair into the cache
func (lru *LRUCache) Put(key int, value int) {
if node, exists := lru.cache[key]; exists {
node.value = value
lru.moveToHead(node)
} else {
newNode := &Node{key: key, value: value}
lru.cache[key] = newNode
lru.addToHead(newNode)
if len(lru.cache) > lru.capacity {
tail := lru.removeTail()
delete(lru.cache, tail.key)
}
}
}
// moveToHead moves a node to the head of the list (most recently used)
func (lru *LRUCache) moveToHead(node *Node) {
lru.removeNode(node)
lru.addToHead(node)
}
// addToHead adds a node to the head of the doubly linked list
func (lru *LRUCache) addToHead(node *Node) {
node.prev = lru.head
node.next = lru.head.next
lru.head.next.prev = node
lru.head.next = node
}
// removeNode removes a node from the doubly linked list
func (lru *LRUCache) removeNode(node *Node) {
node.prev.next = node.next
node.next.prev = node.prev
}
// removeTail removes the least recently used node (from the tail)
func (lru *LRUCache) removeTail() *Node {
tail := lru.tail.prev
lru.removeNode(tail)
return tail
}
func main() {
lru := Constructor(2)
lru.Put(1, 1)
lru.Put(2, 2)
fmt.Println(lru.Get(1)) // Returns 1
lru.Put(3, 3) // Evicts key 2
fmt.Println(lru.Get(2)) // Returns -1 (not found)
lru.Put(4, 4) // Evicts key 1
fmt.Println(lru.Get(1)) // Returns -1 (not found)
fmt.Println(lru.Get(3)) // Returns 3
fmt.Println(lru.Get(4)) // Returns 4
}
Explanation
- Doubly Linked List:
- Nodes represent cache entries (
key
,value
) and are linked in both directions (prev
,next
). - Head and Tail are dummy nodes used to manage the most and least recently used entries.
- Nodes represent cache entries (
- HashMap:
- The
cache
map holds keys and their corresponding nodes for O(1) access.
- The
- Core Operations:
- Get: Retrieves the value of the key and moves it to the head (most recently used).
- Put: Inserts a new key-value pair or updates an existing key. If capacity is exceeded, the least recently used node (at the tail) is removed.
- moveToHead: Updates node usage by moving it to the head.
- removeTail: Removes the least recently used node (just before the tail).
- Constructor:
- Initializes the LRU cache with the specified capacity.
Example Run
Put(1, 1)
andPut(2, 2)
add two entries to the cache.Get(1)
retrieves the value1
and moves it to the head.Put(3, 3)
evicts the least recently used key2
and adds key3
.Put(4, 4)
evicts key1
and adds key4
.
This implementation provides O(1) complexity for both Get
and Put
operations using the doubly linked list and map combination.
Please visit https: https://codeandalgo.com for more such contents
Leave a Reply