undirected-graph-typed
Version:
Undirected Graph
5,042 lines (524 loc) • 46.4 kB
TypeScript
/**
* TreeSet (ordered set) — a restricted, native-like API backed by RedBlackTree.
*
* Design goals:
* - No node exposure (no node inputs/outputs)
* - Native Set-like surface + Java NavigableSet-like helpers
* - Strict default comparator (number/string/Date), otherwise require comparator
*/
import type { Comparator } from '../../types';
import type { TreeSetElementCallback, TreeSetOptions, TreeSetRangeOptions, TreeSetReduceCallback } from '../../types';
/**
* An ordered Set backed by a red-black tree.
*
* - Iteration order is ascending by key.
* - No node exposure: all APIs use keys only.
* @example
* // Set multiple key-value pairs
* const ts = new TreeSet<number, string>();
* ts.setMany([[1, 'a'], [2, 'b'], [3, 'c']]);
* console.log(ts.size); // 3;
*/
export declare class TreeSet<K = any, R = K> implements Iterable<K> {
#private;
/**
* Create a TreeSet from an iterable of keys or raw elements.
*
* @param elements - Iterable of keys, or raw elements if `toElementFn` is provided.
* @param options - Configuration options including optional `toElementFn` to transform raw elements.
* @throws {TypeError} When using the default comparator and encountering unsupported key types,
* or invalid keys (e.g. `NaN`, invalid `Date`).
* @example
* // Standard usage with keys
* const set = new TreeSet([3, 1, 2]);
*
* // Using toElementFn to transform raw objects
* const users = [{ id: 3, name: 'Alice' }, { id: 1, name: 'Bob' }];
* const set = new TreeSet<number, User>(users, { toElementFn: u => u.id });
*/
constructor(elements?: Iterable<R> | Iterable<K>, options?: TreeSetOptions<K, R>);
/**
* Create the strict default comparator.
*
* Supports:
* - `number` (rejects `NaN`; treats `-0` and `0` as equal)
* - `string`
* - `Date` (orders by `getTime()`, rejects invalid dates)
*
* For other key types, a custom comparator must be provided.
*/
static createDefaultComparator<K>(): Comparator<K>;
/**
* Number of elements in the set.
*/
get size(): number;
/**
* Whether the set is empty.
* @example
* // Check empty
* console.log(new TreeSet().isEmpty()); // true;
*/
isEmpty(): boolean;
private _validateKey;
/**
* Add a key to the set (no-op if already present).
* @remarks Expected time O(log n)
* @example
* // Unique tags with sorted order
* const tags = new TreeSet<string>(['javascript', 'typescript', 'react', 'typescript', 'node']);
*
* // Duplicates removed, sorted alphabetically
* console.log([...tags]); // ['javascript', 'node', 'react', 'typescript'];
* console.log(tags.size); // 4;
*
* tags.add('angular');
* console.log(tags.first()); // 'angular';
* console.log(tags.last()); // 'typescript';
*/
add(key: K): this;
/**
* Add multiple keys at once.
* @remarks Expected time O(m log n), where m is the number of keys.
* @param keys - Iterable of keys to add.
* @returns Array of booleans indicating whether each key was newly added.
* @example
* // Add multiple keys
* const ts = new TreeSet<number>();
* ts.addMany([5, 3, 7, 1, 9]);
* console.log(ts.size); // 5;
*/
addMany(keys: Iterable<K>): boolean[];
/**
* Test whether a key exists.
* @remarks Expected time O(log n)
* @example
* // Checking membership in a sorted collection
* const allowed = new TreeSet<string>(['admin', 'editor', 'viewer']);
*
* console.log(allowed.has('admin')); // true;
* console.log(allowed.has('guest')); // false;
*/
has(key: K): boolean;
/**
* Delete a key.
* @returns `true` if the key existed; otherwise `false`.
* @remarks Expected time O(log n)
* @example
* // Removing elements while maintaining order
* const nums = new TreeSet<number>([1, 3, 5, 7, 9]);
*
* console.log(nums.delete(5)); // true;
* console.log(nums.delete(5)); // false; // already gone
* console.log([...nums]); // [1, 3, 7, 9];
*/
delete(key: K): boolean;
/**
* Delete all keys matching a predicate.
* @remarks Time O(N), Space O(N)
* @param predicate - Function (key, index, set) → boolean; return true to delete.
* @returns True if at least one key was deleted.
*/
deleteWhere(predicate: (key: K, index: number, set: this) => boolean): boolean;
/**
* Remove all keys.
* @example
* // Remove all
* const ts = new TreeSet<number>([1, 2]);
* ts.clear();
* console.log(ts.isEmpty()); // true;
*/
clear(): void;
/**
* Iterate over keys in ascending order.
* @example
* // Get sorted keys
* const ts = new TreeSet<number>([30, 10, 20]);
* console.log([...ts.keys()]); // [10, 20, 30];
*/
keys(): IterableIterator<K>;
/**
* Iterate over values in ascending order.
*
* Note: for Set-like containers, `values()` is the same as `keys()`.
* @example
* // Get values (same as keys for Set)
* const ts = new TreeSet<number>([2, 1, 3]);
* console.log([...ts.values()]); // [1, 2, 3];
*/
values(): IterableIterator<K>;
/**
* Iterate over `[value, value]` pairs (native Set convention).
*
* Note: TreeSet stores only keys internally; `[k, k]` is created on-the-fly during iteration.
* @example
* // Iterate entries
* const ts = new TreeSet<number>([3, 1, 2]);
* console.log([...ts.entries()].map(([k]) => k)); // [1, 2, 3];
*/
entries(): IterableIterator<[K, K]>;
[Symbol.iterator](): IterableIterator<K>;
/**
* Visit each value in ascending order.
*
* Callback follows native Set convention: `(value, value2, set)`.
* @example
* // Execute for each
* const ts = new TreeSet<number>([3, 1, 2]);
* const keys: number[] = [];
* ts.forEach(k => keys.push(k));
* console.log(keys); // [1, 2, 3];
*/
forEach(cb: (value: K, value2: K, set: TreeSet<K>) => void, thisArg?: unknown): void;
/**
* Create a new TreeSet by mapping each value to a new key.
*
* This mirrors `RedBlackTree.map`: mapping produces a new ordered container.
* @remarks Time O(n log n) expected, Space O(n)
* @example
* // Transform
* const ts = new TreeSet<number>([1, 2, 3]);
* const doubled = ts.map(k => k * 2);
* console.log([...doubled]); // [2, 4, 6];
*/
map<MK>(callbackfn: TreeSetElementCallback<K, MK, TreeSet<K>>, options?: Omit<TreeSetOptions<MK>, 'toElementFn'> & {
comparator?: (a: MK, b: MK) => number;
}, thisArg?: unknown): TreeSet<MK>;
/**
* Create a new TreeSet containing only values that satisfy the predicate.
* @remarks Time O(n log n) expected, Space O(n)
* @example
* // Filter
* const ts = new TreeSet<number>([1, 2, 3, 4, 5]);
* const evens = ts.filter(k => k % 2 === 0);
* console.log([...evens]); // [2, 4];
*/
filter(callbackfn: TreeSetElementCallback<K, boolean, TreeSet<K>>, thisArg?: unknown): TreeSet<K>;
/**
* Reduce values into a single accumulator.
* @remarks Time O(n), Space O(1)
* @example
* // Aggregate
* const ts = new TreeSet<number>([1, 2, 3]);
* const sum = ts.reduce((acc, k) => acc + k, 0);
* console.log(sum); // 6;
*/
reduce<A>(callbackfn: TreeSetReduceCallback<K, A, TreeSet<K>>, initialValue: A): A;
/**
* Test whether all values satisfy a predicate.
* @remarks Time O(n), Space O(1)
* @example
* // Test all
* const ts = new TreeSet<number>([2, 4, 6]);
* console.log(ts.every(k => k > 0)); // true;
*/
every(callbackfn: TreeSetElementCallback<K, boolean, TreeSet<K>>, thisArg?: unknown): boolean;
/**
* Test whether any value satisfies a predicate.
* @remarks Time O(n), Space O(1)
* @example
* // Test any
* const ts = new TreeSet<number>([1, 3, 5]);
* console.log(ts.some(k => k === 3)); // true;
*/
some(callbackfn: TreeSetElementCallback<K, boolean, TreeSet<K>>, thisArg?: unknown): boolean;
/**
* Find the first value that satisfies a predicate.
* @remarks Time O(n), Space O(1)
* @example
* // Find entry
* const ts = new TreeSet<number>([1, 2, 3]);
* const found = ts.find(k => k === 2);
* console.log(found); // 2;
*/
find(callbackfn: TreeSetElementCallback<K, boolean, TreeSet<K>>, thisArg?: unknown): K | undefined;
/**
* Materialize the set into an array of keys.
* @remarks Time O(n), Space O(n)
* @example
* // Convert to array
* const ts = new TreeSet<number>([3, 1, 2]);
* console.log(ts.toArray()); // [1, 2, 3];
*/
toArray(): K[];
/**
* Print a human-friendly representation.
* @remarks Time O(n), Space O(n)
* @example
* // Display tree
* const ts = new TreeSet<number>([1, 2, 3]);
* expect(() => ts.print()).not.toThrow();
*/
print(): void;
/**
* Smallest key in the set.
* @example
* // Student grade ranking with custom comparator
* interface Student {
* name: string;
* gpa: number;
* }
*
* const ranking = new TreeSet<Student>(
* [
* { name: 'Alice', gpa: 3.8 },
* { name: 'Bob', gpa: 3.5 },
* { name: 'Charlie', gpa: 3.9 },
* { name: 'Diana', gpa: 3.5 }
* ],
* { comparator: (a, b) => b.gpa - a.gpa || a.name.localeCompare(b.name) }
* );
*
* // Sorted by GPA descending, then name ascending
* const names = [...ranking].map(s => s.name);
* console.log(names); // ['Charlie', 'Alice', 'Bob', 'Diana'];
*
* // Top student
* console.log(ranking.first()?.name); // 'Charlie';
*
* // Filter students with GPA >= 3.8
* const honors = ranking.filter(s => s.gpa >= 3.8);
* console.log(honors.toArray().map(s => s.name)); // ['Charlie', 'Alice'];
*/
first(): K | undefined;
/**
* Largest key in the set.
* @example
* // Get the maximum element
* const temps = new TreeSet<number>([18, 22, 15, 30, 25]);
* console.log(temps.last()); // 30;
* console.log(temps.first()); // 15;
*/
last(): K | undefined;
/**
* Remove and return the smallest key.
* @example
* // Remove and return minimum
* const queue = new TreeSet<number>([5, 1, 8, 3]);
*
* console.log(queue.pollFirst()); // 1;
* console.log(queue.pollFirst()); // 3;
* console.log(queue.size); // 2;
*/
pollFirst(): K | undefined;
/**
* Remove and return the largest key.
* @example
* // Remove and return maximum
* const stack = new TreeSet<number>([10, 20, 30]);
*
* console.log(stack.pollLast()); // 30;
* console.log(stack.size); // 2;
*/
pollLast(): K | undefined;
/**
* Smallest key that is >= the given key.
* @example
* // Finding nearest available time slot
* // Available appointment times (minutes from midnight)
* const slots = new TreeSet<number>([540, 600, 660, 720, 840, 900]);
*
* // Customer wants something around 10:30 (630 min)
* const nearest = slots.ceiling(630);
* console.log(nearest); // 660; // 11:00 AM
*
* // What's the latest slot before 2:00 PM (840)?
* const before2pm = slots.lower(840);
* console.log(before2pm); // 720; // 12:00 PM
*
* // Book the 11:00 slot
* slots.delete(660);
* console.log(slots.ceiling(630)); // 720;
*/
ceiling(key: K): K | undefined;
/**
* Largest key that is <= the given key.
* @example
* // Largest element ≤ target
* const breakpoints = new TreeSet<number>([320, 768, 1024, 1280, 1920]);
*
* // Current width is 800 → which breakpoint applies?
* console.log(breakpoints.floor(800)); // 768;
* console.log(breakpoints.floor(1024)); // 1024; // exact match
* console.log(breakpoints.floor(100)); // undefined;
*/
floor(key: K): K | undefined;
/**
* Smallest key that is > the given key.
* @example
* // Smallest element strictly > target
* const levels = new TreeSet<number>([1, 5, 10, 25, 50, 100]);
*
* console.log(levels.higher(10)); // 25;
* console.log(levels.higher(100)); // undefined;
*/
higher(key: K): K | undefined;
/**
* Largest key that is < the given key.
* @example
* // Largest element strictly < target
* const tiers = new TreeSet<number>([100, 200, 500, 1000]);
*
* console.log(tiers.lower(500)); // 200;
* console.log(tiers.lower(100)); // undefined;
*/
lower(key: K): K | undefined;
/**
* Return all keys in a given range.
*
* @param range `[low, high]`
* @param options Inclusive/exclusive bounds (defaults to inclusive).
* @example
* // IP address blocklist with range checking
* // Simplified: use numeric IP representation
* const blocklist = new TreeSet<number>([
* 167772160, // 10.0.0.0
* 167772416, // 10.0.1.0
* 167772672, // 10.0.2.0
* 167773184 // 10.0.4.0
* ]);
*
* // Check if any blocked IP is in range 10.0.1.0 - 10.0.3.0
* const inRange = blocklist.rangeSearch([167772416, 167772928]);
* console.log(inRange); // [167772416, 167772672];
*
* // Quick membership check
* console.log(blocklist.has(167772416)); // true;
* console.log(blocklist.has(167772800)); // false;
*/
rangeSearch(range: [K, K], options?: TreeSetRangeOptions): K[];
/**
* Returns the element at the k-th position in tree order (0-indexed).
* @remarks Time O(log n). Requires `enableOrderStatistic: true`.
* @example
* // Find k-th element in a TreeSet
* const set = new TreeSet<number>([30, 10, 50, 20, 40], { enableOrderStatistic: true });
* console.log(set.getByRank(0)); // 10;
* console.log(set.getByRank(2)); // 30;
* console.log(set.getRank(30)); // 2;
*/
getByRank(k: number): K | undefined;
/**
* Returns the 0-based rank of a key (number of elements that precede it in tree order).
* @remarks Time O(log n). Requires `enableOrderStatistic: true`.
* @example
* // Get the rank of a key in sorted order
* const tree = new TreeSet<number>(
* [10, 20, 30, 40, 50],
* { enableOrderStatistic: true }
* );
* console.log(tree.getRank(10)); // 0; // smallest → rank 0
* console.log(tree.getRank(30)); // 2; // 2 elements before 30 in tree order
* console.log(tree.getRank(50)); // 4; // largest → rank 4
* console.log(tree.getRank(25)); // 2;
*/
getRank(key: K): number;
/**
* Returns elements by rank range (0-indexed, inclusive on both ends).
* @remarks Time O(log n + k). Requires `enableOrderStatistic: true`.
* @example
* // Pagination by position in tree order
* const tree = new TreeSet<number>(
* [10, 20, 30, 40, 50, 60, 70, 80, 90],
* { enableOrderStatistic: true }
* );
* const pageSize = 3;
*
* // Page 1
* console.log(tree.rangeByRank(0, pageSize - 1)); // [10, 20, 30];
* // Page 2
* console.log(tree.rangeByRank(pageSize, 2 * pageSize - 1)); // [40, 50, 60];
* // Page 3
* console.log(tree.rangeByRank(2 * pageSize, 3 * pageSize - 1)); // [70, 80, 90];
*/
rangeByRank(start: number, end: number): K[];
/**
* Creates a shallow clone of this set.
* @remarks Time O(n log n), Space O(n)
* @example
* // Deep clone
* const ts = new TreeSet<number>([1, 2, 3]);
* const copy = ts.clone();
* copy.delete(1);
* console.log(ts.has(1)); // true;
*/
/**
* Return a new TreeSet containing all elements from both sets.
* @remarks When both sets share the same comparator, uses O(n+m) merge. Otherwise O(m log n).
* @param other - Any iterable of keys.
* @returns A new TreeSet.
* @example
* // Merge two sets
* console.log([...a.union(b)]); // [1, 2, 3, 4, 5, 6, 7];
*/
union(other: Iterable<K>): TreeSet<K>;
/**
* Return a new TreeSet containing only elements present in both sets.
* @remarks Time O(n+m) with ordered merge when possible, otherwise O(n log m).
* @param other - Any iterable of keys (converted to Set for fast lookup if not a TreeSet).
* @returns A new TreeSet.
* @example
* // Find common elements
* console.log([...a.intersection(b)]); // [3, 4, 5];
*/
intersection(other: Iterable<K>): TreeSet<K>;
/**
* Return a new TreeSet containing elements in this set but not in the other.
* @remarks Time O(n+m) with ordered merge when possible, otherwise O(n log m).
* @param other - Any iterable of keys.
* @returns A new TreeSet.
* @example
* // Find exclusive elements
* console.log([...a.difference(b)]); // [1, 2];
*/
difference(other: Iterable<K>): TreeSet<K>;
/**
* Return a new TreeSet containing elements in either set but not both.
* @remarks Time O(n+m).
* @param other - Any iterable of keys.
* @returns A new TreeSet.
* @example
* // Find symmetric difference
* console.log([...a.symmetricDifference(b)]); // [1, 2, 6, 7];
*/
symmetricDifference(other: Iterable<K>): TreeSet<K>;
/**
* Check whether every element in this set is also in the other.
* @remarks Time O(n).
* @param other - Any iterable of keys (converted to Set for fast lookup if not a TreeSet).
* @returns `true` if this is a subset of other.
* @example
* // Check subset
* console.log(new TreeSet([3, 4]).isSubsetOf(a)); // true;
*/
isSubsetOf(other: Iterable<K>): boolean;
/**
* Check whether every element in the other set is also in this set.
* @remarks Time O(m).
* @param other - Any iterable of keys.
* @returns `true` if this is a superset of other.
* @example
* // Check superset
* console.log(a.isSupersetOf(new TreeSet([2, 3]))); // true;
*/
isSupersetOf(other: Iterable<K>): boolean;
/**
* Check whether this set and the other share no common elements.
* @remarks Time O(min(n,m)), can short-circuit on first overlap.
* @param other - Any iterable of keys (converted to Set for fast lookup if not a TreeSet).
* @returns `true` if sets are disjoint.
* @example
* // Check disjoint
* console.log(a.isDisjointFrom(new TreeSet([8, 9]))); // true;
*/
isDisjointFrom(other: Iterable<K>): boolean;
/**
* Deep copy
* @example
* // Deep clone
* const ts = new TreeSet<number>([1, 2, 3]);
* const copy = ts.clone();
* copy.delete(1);
* console.log(ts.has(1)); // true;
*/
clone(): TreeSet<K>;
}