Skip to content

Commit

Permalink
Split sorted set and ordered set
Browse files Browse the repository at this point in the history
  • Loading branch information
remlostime committed Nov 19, 2017
1 parent d7f172a commit 95b45f0
Show file tree
Hide file tree
Showing 21 changed files with 738 additions and 732 deletions.

This file was deleted.

4 changes: 0 additions & 4 deletions Ordered Set/AppleOrderedSet.playground/contents.xcplayground

This file was deleted.

76 changes: 0 additions & 76 deletions Ordered Set/AppleOrderedSet.swift

This file was deleted.

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)
Expand Down

This file was deleted.

171 changes: 65 additions & 106 deletions Ordered Set/OrderedSet.playground/Sources/OrderedSet.swift
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
}
}
8 changes: 2 additions & 6 deletions Ordered Set/OrderedSet.playground/contents.xcplayground
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>
Loading

0 comments on commit 95b45f0

Please sign in to comment.