forked from kodecocodes/swift-algorithm-club
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
d7f172a
commit 95b45f0
Showing
21 changed files
with
738 additions
and
732 deletions.
There are no files selected for viewing
76 changes: 0 additions & 76 deletions
76
Ordered Set/AppleOrderedSet.playground/Sources/AppleOrderedSet.swift
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
2 changes: 1 addition & 1 deletion
2
...AppleOrderedSet.playground/Contents.swift → ... Set/OrderedSet.playground/Contents.swift
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
let s = AppleOrderedSet<Int>() | ||
let s = OrderedSet<Int>() | ||
|
||
s.add(1) | ||
s.add(2) | ||
|
6 changes: 0 additions & 6 deletions
6
Ordered Set/OrderedSet.playground/Pages/Example 3.xcplaygroundpage/timeline.xctimeline
This file was deleted.
Oops, something went wrong.
171 changes: 65 additions & 106 deletions
171
Ordered Set/OrderedSet.playground/Sources/OrderedSet.swift
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,117 +1,76 @@ | ||
/* | ||
An Ordered Set is a collection where all items in the set follow an ordering, | ||
usually ordered from 'least' to 'most'. The way you value and compare items | ||
can be user-defined. | ||
*/ | ||
public struct OrderedSet<T: Comparable> { | ||
private var internalSet = [T]() | ||
|
||
public init() { } | ||
|
||
// Returns the number of elements in the OrderedSet. | ||
public var count: Int { | ||
return internalSet.count | ||
} | ||
|
||
// Inserts an item. Performance: O(n) | ||
public mutating func insert(_ item: T) { | ||
if exists(item) { | ||
return // don't add an item if it already exists | ||
} | ||
|
||
// Insert new the item just before the one that is larger. | ||
for i in 0..<count { | ||
if internalSet[i] > item { | ||
internalSet.insert(item, at: i) | ||
return | ||
} | ||
public class OrderedSet<T: Hashable> { | ||
private var objects: [T] = [] | ||
private var indexOfKey: [T: Int] = [:] | ||
|
||
public init() {} | ||
|
||
// O(1) | ||
public func add(_ object: T) { | ||
guard indexOfKey[object] == nil else { | ||
return | ||
} | ||
|
||
// Append to the back if the new item is greater than any other in the set. | ||
internalSet.append(item) | ||
objects.append(object) | ||
indexOfKey[object] = objects.count - 1 | ||
} | ||
|
||
// Removes an item if it exists. Performance: O(n) | ||
public mutating func remove(_ item: T) { | ||
if let index = index(of: item) { | ||
internalSet.remove(at: index) | ||
|
||
// O(n) | ||
public func insert(_ object: T, at index: Int) { | ||
assert(index < objects.count, "Index should be smaller than object count") | ||
assert(index >= 0, "Index should be bigger than 0") | ||
|
||
guard indexOfKey[object] == nil else { | ||
return | ||
} | ||
} | ||
|
||
// Returns true if and only if the item exists somewhere in the set. | ||
public func exists(_ item: T) -> Bool { | ||
return index(of: item) != nil | ||
} | ||
|
||
// Returns the index of an item if it exists, or -1 otherwise. | ||
public func index(of item: T) -> Int? { | ||
var leftBound = 0 | ||
var rightBound = count - 1 | ||
|
||
while leftBound <= rightBound { | ||
let mid = leftBound + ((rightBound - leftBound) / 2) | ||
|
||
if internalSet[mid] > item { | ||
rightBound = mid - 1 | ||
} else if internalSet[mid] < item { | ||
leftBound = mid + 1 | ||
} else if internalSet[mid] == item { | ||
return mid | ||
} else { | ||
// When we get here, we've landed on an item whose value is equal to the | ||
// value of the item we're looking for, but the items themselves are not | ||
// equal. We need to check the items with the same value to the right | ||
// and to the left in order to find an exact match. | ||
|
||
// Check to the right. | ||
for j in stride(from: mid, to: count - 1, by: 1) { | ||
if internalSet[j + 1] == item { | ||
return j + 1 | ||
} else if internalSet[j] < internalSet[j + 1] { | ||
break | ||
} | ||
} | ||
|
||
// Check to the left. | ||
for j in stride(from: mid, to: 0, by: -1) { | ||
if internalSet[j - 1] == item { | ||
return j - 1 | ||
} else if internalSet[j] > internalSet[j - 1] { | ||
break | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
objects.insert(object, at: index) | ||
indexOfKey[object] = index | ||
for i in index+1..<objects.count { | ||
indexOfKey[objects[i]] = i | ||
} | ||
return nil | ||
} | ||
|
||
// Returns the item at the given index. | ||
// Assertion fails if the index is out of the range of [0, count). | ||
public subscript(index: Int) -> T { | ||
assert(index >= 0 && index < count) | ||
return internalSet[index] | ||
|
||
// O(1) | ||
public func object(at index: Int) -> T { | ||
assert(index < objects.count, "Index should be smaller than object count") | ||
assert(index >= 0, "Index should be bigger than 0") | ||
|
||
return objects[index] | ||
} | ||
|
||
// Returns the 'maximum' or 'largest' value in the set. | ||
public func max() -> T? { | ||
return count == 0 ? nil : internalSet[count - 1] | ||
|
||
// O(1) | ||
public func set(_ object: T, at index: Int) { | ||
assert(index < objects.count, "Index should be smaller than object count") | ||
assert(index >= 0, "Index should be bigger than 0") | ||
|
||
guard indexOfKey[object] == nil else { | ||
return | ||
} | ||
|
||
indexOfKey.removeValue(forKey: objects[index]) | ||
indexOfKey[object] = index | ||
objects[index] = object | ||
} | ||
|
||
// Returns the 'minimum' or 'smallest' value in the set. | ||
public func min() -> T? { | ||
return count == 0 ? nil : internalSet[0] | ||
// O(1) | ||
public func indexOf(_ object: T) -> Int { | ||
return indexOfKey[object] ?? -1 | ||
} | ||
|
||
// Returns the k-th largest element in the set, if k is in the range | ||
// [1, count]. Returns nil otherwise. | ||
public func kLargest(_ k: Int) -> T? { | ||
return k > count || k <= 0 ? nil : internalSet[count - k] | ||
|
||
// O(n) | ||
public func remove(_ object: T) { | ||
guard let index = indexOfKey[object] else { | ||
return | ||
} | ||
|
||
indexOfKey.removeValue(forKey: object) | ||
objects.remove(at: index) | ||
for i in index..<objects.count { | ||
indexOfKey[objects[i]] = i | ||
} | ||
} | ||
|
||
// Returns the k-th smallest element in the set, if k is in the range | ||
// [1, count]. Returns nil otherwise. | ||
public func kSmallest(_ k: Int) -> T? { | ||
return k > count || k <= 0 ? nil : internalSet[k - 1] | ||
|
||
public func all() -> [T] { | ||
return objects | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,4 @@ | ||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> | ||
<playground version='6.0' target-platform='ios' display-mode='raw' executeOnSourceChanges='false'> | ||
<pages> | ||
<page name='Example 1'/> | ||
<page name='Example 2'/> | ||
<page name='Example 3'/> | ||
</pages> | ||
<playground version='5.0' target-platform='ios'> | ||
<timeline fileName='timeline.xctimeline'/> | ||
</playground> |
Oops, something went wrong.