Skip to content

Commit 11bb58e

Browse files
authored
Merge pull request kodecocodes#498 from remlostime/lru
LRU Cache
2 parents c2d10b9 + 5616f82 commit 11bb58e

File tree

7 files changed

+441
-0
lines changed

7 files changed

+441
-0
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
let cache = LRUCache<String>(2)
2+
cache.set("a", val: 1)
3+
cache.set("b", val: 2)
4+
cache.get("a") // returns 1
5+
cache.set("c", val: 3) // evicts key "b"
6+
cache.get("b") // returns nil (not found)
7+
cache.set("d", val: 4) // evicts key "a"
8+
cache.get("a") // returns nil (not found)
9+
cache.get("c") // returns 3
10+
cache.get("d") // returns 4
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
//
2+
// LRUCache.swift
3+
//
4+
//
5+
// Created by Kai Chen on 16/07/2017.
6+
//
7+
//
8+
9+
import Foundation
10+
11+
public class LRUCache<KeyType: Hashable> {
12+
private let maxSize: Int
13+
private var cache: [KeyType: Any] = [:]
14+
private var priority: LinkedList<KeyType> = LinkedList<KeyType>()
15+
private var key2node: [KeyType: LinkedList<KeyType>.LinkedListNode<KeyType>] = [:]
16+
17+
public init(_ maxSize: Int) {
18+
self.maxSize = maxSize
19+
}
20+
21+
public func get(_ key: KeyType) -> Any? {
22+
guard let val = cache[key] else {
23+
return nil
24+
}
25+
26+
remove(key)
27+
insert(key, val: val)
28+
29+
return val
30+
}
31+
32+
public func set(_ key: KeyType, val: Any) {
33+
if cache[key] != nil {
34+
remove(key)
35+
} else if priority.count >= maxSize, let keyToRemove = priority.last?.value {
36+
remove(keyToRemove)
37+
}
38+
39+
insert(key, val: val)
40+
}
41+
42+
private func remove(_ key: KeyType) {
43+
cache.removeValue(forKey: key)
44+
guard let node = key2node[key] else {
45+
return
46+
}
47+
priority.remove(node: node)
48+
key2node.removeValue(forKey: key)
49+
}
50+
51+
private func insert(_ key: KeyType, val: Any) {
52+
cache[key] = val
53+
priority.insert(key, atIndex: 0)
54+
guard let first = priority.first else {
55+
return
56+
}
57+
key2node[key] = first
58+
}
59+
}
Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
public final class LinkedList<T> {
2+
3+
public class LinkedListNode<T> {
4+
var value: T
5+
var next: LinkedListNode?
6+
weak var previous: LinkedListNode?
7+
8+
public init(value: T) {
9+
self.value = value
10+
}
11+
}
12+
13+
public typealias Node = LinkedListNode<T>
14+
15+
fileprivate var head: Node?
16+
17+
public init() {}
18+
19+
public var isEmpty: Bool {
20+
return head == nil
21+
}
22+
23+
public var first: Node? {
24+
return head
25+
}
26+
27+
public var last: Node? {
28+
if var node = head {
29+
while case let next? = node.next {
30+
node = next
31+
}
32+
return node
33+
} else {
34+
return nil
35+
}
36+
}
37+
38+
public var count: Int {
39+
if var node = head {
40+
var c = 1
41+
while case let next? = node.next {
42+
node = next
43+
c += 1
44+
}
45+
return c
46+
} else {
47+
return 0
48+
}
49+
}
50+
51+
public func node(atIndex index: Int) -> Node? {
52+
if index >= 0 {
53+
var node = head
54+
var i = index
55+
while node != nil {
56+
if i == 0 { return node }
57+
i -= 1
58+
node = node!.next
59+
}
60+
}
61+
return nil
62+
}
63+
64+
public subscript(index: Int) -> T {
65+
let node = self.node(atIndex: index)
66+
assert(node != nil)
67+
return node!.value
68+
}
69+
70+
public func append(_ value: T) {
71+
let newNode = Node(value: value)
72+
self.append(newNode)
73+
}
74+
75+
public func append(_ node: Node) {
76+
let newNode = LinkedListNode(value: node.value)
77+
if let lastNode = last {
78+
newNode.previous = lastNode
79+
lastNode.next = newNode
80+
} else {
81+
head = newNode
82+
}
83+
}
84+
85+
public func append(_ list: LinkedList) {
86+
var nodeToCopy = list.head
87+
while let node = nodeToCopy {
88+
self.append(node.value)
89+
nodeToCopy = node.next
90+
}
91+
}
92+
93+
private func nodesBeforeAndAfter(index: Int) -> (Node?, Node?) {
94+
assert(index >= 0)
95+
96+
var i = index
97+
var next = head
98+
var prev: Node?
99+
100+
while next != nil && i > 0 {
101+
i -= 1
102+
prev = next
103+
next = next!.next
104+
}
105+
assert(i == 0) // if > 0, then specified index was too large
106+
107+
return (prev, next)
108+
}
109+
110+
public func insert(_ value: T, atIndex index: Int) {
111+
let newNode = Node(value: value)
112+
self.insert(newNode, atIndex: index)
113+
}
114+
115+
public func insert(_ node: Node, atIndex index: Int) {
116+
let (prev, next) = nodesBeforeAndAfter(index: index)
117+
let newNode = LinkedListNode(value: node.value)
118+
newNode.previous = prev
119+
newNode.next = next
120+
prev?.next = newNode
121+
next?.previous = newNode
122+
123+
if prev == nil {
124+
head = newNode
125+
}
126+
}
127+
128+
public func insert(_ list: LinkedList, atIndex index: Int) {
129+
if list.isEmpty { return }
130+
var (prev, next) = nodesBeforeAndAfter(index: index)
131+
var nodeToCopy = list.head
132+
var newNode: Node?
133+
while let node = nodeToCopy {
134+
newNode = Node(value: node.value)
135+
newNode?.previous = prev
136+
if let previous = prev {
137+
previous.next = newNode
138+
} else {
139+
self.head = newNode
140+
}
141+
nodeToCopy = nodeToCopy?.next
142+
prev = newNode
143+
}
144+
prev?.next = next
145+
next?.previous = prev
146+
}
147+
148+
public func removeAll() {
149+
head = nil
150+
}
151+
152+
@discardableResult public func remove(node: Node) -> T {
153+
let prev = node.previous
154+
let next = node.next
155+
156+
if let prev = prev {
157+
prev.next = next
158+
} else {
159+
head = next
160+
}
161+
next?.previous = prev
162+
163+
node.previous = nil
164+
node.next = nil
165+
return node.value
166+
}
167+
168+
@discardableResult public func removeLast() -> T {
169+
assert(!isEmpty)
170+
return remove(node: last!)
171+
}
172+
173+
@discardableResult public func remove(atIndex index: Int) -> T {
174+
let node = self.node(atIndex: index)
175+
assert(node != nil)
176+
return remove(node: node!)
177+
}
178+
}
179+
180+
extension LinkedList: CustomStringConvertible {
181+
public var description: String {
182+
var s = "["
183+
var node = head
184+
while node != nil {
185+
s += "\(node!.value)"
186+
node = node!.next
187+
if node != nil { s += ", " }
188+
}
189+
return s + "]"
190+
}
191+
}
192+
193+
extension LinkedList {
194+
public func reverse() {
195+
var node = head
196+
while let currentNode = node {
197+
node = currentNode.next
198+
swap(&currentNode.next, &currentNode.previous)
199+
head = currentNode
200+
}
201+
}
202+
}
203+
204+
extension LinkedList {
205+
public func map<U>(transform: (T) -> U) -> LinkedList<U> {
206+
let result = LinkedList<U>()
207+
var node = head
208+
while node != nil {
209+
result.append(transform(node!.value))
210+
node = node!.next
211+
}
212+
return result
213+
}
214+
215+
public func filter(predicate: (T) -> Bool) -> LinkedList<T> {
216+
let result = LinkedList<T>()
217+
var node = head
218+
while node != nil {
219+
if predicate(node!.value) {
220+
result.append(node!.value)
221+
}
222+
node = node!.next
223+
}
224+
return result
225+
}
226+
}
227+
228+
extension LinkedList {
229+
convenience init(array: Array<T>) {
230+
self.init()
231+
232+
for element in array {
233+
self.append(element)
234+
}
235+
}
236+
}
237+
238+
extension LinkedList: ExpressibleByArrayLiteral {
239+
public convenience init(arrayLiteral elements: T...) {
240+
self.init()
241+
242+
for element in elements {
243+
self.append(element)
244+
}
245+
}
246+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2+
<playground version='5.0' target-platform='ios'>
3+
<timeline fileName='timeline.xctimeline'/>
4+
</playground>

LRU Cache/LRUCache.swift

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
//
2+
// LRUCache.swift
3+
//
4+
//
5+
// Created by Kai Chen on 16/07/2017.
6+
//
7+
//
8+
9+
import Foundation
10+
11+
public class LRUCache<KeyType: Hashable> {
12+
private let maxSize: Int
13+
private var cache: [KeyType: Any] = [:]
14+
private var priority: LinkedList<KeyType> = LinkedList<KeyType>()
15+
private var key2node: [KeyType: LinkedList<KeyType>.LinkedListNode<KeyType>] = [:]
16+
17+
public init(_ maxSize: Int) {
18+
self.maxSize = maxSize
19+
}
20+
21+
public func get(_ key: KeyType) -> Any? {
22+
guard let val = cache[key] else {
23+
return nil
24+
}
25+
26+
remove(key)
27+
insert(key, val: val)
28+
29+
return val
30+
}
31+
32+
public func set(_ key: KeyType, val: Any) {
33+
if cache[key] != nil {
34+
remove(key)
35+
} else if priority.count >= maxSize, let keyToRemove = priority.last?.value {
36+
remove(keyToRemove)
37+
}
38+
39+
insert(key, val: val)
40+
}
41+
42+
private func remove(_ key: KeyType) {
43+
cache.removeValue(forKey: key)
44+
guard let node = key2node[key] else {
45+
return
46+
}
47+
priority.remove(node: node)
48+
key2node.removeValue(forKey: key)
49+
}
50+
51+
private func insert(_ key: KeyType, val: Any) {
52+
cache[key] = val
53+
priority.insert(key, atIndex: 0)
54+
guard let first = priority.first else {
55+
return
56+
}
57+
key2node[key] = first
58+
}
59+
}

0 commit comments

Comments
 (0)