- DataStructures: Implemented LinkedHashMap and TreeMap (RB Tree) in swift

This commit is contained in:
Magesh K
2025-02-21 19:03:06 +05:30
parent 1a43ad4aa3
commit 08e11eece4
2 changed files with 623 additions and 0 deletions

View File

@@ -0,0 +1,226 @@
//
// LinkedHashMap.swift
// SideStore
//
// Created by Magesh K on 21/02/25.
// Copyright © 2025 SideStore. All rights reserved.
//
/// A generic LinkedHashMap implementation in Swift.
/// It provides constant-time lookup along with predictable (insertion) ordering.
public final class LinkedHashMap<Key: Hashable, Value>: Sequence {
/// Internal doubly-linked list node
fileprivate final class Node {
let key: Key
var value: Value
var next: Node?
weak var prev: Node? // weak to avoid strong reference cycle
init(key: Key, value: Value) {
self.key = key
self.value = value
}
}
// MARK: - Storage
/// Dictionary for fast lookup from key to node.
private var dict: [Key: Node] = [:]
/// Head and tail of the doubly-linked list to maintain order.
private var head: Node?
private var tail: Node?
// MARK: - Initialization
/// Creates an empty LinkedHashMap.
public init() { }
/// Creates a LinkedHashMap from a standard dictionary.
public init(_ dictionary: [Key: Value]) {
for (key, value) in dictionary {
_ = self.put(key: key, value: value)
}
}
// MARK: - Public API
/// The number of key-value pairs in the map.
public var count: Int {
return dict.count
}
/// A Boolean value indicating whether the map is empty.
public var isEmpty: Bool {
return dict.isEmpty
}
/// Returns the value for the given key, or `nil` if the key is not found.
public func get(key: Key) -> Value? {
return dict[key]?.value
}
/// Inserts or updates the value for the given key.
/// - Returns: The previous value for the key if it existed; otherwise, `nil`.
@discardableResult
public func put(key: Key, value: Value) -> Value? {
if let node = dict[key] {
let oldValue = node.value
node.value = value
return oldValue
} else {
let newNode = Node(key: key, value: value)
dict[key] = newNode
appendNode(newNode)
return nil
}
}
/// Removes the value for the given key.
/// - Returns: The removed value if it existed; otherwise, `nil`.
@discardableResult
public func remove(key: Key) -> Value? {
guard let node = dict.removeValue(forKey: key) else { return nil }
removeNode(node)
return node.value
}
/// Removes all key-value pairs from the map.
public func clear() {
dict.removeAll()
head = nil
tail = nil
}
/// Determines whether the map contains the given key.
public func containsKey(_ key: Key) -> Bool {
return dict[key] != nil
}
/// Determines whether the map contains the given value.
/// Note: This method requires that Value conforms to Equatable.
public func containsValue(_ value: Value) -> Bool where Value: Equatable {
var current = head
while let node = current {
if node.value == value {
return true
}
current = node.next
}
return false
}
/// Returns all keys in insertion order.
public var keys: [Key] {
var result = [Key]()
var current = head
while let node = current {
result.append(node.key)
current = node.next
}
return result
}
/// Returns all values in insertion order.
public var values: [Value] {
var result = [Value]()
var current = head
while let node = current {
result.append(node.value)
current = node.next
}
return result
}
/// Subscript for getting and setting values.
public subscript(key: Key) -> Value? {
get {
return get(key: key)
}
set {
if let newValue = newValue {
_ = put(key: key, value: newValue)
} else {
_ = remove(key: key)
}
}
}
// MARK: - Sequence Conformance
/// Iterator that yields key-value pairs in insertion order.
public struct Iterator: IteratorProtocol {
private var current: Node?
fileprivate init(start: Node?) {
self.current = start
}
public mutating func next() -> (key: Key, value: Value)? {
guard let node = current else { return nil }
current = node.next
return (node.key, node.value)
}
}
public func makeIterator() -> Iterator {
return Iterator(start: head)
}
// MARK: - Private Helpers
/// Appends a new node to the end of the linked list.
private func appendNode(_ node: Node) {
if let tailNode = tail {
tailNode.next = node
node.prev = tailNode
tail = node
} else {
head = node
tail = node
}
}
/// Removes the given node from the linked list.
private func removeNode(_ node: Node) {
let prevNode = node.prev
let nextNode = node.next
if let prevNode = prevNode {
prevNode.next = nextNode
} else {
head = nextNode
}
if let nextNode = nextNode {
nextNode.prev = prevNode
} else {
tail = prevNode
}
// Disconnect node's pointers.
node.prev = nil
node.next = nil
}
public func removeValue(forKey key: Key) -> Value? {
return remove(key: key)
}
}
extension LinkedHashMap {
public subscript(key: Key, default defaultValue: @autoclosure () -> Value) -> Value {
get {
if let value = self[key] {
return value
} else {
return defaultValue()
}
}
set {
self[key] = newValue
}
}
}

