0

I am trying to implement a BST that stores a list of words. I know that my tree structure is correct because when I try to traverse and print in order, the list prints alphabetically. However, my search function for looking for an element in a tree returns false each time.

func search(searchValue: String) -> Bool? {
    if searchValue == value as! String{
        return true
    }

    if searchValue < value as! String {
        return left?.search(searchValue: searchValue)
    }
    if searchValue > value as! String{
        return right?.search(searchValue: searchValue)
    }

    return false


}

The function is called in this loop. Every word not in the BST should be appended to an array misspelled. Currently no words are appended to the array. Input array is an array of all the words to be checked against the BST.

 for item in arrayInput
        {
            let target = item.lowercased()//reversed
            let inTree = tree.search(searchValue: target)
            if inTree == false
            {
                misspelled.append(item)
            }
        }

More BST class for context:

  public class BinarySearchTree<T: Comparable> {
        fileprivate(set) public var value: T
        fileprivate(set) public var parent: BinarySearchTree?
        fileprivate(set) public var left: BinarySearchTree?
        fileprivate(set) public var right: BinarySearchTree?


        public init(value: T) {
            self.value = value
        }

        public convenience init(array: [T]) {
            precondition(array.count > 0)
            self.init(value: array.first!)
            for v in array.dropFirst() {
                insert(value: v)
            }
        }

        }
     public func insert(value: T) {
            if value < self.value {
                if let left = left {
                    left.insert(value: value)
                } else {
                    left = BinarySearchTree(value: value)
                    left?.parent = self
                }
            } else {
                if let right = right {
                    right.insert(value: value)
                } else {
                    right = BinarySearchTree(value: value)
                    right?.parent = self
                }
            }
        }
6
  • What's with the "as String!"'s everywhere? Your BST is generic Commented Mar 31, 2017 at 19:12
  • Also, your strong references to parent will cause a retain cycle, and as a result, a memory leak. Commented Mar 31, 2017 at 19:12
  • I am unsure how to do the comparisons without it. Without as! String I get a message "binary operator < can't be applied to types 'T' and 'String' Commented Mar 31, 2017 at 19:14
  • Well your search function searches for strings in particular, so it shouldn't be defined in the generic class. Instead, it should be an extension to the class, where T is constrained to be a string. I can demonstrate this later, if you need Commented Mar 31, 2017 at 19:42
  • That would actually be very helpful @Alexander I am rather new to swift Commented Apr 1, 2017 at 19:50

3 Answers 3

1

I've made some improvements to your code, take a look:

public class BinarySearchTree<T: Comparable> {
    fileprivate(set) public var value: T
    fileprivate(set) public var parent: BinarySearchTree?
    fileprivate(set) public var left: BinarySearchTree?
    fileprivate(set) public var right: BinarySearchTree?


    public init(value: T) {
        self.value = value
    }

    public convenience init(array: [T]) {
        precondition(array.count > 0)
        self.init(value: array.first!)
        for v in array.dropFirst() {
            insert(value: v)
        }
    }

    // Refactored out common code to reduce duplicaiton
    public func insert(value: T) {
        let nodeToModify = value < self.value ? left : right

        if let nodeToModify = nodeToModify {
            nodeToModify.insert(value: value)
        }
        else {
            let subtree = BinarySearchTree(value: value)
            subtree.parent = self
            self.left = subtree
        }
    }


    // Why constrain searching to just Strings? Keep it generic to all T: Comparable
    func search(for searchValue: T) -> Bool {
        if searchValue == value { return true }

        if searchValue < value {
            return left?.search(for: searchValue) ?? false
        }
        if searchValue > value {
            return right?.search(for: searchValue) ?? false
        }

        return false
    }
}

// Move the `search` function outside of the class, and into an extension
// with the constaint that `T == String`
extension BinarySearchTree where T == String {
    func search(for searchValue: String) -> Bool {
        if searchValue == value { return true }

        if searchValue < value {
            return left?.search(for: searchValue) ?? false
        }
        if searchValue > value {
            return right?.search(for: searchValue) ?? false
        }

        return false
    }
}
Sign up to request clarification or add additional context in comments.

