Created
March 16, 2024 06:25
-
-
Save idfumg/529367f45ea05203c47d590e1aead053 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import "fmt" | |
type Set[T comparable] struct { | |
items map[T]struct{} | |
} | |
func NewSet[T comparable]() *Set[T] { | |
return &Set[T]{ | |
items: make(map[T]struct{}), | |
} | |
} | |
func (s *Set[T]) Add(val T) { | |
s.items[val] = struct{}{} | |
} | |
func (s *Set[T]) Remove(val T) { | |
delete(s.items, val) | |
} | |
func (s *Set[T]) Pop() T { | |
if len(s.items) == 0 { | |
panic("Pop() from the emty Set") | |
} | |
for key := range s.items { | |
s.Remove(key) | |
return key | |
} | |
var ans T | |
return ans | |
} | |
func (s *Set[T]) IsEmpty() bool { | |
return len(s.items) == 0 | |
} | |
func (s *Set[T]) String() string { | |
return fmt.Sprintf("%v", s.items) | |
} | |
type LFUCache[KeyT comparable, ValueT any] struct { | |
capacity int | |
values map[KeyT]ValueT | |
freqs map[KeyT]int | |
keys map[int]*Set[KeyT] | |
minFreq int | |
} | |
func NewLFUCache[KeyT comparable, ValueT any](capacity int) *LFUCache[KeyT, ValueT] { | |
return &LFUCache[KeyT, ValueT]{ | |
capacity: capacity, | |
values: make(map[KeyT]ValueT), | |
freqs: make(map[KeyT]int), | |
keys: make(map[int]*Set[KeyT]), | |
minFreq: 0, | |
} | |
} | |
func (lfu *LFUCache[KeyT, ValueT]) Get(key KeyT) (any, bool) { | |
if _, ok := lfu.values[key]; !ok { | |
return nil, false | |
} | |
value := lfu.values[key] | |
freq := lfu.freqs[key] | |
lfu.update(key, value, freq) | |
return value, true | |
} | |
func (lfu *LFUCache[KeyT, ValueT]) Put(key KeyT, value ValueT) { | |
if _, ok := lfu.freqs[key]; ok { | |
freq := lfu.freqs[key] | |
lfu.update(key, value, freq) | |
} else { | |
if len(lfu.values) >= lfu.capacity { | |
lfu.evict() | |
} | |
lfu.values[key] = value | |
lfu.freqs[key] = 1 | |
if _, ok := lfu.keys[1]; !ok { | |
lfu.keys[1] = NewSet[KeyT]() | |
} | |
lfu.keys[1].Add(key) | |
lfu.minFreq = 1 | |
} | |
} | |
func (lfu *LFUCache[KeyT, ValueT]) update(key KeyT, value ValueT, freq int) { | |
lfu.keys[freq].Remove(key) | |
if lfu.keys[freq].IsEmpty() { | |
delete(lfu.keys, freq) | |
if lfu.minFreq == freq { | |
lfu.minFreq += 1 | |
} | |
} | |
lfu.values[key] = value | |
lfu.freqs[key] = freq + 1 | |
if _, ok := lfu.keys[freq+1]; !ok { | |
lfu.keys[freq+1] = NewSet[KeyT]() | |
} | |
lfu.keys[freq+1].Add(key) | |
} | |
func (lfu *LFUCache[KeyT, ValueT]) evict() { | |
key := lfu.keys[lfu.minFreq].Pop() | |
if lfu.keys[lfu.minFreq].IsEmpty() { | |
delete(lfu.keys, lfu.minFreq) | |
} | |
delete(lfu.values, key) | |
delete(lfu.freqs, key) | |
} | |
func main() { | |
Assert := func(ok bool) { | |
if !ok { | |
panic("Assertion is failed") | |
} | |
} | |
lfu := NewLFUCache[int, string](3) | |
lfu.Put(1, "A") | |
lfu.Put(2, "B") | |
got, ok := lfu.Get(1) | |
Assert(ok && got == "A") | |
lfu.Put(3, "C") | |
got, ok = lfu.Get(2) | |
Assert(ok && got == "B") | |
lfu.Put(4, "D") | |
got, ok = lfu.Get(3) | |
Assert(!ok) | |
got, ok = lfu.Get(1) | |
Assert(ok && got == "A") | |
got, ok = lfu.Get(2) | |
Assert(ok && got == "B") | |
got, ok = lfu.Get(4) | |
Assert(ok && got == "D") | |
fmt.Println("OK") | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment