1. Introduction
An AVL Tree is a self-balancing binary search tree. In an AVL Tree, the height difference (or balance factor) between the left and right subtrees of any node is no more than one, ensuring that the tree remains approximately balanced. As a result, the tree maintains logarithmic height, ensuring fast operations like insertion, deletion, and look-up.
2. Implementation Steps
1. Define a Node class with additional attributes for height and balance factor.
2. Define an AVLTree class that will manage the nodes.
3. Implement rotation methods: left, right, left-right, and right-left rotations to maintain balance.
4. Implement the insert method, ensuring that the tree remains balanced after each insertion.
3. Implementation in Swift
// 1. Definition of the Node class class AVLNode<T: Comparable> { var value: T var left: AVLNode? var right: AVLNode? var height: Int init(value: T) { self.value = value self.height = 1 // New node is a leaf node with height 1 } } // 2. Definition of the AVLTree class class AVLTree<T: Comparable> { var root: AVLNode<T>? // Helper function to get the height of a node private func height(_ node: AVLNode<T>?) -> Int { return node?.height ?? 0 } // Helper function to get the balance factor of a node private func getBalance(_ node: AVLNode<T>?) -> Int { return height(node?.left) - height(node?.right) } // 3. Implementing rotations // Right rotation private func rightRotate(_ y: AVLNode<T>) -> AVLNode<T> { let x = y.left! let T3 = x.right x.right = y y.left = T3 y.height = max(height(y.left), height(y.right)) + 1 x.height = max(height(x.left), height(x.right)) + 1 return x } // Left rotation private func leftRotate(_ x: AVLNode<T>) -> AVLNode<T> { let y = x.right! let T2 = y.left y.left = x x.right = T2 x.height = max(height(x.left), height(x.right)) + 1 y.height = max(height(y.left), height(y.right)) + 1 return y } // 4. Insert method func insert(value: T) { root = insert(node: root, value: value) } private func insert(node: AVLNode<T>?, value: T) -> AVLNode<T> { if node == nil { return AVLNode(value: value) } if value < node!.value { node!.left = insert(node: node!.left, value: value) } else if value > node!.value { node!.right = insert(node: node!.right, value: value) } else { return node! // Duplicates are not allowed } node!.height = 1 + max(height(node!.left), height(node!.right)) let balance = getBalance(node) // Left heavy if balance > 1 { if value < node!.left!.value { return rightRotate(node!) } else { node!.left = leftRotate(node!.left!) return rightRotate(node!) } } // Right heavy if balance < -1 { if value > node!.right!.value { return leftRotate(node!) } else { node!.right = rightRotate(node!.right!) return leftRotate(node!) } } return node! } } // Example Usage let avlTree = AVLTree<Int>() avlTree.insert(value: 10) avlTree.insert(value: 20) avlTree.insert(value: 30) // After these insertions, a right rotation occurs to balance the tree.
Output:
The AVL tree is balanced after each insertion, ensuring that the height difference between the left and right subtrees of any node is at most one.
Explanation:
1. The AVLNode class represents each node in the AVL tree. In addition to the value and child references, each node has a height attribute to store its height in the tree.
2. The AVLTree class manages the root node and provides methods to interact with the tree.
3. For the AVL tree to remain balanced, rotations are implemented. The rotation needed depends on whether the left or right subtrees are heavy.
- rightRotate is used when the left subtree is heavy.
- leftRotate is used when the right subtree is heavy.
4. The insert method adds a node to the tree. After each insertion, it checks the balance factor of each node and performs necessary rotations.
The primary advantage of an AVL tree over a regular binary search tree is that it ensures a balanced tree, which guarantees O(log n) time complexities for insertions, deletions, and look-ups.
Comments
Post a Comment