data-structure-typed 2.4.3 → 2.4.5

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 (62) hide show
  1. package/.github/workflows/release.yml +27 -0
  2. package/CHANGELOG.md +24 -1
  3. package/README.md +70 -51
  4. package/dist/cjs/index.cjs +486 -167
  5. package/dist/cjs-legacy/index.cjs +487 -165
  6. package/dist/esm/index.mjs +486 -168
  7. package/dist/esm-legacy/index.mjs +487 -166
  8. package/dist/types/common/error.d.ts +23 -0
  9. package/dist/types/common/index.d.ts +1 -0
  10. package/dist/types/data-structures/base/iterable-element-base.d.ts +1 -1
  11. package/dist/types/data-structures/binary-tree/binary-tree.d.ts +15 -5
  12. package/dist/types/data-structures/binary-tree/bst.d.ts +1 -1
  13. package/dist/types/data-structures/binary-tree/red-black-tree.d.ts +7 -1
  14. package/dist/types/data-structures/graph/abstract-graph.d.ts +44 -0
  15. package/dist/types/data-structures/graph/directed-graph.d.ts +3 -2
  16. package/dist/types/data-structures/graph/undirected-graph.d.ts +16 -2
  17. package/dist/types/data-structures/hash/hash-map.d.ts +2 -2
  18. package/dist/types/data-structures/heap/heap.d.ts +3 -7
  19. package/dist/types/data-structures/queue/deque.d.ts +41 -1
  20. package/dist/types/types/data-structures/binary-tree/avl-tree.d.ts +1 -1
  21. package/dist/types/types/data-structures/binary-tree/red-black-tree.d.ts +1 -1
  22. package/dist/types/types/data-structures/linked-list/doubly-linked-list.d.ts +1 -1
  23. package/dist/types/types/data-structures/linked-list/singly-linked-list.d.ts +1 -1
  24. package/dist/types/types/data-structures/priority-queue/priority-queue.d.ts +1 -1
  25. package/dist/types/types/data-structures/queue/deque.d.ts +6 -0
  26. package/dist/types/types/data-structures/stack/stack.d.ts +1 -1
  27. package/dist/umd/data-structure-typed.js +486 -164
  28. package/dist/umd/data-structure-typed.min.js +6 -4
  29. package/package.json +2 -2
  30. package/src/common/error.ts +60 -0
  31. package/src/common/index.ts +2 -0
  32. package/src/data-structures/base/iterable-element-base.ts +5 -4
  33. package/src/data-structures/binary-tree/binary-indexed-tree.ts +6 -5
  34. package/src/data-structures/binary-tree/binary-tree.ts +121 -49
  35. package/src/data-structures/binary-tree/bst.ts +12 -4
  36. package/src/data-structures/binary-tree/red-black-tree.ts +20 -0
  37. package/src/data-structures/binary-tree/tree-map.ts +8 -7
  38. package/src/data-structures/binary-tree/tree-multi-map.ts +4 -4
  39. package/src/data-structures/binary-tree/tree-multi-set.ts +10 -9
  40. package/src/data-structures/binary-tree/tree-set.ts +7 -6
  41. package/src/data-structures/graph/abstract-graph.ts +124 -19
  42. package/src/data-structures/graph/directed-graph.ts +8 -4
  43. package/src/data-structures/graph/map-graph.ts +1 -1
  44. package/src/data-structures/graph/undirected-graph.ts +99 -4
  45. package/src/data-structures/hash/hash-map.ts +19 -6
  46. package/src/data-structures/heap/heap.ts +21 -17
  47. package/src/data-structures/heap/max-heap.ts +2 -3
  48. package/src/data-structures/linked-list/doubly-linked-list.ts +4 -4
  49. package/src/data-structures/linked-list/singly-linked-list.ts +15 -9
  50. package/src/data-structures/matrix/matrix.ts +9 -10
  51. package/src/data-structures/priority-queue/max-priority-queue.ts +2 -3
  52. package/src/data-structures/queue/deque.ts +72 -4
  53. package/src/data-structures/stack/stack.ts +1 -1
  54. package/src/data-structures/trie/trie.ts +12 -6
  55. package/src/types/data-structures/binary-tree/avl-tree.ts +1 -1
  56. package/src/types/data-structures/binary-tree/red-black-tree.ts +1 -1
  57. package/src/types/data-structures/linked-list/doubly-linked-list.ts +1 -1
  58. package/src/types/data-structures/linked-list/singly-linked-list.ts +1 -1
  59. package/src/types/data-structures/priority-queue/priority-queue.ts +1 -1
  60. package/src/types/data-structures/queue/deque.ts +7 -0
  61. package/src/types/data-structures/stack/stack.ts +1 -1
  62. package/src/utils/utils.ts +4 -2
