Created
September 5, 2022 07:53
-
-
Save derekli66/13901b175ede0d16f14530891a0e6715 to your computer and use it in GitHub Desktop.
LRU cache implementation in Swift
This file contains hidden or 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
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