1. Array with Linear Search for Eviction
Intuition
Store all entries in an array where each record holds (key, value, freq, lastAccessTime).
- get(key): Scan linearly for key. If found, increment freq, update lastAccessTime, and return value. Otherwise return -1.
- put(key, value): If key exists, update value, increment freq, and update time. If new and at capacity, scan all entries to find the entry with the minimum frequency; break ties using oldest lastAccessTime. Overwrite or remove that entry.
Because every operation scans up to C entries, this requires O(C) time per operation.
When to apply: Basic prototyping when capacity is tiny (C <= 20).
Algorithm
- Step 1: Store entries in an array with fields key, value, frequency, timestamp.
- Step 2: On get, search array. If found, increment freq and timestamp, return value; else return -1.
- Step 3: On put, if key exists, update value and increment freq.
- Step 4: If key is new and at capacity, scan to find min freq (and min timestamp for ties), remove it.
- Step 5: Append new entry with freq = 1 and current timestamp.
#include <iostream>#include <vector>#include <climits> struct Node { int key, value, freq, time;}; class LFUCacheBrute { int capacity; int timer = 0; std::vector<Node> cache;public: LFUCacheBrute(int cap) : capacity(cap) {} int get(int key) { for (auto& node : cache) { if (node.key == key) { node.freq++; node.time = ++timer; return node.value; } } return -1; } void put(int key, int value) { if (capacity <= 0) return; for (auto& node : cache) { if (node.key == key) { node.value = value; node.freq++; node.time = ++timer; return; } } if ((int)cache.size() >= capacity) { int minIdx = 0; for (int i = 1; i < (int)cache.size(); ++i) { if (cache[i].freq < cache[minIdx].freq || (cache[i].freq == cache[minIdx].freq && cache[i].time < cache[minIdx].time)) { minIdx = i; } } cache.erase(cache.begin() + minIdx); } cache.push_back({key, value, 1, ++timer}); }}; int main() { LFUCacheBrute lfu(2); lfu.put(1, 1); lfu.put(2, 2); std::cout << lfu.get(1) << std::endl; lfu.put(3, 3); std::cout << lfu.get(2) << std::endl; std::cout << lfu.get(3) << std::endl; lfu.put(4, 4); std::cout << lfu.get(1) << std::endl; std::cout << lfu.get(3) << std::endl; std::cout << lfu.get(4) << std::endl; return 0;}Time & Space Complexity
- Time complexity:
O(C) per get and put where C is cache capacity - Space complexity:
O(C) space for storing cache items