diff --git a/treap/README.mbt.md b/treap/README.mbt.md new file mode 100644 index 0000000..64bccfd --- /dev/null +++ b/treap/README.mbt.md @@ -0,0 +1,43 @@ +# Treap + +Randomized binary search tree for MoonBit. Each node stores a randomly assigned +priority so the structure stays balanced in expectation, while still behaving +like an ordered map keyed by `Compare` values. + +## Highlights +- Generic in both key and value types; only requires `Compare` on keys. +- Supports `insert`, `get`, `contains`, `remove`, `clear`, `len`, and `is_empty`. +- Deterministic pseudo-random priorities keep the tree reproducible in tests. + +## Quick Start +```moonbit +test "README treap usage" { + let treap : Treap[Int, String] = Treap::new() + treap.insert(8, "eight") + treap.insert(3, "three") + treap.insert(5, "five") + assert_eq(treap.len(), 3) + assert_eq(treap.get(5), Some("five")) + assert_eq(treap.contains(7), false) + + treap.insert(5, "FIVE") + assert_eq(treap.get(5), Some("FIVE")) + assert_eq(treap.remove(3), true) + assert_eq(treap.contains(3), false) + + treap.clear() + assert_eq(treap.is_empty(), true) +} +``` + +## API Overview +- `Treap::new()` – construct an empty treap. +- `insert(key, value)` – upsert a key/value pair. +- `get(key)` – retrieve the stored value or `None`. +- `contains(key)` – boolean membership query. +- `remove(key)` – delete the entry if present. +- `clear()` – empty the structure while retaining capacity. +- `len()` / `is_empty()` – observe current occupancy. + +> ℹ️ The internal priority generator is deterministic, making results stable +> across runs while still preserving the balancing guarantees of treaps. diff --git a/treap/README.md b/treap/README.md new file mode 120000 index 0000000..7ae1db3 --- /dev/null +++ b/treap/README.md @@ -0,0 +1 @@ +README.mbt.md \ No newline at end of file diff --git a/treap/moon.pkg.json b/treap/moon.pkg.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/treap/moon.pkg.json @@ -0,0 +1 @@ +{} diff --git a/treap/treap.mbt b/treap/treap.mbt new file mode 100644 index 0000000..e00d9b2 --- /dev/null +++ b/treap/treap.mbt @@ -0,0 +1,226 @@ +///| +struct Node[K, V] { + key : K + mut value : V + priority : Int + mut left : Node[K, V]? + mut right : Node[K, V]? +} + +///| +fn[K, V] Node::new(key : K, value : V, priority : Int) -> Node[K, V] { + Node::{ key, value, priority, left: None, right: None } +} + +///| +fn[K : Compare, V] split( + node_opt : Node[K, V]?, + key : K, +) -> (Node[K, V]?, Node[K, V]?) { + match node_opt { + None => (None, None) + Some(node_value) => { + let node = node_value + if key.compare(node.key) < 0 { + let (less, greater) = split(node.left, key) + node.left = greater + (less, Some(node)) + } else { + let (less, greater) = split(node.right, key) + node.right = less + (Some(node), greater) + } + } + } +} + +///| +fn[K : Compare, V] merge( + left_opt : Node[K, V]?, + right_opt : Node[K, V]?, +) -> Node[K, V]? { + match (left_opt, right_opt) { + (None, right_side) => right_side + (left_side, None) => left_side + (Some(left_value), Some(right_value)) => { + let left = left_value + let right = right_value + if left.priority > right.priority { + let merged = merge(left.right, Some(right)) + left.right = merged + Some(left) + } else { + let merged = merge(Some(left), right.left) + right.left = merged + Some(right) + } + } + } +} + +///| +fn[K : Compare, V] insert_node( + node_opt : Node[K, V]?, + key : K, + value : V, + priority : Int, +) -> (Node[K, V]?, Bool) { + match node_opt { + None => (Some(Node::new(key, value, priority)), true) + Some(node_value) => { + let node = node_value + let cmp = key.compare(node.key) + if cmp == 0 { + node.value = value + (Some(node), false) + } else if priority > node.priority { + let (less, greater) = split(Some(node), key) + let new_node = Node::new(key, value, priority) + new_node.left = less + new_node.right = greater + (Some(new_node), true) + } else if cmp < 0 { + let (new_left, inserted) = insert_node(node.left, key, value, priority) + node.left = new_left + (Some(node), inserted) + } else { + let (new_right, inserted) = insert_node( + node.right, + key, + value, + priority, + ) + node.right = new_right + (Some(node), inserted) + } + } + } +} + +///| +fn[K : Compare, V] remove_node( + node_opt : Node[K, V]?, + key : K, +) -> (Node[K, V]?, Bool) { + match node_opt { + None => (None, false) + Some(node_value) => { + let node = node_value + let cmp = key.compare(node.key) + if cmp == 0 { + let merged = merge(node.left, node.right) + (merged, true) + } else if cmp < 0 { + let (new_left, removed) = remove_node(node.left, key) + node.left = new_left + (Some(node), removed) + } else { + let (new_right, removed) = remove_node(node.right, key) + node.right = new_right + (Some(node), removed) + } + } + } +} + +///| +fn[K : Compare, V] find_node(node_opt : Node[K, V]?, key : K) -> V? { + match node_opt { + None => None + Some(node_value) => { + let node = node_value + let cmp = key.compare(node.key) + if cmp == 0 { + Some(node.value) + } else if cmp < 0 { + find_node(node.left, key) + } else { + find_node(node.right, key) + } + } + } +} + +///| +pub struct Treap[K, V] { + mut root : Node[K, V]? + mut size : Int + mut rng_state : Int +} + +///| +pub fn[K, V] Treap::new() -> Treap[K, V] { + Treap::{ root: None, size: 0, rng_state: 123_456_789 } +} + +///| +pub fn[K, V] len(self : Treap[K, V]) -> Int { + self.size +} + +///| +pub fn[K, V] is_empty(self : Treap[K, V]) -> Bool { + self.size == 0 +} + +///| +pub fn[K, V] clear(self : Treap[K, V]) -> Unit { + self.root = None + self.size = 0 +} + +///| +fn[K, V] Treap::next_priority(self : Treap[K, V]) -> Int { + let modulus = 2_147_483_647 + let mut state = (self.rng_state * 1_103_515_245 + 12_345) % modulus + if state < 0 { + state = -state + } + if state == 0 { + state = 1 + } + self.rng_state = state + state +} + +///| +pub fn[K : Compare, V] Treap::insert( + self : Treap[K, V], + key : K, + value : V, +) -> Unit { + let priority = self.next_priority() + let (new_root, inserted) = insert_node(self.root, key, value, priority) + self.root = new_root + if inserted { + self.size = self.size + 1 + } +} + +///| +pub fn[K : Compare, V] Treap::get(self : Treap[K, V], key : K) -> V? { + find_node(self.root, key) +} + +///| +pub fn[K : Compare, V] Treap::contains(self : Treap[K, V], key : K) -> Bool { + match self.get(key) { + Some(_) => true + None => false + } +} + +///| +pub fn[K : Compare, V] Treap::remove(self : Treap[K, V], key : K) -> Bool { + let (new_root, removed) = remove_node(self.root, key) + self.root = new_root + if removed { + self.size = self.size - 1 + } + removed +} + +///| +pub impl[K, V] Default for Treap[K, V] with default() { + Treap::new() +} diff --git a/treap/treap.mbti b/treap/treap.mbti new file mode 100644 index 0000000..5f88092 --- /dev/null +++ b/treap/treap.mbti @@ -0,0 +1,29 @@ +// Generated using `moon info`, DON'T EDIT IT +package "Lampese/Algorithms-Moonbit/treap" + +// Values + +// Errors + +// Types and methods +type Node[K, V] + +pub struct Treap[K, V] { + mut root : Node[K, V]? + mut size : Int + mut rng_state : Int +} +fn[K, V] Treap::clear(Self[K, V]) -> Unit +fn[K : Compare, V] Treap::contains(Self[K, V], K) -> Bool +fn[K : Compare, V] Treap::get(Self[K, V], K) -> V? +fn[K : Compare, V] Treap::insert(Self[K, V], K, V) -> Unit +fn[K, V] Treap::is_empty(Self[K, V]) -> Bool +fn[K, V] Treap::len(Self[K, V]) -> Int +fn[K, V] Treap::new() -> Self[K, V] +fn[K : Compare, V] Treap::remove(Self[K, V], K) -> Bool +impl[K, V] Default for Treap[K, V] + +// Type aliases + +// Traits + diff --git a/treap/treap_test.mbt b/treap/treap_test.mbt new file mode 100644 index 0000000..64b99ea --- /dev/null +++ b/treap/treap_test.mbt @@ -0,0 +1,80 @@ +///| +test "treap basic operations" { + let treap : Treap[Int, Int] = Treap::new() + assert_eq(treap.is_empty(), true) + treap.insert(10, 100) + treap.insert(5, 50) + treap.insert(20, 200) + assert_eq(treap.len(), 3) + assert_eq(treap.is_empty(), false) + assert_eq(treap.get(10), Some(100)) + assert_eq(treap.get(5), Some(50)) + assert_eq(treap.get(20), Some(200)) + assert_eq(treap.contains(15), false) +} + +///| +test "treap duplicate update preserves size" { + let treap : Treap[Int, String] = Treap::new() + treap.insert(1, "one") + treap.insert(2, "two") + treap.insert(3, "three") + assert_eq(treap.len(), 3) + treap.insert(2, "TWO") + assert_eq(treap.len(), 3) + assert_eq(treap.get(2), Some("TWO")) +} + +///| +test "treap removal cases" { + let treap : Treap[Int, Int] = Treap::new() + let values = [7, 3, 10, 1, 5, 9, 12] + for value in values { + treap.insert(value, value * 2) + } + assert_eq(treap.len(), values.length()) + assert_eq(treap.remove(3), true) + assert_eq(treap.contains(3), false) + assert_eq(treap.remove(10), true) + assert_eq(treap.contains(10), false) + assert_eq(treap.remove(8), false) + assert_eq(treap.len(), values.length() - 2) + assert_eq(treap.get(9), Some(18)) + assert_eq(treap.get(12), Some(24)) +} + +///| +test "treap clear resets structure" { + let treap : Treap[Int, Int] = Treap::default() + for value in [1, 2, 3, 4, 5] { + treap.insert(value, value) + } + assert_eq(treap.len(), 5) + treap.clear() + assert_eq(treap.len(), 0) + assert_eq(treap.is_empty(), true) + assert_eq(treap.get(3), None) + assert_eq(treap.remove(3), false) +} + +///| +test "treap handles larger sequence" { + let treap : Treap[Int, Int] = Treap::new() + for value in 0..<100 { + treap.insert(value, value) + } + assert_eq(treap.len(), 100) + for value in 0..<100 { + assert_eq(treap.get(value), Some(value)) + } + for value in 0..<50 { + assert_eq(treap.remove(value), true) + } + assert_eq(treap.len(), 50) + for value in 0..<50 { + assert_eq(treap.contains(value), false) + } + for value in 50..<100 { + assert_eq(treap.contains(value), true) + } +}