10
10
//===----------------------------------------------------------------------===//
11
11
12
12
extension Sequence {
13
- /// Returns the elements of the sequence such that the 0...k range contains
14
- /// the first k sorted elements in this sequence, using the given predicate
15
- /// as the comparison between elements.
13
+ /// Returns the first k elements of this collection when it's sorted using
14
+ /// the given predicate as the comparison between elements.
16
15
///
17
16
/// This example partially sorts an array of integers to retrieve its three
18
17
/// smallest values:
19
18
///
20
19
/// let numbers = [7,1,6,2,8,3,9]
21
- /// let almostSorted = numbers.partiallySorted(3, <)
22
- /// // [1, 2, 3, 9, 7, 6, 8]
23
- /// let smallestThree = almostSorted.prefix(3)
20
+ /// let smallestThree = numbers.sortedPrefix(3, <)
24
21
/// // [1, 2, 3]
25
22
///
26
- /// The order of equal elements is not guaranteed to be preserved, and the
27
- /// order of the remaining elements is unspecified.
28
- ///
29
- /// If you need to sort a sequence but only need access to a prefix of its
23
+ /// If you need to sort a collection but only need access to a prefix of its
30
24
/// elements, using this method can give you a performance boost over sorting
31
- /// the entire sequence.
25
+ /// the entire collection. The order of equal elements is guaranteed to be
26
+ /// preserved.
32
27
///
33
28
/// - Parameter count: The k number of elements to partially sort.
34
29
/// - Parameter areInIncreasingOrder: A predicate that returns true if its
35
30
/// first argument should be ordered before its second argument;
36
- /// otherwise, false.
31
+ /// otherwise, false.
37
32
///
38
- /// - Complexity: O(k log n )
33
+ /// - Complexity: O(k log k + nk )
39
34
public func partiallySorted(
40
35
_ count: Int ,
41
36
by areInIncreasingOrder: ( Element , Element ) throws -> Bool
@@ -47,236 +42,25 @@ extension Sequence {
47
42
}
48
43
49
44
extension Sequence where Element: Comparable {
50
- /// Returns the elements of the sequence such that the 0...k range contains
51
- /// the first k smallest elements in this sequence.
45
+ /// Returns the first k elements of this collection when it's sorted.
52
46
///
53
47
/// This example partially sorts an array of integers to retrieve its three
54
48
/// smallest values:
55
49
///
56
50
/// let numbers = [7,1,6,2,8,3,9]
57
- /// let almostSorted = numbers.partiallySorted(3)
58
- /// // [1, 2, 3, 9, 7, 6, 8]
59
- /// let smallestThree = almostSorted.prefix(3)
51
+ /// let smallestThree = numbers.sortedPrefix(<)
60
52
/// // [1, 2, 3]
61
53
///
62
- /// The order of equal elements is not guaranteed to be preserved, and the
63
- /// order of the remaining elements is unspecified.
64
- ///
65
- /// If you need to sort a sequence but only need access to a prefix of
66
- /// its elements, using this method can give you a performance boost over
67
- /// sorting the entire sequence.
54
+ /// If you need to sort a sequence but only need access to a prefix of its
55
+ /// elements, using this method can give you a performance boost over sorting
56
+ /// the entire collection. The order of equal elements is guaranteed to be
57
+ /// preserved.
68
58
///
69
59
/// - Parameter count: The k number of elements to partially sort
70
60
/// in ascending order.
71
61
///
72
- /// - Complexity: O(k log n )
62
+ /// - Complexity: O(k log k + nk )
73
63
public func partiallySorted( _ count: Int ) -> [ Element ] {
74
64
return partiallySorted ( count, by: < )
75
65
}
76
66
}
77
-
78
- extension MutableCollection where Self: RandomAccessCollection {
79
- /// Rearranges this collection such that the 0...k range contains the first
80
- /// k sorted elements in this collection, using the given predicate as the
81
- /// comparison between elements.
82
- ///
83
- /// This example partially sorts an array of integers to retrieve its three
84
- /// smallest values:
85
- ///
86
- /// var numbers = [7,1,6,2,8,3,9]
87
- /// numbers.partiallySort(3, <)
88
- /// // [1, 2, 3, 9, 7, 6, 8]
89
- /// let smallestThree = numbers.prefix(3)
90
- /// // [1, 2, 3]
91
- ///
92
- /// The order of equal elements is not guaranteed to be preserved, and the
93
- /// order of the remaining elements is unspecified.
94
- ///
95
- /// If you need to sort a collection but only need access to a prefix of its
96
- /// elements, using this method can give you a performance boost over sorting
97
- /// the entire collection.
98
- ///
99
- /// - Parameter count: The k number of elements to partially sort.
100
- /// - Parameter areInIncreasingOrder: A predicate that returns true if its
101
- /// first argument should be ordered before its second argument;
102
- /// otherwise, false.
103
- ///
104
- /// - Complexity: O(k log n)
105
- public mutating func partiallySort(
106
- _ count: Int ,
107
- by areInIncreasingOrder: ( Element , Element ) throws -> Bool
108
- ) rethrows {
109
- try __partiallySort ( count, by: areInIncreasingOrder)
110
- }
111
- }
112
-
113
- extension MutableCollection
114
- where Self: RandomAccessCollection , Element: Comparable {
115
- /// Rearranges this collection such that the 0...k range contains the first
116
- /// k smallest elements in this collection.
117
- ///
118
- /// This example partially sorts an array of integers to retrieve its three
119
- /// smallest values:
120
- ///
121
- /// var numbers = [7,1,6,2,8,3,9]
122
- /// numbers.partiallySort(3)
123
- /// // [1, 2, 3, 9, 7, 6, 8]
124
- /// let smallestThree = numbers.prefix(3)
125
- /// // [1, 2, 3]
126
- ///
127
- /// The order of equal elements is not guaranteed to be preserved, and the
128
- /// order of the remaining elements is unspecified.
129
- ///
130
- /// If you need to sort a collection but only need access to a prefix of its
131
- /// elements, using this method can give you a performance boost over sorting
132
- /// the entire collection.
133
- ///
134
- /// - Parameter count: The k number of elements to partially sort
135
- /// in ascending order.
136
- ///
137
- /// - Complexity: O(k log n)
138
- public mutating func partiallySort( _ count: Int ) {
139
- partiallySort ( count, by: < )
140
- }
141
- }
142
-
143
- //===----------------------------------------------------------------------===//
144
- // __partiallySort(_:by:)
145
- //===----------------------------------------------------------------------===//
146
-
147
- extension MutableCollection where Self: RandomAccessCollection {
148
- typealias Priority = ( Element , Element ) throws -> Bool
149
-
150
- /// Partially sorts this collection by using an in place heapsort that stops
151
- /// after we find the desired k amount
152
- /// of elements. The heap is stored and processed in reverse order so that
153
- /// the collection doesn't have to be flipped once the final result is found.
154
- ///
155
- /// Complexity: O(k log n)
156
- mutating func __partiallySort(
157
- _ k: Int ,
158
- by areInIncreasingOrder: Priority
159
- ) rethrows {
160
- assert ( k >= 0 , """
161
- Cannot partially sort with a negative amount of elements!
162
- """
163
- )
164
-
165
- assert ( k <= count, """
166
- Cannot partially sort more than this Sequence's size!
167
- """
168
- )
169
-
170
- guard k > 0 else {
171
- return
172
- }
173
- guard isEmpty == false else {
174
- return
175
- }
176
- var heapEndIndex = 0
177
- for i in ( count / 2 ) ..< count {
178
- try siftDown ( i, by: areInIncreasingOrder, heapEndIndex: heapEndIndex)
179
- }
180
- var iterator = ( 0 ..< k) . makeIterator ( )
181
- _ = iterator. next ( )
182
- swapAt ( index ( before: endIndex) , index ( startIndex, offsetBy: heapEndIndex) )
183
- heapEndIndex += 1
184
- while let _ = iterator. next ( ) {
185
- try siftDown (
186
- count - 1 ,
187
- by: areInIncreasingOrder,
188
- heapEndIndex: heapEndIndex
189
- )
190
- swapAt ( index ( before: endIndex) , index ( startIndex, offsetBy: heapEndIndex) )
191
- heapEndIndex += 1
192
- }
193
- }
194
-
195
- /// Sifts down an element from this heap.
196
- /// The heap is stored in reverse order, so sifting down will actually
197
- /// move the element up in the heap.
198
- ///
199
- /// - Parameter i: The element index to sift down
200
- /// - Parameter by: The predicate to use when determining the priority
201
- /// of elements in the heap
202
- /// - Parameter heapEndIndex: The index in reverse order, where the heap ends.
203
- private mutating func siftDown(
204
- _ i: Int ,
205
- by priority: Priority ,
206
- heapEndIndex: Int
207
- ) rethrows {
208
- let indexToSwap = try highestPriorityIndex (
209
- of: i,
210
- by: priority,
211
- heapEndIndex: heapEndIndex
212
- )
213
- guard indexToSwap != i else {
214
- return
215
- }
216
- swapAt (
217
- index ( startIndex, offsetBy: i) ,
218
- index ( startIndex, offsetBy: indexToSwap)
219
- )
220
- try siftDown ( indexToSwap, by: priority, heapEndIndex: heapEndIndex)
221
- }
222
-
223
- private func highestPriorityIndex(
224
- of index: Int ,
225
- by priority: Priority ,
226
- heapEndIndex: Int
227
- ) rethrows -> Int {
228
- let reverseHeapTrueIndex = self . count - 1 - index
229
- let leftChildDistance =
230
- leftChildIndex ( of: reverseHeapTrueIndex) - reverseHeapTrueIndex
231
- let leftChild = index - leftChildDistance
232
-
233
- let rightChildDistance =
234
- rightChildIndex ( of: reverseHeapTrueIndex) - reverseHeapTrueIndex
235
- let rightChild = index - rightChildDistance
236
-
237
- let left = try highestPriorityIndex (
238
- of: index,
239
- and: leftChild,
240
- by: priority,
241
- heapEndIndex: heapEndIndex
242
- )
243
-
244
- let right = try highestPriorityIndex (
245
- of: index,
246
- and: rightChild,
247
- by: priority,
248
- heapEndIndex: heapEndIndex
249
- )
250
- return try highestPriorityIndex (
251
- of: left,
252
- and: right,
253
- by: priority,
254
- heapEndIndex: heapEndIndex
255
- )
256
- }
257
-
258
- private func leftChildIndex( of index: Int ) -> Int {
259
- return ( 2 * index) + 1
260
- }
261
-
262
- private func rightChildIndex( of index: Int ) -> Int {
263
- return ( 2 * index) + 2
264
- }
265
-
266
- private func highestPriorityIndex(
267
- of parent: Int ,
268
- and child: Int ,
269
- by priority: Priority ,
270
- heapEndIndex: Int
271
- ) rethrows -> Int {
272
- guard child >= heapEndIndex else {
273
- return parent
274
- }
275
- let childElement = self [ index ( startIndex, offsetBy: child) ]
276
- let parentElement = self [ index ( startIndex, offsetBy: parent) ]
277
- guard try priority ( childElement, parentElement) else {
278
- return parent
279
- }
280
- return child
281
- }
282
- }
0 commit comments