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
@@ -193,6 +193,54 @@ var _IterableEntryBase = class _IterableEntryBase {
193
193
  __name(_IterableEntryBase, "IterableEntryBase");
194
194
  var IterableEntryBase = _IterableEntryBase;
195
195
 
196
+ // src/common/error.ts
197
+ var ERR = {
198
+ // Range / index
199
+ indexOutOfRange: /* @__PURE__ */ __name((index, min, max, ctx) => `${ctx ? ctx + ": " : ""}Index ${index} is out of range [${min}, ${max}].`, "indexOutOfRange"),
200
+ invalidIndex: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}Index must be an integer.`, "invalidIndex"),
201
+ // Type / argument
202
+ invalidArgument: /* @__PURE__ */ __name((reason, ctx) => `${ctx ? ctx + ": " : ""}${reason}`, "invalidArgument"),
203
+ comparatorRequired: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}Comparator is required for non-number/non-string/non-Date keys.`, "comparatorRequired"),
204
+ invalidKey: /* @__PURE__ */ __name((reason, ctx) => `${ctx ? ctx + ": " : ""}${reason}`, "invalidKey"),
205
+ notAFunction: /* @__PURE__ */ __name((name, ctx) => `${ctx ? ctx + ": " : ""}${name} must be a function.`, "notAFunction"),
206
+ invalidEntry: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}Each entry must be a [key, value] tuple.`, "invalidEntry"),
207
+ invalidNaN: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}NaN is not a valid key.`, "invalidNaN"),
208
+ invalidDate: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}Invalid Date key.`, "invalidDate"),
209
+ reduceEmpty: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}Reduce of empty structure with no initial value.`, "reduceEmpty"),
210
+ callbackReturnType: /* @__PURE__ */ __name((expected, got, ctx) => `${ctx ? ctx + ": " : ""}Callback must return ${expected}; got ${got}.`, "callbackReturnType"),
211
+ // State / operation
212
+ invalidOperation: /* @__PURE__ */ __name((reason, ctx) => `${ctx ? ctx + ": " : ""}${reason}`, "invalidOperation"),
213
+ // Matrix
214
+ matrixDimensionMismatch: /* @__PURE__ */ __name((op) => `Matrix: Dimensions must be compatible for ${op}.`, "matrixDimensionMismatch"),
215
+ matrixSingular: /* @__PURE__ */ __name(() => "Matrix: Singular matrix, inverse does not exist.", "matrixSingular"),
216
+ matrixNotSquare: /* @__PURE__ */ __name(() => "Matrix: Must be square for inversion.", "matrixNotSquare"),
217
+ matrixNotRectangular: /* @__PURE__ */ __name(() => "Matrix: Must be rectangular for transposition.", "matrixNotRectangular"),
218
+ matrixRowMismatch: /* @__PURE__ */ __name((expected, got) => `Matrix: Expected row length ${expected}, but got ${got}.`, "matrixRowMismatch")
219
+ };
220
+
221
+ // src/common/index.ts
222
+ var DFSOperation = /* @__PURE__ */ ((DFSOperation2) => {
223
+ DFSOperation2[DFSOperation2["VISIT"] = 0] = "VISIT";
224
+ DFSOperation2[DFSOperation2["PROCESS"] = 1] = "PROCESS";
225
+ return DFSOperation2;
226
+ })(DFSOperation || {});
227
+ var _Range = class _Range {
228
+ constructor(low, high, includeLow = true, includeHigh = true) {
229
+ this.low = low;
230
+ this.high = high;
231
+ this.includeLow = includeLow;
232
+ this.includeHigh = includeHigh;
233
+ }
234
+ // Determine whether a key is within the range
235
+ isInRange(key, comparator) {
236
+ const lowCheck = this.includeLow ? comparator(key, this.low) >= 0 : comparator(key, this.low) > 0;
237
+ const highCheck = this.includeHigh ? comparator(key, this.high) <= 0 : comparator(key, this.high) < 0;
238
+ return lowCheck && highCheck;
239
+ }
240
+ };
241
+ __name(_Range, "Range");
242
+ var Range = _Range;
243
+
196
244
  // src/data-structures/base/iterable-element-base.ts
197
245
  var _IterableElementBase = class _IterableElementBase {
198
246
  /**
@@ -215,7 +263,7 @@ var _IterableElementBase = class _IterableElementBase {
215
263
  if (options) {
216
264
  const { toElementFn } = options;
217
265
  if (typeof toElementFn === "function") this._toElementFn = toElementFn;
218
- else if (toElementFn) throw new TypeError("toElementFn must be a function type");
266
+ else if (toElementFn) throw new TypeError(ERR.notAFunction("toElementFn"));
219
267
  }
220
268
  }
221
269
  /**
@@ -371,7 +419,7 @@ var _IterableElementBase = class _IterableElementBase {
371
419
  acc = initialValue;
372
420
  } else {
373
421
  const first = iter.next();
374
- if (first.done) throw new TypeError("Reduce of empty structure with no initial value");
422
+ if (first.done) throw new TypeError(ERR.reduceEmpty());
375
423
  acc = first.value;
376
424
  index = 1;
377
425
  }
@@ -441,8 +489,10 @@ var getMSB = /* @__PURE__ */ __name((value) => {
441
489
  }
442
490
  return 1 << 31 - Math.clz32(value);
443
491
  }, "getMSB");
444
- var rangeCheck = /* @__PURE__ */ __name((index, min, max, message = "Index out of bounds.") => {
445
- if (index < min || index > max) throw new RangeError(message);
492
+ var rangeCheck = /* @__PURE__ */ __name((index, min, max, message) => {
493
+ if (index < min || index > max) {
494
+ throw new RangeError(message != null ? message : `Index ${index} is out of range [${min}, ${max}].`);
495
+ }
446
496
  }, "rangeCheck");
447
497
  var throwRangeError = /* @__PURE__ */ __name((message = "The value is off-limits.") => {
448
498
  throw new RangeError(message);
@@ -814,8 +864,8 @@ var _LinkedHashMap = class _LinkedHashMap extends IterableEntryBase {
814
864
  if (this.isEntry(rawElement)) {
815
865
  return rawElement;
816
866
  }
817
- throw new Error(
818
- "If `entryOrRawElements` does not adhere to [key,value], provide `options.toEntryFn` to transform raw records."
867
+ throw new TypeError(
868
+ ERR.invalidArgument("If elements do not adhere to [key, value], provide options.toEntryFn to transform raw records.", "HashMap")
819
869
  );
820
870
  }, "_toEntryFn"));
821
871
  __publicField(this, "_size", 0);
@@ -1025,8 +1075,9 @@ var _LinkedHashMap = class _LinkedHashMap extends IterableEntryBase {
1025
1075
  const cur = node;
1026
1076
  node = node.next;
1027
1077
  if (predicate(cur.key, cur.value, i++, this)) {
1028
- if (isWeakKey(cur.key)) {
1029
- this._objMap.delete(cur.key);
1078
+ const keyToCheck = cur.key;
1079
+ if (isWeakKey(keyToCheck)) {
1080
+ this._objMap.delete(keyToCheck);
1030
1081
  } else {
1031
1082
  const hash = this._hashFn(cur.key);
1032
1083
  delete this._noObjMap[hash];
@@ -1099,6 +1150,13 @@ var _LinkedHashMap = class _LinkedHashMap extends IterableEntryBase {
1099
1150
  }
1100
1151
  }
1101
1152
  _deleteNode(node) {
1153
+ const key = node.key;
1154
+ if (isWeakKey(key)) {
1155
+ this._objMap.delete(key);
1156
+ } else {
1157
+ const hash = this._hashFn(key);
1158
+ delete this._noObjMap[hash];
1159
+ }
1102
1160
  const { prev, next } = node;
1103
1161
  prev.next = next;
1104
1162
  next.prev = prev;
@@ -1544,7 +1602,7 @@ var _SinglyLinkedList = class _SinglyLinkedList extends LinearLinkedBase {
1544
1602
  */
1545
1603
  constructor(elements = [], options) {
1546
1604
  super(options);
1547
- __publicField(this, "_equals", Object.is);
1605
+ __publicField(this, "_equals", /* @__PURE__ */ __name((a, b) => Object.is(a, b), "_equals"));
1548
1606
  __publicField(this, "_head");
1549
1607
  __publicField(this, "_tail");
1550
1608
  __publicField(this, "_length", 0);
@@ -1632,6 +1690,7 @@ var _SinglyLinkedList = class _SinglyLinkedList extends LinearLinkedBase {
1632
1690
  * @returns Removed element or undefined.
1633
1691
  */
1634
1692
  pop() {
1693
+ var _a;
1635
1694
  if (!this.head) return void 0;
1636
1695
  if (this.head === this.tail) {
1637
1696
  const value2 = this.head.value;
@@ -1641,8 +1700,8 @@ var _SinglyLinkedList = class _SinglyLinkedList extends LinearLinkedBase {
1641
1700
  return value2;
1642
1701
  }
1643
1702
  let current = this.head;
1644
- while (current.next !== this.tail) current = current.next;
1645
- const value = this.tail.value;
1703
+ while (current.next && current.next !== this.tail) current = current.next;
1704
+ const value = (_a = this.tail) == null ? void 0 : _a.value;
1646
1705
  current.next = void 0;
1647
1706
  this._tail = current;
1648
1707
  this._length--;
@@ -1730,8 +1789,8 @@ var _SinglyLinkedList = class _SinglyLinkedList extends LinearLinkedBase {
1730
1789
  at(index) {
1731
1790
  if (index < 0 || index >= this._length) return void 0;
1732
1791
  let current = this.head;
1733
- for (let i = 0; i < index; i++) current = current.next;
1734
- return current.value;
1792
+ for (let i = 0; i < index && current; i++) current = current.next;
1793
+ return current == null ? void 0 : current.value;
1735
1794
  }
1736
1795
  /**
1737
1796
  * Type guard: check whether the input is a SinglyLinkedListNode.
@@ -1751,7 +1810,7 @@ var _SinglyLinkedList = class _SinglyLinkedList extends LinearLinkedBase {
1751
1810
  getNodeAt(index) {
1752
1811
  if (index < 0 || index >= this._length) return void 0;
1753
1812
  let current = this.head;
1754
- for (let i = 0; i < index; i++) current = current.next;
1813
+ for (let i = 0; i < index && current; i++) current = current.next;
1755
1814
  return current;
1756
1815
  }
1757
1816
  /**
@@ -2267,7 +2326,7 @@ var _DoublyLinkedList = class _DoublyLinkedList extends LinearLinkedBase {
2267
2326
  */
2268
2327
  constructor(elements = [], options) {
2269
2328
  super(options);
2270
- __publicField(this, "_equals", Object.is);
2329
+ __publicField(this, "_equals", /* @__PURE__ */ __name((a, b) => Object.is(a, b), "_equals"));
2271
2330
  __publicField(this, "_head");
2272
2331
  __publicField(this, "_tail");
2273
2332
  __publicField(this, "_length", 0);
@@ -2455,8 +2514,8 @@ var _DoublyLinkedList = class _DoublyLinkedList extends LinearLinkedBase {
2455
2514
  at(index) {
2456
2515
  if (index < 0 || index >= this._length) return void 0;
2457
2516
  let current = this.head;
2458
- for (let i = 0; i < index; i++) current = current.next;
2459
- return current.value;
2517
+ for (let i = 0; i < index && current; i++) current = current.next;
2518
+ return current == null ? void 0 : current.value;
2460
2519
  }
2461
2520
  /**
2462
2521
  * Get the node reference at a given index.
@@ -2467,7 +2526,7 @@ var _DoublyLinkedList = class _DoublyLinkedList extends LinearLinkedBase {
2467
2526
  getNodeAt(index) {
2468
2527
  if (index < 0 || index >= this._length) return void 0;
2469
2528
  let current = this.head;
2470
- for (let i = 0; i < index; i++) current = current.next;
2529
+ for (let i = 0; i < index && current; i++) current = current.next;
2471
2530
  return current;
2472
2531
  }
2473
2532
  /**
@@ -2979,7 +3038,7 @@ var _Stack = class _Stack extends IterableElementBase {
2979
3038
  */
2980
3039
  constructor(elements = [], options) {
2981
3040
  super(options);
2982
- __publicField(this, "_equals", Object.is);
3041
+ __publicField(this, "_equals", /* @__PURE__ */ __name((a, b) => Object.is(a, b), "_equals"));
2983
3042
  __publicField(this, "_elements", []);
2984
3043
  this.pushMany(elements);
2985
3044
  }
@@ -3605,17 +3664,16 @@ var LinkedListQueue = _LinkedListQueue;
3605
3664
 
3606
3665
  // src/data-structures/queue/deque.ts
3607
3666
  var _Deque = class _Deque extends LinearBase {
3608
- /**
3609
- * Create a Deque and optionally bulk-insert elements.
3610
- * @remarks Time O(N), Space O(N)
3611
- * @param [elements] - Iterable (or iterable-like) of elements/records to insert.
3612
- * @param [options] - Options such as bucketSize, toElementFn, and maxLen.
3613
- * @returns New Deque instance.
3614
- */
3615
3667
  constructor(elements = [], options) {
3616
3668
  super(options);
3617
- __publicField(this, "_equals", Object.is);
3669
+ __publicField(this, "_equals", /* @__PURE__ */ __name((a, b) => Object.is(a, b), "_equals"));
3618
3670
  __publicField(this, "_bucketSize", 1 << 12);
3671
+ __publicField(this, "_autoCompactRatio", 0.5);
3672
+ /**
3673
+ * Counter for shift/pop operations since last compaction check.
3674
+ * Only checks ratio every `_bucketSize` operations to minimize overhead.
3675
+ */
3676
+ __publicField(this, "_compactCounter", 0);
3619
3677
  __publicField(this, "_bucketFirst", 0);
3620
3678
  __publicField(this, "_firstInBucket", 0);
3621
3679
  __publicField(this, "_bucketLast", 0);
@@ -3624,8 +3682,9 @@ var _Deque = class _Deque extends LinearBase {
3624
3682
  __publicField(this, "_buckets", []);
3625
3683
  __publicField(this, "_length", 0);
3626
3684
  if (options) {
3627
- const { bucketSize } = options;
3685
+ const { bucketSize, autoCompactRatio } = options;
3628
3686
  if (typeof bucketSize === "number") this._bucketSize = bucketSize;
3687
+ if (typeof autoCompactRatio === "number") this._autoCompactRatio = autoCompactRatio;
3629
3688
  }
3630
3689
  let _size;
3631
3690
  if ("length" in elements) {
@@ -3650,6 +3709,24 @@ var _Deque = class _Deque extends LinearBase {
3650
3709
  get bucketSize() {
3651
3710
  return this._bucketSize;
3652
3711
  }
3712
+ /**
3713
+ * Get the auto-compaction ratio.
3714
+ * When `elements / (bucketCount * bucketSize)` drops below this ratio after
3715
+ * enough shift/pop operations, the deque auto-compacts.
3716
+ * @remarks Time O(1), Space O(1)
3717
+ * @returns Current ratio threshold. 0 means auto-compact is disabled.
3718
+ */
3719
+ get autoCompactRatio() {
3720
+ return this._autoCompactRatio;
3721
+ }
3722
+ /**
3723
+ * Set the auto-compaction ratio.
3724
+ * @remarks Time O(1), Space O(1)
3725
+ * @param value - Ratio in [0,1]. 0 disables auto-compact.
3726
+ */
3727
+ set autoCompactRatio(value) {
3728
+ this._autoCompactRatio = value;
3729
+ }
3653
3730
  /**
3654
3731
  * Get the index of the first bucket in use.
3655
3732
  * @remarks Time O(1), Space O(1)
@@ -3781,6 +3858,7 @@ var _Deque = class _Deque extends LinearBase {
3781
3858
  }
3782
3859
  }
3783
3860
  this._length -= 1;
3861
+ this._autoCompact();
3784
3862
  return element;
3785
3863
  }
3786
3864
  /**
@@ -3803,6 +3881,7 @@ var _Deque = class _Deque extends LinearBase {
3803
3881
  }
3804
3882
  }
3805
3883
  this._length -= 1;
3884
+ this._autoCompact();
3806
3885
  return element;
3807
3886
  }
3808
3887
  /**
@@ -4135,11 +4214,40 @@ var _Deque = class _Deque extends LinearBase {
4135
4214
  * @remarks Time O(N), Space O(1)
4136
4215
  * @returns void
4137
4216
  */
4217
+ /**
4218
+ * (Protected) Trigger auto-compaction if space utilization drops below threshold.
4219
+ * Only checks every `_bucketSize` operations to minimize hot-path overhead.
4220
+ * Uses element-based ratio: `elements / (bucketCount * bucketSize)`.
4221
+ */
4222
+ _autoCompact() {
4223
+ if (this._autoCompactRatio <= 0 || this._bucketCount <= 1) return;
4224
+ this._compactCounter++;
4225
+ if (this._compactCounter < this._bucketSize) return;
4226
+ this._compactCounter = 0;
4227
+ const utilization = this._length / (this._bucketCount * this._bucketSize);
4228
+ if (utilization < this._autoCompactRatio) {
4229
+ this.shrinkToFit();
4230
+ }
4231
+ }
4232
+ /**
4233
+ * Compact the deque by removing unused buckets.
4234
+ * @remarks Time O(N), Space O(1)
4235
+ * @returns True if compaction was performed (bucket count reduced).
4236
+ */
4237
+ /**
4238
+ * Compact the deque by removing unused buckets.
4239
+ * @remarks Time O(N), Space O(1)
4240
+ * @returns True if compaction was performed (bucket count reduced).
4241
+ */
4242
+ compact() {
4243
+ const before = this._bucketCount;
4244
+ this.shrinkToFit();
4245
+ return this._bucketCount < before;
4246
+ }
4138
4247
  shrinkToFit() {
4139
4248
  if (this._length === 0) return;
4140
4249
  const newBuckets = [];
4141
- if (this._bucketFirst === this._bucketLast) return;
4142
- else if (this._bucketFirst < this._bucketLast) {
4250
+ if (this._bucketFirst <= this._bucketLast) {
4143
4251
  for (let i = this._bucketFirst; i <= this._bucketLast; ++i) {
4144
4252
  newBuckets.push(this._buckets[i]);
4145
4253
  }
@@ -4154,6 +4262,8 @@ var _Deque = class _Deque extends LinearBase {
4154
4262
  this._bucketFirst = 0;
4155
4263
  this._bucketLast = newBuckets.length - 1;
4156
4264
  this._buckets = newBuckets;
4265
+ this._bucketCount = newBuckets.length;
4266
+ this._compactCounter = 0;
4157
4267
  }
4158
4268
  /**
4159
4269
  * Deep clone this deque, preserving options.
@@ -4351,7 +4461,7 @@ var _Heap = class _Heap extends IterableElementBase {
4351
4461
  __publicField(this, "_elements", []);
4352
4462
  __publicField(this, "_DEFAULT_COMPARATOR", /* @__PURE__ */ __name((a, b) => {
4353
4463
  if (typeof a === "object" || typeof b === "object") {
4354
- throw TypeError("When comparing object types, define a custom comparator in options.");
4464
+ throw new TypeError(ERR.comparatorRequired("Heap"));
4355
4465
  }
4356
4466
  if (a > b) return 1;
4357
4467
  if (a < b) return -1;
@@ -4661,7 +4771,7 @@ var _Heap = class _Heap extends IterableElementBase {
4661
4771
  */
4662
4772
  map(callback, options, thisArg) {
4663
4773
  const { comparator, toElementFn, ...rest } = options != null ? options : {};
4664
- if (!comparator) throw new TypeError("Heap.map requires options.comparator for EM");
4774
+ if (!comparator) throw new TypeError(ERR.comparatorRequired("Heap.map"));
4665
4775
  const out = this._createLike([], { ...rest, comparator, toElementFn });
4666
4776
  let i = 0;
4667
4777
  for (const x of this) {
@@ -4686,11 +4796,6 @@ var _Heap = class _Heap extends IterableElementBase {
4686
4796
  }
4687
4797
  return out;
4688
4798
  }
4689
- /**
4690
- * Get the comparator used to order elements.
4691
- * @remarks Time O(1), Space O(1)
4692
- * @returns Comparator function.
4693
- */
4694
4799
  /**
4695
4800
  * Get the comparator used to order elements.
4696
4801
  * @remarks Time O(1), Space O(1)
@@ -4739,8 +4844,7 @@ var _Heap = class _Heap extends IterableElementBase {
4739
4844
  */
4740
4845
  _createInstance(options) {
4741
4846
  const Ctor = this.constructor;
4742
- const next = new Ctor([], { comparator: this.comparator, toElementFn: this.toElementFn, ...options != null ? options : {} });
4743
- return next;
4847
+ return new Ctor([], { comparator: this.comparator, toElementFn: this.toElementFn, ...options != null ? options : {} });
4744
4848
  }
4745
4849
  /**
4746
4850
  * (Protected) Create a like-kind instance seeded by elements.
@@ -4799,7 +4903,7 @@ var _FibonacciHeap = class _FibonacciHeap {
4799
4903
  __publicField(this, "_comparator");
4800
4904
  this.clear();
4801
4905
  this._comparator = comparator || this._defaultComparator;
4802
- if (typeof this.comparator !== "function") throw new Error("FibonacciHeap: comparator must be a function.");
4906
+ if (typeof this.comparator !== "function") throw new TypeError(ERR.notAFunction("comparator", "FibonacciHeap"));
4803
4907
  }
4804
4908
  /**
4805
4909
  * Get the circular root list head.
@@ -5010,9 +5114,7 @@ var _MaxHeap = class _MaxHeap extends Heap {
5010
5114
  super(elements, {
5011
5115
  comparator: /* @__PURE__ */ __name((a, b) => {
5012
5116
  if (typeof a === "object" || typeof b === "object") {
5013
- throw TypeError(
5014
- `When comparing object types, a custom comparator must be defined in the constructor's options parameter.`
5015
- );
5117
+ throw new TypeError(ERR.comparatorRequired("MaxHeap"));
5016
5118
  }
5017
5119
  if (a < b) return 1;
5018
5120
  if (a > b) return -1;
@@ -5177,7 +5279,7 @@ var _AbstractGraph = class _AbstractGraph extends IterableEntryBase {
5177
5279
  const newEdge = this.createEdge(srcOrEdge, dest, weight, value);
5178
5280
  return this._addEdge(newEdge);
5179
5281
  } else {
5180
- throw new Error("dest must be a Vertex or vertex key while srcOrEdge is an Edge");
5282
+ throw new TypeError(ERR.invalidArgument("dest must be a Vertex or vertex key when srcOrEdge is an Edge.", "Graph"));
5181
5283
  }
5182
5284
  }
5183
5285
  }
@@ -5786,8 +5888,8 @@ var _AbstractGraph = class _AbstractGraph extends IterableEntryBase {
5786
5888
  const Ctor = this.constructor;
5787
5889
  const instance = new Ctor();
5788
5890
  const graph = _options == null ? void 0 : _options.graph;
5789
- if (graph) instance._options = { ...instance._options, ...graph };
5790
- else instance._options = { ...instance._options, ...this._options };
5891
+ if (graph) instance["_options"] = { ...instance["_options"], ...graph };
5892
+ else instance["_options"] = { ...instance["_options"], ...this._options };
5791
5893
  return instance;
5792
5894
  }
5793
5895
  /**
@@ -5820,12 +5922,10 @@ var _AbstractGraph = class _AbstractGraph extends IterableEntryBase {
5820
5922
  const [va, vb] = ends;
5821
5923
  const ka = va.key;
5822
5924
  const kb = vb.key;
5823
- const hasA = g.hasVertex ? g.hasVertex(ka) : false;
5824
- const hasB = g.hasVertex ? g.hasVertex(kb) : false;
5925
+ const hasA = typeof g.hasVertex === "function" ? g.hasVertex(ka) : false;
5926
+ const hasB = typeof g.hasVertex === "function" ? g.hasVertex(kb) : false;
5825
5927
  if (hasA && hasB) {
5826
- const w = e.weight;
5827
- const val = e.value;
5828
- const newEdge = g.createEdge(ka, kb, w, val);
5928
+ const newEdge = g.createEdge(ka, kb, e.weight, e.value);
5829
5929
  g._addEdge(newEdge);
5830
5930
  }
5831
5931
  }
@@ -5863,6 +5963,94 @@ var _AbstractGraph = class _AbstractGraph extends IterableEntryBase {
5863
5963
  _getVertexKey(vertexOrKey) {
5864
5964
  return vertexOrKey instanceof AbstractVertex ? vertexOrKey.key : vertexOrKey;
5865
5965
  }
5966
+ /**
5967
+ * The edge connector string used in visual output.
5968
+ * Override in subclasses (e.g., '--' for undirected, '->' for directed).
5969
+ */
5970
+ get _edgeConnector() {
5971
+ return "--";
5972
+ }
5973
+ /**
5974
+ * Generate a text-based visual representation of the graph.
5975
+ *
5976
+ * **Adjacency list format:**
5977
+ * ```
5978
+ * Graph (5 vertices, 6 edges):
5979
+ * A -> B (1), C (2)
5980
+ * B -> D (3)
5981
+ * C -> (no outgoing edges)
5982
+ * D -> A (1)
5983
+ * E (isolated)
5984
+ * ```
5985
+ *
5986
+ * @param options - Optional display settings.
5987
+ * @param options.showWeight - Whether to show edge weights (default: true).
5988
+ * @returns The visual string.
5989
+ */
5990
+ toVisual(options) {
5991
+ var _a;
5992
+ const showWeight = (_a = options == null ? void 0 : options.showWeight) != null ? _a : true;
5993
+ const vertices = [...this._vertexMap.values()];
5994
+ const vertexCount = vertices.length;
5995
+ const edgeCount = this.edgeSet().length;
5996
+ const lines = [`Graph (${vertexCount} vertices, ${edgeCount} edges):`];
5997
+ for (const vertex of vertices) {
5998
+ const neighbors = this.getNeighbors(vertex);
5999
+ if (neighbors.length === 0) {
6000
+ lines.push(` ${vertex.key} (isolated)`);
6001
+ } else {
6002
+ const edgeStrs = neighbors.map((neighbor) => {
6003
+ const edge = this.getEdge(vertex, neighbor);
6004
+ if (edge && showWeight && edge.weight !== void 0 && edge.weight !== 1) {
6005
+ return `${neighbor.key} (${edge.weight})`;
6006
+ }
6007
+ return `${neighbor.key}`;
6008
+ });
6009
+ lines.push(` ${vertex.key} ${this._edgeConnector} ${edgeStrs.join(", ")}`);
6010
+ }
6011
+ }
6012
+ return lines.join("\n");
6013
+ }
6014
+ /**
6015
+ * Generate DOT language representation for Graphviz.
6016
+ *
6017
+ * @param options - Optional display settings.
6018
+ * @param options.name - Graph name (default: 'G').
6019
+ * @param options.showWeight - Whether to label edges with weight (default: true).
6020
+ * @returns DOT format string.
6021
+ */
6022
+ toDot(options) {
6023
+ var _a, _b;
6024
+ const name = (_a = options == null ? void 0 : options.name) != null ? _a : "G";
6025
+ const showWeight = (_b = options == null ? void 0 : options.showWeight) != null ? _b : true;
6026
+ const isDirected = this._edgeConnector === "->";
6027
+ const graphType = isDirected ? "digraph" : "graph";
6028
+ const edgeOp = isDirected ? "->" : "--";
6029
+ const lines = [`${graphType} ${name} {`];
6030
+ for (const vertex of this._vertexMap.values()) {
6031
+ lines.push(` "${vertex.key}";`);
6032
+ }
6033
+ const visited = /* @__PURE__ */ new Set();
6034
+ for (const vertex of this._vertexMap.values()) {
6035
+ for (const neighbor of this.getNeighbors(vertex)) {
6036
+ const edgeId = isDirected ? `${vertex.key}->${neighbor.key}` : [vertex.key, neighbor.key].sort().join("--");
6037
+ if (visited.has(edgeId)) continue;
6038
+ visited.add(edgeId);
6039
+ const edge = this.getEdge(vertex, neighbor);
6040
+ const label = edge && showWeight && edge.weight !== void 0 && edge.weight !== 1 ? ` [label="${edge.weight}"]` : "";
6041
+ lines.push(` "${vertex.key}" ${edgeOp} "${neighbor.key}"${label};`);
6042
+ }
6043
+ }
6044
+ lines.push("}");
6045
+ return lines.join("\n");
6046
+ }
6047
+ /**
6048
+ * Print the graph to console.
6049
+ * @param options - Display settings passed to `toVisual`.
6050
+ */
6051
+ print(options) {
6052
+ console.log(this.toVisual(options));
6053
+ }
5866
6054
  };
5867
6055
  __name(_AbstractGraph, "AbstractGraph");
5868
6056
  var AbstractGraph = _AbstractGraph;
@@ -5897,6 +6085,9 @@ var _DirectedGraph = class _DirectedGraph extends AbstractGraph {
5897
6085
  __publicField(this, "_outEdgeMap", /* @__PURE__ */ new Map());
5898
6086
  __publicField(this, "_inEdgeMap", /* @__PURE__ */ new Map());
5899
6087
  }
6088
+ get _edgeConnector() {
6089
+ return "->";
6090
+ }
5900
6091
  get outEdgeMap() {
5901
6092
  return this._outEdgeMap;
5902
6093
  }
@@ -6677,6 +6868,84 @@ var _UndirectedGraph = class _UndirectedGraph extends AbstractGraph {
6677
6868
  cutVertices
6678
6869
  };
6679
6870
  }
6871
+ /**
6872
+ * Find biconnected components using edge-stack Tarjan variant.
6873
+ * A biconnected component is a maximal biconnected subgraph.
6874
+ * @returns Array of edge arrays, each representing a biconnected component.
6875
+ * @remarks Time O(V + E), Space O(V + E)
6876
+ */
6877
+ getBiconnectedComponents() {
6878
+ const dfn = /* @__PURE__ */ new Map();
6879
+ const low = /* @__PURE__ */ new Map();
6880
+ const edgeStack = [];
6881
+ const components = [];
6882
+ let time = 0;
6883
+ const dfs = /* @__PURE__ */ __name((vertex, parent) => {
6884
+ dfn.set(vertex, time);
6885
+ low.set(vertex, time);
6886
+ time++;
6887
+ const neighbors = this.getNeighbors(vertex);
6888
+ let childCount = 0;
6889
+ for (const neighbor of neighbors) {
6890
+ const edge = this.getEdge(vertex, neighbor);
6891
+ if (!edge) continue;
6892
+ if (!dfn.has(neighbor)) {
6893
+ childCount++;
6894
+ edgeStack.push(edge);
6895
+ dfs(neighbor, vertex);
6896
+ low.set(vertex, Math.min(low.get(vertex), low.get(neighbor)));
6897
+ if (parent === void 0 && childCount > 1 || parent !== void 0 && low.get(neighbor) >= dfn.get(vertex)) {
6898
+ const component = [];
6899
+ let e;
6900
+ do {
6901
+ e = edgeStack.pop();
6902
+ if (e) component.push(e);
6903
+ } while (e && e !== edge);
6904
+ if (component.length > 0) components.push(component);
6905
+ }
6906
+ } else if (neighbor !== parent && dfn.get(neighbor) < dfn.get(vertex)) {
6907
+ edgeStack.push(edge);
6908
+ low.set(vertex, Math.min(low.get(vertex), dfn.get(neighbor)));
6909
+ }
6910
+ }
6911
+ }, "dfs");
6912
+ for (const vertex of this.vertexMap.values()) {
6913
+ if (!dfn.has(vertex)) {
6914
+ dfs(vertex, void 0);
6915
+ if (edgeStack.length > 0) {
6916
+ components.push([...edgeStack]);
6917
+ edgeStack.length = 0;
6918
+ }
6919
+ }
6920
+ }
6921
+ return components;
6922
+ }
6923
+ /**
6924
+ * Detect whether the graph contains a cycle.
6925
+ * Uses DFS with parent tracking.
6926
+ * @returns `true` if a cycle exists, `false` otherwise.
6927
+ * @remarks Time O(V + E), Space O(V)
6928
+ */
6929
+ hasCycle() {
6930
+ const visited = /* @__PURE__ */ new Set();
6931
+ const dfs = /* @__PURE__ */ __name((vertex, parent) => {
6932
+ visited.add(vertex);
6933
+ for (const neighbor of this.getNeighbors(vertex)) {
6934
+ if (!visited.has(neighbor)) {
6935
+ if (dfs(neighbor, vertex)) return true;
6936
+ } else if (neighbor !== parent) {
6937
+ return true;
6938
+ }
6939
+ }
6940
+ return false;
6941
+ }, "dfs");
6942
+ for (const vertex of this.vertexMap.values()) {
6943
+ if (!visited.has(vertex)) {
6944
+ if (dfs(vertex, void 0)) return true;
6945
+ }
6946
+ }
6947
+ return false;
6948
+ }
6680
6949
  /**
6681
6950
  * Get bridges discovered by `tarjan()`.
6682
6951
  * @returns Array of edges that are bridges.
@@ -6829,29 +7098,6 @@ var _MapGraph = class _MapGraph extends DirectedGraph {
6829
7098
  __name(_MapGraph, "MapGraph");
6830
7099
  var MapGraph = _MapGraph;
6831
7100
 
6832
- // src/common/index.ts
6833
- var DFSOperation = /* @__PURE__ */ ((DFSOperation2) => {
6834
- DFSOperation2[DFSOperation2["VISIT"] = 0] = "VISIT";
6835
- DFSOperation2[DFSOperation2["PROCESS"] = 1] = "PROCESS";
6836
- return DFSOperation2;
6837
- })(DFSOperation || {});
6838
- var _Range = class _Range {
6839
- constructor(low, high, includeLow = true, includeHigh = true) {
6840
- this.low = low;
6841
- this.high = high;
6842
- this.includeLow = includeLow;
6843
- this.includeHigh = includeHigh;
6844
- }
6845
- // Determine whether a key is within the range
6846
- isInRange(key, comparator) {
6847
- const lowCheck = this.includeLow ? comparator(key, this.low) >= 0 : comparator(key, this.low) > 0;
6848
- const highCheck = this.includeHigh ? comparator(key, this.high) <= 0 : comparator(key, this.high) < 0;
6849
- return lowCheck && highCheck;
6850
- }
6851
- };
6852
- __name(_Range, "Range");
6853
- var Range = _Range;
6854
-
6855
7101
  // src/data-structures/binary-tree/binary-tree.ts
6856
7102
  var _BinaryTreeNode = class _BinaryTreeNode {
6857
7103
  /**
@@ -7017,14 +7263,14 @@ var _BinaryTree = class _BinaryTree extends IterableEntryBase {
7017
7263
  * @param node - The node.
7018
7264
  * @returns The node's key or undefined.
7019
7265
  */
7020
- __publicField(this, "_DEFAULT_NODE_CALLBACK", /* @__PURE__ */ __name((node) => node ? node.key : void 0, "_DEFAULT_NODE_CALLBACK"));
7266
+ __publicField(this, "_DEFAULT_NODE_CALLBACK", /* @__PURE__ */ __name((node) => node == null ? void 0 : node.key, "_DEFAULT_NODE_CALLBACK"));
7021
7267
  if (options) {
7022
7268
  const { iterationType, toEntryFn, isMapMode, isDuplicate } = options;
7023
7269
  if (iterationType) this.iterationType = iterationType;
7024
7270
  if (isMapMode !== void 0) this._isMapMode = isMapMode;
7025
7271
  if (isDuplicate !== void 0) this._isDuplicate = isDuplicate;
7026
7272
  if (typeof toEntryFn === "function") this._toEntryFn = toEntryFn;
7027
- else if (toEntryFn) throw TypeError("toEntryFn must be a function type");
7273
+ else if (toEntryFn) throw new TypeError(ERR.notAFunction("toEntryFn", "BinaryTree"));
7028
7274
  }
7029
7275
  if (keysNodesEntriesOrRaws) this.setMany(keysNodesEntriesOrRaws);
7030
7276
  }
@@ -7252,7 +7498,7 @@ var _BinaryTree = class _BinaryTree extends IterableEntryBase {
7252
7498
  if (!this._root) {
7253
7499
  this._setRoot(newNode);
7254
7500
  if (this._isMapMode && newNode !== null && newNode !== void 0) this._store.set(newNode.key, newNode);
7255
- this._size = 1;
7501
+ if (newNode !== null) this._size = 1;
7256
7502
  return true;
7257
7503
  }
7258
7504
  const queue = new Queue([this._root]);
@@ -7284,7 +7530,7 @@ var _BinaryTree = class _BinaryTree extends IterableEntryBase {
7284
7530
  potentialParent.right = newNode;
7285
7531
  }
7286
7532
  if (this._isMapMode && newNode !== null && newNode !== void 0) this._store.set(newNode.key, newNode);
7287
- this._size++;
7533
+ if (newNode !== null) this._size++;
7288
7534
  return true;
7289
7535
  }
7290
7536
  return false;
@@ -7853,7 +8099,7 @@ var _BinaryTree = class _BinaryTree extends IterableEntryBase {
7853
8099
  }
7854
8100
  /**
7855
8101
  * Finds all leaf nodes in the tree.
7856
- * @remarks Time O(N), visits every node. Space O(H) for recursive stack or O(N) for iterative queue.
8102
+ * @remarks Time O(N), visits every node. Space O(H) for recursive or iterative stack.
7857
8103
  *
7858
8104
  * @template C - The type of the callback function.
7859
8105
  * @param [callback=this._DEFAULT_NODE_CALLBACK] - Function to call on each leaf node.
@@ -7876,15 +8122,15 @@ var _BinaryTree = class _BinaryTree extends IterableEntryBase {
7876
8122
  }, "dfs");
7877
8123
  dfs(startNode);
7878
8124
  } else {
7879
- const queue = new Queue([startNode]);
7880
- while (queue.length > 0) {
7881
- const cur = queue.shift();
8125
+ const stack = [startNode];
8126
+ while (stack.length > 0) {
8127
+ const cur = stack.pop();
7882
8128
  if (this.isRealNode(cur)) {
7883
8129
  if (this.isLeaf(cur)) {
7884
8130
  leaves.push(callback(cur));
7885
8131
  }
7886
- if (this.isRealNode(cur.left)) queue.push(cur.left);
7887
- if (this.isRealNode(cur.right)) queue.push(cur.right);
8132
+ if (this.isRealNode(cur.right)) stack.push(cur.right);
8133
+ if (this.isRealNode(cur.left)) stack.push(cur.left);
7888
8134
  }
7889
8135
  }
7890
8136
  }
@@ -8340,42 +8586,98 @@ var _BinaryTree = class _BinaryTree extends IterableEntryBase {
8340
8586
  _displayAux(node, options) {
8341
8587
  const { isShowNull, isShowUndefined, isShowRedBlackNIL } = options;
8342
8588
  const emptyDisplayLayout = [["\u2500"], 1, 0, 0];
8343
- if (node === null && !isShowNull) {
8344
- return emptyDisplayLayout;
8345
- } else if (node === void 0 && !isShowUndefined) {
8346
- return emptyDisplayLayout;
8347
- } else if (this.isNIL(node) && !isShowRedBlackNIL) {
8348
- return emptyDisplayLayout;
8349
- } else if (node !== null && node !== void 0) {
8350
- const key = node.key, line = this.isNIL(node) ? "S" : String(key), width = line.length;
8351
- return _buildNodeDisplay(
8352
- line,
8353
- width,
8354
- this._displayAux(node.left, options),
8355
- this._displayAux(node.right, options)
8356
- );
8357
- } else {
8358
- const line = node === void 0 ? "U" : "N", width = line.length;
8359
- return _buildNodeDisplay(line, width, [[""], 1, 0, 0], [[""], 1, 0, 0]);
8360
- }
8361
- function _buildNodeDisplay(line, width, left, right) {
8362
- const [leftLines, leftWidth, leftHeight, leftMiddle] = left;
8363
- const [rightLines, rightWidth, rightHeight, rightMiddle] = right;
8364
- 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));
8365
- const secondLine = (leftHeight > 0 ? " ".repeat(leftMiddle) + "/" + " ".repeat(leftWidth - leftMiddle - 1) : " ".repeat(leftWidth)) + " ".repeat(width) + (rightHeight > 0 ? " ".repeat(rightMiddle) + "\\" + " ".repeat(rightWidth - rightMiddle - 1) : " ".repeat(rightWidth));
8366
- const mergedLines = [firstLine, secondLine];
8367
- for (let i = 0; i < Math.max(leftHeight, rightHeight); i++) {
8368
- const leftLine = i < leftHeight ? leftLines[i] : " ".repeat(leftWidth);
8369
- const rightLine = i < rightHeight ? rightLines[i] : " ".repeat(rightWidth);
8370
- mergedLines.push(leftLine + " ".repeat(width) + rightLine);
8589
+ const newFrame = /* @__PURE__ */ __name((n) => ({
8590
+ node: n,
8591
+ stage: 0,
8592
+ leftLayout: emptyDisplayLayout,
8593
+ rightLayout: emptyDisplayLayout
8594
+ }), "newFrame");
8595
+ const stack = [newFrame(node)];
8596
+ let result = emptyDisplayLayout;
8597
+ const setChildResult = /* @__PURE__ */ __name((layout) => {
8598
+ if (stack.length === 0) {
8599
+ result = layout;
8600
+ return;
8371
8601
  }
8372
- return [
8373
- mergedLines,
8374
- leftWidth + width + rightWidth,
8375
- Math.max(leftHeight, rightHeight) + 2,
8376
- leftWidth + Math.floor(width / 2)
8377
- ];
8602
+ const parent = stack[stack.length - 1];
8603
+ if (parent.stage === 1) parent.leftLayout = layout;
8604
+ else parent.rightLayout = layout;
8605
+ }, "setChildResult");
8606
+ while (stack.length > 0) {
8607
+ const frame = stack[stack.length - 1];
8608
+ const cur = frame.node;
8609
+ if (frame.stage === 0) {
8610
+ if (this._isDisplayLeaf(cur, options)) {
8611
+ stack.pop();
8612
+ const layout = this._resolveDisplayLeaf(cur, options, emptyDisplayLayout);
8613
+ setChildResult(layout);
8614
+ continue;
8615
+ }
8616
+ frame.stage = 1;
8617
+ stack.push(newFrame(cur.left));
8618
+ } else if (frame.stage === 1) {
8619
+ frame.stage = 2;
8620
+ stack.push(newFrame(cur.right));
8621
+ } else {
8622
+ stack.pop();
8623
+ const line = this.isNIL(cur) ? "S" : String(cur.key);
8624
+ const layout = _BinaryTree._buildNodeDisplay(line, line.length, frame.leftLayout, frame.rightLayout);
8625
+ setChildResult(layout);
8626
+ }
8627
+ }
8628
+ return result;
8629
+ }
8630
+ static _buildNodeDisplay(line, width, left, right) {
8631
+ const [leftLines, leftWidth, leftHeight, leftMiddle] = left;
8632
+ const [rightLines, rightWidth, rightHeight, rightMiddle] = right;
8633
+ 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));
8634
+ const secondLine = (leftHeight > 0 ? " ".repeat(leftMiddle) + "/" + " ".repeat(leftWidth - leftMiddle - 1) : " ".repeat(leftWidth)) + " ".repeat(width) + (rightHeight > 0 ? " ".repeat(rightMiddle) + "\\" + " ".repeat(rightWidth - rightMiddle - 1) : " ".repeat(rightWidth));
8635
+ const mergedLines = [firstLine, secondLine];
8636
+ for (let i = 0; i < Math.max(leftHeight, rightHeight); i++) {
8637
+ const leftLine = i < leftHeight ? leftLines[i] : " ".repeat(leftWidth);
8638
+ const rightLine = i < rightHeight ? rightLines[i] : " ".repeat(rightWidth);
8639
+ mergedLines.push(leftLine + " ".repeat(width) + rightLine);
8378
8640
  }
8641
+ return [
8642
+ mergedLines,
8643
+ leftWidth + width + rightWidth,
8644
+ Math.max(leftHeight, rightHeight) + 2,
8645
+ leftWidth + Math.floor(width / 2)
8646
+ ];
8647
+ }
8648
+ /**
8649
+ * Check if a node is a display leaf (empty, null, undefined, NIL, or real leaf).
8650
+ */
8651
+ _isDisplayLeaf(node, options) {
8652
+ const { isShowNull, isShowUndefined, isShowRedBlackNIL } = options;
8653
+ if (node === null && !isShowNull) return true;
8654
+ if (node === void 0 && !isShowUndefined) return true;
8655
+ if (this.isNIL(node) && !isShowRedBlackNIL) return true;
8656
+ if (node === null || node === void 0) return true;
8657
+ const hasDisplayableLeft = this._hasDisplayableChild(node.left, options);
8658
+ const hasDisplayableRight = this._hasDisplayableChild(node.right, options);
8659
+ return !hasDisplayableLeft && !hasDisplayableRight;
8660
+ }
8661
+ _hasDisplayableChild(child, options) {
8662
+ if (child === null) return !!options.isShowNull;
8663
+ if (child === void 0) return !!options.isShowUndefined;
8664
+ if (this.isNIL(child)) return !!options.isShowRedBlackNIL;
8665
+ return true;
8666
+ }
8667
+ /**
8668
+ * Resolve a display leaf node to its layout.
8669
+ */
8670
+ _resolveDisplayLeaf(node, options, emptyDisplayLayout) {
8671
+ const { isShowNull, isShowUndefined, isShowRedBlackNIL } = options;
8672
+ if (node === null && !isShowNull) return emptyDisplayLayout;
8673
+ if (node === void 0 && !isShowUndefined) return emptyDisplayLayout;
8674
+ if (this.isNIL(node) && !isShowRedBlackNIL) return emptyDisplayLayout;
8675
+ if (node !== null && node !== void 0) {
8676
+ const line2 = this.isNIL(node) ? "S" : String(node.key);
8677
+ return _BinaryTree._buildNodeDisplay(line2, line2.length, emptyDisplayLayout, emptyDisplayLayout);
8678
+ }
8679
+ const line = node === void 0 ? "U" : "N";
8680
+ return _BinaryTree._buildNodeDisplay(line, line.length, [[""], 1, 0, 0], [[""], 1, 0, 0]);
8379
8681
  }
8380
8682
  /**
8381
8683
  * (Protected) Swaps the key/value properties of two nodes.
@@ -9381,9 +9683,15 @@ var _BST = class _BST extends BinaryTree {
9381
9683
  if (a < b) return -1;
9382
9684
  return 0;
9383
9685
  }
9686
+ if (a instanceof Date && b instanceof Date) {
9687
+ const ta = a.getTime();
9688
+ const tb = b.getTime();
9689
+ if (Number.isNaN(ta) || Number.isNaN(tb)) throw new TypeError(ERR.invalidDate("BST"));
9690
+ return ta > tb ? 1 : ta < tb ? -1 : 0;
9691
+ }
9384
9692
  if (typeof a === "object" || typeof b === "object") {
9385
- throw TypeError(
9386
- `When comparing object type keys, a custom comparator must be provided in the constructor's options!`
9693
+ throw new TypeError(
9694
+ ERR.comparatorRequired("BST")
9387
9695
  );
9388
9696
  }
9389
9697
  return 0;
@@ -9897,7 +10205,7 @@ var _BinaryIndexedTree = class _BinaryIndexedTree {
9897
10205
  */
9898
10206
  read(count) {
9899
10207
  if (!Number.isInteger(count)) {
9900
- throw new Error("Invalid count");
10208
+ throw new Error(ERR.invalidArgument("count must be an integer", "BinaryIndexedTree"));
9901
10209
  }
9902
10210
  return this._read(Math.max(Math.min(count, this.max), 0));
9903
10211
  }
@@ -9909,7 +10217,7 @@ var _BinaryIndexedTree = class _BinaryIndexedTree {
9909
10217
  */
9910
10218
  lowerBound(sum) {
9911
10219
  if (this.negativeCount > 0) {
9912
- throw new Error("Sequence is not non-descending");
10220
+ throw new Error(ERR.invalidOperation("Sequence is not non-descending.", "BinaryIndexedTree"));
9913
10221
  }
9914
10222
  return this._binarySearch(sum, (x, y) => x < y);
9915
10223
  }
@@ -9922,7 +10230,7 @@ var _BinaryIndexedTree = class _BinaryIndexedTree {
9922
10230
  */
9923
10231
  upperBound(sum) {
9924
10232
  if (this.negativeCount > 0) {
9925
- throw new Error("Must not be descending");
10233
+ throw new Error(ERR.invalidOperation("Sequence must not be descending.", "BinaryIndexedTree"));
9926
10234
  }
9927
10235
  return this._binarySearch(sum, (x, y) => x <= y);
9928
10236
  }
@@ -9973,10 +10281,10 @@ var _BinaryIndexedTree = class _BinaryIndexedTree {
9973
10281
  */
9974
10282
  _checkIndex(index) {
9975
10283
  if (!Number.isInteger(index)) {
9976
- throw new Error("Invalid index: Index must be an integer.");
10284
+ throw new TypeError(ERR.invalidIndex("BinaryIndexedTree"));
9977
10285
  }
9978
10286
  if (index < 0 || index >= this.max) {
9979
- throw new Error("Index out of range: Index must be within the range [0, this.max).");
10287
+ throw new RangeError(ERR.indexOutOfRange(index, 0, this.max - 1, "BinaryIndexedTree"));
9980
10288
  }
9981
10289
  }
9982
10290
  /**
@@ -11565,6 +11873,24 @@ var _RedBlackTree = class _RedBlackTree extends BST {
11565
11873
  * @param [thisArg] - See parameter type for details.
11566
11874
  * @returns A new RedBlackTree with mapped entries.
11567
11875
  */
11876
+ /**
11877
+ * Red-Black trees are self-balancing — `perfectlyBalance` rebuilds via
11878
+ * sorted bulk insert, which naturally produces a balanced RBT.
11879
+ * @remarks Time O(N), Space O(N)
11880
+ */
11881
+ perfectlyBalance(iterationType) {
11882
+ const entries = [];
11883
+ for (const [key, value] of this) entries.push([key, value]);
11884
+ if (entries.length <= 1) return true;
11885
+ this.clear();
11886
+ this.setMany(
11887
+ entries.map(([k]) => k),
11888
+ entries.map(([, v]) => v),
11889
+ true
11890
+ // isBalanceAdd
11891
+ );
11892
+ return true;
11893
+ }
11568
11894
  map(callback, options, thisArg) {
11569
11895
  const out = this._createLike([], options);
11570
11896
  let index = 0;
@@ -11889,7 +12215,7 @@ var _TreeSet = class _TreeSet {
11889
12215
  static createDefaultComparator() {
11890
12216
  return (a, b) => {
11891
12217
  if (typeof a === "number" && typeof b === "number") {
11892
- if (Number.isNaN(a) || Number.isNaN(b)) throw new TypeError("TreeSet: NaN is not a valid key");
12218
+ if (Number.isNaN(a) || Number.isNaN(b)) throw new TypeError(ERR.invalidNaN("TreeSet"));
11893
12219
  const aa = Object.is(a, -0) ? 0 : a;
11894
12220
  const bb = Object.is(b, -0) ? 0 : b;
11895
12221
  return aa > bb ? 1 : aa < bb ? -1 : 0;
@@ -11900,10 +12226,10 @@ var _TreeSet = class _TreeSet {
11900
12226
  if (a instanceof Date && b instanceof Date) {
11901
12227
  const ta = a.getTime();
11902
12228
  const tb = b.getTime();
11903
- if (Number.isNaN(ta) || Number.isNaN(tb)) throw new TypeError("TreeSet: invalid Date key");
12229
+ if (Number.isNaN(ta) || Number.isNaN(tb)) throw new TypeError(ERR.invalidDate("TreeSet"));
11904
12230
  return ta > tb ? 1 : ta < tb ? -1 : 0;
11905
12231
  }
11906
- throw new TypeError("TreeSet: comparator is required for non-number/non-string/non-Date keys");
12232
+ throw new TypeError(ERR.comparatorRequired("TreeSet"));
11907
12233
  };
11908
12234
  }
11909
12235
  /**
@@ -11921,15 +12247,15 @@ var _TreeSet = class _TreeSet {
11921
12247
  _validateKey(key) {
11922
12248
  if (!__privateGet(this, _isDefaultComparator)) return;
11923
12249
  if (typeof key === "number") {
11924
- if (Number.isNaN(key)) throw new TypeError("TreeSet: NaN is not a valid key");
12250
+ if (Number.isNaN(key)) throw new TypeError(ERR.invalidNaN("TreeSet"));
11925
12251
  return;
11926
12252
  }
11927
12253
  if (typeof key === "string") return;
11928
12254
  if (key instanceof Date) {
11929
- if (Number.isNaN(key.getTime())) throw new TypeError("TreeSet: invalid Date key");
12255
+ if (Number.isNaN(key.getTime())) throw new TypeError(ERR.invalidDate("TreeSet"));
11930
12256
  return;
11931
12257
  }
11932
- throw new TypeError("TreeSet: comparator is required for non-number/non-string/non-Date keys");
12258
+ throw new TypeError(ERR.comparatorRequired("TreeSet"));
11933
12259
  }
11934
12260
  /**
11935
12261
  * Add a key to the set (no-op if already present).
@@ -12252,15 +12578,15 @@ var _TreeMultiMap = class _TreeMultiMap {
12252
12578
  _validateKey(key) {
12253
12579
  if (!__privateGet(this, _isDefaultComparator2)) return;
12254
12580
  if (typeof key === "number") {
12255
- if (Number.isNaN(key)) throw new TypeError("TreeMultiMap: NaN is not a valid key");
12581
+ if (Number.isNaN(key)) throw new TypeError(ERR.invalidNaN("TreeMultiMap"));
12256
12582
  return;
12257
12583
  }
12258
12584
  if (typeof key === "string") return;
12259
12585
  if (key instanceof Date) {
12260
- if (Number.isNaN(key.getTime())) throw new TypeError("TreeMultiMap: invalid Date key");
12586
+ if (Number.isNaN(key.getTime())) throw new TypeError(ERR.invalidDate("TreeMultiMap"));
12261
12587
  return;
12262
12588
  }
12263
- throw new TypeError("TreeMultiMap: comparator is required for non-number/non-string/non-Date keys");
12589
+ throw new TypeError(ERR.comparatorRequired("TreeMultiMap"));
12264
12590
  }
12265
12591
  /**
12266
12592
  * Number of distinct keys.
@@ -12685,7 +13011,7 @@ var _TreeMap = class _TreeMap {
12685
13011
  [k, v] = toEntryFn(item);
12686
13012
  } else {
12687
13013
  if (!Array.isArray(item) || item.length < 2) {
12688
- throw new TypeError("TreeMap: each entry must be a [key, value] tuple");
13014
+ throw new TypeError(ERR.invalidEntry("TreeMap"));
12689
13015
  }
12690
13016
  k = item[0];
12691
13017
  v = item[1];
@@ -12706,7 +13032,7 @@ var _TreeMap = class _TreeMap {
12706
13032
  static createDefaultComparator() {
12707
13033
  return (a, b) => {
12708
13034
  if (typeof a === "number" && typeof b === "number") {
12709
- if (Number.isNaN(a) || Number.isNaN(b)) throw new TypeError("TreeMap: NaN is not a valid key");
13035
+ if (Number.isNaN(a) || Number.isNaN(b)) throw new TypeError(ERR.invalidNaN("TreeMap"));
12710
13036
  const aa = Object.is(a, -0) ? 0 : a;
12711
13037
  const bb = Object.is(b, -0) ? 0 : b;
12712
13038
  return aa > bb ? 1 : aa < bb ? -1 : 0;
@@ -12717,24 +13043,24 @@ var _TreeMap = class _TreeMap {
12717
13043
  if (a instanceof Date && b instanceof Date) {
12718
13044
  const ta = a.getTime();
12719
13045
  const tb = b.getTime();
12720
- if (Number.isNaN(ta) || Number.isNaN(tb)) throw new TypeError("TreeMap: invalid Date key");
13046
+ if (Number.isNaN(ta) || Number.isNaN(tb)) throw new TypeError(ERR.invalidDate("TreeMap"));
12721
13047
  return ta > tb ? 1 : ta < tb ? -1 : 0;
12722
13048
  }
12723
- throw new TypeError("TreeMap: comparator is required for non-number/non-string/non-Date keys");
13049
+ throw new TypeError(ERR.comparatorRequired("TreeMap"));
12724
13050
  };
12725
13051
  }
12726
13052
  _validateKey(key) {
12727
13053
  if (!__privateGet(this, _isDefaultComparator3)) return;
12728
13054
  if (typeof key === "number") {
12729
- if (Number.isNaN(key)) throw new TypeError("TreeMap: NaN is not a valid key");
13055
+ if (Number.isNaN(key)) throw new TypeError(ERR.invalidNaN("TreeMap"));
12730
13056
  return;
12731
13057
  }
12732
13058
  if (typeof key === "string") return;
12733
13059
  if (key instanceof Date) {
12734
- if (Number.isNaN(key.getTime())) throw new TypeError("TreeMap: invalid Date key");
13060
+ if (Number.isNaN(key.getTime())) throw new TypeError(ERR.invalidDate("TreeMap"));
12735
13061
  return;
12736
13062
  }
12737
- throw new TypeError("TreeMap: comparator is required for non-number/non-string/non-Date keys");
13063
+ throw new TypeError(ERR.comparatorRequired("TreeMap"));
12738
13064
  }
12739
13065
  /**
12740
13066
  * Number of entries in the map.
@@ -13063,22 +13389,22 @@ var _TreeMultiSet = class _TreeMultiSet {
13063
13389
  _validateKey(key) {
13064
13390
  if (!__privateGet(this, _isDefaultComparator4)) return;
13065
13391
  if (typeof key === "number") {
13066
- if (Number.isNaN(key)) throw new TypeError("TreeMultiSet: NaN is not a valid key");
13392
+ if (Number.isNaN(key)) throw new TypeError(ERR.invalidNaN("TreeMultiSet"));
13067
13393
  return;
13068
13394
  }
13069
13395
  if (typeof key === "string") return;
13070
13396
  if (key instanceof Date) {
13071
- if (Number.isNaN(key.getTime())) throw new TypeError("TreeMultiSet: invalid Date key");
13397
+ if (Number.isNaN(key.getTime())) throw new TypeError(ERR.invalidDate("TreeMultiSet"));
13072
13398
  return;
13073
13399
  }
13074
- throw new TypeError("TreeMultiSet: comparator is required for non-number/non-string/non-Date keys");
13400
+ throw new TypeError(ERR.comparatorRequired("TreeMultiSet"));
13075
13401
  }
13076
13402
  /**
13077
13403
  * Validates that count is a non-negative safe integer.
13078
13404
  * @remarks Time O(1), Space O(1)
13079
13405
  */
13080
13406
  _validateCount(n) {
13081
- if (!Number.isSafeInteger(n) || n < 0) throw new RangeError("TreeMultiSet: count must be a safe integer >= 0");
13407
+ if (!Number.isSafeInteger(n) || n < 0) throw new RangeError(ERR.invalidArgument("count must be a safe integer >= 0.", "TreeMultiSet"));
13082
13408
  }
13083
13409
  /**
13084
13410
  * Total occurrences (sumCounts).
@@ -13237,7 +13563,7 @@ var _TreeMultiSet = class _TreeMultiSet {
13237
13563
  * @remarks Time O(1), Space O(1)
13238
13564
  */
13239
13565
  get comparator() {
13240
- return __privateGet(this, _core4)._comparator;
13566
+ return __privateGet(this, _core4).comparator;
13241
13567
  }
13242
13568
  // ━━━ clear ━━━
13243
13569
  /**
@@ -13374,7 +13700,7 @@ var _TreeMultiSet = class _TreeMultiSet {
13374
13700
  filter(predicate) {
13375
13701
  const result = new _TreeMultiSet([], {
13376
13702
  comparator: __privateGet(this, _isDefaultComparator4) ? void 0 : this.comparator,
13377
- isMapMode: __privateGet(this, _core4)._isMapMode
13703
+ isMapMode: __privateGet(this, _core4).isMapMode
13378
13704
  });
13379
13705
  for (const [k, c] of this.entries()) {
13380
13706
  if (predicate(k, c)) {
@@ -13414,7 +13740,7 @@ var _TreeMultiSet = class _TreeMultiSet {
13414
13740
  map(mapper, options) {
13415
13741
  const result = new _TreeMultiSet([], {
13416
13742
  comparator: options == null ? void 0 : options.comparator,
13417
- isMapMode: __privateGet(this, _core4)._isMapMode
13743
+ isMapMode: __privateGet(this, _core4).isMapMode
13418
13744
  });
13419
13745
  for (const [k, c] of this.entries()) {
13420
13746
  const [newKey, newCount] = mapper(k, c);
@@ -13434,7 +13760,7 @@ var _TreeMultiSet = class _TreeMultiSet {
13434
13760
  clone() {
13435
13761
  const result = new _TreeMultiSet([], {
13436
13762
  comparator: __privateGet(this, _isDefaultComparator4) ? void 0 : this.comparator,
13437
- isMapMode: __privateGet(this, _core4)._isMapMode
13763
+ isMapMode: __privateGet(this, _core4).isMapMode
13438
13764
  });
13439
13765
  for (const [k, c] of this.entries()) {
13440
13766
  result.add(k, c);
@@ -13506,9 +13832,7 @@ var _MaxPriorityQueue = class _MaxPriorityQueue extends PriorityQueue {
13506
13832
  super(elements, {
13507
13833
  comparator: /* @__PURE__ */ __name((a, b) => {
13508
13834
  if (typeof a === "object" || typeof b === "object") {
13509
- throw TypeError(
13510
- `When comparing object types, a custom comparator must be defined in the constructor's options parameter.`
13511
- );
13835
+ throw new TypeError(ERR.comparatorRequired("MaxPriorityQueue"));
13512
13836
  }
13513
13837
  if (a < b) return 1;
13514
13838
  if (a > b) return -1;
@@ -13649,7 +13973,7 @@ var _Matrix = class _Matrix {
13649
13973
  */
13650
13974
  add(matrix) {
13651
13975
  if (!this.isMatchForCalculate(matrix)) {
13652
- throw new Error("Matrix dimensions must match for addition.");
13976
+ throw new Error(ERR.matrixDimensionMismatch("addition"));
13653
13977
  }
13654
13978
  const resultData = [];
13655
13979
  for (let i = 0; i < this.rows; i++) {
@@ -13681,7 +14005,7 @@ var _Matrix = class _Matrix {
13681
14005
  */
13682
14006
  subtract(matrix) {
13683
14007
  if (!this.isMatchForCalculate(matrix)) {
13684
- throw new Error("Matrix dimensions must match for subtraction.");
14008
+ throw new Error(ERR.matrixDimensionMismatch("subtraction"));
13685
14009
  }
13686
14010
  const resultData = [];
13687
14011
  for (let i = 0; i < this.rows; i++) {
@@ -13712,7 +14036,7 @@ var _Matrix = class _Matrix {
13712
14036
  */
13713
14037
  multiply(matrix) {
13714
14038
  if (this.cols !== matrix.rows) {
13715
- throw new Error("Matrix dimensions must be compatible for multiplication (A.cols = B.rows).");
14039
+ throw new Error(ERR.matrixDimensionMismatch("multiplication (A.cols must equal B.rows)"));
13716
14040
  }
13717
14041
  const resultData = [];
13718
14042
  for (let i = 0; i < this.rows; i++) {
@@ -13746,7 +14070,7 @@ var _Matrix = class _Matrix {
13746
14070
  */
13747
14071
  transpose() {
13748
14072
  if (this.data.some((row) => row.length !== this.rows)) {
13749
- throw new Error("Matrix must be rectangular for transposition.");
14073
+ throw new Error(ERR.matrixNotRectangular());
13750
14074
  }
13751
14075
  const resultData = [];
13752
14076
  for (let j = 0; j < this.cols; j++) {
@@ -13771,7 +14095,7 @@ var _Matrix = class _Matrix {
13771
14095
  inverse() {
13772
14096
  var _a;
13773
14097
  if (this.rows !== this.cols) {
13774
- throw new Error("Matrix must be square for inversion.");
14098
+ throw new Error(ERR.matrixNotSquare());
13775
14099
  }
13776
14100
  const augmentedMatrixData = [];
13777
14101
  for (let i = 0; i < this.rows; i++) {
@@ -13793,12 +14117,12 @@ var _Matrix = class _Matrix {
13793
14117
  pivotRow++;
13794
14118
  }
13795
14119
  if (pivotRow === this.rows) {
13796
- throw new Error("Matrix is singular, and its inverse does not exist.");
14120
+ throw new Error(ERR.matrixSingular());
13797
14121
  }
13798
14122
  augmentedMatrix._swapRows(i, pivotRow);
13799
14123
  const pivotElement = (_a = augmentedMatrix.get(i, i)) != null ? _a : 1;
13800
14124
  if (pivotElement === 0) {
13801
- throw new Error("Matrix is singular, and its inverse does not exist (division by zero).");
14125
+ throw new Error(ERR.matrixSingular());
13802
14126
  }
13803
14127
  augmentedMatrix._scaleRow(i, 1 / pivotElement);
13804
14128
  for (let j = 0; j < this.rows; j++) {
@@ -13828,9 +14152,7 @@ var _Matrix = class _Matrix {
13828
14152
  */
13829
14153
  dot(matrix) {
13830
14154
  if (this.cols !== matrix.rows) {
13831
- throw new Error(
13832
- "Number of columns in the first matrix must be equal to the number of rows in the second matrix for dot product."
13833
- );
14155
+ throw new Error(ERR.matrixDimensionMismatch("dot product (A.cols must equal B.rows)"));
13834
14156
  }
13835
14157
  const resultData = [];
13836
14158
  for (let i = 0; i < this.rows; i++) {
@@ -14452,7 +14774,7 @@ var _Trie = class _Trie extends IterableElementBase {
14452
14774
  for (const x of this) {
14453
14775
  const v = thisArg === void 0 ? callback(x, i++, this) : callback.call(thisArg, x, i++, this);
14454
14776
  if (typeof v !== "string") {
14455
- throw new TypeError(`Trie.map callback must return string; got ${typeof v}`);
14777
+ throw new TypeError(ERR.callbackReturnType("string", typeof v, "Trie.map"));
14456
14778
  }
14457
14779
  newTrie.add(v);
14458
14780
  }
@@ -14482,12 +14804,11 @@ var _Trie = class _Trie extends IterableElementBase {
14482
14804
  */
14483
14805
  _createInstance(options) {
14484
14806
  const Ctor = this.constructor;
14485
- const next = new Ctor([], {
14807
+ return new Ctor([], {
14486
14808
  toElementFn: this.toElementFn,
14487
14809
  caseSensitive: this.caseSensitive,
14488
14810
  ...options != null ? options : {}
14489
14811
  });
14490
- return next;
14491
14812
  }
14492
14813
  /**
14493
14814
  * (Protected) Create a like-kind trie and seed it from an iterable.
@@ -14704,6 +15025,7 @@ exports.DirectedGraph = DirectedGraph;
14704
15025
  exports.DirectedVertex = DirectedVertex;
14705
15026
  exports.DoublyLinkedList = DoublyLinkedList;
14706
15027
  exports.DoublyLinkedListNode = DoublyLinkedListNode;
15028
+ exports.ERR = ERR;
14707
15029
  exports.FibonacciHeap = FibonacciHeap;
14708
15030
  exports.FibonacciHeapNode = FibonacciHeapNode;
14709
15031
  exports.HashMap = HashMap;