View File

@@ -0,0 +1,397 @@
//
// TreeMap.swift
// SideStore
//
// Created by Magesh K on 21/02/25.
// Copyright © 2025 SideStore. All rights reserved.
//
public class TreeMap<Key: Comparable, Value>: Sequence {
// MARK: - Node and Color Definitions
fileprivate enum Color {
case red
case black
}
fileprivate class Node {
var key: Key
var value: Value
var left: Node?
var right: Node?
weak var parent: Node?
var color: Color
init(key: Key, value: Value, color: Color = .red, parent: Node? = nil) {
self.key = key
self.value = value
self.color = color
self.parent = parent
}
}
// MARK: - TreeMap Properties and Initializer
private var root: Node?
public private(set) var count: Int = 0
public init() {}
// MARK: - Public Dictionary-like API
/// Subscript: Get or set value for a given key.
public subscript(key: Key) -> Value? {
get { return get(key: key) }
set {
if let newValue = newValue {
_ = insert(key: key, value: newValue)
} else {
_ = remove(key: key)
}
}
}
/// Returns the value associated with the given key.
public func get(key: Key) -> Value? {
guard let node = getNode(forKey: key) else { return nil }
return node.value
}
/// Inserts (or updates) the key with the given value.
/// Returns the old value if the key was already present.
@discardableResult
public func insert(key: Key, value: Value) -> Value? {
if let node = getNode(forKey: key) {
let oldValue = node.value
node.value = value
return oldValue
}
// Create new node
let newNode = Node(key: key, value: value)
var parent: Node? = nil
var current = root
while let cur = current {
parent = cur
if newNode.key < cur.key {
current = cur.left
} else {
current = cur.right
}
}
newNode.parent = parent
if parent == nil {
root = newNode
} else if newNode.key < parent!.key {
parent!.left = newNode
} else {
parent!.right = newNode
}
count += 1
fixAfterInsertion(newNode)
return nil
}
/// Removes the node with the given key.
/// Returns the removed value if it existed.
@discardableResult
public func remove(key: Key) -> Value? {
guard let node = getNode(forKey: key) else { return nil }
let removedValue = node.value
deleteNode(node)
count -= 1
return removedValue
}
/// Returns true if the map is empty.
public var isEmpty: Bool {
return count == 0
}
/// Returns all keys in sorted order.
public var keys: [Key] {
var result = [Key]()
for (k, _) in self { result.append(k) }
return result
}
/// Returns all values in order of their keys.
public var values: [Value] {
var result = [Value]()
for (_, v) in self { result.append(v) }
return result
}
/// Removes all entries.
public func removeAll() {
root = nil
count = 0
}
// MARK: - Internal Helper Methods
/// Standard BST search for a node matching the key.
private func getNode(forKey key: Key) -> Node? {
var current = root
while let node = current {
if key == node.key {
return node
} else if key < node.key {
current = node.left
} else {
current = node.right
}
}
return nil
}
/// Returns the minimum node in the subtree rooted at `node`.
private func minimum(_ node: Node) -> Node {
var current = node
while let next = current.left {
current = next
}
return current
}
// MARK: - Rotation Methods
private func rotateLeft(_ x: Node) {
guard let y = x.right else { return }
x.right = y.left
if let leftChild = y.left {
leftChild.parent = x
}
y.parent = x.parent
if x.parent == nil {
root = y
} else if x === x.parent?.left {
x.parent?.left = y
} else {
x.parent?.right = y
}
y.left = x
x.parent = y
}
private func rotateRight(_ x: Node) {
guard let y = x.left else { return }
x.left = y.right
if let rightChild = y.right {
rightChild.parent = x
}
y.parent = x.parent
if x.parent == nil {
root = y
} else if x === x.parent?.right {
x.parent?.right = y
} else {
x.parent?.left = y
}
y.right = x
x.parent = y
}
// MARK: - Insertion Fix-Up
/// Restores redblack properties after insertion.
private func fixAfterInsertion(_ x: Node) {
var node = x
node.color = .red
while node !== root, let parent = node.parent, parent.color == .red {
if parent === parent.parent?.left {
if let uncle = parent.parent?.right, uncle.color == .red {
parent.color = .black
uncle.color = .black
parent.parent?.color = .red
if let grandparent = parent.parent {
node = grandparent
}
} else {
if node === parent.right {
node = parent
rotateLeft(node)
}
node.parent?.color = .black
node.parent?.parent?.color = .red
if let grandparent = node.parent?.parent {
rotateRight(grandparent)
}
}
} else {
if let uncle = parent.parent?.left, uncle.color == .red {
parent.color = .black
uncle.color = .black
parent.parent?.color = .red
if let grandparent = parent.parent {
node = grandparent
}
} else {
if node === parent.left {
node = parent
rotateRight(node)
}
node.parent?.color = .black
node.parent?.parent?.color = .red
if let grandparent = node.parent?.parent {
rotateLeft(grandparent)
}
}
}
}
root?.color = .black
}
// MARK: - Deletion Helpers
/// Replaces subtree rooted at u with subtree rooted at v.
private func transplant(_ u: Node, _ v: Node?) {
if u.parent == nil {
root = v
} else if u === u.parent?.left {
u.parent?.left = v
} else {
u.parent?.right = v
}
if let vNode = v {
vNode.parent = u.parent
}
}
/// Deletes node z and fixes redblack properties.
private func deleteNode(_ z: Node) {
var y = z
let originalColor = y.color
var x: Node?
if z.left == nil {
x = z.right
transplant(z, z.right)
} else if z.right == nil {
x = z.left
transplant(z, z.left)
} else {
y = minimum(z.right!)
let yOriginalColor = y.color
x = y.right
if y.parent === z {
if x != nil { x!.parent = y }
} else {
transplant(y, y.right)
y.right = z.right
y.right?.parent = y
}
transplant(z, y)
y.left = z.left
y.left?.parent = y
y.color = z.color
if yOriginalColor == .black {
fixAfterDeletion(x, parent: y.parent)
}
return
}
if originalColor == .black {
fixAfterDeletion(x, parent: z.parent)
}
}
/// Restores redblack properties after deletion.
private func fixAfterDeletion(_ x: Node?, parent: Node?) {
var x = x
var parent = parent
while (x == nil || x!.color == .black) && (x !== root) {
if x === parent?.left {
var w = parent?.right
if w?.color == .red {
w?.color = .black
parent?.color = .red
rotateLeft(parent!)
w = parent?.right
}
if (w?.left == nil || w?.left?.color == .black) &&
(w?.right == nil || w?.right?.color == .black) {
w?.color = .red
x = parent
parent = x?.parent
} else {
if w?.right == nil || w?.right?.color == .black {
w?.left?.color = .black
w?.color = .red
if let wUnwrapped = w { rotateRight(wUnwrapped) }
w = parent?.right
}
w?.color = parent?.color ?? .black
parent?.color = .black
w?.right?.color = .black
rotateLeft(parent!)
x = root
parent = nil
}
} else {
var w = parent?.left
if w?.color == .red {
w?.color = .black
parent?.color = .red
rotateRight(parent!)
w = parent?.left
}
if (w?.left == nil || w?.left?.color == .black) &&
(w?.right == nil || w?.right?.color == .black) {
w?.color = .red
x = parent
parent = x?.parent
} else {
if w?.left == nil || w?.left?.color == .black {
w?.right?.color = .black
w?.color = .red
if let wUnwrapped = w { rotateLeft(wUnwrapped) }
w = parent?.left
}
w?.color = parent?.color ?? .black
parent?.color = .black
w?.left?.color = .black
rotateRight(parent!)
x = root
parent = nil
}
}
}
x?.color = .black
}
// Convenience overload if parent is not separately tracked.
private func fixAfterDeletion(_ x: Node?) {
fixAfterDeletion(x, parent: x?.parent)
}
// MARK: - Sequence Conformance (In-Order Traversal)
public struct Iterator: IteratorProtocol {
private var stack: [Node] = []
// Marked as private because Node is a private type.
fileprivate init(root: Node?) {
var current = root
while let node = current {
stack.append(node)
current = node.left
}
}
public mutating func next() -> (Key, Value)? {
if stack.isEmpty { return nil }
let node = stack.removeLast()
let result = (node.key, node.value)
var current = node.right
while let n = current {
stack.append(n)
current = n.left
}
return result
}
}
public func makeIterator() -> Iterator {
return Iterator(root: root)
}
}