简体   繁体   中英

Swift Binary Search Tree Search

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
                }
            }
        }

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
}

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
    }
}

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")
    }
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM