/** * data-structure-typed * * @author Pablo Zeng * @copyright Copyright (c) 2022 Pablo Zeng * @license MIT License */ import type { BinaryTreeDeleteResult, BinaryTreeOptions, BinaryTreePrintOptions, BTNEntry, BTNRep, DFSOrderPattern, EntryCallback, FamilyPosition, IterationType, NodeCallback, NodeDisplayLayout, NodePredicate, RBTNColor, ToEntryFn } from '../../types'; import { IBinaryTree } from '../../interfaces'; import { IterableEntryBase } from '../base'; import { Range } from '../../common'; /** * @template K - The type of the key. * @template V - The type of the value. */ export declare class BinaryTreeNode { key: K; value?: V; parent?: BinaryTreeNode; /** * Creates an instance of BinaryTreeNode. * @remarks Time O(1), Space O(1) * * @param key - The key of the node. * @param [value] - The value associated with the key. */ constructor(key: K, value?: V); _left?: BinaryTreeNode | null | undefined; /** * Gets the left child of the node. * @remarks Time O(1), Space O(1) * * @returns The left child. */ get left(): BinaryTreeNode | null | undefined; /** * Sets the left child of the node and updates its parent reference. * @remarks Time O(1), Space O(1) * * @param v - The node to set as the left child. */ set left(v: BinaryTreeNode | null | undefined); _right?: BinaryTreeNode | null | undefined; /** * Gets the right child of the node. * @remarks Time O(1), Space O(1) * * @returns The right child. */ get right(): BinaryTreeNode | null | undefined; /** * Sets the right child of the node and updates its parent reference. * @remarks Time O(1), Space O(1) * * @param v - The node to set as the right child. */ set right(v: BinaryTreeNode | null | undefined); _height: number; /** * Gets the height of the node (used in self-balancing trees). * @remarks Time O(1), Space O(1) * * @returns The height. */ get height(): number; /** * Sets the height of the node. * @remarks Time O(1), Space O(1) * * @param value - The new height. */ set height(value: number); _color: RBTNColor; /** * Gets the color of the node (used in Red-Black trees). * @remarks Time O(1), Space O(1) * * @returns The node's color. */ get color(): RBTNColor; /** * Sets the color of the node. * @remarks Time O(1), Space O(1) * * @param value - The new color. */ set color(value: RBTNColor); _count: number; /** * Gets the count of nodes in the subtree rooted at this node (used in order-statistic trees). * @remarks Time O(1), Space O(1) * * @returns The subtree node count. */ get count(): number; /** * Sets the count of nodes in the subtree. * @remarks Time O(1), Space O(1) * * @param value - The new count. */ set count(value: number); /** * Gets the position of the node relative to its parent. * @remarks Time O(1), Space O(1) * * @returns The family position (e.g., 'ROOT', 'LEFT', 'RIGHT'). */ get familyPosition(): FamilyPosition; } /** * A general Binary Tree implementation. * * @remarks * This class implements a basic Binary Tree, not a Binary Search Tree. * The `set` operation inserts nodes level-by-level (BFS) into the first available slot. * * @template K - The type of the key. * @template V - The type of the value. * @template R - The type of the raw data object (if using `toEntryFn`). * 1. Two Children Maximum: Each node has at most two children. * 2. Left and Right Children: Nodes have distinct left and right children. * 3. Depth and Height: Depth is the number of edges from the root to a node; height is the maximum depth in the tree. * 4. Subtrees: Each child of a node forms the root of a subtree. * 5. Leaf Nodes: Nodes without children are leaves. * * @example * // determine loan approval using a decision tree * // Decision tree structure * const loanDecisionTree = new BinaryTree( * ['stableIncome', 'goodCredit', 'Rejected', 'Approved', 'Rejected'], * { isDuplicate: true } * ); * * function determineLoanApproval( * node?: BinaryTreeNode | null, * conditions?: { [key: string]: boolean } * ): string { * if (!node) throw new Error('Invalid node'); * * // If it's a leaf node, return the decision result * if (!node.left && !node.right) return node.key; * * // Check if a valid condition exists for the current node's key * return conditions?.[node.key] * ? determineLoanApproval(node.left, conditions) * : determineLoanApproval(node.right, conditions); * } * * // Test case 1: Stable income and good credit score * console.log(determineLoanApproval(loanDecisionTree.root, { stableIncome: true, goodCredit: true })); // 'Approved'; * * // Test case 2: Stable income but poor credit score * console.log(determineLoanApproval(loanDecisionTree.root, { stableIncome: true, goodCredit: false })); // 'Rejected'; * * // Test case 3: No stable income * console.log(determineLoanApproval(loanDecisionTree.root, { stableIncome: false, goodCredit: true })); // 'Rejected'; * * // Test case 4: No stable income and poor credit score * console.log(determineLoanApproval(loanDecisionTree.root, { stableIncome: false, goodCredit: false })); // 'Rejected'; * @example * // evaluate the arithmetic expression represented by the binary tree * const expressionTree = new BinaryTree(['+', 3, '*', null, null, 5, '-', null, null, 2, 8]); * * function evaluate(node?: BinaryTreeNode | null): number { * if (!node) return 0; * * if (typeof node.key === 'number') return node.key; * * const leftValue = evaluate(node.left); // Evaluate the left subtree * const rightValue = evaluate(node.right); // Evaluate the right subtree * * // Perform the operation based on the current node's operator * switch (node.key) { * case '+': * return leftValue + rightValue; * case '-': * return leftValue - rightValue; * case '*': * return leftValue * rightValue; * case '/': * return rightValue !== 0 ? leftValue / rightValue : 0; // Handle division by zero * default: * throw new Error(`Unsupported operator: ${node.key}`); * } * } * * console.log(evaluate(expressionTree.root)); // -27; */ export declare class BinaryTree extends IterableEntryBase implements IBinaryTree { iterationType: IterationType; /** * Creates an instance of BinaryTree. * @remarks Time O(N * M), where N is the number of items in `keysNodesEntriesOrRaws` and M is the tree size at insertion time (due to O(M) `set` operation). Space O(N) for storing the nodes. * * @param [keysNodesEntriesOrRaws=[]] - An iterable of items to set. * @param [options] - Configuration options for the tree. */ constructor(keysNodesEntriesOrRaws?: Iterable | [K | null | undefined, V | undefined] | null | undefined | R>, options?: BinaryTreeOptions); protected readonly _isMapMode: boolean; /** * Gets whether the tree is in Map mode. * @remarks In Map mode (default), values are stored in an external Map, and nodes only hold keys. If false, values are stored directly on the nodes. Time O(1) * * @returns True if in Map mode, false otherwise. */ get isMapMode(): boolean; protected readonly _isDuplicate: boolean; /** * Gets whether the tree allows duplicate keys. * @remarks Time O(1) * * @returns True if duplicates are allowed, false otherwise. */ get isDuplicate(): boolean; protected _store: Map>; /** * Gets the external value store (used in Map mode). * @remarks Time O(1) * * @returns The map storing key-value pairs. */ get store(): Map>; protected _root?: BinaryTreeNode | null | undefined; /** * Gets the root node of the tree. * @remarks Time O(1) * * @returns The root node. */ get root(): BinaryTreeNode | null | undefined; protected _size: number; /** * Gets the number of nodes in the tree. * @remarks Time O(1) * * @returns The size of the tree. */ get size(): number; protected readonly _NIL: BinaryTreeNode; /** * Gets the sentinel NIL node (used in self-balancing trees like Red-Black Tree). * @remarks Time O(1) * * @returns The NIL node. */ get NIL(): BinaryTreeNode; protected readonly _toEntryFn?: ToEntryFn; /** * Gets the function used to convert raw data objects (R) into [key, value] entries. * @remarks Time O(1) * * @returns The conversion function. */ get toEntryFn(): ToEntryFn | undefined; /** * (Protected) Creates a new node. * @remarks Time O(1), Space O(1) * * @param key - The key for the new node. * @param [value] - The value for the new node (used if not in Map mode). * @returns The newly created node. */ createNode(key: K, value?: V): BinaryTreeNode; /** * Creates a new, empty tree of the same type and configuration. * @remarks Time O(1) (excluding options cloning), Space O(1) * * @param [options] - Optional overrides for the new tree's options. * @returns A new, empty tree instance. */ createTree(options?: Partial>): this; /** * Ensures the input is a node. If it's a key or entry, it searches for the node. * @remarks Time O(1) if a node is passed. O(N) if a key or entry is passed (due to `getNode` performing a full search). Space O(1) if iterative search, O(H) if recursive (where H is height, O(N) worst-case). * * @param keyNodeOrEntry - The item to resolve to a node. * @param [iterationType=this.iterationType] - The traversal method to use if searching. * @returns The resolved node, or null/undefined if not found or input is null/undefined. */ ensureNode(keyNodeOrEntry: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined, iterationType?: IterationType): BinaryTreeNode | null | undefined; /** * Checks if the given item is a `BinaryTreeNode` instance. * @remarks Time O(1), Space O(1) * * @param keyNodeOrEntry - The item to check. * @returns True if it's a node, false otherwise. */ isNode(keyNodeOrEntry: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined): keyNodeOrEntry is BinaryTreeNode; /** * Checks if the given item is a raw data object (R) that needs conversion via `toEntryFn`. * @remarks Time O(1), Space O(1) * * @param keyNodeEntryOrRaw - The item to check. * @returns True if it's a raw object, false otherwise. */ isRaw(keyNodeEntryOrRaw: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined | R): keyNodeEntryOrRaw is R; /** * Checks if the given item is a "real" node (i.e., not null, undefined, or NIL). * @remarks Time O(1), Space O(1) * * @param keyNodeOrEntry - The item to check. * @returns True if it's a real node, false otherwise. */ isRealNode(keyNodeOrEntry: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined): keyNodeOrEntry is BinaryTreeNode; /** * Checks if the given item is either a "real" node or null. * @remarks Time O(1), Space O(1) * * @param keyNodeOrEntry - The item to check. * @returns True if it's a real node or null, false otherwise. */ isRealNodeOrNull(keyNodeOrEntry: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined): keyNodeOrEntry is BinaryTreeNode | null; /** * Checks if the given item is the sentinel NIL node. * @remarks Time O(1), Space O(1) * * @param keyNodeOrEntry - The item to check. * @returns True if it's the NIL node, false otherwise. */ isNIL(keyNodeOrEntry: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined): boolean; /** * Checks if the given item is a `Range` object. * @remarks Time O(1), Space O(1) * * @param keyNodeEntryOrPredicate - The item to check. * @returns True if it's a Range, false otherwise. */ isRange(keyNodeEntryOrPredicate: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined | NodePredicate> | Range): keyNodeEntryOrPredicate is Range; /** * Checks if a node is a leaf (has no real children). * @remarks Time O(N) if a key/entry is passed (due to `ensureNode`). O(1) if a node is passed. Space O(1) or O(H) (from `ensureNode`). * * @param keyNodeOrEntry - The node to check. * @returns True if the node is a leaf, false otherwise. */ isLeaf(keyNodeOrEntry: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined): boolean; /** * Checks if the given item is a [key, value] entry pair. * @remarks Time O(1), Space O(1) * * @param keyNodeOrEntry - The item to check. * @returns True if it's an entry, false otherwise. */ isEntry(keyNodeOrEntry: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined): keyNodeOrEntry is BTNEntry; /** * Checks if the given key is valid (comparable or null). * @remarks Time O(1), Space O(1) * * @param key - The key to validate. * @returns True if the key is valid, false otherwise. */ isValidKey(key: unknown): key is K; /** * Adds a new node to the tree. * @remarks Time O(N) — level-order traversal to find an empty slot. Space O(N) for the BFS queue. BST/Red-Black Tree/AVL Tree subclasses override to O(log N). * * @param keyNodeOrEntry - The key, node, or entry to add. * @returns True if the addition was successful, false otherwise. * @example * // Add a single node * const tree = new BinaryTree(); * tree.add(1); * tree.add(2); * tree.add(3); * console.log(tree.size); // 3; * console.log(tree.has(1)); // true; */ add(keyNodeOrEntry: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined): boolean; /** * Adds or updates a new node to the tree. * @remarks Time O(N) — level-order traversal to find an empty slot. Space O(N) for the BFS queue. BST/Red-Black Tree/AVL Tree subclasses override to O(log N). * * @param keyNodeOrEntry - The key, node, or entry to set or update. * @param [value] - The value, if providing just a key. * @returns True if the addition was successful, false otherwise. * @example * // basic BinaryTree creation and insertion * // Create a BinaryTree with entries * const entries: [number, string][] = [ * [6, 'six'], * [1, 'one'], * [2, 'two'], * [7, 'seven'], * [5, 'five'], * [3, 'three'], * [4, 'four'], * [9, 'nine'], * [8, 'eight'] * ]; * * const tree = new BinaryTree(entries); * * // Verify size * console.log(tree.size); // 9; * * // Add new element * tree.set(10, 'ten'); * console.log(tree.size); // 10; */ set(keyNodeOrEntry: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined, value?: V): boolean; /** * Adds multiple items to the tree. * @remarks Time O(N * M), where N is the number of items to set and M is the size of the tree at insertion (due to O(M) `set` operation). Space O(M) (from `set`) + O(N) (for the `inserted` array). * * @param keysNodesEntriesOrRaws - An iterable of items to set. * @returns An array of booleans indicating the success of each individual `set` operation. * @example * // Bulk add * const tree = new BinaryTree(); * tree.addMany([1, 2, 3, 4, 5]); * console.log(tree.size); // 5; */ addMany(keysNodesEntriesOrRaws: Iterable | [K | null | undefined, V | undefined] | null | undefined | R>): boolean[]; /** * Adds or updates multiple items to the tree. * @remarks Time O(N * M), where N is the number of items to set and M is the size of the tree at insertion (due to O(M) `set` operation). Space O(M) (from `set`) + O(N) (for the `inserted` array). * * @param keysNodesEntriesOrRaws - An iterable of items to set or update. * @param [values] - An optional parallel iterable of values. * @returns An array of booleans indicating the success of each individual `set` operation. * @example * // Set multiple entries * const tree = new BinaryTree(); * tree.setMany([[1, 'a'], [2, 'b'], [3, 'c']]); * console.log(tree.size); // 3; */ setMany(keysNodesEntriesOrRaws: Iterable | [K | null | undefined, V | undefined] | null | undefined | R>, values?: Iterable): boolean[]; /** * Merges another tree into this one by seting all its nodes. * @remarks Time O(N * M), same as `setMany`, where N is the size of `anotherTree` and M is the size of this tree. Space O(M) (from `set`). * * @param anotherTree - The tree to merge. * @example * // Combine trees * const t1 = new BinaryTree([1, 2]); * const t2 = new BinaryTree([3, 4]); * t1.merge(t2); * console.log(t1.size); // 4; */ merge(anotherTree: BinaryTree): void; /** * Deletes a node from the tree (internal, returns balancing metadata). * @remarks Time O(N) — O(N) to find the node + O(H) for predecessor swap. Space O(1). BST/Red-Black Tree/AVL Tree subclasses override to O(log N). * @internal Used by AVL/BST subclasses that need balancing metadata after deletion. * * @param keyNodeEntryRawOrPredicate - The node to delete. * @returns An array containing deletion results with balancing metadata. */ protected _deleteInternal(keyNodeEntryRawOrPredicate: BTNRep> | NodePredicate | null>): BinaryTreeDeleteResult>[]; /** * Deletes a node from the tree. * @remarks Time O(N) — O(N) to find the node + O(H) for predecessor swap. Space O(1). BST/Red-Black Tree/AVL Tree subclasses override to O(log N). * * @param keyNodeEntryRawOrPredicate - The node to delete. * @returns True if the node was found and deleted, false otherwise. * @example * // Remove a node * const tree = new BinaryTree([1, 2, 3, 4, 5]); * tree.delete(3); * console.log(tree.has(3)); // false; * console.log(tree.size); // 4; */ delete(keyNodeEntryRawOrPredicate: BTNRep> | NodePredicate | null>): boolean; /** * Search by predicate * @example * // Search by predicate * const tree = new BinaryTree([5, 3, 7, 1, 9]); * const found = tree.search(n => n!.key > 5, true); * console.log(found.length); // >= 1; */ search(keyNodeEntryOrPredicate: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined | NodePredicate | null>, onlyOne?: boolean): (K | undefined)[]; search | null>>(keyNodeEntryOrPredicate: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined | NodePredicate | null>, onlyOne: boolean, callback: C, startNode?: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined, iterationType?: IterationType): ReturnType[]; /** * Gets all nodes matching a predicate. * @remarks Time O(N) (via `search`). Space O(H) or O(N) (via `search`). * * @param keyNodeEntryOrPredicate - The key, node, entry, or predicate function to search for. * @param [onlyOne=false] - If true, stops after finding the first match. * @param [startNode=this._root] - The node to start the search from. * @param [iterationType=this.iterationType] - The traversal method. * @returns An array of matching nodes. * @example * // Get nodes by condition * const tree = new BinaryTree([1, 2, 3, 4, 5]); * const nodes = tree.getNodes(node => node.key > 3); * console.log(nodes.length); // 2; */ getNodes(keyNodeEntryOrPredicate: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined | NodePredicate>, onlyOne?: boolean, startNode?: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined, iterationType?: IterationType): BinaryTreeNode[]; /** * Gets the first node matching a predicate. * @remarks Time O(N) via `search`. Space O(H) or O(N). BST/Red-Black Tree/AVL Tree subclasses override to O(log N) for key lookups. * * @param keyNodeEntryOrPredicate - The key, node, entry, or predicate function to search for. * @param [startNode=this._root] - The node to start the search from. * @param [iterationType=this.iterationType] - The traversal method. * @returns The first matching node, or undefined if not found. * @example * // Get node by key * const tree = new BinaryTree([[1, 'root'], [2, 'child']]); * console.log(tree.getNode(2)?.value); // 'child'; */ getNode(keyNodeEntryOrPredicate: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined | NodePredicate | null>, startNode?: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined, iterationType?: IterationType): BinaryTreeNode | null | undefined; /** * Gets the value associated with a key. * @remarks Time O(1) in Map mode, O(N) otherwise (via `getNode`). Space O(1) in Map mode, O(H) or O(N) otherwise. BST subclasses override non-Map-mode to O(log N). * * @param keyNodeEntryOrPredicate - The key, node, or entry to get the value for. * @param [startNode=this._root] - The node to start searching from (if not in Map mode). * @param [iterationType=this.iterationType] - The traversal method (if not in Map mode). * @returns The associated value, or undefined. * @example * // Retrieve value by key * const tree = new BinaryTree([[1, 'root'], [2, 'left'], [3, 'right']]); * console.log(tree.get(2)); // 'left'; * console.log(tree.get(99)); // undefined; */ get(keyNodeEntryOrPredicate: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined, startNode?: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined, iterationType?: IterationType): V | undefined; /** * Checks if a node matching the predicate exists in the tree. * @remarks Time O(N) via `search`. Space O(H) or O(N). BST/Red-Black Tree/AVL Tree subclasses override to O(log N) for key lookups. * * @param [keyNodeEntryOrPredicate] - The key, node, entry, or predicate to check for. * @param [startNode] - The node to start the search from. * @param [iterationType] - The traversal method. * @returns True if a matching node exists, false otherwise. * @example * // BinaryTree get and has operations * const tree = new BinaryTree( * [ * [5, 'five'], * [3, 'three'], * [7, 'seven'], * [1, 'one'], * [4, 'four'], * [6, 'six'], * [8, 'eight'] * ], * { isMapMode: false } * ); * * // Check if key exists * console.log(tree.has(5)); // true; * console.log(tree.has(10)); // false; * * // Get value by key * console.log(tree.get(3)); // 'three'; * console.log(tree.get(7)); // 'seven'; * console.log(tree.get(100)); // undefined; * * // Get node structure * const node = tree.getNode(5); * console.log(node?.key); // 5; * console.log(node?.value); // 'five'; */ has(keyNodeEntryOrPredicate?: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined | NodePredicate>, startNode?: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined, iterationType?: IterationType): boolean; /** * Clears the tree of all nodes and values. * @remarks Time O(N) if in Map mode (due to `_store.clear()`), O(1) otherwise. Space O(1) * @example * // Remove all nodes * const tree = new BinaryTree([1, 2, 3]); * tree.clear(); * console.log(tree.isEmpty()); // true; */ clear(): void; /** * Checks if the tree is empty. * @remarks Time O(1), Space O(1) * * @returns True if the tree has no nodes, false otherwise. * @example * // Check empty * console.log(new BinaryTree().isEmpty()); // true; */ isEmpty(): boolean; /** * Checks if the tree is perfectly balanced. * @remarks A tree is perfectly balanced if the difference between min and max height is at most 1. Time O(N), as it requires two full traversals (`getMinHeight` and `getHeight`). Space O(H) or O(N) (from height calculation). * * @param [startNode=this._root] - The node to start checking from. * @returns True if perfectly balanced, false otherwise. */ isPerfectlyBalanced(startNode?: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined): boolean; /** * Checks if the tree is a valid Binary Search Tree (BST). * @remarks Time O(N), as it must visit every node. Space O(H) for the call stack (recursive) or explicit stack (iterative), where H is the tree height (O(N) worst-case). * * @param [startNode=this._root] - The node to start checking from. * @param [iterationType=this.iterationType] - The traversal method. * @returns True if it's a valid BST, false otherwise. * @example * // Check BST property * const tree = new BinaryTree([1, 2, 3]); * // BinaryTree doesn't guarantee BST order * console.log(typeof tree.isBST()); // 'boolean'; */ isBST(startNode?: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined, iterationType?: IterationType): boolean; /** * Gets the depth of a node (distance from `startNode`). * @remarks Time O(H), where H is the depth of the `dist` node relative to `startNode`. O(N) worst-case. Space O(1). * * @param dist - The node to find the depth of. * @param [startNode=this._root] - The node to measure depth from (defaults to root). * @returns The depth (0 if `dist` is `startNode`). * @example * // Get depth of a node * const tree = new BinaryTree([1, 2, 3, 4, 5]); * const node = tree.getNode(4); * console.log(tree.getDepth(node!)); // 2; */ getDepth(dist: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined, startNode?: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined): number; /** * Gets the maximum height of the tree (longest path from startNode to a leaf). * @remarks Time O(N), as it must visit every node. Space O(H) for recursive stack (O(N) worst-case) or O(N) for iterative stack (storing node + depth). * * @param [startNode=this._root] - The node to start measuring from. * @param [iterationType=this.iterationType] - The traversal method. * @returns The height ( -1 for an empty tree, 0 for a single-node tree). * @example * // Get tree height * const tree = new BinaryTree([1, 2, 3, 4, 5]); * console.log(tree.getHeight()); // 2; */ getHeight(startNode?: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined, iterationType?: IterationType): number; /** * Gets the minimum height of the tree (shortest path from startNode to a leaf). * @remarks Time O(N), as it must visit every node. Space O(H) for recursive stack (O(N) worst-case) or O(N) for iterative (due to `depths` Map). * * @param [startNode=this._root] - The node to start measuring from. * @param [iterationType=this.iterationType] - The traversal method. * @returns The minimum height (-1 for empty, 0 for single node). */ getMinHeight(startNode?: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined, iterationType?: IterationType): number; getPathToRoot(beginNode: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined): (K | undefined)[]; getPathToRoot | undefined>>(beginNode: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined, callback: C, isReverse?: boolean): ReturnType[]; getLeftMost(): K | undefined; getLeftMost | undefined>>(callback: C, startNode?: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined, iterationType?: IterationType): ReturnType; getRightMost(): K | undefined; getRightMost | undefined>>(callback: C, startNode?: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined, iterationType?: IterationType): ReturnType; /** * Gets the Morris traversal predecessor (rightmost node in the left subtree, or node itself). * @remarks This is primarily a helper for Morris traversal. Time O(H), where H is the height of the left subtree. O(N) worst-case. Space O(1). * * @param node - The node to find the predecessor for. * @returns The Morris predecessor. */ getPredecessor(node: BinaryTreeNode): BinaryTreeNode; /** * Gets the in-order successor of a node in a BST. * @remarks Time O(H), where H is the tree height. O(N) worst-case. Space O(H) (due to `getLeftMost` stack). * * @param [x] - The node to find the successor of. * @returns The successor node, or null/undefined if none exists. */ getSuccessor(x?: K | BinaryTreeNode | null): BinaryTreeNode | null | undefined; /** * Depth-first search traversal * @example * // Depth-first search traversal * const tree = new BinaryTree([1, 2, 3, 4, 5]); * const inOrder = tree.dfs(node => node.key, 'IN'); * console.log(inOrder); // [4, 2, 5, 1, 3]; */ dfs(): (K | undefined)[]; dfs>>(callback?: C, pattern?: DFSOrderPattern, onlyOne?: boolean, startNode?: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined, iterationType?: IterationType): ReturnType[]; dfs | null>>(callback?: C, pattern?: DFSOrderPattern, onlyOne?: boolean, startNode?: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined, iterationType?: IterationType, includeNull?: boolean): ReturnType[]; /** * BinaryTree level-order traversal * @example * // BinaryTree level-order traversal * const tree = new BinaryTree([ * [1, 'one'], * [2, 'two'], * [3, 'three'], * [4, 'four'], * [5, 'five'], * [6, 'six'], * [7, 'seven'] * ]); * * // Binary tree maintains level-order insertion * // Complete binary tree structure * console.log(tree.size); // 7; * * // Verify all keys are present * console.log(tree.has(1)); // true; * console.log(tree.has(4)); // true; * console.log(tree.has(7)); // true; * * // Iterate through tree * const keys: number[] = []; * for (const [key] of tree) { * keys.push(key); * } * console.log(keys.length); // 7; */ bfs(): (K | undefined)[]; bfs>>(callback?: C, startNode?: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined, iterationType?: IterationType, includeNull?: false): ReturnType[]; bfs | null>>(callback?: C, startNode?: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined, iterationType?: IterationType, includeNull?: true): ReturnType[]; /** * Get leaf nodes * @example * // Get leaf nodes * const tree = new BinaryTree([1, 2, 3, 4, 5]); * const leafKeys = tree.leaves(node => node.key); * console.log(leafKeys.length); // > 0; */ leaves(): (K | undefined)[]; leaves>>(callback: C, startNode?: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined, iterationType?: IterationType): ReturnType[]; /** * Level-order grouping * @example * // Level-order grouping * const tree = new BinaryTree([1, 2, 3, 4, 5]); * const levels = tree.listLevels(node => node.key); * console.log(levels[0]); // [1]; * console.log(levels[1].sort()); // [2, 3]; */ listLevels(): (K | undefined)[][]; listLevels>>(callback?: C, startNode?: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined, iterationType?: IterationType, includeNull?: false): ReturnType[][]; listLevels | null>>(callback?: C, startNode?: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined, iterationType?: IterationType, includeNull?: true): ReturnType[][]; /** * Morris traversal (O(1) space) * @example * // Morris traversal (O(1) space) * const tree = new BinaryTree([1, 2, 3]); * const result = tree.morris(node => node.key, 'IN'); * console.log(result.length); // 3; */ morris(): (K | undefined)[]; morris>>(callback?: C, pattern?: DFSOrderPattern, startNode?: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined): ReturnType[]; /** * Clones the tree. * @remarks Time O(N * M), where N is the number of nodes and M is the tree size during insertion (due to `bfs` + `set`, and `set` is O(M)). Space O(N) for the new tree and the BFS queue. * * @returns A new, cloned instance of the tree. * @example * // Deep copy * const tree = new BinaryTree([1, 2, 3]); * const copy = tree.clone(); * copy.delete(1); * console.log(tree.has(1)); // true; */ clone(): this; /** * Creates a new tree containing only the entries that satisfy the predicate. * @remarks Time O(N * M), where N is nodes in this tree, and M is size of the new tree during insertion (O(N) iteration + O(M) `set` for each item). Space O(N) for the new tree. * * @param predicate - A function to test each [key, value] pair. * @param [thisArg] - `this` context for the predicate. * @returns A new, filtered tree. * @example * // Filter nodes by condition * const tree = new BinaryTree([1, 2, 3, 4]); * const result = tree.filter((_, key) => key > 2); * console.log(result.size); // 2; */ filter(predicate: EntryCallback, thisArg?: unknown): this; /** * Creates a new tree by mapping each [key, value] pair to a new entry. * @remarks Time O(N * M), where N is nodes in this tree, and M is size of the new tree during insertion. Space O(N) for the new tree. * * @template MK - New key type. * @template MV - New value type. * @template MR - New raw type. * @param cb - A function to map each [key, value] pair. * @param [options] - Options for the new tree. * @param [thisArg] - `this` context for the callback. * @returns A new, mapped tree. * @example * // Transform to new tree * const tree = new BinaryTree([[1, 10], [2, 20]]); * const mapped = tree.map((v, key) => [key, (v ?? 0) + 1] as [number, number]); * console.log([...mapped.values()]); // contains 11; */ map(cb: EntryCallback, options?: Partial>, thisArg?: unknown): BinaryTree; /** * Generates a string representation of the tree for visualization. * @remarks Time O(N), visits every node. Space O(N*H) or O(N^2) in the worst case, as the string width can grow significantly. * * @param [startNode=this._root] - The node to start printing from. * @param [options] - Options to control the output (e.g., show nulls). * @returns The string representation of the tree. */ toVisual(startNode?: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined, options?: BinaryTreePrintOptions): string; /** * Prints a visual representation of the tree to the console. * @remarks Time O(N) (via `toVisual`). Space O(N*H) or O(N^2) (via `toVisual`). * * @param [options] - Options to control the output. * @param [startNode=this._root] - The node to start printing from. * @example * // Display tree * const tree = new BinaryTree([1, 2, 3]); * expect(() => tree.print()).not.toThrow(); */ print(options?: BinaryTreePrintOptions, startNode?: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined): void; protected _dfs>>(callback: C, pattern?: DFSOrderPattern, onlyOne?: boolean, startNode?: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined, iterationType?: IterationType, includeNull?: boolean, shouldVisitLeft?: (node: BinaryTreeNode | null | undefined) => boolean, shouldVisitRight?: (node: BinaryTreeNode | null | undefined) => boolean, shouldVisitRoot?: (node: BinaryTreeNode | null | undefined) => boolean, shouldProcessRoot?: (node: BinaryTreeNode | null | undefined) => boolean): ReturnType[]; /** * (Protected) Gets the iterator for the tree (default in-order). * @remarks Time O(N) for full iteration. O(H) to get the first element. Space O(H) for the iterative stack. O(H) for recursive stack. * * @param [node=this._root] - The node to start iteration from. * @returns An iterator for [key, value] pairs. */ protected _getIterator(node?: BinaryTreeNode | null | undefined): IterableIterator<[K, V | undefined]>; /** * (Protected) Default callback function, returns the node's key. * @remarks Time O(1) * * @param node - The node. * @returns The node's key or undefined. */ protected readonly _DEFAULT_NODE_CALLBACK: NodeCallback | null | undefined, K | undefined>; /** * (Protected) Snapshots the current tree's configuration options. * @remarks Time O(1) * * @template TK, TV, TR - Generic types for the options. * @returns The options object. */ protected _snapshotOptions(): BinaryTreeOptions; /** * (Protected) Creates a new, empty instance of the same tree constructor. * @remarks Time O(1) * * @template TK, TV, TR - Generic types for the new instance. * @param [options] - Options for the new tree. * @returns A new, empty tree. */ protected _createInstance(options?: Partial>): this; /** * (Protected) Creates a new instance of the same tree constructor, potentially with different generic types. * @remarks Time O(N) (or as per constructor) due to processing the iterable. * * @template TK, TV, TR - Generic types for the new instance. * @param [iter=[]] - An iterable to populate the new tree. * @param [options] - Options for the new tree. * @returns A new tree. */ protected _createLike(iter?: Iterable | [TK | null | undefined, TV | undefined] | null | undefined | TR>, options?: Partial>): BinaryTree; /** * (Protected) Converts a key, node, or entry into a standardized [node, value] tuple. * @remarks Time O(1) * * @param keyNodeOrEntry - The input item. * @param [value] - An optional value (used if input is just a key). * @returns A tuple of [node, value]. */ protected _keyValueNodeOrEntryToNodeAndValue(keyNodeOrEntry: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined, value?: V): [BinaryTreeNode | null | undefined, V | undefined]; /** * (Protected) Helper for cloning. Performs a BFS and sets all nodes to the new tree. * @remarks Time O(N * M) (O(N) BFS + O(M) `set` for each node). * * @param cloned - The new, empty tree instance to populate. */ protected _clone(cloned: BinaryTree): void; /** * (Protected) Recursive helper for `toVisual`. * @remarks Time O(N), Space O(N*H) or O(N^2) * * @param node - The current node. * @param options - Print options. * @returns Layout information for this subtree. */ protected _displayAux(node: BinaryTreeNode | null | undefined, options: BinaryTreePrintOptions): NodeDisplayLayout; protected static _buildNodeDisplay(line: string, width: number, left: NodeDisplayLayout, right: NodeDisplayLayout): NodeDisplayLayout; /** * Check if a node is a display leaf (empty, null, undefined, NIL, or real leaf). */ protected _isDisplayLeaf(node: BinaryTreeNode | null | undefined, options: BinaryTreePrintOptions): boolean; protected _hasDisplayableChild(child: BinaryTreeNode | null | undefined, options: BinaryTreePrintOptions): boolean; /** * Resolve a display leaf node to its layout. */ protected _resolveDisplayLeaf(node: BinaryTreeNode | null | undefined, options: BinaryTreePrintOptions, emptyDisplayLayout: NodeDisplayLayout): NodeDisplayLayout; /** * (Protected) Swaps the key/value properties of two nodes. * @remarks Time O(1) * * @param srcNode - The source node. * @param destNode - The destination node. * @returns The `destNode` (now holding `srcNode`'s properties). */ protected _swapProperties(srcNode: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined, destNode: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined): BinaryTreeNode | undefined; /** * (Protected) Replaces a node in the tree with a new node, maintaining children and parent links. * @remarks Time O(1) * * @param oldNode - The node to be replaced. * @param newNode - The node to insert. * @returns The `newNode`. */ protected _replaceNode(oldNode: BinaryTreeNode, newNode: BinaryTreeNode): BinaryTreeNode; /** * (Protected) Sets the root node and clears its parent reference. * @remarks Time O(1) * * @param v - The node to set as root. */ protected _setRoot(v: BinaryTreeNode | null | undefined): void; /** * (Protected) Converts a key, node, entry, or predicate into a standardized predicate function. * @remarks Time O(1) * * @param keyNodeEntryOrPredicate - The item to convert. * @returns A predicate function. */ protected _ensurePredicate(keyNodeEntryOrPredicate: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined | NodePredicate>): NodePredicate>; /** * (Protected) Checks if an item is a predicate function. * @remarks Time O(1) * * @param p - The item to check. * @returns True if it's a function. */ protected _isPredicate(p: unknown): p is NodePredicate>; /** * (Protected) Extracts the key from a key, node, or entry. * @remarks Time O(1) * * @param keyNodeOrEntry - The item. * @returns The extracted key. */ protected _extractKey(keyNodeOrEntry: K | BinaryTreeNode | [K | null | undefined, V | undefined] | null | undefined): K | null | undefined; /** * (Protected) Sets a value in the external store (Map mode). * @remarks Time O(1) (average for Map.set). * * @param key - The key. * @param value - The value. * @returns True if successful. */ protected _setValue(key: K | null | undefined, value: V | undefined): boolean; /** * (Protected) Clears all nodes from the tree. * @remarks Time O(1) */ protected _clearNodes(): void; /** * (Protected) Clears all values from the external store. * @remarks Time O(N) */ protected _clearValues(): void; }