forked from fanpyi/swift-algorithm-club-cn
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBoundedPriorityQueue.swift
executable file
·137 lines (117 loc) · 3.28 KB
/
BoundedPriorityQueue.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
public class LinkedListNode<T: Comparable> {
var value: T
var next: LinkedListNode?
var previous: LinkedListNode?
public init(value: T) {
self.value = value
}
}
public class BoundedPriorityQueue<T: Comparable> {
private typealias Node = LinkedListNode<T>
private(set) public var count = 0
private var head: Node?
private var tail: Node?
private var maxElements: Int
public init(maxElements: Int) {
self.maxElements = maxElements
}
public var isEmpty: Bool {
return count == 0
}
public func peek() -> T? {
return head?.value
}
public func enqueue(value: T) {
if let node = insert(value, after: findInsertionPoint(value)) {
// If the newly inserted node is the last one in the list, then update
// the tail pointer.
if node.next == nil {
tail = node
}
// If the queue is full, then remove an element from the back.
count += 1
if count > maxElements {
removeLeastImportantElement()
}
}
}
private func insert(value: T, after: Node?) -> Node? {
if let previous = after {
// If the queue is full and we have to insert at the end of the list,
// then there's no reason to insert the new value.
if count == maxElements && previous.next == nil {
print("Queue is full and priority of new object is too small")
return nil
}
// Put the new node in between previous and previous.next (if exists).
let node = Node(value: value)
node.next = previous.next
previous.next?.previous = node
previous.next = node
node.previous = previous
return node
} else if let first = head {
// Have to insert at the head, so shift the existing head up once place.
head = Node(value: value)
head!.next = first
first.previous = head
return head
} else {
// This is the very first item in the queue.
head = Node(value: value)
return head
}
}
/* Find the node after which to insert the new value. If this returns nil,
the new value should be inserted at the head of the list. */
private func findInsertionPoint(value: T) -> Node? {
var node = head
var prev: Node? = nil
while let current = node where value < current.value {
prev = node
node = current.next
}
return prev
}
private func removeLeastImportantElement() {
if let last = tail {
tail = last.previous
tail?.next = nil
count -= 1
}
// Note: Instead of using a tail pointer, we could just scan from the new
// node until the end. Then nodes also don't need a previous pointer. But
// this is much slower on large lists.
}
public func dequeue() -> T? {
if let first = head {
count -= 1
if count == 0 {
head = nil
tail = nil
} else {
head = first.next
head!.previous = nil
}
return first.value
} else {
return nil
}
}
}
extension LinkedListNode: CustomStringConvertible {
public var description: String {
return "\(value)"
}
}
extension BoundedPriorityQueue: CustomStringConvertible {
public var description: String {
var s = "<"
var node = head
while let current = node {
s += "\(current), "
node = current.next
}
return s + ">"
}
}