data-structure-typed 1.53.6 → 1.53.7

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 (118) hide show
  1. package/CHANGELOG.md +1 -1
  2. package/README.md +16 -25
  3. package/benchmark/report.html +32 -5
  4. package/benchmark/report.json +326 -23
  5. package/dist/cjs/common/index.d.ts +12 -0
  6. package/dist/cjs/common/index.js +24 -0
  7. package/dist/cjs/common/index.js.map +1 -0
  8. package/dist/cjs/data-structures/binary-tree/avl-tree-multi-map.js +7 -10
  9. package/dist/cjs/data-structures/binary-tree/avl-tree-multi-map.js.map +1 -1
  10. package/dist/cjs/data-structures/binary-tree/avl-tree.js +2 -2
  11. package/dist/cjs/data-structures/binary-tree/avl-tree.js.map +1 -1
  12. package/dist/cjs/data-structures/binary-tree/binary-tree.d.ts +54 -19
  13. package/dist/cjs/data-structures/binary-tree/binary-tree.js +100 -66
  14. package/dist/cjs/data-structures/binary-tree/binary-tree.js.map +1 -1
  15. package/dist/cjs/data-structures/binary-tree/bst.d.ts +100 -36
  16. package/dist/cjs/data-structures/binary-tree/bst.js +185 -66
  17. package/dist/cjs/data-structures/binary-tree/bst.js.map +1 -1
  18. package/dist/cjs/data-structures/binary-tree/rb-tree.d.ts +4 -0
  19. package/dist/cjs/data-structures/binary-tree/rb-tree.js +6 -2
  20. package/dist/cjs/data-structures/binary-tree/rb-tree.js.map +1 -1
  21. package/dist/cjs/data-structures/binary-tree/tree-multi-map.js +2 -2
  22. package/dist/cjs/data-structures/binary-tree/tree-multi-map.js.map +1 -1
  23. package/dist/cjs/data-structures/heap/heap.d.ts +6 -6
  24. package/dist/cjs/data-structures/heap/heap.js +6 -6
  25. package/dist/cjs/data-structures/linked-list/doubly-linked-list.d.ts +18 -8
  26. package/dist/cjs/data-structures/linked-list/doubly-linked-list.js +24 -10
  27. package/dist/cjs/data-structures/linked-list/doubly-linked-list.js.map +1 -1
  28. package/dist/cjs/data-structures/linked-list/singly-linked-list.d.ts +1 -1
  29. package/dist/cjs/data-structures/linked-list/singly-linked-list.js +1 -1
  30. package/dist/cjs/data-structures/linked-list/singly-linked-list.js.map +1 -1
  31. package/dist/cjs/data-structures/trie/trie.d.ts +110 -4
  32. package/dist/cjs/data-structures/trie/trie.js +122 -12
  33. package/dist/cjs/data-structures/trie/trie.js.map +1 -1
  34. package/dist/cjs/index.d.ts +1 -1
  35. package/dist/cjs/index.js +1 -1
  36. package/dist/cjs/index.js.map +1 -1
  37. package/dist/cjs/types/data-structures/binary-tree/binary-tree.d.ts +1 -1
  38. package/dist/cjs/types/data-structures/binary-tree/bst.d.ts +3 -2
  39. package/dist/cjs/types/data-structures/binary-tree/rb-tree.d.ts +1 -1
  40. package/dist/cjs/types/utils/utils.d.ts +10 -6
  41. package/dist/cjs/utils/utils.js +4 -2
  42. package/dist/cjs/utils/utils.js.map +1 -1
  43. package/dist/mjs/common/index.d.ts +12 -0
  44. package/dist/mjs/common/index.js +24 -0
  45. package/dist/mjs/common/index.js.map +1 -0
  46. package/dist/mjs/data-structures/binary-tree/avl-tree-multi-map.js +8 -10
  47. package/dist/mjs/data-structures/binary-tree/avl-tree-multi-map.js.map +1 -1
  48. package/dist/mjs/data-structures/binary-tree/avl-tree.js +3 -2
  49. package/dist/mjs/data-structures/binary-tree/avl-tree.js.map +1 -1
  50. package/dist/mjs/data-structures/binary-tree/binary-tree.d.ts +54 -19
  51. package/dist/mjs/data-structures/binary-tree/binary-tree.js +95 -61
  52. package/dist/mjs/data-structures/binary-tree/binary-tree.js.map +1 -1
  53. package/dist/mjs/data-structures/binary-tree/bst.d.ts +100 -36
  54. package/dist/mjs/data-structures/binary-tree/bst.js +187 -66
  55. package/dist/mjs/data-structures/binary-tree/bst.js.map +1 -1
  56. package/dist/mjs/data-structures/binary-tree/rb-tree.d.ts +4 -0
  57. package/dist/mjs/data-structures/binary-tree/rb-tree.js +6 -2
  58. package/dist/mjs/data-structures/binary-tree/rb-tree.js.map +1 -1
  59. package/dist/mjs/data-structures/binary-tree/tree-multi-map.js +2 -2
  60. package/dist/mjs/data-structures/binary-tree/tree-multi-map.js.map +1 -1
  61. package/dist/mjs/data-structures/heap/heap.d.ts +6 -6
  62. package/dist/mjs/data-structures/heap/heap.js +6 -6
  63. package/dist/mjs/data-structures/linked-list/doubly-linked-list.d.ts +18 -8
  64. package/dist/mjs/data-structures/linked-list/doubly-linked-list.js +24 -10
  65. package/dist/mjs/data-structures/linked-list/doubly-linked-list.js.map +1 -1
  66. package/dist/mjs/data-structures/linked-list/singly-linked-list.d.ts +1 -1
  67. package/dist/mjs/data-structures/linked-list/singly-linked-list.js +1 -1
  68. package/dist/mjs/data-structures/linked-list/singly-linked-list.js.map +1 -1
  69. package/dist/mjs/data-structures/trie/trie.d.ts +110 -4
  70. package/dist/mjs/data-structures/trie/trie.js +122 -12
  71. package/dist/mjs/data-structures/trie/trie.js.map +1 -1
  72. package/dist/mjs/index.d.ts +1 -1
  73. package/dist/mjs/index.js +1 -1
  74. package/dist/mjs/index.js.map +1 -1
  75. package/dist/mjs/types/data-structures/binary-tree/binary-tree.d.ts +1 -1
  76. package/dist/mjs/types/data-structures/binary-tree/bst.d.ts +3 -2
  77. package/dist/mjs/types/data-structures/binary-tree/rb-tree.d.ts +1 -1
  78. package/dist/mjs/types/utils/utils.d.ts +10 -6
  79. package/dist/mjs/utils/utils.js +4 -2
  80. package/dist/mjs/utils/utils.js.map +1 -1
  81. package/dist/umd/data-structure-typed.js +299 -156
  82. package/dist/umd/data-structure-typed.min.js +3 -3
  83. package/dist/umd/data-structure-typed.min.js.map +1 -1
  84. package/package.json +7 -7
  85. package/src/common/index.ts +19 -0
  86. package/src/data-structures/binary-tree/avl-tree-multi-map.ts +7 -9
  87. package/src/data-structures/binary-tree/avl-tree.ts +3 -2
  88. package/src/data-structures/binary-tree/binary-tree.ts +108 -64
  89. package/src/data-structures/binary-tree/bst.ts +190 -69
  90. package/src/data-structures/binary-tree/rb-tree.ts +6 -2
  91. package/src/data-structures/binary-tree/tree-multi-map.ts +3 -3
  92. package/src/data-structures/heap/heap.ts +39 -39
  93. package/src/data-structures/linked-list/doubly-linked-list.ts +111 -97
  94. package/src/data-structures/linked-list/singly-linked-list.ts +1 -1
  95. package/src/data-structures/trie/trie.ts +116 -11
  96. package/src/index.ts +1 -1
  97. package/src/types/data-structures/binary-tree/binary-tree.ts +1 -1
  98. package/src/types/data-structures/binary-tree/bst.ts +3 -2
  99. package/src/types/data-structures/binary-tree/rb-tree.ts +1 -1
  100. package/src/types/utils/utils.ts +16 -10
  101. package/src/utils/utils.ts +4 -2
  102. package/test/performance/data-structures/binary-tree/avl-tree.test.ts +3 -0
  103. package/test/performance/data-structures/binary-tree/rb-tree.test.ts +4 -1
  104. package/test/performance/reportor.ts +38 -33
  105. package/test/unit/data-structures/binary-tree/avl-tree-multi-map.test.ts +2 -2
  106. package/test/unit/data-structures/binary-tree/binary-tree.test.ts +12 -12
  107. package/test/unit/data-structures/binary-tree/bst.test.ts +79 -3
  108. package/test/unit/data-structures/binary-tree/overall.test.ts +14 -22
  109. package/test/unit/data-structures/binary-tree/rb-tree.test.ts +100 -1
  110. package/test/unit/data-structures/trie/trie.test.ts +151 -0
  111. package/test/unit/utils/utils.test.ts +6 -6
  112. package/dist/cjs/constants/index.d.ts +0 -4
  113. package/dist/cjs/constants/index.js +0 -9
  114. package/dist/cjs/constants/index.js.map +0 -1
  115. package/dist/mjs/constants/index.d.ts +0 -4
  116. package/dist/mjs/constants/index.js +0 -6
  117. package/dist/mjs/constants/index.js.map +0 -1
  118. package/src/constants/index.ts +0 -4
