RosettaCodeData/Task/AVL-tree/Swift/avl-tree.swift

244 lines
7 KiB
Swift
Raw Permalink Normal View History

2025-08-11 18:05:26 -07:00
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