@@ -48,6 +48,7 @@ var dataStructureTyped = (() => {
48
48
  DirectedVertex: () => DirectedVertex,
49
49
  DoublyLinkedList: () => DoublyLinkedList,
50
50
  DoublyLinkedListNode: () => DoublyLinkedListNode,
51
+ ERR: () => ERR,
51
52
  FibonacciHeap: () => FibonacciHeap,
52
53
  FibonacciHeapNode: () => FibonacciHeapNode,
53
54
  HashMap: () => HashMap,
@@ -285,6 +286,52 @@ var dataStructureTyped = (() => {
285
286
  }
286
287
  };
287
288
 
289
+ // src/common/error.ts
290
+ var ERR = {
291
+ // Range / index
292
+ indexOutOfRange: (index, min, max, ctx) => `${ctx ? ctx + ": " : ""}Index ${index} is out of range [${min}, ${max}].`,
293
+ invalidIndex: (ctx) => `${ctx ? ctx + ": " : ""}Index must be an integer.`,
294
+ // Type / argument
295
+ invalidArgument: (reason, ctx) => `${ctx ? ctx + ": " : ""}${reason}`,
296
+ comparatorRequired: (ctx) => `${ctx ? ctx + ": " : ""}Comparator is required for non-number/non-string/non-Date keys.`,
297
+ invalidKey: (reason, ctx) => `${ctx ? ctx + ": " : ""}${reason}`,
298
+ notAFunction: (name, ctx) => `${ctx ? ctx + ": " : ""}${name} must be a function.`,
299
+ invalidEntry: (ctx) => `${ctx ? ctx + ": " : ""}Each entry must be a [key, value] tuple.`,
300
+ invalidNaN: (ctx) => `${ctx ? ctx + ": " : ""}NaN is not a valid key.`,
301
+ invalidDate: (ctx) => `${ctx ? ctx + ": " : ""}Invalid Date key.`,
302
+ reduceEmpty: (ctx) => `${ctx ? ctx + ": " : ""}Reduce of empty structure with no initial value.`,
303
+ callbackReturnType: (expected, got, ctx) => `${ctx ? ctx + ": " : ""}Callback must return ${expected}; got ${got}.`,
304
+ // State / operation
305
+ invalidOperation: (reason, ctx) => `${ctx ? ctx + ": " : ""}${reason}`,
306
+ // Matrix
307
+ matrixDimensionMismatch: (op) => `Matrix: Dimensions must be compatible for ${op}.`,
308
+ matrixSingular: () => "Matrix: Singular matrix, inverse does not exist.",
309
+ matrixNotSquare: () => "Matrix: Must be square for inversion.",
310
+ matrixNotRectangular: () => "Matrix: Must be rectangular for transposition.",
311
+ matrixRowMismatch: (expected, got) => `Matrix: Expected row length ${expected}, but got ${got}.`
312
+ };
313
+
314
+ // src/common/index.ts
315
+ var DFSOperation = /* @__PURE__ */ ((DFSOperation2) => {
316
+ DFSOperation2[DFSOperation2["VISIT"] = 0] = "VISIT";
317
+ DFSOperation2[DFSOperation2["PROCESS"] = 1] = "PROCESS";
318
+ return DFSOperation2;
319
+ })(DFSOperation || {});
320
+ var Range = class {
321
+ constructor(low, high, includeLow = true, includeHigh = true) {
322
+ this.low = low;
323
+ this.high = high;
324
+ this.includeLow = includeLow;
325
+ this.includeHigh = includeHigh;
326
+ }
327
+ // Determine whether a key is within the range
328
+ isInRange(key, comparator) {
329
+ const lowCheck = this.includeLow ? comparator(key, this.low) >= 0 : comparator(key, this.low) > 0;
330
+ const highCheck = this.includeHigh ? comparator(key, this.high) <= 0 : comparator(key, this.high) < 0;
331
+ return lowCheck && highCheck;
332
+ }
333
+ };
334
+
288
335
  // src/data-structures/base/iterable-element-base.ts
289
336
  var IterableElementBase = class {
290
337
  /**
@@ -307,7 +354,7 @@ var dataStructureTyped = (() => {
307
354
  if (options) {
308
355
  const { toElementFn } = options;
309
356
  if (typeof toElementFn === "function") this._toElementFn = toElementFn;
310
- else if (toElementFn) throw new TypeError("toElementFn must be a function type");
357
+ else if (toElementFn) throw new TypeError(ERR.notAFunction("toElementFn"));
311
358
  }
312
359
  }
313
360
  /**
@@ -463,7 +510,7 @@ var dataStructureTyped = (() => {
463
510
  acc = initialValue;
464
511
  } else {
465
512
  const first = iter.next();
466
- if (first.done) throw new TypeError("Reduce of empty structure with no initial value");
513
+ if (first.done) throw new TypeError(ERR.reduceEmpty());
467
514
  acc = first.value;
468
515
  index = 1;
469
516
  }
@@ -531,8 +578,10 @@ var dataStructureTyped = (() => {
531
578
  }
532
579
  return 1 << 31 - Math.clz32(value);
533
580
  };
534
- var rangeCheck = (index, min, max, message = "Index out of bounds.") => {
535
- if (index < min || index > max) throw new RangeError(message);
581
+ var rangeCheck = (index, min, max, message) => {
582
+ if (index < min || index > max) {
583
+ throw new RangeError(message != null ? message : `Index ${index} is out of range [${min}, ${max}].`);
584
+ }
536
585
  };
537
586
  var throwRangeError = (message = "The value is off-limits.") => {
538
587
  throw new RangeError(message);
@@ -894,8 +943,8 @@ var dataStructureTyped = (() => {
894
943
  if (this.isEntry(rawElement)) {
895
944
  return rawElement;
896
945
  }
897
- throw new Error(
898
- "If `entryOrRawElements` does not adhere to [key,value], provide `options.toEntryFn` to transform raw records."
946
+ throw new TypeError(
947
+ ERR.invalidArgument("If elements do not adhere to [key, value], provide options.toEntryFn to transform raw records.", "HashMap")
899
948
  );
900
949
  });
901
950
  __publicField(this, "_size", 0);
@@ -1105,8 +1154,9 @@ var dataStructureTyped = (() => {
1105
1154
  const cur = node;
1106
1155
  node = node.next;
1107
1156
  if (predicate(cur.key, cur.value, i++, this)) {
1108
- if (isWeakKey(cur.key)) {
1109
- this._objMap.delete(cur.key);
1157
+ const keyToCheck = cur.key;
1158
+ if (isWeakKey(keyToCheck)) {
1159
+ this._objMap.delete(keyToCheck);
1110
1160
  } else {
1111
1161
  const hash = this._hashFn(cur.key);
1112
1162
  delete this._noObjMap[hash];
@@ -1179,6 +1229,13 @@ var dataStructureTyped = (() => {
1179
1229
  }
1180
1230
  }
1181
1231
  _deleteNode(node) {
1232
+ const key = node.key;
1233
+ if (isWeakKey(key)) {
1234
+ this._objMap.delete(key);
1235
+ } else {
1236
+ const hash = this._hashFn(key);
1237
+ delete this._noObjMap[hash];
1238
+ }
1182
1239
  const { prev, next } = node;
1183
1240
  prev.next = next;
1184
1241
  next.prev = prev;
@@ -1614,7 +1671,7 @@ var dataStructureTyped = (() => {
1614
1671
  */
1615
1672
  constructor(elements = [], options) {
1616
1673
  super(options);
1617
- __publicField(this, "_equals", Object.is);
1674
+ __publicField(this, "_equals", (a, b) => Object.is(a, b));
1618
1675
  __publicField(this, "_head");
1619
1676
  __publicField(this, "_tail");
1620
1677
  __publicField(this, "_length", 0);
@@ -1702,6 +1759,7 @@ var dataStructureTyped = (() => {
1702
1759
  * @returns Removed element or undefined.
1703
1760
  */
1704
1761
  pop() {
1762
+ var _a;
1705
1763
  if (!this.head) return void 0;
1706
1764
  if (this.head === this.tail) {
1707
1765
  const value2 = this.head.value;
@@ -1711,8 +1769,8 @@ var dataStructureTyped = (() => {
1711
1769
  return value2;
1712
1770
  }
1713
1771
  let current = this.head;
1714
- while (current.next !== this.tail) current = current.next;
1715
- const value = this.tail.value;
1772
+ while (current.next && current.next !== this.tail) current = current.next;
1773
+ const value = (_a = this.tail) == null ? void 0 : _a.value;
1716
1774
  current.next = void 0;
1717
1775
  this._tail = current;
1718
1776
  this._length--;
@@ -1800,8 +1858,8 @@ var dataStructureTyped = (() => {
1800
1858
  at(index) {
1801
1859
  if (index < 0 || index >= this._length) return void 0;
1802
1860
  let current = this.head;
1803
- for (let i = 0; i < index; i++) current = current.next;
1804
- return current.value;
1861
+ for (let i = 0; i < index && current; i++) current = current.next;
1862
+ return current == null ? void 0 : current.value;
1805
1863
  }
1806
1864
  /**
1807
1865
  * Type guard: check whether the input is a SinglyLinkedListNode.
@@ -1821,7 +1879,7 @@ var dataStructureTyped = (() => {
1821
1879
  getNodeAt(index) {
1822
1880
  if (index < 0 || index >= this._length) return void 0;
1823
1881
  let current = this.head;
1824
- for (let i = 0; i < index; i++) current = current.next;
1882
+ for (let i = 0; i < index && current; i++) current = current.next;
1825
1883
  return current;
1826
1884
  }
1827
1885
  /**
@@ -2332,7 +2390,7 @@ var dataStructureTyped = (() => {
2332
2390
  */
2333
2391
  constructor(elements = [], options) {
2334
2392
  super(options);
2335
- __publicField(this, "_equals", Object.is);
2393
+ __publicField(this, "_equals", (a, b) => Object.is(a, b));
2336
2394
  __publicField(this, "_head");
2337
2395
  __publicField(this, "_tail");
2338
2396
  __publicField(this, "_length", 0);
@@ -2520,8 +2578,8 @@ var dataStructureTyped = (() => {
2520
2578
  at(index) {
2521
2579
  if (index < 0 || index >= this._length) return void 0;
2522
2580
  let current = this.head;
2523
- for (let i = 0; i < index; i++) current = current.next;
2524
- return current.value;
2581
+ for (let i = 0; i < index && current; i++) current = current.next;
2582
+ return current == null ? void 0 : current.value;
2525
2583
  }
2526
2584
  /**
2527
2585
  * Get the node reference at a given index.
@@ -2532,7 +2590,7 @@ var dataStructureTyped = (() => {
2532
2590
  getNodeAt(index) {
2533
2591
  if (index < 0 || index >= this._length) return void 0;
2534
2592
  let current = this.head;
2535
- for (let i = 0; i < index; i++) current = current.next;
2593
+ for (let i = 0; i < index && current; i++) current = current.next;
2536
2594
  return current;
2537
2595
  }
2538
2596
  /**
@@ -3038,7 +3096,7 @@ var dataStructureTyped = (() => {
3038
3096
  */
3039
3097
  constructor(elements = [], options) {
3040
3098
  super(options);
3041
- __publicField(this, "_equals", Object.is);
3099
+ __publicField(this, "_equals", (a, b) => Object.is(a, b));
3042
3100
  __publicField(this, "_elements", []);
3043
3101
  this.pushMany(elements);
3044
3102
  }
@@ -3658,17 +3716,16 @@ var dataStructureTyped = (() => {
3658
3716
 
3659
3717
  // src/data-structures/queue/deque.ts
3660
3718
  var Deque = class extends LinearBase {
3661
- /**
3662
- * Create a Deque and optionally bulk-insert elements.
3663
- * @remarks Time O(N), Space O(N)
3664
- * @param [elements] - Iterable (or iterable-like) of elements/records to insert.
3665
- * @param [options] - Options such as bucketSize, toElementFn, and maxLen.
3666
- * @returns New Deque instance.
3667
- */
3668
3719
  constructor(elements = [], options) {
3669
3720
  super(options);
3670
- __publicField(this, "_equals", Object.is);
3721
+ __publicField(this, "_equals", (a, b) => Object.is(a, b));
3671
3722
  __publicField(this, "_bucketSize", 1 << 12);
3723
+ __publicField(this, "_autoCompactRatio", 0.5);
3724
+ /**
3725
+ * Counter for shift/pop operations since last compaction check.
3726
+ * Only checks ratio every `_bucketSize` operations to minimize overhead.
3727
+ */
3728
+ __publicField(this, "_compactCounter", 0);
3672
3729
  __publicField(this, "_bucketFirst", 0);
3673
3730
  __publicField(this, "_firstInBucket", 0);
3674
3731
  __publicField(this, "_bucketLast", 0);
@@ -3677,8 +3734,9 @@ var dataStructureTyped = (() => {
3677
3734
  __publicField(this, "_buckets", []);
3678
3735
  __publicField(this, "_length", 0);
3679
3736
  if (options) {
3680
- const { bucketSize } = options;
3737
+ const { bucketSize, autoCompactRatio } = options;
3681
3738
  if (typeof bucketSize === "number") this._bucketSize = bucketSize;
3739
+ if (typeof autoCompactRatio === "number") this._autoCompactRatio = autoCompactRatio;
3682
3740
  }
3683
3741
  let _size;
3684
3742
  if ("length" in elements) {
@@ -3703,6 +3761,24 @@ var dataStructureTyped = (() => {
3703
3761
  get bucketSize() {
3704
3762
  return this._bucketSize;
3705
3763
  }
3764
+ /**
3765
+ * Get the auto-compaction ratio.
3766
+ * When `elements / (bucketCount * bucketSize)` drops below this ratio after
3767
+ * enough shift/pop operations, the deque auto-compacts.
3768
+ * @remarks Time O(1), Space O(1)
3769
+ * @returns Current ratio threshold. 0 means auto-compact is disabled.
3770
+ */
3771
+ get autoCompactRatio() {
3772
+ return this._autoCompactRatio;
3773
+ }
3774
+ /**
3775
+ * Set the auto-compaction ratio.
3776
+ * @remarks Time O(1), Space O(1)
3777
+ * @param value - Ratio in [0,1]. 0 disables auto-compact.
3778
+ */
3779
+ set autoCompactRatio(value) {
3780
+ this._autoCompactRatio = value;
3781
+ }
3706
3782
  /**
3707
3783
  * Get the index of the first bucket in use.
3708
3784
  * @remarks Time O(1), Space O(1)
@@ -3834,6 +3910,7 @@ var dataStructureTyped = (() => {
3834
3910
  }
3835
3911
  }
3836
3912
  this._length -= 1;
3913
+ this._autoCompact();
3837
3914
  return element;
3838
3915
  }
3839
3916
  /**
@@ -3856,6 +3933,7 @@ var dataStructureTyped = (() => {
3856
3933
  }
3857
3934
  }
3858
3935
  this._length -= 1;
3936
+ this._autoCompact();
3859
3937
  return element;
3860
3938
  }
3861
3939
  /**
@@ -4188,11 +4266,40 @@ var dataStructureTyped = (() => {
4188
4266
  * @remarks Time O(N), Space O(1)
4189
4267
  * @returns void
4190
4268
  */
4269
+ /**
4270
+ * (Protected) Trigger auto-compaction if space utilization drops below threshold.
4271
+ * Only checks every `_bucketSize` operations to minimize hot-path overhead.
4272
+ * Uses element-based ratio: `elements / (bucketCount * bucketSize)`.
4273
+ */
4274
+ _autoCompact() {
4275
+ if (this._autoCompactRatio <= 0 || this._bucketCount <= 1) return;
4276
+ this._compactCounter++;
4277
+ if (this._compactCounter < this._bucketSize) return;
4278
+ this._compactCounter = 0;
4279
+ const utilization = this._length / (this._bucketCount * this._bucketSize);
4280
+ if (utilization < this._autoCompactRatio) {
4281
+ this.shrinkToFit();
4282
+ }
4283
+ }
4284
+ /**
4285
+ * Compact the deque by removing unused buckets.
4286
+ * @remarks Time O(N), Space O(1)
4287
+ * @returns True if compaction was performed (bucket count reduced).
4288
+ */
4289
+ /**
4290
+ * Compact the deque by removing unused buckets.
4291
+ * @remarks Time O(N), Space O(1)
4292
+ * @returns True if compaction was performed (bucket count reduced).
4293
+ */
4294
+ compact() {
4295
+ const before = this._bucketCount;
4296
+ this.shrinkToFit();
4297
+ return this._bucketCount < before;
4298
+ }
4191
4299
  shrinkToFit() {
4192
4300
  if (this._length === 0) return;
4193
4301
  const newBuckets = [];
4194
- if (this._bucketFirst === this._bucketLast) return;
4195
- else if (this._bucketFirst < this._bucketLast) {
4302
+ if (this._bucketFirst <= this._bucketLast) {
4196
4303
  for (let i = this._bucketFirst; i <= this._bucketLast; ++i) {
4197
4304
  newBuckets.push(this._buckets[i]);
4198
4305
  }
@@ -4207,6 +4314,8 @@ var dataStructureTyped = (() => {
4207
4314
  this._bucketFirst = 0;
4208
4315
  this._bucketLast = newBuckets.length - 1;
4209
4316
  this._buckets = newBuckets;
4317
+ this._bucketCount = newBuckets.length;
4318
+ this._compactCounter = 0;
4210
4319
  }
4211
4320
  /**
4212
4321
  * Deep clone this deque, preserving options.
@@ -4402,7 +4511,7 @@ var dataStructureTyped = (() => {
4402
4511
  __publicField(this, "_elements", []);
4403
4512
  __publicField(this, "_DEFAULT_COMPARATOR", (a, b) => {
4404
4513
  if (typeof a === "object" || typeof b === "object") {
4405
- throw TypeError("When comparing object types, define a custom comparator in options.");
4514
+ throw new TypeError(ERR.comparatorRequired("Heap"));
4406
4515
  }
4407
4516
  if (a > b) return 1;
4408
4517
  if (a < b) return -1;
@@ -4712,7 +4821,7 @@ var dataStructureTyped = (() => {
4712
4821
  */
4713
4822
  map(callback, options, thisArg) {
4714
4823
  const { comparator, toElementFn, ...rest } = options != null ? options : {};
4715
- if (!comparator) throw new TypeError("Heap.map requires options.comparator for EM");
4824
+ if (!comparator) throw new TypeError(ERR.comparatorRequired("Heap.map"));
4716
4825
  const out = this._createLike([], { ...rest, comparator, toElementFn });
4717
4826
  let i = 0;
4718
4827
  for (const x of this) {
@@ -4737,11 +4846,6 @@ var dataStructureTyped = (() => {
4737
4846
  }
4738
4847
  return out;
4739
4848
  }
4740
- /**
4741
- * Get the comparator used to order elements.
4742
- * @remarks Time O(1), Space O(1)
4743
- * @returns Comparator function.
4744
- */
4745
4849
  /**
4746
4850
  * Get the comparator used to order elements.
4747
4851
  * @remarks Time O(1), Space O(1)
@@ -4790,8 +4894,7 @@ var dataStructureTyped = (() => {
4790
4894
  */
4791
4895
  _createInstance(options) {
4792
4896
  const Ctor = this.constructor;
4793
- const next = new Ctor([], { comparator: this.comparator, toElementFn: this.toElementFn, ...options != null ? options : {} });
4794
- return next;
4897
+ return new Ctor([], { comparator: this.comparator, toElementFn: this.toElementFn, ...options != null ? options : {} });
4795
4898
  }
4796
4899
  /**
4797
4900
  * (Protected) Create a like-kind instance seeded by elements.
@@ -4846,7 +4949,7 @@ var dataStructureTyped = (() => {
4846
4949
  __publicField(this, "_comparator");
4847
4950
  this.clear();
4848
4951
  this._comparator = comparator || this._defaultComparator;
4849
- if (typeof this.comparator !== "function") throw new Error("FibonacciHeap: comparator must be a function.");
4952
+ if (typeof this.comparator !== "function") throw new TypeError(ERR.notAFunction("comparator", "FibonacciHeap"));
4850
4953
  }
4851
4954
  /**
4852
4955
  * Get the circular root list head.
@@ -5055,9 +5158,7 @@ var dataStructureTyped = (() => {
5055
5158
  super(elements, {
5056
5159
  comparator: (a, b) => {
5057
5160
  if (typeof a === "object" || typeof b === "object") {
5058
- throw TypeError(
5059
- `When comparing object types, a custom comparator must be defined in the constructor's options parameter.`
5060
- );
5161
+ throw new TypeError(ERR.comparatorRequired("MaxHeap"));
5061
5162
  }
5062
5163
  if (a < b) return 1;
5063
5164
  if (a > b) return -1;
@@ -5214,7 +5315,7 @@ var dataStructureTyped = (() => {
5214
5315
  const newEdge = this.createEdge(srcOrEdge, dest, weight, value);
5215
5316
  return this._addEdge(newEdge);
5216
5317
  } else {
5217
- throw new Error("dest must be a Vertex or vertex key while srcOrEdge is an Edge");
5318
+ throw new TypeError(ERR.invalidArgument("dest must be a Vertex or vertex key when srcOrEdge is an Edge.", "Graph"));
5218
5319
  }
5219
5320
  }
5220
5321
  }
@@ -5823,8 +5924,8 @@ var dataStructureTyped = (() => {
5823
5924
  const Ctor = this.constructor;
5824
5925
  const instance = new Ctor();
5825
5926
  const graph = _options == null ? void 0 : _options.graph;
5826
- if (graph) instance._options = { ...instance._options, ...graph };
5827
- else instance._options = { ...instance._options, ...this._options };
5927
+ if (graph) instance["_options"] = { ...instance["_options"], ...graph };
5928
+ else instance["_options"] = { ...instance["_options"], ...this._options };
5828
5929
  return instance;
5829
5930
  }
5830
5931
  /**
@@ -5857,12 +5958,10 @@ var dataStructureTyped = (() => {
5857
5958
  const [va, vb] = ends;
5858
5959
  const ka = va.key;
5859
5960
  const kb = vb.key;
5860
- const hasA = g.hasVertex ? g.hasVertex(ka) : false;
5861
- const hasB = g.hasVertex ? g.hasVertex(kb) : false;
5961
+ const hasA = typeof g.hasVertex === "function" ? g.hasVertex(ka) : false;
5962
+ const hasB = typeof g.hasVertex === "function" ? g.hasVertex(kb) : false;
5862
5963
  if (hasA && hasB) {
5863
- const w = e.weight;
5864
- const val = e.value;
5865
- const newEdge = g.createEdge(ka, kb, w, val);
5964
+ const newEdge = g.createEdge(ka, kb, e.weight, e.value);
5866
5965
  g._addEdge(newEdge);
5867
5966
  }
5868
5967
  }
@@ -5900,6 +5999,94 @@ var dataStructureTyped = (() => {
5900
5999
  _getVertexKey(vertexOrKey) {
5901
6000
  return vertexOrKey instanceof AbstractVertex ? vertexOrKey.key : vertexOrKey;
5902
6001
  }
6002
+ /**
6003
+ * The edge connector string used in visual output.
6004
+ * Override in subclasses (e.g., '--' for undirected, '->' for directed).
6005
+ */
6006
+ get _edgeConnector() {
6007
+ return "--";
6008
+ }
6009
+ /**
6010
+ * Generate a text-based visual representation of the graph.
6011
+ *
6012
+ * **Adjacency list format:**
6013
+ * ```
6014
+ * Graph (5 vertices, 6 edges):
6015
+ * A -> B (1), C (2)
6016
+ * B -> D (3)
6017
+ * C -> (no outgoing edges)
6018
+ * D -> A (1)
6019
+ * E (isolated)
6020
+ * ```
6021
+ *
6022
+ * @param options - Optional display settings.
6023
+ * @param options.showWeight - Whether to show edge weights (default: true).
6024
+ * @returns The visual string.
6025
+ */
6026
+ toVisual(options) {
6027
+ var _a;
6028
+ const showWeight = (_a = options == null ? void 0 : options.showWeight) != null ? _a : true;
6029
+ const vertices = [...this._vertexMap.values()];
6030
+ const vertexCount = vertices.length;
6031
+ const edgeCount = this.edgeSet().length;
6032
+ const lines = [`Graph (${vertexCount} vertices, ${edgeCount} edges):`];
6033
+ for (const vertex of vertices) {
6034
+ const neighbors = this.getNeighbors(vertex);
6035
+ if (neighbors.length === 0) {
6036
+ lines.push(` ${vertex.key} (isolated)`);
6037
+ } else {
6038
+ const edgeStrs = neighbors.map((neighbor) => {
6039
+ const edge = this.getEdge(vertex, neighbor);
6040
+ if (edge && showWeight && edge.weight !== void 0 && edge.weight !== 1) {
6041
+ return `${neighbor.key} (${edge.weight})`;
6042
+ }
6043
+ return `${neighbor.key}`;
6044
+ });
6045
+ lines.push(` ${vertex.key} ${this._edgeConnector} ${edgeStrs.join(", ")}`);
6046
+ }
6047
+ }
6048
+ return lines.join("\n");
6049
+ }
6050
+ /**
6051
+ * Generate DOT language representation for Graphviz.
6052
+ *
6053
+ * @param options - Optional display settings.
6054
+ * @param options.name - Graph name (default: 'G').
6055
+ * @param options.showWeight - Whether to label edges with weight (default: true).
6056
+ * @returns DOT format string.
6057
+ */
6058
+ toDot(options) {
6059
+ var _a, _b;
6060
+ const name = (_a = options == null ? void 0 : options.name) != null ? _a : "G";
6061
+ const showWeight = (_b = options == null ? void 0 : options.showWeight) != null ? _b : true;
6062
+ const isDirected = this._edgeConnector === "->";
6063
+ const graphType = isDirected ? "digraph" : "graph";
6064
+ const edgeOp = isDirected ? "->" : "--";
6065
+ const lines = [`${graphType} ${name} {`];
6066
+ for (const vertex of this._vertexMap.values()) {
6067
+ lines.push(` "${vertex.key}";`);
6068
+ }
6069
+ const visited = /* @__PURE__ */ new Set();
6070
+ for (const vertex of this._vertexMap.values()) {
6071
+ for (const neighbor of this.getNeighbors(vertex)) {
6072
+ const edgeId = isDirected ? `${vertex.key}->${neighbor.key}` : [vertex.key, neighbor.key].sort().join("--");
6073
+ if (visited.has(edgeId)) continue;
6074
+ visited.add(edgeId);
6075
+ const edge = this.getEdge(vertex, neighbor);
6076
+ const label = edge && showWeight && edge.weight !== void 0 && edge.weight !== 1 ? ` [label="${edge.weight}"]` : "";
6077
+ lines.push(` "${vertex.key}" ${edgeOp} "${neighbor.key}"${label};`);
6078
+ }
6079
+ }
6080
+ lines.push("}");
6081
+ return lines.join("\n");
6082
+ }
6083
+ /**
6084
+ * Print the graph to console.
6085
+ * @param options - Display settings passed to `toVisual`.
6086
+ */
6087
+ print(options) {
6088
+ console.log(this.toVisual(options));
6089
+ }
5903
6090
  };
5904
6091
 
5905
6092
  // src/data-structures/graph/directed-graph.ts
@@ -5928,6 +6115,9 @@ var dataStructureTyped = (() => {
5928
6115
  __publicField(this, "_outEdgeMap", /* @__PURE__ */ new Map());
5929
6116
  __publicField(this, "_inEdgeMap", /* @__PURE__ */ new Map());
5930
6117
  }
6118
+ get _edgeConnector() {
6119
+ return "->";
6120
+ }
5931
6121
  get outEdgeMap() {
5932
6122
  return this._outEdgeMap;
5933
6123
  }
@@ -6702,6 +6892,84 @@ var dataStructureTyped = (() => {
6702
6892
  cutVertices
6703
6893
  };
6704
6894
  }
6895
+ /**
6896
+ * Find biconnected components using edge-stack Tarjan variant.
6897
+ * A biconnected component is a maximal biconnected subgraph.
6898
+ * @returns Array of edge arrays, each representing a biconnected component.
6899
+ * @remarks Time O(V + E), Space O(V + E)
6900
+ */
6901
+ getBiconnectedComponents() {
6902
+ const dfn = /* @__PURE__ */ new Map();
6903
+ const low = /* @__PURE__ */ new Map();
6904
+ const edgeStack = [];
6905
+ const components = [];
6906
+ let time = 0;
6907
+ const dfs = (vertex, parent) => {
6908
+ dfn.set(vertex, time);
6909
+ low.set(vertex, time);
6910
+ time++;
6911
+ const neighbors = this.getNeighbors(vertex);
6912
+ let childCount = 0;
6913
+ for (const neighbor of neighbors) {
6914
+ const edge = this.getEdge(vertex, neighbor);
6915
+ if (!edge) continue;
6916
+ if (!dfn.has(neighbor)) {
6917
+ childCount++;
6918
+ edgeStack.push(edge);
6919
+ dfs(neighbor, vertex);
6920
+ low.set(vertex, Math.min(low.get(vertex), low.get(neighbor)));
6921
+ if (parent === void 0 && childCount > 1 || parent !== void 0 && low.get(neighbor) >= dfn.get(vertex)) {
6922
+ const component = [];
6923
+ let e;
6924
+ do {
6925
+ e = edgeStack.pop();
6926
+ if (e) component.push(e);
6927
+ } while (e && e !== edge);
6928
+ if (component.length > 0) components.push(component);
6929
+ }
6930
+ } else if (neighbor !== parent && dfn.get(neighbor) < dfn.get(vertex)) {
6931
+ edgeStack.push(edge);
6932
+ low.set(vertex, Math.min(low.get(vertex), dfn.get(neighbor)));
6933
+ }
6934
+ }
6935
+ };
6936
+ for (const vertex of this.vertexMap.values()) {
6937
+ if (!dfn.has(vertex)) {
6938
+ dfs(vertex, void 0);
6939
+ if (edgeStack.length > 0) {
6940
+ components.push([...edgeStack]);
6941
+ edgeStack.length = 0;
6942
+ }
6943
+ }
6944
+ }
6945
+ return components;
6946
+ }
6947
+ /**
6948
+ * Detect whether the graph contains a cycle.
6949
+ * Uses DFS with parent tracking.
6950
+ * @returns `true` if a cycle exists, `false` otherwise.
6951
+ * @remarks Time O(V + E), Space O(V)
6952
+ */
6953
+ hasCycle() {
6954
+ const visited = /* @__PURE__ */ new Set();
6955
+ const dfs = (vertex, parent) => {
6956
+ visited.add(vertex);
6957
+ for (const neighbor of this.getNeighbors(vertex)) {
6958
+ if (!visited.has(neighbor)) {
6959
+ if (dfs(neighbor, vertex)) return true;
6960
+ } else if (neighbor !== parent) {
6961
+ return true;
6962
+ }
6963
+ }
6964
+ return false;
6965
+ };
6966
+ for (const vertex of this.vertexMap.values()) {
6967
+ if (!visited.has(vertex)) {
6968
+ if (dfs(vertex, void 0)) return true;
6969
+ }
6970
+ }
6971
+ return false;
6972
+ }
6705
6973
  /**
6706
6974
  * Get bridges discovered by `tarjan()`.
6707
6975
  * @returns Array of edges that are bridges.
@@ -6846,27 +7114,6 @@ var dataStructureTyped = (() => {
6846
7114
  }
6847
7115
  };
6848
7116
 
6849
- // src/common/index.ts
6850
- var DFSOperation = /* @__PURE__ */ ((DFSOperation2) => {
6851
- DFSOperation2[DFSOperation2["VISIT"] = 0] = "VISIT";
6852
- DFSOperation2[DFSOperation2["PROCESS"] = 1] = "PROCESS";
6853
- return DFSOperation2;
6854
- })(DFSOperation || {});
6855
- var Range = class {
6856
- constructor(low, high, includeLow = true, includeHigh = true) {
6857
- this.low = low;
6858
- this.high = high;
6859
- this.includeLow = includeLow;
6860
- this.includeHigh = includeHigh;
6861
- }
6862
- // Determine whether a key is within the range
6863
- isInRange(key, comparator) {
6864
- const lowCheck = this.includeLow ? comparator(key, this.low) >= 0 : comparator(key, this.low) > 0;
6865
- const highCheck = this.includeHigh ? comparator(key, this.high) <= 0 : comparator(key, this.high) < 0;
6866
- return lowCheck && highCheck;
6867
- }
6868
- };
6869
-
6870
7117
  // src/data-structures/binary-tree/binary-tree.ts
6871
7118
  var BinaryTreeNode = class {
6872
7119
  /**
@@ -7002,7 +7249,7 @@ var dataStructureTyped = (() => {
7002
7249
  return "MAL_NODE";
7003
7250
  }
7004
7251
  };
7005
- var BinaryTree = class extends IterableEntryBase {
7252
+ var BinaryTree = class _BinaryTree extends IterableEntryBase {
7006
7253
  /**
7007
7254
  * Creates an instance of BinaryTree.
7008
7255
  * @remarks Time O(N * M), where N is the number of items in `keysNodesEntriesOrRaws` and M is the tree size at insertion time (due to O(M) `set` operation). Space O(N) for storing the nodes.
@@ -7030,14 +7277,14 @@ var dataStructureTyped = (() => {
7030
7277
  * @param node - The node.
7031
7278
  * @returns The node's key or undefined.
7032
7279
  */
7033
- __publicField(this, "_DEFAULT_NODE_CALLBACK", (node) => node ? node.key : void 0);
7280
+ __publicField(this, "_DEFAULT_NODE_CALLBACK", (node) => node == null ? void 0 : node.key);
7034
7281
  if (options) {
7035
7282
  const { iterationType, toEntryFn, isMapMode, isDuplicate } = options;
7036
7283
  if (iterationType) this.iterationType = iterationType;
7037
7284
  if (isMapMode !== void 0) this._isMapMode = isMapMode;
7038
7285
  if (isDuplicate !== void 0) this._isDuplicate = isDuplicate;
7039
7286
  if (typeof toEntryFn === "function") this._toEntryFn = toEntryFn;
7040
- else if (toEntryFn) throw TypeError("toEntryFn must be a function type");
7287
+ else if (toEntryFn) throw new TypeError(ERR.notAFunction("toEntryFn", "BinaryTree"));
7041
7288
  }
7042
7289
  if (keysNodesEntriesOrRaws) this.setMany(keysNodesEntriesOrRaws);
7043
7290
  }
@@ -7265,7 +7512,7 @@ var dataStructureTyped = (() => {
7265
7512
  if (!this._root) {
7266
7513
  this._setRoot(newNode);
7267
7514
  if (this._isMapMode && newNode !== null && newNode !== void 0) this._store.set(newNode.key, newNode);
7268
- this._size = 1;
7515
+ if (newNode !== null) this._size = 1;
7269
7516
  return true;
7270
7517
  }
7271
7518
  const queue = new Queue([this._root]);
@@ -7297,7 +7544,7 @@ var dataStructureTyped = (() => {
7297
7544
  potentialParent.right = newNode;
7298
7545
  }
7299
7546
  if (this._isMapMode && newNode !== null && newNode !== void 0) this._store.set(newNode.key, newNode);
7300
- this._size++;
7547
+ if (newNode !== null) this._size++;
7301
7548
  return true;
7302
7549
  }
7303
7550
  return false;
@@ -7866,7 +8113,7 @@ var dataStructureTyped = (() => {
7866
8113
  }
7867
8114
  /**
7868
8115
  * Finds all leaf nodes in the tree.
7869
- * @remarks Time O(N), visits every node. Space O(H) for recursive stack or O(N) for iterative queue.
8116
+ * @remarks Time O(N), visits every node. Space O(H) for recursive or iterative stack.
7870
8117
  *
7871
8118
  * @template C - The type of the callback function.
7872
8119
  * @param [callback=this._DEFAULT_NODE_CALLBACK] - Function to call on each leaf node.
@@ -7889,15 +8136,15 @@ var dataStructureTyped = (() => {
7889
8136
  };
7890
8137
  dfs(startNode);
7891
8138
  } else {
7892
- const queue = new Queue([startNode]);
7893
- while (queue.length > 0) {
7894
- const cur = queue.shift();
8139
+ const stack = [startNode];
8140
+ while (stack.length > 0) {
8141
+ const cur = stack.pop();
7895
8142
  if (this.isRealNode(cur)) {
7896
8143
  if (this.isLeaf(cur)) {
7897
8144
  leaves.push(callback(cur));
7898
8145
  }
7899
- if (this.isRealNode(cur.left)) queue.push(cur.left);
7900
- if (this.isRealNode(cur.right)) queue.push(cur.right);
8146
+ if (this.isRealNode(cur.right)) stack.push(cur.right);
8147
+ if (this.isRealNode(cur.left)) stack.push(cur.left);
7901
8148
  }
7902
8149
  }
7903
8150
  }
@@ -8353,42 +8600,98 @@ var dataStructureTyped = (() => {
8353
8600
  _displayAux(node, options) {
8354
8601
  const { isShowNull, isShowUndefined, isShowRedBlackNIL } = options;
8355
8602
  const emptyDisplayLayout = [["\u2500"], 1, 0, 0];
8356
- if (node === null && !isShowNull) {
8357
- return emptyDisplayLayout;
8358
- } else if (node === void 0 && !isShowUndefined) {
8359
- return emptyDisplayLayout;
8360
- } else if (this.isNIL(node) && !isShowRedBlackNIL) {
8361
- return emptyDisplayLayout;
8362
- } else if (node !== null && node !== void 0) {
8363
- const key = node.key, line = this.isNIL(node) ? "S" : String(key), width = line.length;
8364
- return _buildNodeDisplay(
8365
- line,
8366
- width,
8367
- this._displayAux(node.left, options),
8368
- this._displayAux(node.right, options)
8369
- );
8370
- } else {
8371
- const line = node === void 0 ? "U" : "N", width = line.length;
8372
- return _buildNodeDisplay(line, width, [[""], 1, 0, 0], [[""], 1, 0, 0]);
8373
- }
8374
- function _buildNodeDisplay(line, width, left, right) {
8375
- const [leftLines, leftWidth, leftHeight, leftMiddle] = left;
8376
- const [rightLines, rightWidth, rightHeight, rightMiddle] = right;
8377
- const firstLine = " ".repeat(Math.max(0, leftMiddle + 1)) + "_".repeat(Math.max(0, leftWidth - leftMiddle - 1)) + line + "_".repeat(Math.max(0, rightMiddle)) + " ".repeat(Math.max(0, rightWidth - rightMiddle));
8378
- const secondLine = (leftHeight > 0 ? " ".repeat(leftMiddle) + "/" + " ".repeat(leftWidth - leftMiddle - 1) : " ".repeat(leftWidth)) + " ".repeat(width) + (rightHeight > 0 ? " ".repeat(rightMiddle) + "\\" + " ".repeat(rightWidth - rightMiddle - 1) : " ".repeat(rightWidth));
8379
- const mergedLines = [firstLine, secondLine];
8380
- for (let i = 0; i < Math.max(leftHeight, rightHeight); i++) {
8381
- const leftLine = i < leftHeight ? leftLines[i] : " ".repeat(leftWidth);
8382
- const rightLine = i < rightHeight ? rightLines[i] : " ".repeat(rightWidth);
8383
- mergedLines.push(leftLine + " ".repeat(width) + rightLine);
8603
+ const newFrame = (n) => ({
8604
+ node: n,
8605
+ stage: 0,
8606
+ leftLayout: emptyDisplayLayout,
8607
+ rightLayout: emptyDisplayLayout
8608
+ });
8609
+ const stack = [newFrame(node)];
8610
+ let result = emptyDisplayLayout;
8611
+ const setChildResult = (layout) => {
8612
+ if (stack.length === 0) {
8613
+ result = layout;
8614
+ return;
8384
8615
  }
8385
- return [
8386
- mergedLines,
8387
- leftWidth + width + rightWidth,
8388
- Math.max(leftHeight, rightHeight) + 2,
8389
- leftWidth + Math.floor(width / 2)
8390
- ];
8616
+ const parent = stack[stack.length - 1];
8617
+ if (parent.stage === 1) parent.leftLayout = layout;
8618
+ else parent.rightLayout = layout;
8619
+ };
8620
+ while (stack.length > 0) {
8621
+ const frame = stack[stack.length - 1];
8622
+ const cur = frame.node;
8623
+ if (frame.stage === 0) {
8624
+ if (this._isDisplayLeaf(cur, options)) {
8625
+ stack.pop();
8626
+ const layout = this._resolveDisplayLeaf(cur, options, emptyDisplayLayout);
8627
+ setChildResult(layout);
8628
+ continue;
8629
+ }
8630
+ frame.stage = 1;
8631
+ stack.push(newFrame(cur.left));
8632
+ } else if (frame.stage === 1) {
8633
+ frame.stage = 2;
8634
+ stack.push(newFrame(cur.right));
8635
+ } else {
8636
+ stack.pop();
8637
+ const line = this.isNIL(cur) ? "S" : String(cur.key);
8638
+ const layout = _BinaryTree._buildNodeDisplay(line, line.length, frame.leftLayout, frame.rightLayout);
8639
+ setChildResult(layout);
8640
+ }
8641
+ }
8642
+ return result;
8643
+ }
8644
+ static _buildNodeDisplay(line, width, left, right) {
8645
+ const [leftLines, leftWidth, leftHeight, leftMiddle] = left;
8646
+ const [rightLines, rightWidth, rightHeight, rightMiddle] = right;
8647
+ const firstLine = " ".repeat(Math.max(0, leftMiddle + 1)) + "_".repeat(Math.max(0, leftWidth - leftMiddle - 1)) + line + "_".repeat(Math.max(0, rightMiddle)) + " ".repeat(Math.max(0, rightWidth - rightMiddle));
8648
+ const secondLine = (leftHeight > 0 ? " ".repeat(leftMiddle) + "/" + " ".repeat(leftWidth - leftMiddle - 1) : " ".repeat(leftWidth)) + " ".repeat(width) + (rightHeight > 0 ? " ".repeat(rightMiddle) + "\\" + " ".repeat(rightWidth - rightMiddle - 1) : " ".repeat(rightWidth));
8649
+ const mergedLines = [firstLine, secondLine];
8650
+ for (let i = 0; i < Math.max(leftHeight, rightHeight); i++) {
8651
+ const leftLine = i < leftHeight ? leftLines[i] : " ".repeat(leftWidth);
8652
+ const rightLine = i < rightHeight ? rightLines[i] : " ".repeat(rightWidth);
8653
+ mergedLines.push(leftLine + " ".repeat(width) + rightLine);
8391
8654
  }
8655
+ return [
8656
+ mergedLines,
8657
+ leftWidth + width + rightWidth,
8658
+ Math.max(leftHeight, rightHeight) + 2,
8659
+ leftWidth + Math.floor(width / 2)
8660
+ ];
8661
+ }
8662
+ /**
8663
+ * Check if a node is a display leaf (empty, null, undefined, NIL, or real leaf).
8664
+ */
8665
+ _isDisplayLeaf(node, options) {
8666
+ const { isShowNull, isShowUndefined, isShowRedBlackNIL } = options;
8667
+ if (node === null && !isShowNull) return true;
8668
+ if (node === void 0 && !isShowUndefined) return true;
8669
+ if (this.isNIL(node) && !isShowRedBlackNIL) return true;
8670
+ if (node === null || node === void 0) return true;
8671
+ const hasDisplayableLeft = this._hasDisplayableChild(node.left, options);
8672
+ const hasDisplayableRight = this._hasDisplayableChild(node.right, options);
8673
+ return !hasDisplayableLeft && !hasDisplayableRight;
8674
+ }
8675
+ _hasDisplayableChild(child, options) {
8676
+ if (child === null) return !!options.isShowNull;
8677
+ if (child === void 0) return !!options.isShowUndefined;
8678
+ if (this.isNIL(child)) return !!options.isShowRedBlackNIL;
8679
+ return true;
8680
+ }
8681
+ /**
8682
+ * Resolve a display leaf node to its layout.
8683
+ */
8684
+ _resolveDisplayLeaf(node, options, emptyDisplayLayout) {
8685
+ const { isShowNull, isShowUndefined, isShowRedBlackNIL } = options;
8686
+ if (node === null && !isShowNull) return emptyDisplayLayout;
8687
+ if (node === void 0 && !isShowUndefined) return emptyDisplayLayout;
8688
+ if (this.isNIL(node) && !isShowRedBlackNIL) return emptyDisplayLayout;
8689
+ if (node !== null && node !== void 0) {
8690
+ const line2 = this.isNIL(node) ? "S" : String(node.key);
8691
+ return _BinaryTree._buildNodeDisplay(line2, line2.length, emptyDisplayLayout, emptyDisplayLayout);
8692
+ }
8693
+ const line = node === void 0 ? "U" : "N";
8694
+ return _BinaryTree._buildNodeDisplay(line, line.length, [[""], 1, 0, 0], [[""], 1, 0, 0]);
8392
8695
  }
8393
8696
  /**
8394
8697
  * (Protected) Swaps the key/value properties of two nodes.
@@ -9390,9 +9693,15 @@ var dataStructureTyped = (() => {
9390
9693
  if (a < b) return -1;
9391
9694
  return 0;
9392
9695
  }
9696
+ if (a instanceof Date && b instanceof Date) {
9697
+ const ta = a.getTime();
9698
+ const tb = b.getTime();
9699
+ if (Number.isNaN(ta) || Number.isNaN(tb)) throw new TypeError(ERR.invalidDate("BST"));
9700
+ return ta > tb ? 1 : ta < tb ? -1 : 0;
9701
+ }
9393
9702
  if (typeof a === "object" || typeof b === "object") {
9394
- throw TypeError(
9395
- `When comparing object type keys, a custom comparator must be provided in the constructor's options!`
9703
+ throw new TypeError(
9704
+ ERR.comparatorRequired("BST")
9396
9705
  );
9397
9706
  }
9398
9707
  return 0;
@@ -9904,7 +10213,7 @@ var dataStructureTyped = (() => {
9904
10213
  */
9905
10214
  read(count) {
9906
10215
  if (!Number.isInteger(count)) {
9907
- throw new Error("Invalid count");
10216
+ throw new Error(ERR.invalidArgument("count must be an integer", "BinaryIndexedTree"));
9908
10217
  }
9909
10218
  return this._read(Math.max(Math.min(count, this.max), 0));
9910
10219
  }
@@ -9916,7 +10225,7 @@ var dataStructureTyped = (() => {
9916
10225
  */
9917
10226
  lowerBound(sum) {
9918
10227
  if (this.negativeCount > 0) {
9919
- throw new Error("Sequence is not non-descending");
10228
+ throw new Error(ERR.invalidOperation("Sequence is not non-descending.", "BinaryIndexedTree"));
9920
10229
  }
9921
10230
  return this._binarySearch(sum, (x, y) => x < y);
9922
10231
  }
@@ -9929,7 +10238,7 @@ var dataStructureTyped = (() => {
9929
10238
  */
9930
10239
  upperBound(sum) {
9931
10240
  if (this.negativeCount > 0) {
9932
- throw new Error("Must not be descending");
10241
+ throw new Error(ERR.invalidOperation("Sequence must not be descending.", "BinaryIndexedTree"));
9933
10242
  }
9934
10243
  return this._binarySearch(sum, (x, y) => x <= y);
9935
10244
  }
@@ -9980,10 +10289,10 @@ var dataStructureTyped = (() => {
9980
10289
  */
9981
10290
  _checkIndex(index) {
9982
10291
  if (!Number.isInteger(index)) {
9983
- throw new Error("Invalid index: Index must be an integer.");
10292
+ throw new TypeError(ERR.invalidIndex("BinaryIndexedTree"));
9984
10293
  }
9985
10294
  if (index < 0 || index >= this.max) {
9986
- throw new Error("Index out of range: Index must be within the range [0, this.max).");
10295
+ throw new RangeError(ERR.indexOutOfRange(index, 0, this.max - 1, "BinaryIndexedTree"));
9987
10296
  }
9988
10297
  }
9989
10298
  /**
@@ -11560,6 +11869,24 @@ var dataStructureTyped = (() => {
11560
11869
  * @param [thisArg] - See parameter type for details.
11561
11870
  * @returns A new RedBlackTree with mapped entries.
11562
11871
  */
11872
+ /**
11873
+ * Red-Black trees are self-balancing — `perfectlyBalance` rebuilds via
11874
+ * sorted bulk insert, which naturally produces a balanced RBT.
11875
+ * @remarks Time O(N), Space O(N)
11876
+ */
11877
+ perfectlyBalance(iterationType) {
11878
+ const entries = [];
11879
+ for (const [key, value] of this) entries.push([key, value]);
11880
+ if (entries.length <= 1) return true;
11881
+ this.clear();
11882
+ this.setMany(
11883
+ entries.map(([k]) => k),
11884
+ entries.map(([, v]) => v),
11885
+ true
11886
+ // isBalanceAdd
11887
+ );
11888
+ return true;
11889
+ }
11563
11890
  map(callback, options, thisArg) {
11564
11891
  const out = this._createLike([], options);
11565
11892
  let index = 0;
@@ -11882,7 +12209,7 @@ var dataStructureTyped = (() => {
11882
12209
  static createDefaultComparator() {
11883
12210
  return (a, b) => {
11884
12211
  if (typeof a === "number" && typeof b === "number") {
11885
- if (Number.isNaN(a) || Number.isNaN(b)) throw new TypeError("TreeSet: NaN is not a valid key");
12212
+ if (Number.isNaN(a) || Number.isNaN(b)) throw new TypeError(ERR.invalidNaN("TreeSet"));
11886
12213
  const aa = Object.is(a, -0) ? 0 : a;
11887
12214
  const bb = Object.is(b, -0) ? 0 : b;
11888
12215
  return aa > bb ? 1 : aa < bb ? -1 : 0;
@@ -11893,10 +12220,10 @@ var dataStructureTyped = (() => {
11893
12220
  if (a instanceof Date && b instanceof Date) {
11894
12221
  const ta = a.getTime();
11895
12222
  const tb = b.getTime();
11896
- if (Number.isNaN(ta) || Number.isNaN(tb)) throw new TypeError("TreeSet: invalid Date key");
12223
+ if (Number.isNaN(ta) || Number.isNaN(tb)) throw new TypeError(ERR.invalidDate("TreeSet"));
11897
12224
  return ta > tb ? 1 : ta < tb ? -1 : 0;
11898
12225
  }
11899
- throw new TypeError("TreeSet: comparator is required for non-number/non-string/non-Date keys");
12226
+ throw new TypeError(ERR.comparatorRequired("TreeSet"));
11900
12227
  };
11901
12228
  }
11902
12229
  /**
@@ -11914,15 +12241,15 @@ var dataStructureTyped = (() => {
11914
12241
  _validateKey(key) {
11915
12242
  if (!__privateGet(this, _isDefaultComparator)) return;
11916
12243
  if (typeof key === "number") {
11917
- if (Number.isNaN(key)) throw new TypeError("TreeSet: NaN is not a valid key");
12244
+ if (Number.isNaN(key)) throw new TypeError(ERR.invalidNaN("TreeSet"));
11918
12245
  return;
11919
12246
  }
11920
12247
  if (typeof key === "string") return;
11921
12248
  if (key instanceof Date) {
11922
- if (Number.isNaN(key.getTime())) throw new TypeError("TreeSet: invalid Date key");
12249
+ if (Number.isNaN(key.getTime())) throw new TypeError(ERR.invalidDate("TreeSet"));
11923
12250
  return;
11924
12251
  }
11925
- throw new TypeError("TreeSet: comparator is required for non-number/non-string/non-Date keys");
12252
+ throw new TypeError(ERR.comparatorRequired("TreeSet"));
11926
12253
  }
11927
12254
  /**
11928
12255
  * Add a key to the set (no-op if already present).
@@ -12242,15 +12569,15 @@ var dataStructureTyped = (() => {
12242
12569
  _validateKey(key) {
12243
12570
  if (!__privateGet(this, _isDefaultComparator2)) return;
12244
12571
  if (typeof key === "number") {
12245
- if (Number.isNaN(key)) throw new TypeError("TreeMultiMap: NaN is not a valid key");
12572
+ if (Number.isNaN(key)) throw new TypeError(ERR.invalidNaN("TreeMultiMap"));
12246
12573
  return;
12247
12574
  }
12248
12575
  if (typeof key === "string") return;
12249
12576
  if (key instanceof Date) {
12250
- if (Number.isNaN(key.getTime())) throw new TypeError("TreeMultiMap: invalid Date key");
12577
+ if (Number.isNaN(key.getTime())) throw new TypeError(ERR.invalidDate("TreeMultiMap"));
12251
12578
  return;
12252
12579
  }
12253
- throw new TypeError("TreeMultiMap: comparator is required for non-number/non-string/non-Date keys");
12580
+ throw new TypeError(ERR.comparatorRequired("TreeMultiMap"));
12254
12581
  }
12255
12582
  /**
12256
12583
  * Number of distinct keys.
@@ -12674,7 +13001,7 @@ var dataStructureTyped = (() => {
12674
13001
  [k, v] = toEntryFn(item);
12675
13002
  } else {
12676
13003
  if (!Array.isArray(item) || item.length < 2) {
12677
- throw new TypeError("TreeMap: each entry must be a [key, value] tuple");
13004
+ throw new TypeError(ERR.invalidEntry("TreeMap"));
12678
13005
  }
12679
13006
  k = item[0];
12680
13007
  v = item[1];
@@ -12695,7 +13022,7 @@ var dataStructureTyped = (() => {
12695
13022
  static createDefaultComparator() {
12696
13023
  return (a, b) => {
12697
13024
  if (typeof a === "number" && typeof b === "number") {
12698
- if (Number.isNaN(a) || Number.isNaN(b)) throw new TypeError("TreeMap: NaN is not a valid key");
13025
+ if (Number.isNaN(a) || Number.isNaN(b)) throw new TypeError(ERR.invalidNaN("TreeMap"));
12699
13026
  const aa = Object.is(a, -0) ? 0 : a;
12700
13027
  const bb = Object.is(b, -0) ? 0 : b;
12701
13028
  return aa > bb ? 1 : aa < bb ? -1 : 0;
@@ -12706,24 +13033,24 @@ var dataStructureTyped = (() => {
12706
13033
  if (a instanceof Date && b instanceof Date) {
12707
13034
  const ta = a.getTime();
12708
13035
  const tb = b.getTime();
12709
- if (Number.isNaN(ta) || Number.isNaN(tb)) throw new TypeError("TreeMap: invalid Date key");
13036
+ if (Number.isNaN(ta) || Number.isNaN(tb)) throw new TypeError(ERR.invalidDate("TreeMap"));
12710
13037
  return ta > tb ? 1 : ta < tb ? -1 : 0;
12711
13038
  }
12712
- throw new TypeError("TreeMap: comparator is required for non-number/non-string/non-Date keys");
13039
+ throw new TypeError(ERR.comparatorRequired("TreeMap"));
12713
13040
  };
12714
13041
  }
12715
13042
  _validateKey(key) {
12716
13043
  if (!__privateGet(this, _isDefaultComparator3)) return;
12717
13044
  if (typeof key === "number") {
12718
- if (Number.isNaN(key)) throw new TypeError("TreeMap: NaN is not a valid key");
13045
+ if (Number.isNaN(key)) throw new TypeError(ERR.invalidNaN("TreeMap"));
12719
13046
  return;
12720
13047
  }
12721
13048
  if (typeof key === "string") return;
12722
13049
  if (key instanceof Date) {
12723
- if (Number.isNaN(key.getTime())) throw new TypeError("TreeMap: invalid Date key");
13050
+ if (Number.isNaN(key.getTime())) throw new TypeError(ERR.invalidDate("TreeMap"));
12724
13051
  return;
12725
13052
  }
12726
- throw new TypeError("TreeMap: comparator is required for non-number/non-string/non-Date keys");
13053
+ throw new TypeError(ERR.comparatorRequired("TreeMap"));
12727
13054
  }
12728
13055
  /**
12729
13056
  * Number of entries in the map.
@@ -13051,22 +13378,22 @@ var dataStructureTyped = (() => {
13051
13378
  _validateKey(key) {
13052
13379
  if (!__privateGet(this, _isDefaultComparator4)) return;
13053
13380
  if (typeof key === "number") {
13054
- if (Number.isNaN(key)) throw new TypeError("TreeMultiSet: NaN is not a valid key");
13381
+ if (Number.isNaN(key)) throw new TypeError(ERR.invalidNaN("TreeMultiSet"));
13055
13382
  return;
13056
13383
  }
13057
13384
  if (typeof key === "string") return;
13058
13385
  if (key instanceof Date) {
13059
- if (Number.isNaN(key.getTime())) throw new TypeError("TreeMultiSet: invalid Date key");
13386
+ if (Number.isNaN(key.getTime())) throw new TypeError(ERR.invalidDate("TreeMultiSet"));
13060
13387
  return;
13061
13388
  }
13062
- throw new TypeError("TreeMultiSet: comparator is required for non-number/non-string/non-Date keys");
13389
+ throw new TypeError(ERR.comparatorRequired("TreeMultiSet"));
13063
13390
  }
13064
13391
  /**
13065
13392
  * Validates that count is a non-negative safe integer.
13066
13393
  * @remarks Time O(1), Space O(1)
13067
13394
  */
13068
13395
  _validateCount(n) {
13069
- if (!Number.isSafeInteger(n) || n < 0) throw new RangeError("TreeMultiSet: count must be a safe integer >= 0");
13396
+ if (!Number.isSafeInteger(n) || n < 0) throw new RangeError(ERR.invalidArgument("count must be a safe integer >= 0.", "TreeMultiSet"));
13070
13397
  }
13071
13398
  /**
13072
13399
  * Total occurrences (sumCounts).
@@ -13225,7 +13552,7 @@ var dataStructureTyped = (() => {
13225
13552
  * @remarks Time O(1), Space O(1)
13226
13553
  */
13227
13554
  get comparator() {
13228
- return __privateGet(this, _core4)._comparator;
13555
+ return __privateGet(this, _core4).comparator;
13229
13556
  }
13230
13557
  // ━━━ clear ━━━
13231
13558
  /**
@@ -13362,7 +13689,7 @@ var dataStructureTyped = (() => {
13362
13689
  filter(predicate) {
13363
13690
  const result = new _TreeMultiSet([], {
13364
13691
  comparator: __privateGet(this, _isDefaultComparator4) ? void 0 : this.comparator,
13365
- isMapMode: __privateGet(this, _core4)._isMapMode
13692
+ isMapMode: __privateGet(this, _core4).isMapMode
13366
13693
  });
13367
13694
  for (const [k, c] of this.entries()) {
13368
13695
  if (predicate(k, c)) {
@@ -13402,7 +13729,7 @@ var dataStructureTyped = (() => {
13402
13729
  map(mapper, options) {
13403
13730
  const result = new _TreeMultiSet([], {
13404
13731
  comparator: options == null ? void 0 : options.comparator,
13405
- isMapMode: __privateGet(this, _core4)._isMapMode
13732
+ isMapMode: __privateGet(this, _core4).isMapMode
13406
13733
  });
13407
13734
  for (const [k, c] of this.entries()) {
13408
13735
  const [newKey, newCount] = mapper(k, c);
@@ -13422,7 +13749,7 @@ var dataStructureTyped = (() => {
13422
13749
  clone() {
13423
13750
  const result = new _TreeMultiSet([], {
13424
13751
  comparator: __privateGet(this, _isDefaultComparator4) ? void 0 : this.comparator,
13425
- isMapMode: __privateGet(this, _core4)._isMapMode
13752
+ isMapMode: __privateGet(this, _core4).isMapMode
13426
13753
  });
13427
13754
  for (const [k, c] of this.entries()) {
13428
13755
  result.add(k, c);
@@ -13489,9 +13816,7 @@ var dataStructureTyped = (() => {
13489
13816
  super(elements, {
13490
13817
  comparator: (a, b) => {
13491
13818
  if (typeof a === "object" || typeof b === "object") {
13492
- throw TypeError(
13493
- `When comparing object types, a custom comparator must be defined in the constructor's options parameter.`
13494
- );
13819
+ throw new TypeError(ERR.comparatorRequired("MaxPriorityQueue"));
13495
13820
  }
13496
13821
  if (a < b) return 1;
13497
13822
  if (a > b) return -1;
@@ -13630,7 +13955,7 @@ var dataStructureTyped = (() => {
13630
13955
  */
13631
13956
  add(matrix) {
13632
13957
  if (!this.isMatchForCalculate(matrix)) {
13633
- throw new Error("Matrix dimensions must match for addition.");
13958
+ throw new Error(ERR.matrixDimensionMismatch("addition"));
13634
13959
  }
13635
13960
  const resultData = [];
13636
13961
  for (let i = 0; i < this.rows; i++) {
@@ -13662,7 +13987,7 @@ var dataStructureTyped = (() => {
13662
13987
  */
13663
13988
  subtract(matrix) {
13664
13989
  if (!this.isMatchForCalculate(matrix)) {
13665
- throw new Error("Matrix dimensions must match for subtraction.");
13990
+ throw new Error(ERR.matrixDimensionMismatch("subtraction"));
13666
13991
  }
13667
13992
  const resultData = [];
13668
13993
  for (let i = 0; i < this.rows; i++) {
@@ -13693,7 +14018,7 @@ var dataStructureTyped = (() => {
13693
14018
  */
13694
14019
  multiply(matrix) {
13695
14020
  if (this.cols !== matrix.rows) {
13696
- throw new Error("Matrix dimensions must be compatible for multiplication (A.cols = B.rows).");
14021
+ throw new Error(ERR.matrixDimensionMismatch("multiplication (A.cols must equal B.rows)"));
13697
14022
  }
13698
14023
  const resultData = [];
13699
14024
  for (let i = 0; i < this.rows; i++) {
@@ -13727,7 +14052,7 @@ var dataStructureTyped = (() => {
13727
14052
  */
13728
14053
  transpose() {
13729
14054
  if (this.data.some((row) => row.length !== this.rows)) {
13730
- throw new Error("Matrix must be rectangular for transposition.");
14055
+ throw new Error(ERR.matrixNotRectangular());
13731
14056
  }
13732
14057
  const resultData = [];
13733
14058
  for (let j = 0; j < this.cols; j++) {
@@ -13752,7 +14077,7 @@ var dataStructureTyped = (() => {
13752
14077
  inverse() {
13753
14078
  var _a;
13754
14079
  if (this.rows !== this.cols) {
13755
- throw new Error("Matrix must be square for inversion.");
14080
+ throw new Error(ERR.matrixNotSquare());
13756
14081
  }
13757
14082
  const augmentedMatrixData = [];
13758
14083
  for (let i = 0; i < this.rows; i++) {
@@ -13774,12 +14099,12 @@ var dataStructureTyped = (() => {
13774
14099
  pivotRow++;
13775
14100
  }
13776
14101
  if (pivotRow === this.rows) {
13777
- throw new Error("Matrix is singular, and its inverse does not exist.");
14102
+ throw new Error(ERR.matrixSingular());
13778
14103
  }
13779
14104
  augmentedMatrix._swapRows(i, pivotRow);
13780
14105
  const pivotElement = (_a = augmentedMatrix.get(i, i)) != null ? _a : 1;
13781
14106
  if (pivotElement === 0) {
13782
- throw new Error("Matrix is singular, and its inverse does not exist (division by zero).");
14107
+ throw new Error(ERR.matrixSingular());
13783
14108
  }
13784
14109
  augmentedMatrix._scaleRow(i, 1 / pivotElement);
13785
14110
  for (let j = 0; j < this.rows; j++) {
@@ -13809,9 +14134,7 @@ var dataStructureTyped = (() => {
13809
14134
  */
13810
14135
  dot(matrix) {
13811
14136
  if (this.cols !== matrix.rows) {
13812
- throw new Error(
13813
- "Number of columns in the first matrix must be equal to the number of rows in the second matrix for dot product."
13814
- );
14137
+ throw new Error(ERR.matrixDimensionMismatch("dot product (A.cols must equal B.rows)"));
13815
14138
  }
13816
14139
  const resultData = [];
13817
14140
  for (let i = 0; i < this.rows; i++) {
@@ -14425,7 +14748,7 @@ var dataStructureTyped = (() => {
14425
14748
  for (const x of this) {
14426
14749
  const v = thisArg === void 0 ? callback(x, i++, this) : callback.call(thisArg, x, i++, this);
14427
14750
  if (typeof v !== "string") {
14428
- throw new TypeError(`Trie.map callback must return string; got ${typeof v}`);
14751
+ throw new TypeError(ERR.callbackReturnType("string", typeof v, "Trie.map"));
14429
14752
  }
14430
14753
  newTrie.add(v);
14431
14754
  }
@@ -14455,12 +14778,11 @@ var dataStructureTyped = (() => {
14455
14778
  */
14456
14779
  _createInstance(options) {
14457
14780
  const Ctor = this.constructor;
14458
- const next = new Ctor([], {
14781
+ return new Ctor([], {
14459
14782
  toElementFn: this.toElementFn,
14460
14783
  caseSensitive: this.caseSensitive,
14461
14784
  ...options != null ? options : {}
14462
14785
  });
14463
- return next;
14464
14786
  }
14465
14787
  /**
14466
14788
  * (Protected) Create a like-kind trie and seed it from an iterable.