diff --git a/Data Structures.playground/Pages/Red-Black Tree.xcplaygroundpage/Content.swift b/Data Structures.playground/Pages/Red-Black Tree.xcplaygroundpage/Content.swift new file mode 100644 index 0000000..5a0919c --- /dev/null +++ b/Data Structures.playground/Pages/Red-Black Tree.xcplaygroundpage/Content.swift @@ -0,0 +1,256 @@ +import Foundation + +class RedBlackTreeNode { + var value: T + var isRed: Bool + var left: RedBlackTreeNode? + var right: RedBlackTreeNode? + + init(value: T, isRed: Bool, left: RedBlackTreeNode?, right: RedBlackTreeNode?) { + self.value = value + self.isRed = isRed + self.left = left + self.right = right + } + + static func isRedNode(node: RedBlackTreeNode?) -> Bool { + if (node == nil) { + return false + } + return node!.isRed + } + + func clockwiseRotate() -> RedBlackTreeNode { + let t = self.left! + self.left = t.right + t.right = self + t.isRed = RedBlackTreeNode.isRedNode(node: t.right) + t.right!.isRed = true + return t + } + + func counterclockwiseRotate() -> RedBlackTreeNode { + let t = self.right! + self.right = t.left + t.left = self + t.isRed = RedBlackTreeNode.isRedNode(node: t.left) + t.left!.isRed = true + return t + } + + func flip() { + self.isRed = !self.isRed + } + + func exchange() { + self.flip() + self.left?.flip() + self.right?.flip() + } + + func minimum() -> RedBlackTreeNode { + if (self.left == nil) { + return self + } + return self.left!.minimum() + } + + func maximum() -> RedBlackTreeNode { + if (self.right == nil) { + return self + } + return self.right!.maximum() + } + + func bubbleUp() -> RedBlackTreeNode { + var t = self + if (RedBlackTreeNode.isRedNode(node: t.right)) { + t = t.counterclockwiseRotate() + } + if (RedBlackTreeNode.isRedNode(node: t.left) && RedBlackTreeNode.isRedNode(node: t.left!.left)) { + t = t.clockwiseRotate() + } + if (RedBlackTreeNode.isRedNode(node: t.left) && RedBlackTreeNode.isRedNode(node: t.right)) { + t.exchange() + } + return t + } + + func alignLeftNode() -> RedBlackTreeNode { + var t = self + t.exchange() + if (self.right != nil && RedBlackTreeNode.isRedNode(node: t.right!.left)) { + t.right = t.right!.clockwiseRotate() + t = t.counterclockwiseRotate() + t.exchange() + } + return t + } + + func alignRightNode() -> RedBlackTreeNode { + var t = self + t.exchange() + if (self.left != nil && RedBlackTreeNode.isRedNode(node: t.left!.left)) { + t = t.clockwiseRotate() + t.exchange() + } + return t + } + + func search(value: T) -> RedBlackTreeNode? { + if (self.value == value) { + return self + } else if (self.value < value) { + return self.left?.search(value: value) + } else { + return self.right?.search(value: value) + } + } + + func removeMinimum() -> RedBlackTreeNode? { + if (self.left == nil) { + return nil + } + var t = self + if (!RedBlackTreeNode.isRedNode(node: t.left) && !RedBlackTreeNode.isRedNode(node: t.left!.left)) { + t = t.alignLeftNode() + } + t.left = t.left!.removeMinimum() + return t.bubbleUp() + } + + func preorderTraversal() -> Array { + var traversal: Array = [self.value] + if (self.left != nil) { + traversal += left!.inorderTraversal() + } + if (self.right != nil) { + traversal += right!.inorderTraversal() + } + return traversal; + } + + func inorderTraversal() -> Array { + var traversal: Array = [] + if (self.left != nil) { + traversal += left!.inorderTraversal() + } + traversal += [self.value] + if (self.right != nil) { + traversal += right!.inorderTraversal() + } + return traversal; + } + + func postorderTraversal() -> Array { + var traversal: Array = [] + if (self.left != nil) { + traversal += left!.inorderTraversal() + } + if (self.right != nil) { + traversal += right!.inorderTraversal() + } + traversal += [self.value] + return traversal; + } +} + +class RedBlackTree { + var root: RedBlackTreeNode? = nil + + static func insert(inRoot: RedBlackTreeNode?, val: T) -> RedBlackTreeNode? { + var root = inRoot + if (root == nil) { + return RedBlackTreeNode(value: val, isRed: true, left: nil, right: nil) + } + if (RedBlackTreeNode.isRedNode(node: root!.left) && RedBlackTreeNode.isRedNode(node: root!.right)) { + root!.exchange() + } + if (val == root!.value) { + root!.value = val + } else if (val < root!.value) { + root!.left = insert(inRoot: root!.left, val: val) + } else { + root!.right = insert(inRoot: root!.right, val: val) + } + if (RedBlackTreeNode.isRedNode(node: root!.right)) { + root = root!.counterclockwiseRotate() + } + if (RedBlackTreeNode.isRedNode(node: root!.left) && RedBlackTreeNode.isRedNode(node: root!.left!.left)) { + root = root!.clockwiseRotate() + } + if (RedBlackTreeNode.isRedNode(node: root!.left) && RedBlackTreeNode.isRedNode(node: root!.right)) { + root!.exchange(); + } + return root; + } + + static func remove(inRoot: RedBlackTreeNode?, val: T) -> RedBlackTreeNode? { + var root = inRoot; + if (val < root!.value) { + if (root!.left != nil && !(RedBlackTreeNode.isRedNode(node: root!.left)) && !(RedBlackTreeNode.isRedNode(node: root!.left!.left))) { + root = root!.alignLeftNode() + } + root!.left = remove(inRoot: root!.left, val: val); + } else { + if (RedBlackTreeNode.isRedNode(node: root!.left)) { + root = root!.clockwiseRotate() + } + if (val == root!.value && root!.right == nil) { + return nil + } + if (root!.right != nil && !(RedBlackTreeNode.isRedNode(node: root!.right)) && !(RedBlackTreeNode.isRedNode(node: root!.right!.left))) { + root = root!.alignRightNode() + } + if (val == root!.value) { + root!.value = root!.right!.minimum().value + root!.right = root!.right!.removeMinimum() + } else { + root!.right = remove(inRoot: root!.right, val: val); + } + } + return root!.bubbleUp() + } + + func insert(value: T) { + root = RedBlackTree.insert(inRoot: root, val: value) + if (root != nil) { + root!.isRed = false + } + } + + func remove(value: T) { + if (search(value: value) == nil) { + return + } + root = RedBlackTree.remove(inRoot: root, val: value) + if (root != nil) { + root!.isRed = false + } + } + + func search(value: T) -> RedBlackTreeNode? { + return root?.search(value: value) + } + + func preorderTraversal() -> Array { + if (root == nil) { + return Array() + } + return root!.preorderTraversal() + } + + func inorderTraversal() -> Array { + if (root == nil) { + return Array() + } + return root!.inorderTraversal() + } + + func postorderTraversal() -> Array { + if (root == nil) { + return Array() + } + return root!.postorderTraversal() + } +} diff --git a/Data Structures.playground/Pages/Red-Black Tree.xcplaygroundpage/Contents.swift b/Data Structures.playground/Pages/Red-Black Tree.xcplaygroundpage/Contents.swift deleted file mode 100644 index 2f56e48..0000000 --- a/Data Structures.playground/Pages/Red-Black Tree.xcplaygroundpage/Contents.swift +++ /dev/null @@ -1,40 +0,0 @@ -//: [Previous](@previous) - -import Foundation - -enum RedBlackTreeColorType: Int { - case red = 0, black -} - -class RedBlackTree { - - // MARK: - Properties - - var value: T - var color: RedBlackTreeColorType - var leftChild: RedBlackTree? - var rightChild: RedBlackTree? - weak var parent: RedBlackTree? - - // MARK: Initializers - - convenience init(value: T) { - self.init(value: value, color: .black, leftChild: nil, rightChild: nil, parent: nil) - } - - init(value: T, color: RedBlackTreeColorType, leftChild: RedBlackTree?, rightChild: RedBlackTree?, parent: RedBlackTree?) { - self.value = value - self.color = color - self.leftChild = leftChild - self.rightChild = rightChild - self.parent = parent - } - - // MARK: - Methods - - // FIXME: - Requires implementation - -} - - -//: [Next](@next) diff --git a/README.md b/README.md index c410395..debcb5e 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ # swift-algorithms-data-structs [![Awesome](https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg)](https://github.com/sindresorhus/awesome) -[![Language](https://img.shields.io/badge/language-Swift_5.0-orange.svg)]() +[![Language](https://img.shields.io/badge/language-Swift_5.3-orange.svg)]() [![License](https://img.shields.io/badge/license-MIT-blue.svg)]() -**Last Update: 27/April/2019.** +**Last Update: 18/July/2021.** ![](https://github.com/jVirus/swift-algorithms-data-structs/blob/master/cover-algo-datastruct.png)