data-structure-typed 2.0.5 → 2.1.0

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 (260) hide show
  1. package/CHANGELOG.md +1 -1
  2. package/COMMANDS.md +17 -0
  3. package/benchmark/report.html +13 -77
  4. package/benchmark/report.json +145 -177
  5. package/dist/cjs/data-structures/base/iterable-element-base.d.ts +186 -83
  6. package/dist/cjs/data-structures/base/iterable-element-base.js +149 -107
  7. package/dist/cjs/data-structures/base/iterable-element-base.js.map +1 -1
  8. package/dist/cjs/data-structures/base/iterable-entry-base.d.ts +95 -119
  9. package/dist/cjs/data-structures/base/iterable-entry-base.js +59 -116
  10. package/dist/cjs/data-structures/base/iterable-entry-base.js.map +1 -1
  11. package/dist/cjs/data-structures/base/linear-base.d.ts +250 -192
  12. package/dist/cjs/data-structures/base/linear-base.js +137 -274
  13. package/dist/cjs/data-structures/base/linear-base.js.map +1 -1
  14. package/dist/cjs/data-structures/binary-tree/avl-tree-counter.d.ts +126 -158
  15. package/dist/cjs/data-structures/binary-tree/avl-tree-counter.js +171 -205
  16. package/dist/cjs/data-structures/binary-tree/avl-tree-counter.js.map +1 -1
  17. package/dist/cjs/data-structures/binary-tree/avl-tree-multi-map.d.ts +100 -69
  18. package/dist/cjs/data-structures/binary-tree/avl-tree-multi-map.js +135 -87
  19. package/dist/cjs/data-structures/binary-tree/avl-tree-multi-map.js.map +1 -1
  20. package/dist/cjs/data-structures/binary-tree/avl-tree.d.ts +138 -149
  21. package/dist/cjs/data-structures/binary-tree/avl-tree.js +208 -195
  22. package/dist/cjs/data-structures/binary-tree/avl-tree.js.map +1 -1
  23. package/dist/cjs/data-structures/binary-tree/binary-tree.d.ts +476 -632
  24. package/dist/cjs/data-structures/binary-tree/binary-tree.js +594 -865
  25. package/dist/cjs/data-structures/binary-tree/binary-tree.js.map +1 -1
  26. package/dist/cjs/data-structures/binary-tree/bst.d.ts +258 -306
  27. package/dist/cjs/data-structures/binary-tree/bst.js +505 -481
  28. package/dist/cjs/data-structures/binary-tree/bst.js.map +1 -1
  29. package/dist/cjs/data-structures/binary-tree/red-black-tree.d.ts +107 -179
  30. package/dist/cjs/data-structures/binary-tree/red-black-tree.js +114 -209
  31. package/dist/cjs/data-structures/binary-tree/red-black-tree.js.map +1 -1
  32. package/dist/cjs/data-structures/binary-tree/tree-counter.d.ts +132 -154
  33. package/dist/cjs/data-structures/binary-tree/tree-counter.js +172 -203
  34. package/dist/cjs/data-structures/binary-tree/tree-counter.js.map +1 -1
  35. package/dist/cjs/data-structures/binary-tree/tree-multi-map.d.ts +72 -69
  36. package/dist/cjs/data-structures/binary-tree/tree-multi-map.js +105 -85
  37. package/dist/cjs/data-structures/binary-tree/tree-multi-map.js.map +1 -1
  38. package/dist/cjs/data-structures/graph/abstract-graph.d.ts +238 -233
  39. package/dist/cjs/data-structures/graph/abstract-graph.js +267 -237
  40. package/dist/cjs/data-structures/graph/abstract-graph.js.map +1 -1
  41. package/dist/cjs/data-structures/graph/directed-graph.d.ts +108 -224
  42. package/dist/cjs/data-structures/graph/directed-graph.js +146 -233
  43. package/dist/cjs/data-structures/graph/directed-graph.js.map +1 -1
  44. package/dist/cjs/data-structures/graph/map-graph.d.ts +49 -55
  45. package/dist/cjs/data-structures/graph/map-graph.js +56 -59
  46. package/dist/cjs/data-structures/graph/map-graph.js.map +1 -1
  47. package/dist/cjs/data-structures/graph/undirected-graph.d.ts +103 -146
  48. package/dist/cjs/data-structures/graph/undirected-graph.js +129 -149
  49. package/dist/cjs/data-structures/graph/undirected-graph.js.map +1 -1
  50. package/dist/cjs/data-structures/hash/hash-map.d.ts +164 -338
  51. package/dist/cjs/data-structures/hash/hash-map.js +270 -457
  52. package/dist/cjs/data-structures/hash/hash-map.js.map +1 -1
  53. package/dist/cjs/data-structures/heap/heap.d.ts +214 -289
  54. package/dist/cjs/data-structures/heap/heap.js +340 -349
  55. package/dist/cjs/data-structures/heap/heap.js.map +1 -1
  56. package/dist/cjs/data-structures/heap/max-heap.d.ts +11 -47
  57. package/dist/cjs/data-structures/heap/max-heap.js +11 -66
  58. package/dist/cjs/data-structures/heap/max-heap.js.map +1 -1
  59. package/dist/cjs/data-structures/heap/min-heap.d.ts +12 -47
  60. package/dist/cjs/data-structures/heap/min-heap.js +11 -66
  61. package/dist/cjs/data-structures/heap/min-heap.js.map +1 -1
  62. package/dist/cjs/data-structures/linked-list/doubly-linked-list.d.ts +231 -347
  63. package/dist/cjs/data-structures/linked-list/doubly-linked-list.js +368 -494
  64. package/dist/cjs/data-structures/linked-list/doubly-linked-list.js.map +1 -1
  65. package/dist/cjs/data-structures/linked-list/singly-linked-list.d.ts +261 -310
  66. package/dist/cjs/data-structures/linked-list/singly-linked-list.js +447 -466
  67. package/dist/cjs/data-structures/linked-list/singly-linked-list.js.map +1 -1
  68. package/dist/cjs/data-structures/linked-list/skip-linked-list.d.ts +0 -107
  69. package/dist/cjs/data-structures/linked-list/skip-linked-list.js +0 -100
  70. package/dist/cjs/data-structures/linked-list/skip-linked-list.js.map +1 -1
  71. package/dist/cjs/data-structures/priority-queue/max-priority-queue.d.ts +12 -56
  72. package/dist/cjs/data-structures/priority-queue/max-priority-queue.js +11 -78
  73. package/dist/cjs/data-structures/priority-queue/max-priority-queue.js.map +1 -1
  74. package/dist/cjs/data-structures/priority-queue/min-priority-queue.d.ts +11 -57
  75. package/dist/cjs/data-structures/priority-queue/min-priority-queue.js +10 -79
  76. package/dist/cjs/data-structures/priority-queue/min-priority-queue.js.map +1 -1
  77. package/dist/cjs/data-structures/priority-queue/priority-queue.d.ts +2 -61
  78. package/dist/cjs/data-structures/priority-queue/priority-queue.js +8 -83
  79. package/dist/cjs/data-structures/priority-queue/priority-queue.js.map +1 -1
  80. package/dist/cjs/data-structures/queue/deque.d.ts +227 -254
  81. package/dist/cjs/data-structures/queue/deque.js +309 -348
  82. package/dist/cjs/data-structures/queue/deque.js.map +1 -1
  83. package/dist/cjs/data-structures/queue/queue.d.ts +180 -201
  84. package/dist/cjs/data-structures/queue/queue.js +265 -248
  85. package/dist/cjs/data-structures/queue/queue.js.map +1 -1
  86. package/dist/cjs/data-structures/stack/stack.d.ts +124 -102
  87. package/dist/cjs/data-structures/stack/stack.js +181 -125
  88. package/dist/cjs/data-structures/stack/stack.js.map +1 -1
  89. package/dist/cjs/data-structures/trie/trie.d.ts +164 -165
  90. package/dist/cjs/data-structures/trie/trie.js +189 -172
  91. package/dist/cjs/data-structures/trie/trie.js.map +1 -1
  92. package/dist/cjs/interfaces/binary-tree.d.ts +56 -6
  93. package/dist/cjs/interfaces/graph.d.ts +16 -0
  94. package/dist/cjs/types/data-structures/base/base.d.ts +1 -1
  95. package/dist/cjs/types/data-structures/graph/abstract-graph.d.ts +4 -0
  96. package/dist/cjs/types/utils/utils.d.ts +1 -0
  97. package/dist/cjs/utils/utils.d.ts +1 -1
  98. package/dist/cjs/utils/utils.js +2 -1
  99. package/dist/cjs/utils/utils.js.map +1 -1
  100. package/dist/esm/data-structures/base/iterable-element-base.d.ts +186 -83
  101. package/dist/esm/data-structures/base/iterable-element-base.js +155 -107
  102. package/dist/esm/data-structures/base/iterable-element-base.js.map +1 -1
  103. package/dist/esm/data-structures/base/iterable-entry-base.d.ts +95 -119
  104. package/dist/esm/data-structures/base/iterable-entry-base.js +59 -116
  105. package/dist/esm/data-structures/base/iterable-entry-base.js.map +1 -1
  106. package/dist/esm/data-structures/base/linear-base.d.ts +250 -192
  107. package/dist/esm/data-structures/base/linear-base.js +137 -274
  108. package/dist/esm/data-structures/base/linear-base.js.map +1 -1
  109. package/dist/esm/data-structures/binary-tree/avl-tree-counter.d.ts +126 -158
  110. package/dist/esm/data-structures/binary-tree/avl-tree-counter.js +171 -212
  111. package/dist/esm/data-structures/binary-tree/avl-tree-counter.js.map +1 -1
  112. package/dist/esm/data-structures/binary-tree/avl-tree-multi-map.d.ts +100 -69
  113. package/dist/esm/data-structures/binary-tree/avl-tree-multi-map.js +133 -94
  114. package/dist/esm/data-structures/binary-tree/avl-tree-multi-map.js.map +1 -1
  115. package/dist/esm/data-structures/binary-tree/avl-tree.d.ts +138 -149
  116. package/dist/esm/data-structures/binary-tree/avl-tree.js +206 -200
  117. package/dist/esm/data-structures/binary-tree/avl-tree.js.map +1 -1
  118. package/dist/esm/data-structures/binary-tree/binary-tree.d.ts +476 -632
  119. package/dist/esm/data-structures/binary-tree/binary-tree.js +598 -874
  120. package/dist/esm/data-structures/binary-tree/binary-tree.js.map +1 -1
  121. package/dist/esm/data-structures/binary-tree/bst.d.ts +258 -306
  122. package/dist/esm/data-structures/binary-tree/bst.js +507 -487
  123. package/dist/esm/data-structures/binary-tree/bst.js.map +1 -1
  124. package/dist/esm/data-structures/binary-tree/red-black-tree.d.ts +107 -179
  125. package/dist/esm/data-structures/binary-tree/red-black-tree.js +114 -215
  126. package/dist/esm/data-structures/binary-tree/red-black-tree.js.map +1 -1
  127. package/dist/esm/data-structures/binary-tree/tree-counter.d.ts +132 -154
  128. package/dist/esm/data-structures/binary-tree/tree-counter.js +175 -209
  129. package/dist/esm/data-structures/binary-tree/tree-counter.js.map +1 -1
  130. package/dist/esm/data-structures/binary-tree/tree-multi-map.d.ts +72 -69
  131. package/dist/esm/data-structures/binary-tree/tree-multi-map.js +103 -92
  132. package/dist/esm/data-structures/binary-tree/tree-multi-map.js.map +1 -1
  133. package/dist/esm/data-structures/graph/abstract-graph.d.ts +238 -233
  134. package/dist/esm/data-structures/graph/abstract-graph.js +267 -237
  135. package/dist/esm/data-structures/graph/abstract-graph.js.map +1 -1
  136. package/dist/esm/data-structures/graph/directed-graph.d.ts +108 -224
  137. package/dist/esm/data-structures/graph/directed-graph.js +145 -233
  138. package/dist/esm/data-structures/graph/directed-graph.js.map +1 -1
  139. package/dist/esm/data-structures/graph/map-graph.d.ts +49 -55
  140. package/dist/esm/data-structures/graph/map-graph.js +56 -59
  141. package/dist/esm/data-structures/graph/map-graph.js.map +1 -1
  142. package/dist/esm/data-structures/graph/undirected-graph.d.ts +103 -146
  143. package/dist/esm/data-structures/graph/undirected-graph.js +128 -149
  144. package/dist/esm/data-structures/graph/undirected-graph.js.map +1 -1
  145. package/dist/esm/data-structures/hash/hash-map.d.ts +164 -338
  146. package/dist/esm/data-structures/hash/hash-map.js +270 -457
  147. package/dist/esm/data-structures/hash/hash-map.js.map +1 -1
  148. package/dist/esm/data-structures/heap/heap.d.ts +214 -289
  149. package/dist/esm/data-structures/heap/heap.js +329 -349
  150. package/dist/esm/data-structures/heap/heap.js.map +1 -1
  151. package/dist/esm/data-structures/heap/max-heap.d.ts +11 -47
  152. package/dist/esm/data-structures/heap/max-heap.js +11 -66
  153. package/dist/esm/data-structures/heap/max-heap.js.map +1 -1
  154. package/dist/esm/data-structures/heap/min-heap.d.ts +12 -47
  155. package/dist/esm/data-structures/heap/min-heap.js +11 -66
  156. package/dist/esm/data-structures/heap/min-heap.js.map +1 -1
  157. package/dist/esm/data-structures/linked-list/doubly-linked-list.d.ts +231 -347
  158. package/dist/esm/data-structures/linked-list/doubly-linked-list.js +368 -495
  159. package/dist/esm/data-structures/linked-list/doubly-linked-list.js.map +1 -1
  160. package/dist/esm/data-structures/linked-list/singly-linked-list.d.ts +261 -310
  161. package/dist/esm/data-structures/linked-list/singly-linked-list.js +448 -467
  162. package/dist/esm/data-structures/linked-list/singly-linked-list.js.map +1 -1
  163. package/dist/esm/data-structures/linked-list/skip-linked-list.d.ts +0 -107
  164. package/dist/esm/data-structures/linked-list/skip-linked-list.js +0 -100
  165. package/dist/esm/data-structures/linked-list/skip-linked-list.js.map +1 -1
  166. package/dist/esm/data-structures/priority-queue/max-priority-queue.d.ts +12 -56
  167. package/dist/esm/data-structures/priority-queue/max-priority-queue.js +11 -78
  168. package/dist/esm/data-structures/priority-queue/max-priority-queue.js.map +1 -1
  169. package/dist/esm/data-structures/priority-queue/min-priority-queue.d.ts +11 -57
  170. package/dist/esm/data-structures/priority-queue/min-priority-queue.js +10 -79
  171. package/dist/esm/data-structures/priority-queue/min-priority-queue.js.map +1 -1
  172. package/dist/esm/data-structures/priority-queue/priority-queue.d.ts +2 -61
  173. package/dist/esm/data-structures/priority-queue/priority-queue.js +8 -83
  174. package/dist/esm/data-structures/priority-queue/priority-queue.js.map +1 -1
  175. package/dist/esm/data-structures/queue/deque.d.ts +227 -254
  176. package/dist/esm/data-structures/queue/deque.js +313 -348
  177. package/dist/esm/data-structures/queue/deque.js.map +1 -1
  178. package/dist/esm/data-structures/queue/queue.d.ts +180 -201
  179. package/dist/esm/data-structures/queue/queue.js +263 -248
  180. package/dist/esm/data-structures/queue/queue.js.map +1 -1
  181. package/dist/esm/data-structures/stack/stack.d.ts +124 -102
  182. package/dist/esm/data-structures/stack/stack.js +181 -125
  183. package/dist/esm/data-structures/stack/stack.js.map +1 -1
  184. package/dist/esm/data-structures/trie/trie.d.ts +164 -165
  185. package/dist/esm/data-structures/trie/trie.js +193 -172
  186. package/dist/esm/data-structures/trie/trie.js.map +1 -1
  187. package/dist/esm/interfaces/binary-tree.d.ts +56 -6
  188. package/dist/esm/interfaces/graph.d.ts +16 -0
  189. package/dist/esm/types/data-structures/base/base.d.ts +1 -1
  190. package/dist/esm/types/data-structures/graph/abstract-graph.d.ts +4 -0
  191. package/dist/esm/types/utils/utils.d.ts +1 -0
  192. package/dist/esm/utils/utils.d.ts +1 -1
  193. package/dist/esm/utils/utils.js +2 -1
  194. package/dist/esm/utils/utils.js.map +1 -1
  195. package/dist/umd/data-structure-typed.js +4685 -6477
  196. package/dist/umd/data-structure-typed.min.js +8 -6
  197. package/dist/umd/data-structure-typed.min.js.map +1 -1
  198. package/package.json +3 -4
  199. package/src/data-structures/base/iterable-element-base.ts +238 -115
  200. package/src/data-structures/base/iterable-entry-base.ts +96 -120
  201. package/src/data-structures/base/linear-base.ts +271 -277
  202. package/src/data-structures/binary-tree/avl-tree-counter.ts +198 -216
  203. package/src/data-structures/binary-tree/avl-tree-multi-map.ts +192 -101
  204. package/src/data-structures/binary-tree/avl-tree.ts +239 -206
  205. package/src/data-structures/binary-tree/binary-tree.ts +660 -889
  206. package/src/data-structures/binary-tree/bst.ts +568 -570
  207. package/src/data-structures/binary-tree/red-black-tree.ts +161 -222
  208. package/src/data-structures/binary-tree/tree-counter.ts +199 -218
  209. package/src/data-structures/binary-tree/tree-multi-map.ts +131 -97
  210. package/src/data-structures/graph/abstract-graph.ts +339 -264
  211. package/src/data-structures/graph/directed-graph.ts +146 -236
  212. package/src/data-structures/graph/map-graph.ts +63 -60
  213. package/src/data-structures/graph/undirected-graph.ts +129 -152
  214. package/src/data-structures/hash/hash-map.ts +274 -496
  215. package/src/data-structures/heap/heap.ts +389 -402
  216. package/src/data-structures/heap/max-heap.ts +12 -76
  217. package/src/data-structures/heap/min-heap.ts +13 -76
  218. package/src/data-structures/linked-list/doubly-linked-list.ts +426 -530
  219. package/src/data-structures/linked-list/singly-linked-list.ts +495 -517
  220. package/src/data-structures/linked-list/skip-linked-list.ts +1 -108
  221. package/src/data-structures/priority-queue/max-priority-queue.ts +12 -87
  222. package/src/data-structures/priority-queue/min-priority-queue.ts +11 -88
  223. package/src/data-structures/priority-queue/priority-queue.ts +3 -92
  224. package/src/data-structures/queue/deque.ts +381 -357
  225. package/src/data-structures/queue/queue.ts +310 -264
  226. package/src/data-structures/stack/stack.ts +217 -131
  227. package/src/data-structures/trie/trie.ts +240 -175
  228. package/src/interfaces/binary-tree.ts +240 -6
  229. package/src/interfaces/graph.ts +37 -0
  230. package/src/types/data-structures/base/base.ts +5 -5
  231. package/src/types/data-structures/graph/abstract-graph.ts +5 -0
  232. package/src/types/utils/utils.ts +2 -0
  233. package/src/utils/utils.ts +9 -14
  234. package/test/integration/index.html +1 -1
  235. package/test/performance/benchmark-runner.ts +528 -0
  236. package/test/performance/reportor.mjs +43 -43
  237. package/test/performance/runner-config.json +39 -0
  238. package/test/performance/single-suite-runner.ts +69 -0
  239. package/test/unit/data-structures/binary-tree/avl-tree-counter.test.ts +3 -3
  240. package/test/unit/data-structures/binary-tree/avl-tree-multi-map.test.ts +5 -5
  241. package/test/unit/data-structures/binary-tree/avl-tree.test.ts +4 -4
  242. package/test/unit/data-structures/binary-tree/binary-tree.test.ts +350 -90
  243. package/test/unit/data-structures/binary-tree/bst.test.ts +12 -9
  244. package/test/unit/data-structures/binary-tree/red-black-tree.test.ts +2 -2
  245. package/test/unit/data-structures/binary-tree/tree-counter.test.ts +25 -24
  246. package/test/unit/data-structures/binary-tree/tree-multi-map.test.ts +3 -3
  247. package/test/unit/data-structures/graph/abstract-graph.test.ts +0 -4
  248. package/test/unit/data-structures/graph/directed-graph.test.ts +1 -1
  249. package/test/unit/data-structures/heap/heap.test.ts +14 -21
  250. package/test/unit/data-structures/heap/max-heap.test.ts +5 -9
  251. package/test/unit/data-structures/heap/min-heap.test.ts +1 -4
  252. package/test/unit/data-structures/linked-list/doubly-linked-list.test.ts +14 -14
  253. package/test/unit/data-structures/linked-list/singly-linked-list.test.ts +0 -7
  254. package/test/unit/data-structures/priority-queue/max-priority-queue.test.ts +8 -11
  255. package/test/unit/data-structures/priority-queue/min-priority-queue.test.ts +1 -4
  256. package/test/unit/data-structures/priority-queue/priority-queue.test.ts +1 -4
  257. package/test/unit/data-structures/queue/queue.test.ts +4 -5
  258. package/test/unit/utils/utils.test.ts +0 -1
  259. package/test/performance/data-structures/binary-tree/avl-tree.test.mjs +0 -71
  260. package/test/performance/data-structures/binary-tree/red-black-tree.test.mjs +0 -81
@@ -1,9 +1,22 @@
1
+ /**
2
+ * data-structure-typed
3
+ *
4
+ * @author Pablo Zeng
5
+ * @copyright Copyright (c) 2022 Pablo Zeng <zrwusa@gmail.com>
6
+ * @license MIT License
7
+ */
1
8
  import { LinearLinkedBase, LinkedListNode } from '../base/linear-base';
9
+ /**
10
+ * Node of a singly linked list; stores value and the next link.
11
+ * @remarks Time O(1), Space O(1)
12
+ * @template E
13
+ */
2
14
  export class SinglyLinkedListNode extends LinkedListNode {
3
15
  /**
4
- * The constructor function initializes an instance of a class with a given value and sets the next property to undefined.
5
- * @param {E} value - The "value" parameter is of type E, which means it can be any data type. It represents the value that
6
- * will be stored in the node of a linked list.
16
+ * Create a list node.
17
+ * @remarks Time O(1), Space O(1)
18
+ * @param value - Element value to store.
19
+ * @returns New node instance.
7
20
  */
8
21
  constructor(value) {
9
22
  super(value);
@@ -11,20 +24,34 @@ export class SinglyLinkedListNode extends LinkedListNode {
11
24
  this._next = undefined;
12
25
  }
13
26
  _next;
27
+ /**
28
+ * Get the next node.
29
+ * @remarks Time O(1), Space O(1)
30
+ * @returns Next node or undefined.
31
+ */
14
32
  get next() {
15
33
  return this._next;
16
34
  }
35
+ /**
36
+ * Set the next node.
37
+ * @remarks Time O(1), Space O(1)
38
+ * @param value - Next node or undefined.
39
+ * @returns void
40
+ */
17
41
  set next(value) {
18
42
  this._next = value;
19
43
  }
20
44
  }
21
45
  /**
46
+ * Singly linked list with O(1) push/pop-like ends operations and linear scans.
47
+ * @remarks Time O(1), Space O(1)
48
+ * @template E
49
+ * @template R
22
50
  * 1. Node Structure: Each node contains three parts: a data field, a pointer (or reference) to the previous node, and a pointer to the next node. This structure allows traversal of the linked list in both directions.
23
51
  * 2. Bidirectional Traversal: Unlike doubly linked lists, singly linked lists can be easily traversed forwards but not backwards.
24
52
  * 3. No Centralized Index: Unlike arrays, elements in a linked list are not stored contiguously, so there is no centralized index. Accessing elements in a linked list typically requires traversing from the head or tail node.
25
53
  * 4. High Efficiency in Insertion and Deletion: Adding or removing elements in a linked list does not require moving other elements, making these operations more efficient than in arrays.
26
54
  * Caution: Although our linked list classes provide methods such as at, setAt, addAt, and indexOf that are based on array indices, their time complexity, like that of the native Array.lastIndexOf, is 𝑂(𝑛). If you need to use these methods frequently, you might want to consider other data structures, such as Deque or Queue (designed for random access). Similarly, since the native Array.shift method has a time complexity of 𝑂(𝑛), using an array to simulate a queue can be inefficient. In such cases, you should use Queue or Deque, as these data structures leverage deferred array rearrangement, effectively reducing the average time complexity to 𝑂(1).
27
- *
28
55
  * @example
29
56
  * // implementation of a basic text editor
30
57
  * class TextEditor {
@@ -93,60 +120,88 @@ export class SinglyLinkedListNode extends LinkedListNode {
93
120
  * console.log(editor.getText()); // 'Haello'
94
121
  */
95
122
  export class SinglyLinkedList extends LinearLinkedBase {
123
+ _equals = Object.is;
124
+ /**
125
+ * Create a SinglyLinkedList and optionally bulk-insert elements.
126
+ * @remarks Time O(N), Space O(N)
127
+ * @param [elements] - Iterable of elements or nodes (or raw records if toElementFn is provided).
128
+ * @param [options] - Options such as maxLen and toElementFn.
129
+ * @returns New SinglyLinkedList instance.
130
+ */
96
131
  constructor(elements = [], options) {
97
132
  super(options);
98
- if (options) {
99
- }
100
133
  this.pushMany(elements);
101
134
  }
102
135
  _head;
136
+ /**
137
+ * Get the head node.
138
+ * @remarks Time O(1), Space O(1)
139
+ * @returns Head node or undefined.
140
+ */
103
141
  get head() {
104
142
  return this._head;
105
143
  }
106
144
  _tail;
145
+ /**
146
+ * Get the tail node.
147
+ * @remarks Time O(1), Space O(1)
148
+ * @returns Tail node or undefined.
149
+ */
107
150
  get tail() {
108
151
  return this._tail;
109
152
  }
153
+ _length = 0;
154
+ /**
155
+ * Get the number of elements.
156
+ * @remarks Time O(1), Space O(1)
157
+ * @returns Current length.
158
+ */
159
+ get length() {
160
+ return this._length;
161
+ }
162
+ /**
163
+ * Get the first element value.
164
+ * @remarks Time O(1), Space O(1)
165
+ * @returns First element or undefined.
166
+ */
110
167
  get first() {
111
168
  return this.head?.value;
112
169
  }
170
+ /**
171
+ * Get the last element value.
172
+ * @remarks Time O(1), Space O(1)
173
+ * @returns Last element or undefined.
174
+ */
113
175
  get last() {
114
176
  return this.tail?.value;
115
177
  }
116
- _length = 0;
117
- get length() {
118
- return this._length;
119
- }
120
178
  /**
121
- * Time Complexity: O(n)
122
- * Space Complexity: O(n)
123
- *
124
- * The `fromArray` function creates a new SinglyLinkedList instance and populates it with the elements from the given
125
- * array.
126
- * @param {E[]} data - The `data` parameter is an array of elements of type `E`.
127
- * @returns The `fromArray` function returns a `SinglyLinkedList` object.
179
+ * Create a new list from an iterable of elements.
180
+ * @remarks Time O(N), Space O(N)
181
+ * @template E
182
+ * @template R
183
+ * @template S
184
+ * @param this - The constructor (subclass) to instantiate.
185
+ * @param data - Iterable of elements to insert.
186
+ * @param [options] - Options forwarded to the constructor.
187
+ * @returns A new list populated with the iterable's elements.
128
188
  */
129
- static fromArray(data) {
130
- const singlyLinkedList = new SinglyLinkedList();
131
- for (const item of data) {
132
- singlyLinkedList.push(item);
133
- }
134
- return singlyLinkedList;
189
+ static from(data, options) {
190
+ const list = new this([], options);
191
+ for (const x of data)
192
+ list.push(x);
193
+ return list;
135
194
  }
136
195
  /**
137
- * Time Complexity: O(1)
138
- * Space Complexity: O(1)
139
- *
140
- * The `push` function adds a new element or node to the end of a singly linked list.
141
- * @param {E | SinglyLinkedListNode<E>} elementOrNode - The `elementOrNode` parameter in the `push`
142
- * method can accept either an element of type `E` or a `SinglyLinkedListNode<E>` object.
143
- * @returns The `push` method is returning a boolean value, specifically `true`.
196
+ * Append an element/node to the tail.
197
+ * @remarks Time O(1), Space O(1)
198
+ * @param elementOrNode - Element or node to append.
199
+ * @returns True when appended.
144
200
  */
145
201
  push(elementOrNode) {
146
202
  const newNode = this._ensureNode(elementOrNode);
147
203
  if (!this.head) {
148
- this._head = newNode;
149
- this._tail = newNode;
204
+ this._head = this._tail = newNode;
150
205
  }
151
206
  else {
152
207
  this.tail.next = newNode;
@@ -158,12 +213,9 @@ export class SinglyLinkedList extends LinearLinkedBase {
158
213
  return true;
159
214
  }
160
215
  /**
161
- * Time Complexity: O(n)
162
- * Space Complexity: O(1)
163
- *
164
- * The `pop` function removes and returns the value of the last element in a linked list.
165
- * @returns The method is returning the value of the element that is being popped from the end of the
166
- * list.
216
+ * Remove and return the tail element.
217
+ * @remarks Time O(N), Space O(1)
218
+ * @returns Removed element or undefined.
167
219
  */
168
220
  pop() {
169
221
  if (!this.head)
@@ -176,9 +228,8 @@ export class SinglyLinkedList extends LinearLinkedBase {
176
228
  return value;
177
229
  }
178
230
  let current = this.head;
179
- while (current.next !== this.tail) {
231
+ while (current.next !== this.tail)
180
232
  current = current.next;
181
- }
182
233
  const value = this.tail.value;
183
234
  current.next = undefined;
184
235
  this._tail = current;
@@ -186,36 +237,30 @@ export class SinglyLinkedList extends LinearLinkedBase {
186
237
  return value;
187
238
  }
188
239
  /**
189
- * Time Complexity: O(1)
190
- * Space Complexity: O(1)
191
- *
192
- * The `shift()` function removes and returns the value of the first element in a linked list.
193
- * @returns The value of the removed node.
240
+ * Remove and return the head element.
241
+ * @remarks Time O(1), Space O(1)
242
+ * @returns Removed element or undefined.
194
243
  */
195
244
  shift() {
196
245
  if (!this.head)
197
246
  return undefined;
198
- const removedNode = this.head;
247
+ const removed = this.head;
199
248
  this._head = this.head.next;
249
+ if (!this._head)
250
+ this._tail = undefined;
200
251
  this._length--;
201
- return removedNode.value;
252
+ return removed.value;
202
253
  }
203
254
  /**
204
- * Time Complexity: O(1)
205
- * Space Complexity: O(1)
206
- *
207
- * The unshift function adds a new element or node to the beginning of a singly linked list in
208
- * TypeScript.
209
- * @param {E | SinglyLinkedListNode<E>} elementOrNode - The `elementOrNode` parameter in the
210
- * `unshift` method can be either an element of type `E` or a `SinglyLinkedListNode` containing an
211
- * element of type `E`.
212
- * @returns The `unshift` method is returning a boolean value, specifically `true`.
255
+ * Prepend an element/node to the head.
256
+ * @remarks Time O(1), Space O(1)
257
+ * @param elementOrNode - Element or node to prepend.
258
+ * @returns True when prepended.
213
259
  */
214
260
  unshift(elementOrNode) {
215
261
  const newNode = this._ensureNode(elementOrNode);
216
262
  if (!this.head) {
217
- this._head = newNode;
218
- this._tail = newNode;
263
+ this._head = this._tail = newNode;
219
264
  }
220
265
  else {
221
266
  newNode.next = this.head;
@@ -225,63 +270,42 @@ export class SinglyLinkedList extends LinearLinkedBase {
225
270
  return true;
226
271
  }
227
272
  /**
228
- * Time Complexity: O(k)
229
- * Space Complexity: O(k)
230
- *
231
- * The function `pushMany` iterates over elements and pushes them into a data structure, applying a
232
- * transformation function if provided.
233
- * @param {Iterable<E> | Iterable<R> | Iterable<SinglyLinkedListNode<E>>} elements - The `elements`
234
- * parameter in the `pushMany` function can accept an iterable containing elements of type `E`, `R`,
235
- * or `SinglyLinkedListNode<E>`.
236
- * @returns The `pushMany` function returns an array of boolean values indicating whether each
237
- * element was successfully pushed into the data structure.
273
+ * Append a sequence of elements/nodes.
274
+ * @remarks Time O(N), Space O(1)
275
+ * @param elements - Iterable of elements or nodes (or raw records if toElementFn is provided).
276
+ * @returns Array of per-element success flags.
238
277
  */
239
278
  pushMany(elements) {
240
279
  const ans = [];
241
280
  for (const el of elements) {
242
- if (this.toElementFn) {
281
+ if (this.toElementFn)
243
282
  ans.push(this.push(this.toElementFn(el)));
244
- continue;
245
- }
246
- ans.push(this.push(el));
283
+ else
284
+ ans.push(this.push(el));
247
285
  }
248
286
  return ans;
249
287
  }
250
288
  /**
251
- * Time Complexity: O(k)
252
- * Space Complexity: O(k)
253
- *
254
- * The function `unshiftMany` iterates over elements and adds them to a data structure, optionally
255
- * converting them using a provided function.
256
- * @param {Iterable<E> | Iterable<R> | Iterable<SinglyLinkedListNode<E>>} elements - The `elements`
257
- * parameter in the `unshiftMany` function can accept an iterable containing elements of type `E`,
258
- * `R`, or `SinglyLinkedListNode<E>`. The function iterates over each element in the iterable and
259
- * performs an `unshift` operation on the linked list for each
260
- * @returns The `unshiftMany` function is returning an array of boolean values, where each value
261
- * represents the result of calling the `unshift` method on the current instance of the class.
289
+ * Prepend a sequence of elements/nodes.
290
+ * @remarks Time O(N), Space O(1)
291
+ * @param elements - Iterable of elements or nodes (or raw records if toElementFn is provided).
292
+ * @returns Array of per-element success flags.
262
293
  */
263
294
  unshiftMany(elements) {
264
295
  const ans = [];
265
296
  for (const el of elements) {
266
- if (this.toElementFn) {
297
+ if (this.toElementFn)
267
298
  ans.push(this.unshift(this.toElementFn(el)));
268
- continue;
269
- }
270
- ans.push(this.unshift(el));
299
+ else
300
+ ans.push(this.unshift(el));
271
301
  }
272
302
  return ans;
273
303
  }
274
304
  /**
275
- * Time Complexity: O(n)
276
- * Space Complexity: O(1)
277
- *
278
- * This function searches for a specific element in a singly linked list based on a given node or
279
- * predicate.
280
- * @param {E | SinglyLinkedListNode<E> | ((node: SinglyLinkedListNode<E>) => boolean)} elementNodeOrPredicate
281
- * elementNodeOrPredicate - The `elementNodeOrPredicate` parameter in the `get` method can be one of
282
- * the following types:
283
- * @returns The `get` method returns the value of the first node in the singly linked list that
284
- * satisfies the provided predicate function. If no such node is found, it returns `undefined`.
305
+ * Find the first value matching a predicate (by node).
306
+ * @remarks Time O(N), Space O(1)
307
+ * @param elementNodeOrPredicate - Element, node, or node predicate to match.
308
+ * @returns Matched value or undefined.
285
309
  */
286
310
  search(elementNodeOrPredicate) {
287
311
  const predicate = this._ensurePredicate(elementNodeOrPredicate);
@@ -294,97 +318,67 @@ export class SinglyLinkedList extends LinearLinkedBase {
294
318
  return undefined;
295
319
  }
296
320
  /**
297
- * Time Complexity: O(n)
298
- * Space Complexity: O(1)
299
- *
300
- * The function `at` returns the value at a specified index in a linked list, or undefined if the index is out of range.
301
- * @param {number} index - The index parameter is a number that represents the position of the element we want to
302
- * retrieve from the list.
303
- * @returns The method `at(index: number): E | undefined` returns the value at the specified index in the linked list, or
304
- * `undefined` if the index is out of bounds.
321
+ * Get the element at a given index.
322
+ * @remarks Time O(N), Space O(1)
323
+ * @param index - Zero-based index.
324
+ * @returns Element or undefined.
305
325
  */
306
326
  at(index) {
307
327
  if (index < 0 || index >= this._length)
308
328
  return undefined;
309
329
  let current = this.head;
310
- for (let i = 0; i < index; i++) {
330
+ for (let i = 0; i < index; i++)
311
331
  current = current.next;
312
- }
313
332
  return current.value;
314
333
  }
315
334
  /**
316
- * Time Complexity: O(1)
317
- * Space Complexity: O(1)
318
- *
319
- * The function `isNode` in TypeScript checks if the input is an instance of `SinglyLinkedListNode`.
320
- * @param {E | SinglyLinkedListNode<E> | ((node: SinglyLinkedListNode<E>) => boolean)} elementNodeOrPredicate
321
- * elementNodeOrPredicate - The `elementNodeOrPredicate` parameter in the `isNode` function can be
322
- * one of the following types:
323
- * @returns The `isNode` function is checking if the `elementNodeOrPredicate` parameter is an
324
- * instance of `SinglyLinkedListNode<E>`. If it is, the function returns `true`, indicating that the
325
- * parameter is a `SinglyLinkedListNode<E>`. If it is not an instance of `SinglyLinkedListNode<E>`,
326
- * the function returns `false`.
335
+ * Type guard: check whether the input is a SinglyLinkedListNode.
336
+ * @remarks Time O(1), Space O(1)
337
+ * @param elementNodeOrPredicate - Element, node, or predicate.
338
+ * @returns True if the value is a SinglyLinkedListNode.
327
339
  */
328
340
  isNode(elementNodeOrPredicate) {
329
341
  return elementNodeOrPredicate instanceof SinglyLinkedListNode;
330
342
  }
331
343
  /**
332
- * Time Complexity: O(n)
333
- * Space Complexity: O(1)
334
- *
335
- * The function `getNodeAt` returns the node at a given index in a singly linked list.
336
- * @param {number} index - The `index` parameter is a number that represents the position of the node we want to
337
- * retrieve from the linked list. It indicates the zero-based index of the node we want to access.
338
- * @returns The method `getNodeAt(index: number)` returns a `SinglyLinkedListNode<E>` object if the node at the
339
- * specified index exists, or `undefined` if the index is out of bounds.
344
+ * Get the node reference at a given index.
345
+ * @remarks Time O(N), Space O(1)
346
+ * @param index - Zero-based index.
347
+ * @returns Node or undefined.
340
348
  */
341
349
  getNodeAt(index) {
350
+ if (index < 0 || index >= this._length)
351
+ return undefined;
342
352
  let current = this.head;
343
- for (let i = 0; i < index; i++) {
353
+ for (let i = 0; i < index; i++)
344
354
  current = current.next;
345
- }
346
355
  return current;
347
356
  }
348
357
  /**
349
- * Time Complexity: O(n)
350
- * Space Complexity: O(1)
351
- *
352
- * The `deleteAt` function removes an element at a specified index from a linked list and returns the removed element.
353
- * @param {number} index - The index parameter represents the position of the element that needs to be deleted in the
354
- * data structure. It is of type number.
355
- * @returns The method `deleteAt` returns the value of the node that was deleted, or `undefined` if the index is out of
356
- * bounds.
358
+ * Delete the element at an index.
359
+ * @remarks Time O(N), Space O(1)
360
+ * @param index - Zero-based index.
361
+ * @returns Removed element or undefined.
357
362
  */
358
363
  deleteAt(index) {
359
364
  if (index < 0 || index >= this._length)
360
- return;
361
- let deleted;
362
- if (index === 0) {
363
- deleted = this.first;
364
- this.shift();
365
- return deleted;
366
- }
365
+ return undefined;
366
+ if (index === 0)
367
+ return this.shift();
367
368
  const targetNode = this.getNodeAt(index);
368
369
  const prevNode = this._getPrevNode(targetNode);
369
- if (prevNode && targetNode) {
370
- deleted = targetNode.value;
371
- prevNode.next = targetNode.next;
372
- if (targetNode === this.tail)
373
- this._tail = prevNode;
374
- this._length--;
375
- return deleted;
376
- }
377
- return;
370
+ const value = targetNode.value;
371
+ prevNode.next = targetNode.next;
372
+ if (targetNode === this.tail)
373
+ this._tail = prevNode;
374
+ this._length--;
375
+ return value;
378
376
  }
379
377
  /**
380
- * Time Complexity: O(n)
381
- * Space Complexity: O(1)
382
- *
383
- * The delete function removes a node with a specific value from a singly linked list.
384
- * @param {E | SinglyLinkedListNode<E>} elementOrNode - The `elementOrNode` parameter can accept either a value of type `E`
385
- * or a `SinglyLinkedListNode<E>` object.
386
- * @returns The `delete` method returns a boolean value. It returns `true` if the value or node is found and
387
- * successfully deleted from the linked list, and `false` if the value or node is not found in the linked list.
378
+ * Delete the first match by value/node.
379
+ * @remarks Time O(N), Space O(1)
380
+ * @param [elementOrNode] - Element or node to remove; if omitted/undefined, nothing happens.
381
+ * @returns True if removed.
388
382
  */
389
383
  delete(elementOrNode) {
390
384
  if (elementOrNode === undefined || !this.head)
@@ -394,7 +388,6 @@ export class SinglyLinkedList extends LinearLinkedBase {
394
388
  return false;
395
389
  const prevNode = this._getPrevNode(node);
396
390
  if (!prevNode) {
397
- // The node is the head
398
391
  this._head = node.next;
399
392
  if (node === this.tail)
400
393
  this._tail = undefined;
@@ -408,31 +401,19 @@ export class SinglyLinkedList extends LinearLinkedBase {
408
401
  return true;
409
402
  }
410
403
  /**
411
- * Time Complexity: O(n)
412
- * Space Complexity: O(1)
413
- *
414
- * The `addAt` function inserts a new element or node at a specified index in a singly linked list.
415
- * @param {number} index - The `index` parameter represents the position at which you want to add a
416
- * new element or node in the linked list. It is a number that indicates the index where the new
417
- * element or node should be inserted.
418
- * @param {E | SinglyLinkedListNode<E>} newElementOrNode - The `newElementOrNode` parameter in the
419
- * `addAt` method can be either a value of type `E` or a `SinglyLinkedListNode<E>` object. This
420
- * parameter represents the element or node that you want to add to the linked list at the specified
421
- * index.
422
- * @returns The `addAt` method returns a boolean value - `true` if the element or node was
423
- * successfully added at the specified index, and `false` if the index is out of bounds.
404
+ * Insert a new element/node at an index, shifting following nodes.
405
+ * @remarks Time O(N), Space O(1)
406
+ * @param index - Zero-based index.
407
+ * @param newElementOrNode - Element or node to insert.
408
+ * @returns True if inserted.
424
409
  */
425
410
  addAt(index, newElementOrNode) {
426
411
  if (index < 0 || index > this._length)
427
412
  return false;
428
- if (index === 0) {
429
- this.unshift(newElementOrNode);
430
- return true;
431
- }
432
- if (index === this._length) {
433
- this.push(newElementOrNode);
434
- return true;
435
- }
413
+ if (index === 0)
414
+ return this.unshift(newElementOrNode);
415
+ if (index === this._length)
416
+ return this.push(newElementOrNode);
436
417
  const newNode = this._ensureNode(newElementOrNode);
437
418
  const prevNode = this.getNodeAt(index - 1);
438
419
  newNode.next = prevNode.next;
@@ -441,43 +422,31 @@ export class SinglyLinkedList extends LinearLinkedBase {
441
422
  return true;
442
423
  }
443
424
  /**
444
- * Time Complexity: O(n)
445
- * Space Complexity: O(1)
446
- *
447
- * The function setAt(index, value) updates the value at a specified index in a data structure if the
448
- * index exists.
449
- * @param {number} index - The `index` parameter in the `setAt` method refers to the position in the
450
- * data structure where you want to set a new value.
451
- * @param {E} value - The `value` parameter in the `setAt` method represents the new value that you
452
- * want to set at the specified index in the data structure.
453
- * @returns The `setAt` method returns a boolean value - `true` if the value at the specified index
454
- * is successfully updated, and `false` if the index is out of bounds (i.e., the node at that index
455
- * does not exist).
425
+ * Set the element value at an index.
426
+ * @remarks Time O(N), Space O(1)
427
+ * @param index - Zero-based index.
428
+ * @param value - New value.
429
+ * @returns True if updated.
456
430
  */
457
431
  setAt(index, value) {
458
432
  const node = this.getNodeAt(index);
459
- if (node) {
460
- node.value = value;
461
- return true;
462
- }
463
- return false;
433
+ if (!node)
434
+ return false;
435
+ node.value = value;
436
+ return true;
464
437
  }
465
438
  /**
466
- * Time Complexity: O(1)
467
- * Space Complexity: O(1)
468
- *
469
- * The function checks if the length of a data structure is equal to zero and returns a boolean value indicating
470
- * whether it is empty or not.
471
- * @returns A boolean value indicating whether the length of the object is equal to 0.
439
+ * Check whether the list is empty.
440
+ * @remarks Time O(1), Space O(1)
441
+ * @returns True if length is 0.
472
442
  */
473
443
  isEmpty() {
474
444
  return this._length === 0;
475
445
  }
476
446
  /**
477
- * Time Complexity: O(1)
478
- * Space Complexity: O(1)
479
- *
480
- * The `clear` function resets the linked list by setting the head, tail, and length to undefined and 0 respectively.
447
+ * Remove all nodes and reset length.
448
+ * @remarks Time O(N), Space O(1)
449
+ * @returns void
481
450
  */
482
451
  clear() {
483
452
  this._head = undefined;
@@ -485,18 +454,16 @@ export class SinglyLinkedList extends LinearLinkedBase {
485
454
  this._length = 0;
486
455
  }
487
456
  /**
488
- * Time Complexity: O(n)
489
- * Space Complexity: O(1)
490
- *
491
- * The `reverse` function reverses the order of the nodes in a singly linked list.
492
- * @returns The reverse() method does not return anything. It has a return type of void.
457
+ * Reverse the list in place.
458
+ * @remarks Time O(N), Space O(1)
459
+ * @returns This list.
493
460
  */
494
461
  reverse() {
495
462
  if (!this.head || this.head === this.tail)
496
463
  return this;
497
- let prev = undefined;
464
+ let prev;
498
465
  let current = this.head;
499
- let next = undefined;
466
+ let next;
500
467
  while (current) {
501
468
  next = current.next;
502
469
  current.next = prev;
@@ -507,17 +474,10 @@ export class SinglyLinkedList extends LinearLinkedBase {
507
474
  return this;
508
475
  }
509
476
  /**
510
- * Time Complexity: O(n)
511
- * Space Complexity: O(1)
512
- *
513
- * The function `getNode` in TypeScript searches for a node in a singly linked list based on a given
514
- * element, node, or predicate.
515
- * @param {E | SinglyLinkedListNode<E> | ((node: SinglyLinkedListNode<E>) => boolean) | undefined} elementNodeOrPredicate
516
- * elementNodeOrPredicate - The `elementNodeOrPredicate` parameter in the `getNode` method can be one
517
- * of the following types:
518
- * @returns The `getNode` method returns either a `SinglyLinkedListNode<E>` if a matching node is
519
- * found based on the provided predicate, or it returns `undefined` if no matching node is found or
520
- * if the input parameter is `undefined`.
477
+ * Find a node by value, reference, or predicate.
478
+ * @remarks Time O(N), Space O(1)
479
+ * @param [elementNodeOrPredicate] - Element, node, or node predicate to match.
480
+ * @returns Matching node or undefined.
521
481
  */
522
482
  getNode(elementNodeOrPredicate) {
523
483
  if (elementNodeOrPredicate === undefined)
@@ -527,28 +487,18 @@ export class SinglyLinkedList extends LinearLinkedBase {
527
487
  const predicate = this._ensurePredicate(elementNodeOrPredicate);
528
488
  let current = this.head;
529
489
  while (current) {
530
- if (predicate(current)) {
490
+ if (predicate(current))
531
491
  return current;
532
- }
533
492
  current = current.next;
534
493
  }
535
494
  return undefined;
536
495
  }
537
496
  /**
538
- * Time Complexity: O(n)
539
- * Space Complexity: O(1)
540
- *
541
- * The function `addBefore` in TypeScript adds a new element or node before an existing element or
542
- * node in a singly linked list.
543
- * @param {E | SinglyLinkedListNode<E>} existingElementOrNode - existingElementOrNode represents the
544
- * element or node in the linked list before which you want to add a new element or node.
545
- * @param {E | SinglyLinkedListNode<E>} newElementOrNode - The `newElementOrNode` parameter in the
546
- * `addBefore` method represents the element or node that you want to insert before the existing
547
- * element or node in the linked list. This new element can be of type `E` or a
548
- * `SinglyLinkedListNode<E>`.
549
- * @returns The `addBefore` method returns a boolean value - `true` if the new element or node was
550
- * successfully added before the existing element or node, and `false` if the operation was
551
- * unsuccessful.
497
+ * Insert a new element/node before an existing one.
498
+ * @remarks Time O(N), Space O(1)
499
+ * @param existingElementOrNode - Existing element or node.
500
+ * @param newElementOrNode - Element or node to insert.
501
+ * @returns True if inserted.
552
502
  */
553
503
  addBefore(existingElementOrNode, newElementOrNode) {
554
504
  const existingNode = this.getNode(existingElementOrNode);
@@ -557,8 +507,11 @@ export class SinglyLinkedList extends LinearLinkedBase {
557
507
  const prevNode = this._getPrevNode(existingNode);
558
508
  const newNode = this._ensureNode(newElementOrNode);
559
509
  if (!prevNode) {
560
- // Add at the head
561
- this.unshift(newNode);
510
+ newNode.next = this._head;
511
+ this._head = newNode;
512
+ if (!this._tail)
513
+ this._tail = newNode;
514
+ this._length++;
562
515
  }
563
516
  else {
564
517
  prevNode.next = newNode;
@@ -568,299 +521,327 @@ export class SinglyLinkedList extends LinearLinkedBase {
568
521
  return true;
569
522
  }
570
523
  /**
571
- * Time Complexity: O(n)
572
- * Space Complexity: O(1)
573
- *
574
- * The `addAfter` function in TypeScript adds a new element or node after an existing element or node
575
- * in a singly linked list.
576
- * @param {E | SinglyLinkedListNode<E>} existingElementOrNode - existingElementOrNode can be either
577
- * an element of type E or a SinglyLinkedListNode of type E.
578
- * @param {E | SinglyLinkedListNode<E>} newElementOrNode - The `newElementOrNode` parameter in the
579
- * `addAfter` method represents the element or node that you want to add after the existing element
580
- * or node in a singly linked list. This parameter can be either the value of the new element or a
581
- * reference to a `SinglyLinkedListNode` containing
582
- * @returns The `addAfter` method returns a boolean value - `true` if the new element or node was
583
- * successfully added after the existing element or node, and `false` if the existing element or node
584
- * was not found.
524
+ * Insert a new element/node after an existing one.
525
+ * @remarks Time O(N), Space O(1)
526
+ * @param existingElementOrNode - Existing element or node.
527
+ * @param newElementOrNode - Element or node to insert.
528
+ * @returns True if inserted.
585
529
  */
586
530
  addAfter(existingElementOrNode, newElementOrNode) {
587
531
  const existingNode = this.getNode(existingElementOrNode);
588
- if (existingNode) {
589
- const newNode = this._ensureNode(newElementOrNode);
590
- newNode.next = existingNode.next;
591
- existingNode.next = newNode;
592
- if (existingNode === this.tail) {
593
- this._tail = newNode;
594
- }
595
- this._length++;
596
- return true;
597
- }
598
- return false;
532
+ if (!existingNode)
533
+ return false;
534
+ const newNode = this._ensureNode(newElementOrNode);
535
+ newNode.next = existingNode.next;
536
+ existingNode.next = newNode;
537
+ if (existingNode === this.tail)
538
+ this._tail = newNode;
539
+ this._length++;
540
+ return true;
599
541
  }
600
542
  /**
601
- * Time Complexity: O(n)
602
- * Space Complexity: O(1)
603
- *
604
- * The function `splice` in TypeScript overrides the default behavior to remove and insert elements
605
- * in a singly linked list while handling boundary cases.
606
- * @param {number} start - The `start` parameter in the `splice` method indicates the index at which
607
- * to start modifying the list. It specifies the position where elements will be added or removed.
608
- * @param {number} [deleteCount=0] - The `deleteCount` parameter in the `splice` method specifies the
609
- * number of elements to remove from the array starting at the specified `start` index. If
610
- * `deleteCount` is not provided, it defaults to 0, meaning no elements will be removed but new
611
- * elements can still be inserted at
612
- * @param {E[]} items - The `items` parameter in the `splice` method represents the elements to be
613
- * inserted into the list at the specified `start` index. These elements will be inserted in place of
614
- * the elements that are removed from the list. The `splice` method allows you to add new elements to
615
- * the list while
616
- * @returns The `splice` method is returning a `SinglyLinkedList` containing the elements that were
617
- * removed from the original list during the splice operation.
543
+ * Remove and/or insert elements at a position (array-like behavior).
544
+ * @remarks Time O(N + M), Space O(M)
545
+ * @param start - Start index (clamped to [0, length]).
546
+ * @param [deleteCount] - Number of elements to remove (default 0).
547
+ * @param [items] - Elements to insert after `start`.
548
+ * @returns A new list containing the removed elements (typed as `this`).
618
549
  */
619
550
  splice(start, deleteCount = 0, ...items) {
620
- const removedList = this._createInstance({ toElementFn: this._toElementFn, maxLen: this._maxLen });
621
- // If `start` is out of range, perform boundary processing
622
551
  start = Math.max(0, Math.min(start, this.length));
623
552
  deleteCount = Math.max(0, deleteCount);
624
- // Find the predecessor node of `start`
553
+ const removedList = this._createInstance();
625
554
  const prevNode = start === 0 ? undefined : this.getNodeAt(start - 1);
626
- const startNode = prevNode ? prevNode.next : this.head;
627
- let current = startNode;
628
- for (let i = 0; i < deleteCount && current; i++) {
629
- removedList.push(current.value);
630
- current = current.next;
631
- }
632
- const nextNode = current;
633
- let lastInsertedNode = undefined;
634
- for (const item of items) {
635
- const newNode = this._ensureNode(item);
636
- if (!lastInsertedNode) {
637
- if (prevNode) {
638
- prevNode.next = newNode;
639
- }
640
- else {
641
- this._head = newNode;
642
- }
643
- }
644
- else {
645
- lastInsertedNode.next = newNode;
646
- }
647
- lastInsertedNode = newNode;
648
- }
649
- // Connect new node to `nextNode`
650
- if (lastInsertedNode) {
651
- lastInsertedNode.next = nextNode;
555
+ let cur = prevNode ? prevNode.next : this.head;
556
+ let removedCount = 0;
557
+ while (removedCount < deleteCount && cur) {
558
+ removedList.push(cur.value);
559
+ cur = cur.next;
560
+ removedCount++;
652
561
  }
653
- else if (prevNode) {
654
- prevNode.next = nextNode;
562
+ const afterNode = cur;
563
+ if (prevNode) {
564
+ prevNode.next = afterNode;
655
565
  }
656
- // Update tail node and length
657
- if (!nextNode) {
658
- this._tail = lastInsertedNode || prevNode;
566
+ else {
567
+ this._head = afterNode;
568
+ }
569
+ if (!afterNode)
570
+ this._tail = prevNode;
571
+ if (items.length > 0) {
572
+ let firstInserted;
573
+ let lastInserted;
574
+ for (const it of items) {
575
+ const node = this._ensureNode(it);
576
+ if (!firstInserted)
577
+ firstInserted = node;
578
+ if (lastInserted)
579
+ lastInserted.next = node;
580
+ lastInserted = node;
581
+ }
582
+ if (prevNode)
583
+ prevNode.next = firstInserted;
584
+ else
585
+ this._head = firstInserted;
586
+ lastInserted.next = afterNode;
587
+ if (!afterNode)
588
+ this._tail = lastInserted;
589
+ }
590
+ this._length += items.length - removedCount;
591
+ if (this._length === 0) {
592
+ this._head = undefined;
593
+ this._tail = undefined;
659
594
  }
660
- this._length += items.length - removedList.length;
661
595
  return removedList;
662
596
  }
663
597
  /**
664
- * Time Complexity: O(n)
665
- * Space Complexity: O(1)
666
- *
667
- * The function `countOccurrences` iterates through a singly linked list and counts the occurrences
668
- * of a specified element or nodes that satisfy a given predicate.
669
- * @param {E | SinglyLinkedListNode<E> | ((node: SinglyLinkedListNode<E>) => boolean)} elementOrNode
670
- * - The `elementOrNode` parameter in the `countOccurrences` method can accept three types of values:
671
- * @returns The `countOccurrences` method returns the number of occurrences of the specified element,
672
- * node, or predicate function in the singly linked list.
598
+ * Count how many nodes match a value/node/predicate.
599
+ * @remarks Time O(N), Space O(1)
600
+ * @param elementOrNode - Element, node, or node predicate to match.
601
+ * @returns Number of matches in the list.
673
602
  */
674
603
  countOccurrences(elementOrNode) {
675
- const predicate = this._ensurePredicate(elementOrNode);
604
+ const predicate = elementOrPredicate(elementOrNode, this._equals);
676
605
  let count = 0;
677
606
  let current = this.head;
678
607
  while (current) {
679
- if (predicate(current)) {
608
+ if (predicate(current))
680
609
  count++;
681
- }
682
610
  current = current.next;
683
611
  }
684
612
  return count;
685
613
  }
686
614
  /**
687
- * Time Complexity: O(n)
688
- * Space Complexity: O(n)
689
- *
690
- * The `clone` function returns a new instance of the `SinglyLinkedList` class with the same values
691
- * as the original list.
692
- * @returns The `clone()` method is returning a new instance of the `SinglyLinkedList` class, which
693
- * is a clone of the original list.
615
+ * Set the equality comparator used to compare values.
616
+ * @remarks Time O(1), Space O(1)
617
+ * @param equals - Equality predicate (a, b) → boolean.
618
+ * @returns This list.
694
619
  */
695
- clone() {
696
- return new SinglyLinkedList(this, { toElementFn: this.toElementFn, maxLen: this._maxLen });
697
- }
698
- /**
699
- * Time Complexity: O(n)
700
- * Space Complexity: O(n)
701
- *
702
- * The `filter` function creates a new SinglyLinkedList by iterating over the elements of the current
703
- * list and applying a callback function to each element to determine if it should be included in the
704
- * filtered list.
705
- * @param callback - The callback parameter is a function that will be called for each element in the
706
- * list. It takes three arguments: the current element, the index of the current element, and the
707
- * list itself. The callback function should return a boolean value indicating whether the current
708
- * element should be included in the filtered list or not
709
- * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that specifies the value
710
- * to be used as `this` when executing the `callback` function. If `thisArg` is provided, it will be
711
- * passed as the `this` value to the `callback` function. If `thisArg` is
712
- * @returns The `filter` method is returning a new `SinglyLinkedList` object that contains the
713
- * elements that pass the filter condition specified by the `callback` function.
620
+ setEquality(equals) {
621
+ this._equals = equals;
622
+ return this;
623
+ }
624
+ /**
625
+ * Delete the first node whose value matches a predicate.
626
+ * @remarks Time O(N), Space O(1)
627
+ * @param predicate - Predicate (value, index, list) boolean to decide deletion.
628
+ * @returns True if a node was removed.
714
629
  */
715
- filter(callback, thisArg) {
716
- const filteredList = this._createInstance({ toElementFn: this.toElementFn, maxLen: this._maxLen });
717
- let index = 0;
718
- for (const current of this) {
719
- if (callback.call(thisArg, current, index, this)) {
720
- filteredList.push(current);
630
+ deleteWhere(predicate) {
631
+ let prev;
632
+ let current = this.head;
633
+ let i = 0;
634
+ while (current) {
635
+ if (predicate(current.value, i++, this)) {
636
+ if (!prev) {
637
+ this._head = current.next;
638
+ if (current === this._tail)
639
+ this._tail = undefined;
640
+ }
641
+ else {
642
+ prev.next = current.next;
643
+ if (current === this._tail)
644
+ this._tail = prev;
645
+ }
646
+ this._length--;
647
+ return true;
721
648
  }
722
- index++;
723
- }
724
- return filteredList;
725
- }
726
- /**
727
- * Time Complexity: O(n)
728
- * Space Complexity: O(n)
729
- *
730
- * The `map` function takes a callback function and returns a new SinglyLinkedList with the results
731
- * of applying the callback to each element in the original list.
732
- * @param callback - The `callback` parameter is a function that will be called for each element in
733
- * the original list. It takes three arguments: `current` (the current element being processed),
734
- * `index` (the index of the current element), and `this` (the original list). It should return a
735
- * value
736
- * @param [toElementFn] - The `toElementFn` parameter is an optional function that can be used to
737
- * convert the raw element (`RR`) to the desired element type (`T`). It takes the raw element as
738
- * input and returns the converted element. If this parameter is not provided, the raw element will
739
- * be used as is.
740
- * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that allows you to
741
- * specify the value of `this` within the callback function. It is used to set the context or scope
742
- * in which the callback function will be executed. If `thisArg` is provided, it will be used as the
743
- * value of
744
- * @returns a new instance of the `SinglyLinkedList` class with the mapped elements.
745
- */
746
- map(callback, toElementFn, thisArg) {
747
- const mappedList = new SinglyLinkedList([], { toElementFn, maxLen: this._maxLen });
748
- let index = 0;
749
- for (const current of this) {
750
- mappedList.push(callback.call(thisArg, current, index, this));
751
- index++;
649
+ prev = current;
650
+ current = current.next;
752
651
  }
753
- return mappedList;
652
+ return false;
754
653
  }
755
654
  /**
756
- * The function `_createInstance` returns a new instance of `SinglyLinkedList` with the specified
757
- * options.
758
- * @param [options] - The `options` parameter in the `_createInstance` method is of type
759
- * `SinglyLinkedListOptions<E, R>`, which is used to configure the behavior of the `SinglyLinkedList`
760
- * instance being created. It is an optional parameter, meaning it can be omitted when calling the
761
- * method.
762
- * @returns An instance of the `SinglyLinkedList` class with an empty array and the provided options
763
- * is being returned.
655
+ * Deep clone this list (values are copied by reference).
656
+ * @remarks Time O(N), Space O(N)
657
+ * @returns A new list with the same element sequence.
764
658
  */
765
- _createInstance(options) {
766
- return new SinglyLinkedList([], options);
659
+ clone() {
660
+ const out = this._createInstance();
661
+ for (const v of this)
662
+ out.push(v);
663
+ return out;
767
664
  }
768
665
  /**
769
- * The function `_getIterator` returns an iterable iterator that yields the values of a linked list.
666
+ * Filter values into a new list of the same class.
667
+ * @remarks Time O(N), Space O(N)
668
+ * @param callback - Predicate (value, index, list) → boolean to keep value.
669
+ * @param [thisArg] - Value for `this` inside the callback.
670
+ * @returns A new list with kept values.
770
671
  */
771
- *_getIterator() {
772
- let current = this.head;
773
- while (current) {
774
- yield current.value;
775
- current = current.next;
776
- }
672
+ filter(callback, thisArg) {
673
+ const out = this._createInstance();
674
+ let index = 0;
675
+ for (const value of this)
676
+ if (callback.call(thisArg, value, index++, this))
677
+ out.push(value);
678
+ return out;
777
679
  }
778
680
  /**
779
- * The function returns an iterator that iterates over the elements of a collection in reverse order.
681
+ * Map values into a new list of the same class.
682
+ * @remarks Time O(N), Space O(N)
683
+ * @param callback - Mapping function (value, index, list) → newValue.
684
+ * @param [thisArg] - Value for `this` inside the callback.
685
+ * @returns A new list with mapped values.
780
686
  */
781
- *_getReverseIterator() {
782
- const reversedArr = [...this].reverse();
783
- for (const item of reversedArr) {
784
- yield item;
687
+ mapSame(callback, thisArg) {
688
+ const out = this._createInstance();
689
+ let index = 0;
690
+ for (const value of this) {
691
+ const mv = thisArg === undefined ? callback(value, index++, this) : callback.call(thisArg, value, index++, this);
692
+ out.push(mv);
785
693
  }
694
+ return out;
786
695
  }
787
696
  /**
788
- * The function `_getNodeIterator` returns an iterator that iterates over the nodes of a singly
789
- * linked list.
697
+ * Map values into a new list (possibly different element type).
698
+ * @remarks Time O(N), Space O(N)
699
+ * @template EM
700
+ * @template RM
701
+ * @param callback - Mapping function (value, index, list) → newElement.
702
+ * @param [options] - Options for the output list (e.g., maxLen, toElementFn).
703
+ * @param [thisArg] - Value for `this` inside the callback.
704
+ * @returns A new SinglyLinkedList with mapped values.
790
705
  */
791
- *_getNodeIterator() {
792
- let current = this.head;
793
- while (current) {
794
- yield current;
795
- current = current.next;
796
- }
706
+ map(callback, options, thisArg) {
707
+ const out = this._createLike([], { ...(options ?? {}), maxLen: this._maxLen });
708
+ let index = 0;
709
+ for (const value of this)
710
+ out.push(callback.call(thisArg, value, index++, this));
711
+ return out;
712
+ }
713
+ /**
714
+ * (Protected) Create a node from a value.
715
+ * @remarks Time O(1), Space O(1)
716
+ * @param value - Value to wrap in a node.
717
+ * @returns A new SinglyLinkedListNode instance.
718
+ */
719
+ _createNode(value) {
720
+ return new SinglyLinkedListNode(value);
797
721
  }
798
- // protected *_getReverseNodeIterator(): IterableIterator<SinglyLinkedListNode<E>> {
799
- // const reversedArr = [...this._getNodeIterator()].reverse();
800
- //
801
- // for (const item of reversedArr) {
802
- // yield item;
803
- // }
804
- // }
805
- /**
806
- * The _isPredicate function in TypeScript checks if the input is a function that takes a
807
- * SinglyLinkedListNode as an argument and returns a boolean.
808
- * @param {E | SinglyLinkedListNode<E> | ((node: SinglyLinkedListNode<E>) => boolean)} elementNodeOrPredicate
809
- * elementNodeOrPredicate - The `elementNodeOrPredicate` parameter can be one of the following types:
810
- * @returns The _isPredicate method is returning a boolean value based on whether the
811
- * elementNodeOrPredicate parameter is a function or not. If the elementNodeOrPredicate is a
812
- * function, the method will return true, indicating that it is a predicate function. If it is not a
813
- * function, the method will return false.
722
+ /**
723
+ * (Protected) Check if input is a node predicate function.
724
+ * @remarks Time O(1), Space O(1)
725
+ * @param elementNodeOrPredicate - Element, node, or node predicate.
726
+ * @returns True if input is a predicate function.
814
727
  */
815
728
  _isPredicate(elementNodeOrPredicate) {
816
729
  return typeof elementNodeOrPredicate === 'function';
817
730
  }
818
731
  /**
819
- * The function `_ensureNode` ensures that the input is a valid node and returns it, creating a new
820
- * node if necessary.
821
- * @param {E | SinglyLinkedListNode<E>} elementOrNode - The `elementOrNode` parameter can be either
822
- * an element of type `E` or a `SinglyLinkedListNode` containing an element of type `E`.
823
- * @returns A SinglyLinkedListNode<E> object is being returned.
732
+ * (Protected) Normalize input into a node instance.
733
+ * @remarks Time O(1), Space O(1)
734
+ * @param elementOrNode - Element or node.
735
+ * @returns A SinglyLinkedListNode for the provided input.
824
736
  */
825
737
  _ensureNode(elementOrNode) {
826
738
  if (this.isNode(elementOrNode))
827
739
  return elementOrNode;
828
- return new SinglyLinkedListNode(elementOrNode);
740
+ return this._createNode(elementOrNode);
829
741
  }
830
742
  /**
831
- * The function `_ensurePredicate` in TypeScript ensures that the input is either a node, a predicate
832
- * function, or a value to compare with the node's value.
833
- * @param {E | SinglyLinkedListNode<E> | ((node: SinglyLinkedListNode<E>) => boolean)} elementNodeOrPredicate
834
- * elementNodeOrPredicate - The `elementNodeOrPredicate` parameter can be one of the following types:
835
- * @returns A function is being returned. If the input `elementNodeOrPredicate` is already a node, a
836
- * function is returned that checks if a given node is equal to the input node. If the input is a
837
- * predicate function, it is returned as is. If the input is neither a node nor a predicate function,
838
- * a function is returned that checks if a given node's value is equal to the input
743
+ * (Protected) Normalize input into a node predicate.
744
+ * @remarks Time O(1), Space O(1)
745
+ * @param elementNodeOrPredicate - Element, node, or predicate.
746
+ * @returns A predicate taking a node and returning true/false.
839
747
  */
840
748
  _ensurePredicate(elementNodeOrPredicate) {
841
749
  if (this.isNode(elementNodeOrPredicate))
842
750
  return (node) => node === elementNodeOrPredicate;
843
751
  if (this._isPredicate(elementNodeOrPredicate))
844
752
  return elementNodeOrPredicate;
845
- return (node) => node.value === elementNodeOrPredicate;
753
+ const value = elementNodeOrPredicate;
754
+ return (node) => this._equals(node.value, value);
846
755
  }
847
756
  /**
848
- * The function `_getPrevNode` returns the node before a given node in a singly linked list.
849
- * @param node - The `node` parameter in the `_getPrevNode` method is a reference to a node in a
850
- * singly linked list. The method is used to find the node that comes before the given node in the
851
- * linked list.
852
- * @returns The `_getPrevNode` method returns either the previous node of the input node in a singly
853
- * linked list or `undefined` if the input node is the head of the list or if the input node is not
854
- * found in the list.
757
+ * (Protected) Get the previous node of a given node.
758
+ * @remarks Time O(N), Space O(1)
759
+ * @param node - A node in the list.
760
+ * @returns Previous node or undefined.
855
761
  */
856
762
  _getPrevNode(node) {
857
763
  if (!this.head || this.head === node)
858
764
  return undefined;
859
765
  let current = this.head;
860
- while (current.next && current.next !== node) {
766
+ while (current.next && current.next !== node)
861
767
  current = current.next;
862
- }
863
768
  return current.next === node ? current : undefined;
864
769
  }
770
+ /**
771
+ * (Protected) Iterate values from head to tail.
772
+ * @remarks Time O(N), Space O(1)
773
+ * @returns Iterator of values (E).
774
+ */
775
+ *_getIterator() {
776
+ let current = this.head;
777
+ while (current) {
778
+ yield current.value;
779
+ current = current.next;
780
+ }
781
+ }
782
+ /**
783
+ * (Protected) Iterate values from tail to head.
784
+ * @remarks Time O(N), Space O(N)
785
+ * @returns Iterator of values (E).
786
+ */
787
+ *_getReverseIterator() {
788
+ const reversedArr = [...this].reverse();
789
+ for (const item of reversedArr)
790
+ yield item;
791
+ }
792
+ /**
793
+ * (Protected) Iterate nodes from head to tail.
794
+ * @remarks Time O(N), Space O(1)
795
+ * @returns Iterator of nodes.
796
+ */
797
+ *_getNodeIterator() {
798
+ let current = this.head;
799
+ while (current) {
800
+ yield current;
801
+ current = current.next;
802
+ }
803
+ }
804
+ /**
805
+ * (Protected) Create an empty instance of the same concrete class.
806
+ * @remarks Time O(1), Space O(1)
807
+ * @param [options] - Options forwarded to the constructor.
808
+ * @returns An empty like-kind list instance.
809
+ */
810
+ _createInstance(options) {
811
+ const Ctor = this.constructor;
812
+ return new Ctor([], options);
813
+ }
814
+ /**
815
+ * (Protected) Create a like-kind instance and seed it from an iterable.
816
+ * @remarks Time O(N), Space O(N)
817
+ * @template EM
818
+ * @template RM
819
+ * @param [elements] - Iterable used to seed the new list.
820
+ * @param [options] - Options forwarded to the constructor.
821
+ * @returns A like-kind SinglyLinkedList instance.
822
+ */
823
+ _createLike(elements = [], options) {
824
+ const Ctor = this.constructor;
825
+ return new Ctor(elements, options);
826
+ }
827
+ /**
828
+ * (Protected) Spawn an empty like-kind list instance.
829
+ * @remarks Time O(1), Space O(1)
830
+ * @template EM
831
+ * @template RM
832
+ * @param [options] - Options forwarded to the constructor.
833
+ * @returns An empty like-kind SinglyLinkedList instance.
834
+ */
835
+ _spawnLike(options) {
836
+ return this._createLike([], options);
837
+ }
838
+ }
839
+ function elementOrPredicate(input, equals) {
840
+ if (input instanceof SinglyLinkedListNode)
841
+ return (node) => node === input;
842
+ if (typeof input === 'function')
843
+ return input;
844
+ const value = input;
845
+ return (node) => equals(node.value, value);
865
846
  }
866
847
  //# sourceMappingURL=singly-linked-list.js.map