@@ -92,13 +92,100 @@ export class TrieNode {
92
92
  * 9. Spell Check: Checking the spelling of words.
93
93
  * 10. IP Routing: Used in certain types of IP routing algorithms.
94
94
  * 11. Text Word Frequency Count: Counting and storing the frequency of words in a large amount of text data.
95
+ * @example
96
+ * // Autocomplete: Prefix validation and checking
97
+ * const autocomplete = new Trie<string>(['gmail.com', 'gmail.co.nz', 'gmail.co.jp', 'yahoo.com', 'outlook.com']);
98
+ *
99
+ * // Get all completions for a prefix
100
+ * const gmailCompletions = autocomplete.getWords('gmail');
101
+ * console.log(gmailCompletions); // ['gmail.com', 'gmail.co.nz', 'gmail.co.jp']
102
+ * @example
103
+ * // File System Path Operations
104
+ * const fileSystem = new Trie<string>([
105
+ * '/home/user/documents/file1.txt',
106
+ * '/home/user/documents/file2.txt',
107
+ * '/home/user/pictures/photo.jpg',
108
+ * '/home/user/pictures/vacation/',
109
+ * '/home/user/downloads'
110
+ * ]);
111
+ *
112
+ * // Find common directory prefix
113
+ * console.log(fileSystem.getLongestCommonPrefix()); // '/home/user/'
114
+ *
115
+ * // List all files in a directory
116
+ * const documentsFiles = fileSystem.getWords('/home/user/documents/');
117
+ * console.log(documentsFiles); // ['/home/user/documents/file1.txt', '/home/user/documents/file2.txt']
118
+ * @example
119
+ * // Autocomplete: Basic word suggestions
120
+ * // Create a trie for autocomplete
121
+ * const autocomplete = new Trie<string>([
122
+ * 'function',
123
+ * 'functional',
124
+ * 'functions',
125
+ * 'class',
126
+ * 'classes',
127
+ * 'classical',
128
+ * 'closure',
129
+ * 'const',
130
+ * 'constructor'
131
+ * ]);
132
+ *
133
+ * // Test autocomplete with different prefixes
134
+ * console.log(autocomplete.getWords('fun')); // ['functional', 'functions', 'function']
135
+ * console.log(autocomplete.getWords('cla')); // ['classes', 'classical', 'class']
136
+ * console.log(autocomplete.getWords('con')); // ['constructor', 'const']
137
+ *
138
+ * // Test with non-matching prefix
139
+ * console.log(autocomplete.getWords('xyz')); // []
140
+ * @example
141
+ * // Dictionary: Case-insensitive word lookup
142
+ * // Create a case-insensitive dictionary
143
+ * const dictionary = new Trie<string>([], { caseSensitive: false });
144
+ *
145
+ * // Add words with mixed casing
146
+ * dictionary.add('Hello');
147
+ * dictionary.add('WORLD');
148
+ * dictionary.add('JavaScript');
149
+ *
150
+ * // Test lookups with different casings
151
+ * console.log(dictionary.has('hello')); // true
152
+ * console.log(dictionary.has('HELLO')); // true
153
+ * console.log(dictionary.has('Hello')); // true
154
+ * console.log(dictionary.has('javascript')); // true
155
+ * console.log(dictionary.has('JAVASCRIPT')); // true
156
+ * @example
157
+ * // IP Address Routing Table
158
+ * // Add IP address prefixes and their corresponding routes
159
+ * const routes = {
160
+ * '192.168.1': 'LAN_SUBNET_1',
161
+ * '192.168.2': 'LAN_SUBNET_2',
162
+ * '10.0.0': 'PRIVATE_NETWORK_1',
163
+ * '10.0.1': 'PRIVATE_NETWORK_2'
164
+ * };
165
+ *
166
+ * const ipRoutingTable = new Trie<string>(Object.keys(routes));
167
+ *
168
+ * // Check IP address prefix matching
169
+ * console.log(ipRoutingTable.hasPrefix('192.168.1')); // true
170
+ * console.log(ipRoutingTable.hasPrefix('192.168.2')); // true
171
+ *
172
+ * // Validate IP address belongs to subnet
173
+ * const ip = '192.168.1.100';
174
+ * const subnet = ip.split('.').slice(0, 3).join('.');
175
+ * console.log(ipRoutingTable.hasPrefix(subnet)); // true
95
176
  */
96
177
  export class Trie<R = any> extends IterableElementBase<string, R, Trie<R>> {
97
178
  /**
98
- * The constructor function for the Trie class.
99
- * @param words: Iterable string Initialize the trie with a set of words
100
- * @param options?: TrieOptions Allow the user to pass in options for the trie
101
- * @return This
179
+ * The constructor initializes a Trie data structure with optional options and words provided as
180
+ * input.
181
+ * @param {Iterable<string> | Iterable<R>} words - The `words` parameter in the constructor is an
182
+ * iterable containing either strings or elements of type `R`. It is used to initialize the Trie with
183
+ * a list of words or elements. If no `words` are provided, an empty iterable is used as the default
184
+ * value.
185
+ * @param [options] - The `options` parameter in the constructor is an optional object that can
186
+ * contain configuration options for the Trie data structure. One of the options it can have is
187
+ * `caseSensitive`, which is a boolean value indicating whether the Trie should be case-sensitive or
188
+ * not. If `caseSensitive` is set to `
102
189
  */
103
190
  constructor(words: Iterable<string> | Iterable<R> = [], options?: TrieOptions<R>) {
104
191
  super(options);
@@ -107,13 +194,7 @@ export class Trie<R = any> extends IterableElementBase<string, R, Trie<R>> {
107
194
  if (caseSensitive !== undefined) this._caseSensitive = caseSensitive;
108
195
  }
109
196
  if (words) {
110
- for (const word of words) {
111
- if (this.toElementFn) {
112
- this.add(this.toElementFn(word as R));
113
- } else {
114
- this.add(word as string);
115
- }
116
- }
197
+ this.addMany(words);
117
198
  }
118
199
  }
119
200
 
@@ -175,6 +256,30 @@ export class Trie<R = any> extends IterableElementBase<string, R, Trie<R>> {
175
256
  return isNewWord;
176
257
  }
177
258
 
259
+ /**
260
+ * Time Complexity: O(n * l)
261
+ * Space Complexity: O(1)
262
+ *
263
+ * The `addMany` function in TypeScript takes an iterable of strings or elements of type R, converts
264
+ * them using a provided function if available, and adds them to a data structure while returning an
265
+ * array of boolean values indicating success.
266
+ * @param {Iterable<string> | Iterable<R>} words - The `words` parameter in the `addMany` function is
267
+ * an iterable that contains either strings or elements of type `R`.
268
+ * @returns The `addMany` method returns an array of boolean values indicating whether each word in
269
+ * the input iterable was successfully added to the data structure.
270
+ */
271
+ addMany(words: Iterable<string> | Iterable<R> = []): boolean[] {
272
+ const ans: boolean[] = [];
273
+ for (const word of words) {
274
+ if (this.toElementFn) {
275
+ ans.push(this.add(this.toElementFn(word as R)));
276
+ } else {
277
+ ans.push(this.add(word as string));
278
+ }
279
+ }
280
+ return ans;
281
+ }
282
+
178
283
  /**
179
284
  * Time Complexity: O(l), where l is the length of the input word.
180
285
  * Space Complexity: O(1) - Constant space.
package/src/index.ts CHANGED
@@ -2,4 +2,4 @@ export * from './data-structures';
2
2
  export * from './utils';
3
3
  export * from './interfaces';
4
4
  export * from './types';
5
- export * from './constants';
5
+ export * from './common';
@@ -1,6 +1,6 @@
1
1
  import { BinaryTree, BinaryTreeNode } from '../../../data-structures';
2
2
  import { IterationType, OptValue } from '../../common';
3
- import { DFSOperation } from '../../../constants';
3
+ import { DFSOperation } from '../../../common';
4
4
 
5
5
  export type BinaryTreeNodeNested<K, V> = BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, BinaryTreeNode<K, V, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
6
6
 
@@ -1,13 +1,14 @@
1
1
  import { BST, BSTNode } from '../../../data-structures';
2
2
  import type { BinaryTreeOptions } from './binary-tree';
3
- import { Comparator } from '../../common';
3
+ import { Comparable } from '../../utils';
4
4
 
5
5
  export type BSTNodeNested<K, V> = BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
6
6
 
7
7
  export type BSTNested<K, V, R, NODE extends BSTNode<K, V, NODE>> = BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
8
8
 
9
9
  export type BSTOptions<K, V, R> = BinaryTreeOptions<K, V, R> & {
10
- comparator?: Comparator<K>
10
+ extractComparable?: (key: K) => Comparable
11
+ isReverse?: boolean;
11
12
  }
12
13
 
13
14
  export type BSTNOptKey<K> = K | undefined;
@@ -7,4 +7,4 @@ export type RedBlackTreeNodeNested<K, V> = RedBlackTreeNode<K, V, RedBlackTreeNo
7
7
 
8
8
  export type RedBlackTreeNested<K, V, R, NODE extends RedBlackTreeNode<K, V, NODE>> = RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, RedBlackTree<K, V, R, NODE, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
9
9
 
10
- export type RBTreeOptions<K, V, R> = BSTOptions<K, V, R> & {};
10
+ export type RBTreeOptions<K, V, R> = Omit<BSTOptions<K, V, R>, 'isReverse'> & {};
@@ -7,17 +7,23 @@ export type SpecifyOptional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T,
7
7
 
8
8
  export type Any = string | number | bigint | boolean | symbol | undefined | object;
9
9
 
10
+ export type Arithmetic = number | bigint;
11
+
10
12
  export type ComparablePrimitive = number | bigint | string | boolean;
11
13
 
12
- // TODO type safety looks not strict
13
- export type ComparableObject = { [key in string]: any } & (
14
- | {
15
- valueOf: () => ComparablePrimitive | ComparableObject;
16
- toString?: () => string;
17
- }
18
- | {
19
- toString: () => string;
20
- }
21
- );
14
+ export interface BaseComparableObject {
15
+ [key: string]: unknown;
16
+ }
17
+
18
+ export interface ValueComparableObject extends BaseComparableObject {
19
+ valueOf: () => ComparablePrimitive | ValueComparableObject;
20
+ toString?: () => string;
21
+ }
22
+
23
+ export interface StringComparableObject extends BaseComparableObject {
24
+ toString: () => string;
25
+ }
26
+
27
+ export type ComparableObject = ValueComparableObject | StringComparableObject;
22
28
 
23
29
  export type Comparable = ComparablePrimitive | Date | ComparableObject;
@@ -226,7 +226,8 @@ export const roundFixed = (num: number, digit: number = 10) => {
226
226
  */
227
227
  function isPrimitiveComparable(value: unknown): value is ComparablePrimitive {
228
228
  const valueType = typeof value;
229
- if (valueType === 'number') return !Number.isNaN(value);
229
+ if (valueType === 'number') return true;
230
+ // if (valueType === 'number') return !Number.isNaN(value);
230
231
  return valueType === 'bigint' || valueType === 'string' || valueType === 'boolean';
231
232
  }
232
233
 
@@ -274,7 +275,8 @@ export function isComparable(value: unknown, isForceObjectComparable = false): v
274
275
  if (isPrimitiveComparable(value)) return true;
275
276
 
276
277
  if (typeof value !== 'object') return false;
277
- if (value instanceof Date) return !Number.isNaN(value.getTime());
278
+ if (value instanceof Date) return true;
279
+ // if (value instanceof Date) return !Number.isNaN(value.getTime());
278
280
  if (isForceObjectComparable) return true;
279
281
  const comparableValue = tryObjectToPrimitive(value);
280
282
  if (comparableValue === null || comparableValue === undefined) return false;
@@ -19,6 +19,9 @@ suite
19
19
  .add(`${HUNDRED_THOUSAND.toLocaleString()} get`, () => {
20
20
  for (let i = 0; i < randomArray.length; i++) avlTree.get(randomArray[i]);
21
21
  })
22
+ .add(`${HUNDRED_THOUSAND.toLocaleString()} getNode`, () => {
23
+ for (let i = 0; i < randomArray.length; i++) avlTree.getNode(randomArray[i]);
24
+ })
22
25
  .add(`${HUNDRED_THOUSAND.toLocaleString()} iterator`, () => {
23
26
  const entries = [...avlTree];
24
27
  return entries.length === HUNDRED_THOUSAND;
@@ -23,9 +23,12 @@ suite
23
23
  .add(`${HUNDRED_THOUSAND.toLocaleString()} get`, () => {
24
24
  for (let i = 0; i < randomArray.length; i++) rbTree.get(randomArray[i]);
25
25
  })
26
+ .add(`${HUNDRED_THOUSAND.toLocaleString()} getNode`, () => {
27
+ for (let i = 0; i < randomArray.length; i++) rbTree.getNode(randomArray[i]);
28
+ })
26
29
  .add(`${HUNDRED_THOUSAND.toLocaleString()} node mode add randomly`, () => {
27
30
  rbTreeNodeMode.clear();
28
- for (let i = 0; i < randomArray.length; i++) rbTree.add(randomArray[i]);
31
+ for (let i = 0; i < randomArray.length; i++) rbTreeNodeMode.add(randomArray[i]);
29
32
  })
30
33
  .add(`${HUNDRED_THOUSAND.toLocaleString()} node mode get`, () => {
31
34
  for (let i = 0; i < randomArray.length; i++) rbTreeNodeMode.get(randomArray[i]);
@@ -8,6 +8,22 @@ import { PerformanceTest } from './types';
8
8
  const args = process.argv.slice(2);
9
9
 
10
10
  const { GREEN, BOLD, END, YELLOW, GRAY, CYAN, BG_YELLOW } = ConsoleColor;
11
+ const isOnlyOrdered = true;
12
+ const runOrder = [
13
+ 'heap',
14
+ 'avl-tree',
15
+ 'rb-tree',
16
+ 'doubly-linked-list',
17
+ 'directed-graph',
18
+ 'queue',
19
+ 'deque',
20
+ 'hash-map',
21
+ 'trie',
22
+ 'stack'
23
+ // 'singly-linked-list',
24
+ // 'priority-queue',
25
+ // 'binary-tree-overall'
26
+ ];
11
27
 
12
28
  const getRelativePath = (file: string) => {
13
29
  return path.relative(__dirname, file);
@@ -80,7 +96,7 @@ const composeReport = () => {
80
96
  #json-to-html {
81
97
  padding: 0 10px 20px;
82
98
  }
83
-
99
+
84
100
  .json-to-html-label {
85
101
  font-size: 2rem;
86
102
  margin: 2rem 0 0 3px;
@@ -92,19 +108,19 @@ const composeReport = () => {
92
108
  margin-top: 10px;
93
109
  font-size: 16px;
94
110
  }
95
-
111
+
96
112
  .content table th,
97
113
  .content table td {
98
114
  padding: 8px 12px;
99
115
  text-align: left;
100
116
  border: 1px solid #ddd;
101
117
  }
102
-
118
+
103
119
  .content table th {
104
120
  background-color: #f2f2f2;
105
121
  font-weight: bold;
106
122
  }
107
-
123
+
108
124
  .content table tr:nth-child(odd) {
109
125
  background-color: #ffffff;
110
126
  }
@@ -188,46 +204,35 @@ function replaceMarkdownContent(startMarker: string, endMarker: string, newText:
188
204
  });
189
205
  }
190
206
 
191
- const order = [
192
- 'heap',
193
- 'rb-tree',
194
- 'queue',
195
- 'deque',
196
- 'hash-map',
197
- 'trie',
198
- 'avl-tree',
199
- 'binary-tree-overall',
200
- 'directed-graph',
201
- 'doubly-linked-list',
202
- 'singly-linked-list',
203
- 'priority-queue',
204
- 'stack'
205
- ];
206
-
207
- const sortedPerformanceTests = [...performanceTests].sort((a, b) => {
208
- const indexA = order.indexOf(a.testName);
209
- const indexB = order.indexOf(b.testName);
207
+ const sortedPerformanceTests = (
208
+ isOnlyOrdered ? [...performanceTests].filter(test => runOrder.includes(test.testName)) : [...performanceTests]
209
+ ).sort((a, b) => {
210
+ const indexA = runOrder.indexOf(a.testName);
211
+ const indexB = runOrder.indexOf(b.testName);
210
212
 
211
- // If both a and b are in the order, sort them according to their indices in the order.
213
+ // If both a and b are in the runOrder, sort them according to their indices in the runOrder.
212
214
  if (indexA !== -1 && indexB !== -1) {
213
215
  return indexA - indexB;
214
216
  }
215
217
 
216
- // If there is only 'a' in the order, then place 'b' in front.
218
+ // If there is only 'a' in the runOrder, then place 'b' in front.
217
219
  if (indexA !== -1) {
218
220
  return 1;
219
221
  }
220
222
 
221
- // If only b is in the order, then a should be placed before it.
223
+ // If only b is in the runOrder, then a should be placed before it.
222
224
  if (indexB !== -1) {
223
225
  return -1;
224
226
  }
225
227
 
226
- // If neither a nor b are in order, keep their original order
228
+ // If neither a nor b are in runOrder, keep their original runOrder
227
229
  return 0;
228
230
  });
229
231
 
230
- console.log(`${GREEN} Found tests${END}: ${sortedPerformanceTests.map(test => test.testName)}`);
232
+ console.log(`${GREEN} Found tests (${performanceTests.length})${END}: ${performanceTests.map(test => test.testName)}`);
233
+ console.log(
234
+ `${GREEN} Running tests (${sortedPerformanceTests.length})${END}: ${sortedPerformanceTests.map(test => test.testName)}`
235
+ );
231
236
 
232
237
  sortedPerformanceTests.forEach(item => {
233
238
  const { suite, testName, file } = item;
@@ -245,22 +250,22 @@ sortedPerformanceTests.forEach(item => {
245
250
  return {
246
251
  'test name': benchmark.name,
247
252
  'time taken (ms)': numberFix(benchmark.times.period * 1000, 2),
248
- 'executions per sec': numberFix(benchmark.hz, 2),
253
+ // 'executions per sec': numberFix(benchmark.hz, 2),
249
254
  // 'executed times': numberFix(benchmark.count, 0),
250
- // 'sample mean (secs)': numberFix(benchmark.stats.mean, 2),
255
+ 'sample mean (secs)': numberFix(benchmark.stats.mean, 2),
251
256
  'sample deviation': numberFix(benchmark.stats.deviation, 2)
252
257
  };
253
258
  });
254
259
 
255
260
  report[testName].testName = testName;
256
- const isDone = completedCount === performanceTests.length;
261
+ const isDone = completedCount === sortedPerformanceTests.length;
257
262
  runTime = Number(runTime.toFixed(2));
258
263
  const isTimeWarn = runTime > 120;
259
264
  console.log(
260
265
  // `Files: ${GREEN}${testFileCount}${END} `,
261
266
  // `Suites: ${GREEN}${performanceTests.length}${END} `,
262
- `Suites Progress: ${isDone ? GREEN : YELLOW}${completedCount}${END}/${isDone ? GREEN : YELLOW}${performanceTests.length}${END}`,
263
- `Time: ${isTimeWarn ? YELLOW : GREEN}${runTime}s${END}`
267
+ `Suites Progress: ${isDone ? GREEN : YELLOW}${completedCount}${END}/${isDone ? GREEN : YELLOW}${sortedPerformanceTests.length}${END}`,
268
+ `Time Costs: ${isTimeWarn ? YELLOW : GREEN}${runTime}s${END}`
264
269
  );
265
270
  if (isDone) {
266
271
  composeReport();
@@ -736,7 +736,7 @@ describe('AVLTree toEntryFn', () => {
736
736
  { obj: { id: 5 } }
737
737
  ])
738
738
  ).toThrowError(
739
- `When comparing object types, a custom comparator must be defined in the constructor's options parameter.`
739
+ `When comparing object types, a custom extractComparable must be defined in the constructor's options parameter.`
740
740
  );
741
741
  });
742
742
 
@@ -744,7 +744,7 @@ describe('AVLTree toEntryFn', () => {
744
744
  const tree = new AVLTreeMultiMap<{ obj: { id: number } }, number>(
745
745
  [{ obj: { id: 1 } }, { obj: { id: 2 } }, { obj: { id: 3 } }, { obj: { id: 4 } }, { obj: { id: 5 } }],
746
746
  {
747
- comparator: (a, b) => a.obj.id - b.obj.id
747
+ extractComparable: key => key.obj.id
748
748
  }
749
749
  );
750
750
 
@@ -103,9 +103,9 @@ describe('BinaryTree addMany', () => {
103
103
  [undefined, 22, 44, 33]
104
104
  );
105
105
  expect(tree.get(2)).toBe(22);
106
- expect(tree.get(tree.getNodeByKey(3))).toBe(33);
107
- expect(tree.get(tree.getNodeByKey(4))).toBe(44);
108
- expect(tree.get(tree.getNodeByKey(1))).toBe(1);
106
+ expect(tree.get(tree.getNode(3))).toBe(33);
107
+ expect(tree.get(tree.getNode(4))).toBe(44);
108
+ expect(tree.get(tree.getNode(1))).toBe(1);
109
109
  });
110
110
 
111
111
  it('should addMany undefined and null', () => {
@@ -349,7 +349,7 @@ describe('BinaryTree', () => {
349
349
  expect(tree.isBST(tree.getNode(4), 'ITERATIVE')).toBe(true);
350
350
  expect(tree.getNodes(2, false, null)).toEqual([]);
351
351
  expect(tree.getNodes(undefined)).toEqual([]);
352
- expect(tree.getNodes(tree.getNodeByKey(2), false, tree.root)).toEqual([tree.getNodeByKey(2)]);
352
+ expect(tree.getNodes(tree.getNode(2), false, tree.root)).toEqual([tree.getNode(2)]);
353
353
  });
354
354
 
355
355
  describe('should isKey', () => {
@@ -362,9 +362,9 @@ describe('BinaryTree', () => {
362
362
  expect(tree.isKey(-Infinity)).toBe(true);
363
363
  });
364
364
 
365
- it('NaN should not be a key', () => {
366
- expect(tree.isKey(NaN)).toBe(false);
367
- });
365
+ // it('NaN should not be a key', () => {
366
+ // expect(tree.isKey(NaN)).toBe(false);
367
+ // });
368
368
 
369
369
  it('strings should be a key', () => {
370
370
  expect(tree.isKey('hello')).toBe(true);
@@ -400,9 +400,9 @@ describe('BinaryTree', () => {
400
400
  expect(tree.isKey(new Date('2024-01-01'))).toBe(true);
401
401
  });
402
402
 
403
- it('invalid Date objects should not be a key', () => {
404
- expect(tree.isKey(new Date('invalid'))).toBe(false);
405
- });
403
+ // it('invalid Date objects should not be a key', () => {
404
+ // expect(tree.isKey(new Date('invalid'))).toBe(false);
405
+ // });
406
406
  });
407
407
 
408
408
  describe('arrays', () => {
@@ -1155,8 +1155,8 @@ describe('BinaryTree', () => {
1155
1155
  tree.add([3, 'B']);
1156
1156
  tree.add([7, 'C']);
1157
1157
 
1158
- expect(tree.getPathToRoot(undefined, 7)).toEqual([5, 7]);
1159
- expect(tree.getPathToRoot(undefined, 1)).toEqual([]);
1158
+ expect(tree.getPathToRoot(7)).toEqual([7, 5]);
1159
+ expect(tree.getPathToRoot(1)).toEqual([]);
1160
1160
  });
1161
1161
 
1162
1162
  it('should check if the tree is perfectly balanced', () => {
@@ -1,4 +1,4 @@
1
- import { BinaryTreeNode, BST, BSTNode } from '../../../../src';
1
+ import { BinaryTreeNode, BST, BSTNode, Range } from '../../../../src';
2
2
  import { isDebugTest, isTestStackOverflow, SYSTEM_MAX_CALL_STACK } from '../../../config';
3
3
 
4
4
  const isDebug = isDebugTest;
@@ -974,7 +974,7 @@ describe('BST operations test recursively', () => {
974
974
 
975
975
  if (isTestStackOverflow) {
976
976
  it('should getLeftMost', () => {
977
- const bst = new BST<number>([], { comparator: (a, b) => b - a });
977
+ const bst = new BST<number>([], { extractComparable: key => key });
978
978
  for (let i = 1; i <= SYSTEM_MAX_CALL_STACK; i++) bst.add(i);
979
979
 
980
980
  expect(() => {
@@ -1009,7 +1009,7 @@ describe('BST isBST', function () {
1009
1009
 
1010
1010
  it('isBST when variant is Max', () => {
1011
1011
  const bst = new BST<number, number>([1, 2, 3, 9, 8, 5, 6, 7, 4], {
1012
- comparator: (a, b) => b - a
1012
+ isReverse: true
1013
1013
  });
1014
1014
  bst.addMany([1, 2, 3, 9, 8, 5, 6, 7, 4]);
1015
1015
  expect(bst.isBST()).toBe(true);
@@ -1529,3 +1529,79 @@ describe('BST iterative methods not map mode test', () => {
1529
1529
  expect(balanced.leaves(node => balanced.get(node?.key))).toEqual(['a', 'f', 'd', 'i']);
1530
1530
  });
1531
1531
  });
1532
+
1533
+ describe('classic use', () => {
1534
+ // Test case for finding the kth smallest element
1535
+ it('@example Find kth smallest element', () => {
1536
+ // Create a BST with some elements
1537
+ const bst = new BST<number>([5, 3, 7, 1, 4, 6, 8]);
1538
+ const sortedKeys = bst.dfs(node => node.key, 'IN');
1539
+
1540
+ // Helper function to find kth smallest
1541
+ const findKthSmallest = (k: number): number | undefined => {
1542
+ return sortedKeys[k - 1];
1543
+ };
1544
+
1545
+ // Assertions
1546
+ expect(findKthSmallest(1)).toBe(1);
1547
+ expect(findKthSmallest(3)).toBe(4);
1548
+ expect(findKthSmallest(7)).toBe(8);
1549
+ });
1550
+
1551
+ // Test case for finding elements in a given range
1552
+ it('@example Find elements in a range', () => {
1553
+ const bst = new BST<number>([10, 5, 15, 3, 7, 12, 18]);
1554
+ expect(bst.search(new Range(5, 10))).toEqual([10, 5, 7]);
1555
+ expect(bst.search(new Range(4, 12))).toEqual([10, 12, 5, 7]);
1556
+ expect(bst.search(new Range(4, 12, true, false))).toEqual([10, 5, 7]);
1557
+ expect(bst.search(new Range(15, 20))).toEqual([15, 18]);
1558
+ expect(bst.search(new Range(15, 20, false))).toEqual([18]);
1559
+ });
1560
+
1561
+ // Test case for Huffman coding simulation
1562
+ it('Huffman coding frequency simulation', () => {
1563
+ // Create a BST to simulate Huffman tree
1564
+ const frequencyBST = new BST<string, number>([
1565
+ ['a', 5],
1566
+ ['b', 9],
1567
+ ['c', 12],
1568
+ ['d', 13],
1569
+ ['e', 16],
1570
+ ['f', 45]
1571
+ ]);
1572
+
1573
+ // Sort nodes by frequency
1574
+ const sortedFrequencies = frequencyBST.dfs(node => ({ char: node.key, freq: node.value }), 'IN');
1575
+
1576
+ // Build Huffman tree simulation
1577
+ expect(sortedFrequencies[0].char).toBe('a');
1578
+ expect(sortedFrequencies[5].char).toBe('f');
1579
+ });
1580
+
1581
+ // Test case for Lowest Common Ancestor (LCA)
1582
+ it('@example Find lowest common ancestor', () => {
1583
+ const bst = new BST<number>([20, 10, 30, 5, 15, 25, 35, 3, 7, 12, 18]);
1584
+
1585
+ function findFirstCommon(arr1: number[], arr2: number[]): number | undefined {
1586
+ for (const num of arr1) {
1587
+ if (arr2.indexOf(num) !== -1) {
1588
+ return num;
1589
+ }
1590
+ }
1591
+ return undefined;
1592
+ }
1593
+
1594
+ // LCA helper function
1595
+ const findLCA = (num1: number, num2: number): number | undefined => {
1596
+ const path1 = bst.getPathToRoot(num1);
1597
+ const path2 = bst.getPathToRoot(num2);
1598
+ // Find the first common ancestor
1599
+ return findFirstCommon(path1, path2);
1600
+ };
1601
+
1602
+ // Assertions
1603
+ expect(findLCA(3, 10)).toBe(7);
1604
+ expect(findLCA(5, 35)).toBe(15);
1605
+ expect(findLCA(20, 30)).toBe(25);
1606
+ });
1607
+ });