RosettaCodeData/Task/AVL-tree/Swift/avl-tree.swift
2025-08-11 18:05:26 -07:00

243 lines
7 KiB
Swift
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import Foundation
// MARK: - AVL Tree ---------------------------------------------------------
final class AVLTree {
// ---------- Node ------------------------------------------------------
private class Node {
var key: Int
var balance: Int = 0
var height: Int = 0
var left: Node?
var right: Node?
weak var parent: Node? // weak to avoid retain cycles
init(key: Int, parent: Node?) {
self.key = key
self.parent = parent
}
}
// ---------- Root -------------------------------------------------------
private var root: Node?
// ---------- Public API -------------------------------------------------
/// Inserts `key`. Returns `true` if the key was added, `false` if it already existed.
@discardableResult
func insert(_ key: Int) -> Bool {
// empty tree new root
guard let rootNode = root else {
root = Node(key: key, parent: nil)
return true
}
var n: Node? = rootNode
while let cur = n {
if cur.key == key { return false } // duplicate
let goLeft = key < cur.key
let parent = cur
n = goLeft ? cur.left : cur.right
// we have found the empty spot insert
if n == nil {
let newNode = Node(key: key, parent: parent)
if goLeft {
parent.left = newNode
} else {
parent.right = newNode
}
rebalance(parent) // fix AVL balance upwards
break
}
}
return true
}
/// Deletes `key` if it exists. Does nothing when the key is not present.
func delete(_ key: Int) {
var current = root
while let node = current {
if key == node.key {
delete(node) // internal helper that really removes the node
return
}
current = (key < node.key) ? node.left : node.right
}
// key not found nothing to do
}
/// Prints the balance factor of every node inorder.
func printBalance() {
printBalance(node: root)
}
// ---------- Private helpers -------------------------------------------
/// Removes `node` from the tree (used by the public `delete(_:)` above).
private func delete(_ node: Node) {
// ----- 1 leaf node ------------------------------------------------
if node.left == nil && node.right == nil {
if let parent = node.parent {
if parent.left === node { parent.left = nil }
else { parent.right = nil }
rebalance(parent)
} else {
root = nil // tree becomes empty
}
return
}
// ----- 2 node has a left subtree replace with predecessor -----
if let left = node.left {
var predecessor = left
while let r = predecessor.right { predecessor = r }
node.key = predecessor.key
delete(predecessor)
}
// ----- 3 otherwise it has a right subtree replace with successor
else if let right = node.right {
var successor = right
while let l = successor.left { successor = l }
node.key = successor.key
delete(successor)
}
}
/// Walks upward from `n`, fixing heights, balances and performing rotations.
private func rebalance(_ n: Node) {
setBalance(of: n)
var node = n
if node.balance == -2 {
// left heavy
if height(of: node.left?.left) >= height(of: node.left?.right) {
node = rotateRight(node)
} else {
node = rotateLeftThenRight(node)
}
} else if node.balance == 2 {
// right heavy
if height(of: node.right?.right) >= height(of: node.right?.left) {
node = rotateLeft(node)
} else {
node = rotateRightThenLeft(node)
}
}
// continue upwards or make this node the new root
if let parent = node.parent {
rebalance(parent)
} else {
root = node
}
}
// ---------- Rotations -------------------------------------------------
private func rotateLeft(_ a: Node) -> Node {
guard let b = a.right else { return a } // safety guard
// detach b from a
b.parent = a.parent
a.right = b.left
a.right?.parent = a
// attach a under b
b.left = a
a.parent = b
// reconnect b with the rest of the tree
if let p = b.parent {
if p.left === a {
p.left = b
} else {
p.right = b
}
}
setBalance(of: a, b)
return b
}
private func rotateRight(_ a: Node) -> Node {
guard let b = a.left else { return a } // safety guard
b.parent = a.parent
a.left = b.right
a.left?.parent = a
b.right = a
a.parent = b
if let p = b.parent {
if p.left === a {
p.left = b
} else {
p.right = b
}
}
setBalance(of: a, b)
return b
}
private func rotateLeftThenRight(_ n: Node) -> Node {
if let left = n.left {
n.left = rotateLeft(left)
}
return rotateRight(n)
}
private func rotateRightThenLeft(_ n: Node) -> Node {
if let right = n.right {
n.right = rotateRight(right)
}
return rotateLeft(n)
}
// ---------- Height / Balance helpers ----------------------------------
/// Height of a node `-1` for `nil` (matches the Java implementation).
private func height(of node: Node?) -> Int {
node?.height ?? -1
}
/// Recomputes stored height of `node`.
private func reheight(_ node: Node?) {
guard let node = node else { return }
node.height = 1 + max(height(of: node.left), height(of: node.right))
}
/// Updates both `height` and `balance` for every supplied node.
private func setBalance(of nodes: Node...) {
for n in nodes {
reheight(n)
n.balance = height(of: n.right) - height(of: n.left)
}
}
// ---------- Printing ---------------------------------------------------
private func printBalance(node: Node?) {
guard let node = node else { return }
printBalance(node: node.left)
print("\(node.balance) ", terminator: "")
printBalance(node: node.right)
}
}
// MARK: - Demo -------------------------------------------------------------
let tree = AVLTree()
print("Inserting values 1 to 10")
for i in 1...10 {
_ = tree.insert(i)
}
print("Printing balance: ", terminator: "")
tree.printBalance()
print() // newline