or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

index.mddocs/

Functional Red-Black Tree

A fully persistent (functional) red-black tree implementation written in pure JavaScript. This data structure enables non-destructive updates by returning new tree instances with modifications rather than mutating existing trees in place, using memory-efficient copy-on-write semantics.

Package Information

  • Package Name: functional-red-black-tree
  • Package Type: npm
  • Language: JavaScript
  • Installation: npm install functional-red-black-tree

Core Imports

var createTree = require("functional-red-black-tree");

Basic Usage

var createTree = require("functional-red-black-tree");

// Create a tree with default comparison
var t1 = createTree();

// Insert some items
var t2 = t1.insert(1, "foo");
var t3 = t2.insert(2, "bar");

// Remove something  
var t4 = t3.remove(1);

// Access values
console.log(t3.get(1)); // "foo"
console.log(t4.get(1)); // undefined

// Iterate over tree
t3.forEach(function(key, value) {
  console.log(key, value);
});

Architecture

The library uses several key design patterns:

  • Persistent Data Structure: All operations return new tree instances without mutating the original
  • Copy-on-Write: Memory-efficient sharing of unchanged subtrees between versions
  • Red-Black Tree: Self-balancing binary search tree maintaining O(log n) operations
  • Iterator Pattern: Provides iterator objects for traversing tree contents
  • Functional API: Pure functions that don't modify input parameters

Capabilities

Tree Creation

Creates a new empty red-black tree with optional custom comparison function.

/**
 * Creates an empty functional tree
 * @param {function} [compare] - Optional comparison function (same semantics as Array.sort())
 * @returns {RedBlackTree} An empty tree ordered by compare function
 */
function createTree(compare);

Tree Properties

Access tree metadata and structure information.

// Number of items in the tree
tree.length;

// Sorted array of all keys in the tree
tree.keys;

// Array of all values in the tree  
tree.values;

// Root node of the tree (or null if empty)
tree.root;

// Iterator pointing to first element
tree.begin;

// Iterator pointing to last element
tree.end;

Tree Operations

Core operations for inserting, removing, and retrieving data.

/**
 * Creates a new tree with the key-value pair inserted
 * @param {*} key - Key of the item to insert
 * @param {*} value - Value of the item to insert
 * @returns {RedBlackTree} New tree with key and value inserted
 */
tree.insert(key, value);

/**
 * Removes the first item with key from tree
 * @param {*} key - Key of the item to remove
 * @returns {RedBlackTree} New tree with the given item removed if it exists
 */
tree.remove(key);

/**
 * Retrieves the value associated to the given key
 * @param {*} key - Key of the item to look up
 * @returns {*} The value of the first node associated to key, or undefined
 */
tree.get(key);

Tree Search

Methods for finding specific elements and ranges.

/**
 * Returns an iterator pointing to the first item with key
 * @param {*} key - Key to search for
 * @returns {RedBlackTreeIterator} Iterator at the element, or invalid iterator if not found
 */
tree.find(key);

/**
 * Find the first item in the tree whose key is >= key
 * @param {*} key - Key to search for
 * @returns {RedBlackTreeIterator} Iterator at the given element
 */
tree.ge(key);

/**
 * Finds the first item in the tree whose key is > key
 * @param {*} key - Key to search for
 * @returns {RedBlackTreeIterator} Iterator at the given element
 */
tree.gt(key);

/**
 * Finds the last item in the tree whose key is < key
 * @param {*} key - Key to search for
 * @returns {RedBlackTreeIterator} Iterator at the given element
 */
tree.lt(key);

/**
 * Finds the last item in the tree whose key is <= key
 * @param {*} key - Key to search for
 * @returns {RedBlackTreeIterator} Iterator at the given element
 */
tree.le(key);

/**
 * Finds an iterator starting at the given position index
 * @param {number} position - Index at which the iterator gets created
 * @returns {RedBlackTreeIterator} Iterator starting at position
 */
tree.at(position);

Tree Traversal

Methods for visiting tree elements in order.

/**
 * Walks a visitor function over the nodes of the tree in order
 * @param {function} visitor - Callback that gets executed on each node (key, value)
 * @param {*} [lo] - Optional start of the range to visit (inclusive)
 * @param {*} [hi] - Optional end of the range to visit (non-inclusive)
 * @returns {*} The last value returned by the callback
 */
tree.forEach(visitor, lo, hi);

Usage Examples:

var tree = createTree().insert(1, "a").insert(2, "b").insert(3, "c");

// Visit all nodes
tree.forEach(function(key, value) {
  console.log(key, value);
});

// Visit range [1, 3)
tree.forEach(function(key, value) {
  console.log(key, value);
}, 1, 3);

// Early termination
tree.forEach(function(key, value) {
  if (key === 2) return true; // Stop iteration
  console.log(key, value);
});

Iterator Interface

Iterator objects for traversing and manipulating tree contents.

// Iterator properties
iter.valid;     // boolean - Checks if the iterator is valid
iter.key;       // * - The key of the item referenced by the iterator
iter.value;     // * - The value of the item referenced by the iterator
iter.node;      // RBNode|null - The node at the iterator's current position
iter.tree;      // RedBlackTree - The tree associated to the iterator
iter.index;     // number - Returns the position of this iterator in the sequence
iter.hasNext;   // boolean - True if iterator is not at the end of the sequence
iter.hasPrev;   // boolean - True if iterator is not at the beginning of the sequence

/**
 * Makes a copy of the iterator
 * @returns {RedBlackTreeIterator} New iterator copy
 */
iter.clone();

/**
 * Removes the item at the position of the iterator
 * @returns {RedBlackTree} New binary search tree with iter's item removed
 */
iter.remove();

/**
 * Updates the value of the node in the tree at this iterator
 * @param {*} value - New value for the node
 * @returns {RedBlackTree} New binary search tree with the corresponding node updated
 * @throws {Error} Throws "Can't update empty node!" if iterator is invalid
 */
iter.update(value);

/**
 * Advances the iterator to the next position
 */
iter.next();

/**
 * Moves the iterator backward one element
 */
iter.prev();

Usage Examples:

var tree = createTree().insert(1, "a").insert(2, "b").insert(3, "c");

// Forward iteration
var iter = tree.begin;
while(iter.valid) {
  console.log(iter.key, iter.value);
  iter.next();
}

// Backward iteration
var iter = tree.end;
while(iter.valid) {
  console.log(iter.key, iter.value);
  iter.prev();
}

// Iterator modification
var newTree = tree.begin.update("modified");
var newTree2 = tree.find(2).remove();

Node Properties

Properties available on tree nodes accessed via iterators or tree.root.

// Node properties
node.key;    // * - The key associated to the node
node.value;  // * - The value associated to the node  
node.left;   // RBNode|null - The left subtree of the node
node.right;  // RBNode|null - The right subtree of the node

Types

/**
 * Red-black tree class
 */
function RedBlackTree(compare, root) {
  this._compare = compare;
  this.root = root;
}

/**
 * Tree node class
 */
function RBNode(color, key, value, left, right, count) {
  this._color = color;
  this.key = key;
  this.value = value;
  this.left = left;
  this.right = right;
  this._count = count;
}

/**
 * Iterator class for traversing tree
 */
function RedBlackTreeIterator(tree, stack) {
  this.tree = tree;
  this._stack = stack;
}

/**
 * Default comparison function
 * @param {*} a - First value to compare
 * @param {*} b - Second value to compare  
 * @returns {number} -1 if a < b, 1 if a > b, 0 if equal
 */
function defaultCompare(a, b) {
  if(a < b) return -1;
  if(a > b) return 1;
  return 0;
}

Advanced Usage

Custom Comparison Functions

// Custom string comparison (case-insensitive)
var tree = createTree(function(a, b) {
  a = a.toLowerCase();
  b = b.toLowerCase();
  if(a < b) return -1;
  if(a > b) return 1;
  return 0;
});

// Numeric comparison for objects
var tree = createTree(function(a, b) {
  return a.priority - b.priority;
});

Range Queries

var tree = createTree();
// ... populate tree ...

// Find all items between 10 and 20 (inclusive)
var results = [];
tree.forEach(function(key, value) {
  results.push({key: key, value: value});
}, 10, 21);

// Get iterator range
var start = tree.ge(10);  // First element >= 10
var end = tree.gt(20);    // First element > 20

Persistent Data Benefits

var t1 = createTree().insert(1, "a").insert(2, "b");
var t2 = t1.insert(3, "c");  // t1 is unchanged
var t3 = t1.remove(1);       // Both t1 and t2 are unchanged

// Can iterate over previous versions while modifying
t1.forEach(function(key, value) {
  console.log("t1:", key, value);
});

t2.forEach(function(key, value) {
  console.log("t2:", key, value);
});