A high-performance, feature-rich AVL Tree (self-balancing binary search tree) implementation for JavaScript/TypeScript.
Sawit (Indonesian for "palm oil tree") provides a sorted set data structure with O(log n) operations, perfect for scenarios where you need fast insertion, deletion, and ordered queries.
- π O(log n) insert, delete, search, and order statistics
- π― Order Statistics:
kthSmallest,kthLargest,rank,select - π Range Queries:
range,rangeCount,floor,ceiling - π Set Operations:
union,intersection,difference - πͺ Iterators:
for...of,inOrder,preOrder,postOrder,levelOrder - π§© Functional API:
map,filter,reduce,every,some,find - π¦ Zero Dependencies: Pure TypeScript implementation
- π Full TypeScript Support: Complete type definitions included
npm install sawit.js
# or
yarn add sawit.js
# or
bun add sawit.jsimport { SawitTree } from 'sawit.js';
// Create a tree
const tree = new SawitTree<number>();
// Insert values (chainable)
tree.insert(5).insert(3).insert(7).insert(1).insert(9);
// Check existence
console.log(tree.has(5)); // true
console.log(tree.size); // 5
// Get min/max
console.log(tree.min()); // 1
console.log(tree.max()); // 9
// Iterate in sorted order
for (const value of tree) {
console.log(value); // 1, 3, 5, 7, 9
}
// Convert to array
console.log(tree.toArray()); // [1, 3, 5, 7, 9]// Objects with custom comparison
interface User {
id: number;
name: string;
score: number;
}
const leaderboard = new SawitTree<User>((a, b) => b.score - a.score); // Descending
leaderboard.insert({ id: 1, name: 'Alice', score: 100 });
leaderboard.insert({ id: 2, name: 'Bob', score: 150 });
leaderboard.insert({ id: 3, name: 'Charlie', score: 120 });
// Get top player
const top = leaderboard.kthSmallest(1);
console.log(top?.name); // 'Bob'const tree = SawitTree.from([1, 3, 5, 7, 9, 11, 13, 15]);
// Get all values in range [5, 11]
console.log(tree.range(5, 11)); // [5, 7, 9, 11]
// Floor & Ceiling
console.log(tree.floor(6)); // 5 (largest β€ 6)
console.log(tree.ceiling(6)); // 7 (smallest β₯ 6)
// Count elements in range
console.log(tree.rangeCount(5, 11)); // 4const tree = SawitTree.from([10, 20, 30, 40, 50]);
// Rank: how many elements < value
console.log(tree.rank(30)); // 2
// Select: get element at rank
console.log(tree.select(2)); // 30
// Kth smallest/largest
console.log(tree.kthSmallest(2)); // 20 (2nd smallest)
console.log(tree.kthLargest(2)); // 40 (2nd largest)const numbers = SawitTree.from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
// Filter even numbers
const evens = numbers.filter(n => n % 2 === 0);
console.log(evens.toArray()); // [2, 4, 6, 8, 10]
// Map to squares
const squares = numbers.map(n => n * n);
console.log(squares.toArray()); // [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
// Reduce to sum
const sum = numbers.reduce((acc, n) => acc + n, 0);
console.log(sum); // 55const a = SawitTree.from([1, 2, 3, 4, 5]);
const b = SawitTree.from([4, 5, 6, 7, 8]);
console.log(a.union(b).toArray()); // [1, 2, 3, 4, 5, 6, 7, 8]
console.log(a.intersection(b).toArray()); // [4, 5]
console.log(a.difference(b).toArray()); // [1, 2, 3]| Method | Description |
|---|---|
new SawitTree<T>(comparator?) |
Create empty tree with optional comparator |
SawitTree.from(iterable, comparator?) |
Create tree from iterable |
SawitTree.of(...values) |
Create tree from arguments |
| Property | Type | Description | Complexity |
|---|---|---|---|
size |
number |
Number of elements | O(1) |
height |
number |
Tree height | O(1) |
isEmpty |
boolean |
True if empty | O(1) |
| Method | Returns | Description | Complexity |
|---|---|---|---|
insert(value) |
this |
Insert value | O(log n) |
insertAll(values) |
this |
Insert multiple | O(k log n) |
delete(value) |
boolean |
Remove value | O(log n) |
has(value) |
boolean |
Check existence | O(log n) |
clear() |
void |
Remove all | O(1) |
| Method | Returns | Description | Complexity |
|---|---|---|---|
min() |
T | undefined |
Minimum value | O(log n) |
max() |
T | undefined |
Maximum value | O(log n) |
extractMin() |
T | undefined |
Remove & return min | O(log n) |
extractMax() |
T | undefined |
Remove & return max | O(log n) |
| Method | Returns | Description | Complexity |
|---|---|---|---|
floor(value) |
T | undefined |
Largest β€ value | O(log n) |
ceiling(value) |
T | undefined |
Smallest β₯ value | O(log n) |
lower(value) |
T | undefined |
Largest < value | O(log n) |
higher(value) |
T | undefined |
Smallest > value | O(log n) |
| Method | Returns | Description | Complexity |
|---|---|---|---|
rank(value) |
number |
Count of elements < value | O(log n) |
select(k) |
T | undefined |
Element at rank k (0-indexed) | O(log n) |
kthSmallest(k) |
T | undefined |
K-th smallest (1-indexed) | O(log n) |
kthLargest(k) |
T | undefined |
K-th largest (1-indexed) | O(log n) |
| Method | Returns | Description | Complexity |
|---|---|---|---|
range(low, high) |
T[] |
Elements in [low, high] | O(k + log n) |
rangeCount(low, high) |
number |
Count in range | O(log n) |
| Method | Returns | Description |
|---|---|---|
[Symbol.iterator]() |
Iterator<T> |
In-order iterator |
inOrder() |
Generator<T> |
Left, Root, Right |
preOrder() |
Generator<T> |
Root, Left, Right |
postOrder() |
Generator<T> |
Left, Right, Root |
levelOrder() |
Generator<T> |
BFS traversal |
reverseInOrder() |
Generator<T> |
Descending order |
| Method | Returns | Description | Complexity |
|---|---|---|---|
forEach(callback) |
void |
Execute for each | O(n) |
map(fn, comparator?) |
SawitTree<U> |
Transform to new tree | O(n log n) |
filter(predicate) |
SawitTree<T> |
Filter elements | O(n log n) |
reduce(fn, initial) |
U |
Reduce to value | O(n) |
every(predicate) |
boolean |
All match? | O(n) |
some(predicate) |
boolean |
Any match? | O(n) |
find(predicate) |
T | undefined |
First match | O(n) |
| Method | Returns | Description | Complexity |
|---|---|---|---|
union(other) |
SawitTree<T> |
All from both | O((n+m) log(n+m)) |
intersection(other) |
SawitTree<T> |
Common elements | O(n log m) |
difference(other) |
SawitTree<T> |
In this, not other | O(n log m) |
symmetricDifference(other) |
SawitTree<T> |
In one, not both | O((n+m) log(n+m)) |
isSubsetOf(other) |
boolean |
All in other? | O(n log m) |
isSupersetOf(other) |
boolean |
Contains all of other? | O(m log n) |
| Method | Returns | Description | Complexity |
|---|---|---|---|
toArray() |
T[] |
Sorted array | O(n) |
toSet() |
Set<T> |
Convert to Set | O(n) |
clone() |
SawitTree<T> |
Deep copy | O(n log n) |
toString() |
string |
JSON structure | O(n) |
| Operation | Sawit.js (AVL) | Array | Sorted Array |
|---|---|---|---|
| Insert | O(log n) | O(1)* | O(n) |
| Delete | O(log n) | O(n) | O(n) |
| Search | O(log n) | O(n) | O(log n) |
| Min/Max | O(log n) | O(n) | O(1) |
| Kth Element | O(log n) | O(n log n) | O(1) |
| Range Query | O(k + log n) | O(n) | O(k + log n) |
*Array insert is O(1) amortized at end, O(n) at arbitrary position.
MIT Β© xirf
Contributions welcome! Please read our Contributing Guide first.
Made with β€οΈ and π΄