Created
April 7, 2017 21:46
-
-
Save JackieQi/1ff9d78a35e61947ef3fbf4480e9fa31 to your computer and use it in GitHub Desktop.
LRU Cache 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 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