trie-typed 2.4.2 → 2.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/dist/cjs/index.cjs +1 -2
  2. package/dist/cjs/index.cjs.map +1 -1
  3. package/dist/cjs-legacy/index.cjs +1 -2
  4. package/dist/cjs-legacy/index.cjs.map +1 -1
  5. package/dist/esm/index.mjs +1 -2
  6. package/dist/esm/index.mjs.map +1 -1
  7. package/dist/esm-legacy/index.mjs +1 -2
  8. package/dist/esm-legacy/index.mjs.map +1 -1
  9. package/dist/types/data-structures/base/iterable-element-base.d.ts +1 -1
  10. package/dist/types/data-structures/binary-tree/binary-tree.d.ts +5 -5
  11. package/dist/types/data-structures/binary-tree/bst.d.ts +1 -1
  12. package/dist/types/data-structures/binary-tree/tree-map.d.ts +10 -0
  13. package/dist/types/data-structures/binary-tree/tree-set.d.ts +10 -0
  14. package/dist/types/data-structures/graph/directed-graph.d.ts +2 -2
  15. package/dist/types/data-structures/graph/undirected-graph.d.ts +2 -2
  16. package/dist/types/data-structures/hash/hash-map.d.ts +2 -2
  17. package/dist/types/data-structures/heap/heap.d.ts +3 -7
  18. package/dist/types/types/data-structures/binary-tree/avl-tree.d.ts +1 -1
  19. package/dist/types/types/data-structures/binary-tree/red-black-tree.d.ts +1 -1
  20. package/dist/types/types/data-structures/linked-list/doubly-linked-list.d.ts +1 -1
  21. package/dist/types/types/data-structures/linked-list/singly-linked-list.d.ts +1 -1
  22. package/dist/types/types/data-structures/priority-queue/priority-queue.d.ts +1 -1
  23. package/dist/types/types/data-structures/stack/stack.d.ts +1 -1
  24. package/dist/umd/trie-typed.js +1 -2
  25. package/dist/umd/trie-typed.js.map +1 -1
  26. package/dist/umd/trie-typed.min.js +1 -1
  27. package/dist/umd/trie-typed.min.js.map +1 -1
  28. package/package.json +2 -2
  29. package/src/data-structures/base/iterable-element-base.ts +2 -2
  30. package/src/data-structures/binary-tree/binary-tree.ts +8 -7
  31. package/src/data-structures/binary-tree/bst.ts +1 -1
  32. package/src/data-structures/binary-tree/tree-map.ts +16 -0
  33. package/src/data-structures/binary-tree/tree-multi-set.ts +5 -5
  34. package/src/data-structures/binary-tree/tree-set.ts +16 -0
  35. package/src/data-structures/graph/abstract-graph.ts +18 -18
  36. package/src/data-structures/graph/directed-graph.ts +4 -4
  37. package/src/data-structures/graph/map-graph.ts +1 -1
  38. package/src/data-structures/graph/undirected-graph.ts +4 -4
  39. package/src/data-structures/hash/hash-map.ts +6 -4
  40. package/src/data-structures/heap/heap.ts +17 -14
  41. package/src/data-structures/linked-list/doubly-linked-list.ts +4 -4
  42. package/src/data-structures/linked-list/singly-linked-list.ts +15 -9
  43. package/src/data-structures/queue/deque.ts +1 -1
  44. package/src/data-structures/stack/stack.ts +1 -1
  45. package/src/data-structures/trie/trie.ts +10 -5
  46. package/src/types/data-structures/binary-tree/avl-tree.ts +1 -1
  47. package/src/types/data-structures/binary-tree/red-black-tree.ts +1 -1
  48. package/src/types/data-structures/linked-list/doubly-linked-list.ts +1 -1
  49. package/src/types/data-structures/linked-list/singly-linked-list.ts +1 -1
  50. package/src/types/data-structures/priority-queue/priority-queue.ts +1 -1
  51. package/src/types/data-structures/stack/stack.ts +1 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/index.ts","../../src/data-structures/base/iterable-element-base.ts","../../src/data-structures/trie/trie.ts","../../src/common/index.ts"],"sourcesContent":["/**\n * data-structure-typed\n *\n * @author Pablo Zeng\n * @copyright Copyright (c) 2022 Pablo Zeng <zrwusa@gmail.com>\n * @license MIT License\n */\nexport * from './data-structures/trie';\nexport * from './types/data-structures/trie';\nexport * from './types/common';\nexport * from './types/utils';\nexport * from './common';","import type { ElementCallback, IterableElementBaseOptions, ReduceElementCallback } from '../../types';\n\n/**\n * Base class that makes a data structure iterable and provides common\n * element-wise utilities (e.g., map/filter/reduce/find).\n *\n * @template E The public element type yielded by the structure.\n * @template R The underlying \"raw\" element type used internally or by converters.\n *\n * @remarks\n * This class implements the JavaScript iteration protocol (via `Symbol.iterator`)\n * and offers array-like helpers with predictable time/space complexity.\n */\nexport abstract class IterableElementBase<E, R> implements Iterable<E> {\n /**\n * Create a new iterable base.\n *\n * @param options Optional behavior overrides. When provided, a `toElementFn`\n * is used to convert a raw element (`R`) into a public element (`E`).\n *\n * @remarks\n * Time O(1), Space O(1).\n */\n protected constructor(options?: IterableElementBaseOptions<E, R>) {\n if (options) {\n const { toElementFn } = options;\n if (typeof toElementFn === 'function') this._toElementFn = toElementFn;\n else if (toElementFn) throw new TypeError('toElementFn must be a function type');\n }\n }\n\n /**\n * The converter used to transform a raw element (`R`) into a public element (`E`).\n *\n * @remarks\n * Time O(1), Space O(1).\n */\n protected _toElementFn?: (rawElement: R) => E;\n\n /**\n * Exposes the current `toElementFn`, if configured.\n *\n * @returns The converter function or `undefined` when not set.\n * @remarks\n * Time O(1), Space O(1).\n */\n get toElementFn(): ((rawElement: R) => E) | undefined {\n return this._toElementFn;\n }\n\n /**\n * Returns an iterator over the structure's elements.\n *\n * @param args Optional iterator arguments forwarded to the internal iterator.\n * @returns An `IterableIterator<E>` that yields the elements in traversal order.\n *\n * @remarks\n * Producing the iterator is O(1); consuming the entire iterator is Time O(n) with O(1) extra space.\n */\n *[Symbol.iterator](...args: unknown[]): IterableIterator<E> {\n yield* this._getIterator(...args);\n }\n\n /**\n * Returns an iterator over the values (alias of the default iterator).\n *\n * @returns An `IterableIterator<E>` over all elements.\n * @remarks\n * Creating the iterator is O(1); full iteration is Time O(n), Space O(1).\n */\n *values(): IterableIterator<E> {\n for (const item of this) yield item;\n }\n\n /**\n * Tests whether all elements satisfy the predicate.\n *\n * @template TReturn\n * @param predicate Function invoked for each element with signature `(value, index, self)`.\n * @param thisArg Optional `this` binding for the predicate.\n * @returns `true` if every element passes; otherwise `false`.\n *\n * @remarks\n * Time O(n) in the worst case; may exit early when the first failure is found. Space O(1).\n */\n every(predicate: ElementCallback<E, R, boolean>, thisArg?: unknown): boolean {\n let index = 0;\n for (const item of this) {\n if (thisArg === undefined) {\n if (!predicate(item, index++, this)) return false;\n } else {\n const fn = predicate as (this: unknown, v: E, i: number, self: this) => boolean;\n if (!fn.call(thisArg, item, index++, this)) return false;\n }\n }\n return true;\n }\n\n /**\n * Tests whether at least one element satisfies the predicate.\n *\n * @param predicate Function invoked for each element with signature `(value, index, self)`.\n * @param thisArg Optional `this` binding for the predicate.\n * @returns `true` if any element passes; otherwise `false`.\n *\n * @remarks\n * Time O(n) in the worst case; may exit early on first success. Space O(1).\n */\n some(predicate: ElementCallback<E, R, boolean>, thisArg?: unknown): boolean {\n let index = 0;\n for (const item of this) {\n if (thisArg === undefined) {\n if (predicate(item, index++, this)) return true;\n } else {\n const fn = predicate as (this: unknown, v: E, i: number, self: this) => boolean;\n if (fn.call(thisArg, item, index++, this)) return true;\n }\n }\n return false;\n }\n\n /**\n * Invokes a callback for each element in iteration order.\n *\n * @param callbackfn Function invoked per element with signature `(value, index, self)`.\n * @param thisArg Optional `this` binding for the callback.\n * @returns `void`.\n *\n * @remarks\n * Time O(n), Space O(1).\n */\n forEach(callbackfn: ElementCallback<E, R, void>, thisArg?: unknown): void {\n let index = 0;\n for (const item of this) {\n if (thisArg === undefined) {\n callbackfn(item, index++, this);\n } else {\n const fn = callbackfn as (this: unknown, v: E, i: number, self: this) => void;\n fn.call(thisArg, item, index++, this);\n }\n }\n }\n\n /**\n * Finds the first element that satisfies the predicate and returns it.\n *\n * @overload\n * Finds the first element of type `S` (a subtype of `E`) that satisfies the predicate and returns it.\n * @template S\n * @param predicate Type-guard predicate: `(value, index, self) => value is S`.\n * @param thisArg Optional `this` binding for the predicate.\n * @returns The matched element typed as `S`, or `undefined` if not found.\n *\n * @overload\n * @param predicate Boolean predicate: `(value, index, self) => boolean`.\n * @param thisArg Optional `this` binding for the predicate.\n * @returns The first matching element as `E`, or `undefined` if not found.\n *\n * @remarks\n * Time O(n) in the worst case; may exit early on the first match. Space O(1).\n */\n find<S extends E>(predicate: ElementCallback<E, R, S>, thisArg?: unknown): S | undefined;\n find(predicate: ElementCallback<E, R, unknown>, thisArg?: unknown): E | undefined;\n\n // Implementation signature\n find(predicate: ElementCallback<E, R, boolean>, thisArg?: unknown): E | undefined {\n let index = 0;\n for (const item of this) {\n if (thisArg === undefined) {\n if (predicate(item, index++, this)) return item;\n } else {\n const fn = predicate as (this: unknown, v: E, i: number, self: this) => boolean;\n if (fn.call(thisArg, item, index++, this)) return item;\n }\n }\n return;\n }\n\n /**\n * Checks whether a strictly-equal element exists in the structure.\n *\n * @param element The element to test with `===` equality.\n * @returns `true` if an equal element is found; otherwise `false`.\n *\n * @remarks\n * Time O(n) in the worst case. Space O(1).\n */\n has(element: E): boolean {\n for (const ele of this) if (ele === element) return true;\n return false;\n }\n\n reduce(callbackfn: ReduceElementCallback<E, R>): E;\n reduce(callbackfn: ReduceElementCallback<E, R>, initialValue: E): E;\n reduce<U>(callbackfn: ReduceElementCallback<E, R, U>, initialValue: U): U;\n\n /**\n * Reduces all elements to a single accumulated value.\n *\n * @overload\n * @param callbackfn Reducer of signature `(acc, value, index, self) => nextAcc`. The first element is used as the initial accumulator.\n * @returns The final accumulated value typed as `E`.\n *\n * @overload\n * @param callbackfn Reducer of signature `(acc, value, index, self) => nextAcc`.\n * @param initialValue The initial accumulator value of type `E`.\n * @returns The final accumulated value typed as `E`.\n *\n * @overload\n * @template U The accumulator type when it differs from `E`.\n * @param callbackfn Reducer of signature `(acc: U, value, index, self) => U`.\n * @param initialValue The initial accumulator value of type `U`.\n * @returns The final accumulated value typed as `U`.\n *\n * @remarks\n * Time O(n), Space O(1). Throws if called on an empty structure without `initialValue`.\n */\n reduce<U>(callbackfn: ReduceElementCallback<E, R, U>, initialValue?: U): U {\n let index = 0;\n const iter = this[Symbol.iterator]();\n let acc: U;\n\n if (arguments.length >= 2) {\n acc = initialValue as U;\n } else {\n const first = iter.next();\n if (first.done) throw new TypeError('Reduce of empty structure with no initial value');\n acc = first.value as unknown as U;\n index = 1;\n }\n\n for (const value of iter as unknown as Iterable<E>) {\n acc = callbackfn(acc, value, index++, this);\n }\n return acc;\n }\n\n /**\n * Materializes the elements into a new array.\n *\n * @returns A shallow array copy of the iteration order.\n * @remarks\n * Time O(n), Space O(n).\n */\n toArray(): E[] {\n return [...this];\n }\n\n /**\n * Returns a representation of the structure suitable for quick visualization.\n * Defaults to an array of elements; subclasses may override to provide richer visuals.\n *\n * @returns A visual representation (array by default).\n * @remarks\n * Time O(n), Space O(n).\n */\n toVisual(): E[] {\n return [...this];\n }\n\n /**\n * Prints `toVisual()` to the console. Intended for quick debugging.\n *\n * @returns `void`.\n * @remarks\n * Time O(n) due to materialization, Space O(n) for the intermediate representation.\n */\n print(): void {\n console.log(this.toVisual());\n }\n\n /**\n * Indicates whether the structure currently contains no elements.\n *\n * @returns `true` if empty; otherwise `false`.\n * @remarks\n * Expected Time O(1), Space O(1) for most implementations.\n */\n abstract isEmpty(): boolean;\n\n /**\n * Removes all elements from the structure.\n *\n * @returns `void`.\n * @remarks\n * Expected Time O(1) or O(n) depending on the implementation; Space O(1).\n */\n abstract clear(): void;\n\n /**\n * Creates a structural copy with the same element values and configuration.\n *\n * @returns A clone of the current instance (same concrete type).\n * @remarks\n * Expected Time O(n) to copy elements; Space O(n).\n */\n abstract clone(): this;\n\n /**\n * Maps each element to a new element and returns a new iterable structure.\n *\n * @template EM The mapped element type.\n * @template RM The mapped raw element type used internally by the target structure.\n * @param callback Function with signature `(value, index, self) => mapped`.\n * @param options Optional options for the returned structure, including its `toElementFn`.\n * @param thisArg Optional `this` binding for the callback.\n * @returns A new `IterableElementBase<EM, RM>` containing mapped elements.\n *\n * @remarks\n * Time O(n), Space O(n).\n */\n abstract map<EM, RM>(\n callback: ElementCallback<E, R, EM>,\n options?: IterableElementBaseOptions<EM, RM>,\n thisArg?: unknown\n ): IterableElementBase<EM, RM>;\n\n /**\n * Maps each element to the same element type and returns the same concrete structure type.\n *\n * @param callback Function with signature `(value, index, self) => mappedValue`.\n * @param thisArg Optional `this` binding for the callback.\n * @returns A new instance of the same concrete type with mapped elements.\n *\n * @remarks\n * Time O(n), Space O(n).\n */\n abstract mapSame(callback: ElementCallback<E, R, E>, thisArg?: unknown): this;\n\n /**\n * Filters elements using the provided predicate and returns the same concrete structure type.\n *\n * @param predicate Function with signature `(value, index, self) => boolean`.\n * @param thisArg Optional `this` binding for the predicate.\n * @returns A new instance of the same concrete type containing only elements that pass the predicate.\n *\n * @remarks\n * Time O(n), Space O(k) where `k` is the number of kept elements.\n */\n abstract filter(predicate: ElementCallback<E, R, boolean>, thisArg?: unknown): this;\n\n /**\n * Internal iterator factory used by the default iterator.\n *\n * @param args Optional iterator arguments.\n * @returns An iterator over elements.\n *\n * @remarks\n * Implementations should yield in O(1) per element with O(1) extra space when possible.\n */\n protected abstract _getIterator(...args: unknown[]): IterableIterator<E>;\n}\n","/**\n * data-structure-typed\n *\n * @author Pablo Zeng\n * @copyright Copyright (c) 2022 Pablo Zeng <zrwusa@gmail.com>\n * @license MIT License\n */\n\nimport type { ElementCallback, TrieOptions } from '../../types';\nimport { IterableElementBase } from '../base';\n\n/**\n * Node used by Trie to store one character and its children.\n * @remarks Time O(1), Space O(1)\n */\nexport class TrieNode {\n /**\n * Create a Trie node with a character key.\n * @remarks Time O(1), Space O(1)\n * @returns New TrieNode instance.\n */\n\n constructor(key: string) {\n this._key = key;\n this._isEnd = false;\n this._children = new Map<string, TrieNode>();\n }\n\n protected _key: string;\n\n /**\n * Get the character key of this node.\n * @remarks Time O(1), Space O(1)\n * @returns Character key string.\n */\n\n get key(): string {\n return this._key;\n }\n\n /**\n * Set the character key of this node.\n * @remarks Time O(1), Space O(1)\n * @param value - New character key.\n * @returns void\n */\n\n set key(value: string) {\n this._key = value;\n }\n\n protected _children: Map<string, TrieNode>;\n\n /**\n * Get the child map of this node.\n * @remarks Time O(1), Space O(1)\n * @returns Map from character to child node.\n */\n\n get children(): Map<string, TrieNode> {\n return this._children;\n }\n\n /**\n * Replace the child map of this node.\n * @remarks Time O(1), Space O(1)\n * @param value - New map of character → node.\n * @returns void\n */\n\n set children(value: Map<string, TrieNode>) {\n this._children = value;\n }\n\n protected _isEnd: boolean;\n\n /**\n * Check whether this node marks the end of a word.\n * @remarks Time O(1), Space O(1)\n * @returns True if this node ends a word.\n */\n\n get isEnd(): boolean {\n return this._isEnd;\n }\n\n /**\n * Mark this node as the end of a word or not.\n * @remarks Time O(1), Space O(1)\n * @param value - Whether this node ends a word.\n * @returns void\n */\n\n set isEnd(value: boolean) {\n this._isEnd = value;\n }\n}\n\n/**\n * Prefix tree (Trie) for fast prefix queries and word storage.\n * @remarks Time O(1), Space O(1)\n * @template R\n * 1. Node Structure: Each node in a Trie represents a string (or a part of a string). The root node typically represents an empty string.\n * 2. Child Node Relationship: Each node's children represent the strings that can be formed by adding one character to the string at the current node. For example, if a node represents the string 'ca', one of its children might represent 'cat'.\n * 3. Fast Retrieval: Trie allows retrieval in O(m) time complexity, where m is the length of the string to be searched.\n * 4. Space Efficiency: Trie can store a large number of strings very space-efficiently, especially when these strings share common prefixes.\n * 5. Autocomplete and Prediction: Trie can be used for implementing autocomplete and word prediction features, as it can quickly find all strings with a common prefix.\n * 6. Sorting: Trie can be used to sort a set of strings in alphabetical order.\n * 7. String Retrieval: For example, searching for a specific string in a large set of strings.\n * 8. Autocomplete: Providing recommended words or phrases as a user types.\n * 9. Spell Check: Checking the spelling of words.\n * 10. IP Routing: Used in certain types of IP routing algorithms.\n * 11. Text Word Frequency Count: Counting and storing the frequency of words in a large amount of text data.\n * @example\n * // basic Trie creation and add words\n * // Create a simple Trie with initial words\n * const trie = new Trie(['apple', 'app', 'apply']);\n *\n * // Verify size\n * console.log(trie.size); // 3;\n *\n * // Check if words exist\n * console.log(trie.has('apple')); // true;\n * console.log(trie.has('app')); // true;\n *\n * // Add a new word\n * trie.add('application');\n * console.log(trie.size); // 4;\n * @example\n * // Trie getWords and prefix search\n * const trie = new Trie(['apple', 'app', 'apply', 'application', 'apricot']);\n *\n * // Get all words with prefix 'app'\n * const appWords = trie.getWords('app');\n * console.log(appWords); // contains 'app';\n * console.log(appWords); // contains 'apple';\n * console.log(appWords); // contains 'apply';\n * console.log(appWords); // contains 'application';\n * expect(appWords).not.toContain('apricot');\n * @example\n * // Trie isPrefix and isAbsolutePrefix checks\n * const trie = new Trie(['tree', 'trial', 'trick', 'trip', 'trie']);\n *\n * // Check if string is a prefix of any word\n * console.log(trie.hasPrefix('tri')); // true;\n * console.log(trie.hasPrefix('tr')); // true;\n * console.log(trie.hasPrefix('xyz')); // false;\n *\n * // Check if string is an absolute prefix (not a complete word)\n * console.log(trie.hasPurePrefix('tri')); // true;\n * console.log(trie.hasPurePrefix('tree')); // false; // 'tree' is a complete word\n *\n * // Verify size\n * console.log(trie.size); // 5;\n * @example\n * // Trie delete and iteration\n * const trie = new Trie(['car', 'card', 'care', 'careful', 'can', 'cat']);\n *\n * // Delete a word\n * trie.delete('card');\n * console.log(trie.has('card')); // false;\n *\n * // Word with same prefix still exists\n * console.log(trie.has('care')); // true;\n *\n * // Size decreased\n * console.log(trie.size); // 5;\n *\n * // Iterate through all words\n * const allWords = [...trie];\n * console.log(allWords.length); // 5;\n * @example\n * // Trie for autocomplete search index\n * // Trie is perfect for autocomplete: O(m + k) where m is prefix length, k is results\n * const searchIndex = new Trie(['typescript', 'javascript', 'python', 'java', 'rust', 'ruby', 'golang', 'kotlin']);\n *\n * // User types 'j' - get all suggestions\n * const jResults = searchIndex.getWords('j');\n * console.log(jResults); // contains 'javascript';\n * console.log(jResults); // contains 'java';\n * console.log(jResults.length); // 2;\n *\n * // User types 'ja' - get more specific suggestions\n * const jaResults = searchIndex.getWords('ja');\n * console.log(jaResults); // contains 'javascript';\n * console.log(jaResults); // contains 'java';\n * console.log(jaResults.length); // 2;\n *\n * // User types 'jav' - even more specific\n * const javResults = searchIndex.getWords('jav');\n * console.log(javResults); // contains 'javascript';\n * console.log(javResults); // contains 'java';\n * console.log(javResults.length); // 2;\n *\n * // Check for common prefix\n *\n * console.log(searchIndex.hasCommonPrefix('ja')); // false; // Not all words start with 'ja'\n *\n * // Total words in index\n * console.log(searchIndex.size); // 8;\n *\n * // Get height (depth of tree)\n * const height = searchIndex.getHeight();\n * console.log(typeof height); // 'number';\n * @example\n * // Dictionary: Case-insensitive word lookup\n * // Create a case-insensitive dictionary\n * const dictionary = new Trie<string>([], { caseSensitive: false });\n *\n * // Add words with mixed casing\n * dictionary.add('Hello');\n * dictionary.add('WORLD');\n * dictionary.add('JavaScript');\n *\n * // Test lookups with different casings\n * console.log(dictionary.has('hello')); // true;\n * console.log(dictionary.has('HELLO')); // true;\n * console.log(dictionary.has('Hello')); // true;\n * console.log(dictionary.has('javascript')); // true;\n * console.log(dictionary.has('JAVASCRIPT')); // true;\n * @example\n * // File System Path Operations\n * const fileSystem = new Trie<string>([\n * '/home/user/documents/file1.txt',\n * '/home/user/documents/file2.txt',\n * '/home/user/pictures/photo.jpg',\n * '/home/user/pictures/vacation/',\n * '/home/user/downloads'\n * ]);\n *\n * // Find common directory prefix\n * console.log(fileSystem.getLongestCommonPrefix()); // '/home/user/';\n *\n * // List all files in a directory\n * const documentsFiles = fileSystem.getWords('/home/user/documents/');\n * console.log(documentsFiles); // ['/home/user/documents/file1.txt', '/home/user/documents/file2.txt'];\n * @example\n * // IP Address Routing Table\n * // Add IP address prefixes and their corresponding routes\n * const routes = {\n * '192.168.1': 'LAN_SUBNET_1',\n * '192.168.2': 'LAN_SUBNET_2',\n * '10.0.0': 'PRIVATE_NETWORK_1',\n * '10.0.1': 'PRIVATE_NETWORK_2'\n * };\n *\n * const ipRoutingTable = new Trie<string>(Object.keys(routes));\n *\n * // Check IP address prefix matching\n * console.log(ipRoutingTable.hasPrefix('192.168.1')); // true;\n * console.log(ipRoutingTable.hasPrefix('192.168.2')); // true;\n *\n * // Validate IP address belongs to subnet\n * const ip = '192.168.1.100';\n * const subnet = ip.split('.').slice(0, 3).join('.');\n * console.log(ipRoutingTable.hasPrefix(subnet)); // true;\n */\nexport class Trie<R = any> extends IterableElementBase<string, R> {\n /**\n * Create a Trie and optionally bulk-insert words.\n * @remarks Time O(totalChars), Space O(totalChars)\n * @param [words] - Iterable of strings (or raw records if toElementFn is provided).\n * @param [options] - Options such as toElementFn and caseSensitive.\n * @returns New Trie instance.\n */\n\n constructor(words: Iterable<string> | Iterable<R> = [], options?: TrieOptions<R>) {\n super(options);\n if (options) {\n const { caseSensitive } = options;\n if (caseSensitive !== undefined) this._caseSensitive = caseSensitive;\n }\n if (words) {\n this.addMany(words);\n }\n }\n\n protected _size: number = 0;\n\n /**\n * Get the number of stored words.\n * @remarks Time O(1), Space O(1)\n * @returns Word count.\n */\n\n get size(): number {\n return this._size;\n }\n\n protected _caseSensitive: boolean = true;\n\n /**\n * Get whether comparisons are case-sensitive.\n * @remarks Time O(1), Space O(1)\n * @returns True if case-sensitive.\n */\n\n get caseSensitive(): boolean {\n return this._caseSensitive;\n }\n\n protected _root: TrieNode = new TrieNode('');\n\n /**\n * Get the root node.\n * @remarks Time O(1), Space O(1)\n * @returns Root TrieNode.\n */\n\n get root() {\n return this._root;\n }\n\n /**\n * (Protected) Get total count for base class iteration.\n * @remarks Time O(1), Space O(1)\n * @returns Total number of elements.\n */\n\n protected get _total() {\n return this._size;\n }\n\n /**\n * Insert one word into the trie.\n * @remarks Time O(L), Space O(L)\n * @param word - Word to insert.\n * @returns True if the word was newly added.\n */\n\n add(word: string): boolean {\n word = this._caseProcess(word);\n let cur = this.root;\n let isNewWord = false;\n for (const c of word) {\n let nodeC = cur.children.get(c);\n if (!nodeC) {\n nodeC = new TrieNode(c);\n cur.children.set(c, nodeC);\n }\n cur = nodeC;\n }\n if (!cur.isEnd) {\n isNewWord = true;\n cur.isEnd = true;\n this._size++;\n }\n return isNewWord;\n }\n\n /**\n * Insert many words from an iterable.\n * @remarks Time O(ΣL), Space O(ΣL)\n * @param words - Iterable of strings (or raw records if toElementFn is provided).\n * @returns Array of per-word 'added' flags.\n */\n\n addMany(words: Iterable<string> | Iterable<R>): boolean[] {\n const ans: boolean[] = [];\n for (const word of words) {\n if (this.toElementFn) {\n ans.push(this.add(this.toElementFn(word as R)));\n } else {\n ans.push(this.add(word as string));\n }\n }\n return ans;\n }\n\n /**\n * Check whether a word exists.\n * @remarks Time O(L), Space O(1)\n * @param word - Word to search for.\n * @returns True if present.\n */\n\n override has(word: string): boolean {\n word = this._caseProcess(word);\n let cur = this.root;\n for (const c of word) {\n const nodeC = cur.children.get(c);\n if (!nodeC) return false;\n cur = nodeC;\n }\n return cur.isEnd;\n }\n\n /**\n * Check whether the trie is empty.\n * @remarks Time O(1), Space O(1)\n * @returns True if size is 0.\n */\n\n isEmpty(): boolean {\n return this._size === 0;\n }\n\n /**\n * Remove all words and reset to a fresh root.\n * @remarks Time O(1), Space O(1)\n * @returns void\n */\n\n clear(): void {\n this._size = 0;\n this._root = new TrieNode('');\n }\n\n /**\n * Delete one word if present.\n * @remarks Time O(L), Space O(1)\n * @param word - Word to delete.\n * @returns True if a word was removed.\n */\n\n delete(word: string): boolean {\n word = this._caseProcess(word);\n let isDeleted = false;\n const dfs = (cur: TrieNode, i: number): boolean => {\n const char = word[i];\n const child = cur.children.get(char);\n if (child) {\n if (i === word.length - 1) {\n if (child.isEnd) {\n if (child.children.size > 0) {\n child.isEnd = false;\n } else {\n cur.children.delete(char);\n }\n isDeleted = true;\n return true;\n }\n return false;\n }\n const res = dfs(child, i + 1);\n if (res && !cur.isEnd && child.children.size === 0) {\n cur.children.delete(char);\n return true;\n }\n return false;\n }\n return false;\n };\n\n dfs(this.root, 0);\n if (isDeleted) {\n this._size--;\n }\n return isDeleted;\n }\n\n /**\n * Compute the height (max depth) of the trie.\n * @remarks Time O(N), Space O(H)\n * @returns Maximum depth from root to a leaf.\n */\n\n getHeight(): number {\n const startNode = this.root;\n let maxDepth = 0;\n if (startNode) {\n const bfs = (node: TrieNode, level: number) => {\n if (level > maxDepth) {\n maxDepth = level;\n }\n const { children } = node;\n if (children) {\n for (const child of children.entries()) {\n bfs(child[1], level + 1);\n }\n }\n };\n bfs(startNode, 0);\n }\n return maxDepth;\n }\n\n /**\n * Check whether input is a proper prefix of at least one word.\n * @remarks Time O(L), Space O(1)\n * @param input - String to test as prefix.\n * @returns True if input is a prefix but not a full word.\n */\n\n hasPurePrefix(input: string): boolean {\n input = this._caseProcess(input);\n let cur = this.root;\n for (const c of input) {\n const nodeC = cur.children.get(c);\n if (!nodeC) return false;\n cur = nodeC;\n }\n return !cur.isEnd;\n }\n\n /**\n * Check whether any word starts with input.\n * @remarks Time O(L), Space O(1)\n * @param input - String to test as prefix.\n * @returns True if input matches a path from root.\n */\n\n hasPrefix(input: string): boolean {\n input = this._caseProcess(input);\n let cur = this.root;\n for (const c of input) {\n const nodeC = cur.children.get(c);\n if (!nodeC) return false;\n cur = nodeC;\n }\n return true;\n }\n\n /**\n * Check whether the trie’s longest common prefix equals input.\n * @remarks Time O(min(H,L)), Space O(1)\n * @param input - Candidate longest common prefix.\n * @returns True if input equals the common prefix.\n */\n\n hasCommonPrefix(input: string): boolean {\n input = this._caseProcess(input);\n let commonPre = '';\n const dfs = (cur: TrieNode) => {\n commonPre += cur.key;\n if (commonPre === input) return;\n if (cur.isEnd) return;\n if (cur && cur.children && cur.children.size === 1) dfs(Array.from(cur.children.values())[0]);\n else return;\n };\n dfs(this.root);\n return commonPre === input;\n }\n\n /**\n * Return the longest common prefix among all words.\n * @remarks Time O(H), Space O(1)\n * @returns The longest common prefix string.\n */\n\n getLongestCommonPrefix(): string {\n let commonPre = '';\n const dfs = (cur: TrieNode) => {\n commonPre += cur.key;\n if (cur.isEnd) return;\n if (cur && cur.children && cur.children.size === 1) dfs(Array.from(cur.children.values())[0]);\n else return;\n };\n dfs(this.root);\n return commonPre;\n }\n\n /**\n * Collect words under a prefix up to a maximum count.\n * @remarks Time O(K·L), Space O(K·L)\n * @param [prefix] - Prefix to match; default empty string for root.\n * @param [max] - Maximum number of words to return; default is Number.MAX_SAFE_INTEGER.\n * @param [isAllWhenEmptyPrefix] - When true, collect from root even if prefix is empty.\n * @returns Array of collected words (at most max).\n */\n\n getWords(prefix = '', max = Number.MAX_SAFE_INTEGER, isAllWhenEmptyPrefix = false): string[] {\n prefix = this._caseProcess(prefix);\n const words: string[] = [];\n let found = 0;\n\n const dfs = (node: TrieNode, word: string): void => {\n for (const [char, childNode] of node.children) {\n if (found >= max) return;\n dfs(childNode, word + char);\n }\n if (node.isEnd) {\n if (found >= max) return;\n words.push(word);\n found++;\n }\n };\n\n let startNode = this.root;\n\n if (prefix) {\n for (const c of prefix) {\n const nodeC = startNode.children.get(c);\n if (nodeC) {\n startNode = nodeC;\n } else {\n return [];\n }\n }\n }\n\n if (isAllWhenEmptyPrefix || startNode !== this.root) dfs(startNode, prefix);\n\n return words;\n }\n\n /**\n * Deep clone this trie by iterating and inserting all words.\n * @remarks Time O(ΣL), Space O(ΣL)\n * @returns A new trie with the same words and options.\n */\n\n clone(): this {\n const next = this._createInstance();\n for (const x of this) next.add(x);\n return next;\n }\n\n /**\n * Filter words into a new trie of the same class.\n * @remarks Time O(ΣL), Space O(ΣL)\n * @param predicate - Predicate (word, index, trie) → boolean to keep word.\n * @param [thisArg] - Value for `this` inside the predicate.\n * @returns A new trie containing words that satisfy the predicate.\n */\n\n filter(predicate: ElementCallback<string, R, boolean>, thisArg?: any): this {\n const results = this._createInstance();\n let index = 0;\n for (const word of this) {\n if (predicate.call(thisArg, word, index, this)) {\n results.add(word);\n }\n index++;\n }\n return results;\n }\n\n map<RM>(callback: ElementCallback<string, R, string>, options?: TrieOptions<RM>, thisArg?: any): Trie<RM>;\n\n /**\n * Map words into a new trie (possibly different record type).\n * @remarks Time O(ΣL), Space O(ΣL)\n * @template EM\n * @template RM\n * @param callback - Mapping function (word, index, trie) → newWord (string).\n * @param [options] - Options for the output trie (e.g., toElementFn, caseSensitive).\n * @param [thisArg] - Value for `this` inside the callback.\n * @returns A new Trie constructed from mapped words.\n */\n\n map<EM, RM>(\n callback: ElementCallback<string, R, EM>,\n options?: TrieOptions<RM>,\n thisArg?: any\n ): IterableElementBase<EM, RM>;\n\n map<EM, RM>(callback: ElementCallback<string, R, EM>, options?: TrieOptions<RM>, thisArg?: any): any {\n const newTrie = this._createLike<RM>([], options);\n let i = 0;\n for (const x of this) {\n const v = thisArg === undefined ? callback(x, i++, this) : callback.call(thisArg, x, i++, this);\n if (typeof v !== 'string') {\n throw new TypeError(`Trie.map callback must return string; got ${typeof v}`);\n }\n newTrie.add(v);\n }\n return newTrie;\n }\n\n /**\n * Map words into a new trie of the same element type.\n * @remarks Time O(ΣL), Space O(ΣL)\n * @param callback - Mapping function (word, index, trie) → string.\n * @param [thisArg] - Value for `this` inside the callback.\n * @returns A new trie with mapped words.\n */\n\n mapSame(callback: ElementCallback<string, R, string>, thisArg?: any): this {\n const next = this._createInstance();\n let i = 0;\n for (const key of this) {\n const mapped = thisArg === undefined ? callback(key, i++, this) : callback.call(thisArg, key, i++, this);\n next.add(mapped);\n }\n return next;\n }\n\n /**\n * (Protected) Create an empty instance of the same concrete class.\n * @remarks Time O(1), Space O(1)\n * @param [options] - Options forwarded to the constructor.\n * @returns An empty like-kind trie instance.\n */\n\n protected _createInstance(options?: TrieOptions<R>): this {\n const Ctor: any = this.constructor;\n const next: any = new Ctor([], {\n toElementFn: this.toElementFn,\n caseSensitive: this.caseSensitive,\n ...(options ?? {})\n });\n return next as this;\n }\n\n /**\n * (Protected) Create a like-kind trie and seed it from an iterable.\n * @remarks Time O(ΣL), Space O(ΣL)\n * @template RM\n * @param [elements] - Iterable used to seed the new trie.\n * @param [options] - Options forwarded to the constructor.\n * @returns A like-kind Trie instance.\n */\n\n protected _createLike<RM>(elements: Iterable<string> | Iterable<RM> = [], options?: TrieOptions<RM>): Trie<RM> {\n const Ctor: any = this.constructor;\n return new Ctor(elements, options) as Trie<RM>;\n }\n\n /**\n * (Protected) Spawn an empty like-kind trie instance.\n * @remarks Time O(1), Space O(1)\n * @template RM\n * @param [options] - Options forwarded to the constructor.\n * @returns An empty like-kind Trie instance.\n */\n\n protected _spawnLike<RM>(options?: TrieOptions<RM>): Trie<RM> {\n return this._createLike<RM>([], options);\n }\n\n /**\n * (Protected) Iterate all words in lexicographic order of edges.\n * @remarks Time O(ΣL), Space O(H)\n * @returns Iterator of words.\n */\n\n protected *_getIterator(): IterableIterator<string> {\n function* _dfs(node: TrieNode, path: string): IterableIterator<string> {\n if (node.isEnd) {\n yield path;\n }\n for (const [char, childNode] of node.children) {\n yield* _dfs(childNode, path + char);\n }\n }\n\n yield* _dfs(this.root, '');\n }\n\n /**\n * (Protected) Normalize a string according to case sensitivity.\n * @remarks Time O(L), Space O(L)\n * @param str - Input string to normalize.\n * @returns Normalized string based on caseSensitive.\n */\n\n protected _caseProcess(str: string) {\n if (!this._caseSensitive) {\n str = str.toLowerCase();\n }\n return str;\n }\n}\n","export enum DFSOperation {\n VISIT = 0,\n PROCESS = 1\n}\n\nexport class Range<K> {\n constructor(\n public low: K,\n public high: K,\n public includeLow: boolean = true,\n public includeHigh: boolean = true\n ) {\n // if (!(isComparable(low) && isComparable(high))) throw new RangeError('low or high is not comparable');\n // if (low > high) throw new RangeError('low must be less than or equal to high');\n }\n\n // Determine whether a key is within the range\n isInRange(key: K, comparator: (a: K, b: K) => number): boolean {\n const lowCheck = this.includeLow ? comparator(key, this.low) >= 0 : comparator(key, this.low) > 0;\n const highCheck = this.includeHigh ? comparator(key, this.high) <= 0 : comparator(key, this.high) < 0;\n return lowCheck && highCheck;\n }\n}\n"],"mappings":"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","names":["src_exports","__export","DFSOperation","Range","Trie","TrieNode","IterableElementBase","options","__publicField","toElementFn","args","item","predicate","thisArg","index","callbackfn","element","ele","initialValue","iter","acc","first","value","TrieNode","key","__publicField","value","Trie","IterableElementBase","words","options","caseSensitive","word","cur","isNewWord","c","nodeC","ans","isDeleted","dfs","char","child","startNode","maxDepth","bfs","node","level","children","input","commonPre","prefix","max","isAllWhenEmptyPrefix","found","childNode","next","x","predicate","thisArg","results","index","callback","newTrie","v","i","mapped","Ctor","elements","_dfs","path","str","DFSOperation","Range","low","high","includeLow","includeHigh","key","comparator","lowCheck","highCheck"]}
1
+ {"version":3,"sources":["../../src/index.ts","../../src/data-structures/base/iterable-element-base.ts","../../src/data-structures/trie/trie.ts","../../src/common/index.ts"],"sourcesContent":["/**\n * data-structure-typed\n *\n * @author Pablo Zeng\n * @copyright Copyright (c) 2022 Pablo Zeng <zrwusa@gmail.com>\n * @license MIT License\n */\nexport * from './data-structures/trie';\nexport * from './types/data-structures/trie';\nexport * from './types/common';\nexport * from './types/utils';\nexport * from './common';","import type { ElementCallback, IterableElementBaseOptions, ReduceElementCallback } from '../../types';\n\n/**\n * Base class that makes a data structure iterable and provides common\n * element-wise utilities (e.g., map/filter/reduce/find).\n *\n * @template E The public element type yielded by the structure.\n * @template R The underlying \"raw\" element type used internally or by converters.\n *\n * @remarks\n * This class implements the JavaScript iteration protocol (via `Symbol.iterator`)\n * and offers array-like helpers with predictable time/space complexity.\n */\nexport abstract class IterableElementBase<E, R> implements Iterable<E> {\n /**\n * Create a new iterable base.\n *\n * @param options Optional behavior overrides. When provided, a `toElementFn`\n * is used to convert a raw element (`R`) into a public element (`E`).\n *\n * @remarks\n * Time O(1), Space O(1).\n */\n protected constructor(options?: IterableElementBaseOptions<E, R>) {\n if (options) {\n const { toElementFn } = options;\n if (typeof toElementFn === 'function') this._toElementFn = toElementFn;\n else if (toElementFn) throw new TypeError('toElementFn must be a function type');\n }\n }\n\n /**\n * The converter used to transform a raw element (`R`) into a public element (`E`).\n *\n * @remarks\n * Time O(1), Space O(1).\n */\n protected readonly _toElementFn?: (rawElement: R) => E;\n\n /**\n * Exposes the current `toElementFn`, if configured.\n *\n * @returns The converter function or `undefined` when not set.\n * @remarks\n * Time O(1), Space O(1).\n */\n get toElementFn(): ((rawElement: R) => E) | undefined {\n return this._toElementFn;\n }\n\n /**\n * Returns an iterator over the structure's elements.\n *\n * @param args Optional iterator arguments forwarded to the internal iterator.\n * @returns An `IterableIterator<E>` that yields the elements in traversal order.\n *\n * @remarks\n * Producing the iterator is O(1); consuming the entire iterator is Time O(n) with O(1) extra space.\n */\n *[Symbol.iterator](...args: unknown[]): IterableIterator<E> {\n yield* this._getIterator(...args);\n }\n\n /**\n * Returns an iterator over the values (alias of the default iterator).\n *\n * @returns An `IterableIterator<E>` over all elements.\n * @remarks\n * Creating the iterator is O(1); full iteration is Time O(n), Space O(1).\n */\n *values(): IterableIterator<E> {\n for (const item of this) yield item;\n }\n\n /**\n * Tests whether all elements satisfy the predicate.\n *\n * @template TReturn\n * @param predicate Function invoked for each element with signature `(value, index, self)`.\n * @param thisArg Optional `this` binding for the predicate.\n * @returns `true` if every element passes; otherwise `false`.\n *\n * @remarks\n * Time O(n) in the worst case; may exit early when the first failure is found. Space O(1).\n */\n every(predicate: ElementCallback<E, R, boolean>, thisArg?: unknown): boolean {\n let index = 0;\n for (const item of this) {\n if (thisArg === undefined) {\n if (!predicate(item, index++, this)) return false;\n } else {\n const fn = predicate as (this: unknown, v: E, i: number, self: this) => boolean;\n if (!fn.call(thisArg, item, index++, this)) return false;\n }\n }\n return true;\n }\n\n /**\n * Tests whether at least one element satisfies the predicate.\n *\n * @param predicate Function invoked for each element with signature `(value, index, self)`.\n * @param thisArg Optional `this` binding for the predicate.\n * @returns `true` if any element passes; otherwise `false`.\n *\n * @remarks\n * Time O(n) in the worst case; may exit early on first success. Space O(1).\n */\n some(predicate: ElementCallback<E, R, boolean>, thisArg?: unknown): boolean {\n let index = 0;\n for (const item of this) {\n if (thisArg === undefined) {\n if (predicate(item, index++, this)) return true;\n } else {\n const fn = predicate as (this: unknown, v: E, i: number, self: this) => boolean;\n if (fn.call(thisArg, item, index++, this)) return true;\n }\n }\n return false;\n }\n\n /**\n * Invokes a callback for each element in iteration order.\n *\n * @param callbackfn Function invoked per element with signature `(value, index, self)`.\n * @param thisArg Optional `this` binding for the callback.\n * @returns `void`.\n *\n * @remarks\n * Time O(n), Space O(1).\n */\n forEach(callbackfn: ElementCallback<E, R, void>, thisArg?: unknown): void {\n let index = 0;\n for (const item of this) {\n if (thisArg === undefined) {\n callbackfn(item, index++, this);\n } else {\n const fn = callbackfn as (this: unknown, v: E, i: number, self: this) => void;\n fn.call(thisArg, item, index++, this);\n }\n }\n }\n\n /**\n * Finds the first element that satisfies the predicate and returns it.\n *\n * @overload\n * Finds the first element of type `S` (a subtype of `E`) that satisfies the predicate and returns it.\n * @template S\n * @param predicate Type-guard predicate: `(value, index, self) => value is S`.\n * @param thisArg Optional `this` binding for the predicate.\n * @returns The matched element typed as `S`, or `undefined` if not found.\n *\n * @overload\n * @param predicate Boolean predicate: `(value, index, self) => boolean`.\n * @param thisArg Optional `this` binding for the predicate.\n * @returns The first matching element as `E`, or `undefined` if not found.\n *\n * @remarks\n * Time O(n) in the worst case; may exit early on the first match. Space O(1).\n */\n find<S extends E>(predicate: ElementCallback<E, R, S>, thisArg?: unknown): S | undefined;\n find(predicate: ElementCallback<E, R, unknown>, thisArg?: unknown): E | undefined;\n\n // Implementation signature\n find(predicate: ElementCallback<E, R, boolean>, thisArg?: unknown): E | undefined {\n let index = 0;\n for (const item of this) {\n if (thisArg === undefined) {\n if (predicate(item, index++, this)) return item;\n } else {\n const fn = predicate as (this: unknown, v: E, i: number, self: this) => boolean;\n if (fn.call(thisArg, item, index++, this)) return item;\n }\n }\n return;\n }\n\n /**\n * Checks whether a strictly-equal element exists in the structure.\n *\n * @param element The element to test with `===` equality.\n * @returns `true` if an equal element is found; otherwise `false`.\n *\n * @remarks\n * Time O(n) in the worst case. Space O(1).\n */\n has(element: E): boolean {\n for (const ele of this) if (ele === element) return true;\n return false;\n }\n\n reduce(callbackfn: ReduceElementCallback<E, R>): E;\n reduce(callbackfn: ReduceElementCallback<E, R>, initialValue: E): E;\n reduce<U>(callbackfn: ReduceElementCallback<E, R, U>, initialValue: U): U;\n\n /**\n * Reduces all elements to a single accumulated value.\n *\n * @overload\n * @param callbackfn Reducer of signature `(acc, value, index, self) => nextAcc`. The first element is used as the initial accumulator.\n * @returns The final accumulated value typed as `E`.\n *\n * @overload\n * @param callbackfn Reducer of signature `(acc, value, index, self) => nextAcc`.\n * @param initialValue The initial accumulator value of type `E`.\n * @returns The final accumulated value typed as `E`.\n *\n * @overload\n * @template U The accumulator type when it differs from `E`.\n * @param callbackfn Reducer of signature `(acc: U, value, index, self) => U`.\n * @param initialValue The initial accumulator value of type `U`.\n * @returns The final accumulated value typed as `U`.\n *\n * @remarks\n * Time O(n), Space O(1). Throws if called on an empty structure without `initialValue`.\n */\n reduce<U>(callbackfn: ReduceElementCallback<E, R, U>, initialValue?: U): U {\n let index = 0;\n const iter = this[Symbol.iterator]();\n let acc: U;\n\n if (arguments.length >= 2) {\n acc = initialValue as U;\n } else {\n const first = iter.next();\n if (first.done) throw new TypeError('Reduce of empty structure with no initial value');\n acc = first.value as unknown as U;\n index = 1;\n }\n\n for (const value of iter) {\n acc = callbackfn(acc, value, index++, this);\n }\n return acc;\n }\n\n /**\n * Materializes the elements into a new array.\n *\n * @returns A shallow array copy of the iteration order.\n * @remarks\n * Time O(n), Space O(n).\n */\n toArray(): E[] {\n return [...this];\n }\n\n /**\n * Returns a representation of the structure suitable for quick visualization.\n * Defaults to an array of elements; subclasses may override to provide richer visuals.\n *\n * @returns A visual representation (array by default).\n * @remarks\n * Time O(n), Space O(n).\n */\n toVisual(): E[] {\n return [...this];\n }\n\n /**\n * Prints `toVisual()` to the console. Intended for quick debugging.\n *\n * @returns `void`.\n * @remarks\n * Time O(n) due to materialization, Space O(n) for the intermediate representation.\n */\n print(): void {\n console.log(this.toVisual());\n }\n\n /**\n * Indicates whether the structure currently contains no elements.\n *\n * @returns `true` if empty; otherwise `false`.\n * @remarks\n * Expected Time O(1), Space O(1) for most implementations.\n */\n abstract isEmpty(): boolean;\n\n /**\n * Removes all elements from the structure.\n *\n * @returns `void`.\n * @remarks\n * Expected Time O(1) or O(n) depending on the implementation; Space O(1).\n */\n abstract clear(): void;\n\n /**\n * Creates a structural copy with the same element values and configuration.\n *\n * @returns A clone of the current instance (same concrete type).\n * @remarks\n * Expected Time O(n) to copy elements; Space O(n).\n */\n abstract clone(): this;\n\n /**\n * Maps each element to a new element and returns a new iterable structure.\n *\n * @template EM The mapped element type.\n * @template RM The mapped raw element type used internally by the target structure.\n * @param callback Function with signature `(value, index, self) => mapped`.\n * @param options Optional options for the returned structure, including its `toElementFn`.\n * @param thisArg Optional `this` binding for the callback.\n * @returns A new `IterableElementBase<EM, RM>` containing mapped elements.\n *\n * @remarks\n * Time O(n), Space O(n).\n */\n abstract map<EM, RM>(\n callback: ElementCallback<E, R, EM>,\n options?: IterableElementBaseOptions<EM, RM>,\n thisArg?: unknown\n ): IterableElementBase<EM, RM>;\n\n /**\n * Maps each element to the same element type and returns the same concrete structure type.\n *\n * @param callback Function with signature `(value, index, self) => mappedValue`.\n * @param thisArg Optional `this` binding for the callback.\n * @returns A new instance of the same concrete type with mapped elements.\n *\n * @remarks\n * Time O(n), Space O(n).\n */\n abstract mapSame(callback: ElementCallback<E, R, E>, thisArg?: unknown): this;\n\n /**\n * Filters elements using the provided predicate and returns the same concrete structure type.\n *\n * @param predicate Function with signature `(value, index, self) => boolean`.\n * @param thisArg Optional `this` binding for the predicate.\n * @returns A new instance of the same concrete type containing only elements that pass the predicate.\n *\n * @remarks\n * Time O(n), Space O(k) where `k` is the number of kept elements.\n */\n abstract filter(predicate: ElementCallback<E, R, boolean>, thisArg?: unknown): this;\n\n /**\n * Internal iterator factory used by the default iterator.\n *\n * @param args Optional iterator arguments.\n * @returns An iterator over elements.\n *\n * @remarks\n * Implementations should yield in O(1) per element with O(1) extra space when possible.\n */\n protected abstract _getIterator(...args: unknown[]): IterableIterator<E>;\n}\n","/**\n * data-structure-typed\n *\n * @author Pablo Zeng\n * @copyright Copyright (c) 2022 Pablo Zeng <zrwusa@gmail.com>\n * @license MIT License\n */\n\nimport type { ElementCallback, TrieOptions } from '../../types';\nimport { IterableElementBase } from '../base';\n\n/**\n * Node used by Trie to store one character and its children.\n * @remarks Time O(1), Space O(1)\n */\nexport class TrieNode {\n /**\n * Create a Trie node with a character key.\n * @remarks Time O(1), Space O(1)\n * @returns New TrieNode instance.\n */\n\n constructor(key: string) {\n this._key = key;\n this._isEnd = false;\n this._children = new Map<string, TrieNode>();\n }\n\n protected _key: string;\n\n /**\n * Get the character key of this node.\n * @remarks Time O(1), Space O(1)\n * @returns Character key string.\n */\n\n get key(): string {\n return this._key;\n }\n\n /**\n * Set the character key of this node.\n * @remarks Time O(1), Space O(1)\n * @param value - New character key.\n * @returns void\n */\n\n set key(value: string) {\n this._key = value;\n }\n\n protected _children: Map<string, TrieNode>;\n\n /**\n * Get the child map of this node.\n * @remarks Time O(1), Space O(1)\n * @returns Map from character to child node.\n */\n\n get children(): Map<string, TrieNode> {\n return this._children;\n }\n\n /**\n * Replace the child map of this node.\n * @remarks Time O(1), Space O(1)\n * @param value - New map of character → node.\n * @returns void\n */\n\n set children(value: Map<string, TrieNode>) {\n this._children = value;\n }\n\n protected _isEnd: boolean;\n\n /**\n * Check whether this node marks the end of a word.\n * @remarks Time O(1), Space O(1)\n * @returns True if this node ends a word.\n */\n\n get isEnd(): boolean {\n return this._isEnd;\n }\n\n /**\n * Mark this node as the end of a word or not.\n * @remarks Time O(1), Space O(1)\n * @param value - Whether this node ends a word.\n * @returns void\n */\n\n set isEnd(value: boolean) {\n this._isEnd = value;\n }\n}\n\n/**\n * Prefix tree (Trie) for fast prefix queries and word storage.\n * @remarks Time O(1), Space O(1)\n * @template R\n * 1. Node Structure: Each node in a Trie represents a string (or a part of a string). The root node typically represents an empty string.\n * 2. Child Node Relationship: Each node's children represent the strings that can be formed by adding one character to the string at the current node. For example, if a node represents the string 'ca', one of its children might represent 'cat'.\n * 3. Fast Retrieval: Trie allows retrieval in O(m) time complexity, where m is the length of the string to be searched.\n * 4. Space Efficiency: Trie can store a large number of strings very space-efficiently, especially when these strings share common prefixes.\n * 5. Autocomplete and Prediction: Trie can be used for implementing autocomplete and word prediction features, as it can quickly find all strings with a common prefix.\n * 6. Sorting: Trie can be used to sort a set of strings in alphabetical order.\n * 7. String Retrieval: For example, searching for a specific string in a large set of strings.\n * 8. Autocomplete: Providing recommended words or phrases as a user types.\n * 9. Spell Check: Checking the spelling of words.\n * 10. IP Routing: Used in certain types of IP routing algorithms.\n * 11. Text Word Frequency Count: Counting and storing the frequency of words in a large amount of text data.\n * @example\n * // basic Trie creation and add words\n * // Create a simple Trie with initial words\n * const trie = new Trie(['apple', 'app', 'apply']);\n *\n * // Verify size\n * console.log(trie.size); // 3;\n *\n * // Check if words exist\n * console.log(trie.has('apple')); // true;\n * console.log(trie.has('app')); // true;\n *\n * // Add a new word\n * trie.add('application');\n * console.log(trie.size); // 4;\n * @example\n * // Trie getWords and prefix search\n * const trie = new Trie(['apple', 'app', 'apply', 'application', 'apricot']);\n *\n * // Get all words with prefix 'app'\n * const appWords = trie.getWords('app');\n * console.log(appWords); // contains 'app';\n * console.log(appWords); // contains 'apple';\n * console.log(appWords); // contains 'apply';\n * console.log(appWords); // contains 'application';\n * expect(appWords).not.toContain('apricot');\n * @example\n * // Trie isPrefix and isAbsolutePrefix checks\n * const trie = new Trie(['tree', 'trial', 'trick', 'trip', 'trie']);\n *\n * // Check if string is a prefix of any word\n * console.log(trie.hasPrefix('tri')); // true;\n * console.log(trie.hasPrefix('tr')); // true;\n * console.log(trie.hasPrefix('xyz')); // false;\n *\n * // Check if string is an absolute prefix (not a complete word)\n * console.log(trie.hasPurePrefix('tri')); // true;\n * console.log(trie.hasPurePrefix('tree')); // false; // 'tree' is a complete word\n *\n * // Verify size\n * console.log(trie.size); // 5;\n * @example\n * // Trie delete and iteration\n * const trie = new Trie(['car', 'card', 'care', 'careful', 'can', 'cat']);\n *\n * // Delete a word\n * trie.delete('card');\n * console.log(trie.has('card')); // false;\n *\n * // Word with same prefix still exists\n * console.log(trie.has('care')); // true;\n *\n * // Size decreased\n * console.log(trie.size); // 5;\n *\n * // Iterate through all words\n * const allWords = [...trie];\n * console.log(allWords.length); // 5;\n * @example\n * // Trie for autocomplete search index\n * // Trie is perfect for autocomplete: O(m + k) where m is prefix length, k is results\n * const searchIndex = new Trie(['typescript', 'javascript', 'python', 'java', 'rust', 'ruby', 'golang', 'kotlin']);\n *\n * // User types 'j' - get all suggestions\n * const jResults = searchIndex.getWords('j');\n * console.log(jResults); // contains 'javascript';\n * console.log(jResults); // contains 'java';\n * console.log(jResults.length); // 2;\n *\n * // User types 'ja' - get more specific suggestions\n * const jaResults = searchIndex.getWords('ja');\n * console.log(jaResults); // contains 'javascript';\n * console.log(jaResults); // contains 'java';\n * console.log(jaResults.length); // 2;\n *\n * // User types 'jav' - even more specific\n * const javResults = searchIndex.getWords('jav');\n * console.log(javResults); // contains 'javascript';\n * console.log(javResults); // contains 'java';\n * console.log(javResults.length); // 2;\n *\n * // Check for common prefix\n *\n * console.log(searchIndex.hasCommonPrefix('ja')); // false; // Not all words start with 'ja'\n *\n * // Total words in index\n * console.log(searchIndex.size); // 8;\n *\n * // Get height (depth of tree)\n * const height = searchIndex.getHeight();\n * console.log(typeof height); // 'number';\n * @example\n * // Dictionary: Case-insensitive word lookup\n * // Create a case-insensitive dictionary\n * const dictionary = new Trie<string>([], { caseSensitive: false });\n *\n * // Add words with mixed casing\n * dictionary.add('Hello');\n * dictionary.add('WORLD');\n * dictionary.add('JavaScript');\n *\n * // Test lookups with different casings\n * console.log(dictionary.has('hello')); // true;\n * console.log(dictionary.has('HELLO')); // true;\n * console.log(dictionary.has('Hello')); // true;\n * console.log(dictionary.has('javascript')); // true;\n * console.log(dictionary.has('JAVASCRIPT')); // true;\n * @example\n * // File System Path Operations\n * const fileSystem = new Trie<string>([\n * '/home/user/documents/file1.txt',\n * '/home/user/documents/file2.txt',\n * '/home/user/pictures/photo.jpg',\n * '/home/user/pictures/vacation/',\n * '/home/user/downloads'\n * ]);\n *\n * // Find common directory prefix\n * console.log(fileSystem.getLongestCommonPrefix()); // '/home/user/';\n *\n * // List all files in a directory\n * const documentsFiles = fileSystem.getWords('/home/user/documents/');\n * console.log(documentsFiles); // ['/home/user/documents/file1.txt', '/home/user/documents/file2.txt'];\n * @example\n * // IP Address Routing Table\n * // Add IP address prefixes and their corresponding routes\n * const routes = {\n * '192.168.1': 'LAN_SUBNET_1',\n * '192.168.2': 'LAN_SUBNET_2',\n * '10.0.0': 'PRIVATE_NETWORK_1',\n * '10.0.1': 'PRIVATE_NETWORK_2'\n * };\n *\n * const ipRoutingTable = new Trie<string>(Object.keys(routes));\n *\n * // Check IP address prefix matching\n * console.log(ipRoutingTable.hasPrefix('192.168.1')); // true;\n * console.log(ipRoutingTable.hasPrefix('192.168.2')); // true;\n *\n * // Validate IP address belongs to subnet\n * const ip = '192.168.1.100';\n * const subnet = ip.split('.').slice(0, 3).join('.');\n * console.log(ipRoutingTable.hasPrefix(subnet)); // true;\n */\nexport class Trie<R = any> extends IterableElementBase<string, R> {\n /**\n * Create a Trie and optionally bulk-insert words.\n * @remarks Time O(totalChars), Space O(totalChars)\n * @param [words] - Iterable of strings (or raw records if toElementFn is provided).\n * @param [options] - Options such as toElementFn and caseSensitive.\n * @returns New Trie instance.\n */\n\n constructor(words: Iterable<string> | Iterable<R> = [], options?: TrieOptions<R>) {\n super(options);\n if (options) {\n const { caseSensitive } = options;\n if (caseSensitive !== undefined) this._caseSensitive = caseSensitive;\n }\n if (words) {\n this.addMany(words);\n }\n }\n\n protected _size: number = 0;\n\n /**\n * Get the number of stored words.\n * @remarks Time O(1), Space O(1)\n * @returns Word count.\n */\n\n get size(): number {\n return this._size;\n }\n\n protected _caseSensitive: boolean = true;\n\n /**\n * Get whether comparisons are case-sensitive.\n * @remarks Time O(1), Space O(1)\n * @returns True if case-sensitive.\n */\n\n get caseSensitive(): boolean {\n return this._caseSensitive;\n }\n\n protected _root: TrieNode = new TrieNode('');\n\n /**\n * Get the root node.\n * @remarks Time O(1), Space O(1)\n * @returns Root TrieNode.\n */\n\n get root() {\n return this._root;\n }\n\n /**\n * (Protected) Get total count for base class iteration.\n * @remarks Time O(1), Space O(1)\n * @returns Total number of elements.\n */\n\n protected get _total() {\n return this._size;\n }\n\n /**\n * Insert one word into the trie.\n * @remarks Time O(L), Space O(L)\n * @param word - Word to insert.\n * @returns True if the word was newly added.\n */\n\n add(word: string): boolean {\n word = this._caseProcess(word);\n let cur = this.root;\n let isNewWord = false;\n for (const c of word) {\n let nodeC = cur.children.get(c);\n if (!nodeC) {\n nodeC = new TrieNode(c);\n cur.children.set(c, nodeC);\n }\n cur = nodeC;\n }\n if (!cur.isEnd) {\n isNewWord = true;\n cur.isEnd = true;\n this._size++;\n }\n return isNewWord;\n }\n\n /**\n * Insert many words from an iterable.\n * @remarks Time O(ΣL), Space O(ΣL)\n * @param words - Iterable of strings (or raw records if toElementFn is provided).\n * @returns Array of per-word 'added' flags.\n */\n\n addMany(words: Iterable<string> | Iterable<R>): boolean[] {\n const ans: boolean[] = [];\n for (const word of words) {\n if (this.toElementFn) {\n ans.push(this.add(this.toElementFn(word as R)));\n } else {\n ans.push(this.add(word as string));\n }\n }\n return ans;\n }\n\n /**\n * Check whether a word exists.\n * @remarks Time O(L), Space O(1)\n * @param word - Word to search for.\n * @returns True if present.\n */\n\n override has(word: string): boolean {\n word = this._caseProcess(word);\n let cur = this.root;\n for (const c of word) {\n const nodeC = cur.children.get(c);\n if (!nodeC) return false;\n cur = nodeC;\n }\n return cur.isEnd;\n }\n\n /**\n * Check whether the trie is empty.\n * @remarks Time O(1), Space O(1)\n * @returns True if size is 0.\n */\n\n isEmpty(): boolean {\n return this._size === 0;\n }\n\n /**\n * Remove all words and reset to a fresh root.\n * @remarks Time O(1), Space O(1)\n * @returns void\n */\n\n clear(): void {\n this._size = 0;\n this._root = new TrieNode('');\n }\n\n /**\n * Delete one word if present.\n * @remarks Time O(L), Space O(1)\n * @param word - Word to delete.\n * @returns True if a word was removed.\n */\n\n delete(word: string): boolean {\n word = this._caseProcess(word);\n let isDeleted = false;\n const dfs = (cur: TrieNode, i: number): boolean => {\n const char = word[i];\n const child = cur.children.get(char);\n if (child) {\n if (i === word.length - 1) {\n if (child.isEnd) {\n if (child.children.size > 0) {\n child.isEnd = false;\n } else {\n cur.children.delete(char);\n }\n isDeleted = true;\n return true;\n }\n return false;\n }\n const res = dfs(child, i + 1);\n if (res && !cur.isEnd && child.children.size === 0) {\n cur.children.delete(char);\n return true;\n }\n return false;\n }\n return false;\n };\n\n dfs(this.root, 0);\n if (isDeleted) {\n this._size--;\n }\n return isDeleted;\n }\n\n /**\n * Compute the height (max depth) of the trie.\n * @remarks Time O(N), Space O(H)\n * @returns Maximum depth from root to a leaf.\n */\n\n getHeight(): number {\n const startNode = this.root;\n let maxDepth = 0;\n if (startNode) {\n const bfs = (node: TrieNode, level: number) => {\n if (level > maxDepth) {\n maxDepth = level;\n }\n const { children } = node;\n if (children) {\n for (const child of children.entries()) {\n bfs(child[1], level + 1);\n }\n }\n };\n bfs(startNode, 0);\n }\n return maxDepth;\n }\n\n /**\n * Check whether input is a proper prefix of at least one word.\n * @remarks Time O(L), Space O(1)\n * @param input - String to test as prefix.\n * @returns True if input is a prefix but not a full word.\n */\n\n hasPurePrefix(input: string): boolean {\n input = this._caseProcess(input);\n let cur = this.root;\n for (const c of input) {\n const nodeC = cur.children.get(c);\n if (!nodeC) return false;\n cur = nodeC;\n }\n return !cur.isEnd;\n }\n\n /**\n * Check whether any word starts with input.\n * @remarks Time O(L), Space O(1)\n * @param input - String to test as prefix.\n * @returns True if input matches a path from root.\n */\n\n hasPrefix(input: string): boolean {\n input = this._caseProcess(input);\n let cur = this.root;\n for (const c of input) {\n const nodeC = cur.children.get(c);\n if (!nodeC) return false;\n cur = nodeC;\n }\n return true;\n }\n\n /**\n * Check whether the trie’s longest common prefix equals input.\n * @remarks Time O(min(H,L)), Space O(1)\n * @param input - Candidate longest common prefix.\n * @returns True if input equals the common prefix.\n */\n\n hasCommonPrefix(input: string): boolean {\n input = this._caseProcess(input);\n let commonPre = '';\n const dfs = (cur: TrieNode) => {\n commonPre += cur.key;\n if (commonPre === input) return;\n if (cur.isEnd) return;\n if (cur && cur.children && cur.children.size === 1) dfs(Array.from(cur.children.values())[0]);\n else return;\n };\n dfs(this.root);\n return commonPre === input;\n }\n\n /**\n * Return the longest common prefix among all words.\n * @remarks Time O(H), Space O(1)\n * @returns The longest common prefix string.\n */\n\n getLongestCommonPrefix(): string {\n let commonPre = '';\n const dfs = (cur: TrieNode) => {\n commonPre += cur.key;\n if (cur.isEnd) return;\n if (cur && cur.children && cur.children.size === 1) dfs(Array.from(cur.children.values())[0]);\n else return;\n };\n dfs(this.root);\n return commonPre;\n }\n\n /**\n * Collect words under a prefix up to a maximum count.\n * @remarks Time O(K·L), Space O(K·L)\n * @param [prefix] - Prefix to match; default empty string for root.\n * @param [max] - Maximum number of words to return; default is Number.MAX_SAFE_INTEGER.\n * @param [isAllWhenEmptyPrefix] - When true, collect from root even if prefix is empty.\n * @returns Array of collected words (at most max).\n */\n\n getWords(prefix = '', max = Number.MAX_SAFE_INTEGER, isAllWhenEmptyPrefix = false): string[] {\n prefix = this._caseProcess(prefix);\n const words: string[] = [];\n let found = 0;\n\n const dfs = (node: TrieNode, word: string): void => {\n for (const [char, childNode] of node.children) {\n if (found >= max) return;\n dfs(childNode, word + char);\n }\n if (node.isEnd) {\n if (found >= max) return;\n words.push(word);\n found++;\n }\n };\n\n let startNode = this.root;\n\n if (prefix) {\n for (const c of prefix) {\n const nodeC = startNode.children.get(c);\n if (nodeC) {\n startNode = nodeC;\n } else {\n return [];\n }\n }\n }\n\n if (isAllWhenEmptyPrefix || startNode !== this.root) dfs(startNode, prefix);\n\n return words;\n }\n\n /**\n * Deep clone this trie by iterating and inserting all words.\n * @remarks Time O(ΣL), Space O(ΣL)\n * @returns A new trie with the same words and options.\n */\n\n clone(): this {\n const next = this._createInstance();\n for (const x of this) next.add(x);\n return next;\n }\n\n /**\n * Filter words into a new trie of the same class.\n * @remarks Time O(ΣL), Space O(ΣL)\n * @param predicate - Predicate (word, index, trie) → boolean to keep word.\n * @param [thisArg] - Value for `this` inside the predicate.\n * @returns A new trie containing words that satisfy the predicate.\n */\n\n filter(predicate: ElementCallback<string, R, boolean>, thisArg?: any): this {\n const results = this._createInstance();\n let index = 0;\n for (const word of this) {\n if (predicate.call(thisArg, word, index, this)) {\n results.add(word);\n }\n index++;\n }\n return results;\n }\n\n map<RM>(callback: ElementCallback<string, R, string>, options?: TrieOptions<RM>, thisArg?: any): Trie<RM>;\n\n /**\n * Map words into a new trie (possibly different record type).\n * @remarks Time O(ΣL), Space O(ΣL)\n * @template EM\n * @template RM\n * @param callback - Mapping function (word, index, trie) → newWord (string).\n * @param [options] - Options for the output trie (e.g., toElementFn, caseSensitive).\n * @param [thisArg] - Value for `this` inside the callback.\n * @returns A new Trie constructed from mapped words.\n */\n\n map<EM, RM>(\n callback: ElementCallback<string, R, EM>,\n options?: TrieOptions<RM>,\n thisArg?: any\n ): IterableElementBase<EM, RM>;\n\n map<EM, RM>(callback: ElementCallback<string, R, EM>, options?: TrieOptions<RM>, thisArg?: any): any {\n const newTrie = this._createLike<RM>([], options);\n let i = 0;\n for (const x of this) {\n const v = thisArg === undefined ? callback(x, i++, this) : callback.call(thisArg, x, i++, this);\n if (typeof v !== 'string') {\n throw new TypeError(`Trie.map callback must return string; got ${typeof v}`);\n }\n newTrie.add(v);\n }\n return newTrie;\n }\n\n /**\n * Map words into a new trie of the same element type.\n * @remarks Time O(ΣL), Space O(ΣL)\n * @param callback - Mapping function (word, index, trie) → string.\n * @param [thisArg] - Value for `this` inside the callback.\n * @returns A new trie with mapped words.\n */\n\n mapSame(callback: ElementCallback<string, R, string>, thisArg?: any): this {\n const next = this._createInstance();\n let i = 0;\n for (const key of this) {\n const mapped = thisArg === undefined ? callback(key, i++, this) : callback.call(thisArg, key, i++, this);\n next.add(mapped);\n }\n return next;\n }\n\n /**\n * (Protected) Create an empty instance of the same concrete class.\n * @remarks Time O(1), Space O(1)\n * @param [options] - Options forwarded to the constructor.\n * @returns An empty like-kind trie instance.\n */\n\n protected _createInstance(options?: TrieOptions<R>): this {\n const Ctor = this.constructor as new (\n elements?: Iterable<string> | Iterable<R>,\n options?: TrieOptions<R>\n ) => this;\n return new Ctor([], {\n toElementFn: this.toElementFn,\n caseSensitive: this.caseSensitive,\n ...(options ?? {})\n });\n }\n\n /**\n * (Protected) Create a like-kind trie and seed it from an iterable.\n * @remarks Time O(ΣL), Space O(ΣL)\n * @template RM\n * @param [elements] - Iterable used to seed the new trie.\n * @param [options] - Options forwarded to the constructor.\n * @returns A like-kind Trie instance.\n */\n\n protected _createLike<RM>(elements: Iterable<string> | Iterable<RM> = [], options?: TrieOptions<RM>): Trie<RM> {\n const Ctor = this.constructor as new (\n elements?: Iterable<string> | Iterable<RM>,\n options?: TrieOptions<RM>\n ) => Trie<RM>;\n return new Ctor(elements, options);\n }\n\n /**\n * (Protected) Spawn an empty like-kind trie instance.\n * @remarks Time O(1), Space O(1)\n * @template RM\n * @param [options] - Options forwarded to the constructor.\n * @returns An empty like-kind Trie instance.\n */\n\n protected _spawnLike<RM>(options?: TrieOptions<RM>): Trie<RM> {\n return this._createLike<RM>([], options);\n }\n\n /**\n * (Protected) Iterate all words in lexicographic order of edges.\n * @remarks Time O(ΣL), Space O(H)\n * @returns Iterator of words.\n */\n\n protected *_getIterator(): IterableIterator<string> {\n function* _dfs(node: TrieNode, path: string): IterableIterator<string> {\n if (node.isEnd) {\n yield path;\n }\n for (const [char, childNode] of node.children) {\n yield* _dfs(childNode, path + char);\n }\n }\n\n yield* _dfs(this.root, '');\n }\n\n /**\n * (Protected) Normalize a string according to case sensitivity.\n * @remarks Time O(L), Space O(L)\n * @param str - Input string to normalize.\n * @returns Normalized string based on caseSensitive.\n */\n\n protected _caseProcess(str: string) {\n if (!this._caseSensitive) {\n str = str.toLowerCase();\n }\n return str;\n }\n}\n","export enum DFSOperation {\n VISIT = 0,\n PROCESS = 1\n}\n\nexport class Range<K> {\n constructor(\n public low: K,\n public high: K,\n public includeLow: boolean = true,\n public includeHigh: boolean = true\n ) {\n // if (!(isComparable(low) && isComparable(high))) throw new RangeError('low or high is not comparable');\n // if (low > high) throw new RangeError('low must be less than or equal to high');\n }\n\n // Determine whether a key is within the range\n isInRange(key: K, comparator: (a: K, b: K) => number): boolean {\n const lowCheck = this.includeLow ? comparator(key, this.low) >= 0 : comparator(key, this.low) > 0;\n const highCheck = this.includeHigh ? comparator(key, this.high) <= 0 : comparator(key, this.high) < 0;\n return lowCheck && highCheck;\n }\n}\n"],"mappings":"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","names":["src_exports","__export","DFSOperation","Range","Trie","TrieNode","IterableElementBase","options","__publicField","toElementFn","args","item","predicate","thisArg","index","callbackfn","element","ele","initialValue","iter","acc","first","value","TrieNode","key","__publicField","value","Trie","IterableElementBase","words","options","caseSensitive","word","cur","isNewWord","c","nodeC","ans","isDeleted","dfs","char","child","startNode","maxDepth","bfs","node","level","children","input","commonPre","prefix","max","isAllWhenEmptyPrefix","found","childNode","next","x","predicate","thisArg","results","index","callback","newTrie","v","i","mapped","Ctor","elements","_dfs","path","str","DFSOperation","Range","low","high","includeLow","includeHigh","key","comparator","lowCheck","highCheck"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "trie-typed",
3
- "version": "2.4.2",
3
+ "version": "2.4.4",
4
4
  "description": "Trie, prefix tree",
5
5
  "browser": "dist/umd/trie-typed.min.js",
6
6
  "umd:main": "dist/umd/trie-typed.min.js",
@@ -166,6 +166,6 @@
166
166
  "typescript": "^4.9.5"
167
167
  },
168
168
  "dependencies": {
169
- "data-structure-typed": "^2.4.2"
169
+ "data-structure-typed": "^2.4.4"
170
170
  }
171
171
  }
@@ -35,7 +35,7 @@ export abstract class IterableElementBase<E, R> implements Iterable<E> {
35
35
  * @remarks
36
36
  * Time O(1), Space O(1).
37
37
  */
38
- protected _toElementFn?: (rawElement: R) => E;
38
+ protected readonly _toElementFn?: (rawElement: R) => E;
39
39
 
40
40
  /**
41
41
  * Exposes the current `toElementFn`, if configured.
@@ -229,7 +229,7 @@ export abstract class IterableElementBase<E, R> implements Iterable<E> {
229
229
  index = 1;
230
230
  }
231
231
 
232
- for (const value of iter as unknown as Iterable<E>) {
232
+ for (const value of iter) {
233
233
  acc = callbackfn(acc, value, index++, this);
234
234
  }
235
235
  return acc;
@@ -377,7 +377,7 @@ export class BinaryTree<K = any, V = any, R = any>
377
377
  if (keysNodesEntriesOrRaws) this.setMany(keysNodesEntriesOrRaws);
378
378
  }
379
379
 
380
- protected _isMapMode = true;
380
+ protected readonly _isMapMode: boolean = true;
381
381
 
382
382
  /**
383
383
  * Gets whether the tree is in Map mode.
@@ -389,7 +389,7 @@ export class BinaryTree<K = any, V = any, R = any>
389
389
  return this._isMapMode;
390
390
  }
391
391
 
392
- protected _isDuplicate = false;
392
+ protected readonly _isDuplicate: boolean = false;
393
393
 
394
394
  /**
395
395
  * Gets whether the tree allows duplicate keys.
@@ -440,7 +440,7 @@ export class BinaryTree<K = any, V = any, R = any>
440
440
  return this._size;
441
441
  }
442
442
 
443
- protected _NIL: BinaryTreeNode<K, V> = new BinaryTreeNode<K, V>(NaN as K) as unknown as BinaryTreeNode<K, V>;
443
+ protected readonly _NIL = new BinaryTreeNode<K, V>(NaN as K);
444
444
 
445
445
  /**
446
446
  * Gets the sentinel NIL node (used in self-balancing trees like Red-Black Tree).
@@ -452,7 +452,7 @@ export class BinaryTree<K = any, V = any, R = any>
452
452
  return this._NIL;
453
453
  }
454
454
 
455
- protected _toEntryFn?: ToEntryFn<K, V, R>;
455
+ protected readonly _toEntryFn?: ToEntryFn<K, V, R>;
456
456
 
457
457
  /**
458
458
  * Gets the function used to convert raw data objects (R) into [key, value] entries.
@@ -1014,7 +1014,7 @@ export class BinaryTree<K = any, V = any, R = any>
1014
1014
  ): BinaryTreeNode<K, V> | null | undefined {
1015
1015
  if (this._isMapMode && keyNodeEntryOrPredicate !== null && keyNodeEntryOrPredicate !== undefined) {
1016
1016
  if (!this._isPredicate(keyNodeEntryOrPredicate)) {
1017
- const key = this._extractKey(keyNodeEntryOrPredicate as any);
1017
+ const key = this._extractKey(keyNodeEntryOrPredicate);
1018
1018
  if (key === null || key === undefined) return;
1019
1019
  return this._store.get(key);
1020
1020
  }
@@ -1078,7 +1078,7 @@ export class BinaryTree<K = any, V = any, R = any>
1078
1078
  ): boolean {
1079
1079
  if (this._isMapMode && keyNodeEntryOrPredicate !== undefined && keyNodeEntryOrPredicate !== null) {
1080
1080
  if (!this._isPredicate(keyNodeEntryOrPredicate)) {
1081
- const key = this._extractKey(keyNodeEntryOrPredicate as any);
1081
+ const key = this._extractKey(keyNodeEntryOrPredicate);
1082
1082
  if (key === null || key === undefined) return false;
1083
1083
  return this._store.has(key);
1084
1084
  }
@@ -2136,7 +2136,8 @@ export class BinaryTree<K = any, V = any, R = any>
2136
2136
  * @param node - The node.
2137
2137
  * @returns The node's key or undefined.
2138
2138
  */
2139
- protected _DEFAULT_NODE_CALLBACK = (node: BinaryTreeNode<K, V> | null | undefined) => (node ? node.key : undefined);
2139
+ protected readonly _DEFAULT_NODE_CALLBACK: NodeCallback<BinaryTreeNode<K, V> | null | undefined, K | undefined> =
2140
+ (node): K | undefined => node?.key;
2140
2141
 
2141
2142
  /**
2142
2143
  * (Protected) Snapshots the current tree's configuration options.
@@ -391,7 +391,7 @@ export class BST<K = any, V = any, R = any> extends BinaryTree<K, V, R> implemen
391
391
 
392
392
  * @remarks Time O(1) Space O(1)
393
393
  */
394
- protected _comparator: Comparator<K>;
394
+ protected readonly _comparator: Comparator<K>;
395
395
 
396
396
  /**
397
397
  * Gets the comparator function used by the tree.
@@ -436,4 +436,20 @@ export class TreeMap<K = any, V = any, R = [K, V]> implements Iterable<[K, V | u
436
436
 
437
437
  return out;
438
438
  }
439
+
440
+ /**
441
+ * Creates a shallow clone of this map.
442
+ * @remarks Time O(n log n), Space O(n)
443
+ * @example
444
+ * const original = new TreeMap([['a', 1], ['b', 2]]);
445
+ * const copy = original.clone();
446
+ * copy.set('c', 3);
447
+ * original.has('c'); // false (original unchanged)
448
+ */
449
+ clone(): TreeMap<K, V> {
450
+ return new TreeMap<K, V>(this, {
451
+ comparator: this.#isDefaultComparator ? undefined : this.#userComparator,
452
+ isMapMode: this.#core.isMapMode
453
+ });
454
+ }
439
455
  }
@@ -247,7 +247,7 @@ export class TreeMultiSet<K = any, R = K> implements Iterable<K> {
247
247
  * @remarks Time O(1), Space O(1)
248
248
  */
249
249
  get comparator(): Comparator<K> {
250
- return (this.#core as any)._comparator;
250
+ return this.#core.comparator;
251
251
  }
252
252
 
253
253
  // ━━━ clear ━━━
@@ -398,7 +398,7 @@ export class TreeMultiSet<K = any, R = K> implements Iterable<K> {
398
398
  filter(predicate: (key: K, count: number) => boolean): TreeMultiSet<K> {
399
399
  const result = new TreeMultiSet<K>([], {
400
400
  comparator: this.#isDefaultComparator ? undefined : this.comparator,
401
- isMapMode: (this.#core as any)._isMapMode
401
+ isMapMode: this.#core.isMapMode
402
402
  });
403
403
  for (const [k, c] of this.entries()) {
404
404
  if (predicate(k, c)) {
@@ -443,7 +443,7 @@ export class TreeMultiSet<K = any, R = K> implements Iterable<K> {
443
443
  ): TreeMultiSet<K2> {
444
444
  const result = new TreeMultiSet<K2>([], {
445
445
  comparator: options?.comparator,
446
- isMapMode: (this.#core as any)._isMapMode
446
+ isMapMode: this.#core.isMapMode
447
447
  });
448
448
  for (const [k, c] of this.entries()) {
449
449
  const [newKey, newCount] = mapper(k, c);
@@ -464,7 +464,7 @@ export class TreeMultiSet<K = any, R = K> implements Iterable<K> {
464
464
  clone(): TreeMultiSet<K> {
465
465
  const result = new TreeMultiSet<K>([], {
466
466
  comparator: this.#isDefaultComparator ? undefined : this.comparator,
467
- isMapMode: (this.#core as any)._isMapMode
467
+ isMapMode: this.#core.isMapMode
468
468
  });
469
469
  for (const [k, c] of this.entries()) {
470
470
  result.add(k, c);
@@ -486,7 +486,7 @@ export class TreeMultiSet<K = any, R = K> implements Iterable<K> {
486
486
  callback?: C
487
487
  ): (C extends undefined ? K : ReturnType<C>)[] {
488
488
  const cb = callback ?? ((k: K) => k);
489
- return this.#core.rangeSearch(range, node => cb(node.key)) as any;
489
+ return this.#core.rangeSearch(range, node => cb(node.key));
490
490
  }
491
491
 
492
492
  /**
@@ -404,4 +404,20 @@ export class TreeSet<K = any, R = K> implements Iterable<K> {
404
404
 
405
405
  return out;
406
406
  }
407
+
408
+ /**
409
+ * Creates a shallow clone of this set.
410
+ * @remarks Time O(n log n), Space O(n)
411
+ * @example
412
+ * const original = new TreeSet([1, 2, 3]);
413
+ * const copy = original.clone();
414
+ * copy.add(4);
415
+ * original.has(4); // false (original unchanged)
416
+ */
417
+ clone(): TreeSet<K> {
418
+ return new TreeSet<K>(this, {
419
+ comparator: this.#isDefaultComparator ? undefined : this.#userComparator,
420
+ isMapMode: this.#core.isMapMode
421
+ });
422
+ }
407
423
  }
@@ -65,7 +65,7 @@ export abstract class AbstractGraph<
65
65
  */
66
66
  constructor(options?: Partial<Record<string, unknown>>) {
67
67
  super();
68
- const graph = (options as any)?.graph as GraphOptions<V> | undefined;
68
+ const graph = (options as { graph?: GraphOptions<V> })?.graph;
69
69
  this._options = { defaultEdgeWeight: 1, ...(graph ?? {}) };
70
70
  }
71
71
 
@@ -984,11 +984,12 @@ export abstract class AbstractGraph<
984
984
  * @remarks Time O(1), Space O(1)
985
985
  */
986
986
  protected _createInstance(_options?: Partial<Record<string, unknown>>): this {
987
- const Ctor: any = (this as any).constructor;
988
- const instance: this = new Ctor();
989
- const graph = (_options as any)?.graph as GraphOptions<V> | undefined;
990
- if (graph) (instance as any)._options = { ...(instance as any)._options, ...graph };
991
- else (instance as any)._options = { ...(instance as any)._options, ...(this as any)._options };
987
+ const Ctor = this.constructor as new () => this;
988
+ const instance = new Ctor();
989
+ const graph = (_options as { graph?: GraphOptions<V> })?.graph;
990
+ // Use bracket notation for protected field access on dynamically created instance
991
+ if (graph) instance['_options'] = { ...instance['_options'], ...graph };
992
+ else instance['_options'] = { ...instance['_options'], ...this._options };
992
993
  return instance;
993
994
  }
994
995
 
@@ -1009,28 +1010,27 @@ export abstract class AbstractGraph<
1009
1010
  // 1) Add vertices
1010
1011
  if (iter) {
1011
1012
  for (const [k, v] of iter) {
1012
- (g as any).addVertex(k as VertexKey, v as V | undefined);
1013
+ g.addVertex(k as VertexKey, v as V | undefined);
1013
1014
  }
1014
1015
  } else {
1015
1016
  for (const [k, v] of this) {
1016
- (g as any).addVertex(k as VertexKey, v as V | undefined);
1017
+ g.addVertex(k as VertexKey, v as V | undefined);
1017
1018
  }
1018
1019
  }
1019
1020
  // 2) Add edges whose endpoints exist in the new graph
1020
1021
  const edges = this.edgeSet();
1021
- for (const e of edges as any[]) {
1022
- const ends = this.getEndsOfEdge(e as any) as unknown as [any, any] | undefined;
1022
+ for (const e of edges) {
1023
+ const ends = this.getEndsOfEdge(e);
1023
1024
  if (!ends) continue;
1024
1025
  const [va, vb] = ends;
1025
- const ka = (va as any).key as VertexKey;
1026
- const kb = (vb as any).key as VertexKey;
1027
- const hasA = (g as any).hasVertex ? (g as any).hasVertex(ka) : false;
1028
- const hasB = (g as any).hasVertex ? (g as any).hasVertex(kb) : false;
1026
+ const ka = va.key;
1027
+ const kb = vb.key;
1028
+ // Defensive check for edge cases where hasVertex may be overridden/undefined
1029
+ const hasA = typeof g.hasVertex === 'function' ? g.hasVertex(ka) : false;
1030
+ const hasB = typeof g.hasVertex === 'function' ? g.hasVertex(kb) : false;
1029
1031
  if (hasA && hasB) {
1030
- const w = (e as any).weight;
1031
- const val = (e as any).value;
1032
- const newEdge = (g as any).createEdge(ka, kb, w, val);
1033
- (g as any)._addEdge(newEdge);
1032
+ const newEdge = g.createEdge(ka, kb, e.weight, e.value);
1033
+ (g as this & { _addEdge(edge: EO): boolean })._addEdge(newEdge);
1034
1034
  }
1035
1035
  }
1036
1036
  return g;
@@ -207,8 +207,8 @@ export class DirectedGraph<
207
207
  * @returns DirectedGraph with all keys added.
208
208
  * @remarks Time O(V), Space O(V)
209
209
  */
210
- static fromKeys<K extends VertexKey>(keys: Iterable<K>): DirectedGraph<K, any, DirectedVertex<K>, DirectedEdge<any>> {
211
- const g: DirectedGraph<K, any, DirectedVertex<K>, DirectedEdge<any>> = new DirectedGraph<K, any>({
210
+ static fromKeys<K extends VertexKey>(keys: Iterable<K>): DirectedGraph<K, undefined, DirectedVertex<K>, DirectedEdge<undefined>> {
211
+ const g: DirectedGraph<K, undefined, DirectedVertex<K>, DirectedEdge<undefined>> = new DirectedGraph<K, undefined>({
212
212
  vertexValueInitializer: (k: VertexKey) => k as K
213
213
  });
214
214
  for (const k of keys) g.addVertex(k);
@@ -224,8 +224,8 @@ export class DirectedGraph<
224
224
  */
225
225
  static fromEntries<V>(
226
226
  entries: Iterable<[VertexKey, V]>
227
- ): DirectedGraph<V, any, DirectedVertex<V>, DirectedEdge<any>> {
228
- const g: DirectedGraph<V, any, DirectedVertex<V>, DirectedEdge<any>> = new DirectedGraph<V, any>();
227
+ ): DirectedGraph<V, undefined, DirectedVertex<V>, DirectedEdge<undefined>> {
228
+ const g: DirectedGraph<V, undefined, DirectedVertex<V>, DirectedEdge<undefined>> = new DirectedGraph<V, undefined>();
229
229
  for (const [k, v] of entries) g.addVertex(k, v);
230
230
  return g;
231
231
  }
@@ -111,7 +111,7 @@ export class MapGraph<
111
111
  * @remarks Time O(1), Space O(1)
112
112
  */
113
113
  protected override _snapshotOptions(): Record<string, unknown> {
114
- return { ...(super._snapshotOptions() as any), originCoord: this.originCoord, bottomRight: this.bottomRight };
114
+ return { ...super._snapshotOptions(), originCoord: this.originCoord, bottomRight: this.bottomRight };
115
115
  }
116
116
 
117
117
  /**
@@ -232,8 +232,8 @@ export class UndirectedGraph<
232
232
  */
233
233
  static fromKeys<K extends VertexKey>(
234
234
  keys: Iterable<K>
235
- ): UndirectedGraph<K, any, UndirectedVertex<K>, UndirectedEdge<any>> {
236
- const g: UndirectedGraph<K, any, UndirectedVertex<K>, UndirectedEdge<any>> = new UndirectedGraph<K, any>({
235
+ ): UndirectedGraph<K, undefined, UndirectedVertex<K>, UndirectedEdge<undefined>> {
236
+ const g: UndirectedGraph<K, undefined, UndirectedVertex<K>, UndirectedEdge<undefined>> = new UndirectedGraph<K, undefined>({
237
237
  vertexValueInitializer: (k: VertexKey) => k as K
238
238
  });
239
239
  for (const k of keys) g.addVertex(k);
@@ -249,8 +249,8 @@ export class UndirectedGraph<
249
249
  */
250
250
  static fromEntries<V>(
251
251
  entries: Iterable<[VertexKey, V]>
252
- ): UndirectedGraph<V, any, UndirectedVertex<V>, UndirectedEdge<any>> {
253
- const g: UndirectedGraph<V, any, UndirectedVertex<V>, UndirectedEdge<any>> = new UndirectedGraph<V, any>();
252
+ ): UndirectedGraph<V, undefined, UndirectedVertex<V>, UndirectedEdge<undefined>> {
253
+ const g: UndirectedGraph<V, undefined, UndirectedVertex<V>, UndirectedEdge<undefined>> = new UndirectedGraph<V, undefined>();
254
254
  for (const [k, v] of entries) g.addVertex(k, v);
255
255
  return g;
256
256
  }
@@ -197,7 +197,7 @@ export class HashMap<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
197
197
  return this._objMap;
198
198
  }
199
199
 
200
- protected _toEntryFn?: (rawElement: R) => [K, V];
200
+ protected readonly _toEntryFn?: (rawElement: R) => [K, V];
201
201
 
202
202
  /**
203
203
  * Get the raw→entry converter function if present.
@@ -530,7 +530,7 @@ export class LinkedHashMap<K = any, V = any, R = [K, V]> extends IterableEntryBa
530
530
  return this._tail;
531
531
  }
532
532
 
533
- protected _toEntryFn?: (rawElement: R) => [K, V] = (rawElement: R) => {
533
+ protected readonly _toEntryFn?: (rawElement: R) => [K, V] = (rawElement: R) => {
534
534
  if (this.isEntry(rawElement)) {
535
535
  return rawElement;
536
536
  }
@@ -538,6 +538,7 @@ export class LinkedHashMap<K = any, V = any, R = [K, V]> extends IterableEntryBa
538
538
  'If `entryOrRawElements` does not adhere to [key,value], provide `options.toEntryFn` to transform raw records.'
539
539
  );
540
540
  };
541
+
541
542
  get toEntryFn() {
542
543
  return this._toEntryFn;
543
544
  }
@@ -712,8 +713,9 @@ export class LinkedHashMap<K = any, V = any, R = [K, V]> extends IterableEntryBa
712
713
  const cur = node;
713
714
  node = node.next;
714
715
  if (predicate(cur.key as K, cur.value as V | undefined, i++, this)) {
715
- if (isWeakKey(cur.key as unknown as object)) {
716
- this._objMap.delete(cur.key as unknown as object);
716
+ const keyToCheck: unknown = cur.key;
717
+ if (isWeakKey(keyToCheck)) {
718
+ this._objMap.delete(keyToCheck);
717
719
  } else {
718
720
  const hash = this._hashFn(cur.key as K);
719
721
  delete this._noObjMap[hash];