Skip to content

Instantly share code, notes, and snippets.

@JackieQi
Created April 7, 2017 21:46
Show Gist options
  • Save JackieQi/1ff9d78a35e61947ef3fbf4480e9fa31 to your computer and use it in GitHub Desktop.
Save JackieQi/1ff9d78a35e61947ef3fbf4480e9fa31 to your computer and use it in GitHub Desktop.
LRU Cache in Swift
class Node<K: Equatable, V> {
var next: Node?
var previous: Node?
var key: K
var value: V?
init(key: K, value: V?) {
self.key = key
self.value = value
}
}
extension Node: Equatable {
static func ==(lhs: Node, rhs: Node) -> Bool {
return lhs.key == rhs.key
}
}
class DoubleLinkedList<K: Hashable, V> {
var head: Node<K, V>?
var tail: Node<K, V>?
init() {
}
func addToHead(node: Node<K, V>) {
if head == nil {
head = node
tail = node
}
else {
head?.previous = node
node.next = head
head = node
}
}
func remove(node: Node<K, V>) {
if node == head {
if head?.next != nil {
head = head?.next
head?.previous = nil
}
else {
head = nil
tail = nil
}
}
else if node.next != nil {
node.previous?.next = node.next
node.next?.previous = node.previous
}
else {
node.previous?.next = nil
tail = node.previous
}
}
}
class LRUCache<K: Hashable, V>: CustomStringConvertible {
let capacity: Int
private let queue: DoubleLinkedList<K, V>
private var hashTable: [K: Node<K,V>]
init(capacity: Int) {
self.capacity = capacity
self.queue = DoubleLinkedList()
self.hashTable = [K: Node<K,V>].init(minimumCapacity: capacity)
}
subscript(key: K) -> V? {
get {
guard let node = hashTable[key] else {
return nil
}
if node != queue.head {
queue.remove(node: node)
queue.addToHead(node: node)
}
return node.value
}
set {
if let node = hashTable[key] {
node.value = newValue
queue.remove(node: node)
queue.addToHead(node: node)
}
else {
let node = Node(key: key, value: newValue)
if hashTable.count == capacity {
if let tail = queue.tail {
queue.remove(node: tail)
hashTable.removeValue(forKey: tail.key)
queue.addToHead(node: node)
hashTable[key] = node
}
}
else {
queue.addToHead(node: node)
hashTable[key] = node
}
}
}
}
var description: String {
var result = ""
var head = queue.head
while case let node? = head {
result += ("node: (\(node.key), \(String(describing: node.value)))")
if node != queue.tail {
result += " -> "
}
head = head?.next
}
return result
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment