|
1 | 1 | # Ordered Set
|
2 | 2 |
|
| 3 | +## Sorted Array Version |
| 4 | + |
3 | 5 | An Ordered Set is a collection of unique items in sorted order. Items are usually sorted from least to greatest.
|
4 | 6 |
|
5 | 7 | The Ordered Set data type is a hybrid of:
|
@@ -323,15 +325,129 @@ The right side did not contain the item, so we look at the left side:
|
323 | 325 |
|
324 | 326 | [X, X, Player 1, Player 2, Player 3, Player 4, Player 5, X, X]
|
325 | 327 | * mid
|
326 |
| - |
| 328 | + |
327 | 329 | [X, X, Player 1, Player 2, Player 3, Player 4, Player 5, X, X]
|
328 | 330 | * mid
|
329 | 331 |
|
330 | 332 | Finally, we've found `Player 2`, and return index 3.
|
331 | 333 |
|
332 |
| -## See Also |
| 334 | +## Apple's Ordered Set |
| 335 | +Below the ordered set is based on sorted array. But [Apple's version](https://developer.apple.com/documentation/foundation/nsorderedset), it's pretty different. Now, let's look into how to implement apple's ordered set. |
| 336 | + |
| 337 | +Here is the example about how it works |
| 338 | + |
| 339 | +```swift |
| 340 | +let s = AppleOrderedSet<Int>() |
| 341 | + |
| 342 | +s.add(1) |
| 343 | +s.add(2) |
| 344 | +s.add(-1) |
| 345 | +s.add(0) |
| 346 | +s.insert(4, at: 3) |
| 347 | + |
| 348 | +print(s.all()) // [1, 2, -1, 4, 0] |
| 349 | + |
| 350 | +s.set(-1, at: 0) // We already have -1 in index: 2, so we will do nothing here |
| 351 | + |
| 352 | +print(s.all()) // [1, 2, -1, 4, 0] |
| 353 | + |
| 354 | +s.remove(-1) |
| 355 | + |
| 356 | +print(s.all()) // [1, 2, 4, 0] |
| 357 | + |
| 358 | +print(s.object(at: 1)) // 2 |
| 359 | + |
| 360 | +print(s.object(at: 2)) // 4 |
| 361 | +``` |
| 362 | + |
| 363 | +The significant difference is the the array is not sorted. The elements in the array are the same when insert them. Image the array without duplicates and with `O(logn)` or `O(1)` search time. |
| 364 | + |
| 365 | +The idea here is using a data structure to provide `O(1)` or `O(logn)` time complexity, so it's easy to think about hash table. |
| 366 | + |
| 367 | +```swift |
| 368 | +var indexOfKey: [T: Int] |
| 369 | +var objects: [T] |
| 370 | +``` |
| 371 | + |
| 372 | +`indexOfKey` is used to track the index of the element. `objects` is array holding elements. |
| 373 | + |
| 374 | +We will go through some key functions details here. |
| 375 | + |
| 376 | +### Add |
333 | 377 |
|
334 |
| -[Apple Ordered Set](AppleOrderedSet.playground) |
335 |
| -@remlostime added an Apple version of `OrderedSet` |
| 378 | +Update `indexOfKey` and insert element in the end of `objects` |
| 379 | + |
| 380 | +```swift |
| 381 | +// O(1) |
| 382 | +public func add(_ object: T) { |
| 383 | + guard indexOfKey[object] == nil else { |
| 384 | + return |
| 385 | + } |
| 386 | + |
| 387 | + objects.append(object) |
| 388 | + indexOfKey[object] = objects.count - 1 |
| 389 | +} |
| 390 | +``` |
| 391 | + |
| 392 | +### Insert |
| 393 | + |
| 394 | +Insert in a random place of the array will cost `O(n)` time. |
| 395 | + |
| 396 | +```swift |
| 397 | +// O(n) |
| 398 | +public func insert(_ object: T, at index: Int) { |
| 399 | + assert(index < objects.count, "Index should be smaller than object count") |
| 400 | + assert(index >= 0, "Index should be bigger than 0") |
| 401 | + |
| 402 | + guard indexOfKey[object] == nil else { |
| 403 | + return |
| 404 | + } |
| 405 | + |
| 406 | + objects.insert(object, at: index) |
| 407 | + indexOfKey[object] = index |
| 408 | + for i in index+1..<objects.count { |
| 409 | + indexOfKey[objects[i]] = i |
| 410 | + } |
| 411 | +} |
| 412 | +``` |
| 413 | + |
| 414 | +### Set |
| 415 | + |
| 416 | +If the `object` already existed in the `OrderedSet`, do nothing. Otherwise, we need to update the `indexOfkey` and `objects`. |
| 417 | + |
| 418 | +```swift |
| 419 | +// O(1) |
| 420 | +public func set(_ object: T, at index: Int) { |
| 421 | + assert(index < objects.count, "Index should be smaller than object count") |
| 422 | + assert(index >= 0, "Index should be bigger than 0") |
| 423 | + |
| 424 | + guard indexOfKey[object] == nil else { |
| 425 | + return |
| 426 | + } |
| 427 | + |
| 428 | + indexOfKey.removeValue(forKey: objects[index]) |
| 429 | + indexOfKey[object] = index |
| 430 | + objects[index] = object |
| 431 | +} |
| 432 | +``` |
| 433 | + |
| 434 | +### Remove |
| 435 | + |
| 436 | +Remove element in the array will cost `O(n)`. At the same time, we need to update all elements's index after the removed element. |
| 437 | + |
| 438 | +```swift |
| 439 | +// O(n) |
| 440 | +public func remove(_ object: T) { |
| 441 | + guard let index = indexOfKey[object] else { |
| 442 | + return |
| 443 | + } |
| 444 | + |
| 445 | + indexOfKey.removeValue(forKey: object) |
| 446 | + objects.remove(at: index) |
| 447 | + for i in index..<objects.count { |
| 448 | + indexOfKey[objects[i]] = i |
| 449 | + } |
| 450 | +} |
| 451 | +``` |
336 | 452 |
|
337 |
| -*Written By Zain Humayun* |
| 453 | +*Ordered Set is Written By Zain Humayun, Apple Ordered Set is Written By Kai Chen* |
0 commit comments