Skip to content

Instantly share code, notes, and snippets.

@derekli66
Created September 5, 2022 07:53
Show Gist options
  • Save derekli66/13901b175ede0d16f14530891a0e6715 to your computer and use it in GitHub Desktop.
Save derekli66/13901b175ede0d16f14530891a0e6715 to your computer and use it in GitHub Desktop.
LRU cache implementation in Swift
class ListNode<T> {
var val: T?
var key: Int
var next: ListNode?
var previous: ListNode?
init(key: Int) {
self.key = key
}
}
class DoublyLinkedList<T> {
typealias Node = ListNode<T>
private var dummyHead: Node = Node(key: Int.min)
private var dummyTail: Node = Node(key: Int.min)
private var count: Int = 0
init() {
dummyHead.next = dummyTail
dummyTail.previous = dummyHead
}
func append(_ node: Node) {
let lastNode = dummyTail.previous
lastNode?.next = node
node.previous = lastNode
node.next = dummyTail
dummyTail.previous = node
count += 1
}
func insert(at node: Node, with newNode: Node) {
let previous = node.previous
previous?.next = newNode
newNode.previous = previous
newNode.next = node
node.previous = newNode
count += 1
}
func delete(_ node: Node) {
let previous = node.previous
let next = node.next
previous?.next = next
next?.previous = previous
node.previous = nil
node.next = nil
count -= 1
}
func insertFront(_ node: Node) {
let frontNode = dummyHead.next!
insert(at: frontNode, with: node)
}
func findNode(_ key: Int) -> Node? {
var pivot: Node? = dummyHead.next
while pivot != nil {
if pivot!.key == key && pivot !== dummyTail && pivot !== dummyHead {
return pivot
}
pivot = pivot?.next
}
return nil
}
func first() -> Node? {
if dummyHead.next !== dummyTail {
return dummyTail.next
}
return nil
}
func last() -> Node? {
if dummyTail.previous !== dummyHead {
return dummyTail.previous
}
return nil
}
func size() -> Int {
return count
}
}
class LRUCache {
typealias Node = DoublyLinkedList<Int>.Node
private var list = DoublyLinkedList<Int>()
private var map = [Int: Node]()
private var capacity: Int
init(_ capacity: Int) {
self.capacity = capacity
}
func get(_ key: Int) -> Int {
if map[key] == nil { return -1 }
let node = map[key]!
let value = node.val!
deleteFor(key)
insertNode(key, value)
return value
}
func put(_ key: Int, _ value: Int) {
if map[key] == nil {
// Check if capacity is full then evict the last node
if map.count == capacity { evict() }
}
else {
deleteFor(key)
}
insertNode(key, value)
}
private func insertNode(_ key: Int, _ value: Int) {
let newNode = createNode(key, value)
list.insertFront(newNode)
map[key] = newNode
}
private func createNode(_ key: Int,_ value: Int) -> Node {
let node = Node(key: key)
node.val = value
return node
}
private func deleteFor(_ key: Int) {
if map[key] == nil { return }
let node = map[key]!
map[key] = nil
list.delete(node)
}
private func evict() {
if map.count == 0 { return }
let lastNode = list.last()!
map[lastNode.key] = nil
list.delete(lastNode)
}
}
/**
* Your LRUCache object will be instantiated and called as such:
* let obj = LRUCache(capacity)
* let ret_1: Int = obj.get(key)
* obj.put(key, value)
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment