Swift Binary Search Tree

Filed Under: Swift

In this tutorial, we’ll be discussing Binary trees and the implement the various operations that can be performed using it in Swift.

Binary Search Tree

A Binary Search Tree in Swift is a Binary Tree which must follow the following rules:

All nodes in the left subtree must have lesser value than the value in the root node.
All node in the right subtree must have greater value than the value in the root node.
Left and Right subtrees of root node should follow the above rules recursively.

They typically provide OLogN time for insertion and lookup.

Swift Binary Search Tree Implementation

Let’s define the Node for a tree.


class Node<T> {
    
    var data: T
    var leftNode: Node?
    var rightNode: Node?
    
    init(data: T,
         leftNode: Node? = nil,
         rightNode: Node? = nil) {
        self.data = data
        self.leftNode = leftNode
        self.rightNode = rightNode
    }

}

Let’s define the BinarySearchTree class in Swift. Here we’ll define functions to insert Nodes into the tree taking care of the BST rules:


class BST<T: Comparable & CustomStringConvertible> {
    
    private var rootNode: Node<T>?
    
    func addNode(_ value: T) {
        let node = Node(data: value)
        if let rootNode = self.rootNode {
            self.insert(rootNode, node)
        } else {
            self.rootNode = node
        }
    }
    

    private func insert(_ root: Node<T>, _ node: Node<T>) {
        if root.data > node.data {
            if let leftNode = root.leftNode {
                self.insert(leftNode, node)
            } else {
                root.leftNode = node
            }
        } else {
            if let rightNode = root.rightNode {
                self.insert(rightNode, node)
            } else {
                root.rightNode = node
            }
        }
    }
    
    func printTree() {
        self.inorder(self.rootNode)
    }

    
    private func inorder(_ node: Node<T>?) {
        guard let _ = node else { return }
        self.inorder(node?.leftNode)
        print("\(node!.data)", terminator: " ")
        self.inorder(node?.rightNode)
    }
}

We’ve assigned the Comparable and CustomStringConvertible protocols in order to compare the values of the Nodes and print the formatted data respectively.

The inorder function prints the left subtree followed by the current node value, followed by right subtree

Now let’s add elements into the tree.


let numberList : Array<Int> = [8, 2, 10, 9, 11, 1, 7]
var root = BST<Int>()
for number in numberList {
    root.addNode(number)
}
//should print sorted tree
root.printTree()

The output of the tree is:
swift binary search tree print

As you can see the values in the BST are set in a sorted order.

Searching a value in the tree


extension BST {
    
    func search(value: T) {
        self.search(self.rootNode, value)
    }
    
    private func search(_ root: Node<T>?, _ element: T) {
        
        guard let rootNode = root else {
            print("NODE is Not available : \(element)")
            return
        }
        
        print("current root node \(rootNode.data)")
        if element > rootNode.data {
            self.search(rootNode.rightNode, element)
        } else if element < rootNode.data {
            self.search(rootNode.leftNode, element)
        } else {
            print("NODE VALUE AVAILABLE : \(rootNode.data)")
        }
    }
}

We’ve created a search function in the extension.
In this, we simply check the node value and based on the comparison, search it recursively in the left or right subtree.

The output of two sample runs is:

swift binary search tree search elements

Deleting a Node

Implementation of Deleting a Node in a BST is a little more tricky.

After the node is deleted, we need to rearrange the BST so that it stays sorted.
Use the following rule for deletion:

After removing a node, we replace the node with either its biggest child on the left or its smallest child on the right subtree.

This means we need to first create functions in our Node class for the minimum and maximum node of the tree.
The following illustration contains the updated class Node.
swift binary search tree node class

And now we create another extension of the BST class for the deletion function which works recursively:


extension BST{
    
    func deleteKey(value: T)
    {
    rootNode = deleteRec(rootNode, value)
    }
    
    /* A recursive function to insert a new key in BST */
    func deleteRec(_ root: Node<T>?, _ key: T) -> Node<T>?
    {
    /* Base Case: If the tree is empty */
        if  root == nil{
        return root
        }
    
        if key < (root?.data)! {
        root?.leftNode = deleteRec(root?.leftNode, key)
        }
        else if key > (root?.data)!{
            root?.rightNode = deleteRec(root?.rightNode, key)
            }
    else
    {
        if root?.leftNode == nil{
            return root?.rightNode
        }
        else if root?.rightNode == nil{
            return root?.leftNode
        }
        
    root?.data = (minValue(root?.rightNode))!
    root?.rightNode = deleteRec(root?.rightNode, (root?.data)!)
    }
    
    return root;
    }
    
    public func minValue(_ node: Node<T>?) -> T? {
        
        var tempNode = node
        
        while let next = tempNode?.leftNode {
            tempNode = next
        }
        return tempNode?.data
    }
    
}

The output when deleting the first key is:
swift binary search tree delete node

That’s all for Swift Binary Search Tree implementation.

Comments

  1. rani sofyan says:

    what is the Swift Binary Search Tree used for?

Leave a Reply

Your email address will not be published. Required fields are marked *

close
Generic selectors
Exact matches only
Search in title
Search in content
Search in posts
Search in pages