May 10, 2020

Tree in Swift

Tree data structure is something I am sure every programmer has implemented at least once (though more for interviews than in job 😁). Nevertheless let's see how to represent a binary tree in Swift.

A binary tree is a specific form of tree data structure where each node has at most two children which are referred to as the left child and the right child. [Ref]

You probably figured out from the definition that left and right children are itself Trees, so let's start with a class which is a Ref type (with a value type like structure we cannot represent a Tree, which means an infinite size memory)

class TreeClass<T> {
    var data: T
    var left: TreeClass<T>?
    var right: TreeClass<T>?

    init(data: T, left: TreeClass<T>?, right: TreeClass<T>?) {
        self.data = data
        self.left = left
        self.right = right
    }
}

Now represent a tree with root (3) left child (1) and right child (2)

let tree11 = TreeC(data: 1, left: nil, right: nil)
let tree22 = TreeC(data: 2, left: nil, right: nil)
let tree33 = TreeC(data: 3, left: tree11, right: tree22)

Let's write a preorder traversal algorithm

func preorder<T>(tree: TreeC<T>?) {
    guard let t = tree else {
        return
    }
    print(t.data)
    preorder(tree: t.left)
    preorder(tree: t.right)
}

In Swift there is another (better) way to represent recursive data structures like Tree and that is called Indirect enum

With it an enum case can refer to itself which essentially is possible as compiler internally make it like a reference type. (for normal enums which are value type, internally compiler treat them as C unions )

indirect enum Tree<T> {
  case Nil
  case Node(value: T ,left: Tree<T> ,right: Tree<T>)
}

Much better, right?

Same tree representation

let tree1 = Tree.Node(value: 1, left: Tree.Nil, right: Tree.Nil)
let tree2 = Tree.Node(value: 2, left: Tree.Nil, right: Tree.Nil)
let tree3 = Tree.Node(value: 3, left: tree1, right: tree2)

And preorder algorithm

func preorder<T>(tree:Tree<T>) {
    switch tree {
    case .Nil:
        break;
    case .Node(let value, let left, let right):
        print(value)
        preorder(tree: left)
        preorder(tree: right)
    }
}

Swift is evolving very fast and has so many features that sometime we miss to use the best feature available for a given problem.

Tagged with: