Skip to content

Commit

Permalink
Add BinarySearchTree (#160)
Browse files Browse the repository at this point in the history
  • Loading branch information
jsbean authored Sep 2, 2018
1 parent e3239e1 commit 80fb305
Show file tree
Hide file tree
Showing 3 changed files with 178 additions and 0 deletions.
154 changes: 154 additions & 0 deletions Sources/DataStructures/BinarySearchTree.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
//
// BinarySearchTree.swift
// DataStructures
//
// Created by James Bean on 9/1/18.
//

public enum BinarySearchTree <Value: Comparable> {

// MARK: - Cases

case empty
case leaf(Value)
indirect case node(BinarySearchTree, Value, BinarySearchTree)
}

extension BinarySearchTree {

public init <S> (_ sequence: S) where S: Sequence, S.Element == Value {
var tree: BinarySearchTree = .empty
sequence.forEach { tree = tree.inserting($0) }
self = tree
}
}

extension BinarySearchTree {

// MARK: - Computed Properties

/// - Returns: The amount of nodes contained herein.
public var count: Int {
switch self {
case .empty:
return 0
case .leaf:
return 1
case .node(let left, _, let right):
return left.count + 1 + right.count
}
}

/// - Returns: The height of this `BinarySearchTree`.
public var height: Int {
switch self {
case .empty:
return 0
case .leaf:
return 1
case .node(let left, _, let right):
return 1 + max(left.height, right.height)
}
}

/// - Returns: The values of the nodes contained herein in `inOrder` (sorted) order.
///
/// - Complexity: O(*n*)
public var inOrder: [Value] {
func traverse(_ node: BinarySearchTree, into result: [Value]) -> [Value] {
switch node {
case .empty:
return result
case .leaf(let value):
return result + [value]
case .node(let left, let value, let right):
return left.inOrder + [value] + right.inOrder
}
}
return traverse(self, into: [])
}

/// - Returns: The left-most descendent.
public var minDescendent: BinarySearchTree {
var node = self
var prev = node
while case let .node(next, _, _) = node {
prev = node
node = next
}
if case .leaf = node {
return node
}
return prev
}

/// - Returns: The right-most descendent.
public var maxDescendent: BinarySearchTree {
var node = self
var prev = node
while case let .node(_, _, next) = node {
prev = node
node = next
}
if case .leaf = node {
return node
}
return prev
}
}

extension BinarySearchTree {

// MARK: - Instance Methods

/// - Returns: A `BinarySearchTree` with the given `newValue` inserted in the appropriate place.
public func inserting(_ newValue: Value) -> BinarySearchTree {
switch self {
case .empty:
return .leaf(newValue)
case .leaf(let value):
if newValue < value {
return .node(.leaf(newValue), value, .empty)
} else {
return .node(.empty, value, .leaf(newValue))
}
case .node(let left, let value, let right):
if newValue < value {
return .node(left.inserting(newValue), value, right)
} else {
return .node(left, value, right.inserting(newValue))
}
}
}

/// - Returns: `true` if this `BinarySearchTree` contains the given `value`. Otherwise, `false`.
public func contains(_ value: Value) -> Bool {
return search(for: value) != nil
}

/// - Returns: The `BinarySearchTree` which contains the given `target`, if it exists.
/// Otherwise, `nil`.
public func search(for target: Value) -> BinarySearchTree? {
switch self {
case .empty:
return nil
case .leaf(let value):
return target == value ? self : nil
case .node(let left, let value, let right):
if target < value {
return left.search(for: target)
} else if value < target {
return right.search(for: target)
} else {
return self
}
}
}
}

extension BinarySearchTree: ExpressibleByArrayLiteral {

public init(arrayLiteral elements: Value...) {
self.init(elements)
}
}
17 changes: 17 additions & 0 deletions Tests/DataStructuresTests/BinarySearchTreeTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//
// BinarySearchTreeTests.swift
// DataStructuresTests
//
// Created by James Bean on 9/1/18.
//

import XCTest
import DataStructures

class BinarySearchTreeTests: XCTestCase {

func testInitSequence() {
let bst: BinarySearchTree<Int> = [5,1,4,3,2,6,7]
XCTAssertEqual(bst.inOrder, [1,2,3,4,5,6,7])
}
}
7 changes: 7 additions & 0 deletions Tests/DataStructuresTests/XCTestManifests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ extension BinaryHeapTests {
]
}

extension BinarySearchTreeTests {
static let __allTests = [
("testInitSequence", testInitSequence),
]
}

extension CircularArrayTests {
static let __allTests = [
("testCollection", testCollection),
Expand Down Expand Up @@ -458,6 +464,7 @@ public func __allTests() -> [XCTestCaseEntry] {
testCase(ArrayExtensionsTests.__allTests),
testCase(BimapTests.__allTests),
testCase(BinaryHeapTests.__allTests),
testCase(BinarySearchTreeTests.__allTests),
testCase(CircularArrayTests.__allTests),
testCase(ContiguousSegmentCollectionTests.__allTests),
testCase(DictionaryProtocolsTests.__allTests),
Expand Down

0 comments on commit 80fb305

Please sign in to comment.