Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion kmp/kmp.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ fn get_z(s : String) -> Array[Int] {
/// inspect(z_func(b), content="[5, 4, 3, 2, 1]")
/// inspect(z_func(b, t=a), content="[4, 3, 2, 1, 0, 2, 1]")
/// ```
pub fn z_func(s : String, t? : String = "") -> Array[Int] {
pub fn z_func(s : String, t~ : String = "") -> Array[Int] {
let z : Array[Int] = get_z(s)
match t {
"" => z
Expand Down
2 changes: 1 addition & 1 deletion lca/lca.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ fn _init(self : LCA) -> Unit {
/// let lca = create_Lca(data, root = 1)
/// inspect(lca.get_root(), content="1")
/// ```
pub fn create_Lca(data : Array[(Int, Int)], root? : Int = 1) -> LCA {
pub fn create_Lca(data : Array[(Int, Int)], root~ : Int = 1) -> LCA {
if data.length() == 0 {
abort("Data is empty")
} else if root < 1 || root > data.length() {
Expand Down
40 changes: 40 additions & 0 deletions splay/README.mbt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Splay Tree

Self-adjusting binary search tree implementation for MoonBit. The tree splays
(nodes rotate towards the root) on every access so that recently used keys stay
close to the top, providing excellent practical performance for skewed
workloads.

## Highlights
- Generic over key and value types (keys must implement `Compare`).
- `insert`, `get`, `contains`, `remove`, and `clear` operations provided.
- Automatically keeps the most recently accessed key at the root.

## Quick Start
```moonbit
test "README basic usage" {
let tree : SplayTree[Int, String] = SplayTree::new()
tree.insert(42, "answer")
tree.insert(7, "lucky")
assert_eq(tree.get(7), Some("lucky"))
tree.insert(15, "middle")
assert_eq(tree.remove(42), true)
assert_eq(tree.contains(42), false)
assert_eq(tree.len(), 2)

tree.clear()
assert_eq(tree.is_empty(), true)
}
```

## API Overview
- `SplayTree::new()` – create an empty tree.
- `insert(key, value)` – add or update a key.
- `get(key)` – fetch the value and splay the node to the root.
- `contains(key)` – boolean membership check (also splays).
- `remove(key)` – delete a key when present.
- `clear()` – remove everything while keeping the structure reusable.
- `len()` / `is_empty()` – observe current size.

> ℹ️ Splaying keeps the tree balanced enough for amortized `O(log n)` access
> while making repeated queries for the same keys very fast.
1 change: 1 addition & 0 deletions splay/README.md
1 change: 1 addition & 0 deletions splay/moon.pkg.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
230 changes: 230 additions & 0 deletions splay/splay.mbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
///|
struct Node[K, V] {
key : K
mut value : V
mut left : Node[K, V]?
mut right : Node[K, V]?
}

///|
fn[K, V] Node::new(key : K, value : V) -> Node[K, V] {
Node::{ key, value, left: None, right: None }
}

///|
fn[K, V] rotate_right(node_value : Node[K, V]) -> Node[K, V] {
match node_value.left {
Some(left_value) => {
let parent = node_value
let child = left_value
parent.left = child.right
child.right = Some(parent)
child
}
None => node_value
}
}

///|
fn[K, V] rotate_left(node_value : Node[K, V]) -> Node[K, V] {
match node_value.right {
Some(right_value) => {
let parent = node_value
let child = right_value
parent.right = child.left
child.left = Some(parent)
child
}
None => node_value
}
}

///|
fn[K : Compare, V] splay(root : Node[K, V]?, key : K) -> Node[K, V]? {
match root {
None => None
Some(node_value) => {
let node = node_value
let cmp_root = key.compare(node.key)
if cmp_root < 0 {
match node.left {
None => Some(node)
Some(left_value) => {
let left_child = left_value
let cmp_left = key.compare(left_child.key)
if cmp_left < 0 {
left_child.left = splay(left_child.left, key)
node.left = Some(left_child)
Some(rotate_right(rotate_right(node)))
} else if cmp_left > 0 {
left_child.right = splay(left_child.right, key)
let rotated = rotate_left(left_child)
node.left = Some(rotated)
Some(rotate_right(node))
} else {
node.left = Some(left_child)
Some(rotate_right(node))
}
}
}
} else if cmp_root > 0 {
match node.right {
None => Some(node)
Some(right_value) => {
let right_child = right_value
let cmp_right = key.compare(right_child.key)
if cmp_right > 0 {
right_child.right = splay(right_child.right, key)
node.right = Some(right_child)
Some(rotate_left(rotate_left(node)))
} else if cmp_right < 0 {
right_child.left = splay(right_child.left, key)
let rotated = rotate_right(right_child)
node.right = Some(rotated)
Some(rotate_left(node))
} else {
node.right = Some(right_child)
Some(rotate_left(node))
}
}
}
} else {
Some(node)
}
}
}
}

///|
pub struct SplayTree[K, V] {
mut root : Node[K, V]?
mut size : Int
}

///|
pub fn[K, V] SplayTree::new() -> SplayTree[K, V] {
SplayTree::{ root: None, size: 0 }
}

///|
pub fn[K, V] len(self : SplayTree[K, V]) -> Int {
self.size
}

///|
pub fn[K, V] is_empty(self : SplayTree[K, V]) -> Bool {
self.size == 0
}

///|
pub fn[K, V] clear(self : SplayTree[K, V]) -> Unit {
self.root = None
self.size = 0
}

///|
pub fn[K : Compare, V] SplayTree::insert(
self : SplayTree[K, V],
key : K,
value : V,
) -> Unit {
let splayed = splay(self.root, key)
match splayed {
None => {
self.root = Some(Node::new(key, value))
self.size = self.size + 1
}
Some(root_value) => {
let root = root_value
let cmp = key.compare(root.key)
if cmp == 0 {
root.value = value
self.root = Some(root)
} else if cmp < 0 {
let left_sub = root.left
root.left = None
let new_root = Node::{ key, value, left: left_sub, right: Some(root) }
self.root = Some(new_root)
self.size = self.size + 1
} else {
let right_sub = root.right
root.right = None
let new_root = Node::{ key, value, left: Some(root), right: right_sub }
self.root = Some(new_root)
self.size = self.size + 1
}
}
}
}

///|
pub fn[K : Compare, V] SplayTree::get(self : SplayTree[K, V], key : K) -> V? {
self.root = splay(self.root, key)
match self.root {
Some(root) =>
if key.compare(root.key) == 0 {
Some(root.value)
} else {
None
}
None => None
}
}

///|
pub fn[K : Compare, V] SplayTree::contains(
self : SplayTree[K, V],
key : K,
) -> Bool {
match self.get(key) {
Some(_) => true
None => false
}
}

///|
pub fn[K : Compare, V] SplayTree::remove(
self : SplayTree[K, V],
key : K,
) -> Bool {
if self.size == 0 {
return false
}
self.root = splay(self.root, key)
match self.root {
Some(root_value) => {
let root = root_value
if key.compare(root.key) != 0 {
self.root = Some(root)
false
} else {
let left_sub = root.left
let right_sub = root.right
root.left = None
root.right = None
self.size = self.size - 1
match left_sub {
None => self.root = right_sub
Some(left_root_value) => {
let new_root = splay(Some(left_root_value), key)
match new_root {
Some(left_root_node) => {
let left_root = left_root_node
left_root.right = right_sub
self.root = Some(left_root)
}
None => self.root = right_sub
}
}
}
true
}
}
None => false
}
}

///|
pub impl[K, V] Default for SplayTree[K, V] with default() {
SplayTree::new()
}
28 changes: 28 additions & 0 deletions splay/splay.mbti
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Generated using `moon info`, DON'T EDIT IT
package "Lampese/Algorithms-Moonbit/splay"

// Values

// Errors

// Types and methods
type Node[K, V]

pub struct SplayTree[K, V] {
mut root : Node[K, V]?
mut size : Int
}
fn[K, V] SplayTree::clear(Self[K, V]) -> Unit
fn[K : Compare, V] SplayTree::contains(Self[K, V], K) -> Bool
fn[K : Compare, V] SplayTree::get(Self[K, V], K) -> V?
fn[K : Compare, V] SplayTree::insert(Self[K, V], K, V) -> Unit
fn[K, V] SplayTree::is_empty(Self[K, V]) -> Bool
fn[K, V] SplayTree::len(Self[K, V]) -> Int
fn[K, V] SplayTree::new() -> Self[K, V]
fn[K : Compare, V] SplayTree::remove(Self[K, V], K) -> Bool
impl[K, V] Default for SplayTree[K, V]

// Type aliases

// Traits

61 changes: 61 additions & 0 deletions splay/splay_test.mbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
///|
test "splay basic operations" {
let tree : SplayTree[Int, Int] = SplayTree::new()
assert_eq(tree.is_empty(), true)
tree.insert(10, 100)
tree.insert(20, 200)
tree.insert(5, 50)
assert_eq(tree.len(), 3)
assert_eq(tree.is_empty(), false)
assert_eq(tree.get(20), Some(200))
assert_eq(tree.get(20), Some(200))
assert_eq(tree.contains(5), true)
assert_eq(tree.remove(5), true)
assert_eq(tree.contains(5), false)
assert_eq(tree.len(), 2)
}

///|
test "splay repeated access stays consistent" {
let tree : SplayTree[Int, Int] = SplayTree::new()
tree.insert(30, 300)
tree.insert(40, 400)
tree.insert(10, 100)
tree.insert(50, 500)
tree.insert(20, 200)
assert_eq(tree.get(10), Some(100))
assert_eq(tree.get(50), Some(500))
assert_eq(tree.get(20), Some(200))
assert_eq(tree.remove(10), true)
assert_eq(tree.contains(10), false)
assert_eq(tree.get(50), Some(500))
}

///|
test "splay removes and re-links subtrees" {
let tree : SplayTree[Int, Int] = SplayTree::new()
tree.insert(25, 1)
tree.insert(15, 2)
tree.insert(35, 3)
tree.insert(30, 4)
tree.insert(40, 5)
assert_eq(tree.remove(35), true)
assert_eq(tree.contains(35), false)
assert_eq(tree.len(), 4)
assert_eq(tree.get(30), Some(4))
assert_eq(tree.get(40), Some(5))
assert_eq(tree.get(15), Some(2))
}

///|
test "splay clear and replace value" {
let tree : SplayTree[Int, Int] = SplayTree::new()
tree.insert(1, 10)
tree.insert(1, 20)
assert_eq(tree.len(), 1)
assert_eq(tree.get(1), Some(20))
tree.clear()
assert_eq(tree.len(), 0)
assert_eq(tree.get(1), None)
assert_eq(tree.is_empty(), true)
}
4 changes: 2 additions & 2 deletions string_hash/string_hash.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ let empty_hash : StringHash = StringHash::{
///|
/// Create a new StringHash object.
pub fn StringHash::new(
mod? : Int64 = 998244353,
base? : Int64 = 131,
mod~ : Int64 = 998244353,
base~ : Int64 = 131,
s : String,
) -> StringHash {
let n = s.length()
Expand Down
Loading