Swift Program to Implement Tree Sort

Swift Program to Implement Tree Sort

Tree Sort is a simple yet elegant sorting algorithm that uses a binary search tree (BST) to arrange data in order. The algorithm works by first inserting all elements of an array into a BST. Then, an in-order traversal of the tree produces the elements in sorted order. Because of its use of trees, Tree Sort can be faster than simple algorithms like Bubble Sort or Insertion Sort for large datasets, especially when the tree is balanced.

Pluralsight Logo
Accelerate your tech career
with hands-on learning.
Whether you're a tech newbie or a total pro,
get the skills and confidence to land your next move.
Start 10-Day Free Trial

Tree Sort is widely used in situations where data naturally fits into a hierarchical structure, such as file systems or search trees. For beginners, learning Tree Sort provides a good introduction to both sorting techniques and binary trees. It also helps build a strong foundation for understanding more advanced data structures like AVL trees or Red-Black trees.

Program 1: Basic Tree Sort Using Recursive Insertion

This program demonstrates a straightforward Tree Sort using a binary search tree and recursion. It inserts integers into a BST and then retrieves them in sorted order through in-order traversal.

import Foundation

class TreeNode {

    var value: Int
    var left: TreeNode?
    var right: TreeNode?

    init(_ value: Int) {
        self.value = value
    }

}

func insert(_ root: TreeNode?, _ value: Int) -> TreeNode {

    guard let root = root else { return TreeNode(value) }

    if value < root.value {
        root.left = insert(root.left, value)
    } else {
        root.right = insert(root.right, value)
    }

    return root

}

func inorderTraversal(_ root: TreeNode?, _ result: inout [Int]) {

    guard let root = root else { return }

    inorderTraversal(root.left, &result)

    result.append(root.value)

    inorderTraversal(root.right, &result)

}

let data = [42, 15, 33, 7, 51, 27]
var root: TreeNode?

for value in data {
    root = insert(root, value)
}

var sortedData = [Int]()

inorderTraversal(root, &sortedData)

print("Sorted data:", sortedData)

This program works by building a binary search tree recursively. Each new value is placed in the correct position in the tree, and then in-order traversal collects the values in ascending order. Beginners can easily see how recursion and tree structures interact to perform sorting.

Program 2: Tree Sort with Strings

This program shows that Tree Sort can be applied not only to numbers but also to strings. It uses the same logic of a BST and in-order traversal.

import Foundation

class StringNode {

    var value: String
    var left: StringNode?
    var right: StringNode?

    init(_ value: String) {
        self.value = value
    }

}

func insert(_ root: StringNode?, _ value: String) -> StringNode {

    guard let root = root else { return StringNode(value) }

    if value < root.value {
        root.left = insert(root.left, value)
    } else {
        root.right = insert(root.right, value)
    }

    return root

}

func inorderTraversal(_ root: StringNode?, _ result: inout [String]) {

    guard let root = root else { return }

    inorderTraversal(root.left, &result)

    result.append(root.value)

    inorderTraversal(root.right, &result)

}

let names = ["Alice", "Charlie", "Bob", "Eve", "David"]
var nameRoot: StringNode?

for name in names {
    nameRoot = insert(nameRoot, name)
}

var sortedNames = [String]()

inorderTraversal(nameRoot, &sortedNames)

print("Sorted names:", sortedNames)

By using Tree Sort on strings, beginners can understand that the sorting logic is not limited to numbers. The algorithm relies on a comparison operator, so it works for any comparable data type.

Program 3: Tree Sort Using Iterative Insertion

In this version, the insertion into the BST is done iteratively instead of recursively. This can prevent stack overflow for large datasets.

import Foundation

class IterNode {

    var value: Int
    var left: IterNode?
    var right: IterNode?

    init(_ value: Int) {
        self.value = value
    }

}

func insertIterative(_ root: IterNode?, _ value: Int) -> IterNode {

    if root == nil { return IterNode(value) }
    var current = root

    while true {

        if value < current!.value {

            if current!.left == nil {
                current!.left = IterNode(value)
                break
            } else {
                current = current!.left
            }

        } else {

            if current!.right == nil {
                current!.right = IterNode(value)
                break
            } else {
                current = current!.right
            }

        }

    }


    return root!

}

func inorderIterative(_ root: IterNode?) -> [Int] {

    var stack: [IterNode] = []
    var result: [Int] = []
    var current = root

    while current != nil || !stack.isEmpty {

        while current != nil {
            stack.append(current!)
            current = current?.left
        }

        current = stack.popLast()

        result.append(current!.value)

        current = current?.right

    }

    return result

}

let numbers = [12, 5, 8, 20, 15]
var iterRoot: IterNode?