Comments

1

I believe the issue is that you are reaching the leaf node of your binary search tree and then returning nil. The misspelled word is either less than or greater than the stored value of the leaf, so you are looking for the left or right child and those values are nil so the function is returning nil.

There are several ways you could go about fixing this, but the simplest change would be to nil coalesce to false when the left or right is nil.

func search(searchValue: String) -> Bool {
    if searchValue == value as! String {
        return true
    }

    if searchValue < value as! String {
        return left?.search(searchValue: searchValue) ?? false
    }
    if searchValue > value as! String {
        return right?.search(searchValue: searchValue) ?? false
    }

    return false
}

3 Comments

@vacawama how? If the searchvalue < value (the only way that the left tree code block will be entered) than the search value can't be in the right tree.
You're right. I retract my comment. And upvote your answer.
There is no longer a need for search to return an optional since all of your returns are true are false.
1

Please find my Binary search tree implementation in Swift 4

class SearchTreeNode<T: Comparable>{
  private var element: T
  var parent: SearchTreeNode?
  var left: SearchTreeNode?
  var right: SearchTreeNode?

  init(value _element: T, parent: SearchTreeNode<T>?) {
    element = _element
    self.parent = parent
  }

  func value() -> T {
    return element
  }
}

class BinarySearchTree<T: Comparable>{
  var root: SearchTreeNode<T>

  init(rootValue _element: T) {
    root = SearchTreeNode(value: _element, parent: nil)
  }

  func append(value: T)  {
    addValue(toTree: root, _element: value)
  }

  func isPresent(element: T) {
    if let node = search(for: element, nodeToSearch: root){
      print(node.right?.value())
      print(node.left?.value())
      print(node.parent?.value())
      print("Item is presnt in search tree")
    }else{
      print("Item not presnt in search tree")
    }
  }

  private func addValue(toTree currentNode: SearchTreeNode<T>, _element: T){
    if currentNode.value() == _element {
      print("Already Presnt")
    }else if currentNode.value() > _element {
      if currentNode.left == nil {
        currentNode.left = SearchTreeNode(value: _element, parent: currentNode)
      }else{
        addValue(toTree: currentNode.left!, _element: _element)
      }
    }else if currentNode.value() < _element{
      if currentNode.right == nil {
        currentNode.right = SearchTreeNode(value: _element, parent: currentNode)
      }else{
        addValue(toTree: currentNode.right!, _element: _element)
      }
    }
  }

  private func search(for _element: T, nodeToSearch node: SearchTreeNode<T>) -> SearchTreeNode<T>?{
    if node.value() == _element {
      return node
    }else if node.value() > _element {
      if node.left == nil {
        return nil
      }else{
        return search(for: _element, nodeToSearch: node.left!)
      }
    }else if node.value() < _element{
      if node.right == nil {
        return nil
      }else{
        return search(for: _element, nodeToSearch: node.right!)
      }
    }else{
      return nil
    }
  }

  func getRightMostNode(forNode node: SearchTreeNode<T>) -> SearchTreeNode<T> {
    if node.right != nil {
      return getRightMostNode(forNode: node.right!)
    }
    return node
  }

  func delete(_element: T){
    if let node = search(for: _element, nodeToSearch: root) {
      if (node.left != nil) && (node.right != nil) {
        var rightMostNode = getRightMostNode(forNode: node.left!)
        rightMostNode.right = node.right
        node.left?.parent = node.parent
        (node.parent?.left?.value() == _element) ? (node.parent?.left = node.left) : (node.parent?.right = node.left)
      }else if (node.left != nil) {
        node.left?.parent = node.parent
        (node.parent?.left?.value() == _element) ? (node.parent?.left = node.left) : (node.parent?.right = node.left)
      }else if (node.right != nil){
        node.right?.parent = node.parent
        (node.parent?.left?.value() == _element) ? (node.parent?.left = node.right) : (node.parent?.right = node.right)
      }else{
        (node.parent?.left?.value() == _element) ? (node.parent?.left = nil) : (node.parent?.right = nil)
      }
    }else{
      print("Element for deletion is not present")
    }
  }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.