for n in numbers {
    iterRoot = insertIterative(iterRoot, n)
}

let sortedNumbers = inorderIterative(iterRoot)

print("Sorted numbers (iterative):", sortedNumbers)

Using iterative insertion is helpful for beginners to understand that recursion is not mandatory. This approach also helps avoid stack depth issues for very large datasets.

Program 4: Generic Tree Sort Using Comparable Types

This version demonstrates a generic Tree Sort that can handle any type conforming to the Comparable protocol, such as integers, doubles, or strings.

import Foundation

class GenericNode<T: Comparable> {

    var value: T
    var left: GenericNode?
    var right: GenericNode?

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

}

func insert<T: Comparable>(_ root: GenericNode<T>?, _ value: T) -> GenericNode<T> {

    guard let root = root else { return GenericNode(value) }

    if value < root.value {
        root.left = insert(root.left, value)
    } else {
        root.right = insert(root.right, value)
    }

    return root

}

func inorderTraversal<T>(_ root: GenericNode<T>?, _ result: inout [T]) {

    guard let root = root else { return }

    inorderTraversal(root.left, &result)

    result.append(root.value)

    inorderTraversal(root.right, &result)

}

let mixedData: [Double] = [3.5, 1.2, 4.8, 2.0, 0.9]
var genericRoot: GenericNode<Double>?

for value in mixedData {
    genericRoot = insert(genericRoot, value)
}

var sortedMixed: [Double] = []

inorderTraversal(genericRoot, &sortedMixed)

print("Sorted doubles (generic):", sortedMixed)

This generic approach is useful for beginners to see how Swift generics allow a single sorting function to work with multiple data types while keeping the code clean and reusable.

Program 5: Tree Sort Using Tuples with Custom Key

Here, Tree Sort is applied to tuples by using a key for comparison. This allows sorting complex data based on a specific attribute.

import Foundation

class TupleNode<T: Comparable, U> {

    var value: (T, U)
    var left: TupleNode?
    var right: TupleNode?

    init(_ value: (T, U)) {
        self.value = value
    }

}

func insert<T: Comparable, U>(_ root: TupleNode<T, U>?, _ value: (T, U)) -> TupleNode<T, U> {

    guard let root = root else { return TupleNode(value) }

    if value.0 < root.value.0 {
        root.left = insert(root.left, value)
    } else {
        root.right = insert(root.right, value)
    }

    return root

}

func inorderTraversal<T, U>(_ root: TupleNode<T, U>?, _ result: inout [(T, U)]) {

    guard let root = root else { return }

    inorderTraversal(root.left, &result)

    result.append(root.value)

    inorderTraversal(root.right, &result)

}

let people: [(String, Int)] = [("Alice", 3), ("Bob", 1), ("Charlie", 2)]
var tupleRoot: TupleNode<Int, String>?

for person in people {
    tupleRoot = insert(tupleRoot, (person.1, person.0))
}

var sortedPeople: [(Int, String)] = []

inorderTraversal(tupleRoot, &sortedPeople)

print("Sorted by score:", sortedPeople)

Using tuples with Tree Sort demonstrates that the algorithm can sort any complex structure, as long as there is a comparable key. Beginners can see how sorting can be customized without changing the underlying tree logic.

Frequently Asked Questions (FAQ)

This section answers some common questions about Tree Sort and its applications.

Q1: Is Tree Sort efficient for large datasets?
Tree Sort is efficient when the binary tree is balanced, giving an average time complexity of O(n log n). For unbalanced trees, the worst case is O(n²).

Q2: Can Tree Sort handle duplicate elements?
Yes, duplicates can be inserted either to the left or right consistently. The in-order traversal will include all duplicates in sorted order.

Q3: Is Tree Sort stable?
Tree Sort is not stable by default. If stability is required, additional logic is needed to maintain insertion order for equal elements.

Q4: Can Tree Sort be applied to strings or custom objects?
Absolutely. As long as the data type conforms to Comparable, Tree Sort works for numbers, strings, tuples, or other objects with a comparable key.

Q5: Should I use recursion or iteration for Tree Sort?
Recursion is simpler and easier to understand for beginners. Iteration avoids stack overflow for large datasets and is more suitable for production-level code.

Conclusion

Tree Sort is a versatile and educational algorithm that introduces both sorting and binary trees. By understanding how to insert elements into a binary search tree and perform in-order traversal, beginners can grasp fundamental programming concepts like recursion, iteration, and generics. Whether sorting integers, doubles, strings, or custom objects, Tree Sort offers a clear, structured approach to organizing data. Practicing with Tree Sort also lays a foundation for learning more advanced tree-based algorithms, making it a valuable tool in any programmer’s toolkit.

Scroll to Top