data-structure-typed 0.8.6

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 (166) hide show
  1. package/.idea/data-structure-typed.iml +12 -0
  2. package/.idea/modules.xml +8 -0
  3. package/.idea/vcs.xml +6 -0
  4. package/README.md +2 -0
  5. package/dist/data-structures/binary-tree/aa-tree.js +6 -0
  6. package/dist/data-structures/binary-tree/avl-tree.js +231 -0
  7. package/dist/data-structures/binary-tree/b-tree.js +6 -0
  8. package/dist/data-structures/binary-tree/binary-indexed-tree.js +31 -0
  9. package/dist/data-structures/binary-tree/binary-tree.js +992 -0
  10. package/dist/data-structures/binary-tree/bst.js +431 -0
  11. package/dist/data-structures/binary-tree/index.js +20 -0
  12. package/dist/data-structures/binary-tree/rb-tree.js +6 -0
  13. package/dist/data-structures/binary-tree/segment-tree.js +151 -0
  14. package/dist/data-structures/binary-tree/splay-tree.js +6 -0
  15. package/dist/data-structures/binary-tree/tree-multiset.js +16 -0
  16. package/dist/data-structures/binary-tree/two-three-tree.js +6 -0
  17. package/dist/data-structures/graph/abstract-graph.js +648 -0
  18. package/dist/data-structures/graph/directed-graph.js +268 -0
  19. package/dist/data-structures/graph/index.js +19 -0
  20. package/dist/data-structures/graph/undirected-graph.js +142 -0
  21. package/dist/data-structures/hash/coordinate-map.js +24 -0
  22. package/dist/data-structures/hash/coordinate-set.js +21 -0
  23. package/dist/data-structures/hash/hash-table.js +2 -0
  24. package/dist/data-structures/hash/index.js +17 -0
  25. package/dist/data-structures/hash/pair.js +2 -0
  26. package/dist/data-structures/hash/tree-map.js +2 -0
  27. package/dist/data-structures/hash/tree-set.js +2 -0
  28. package/dist/data-structures/heap/heap.js +114 -0
  29. package/dist/data-structures/heap/index.js +19 -0
  30. package/dist/data-structures/heap/max-heap.js +22 -0
  31. package/dist/data-structures/heap/min-heap.js +22 -0
  32. package/dist/data-structures/index.js +25 -0
  33. package/dist/data-structures/linked-list/doubly-linked-list.js +259 -0
  34. package/dist/data-structures/linked-list/index.js +18 -0
  35. package/dist/data-structures/linked-list/singly-linked-list.js +660 -0
  36. package/dist/data-structures/linked-list/skip-linked-list.js +2 -0
  37. package/dist/data-structures/matrix/index.js +19 -0
  38. package/dist/data-structures/matrix/matrix.js +14 -0
  39. package/dist/data-structures/matrix/matrix2d.js +119 -0
  40. package/dist/data-structures/matrix/navigator.js +78 -0
  41. package/dist/data-structures/matrix/vector2d.js +161 -0
  42. package/dist/data-structures/priority-queue/index.js +19 -0
  43. package/dist/data-structures/priority-queue/max-priority-queue.js +15 -0
  44. package/dist/data-structures/priority-queue/min-priority-queue.js +15 -0
  45. package/dist/data-structures/priority-queue/priority-queue.js +174 -0
  46. package/dist/data-structures/queue/deque.js +132 -0
  47. package/dist/data-structures/queue/index.js +17 -0
  48. package/dist/data-structures/queue/queue.js +113 -0
  49. package/dist/data-structures/stack/index.js +17 -0
  50. package/dist/data-structures/stack/stack.js +97 -0
  51. package/dist/data-structures/trampoline.js +52 -0
  52. package/dist/data-structures/trie/index.js +17 -0
  53. package/dist/data-structures/trie/trie.js +141 -0
  54. package/dist/index.js +17 -0
  55. package/dist/types/data-structures/binary-tree/aa-tree.d.ts +2 -0
  56. package/dist/types/data-structures/binary-tree/avl-tree.d.ts +21 -0
  57. package/dist/types/data-structures/binary-tree/b-tree.d.ts +2 -0
  58. package/dist/types/data-structures/binary-tree/binary-indexed-tree.d.ts +8 -0
  59. package/dist/types/data-structures/binary-tree/binary-tree.d.ts +140 -0
  60. package/dist/types/data-structures/binary-tree/bst.d.ts +32 -0
  61. package/dist/types/data-structures/binary-tree/index.d.ts +4 -0
  62. package/dist/types/data-structures/binary-tree/rb-tree.d.ts +2 -0
  63. package/dist/types/data-structures/binary-tree/segment-tree.d.ts +33 -0
  64. package/dist/types/data-structures/binary-tree/splay-tree.d.ts +2 -0
  65. package/dist/types/data-structures/binary-tree/tree-multiset.d.ts +11 -0
  66. package/dist/types/data-structures/binary-tree/two-three-tree.d.ts +2 -0
  67. package/dist/types/data-structures/graph/abstract-graph.d.ts +126 -0
  68. package/dist/types/data-structures/graph/directed-graph.d.ts +51 -0
  69. package/dist/types/data-structures/graph/index.d.ts +3 -0
  70. package/dist/types/data-structures/graph/undirected-graph.d.ts +24 -0
  71. package/dist/types/data-structures/hash/coordinate-map.d.ts +8 -0
  72. package/dist/types/data-structures/hash/coordinate-set.d.ts +7 -0
  73. package/dist/types/data-structures/hash/hash-table.d.ts +1 -0
  74. package/dist/types/data-structures/hash/index.d.ts +1 -0
  75. package/dist/types/data-structures/hash/pair.d.ts +1 -0
  76. package/dist/types/data-structures/hash/tree-map.d.ts +1 -0
  77. package/dist/types/data-structures/hash/tree-set.d.ts +1 -0
  78. package/dist/types/data-structures/heap/heap.d.ts +72 -0
  79. package/dist/types/data-structures/heap/index.d.ts +3 -0
  80. package/dist/types/data-structures/heap/max-heap.d.ts +14 -0
  81. package/dist/types/data-structures/heap/min-heap.d.ts +14 -0
  82. package/dist/types/data-structures/index.d.ts +9 -0
  83. package/dist/types/data-structures/linked-list/doubly-linked-list.d.ts +59 -0
  84. package/dist/types/data-structures/linked-list/index.d.ts +2 -0
  85. package/dist/types/data-structures/linked-list/singly-linked-list.d.ts +358 -0
  86. package/dist/types/data-structures/linked-list/skip-linked-list.d.ts +1 -0
  87. package/dist/types/data-structures/matrix/index.d.ts +3 -0
  88. package/dist/types/data-structures/matrix/matrix.d.ts +9 -0
  89. package/dist/types/data-structures/matrix/matrix2d.d.ts +25 -0
  90. package/dist/types/data-structures/matrix/navigator.d.ts +31 -0
  91. package/dist/types/data-structures/matrix/vector2d.d.ts +74 -0
  92. package/dist/types/data-structures/priority-queue/index.d.ts +3 -0
  93. package/dist/types/data-structures/priority-queue/max-priority-queue.d.ts +4 -0
  94. package/dist/types/data-structures/priority-queue/min-priority-queue.d.ts +4 -0
  95. package/dist/types/data-structures/priority-queue/priority-queue.d.ts +36 -0
  96. package/dist/types/data-structures/queue/deque.d.ts +37 -0
  97. package/dist/types/data-structures/queue/index.d.ts +1 -0
  98. package/dist/types/data-structures/queue/queue.d.ts +76 -0
  99. package/dist/types/data-structures/stack/index.d.ts +1 -0
  100. package/dist/types/data-structures/stack/stack.d.ts +69 -0
  101. package/dist/types/data-structures/trampoline.d.ts +25 -0
  102. package/dist/types/data-structures/trie/index.d.ts +1 -0
  103. package/dist/types/data-structures/trie/trie.d.ts +28 -0
  104. package/dist/types/index.d.ts +1 -0
  105. package/dist/types/index.js +17 -0
  106. package/dist/types/types/index.d.ts +1 -0
  107. package/dist/types/types/utils.d.ts +46 -0
  108. package/dist/types/utils.d.ts +122 -0
  109. package/dist/types/utils.js +53 -0
  110. package/dist/utils.js +569 -0
  111. package/package.json +75 -0
  112. package/src/data-structures/binary-tree/aa-tree.ts +3 -0
  113. package/src/data-structures/binary-tree/avl-tree.ts +232 -0
  114. package/src/data-structures/binary-tree/b-tree.ts +3 -0
  115. package/src/data-structures/binary-tree/binary-indexed-tree.ts +33 -0
  116. package/src/data-structures/binary-tree/binary-tree.ts +1088 -0
  117. package/src/data-structures/binary-tree/bst.ts +404 -0
  118. package/src/data-structures/binary-tree/index.ts +4 -0
  119. package/src/data-structures/binary-tree/rb-tree.ts +3 -0
  120. package/src/data-structures/binary-tree/segment-tree.ts +164 -0
  121. package/src/data-structures/binary-tree/splay-tree.ts +3 -0
  122. package/src/data-structures/binary-tree/tree-multiset.ts +21 -0
  123. package/src/data-structures/binary-tree/two-three-tree.ts +3 -0
  124. package/src/data-structures/graph/abstract-graph.ts +789 -0
  125. package/src/data-structures/graph/directed-graph.ts +322 -0
  126. package/src/data-structures/graph/index.ts +3 -0
  127. package/src/data-structures/graph/undirected-graph.ts +154 -0
  128. package/src/data-structures/hash/coordinate-map.ts +24 -0
  129. package/src/data-structures/hash/coordinate-set.ts +20 -0
  130. package/src/data-structures/hash/hash-table.ts +1 -0
  131. package/src/data-structures/hash/index.ts +1 -0
  132. package/src/data-structures/hash/pair.ts +1 -0
  133. package/src/data-structures/hash/tree-map.ts +1 -0
  134. package/src/data-structures/hash/tree-set.ts +1 -0
  135. package/src/data-structures/heap/heap.ts +136 -0
  136. package/src/data-structures/heap/index.ts +3 -0
  137. package/src/data-structures/heap/max-heap.ts +22 -0
  138. package/src/data-structures/heap/min-heap.ts +24 -0
  139. package/src/data-structures/index.ts +10 -0
  140. package/src/data-structures/linked-list/doubly-linked-list.ts +258 -0
  141. package/src/data-structures/linked-list/index.ts +2 -0
  142. package/src/data-structures/linked-list/singly-linked-list.ts +750 -0
  143. package/src/data-structures/linked-list/skip-linked-list.ts +1 -0
  144. package/src/data-structures/matrix/index.ts +3 -0
  145. package/src/data-structures/matrix/matrix.ts +13 -0
  146. package/src/data-structures/matrix/matrix2d.ts +125 -0
  147. package/src/data-structures/matrix/navigator.ts +99 -0
  148. package/src/data-structures/matrix/vector2d.ts +189 -0
  149. package/src/data-structures/priority-queue/index.ts +3 -0
  150. package/src/data-structures/priority-queue/max-priority-queue.ts +12 -0
  151. package/src/data-structures/priority-queue/min-priority-queue.ts +12 -0
  152. package/src/data-structures/priority-queue/priority-queue.ts +208 -0
  153. package/src/data-structures/queue/deque.ts +139 -0
  154. package/src/data-structures/queue/index.ts +1 -0
  155. package/src/data-structures/queue/queue.ts +123 -0
  156. package/src/data-structures/stack/index.ts +1 -0
  157. package/src/data-structures/stack/stack.ts +104 -0
  158. package/src/data-structures/trampoline.ts +91 -0
  159. package/src/data-structures/trie/index.ts +1 -0
  160. package/src/data-structures/trie/trie.ts +153 -0
  161. package/src/index.ts +1 -0
  162. package/src/types/index.ts +1 -0
  163. package/src/types/patches/index.d.ts +0 -0
  164. package/src/types/utils.ts +158 -0
  165. package/src/utils.ts +605 -0
  166. package/tsconfig.json +52 -0
@@ -0,0 +1,1088 @@
1
+ import {ThunkOrValue, trampoline} from '../trampoline';
2
+
3
+ export type BinaryTreeNodePropertyName = 'id' | 'val' | 'count';
4
+ export type NodeOrPropertyName = 'node' | BinaryTreeNodePropertyName;
5
+ export type DFSOrderPattern = 'in' | 'pre' | 'post';
6
+ export type BinaryTreeNodeId = number;
7
+ export type BinaryTreeDeleted<T> = { deleted: BinaryTreeNode<T> | null | undefined, needBalanced: BinaryTreeNode<T> | null };
8
+ export type ResultByProperty<T> = T | BinaryTreeNode<T> | number | BinaryTreeNodeId;
9
+ export type ResultsByProperty<T> = ResultByProperty<T>[];
10
+
11
+ export interface BinaryTreeNodeObj<T> {
12
+ id: BinaryTreeNodeId;
13
+ val: T;
14
+ count?: number;
15
+ }
16
+
17
+ export enum FamilyPosition {root, left, right}
18
+
19
+ export enum LoopType { iterative = 1, recursive = 2}
20
+
21
+ export class BinaryTreeNode<T> {
22
+ protected _id: BinaryTreeNodeId;
23
+ get id(): BinaryTreeNodeId {
24
+ return this._id;
25
+ }
26
+
27
+ set id(v: BinaryTreeNodeId) {
28
+ this._id = v;
29
+ }
30
+
31
+ protected _val: T;
32
+ get val(): T {
33
+ return this._val;
34
+ }
35
+
36
+ set val(v: T) {
37
+ this._val = v;
38
+ }
39
+
40
+ protected _left?: BinaryTreeNode<T> | null;
41
+ get left(): BinaryTreeNode<T> | null | undefined {
42
+ return this._left;
43
+ }
44
+
45
+ set left(v: BinaryTreeNode<T> | null | undefined) {
46
+ if (v) {
47
+ v.parent = this;
48
+ v.familyPosition = FamilyPosition.left;
49
+ }
50
+ this._left = v;
51
+ }
52
+
53
+ protected _right?: BinaryTreeNode<T> | null;
54
+ get right(): BinaryTreeNode<T> | null | undefined {
55
+ return this._right;
56
+ }
57
+
58
+ set right(v: BinaryTreeNode<T> | null | undefined) {
59
+ if (v) {
60
+ v.parent = this;
61
+ v.familyPosition = FamilyPosition.right;
62
+ }
63
+ this._right = v;
64
+ }
65
+
66
+ protected _parent: BinaryTreeNode<T> | null | undefined = undefined;
67
+ get parent(): BinaryTreeNode<T> | null | undefined {
68
+ return this._parent;
69
+ }
70
+
71
+ set parent(v: BinaryTreeNode<T> | null | undefined) {
72
+ this._parent = v;
73
+ }
74
+
75
+ protected _familyPosition: FamilyPosition = FamilyPosition.root;
76
+ get familyPosition(): FamilyPosition {
77
+ return this._familyPosition;
78
+ }
79
+
80
+ set familyPosition(v: FamilyPosition) {
81
+ this._familyPosition = v;
82
+ }
83
+
84
+ protected _count = 1;
85
+ get count(): number {
86
+ return this._count;
87
+ }
88
+
89
+ set count(v: number) {
90
+ this._count = v;
91
+ }
92
+
93
+ protected _height = 0;
94
+
95
+ get height(): number {
96
+ return this._height;
97
+ }
98
+
99
+ set height(v: number) {
100
+ this._height = v;
101
+ }
102
+
103
+ constructor(id: BinaryTreeNodeId, val: T, count?: number) {
104
+ this._id = id;
105
+ this._val = val;
106
+ this._count = count ?? 1;
107
+ }
108
+
109
+ swapLocation(swapNode: BinaryTreeNode<T>): BinaryTreeNode<T> {
110
+ const {val, count, height} = swapNode;
111
+ const tempNode = new BinaryTreeNode<T>(swapNode.id, val);
112
+ tempNode.val = val;
113
+ tempNode.count = count;
114
+ tempNode.height = height;
115
+
116
+ swapNode.id = this.id;
117
+ swapNode.val = this.val;
118
+ swapNode.count = this.count;
119
+ swapNode.height = this.height;
120
+
121
+ this.id = tempNode.id;
122
+ this.val = tempNode.val;
123
+ this.count = tempNode.count;
124
+ this.height = tempNode.height;
125
+ return swapNode;
126
+ }
127
+
128
+ clone(): BinaryTreeNode<T> {
129
+ return new BinaryTreeNode<T>(this.id, this.val, this.count);
130
+ }
131
+ }
132
+
133
+ export class BinaryTree<T> {
134
+ protected _root: BinaryTreeNode<T> | null = null;
135
+ public get root(): BinaryTreeNode<T> | null {
136
+ return this._root;
137
+ }
138
+
139
+ protected set root(v: BinaryTreeNode<T> | null) {
140
+ if (v) {
141
+ v.parent = null;
142
+ v.familyPosition = FamilyPosition.root;
143
+ }
144
+ this._root = v;
145
+ }
146
+
147
+ protected _size = 0;
148
+ get size(): number {
149
+ return this._size;
150
+ }
151
+
152
+ protected set size(v: number) {
153
+ this._size = v;
154
+ }
155
+
156
+ protected _count = 0;
157
+ get count(): number {
158
+ return this._count;
159
+ }
160
+
161
+ protected set count(v: number) {
162
+ this._count = v;
163
+ }
164
+
165
+ private readonly _autoIncrementId: boolean = false;
166
+ private _maxId: number = -1;
167
+ private readonly _isDuplicatedVal: boolean = false;
168
+
169
+ protected _loopType: LoopType = LoopType.iterative;
170
+ protected _visitedId: BinaryTreeNodeId[] = [];
171
+ protected _visitedVal: Array<T> = [];
172
+ protected _visitedNode: BinaryTreeNode<T>[] = [];
173
+ protected _visitedCount: number[] = [];
174
+ protected _visitedLeftSum: number[] = [];
175
+
176
+ protected _resetResults() {
177
+ this._visitedId = [];
178
+ this._visitedVal = [];
179
+ this._visitedNode = [];
180
+ this._visitedCount = [];
181
+ this._visitedLeftSum = [];
182
+ }
183
+
184
+ constructor(options?: {
185
+ loopType?: LoopType,
186
+ autoIncrementId?: boolean,
187
+ isDuplicatedVal?: boolean
188
+ }) {
189
+ if (options !== undefined) {
190
+ const {
191
+ loopType = LoopType.iterative,
192
+ autoIncrementId = false,
193
+ isDuplicatedVal = false
194
+ } = options;
195
+ this._isDuplicatedVal = isDuplicatedVal;
196
+ this._autoIncrementId = autoIncrementId;
197
+ this._loopType = loopType;
198
+ }
199
+ }
200
+
201
+ createNode(id: BinaryTreeNodeId, val: T | null, count?: number): BinaryTreeNode<T> | null {
202
+ return val !== null ? new BinaryTreeNode(id, val, count) : null;
203
+ }
204
+
205
+ clear() {
206
+ this.root = null;
207
+ this.size = 0;
208
+ this.count = 0;
209
+ this._maxId = -1;
210
+ }
211
+
212
+ isEmpty(): boolean {
213
+ return this.size === 0;
214
+ }
215
+
216
+ insertTo({newNode, parent}: { newNode: BinaryTreeNode<T> | null, parent: BinaryTreeNode<T> }) {
217
+ if (parent) {
218
+ if (parent.left === undefined) {
219
+ if (newNode) {
220
+ newNode.parent = parent;
221
+ newNode.familyPosition = FamilyPosition.left;
222
+ }
223
+ parent.left = newNode;
224
+ if (newNode !== null) {
225
+ this.size++;
226
+ this.count += newNode?.count ?? 0;
227
+ }
228
+
229
+ return parent.left;
230
+ } else if (parent.right === undefined) {
231
+ if (newNode) {
232
+ newNode.parent = parent;
233
+ newNode.familyPosition = FamilyPosition.right;
234
+ }
235
+ parent.right = newNode;
236
+ if (newNode !== null) {
237
+ this.size++;
238
+ this.count += newNode?.count ?? 0;
239
+ }
240
+ return parent.right;
241
+ } else {
242
+ return;
243
+ }
244
+ } else {
245
+ return;
246
+ }
247
+ }
248
+
249
+ put(id: BinaryTreeNodeId, val: T, count?: number): BinaryTreeNode<T> | null | undefined {
250
+ count = count ?? 1;
251
+
252
+ const _bfs = (root: BinaryTreeNode<T>, newNode: BinaryTreeNode<T> | null): BinaryTreeNode<T> | undefined | null => {
253
+ const queue: Array<BinaryTreeNode<T> | null> = [root];
254
+ while (queue.length > 0) {
255
+ const cur = queue.shift();
256
+ if (cur) {
257
+ const inserted = this.insertTo({newNode, parent: cur});
258
+ if (inserted !== undefined) return inserted;
259
+ if (cur.left) queue.push(cur.left);
260
+ if (cur.right) queue.push(cur.right);
261
+ } else return;
262
+ }
263
+ return;
264
+ };
265
+
266
+ let inserted: BinaryTreeNode<T> | null | undefined;
267
+ const needInsert = val !== null ? new BinaryTreeNode<T>(id, val, count) : null;
268
+ const existNode = val !== null ? this.get(id, 'id') : null;
269
+ if (this.root) {
270
+ if (existNode) {
271
+ existNode.count += count;
272
+ existNode.val = val;
273
+ if (needInsert !== null) {
274
+ this.count += count;
275
+ inserted = existNode;
276
+ }
277
+ } else {
278
+ inserted = _bfs(this.root, needInsert);
279
+ }
280
+ } else {
281
+ this.root = val !== null ? new BinaryTreeNode<T>(id, val, count) : null;
282
+ if (needInsert !== null) {
283
+ this.size = 1;
284
+ this.count = count;
285
+ }
286
+ inserted = this.root;
287
+ }
288
+ return inserted;
289
+ }
290
+
291
+ insertMany(data: T[] | BinaryTreeNode<T>[]): (BinaryTreeNode<T> | null | undefined)[] {
292
+ const inserted: (BinaryTreeNode<T> | null | undefined)[] = [];
293
+ const map: Map<T | BinaryTreeNode<T>, number> = new Map();
294
+
295
+ if (!this._isDuplicatedVal) {
296
+ for (const i of data) map.set(i, (map.get(i) ?? 0) + 1);
297
+ }
298
+
299
+ for (const item of data) {
300
+ const count = this._isDuplicatedVal ? 1 : map.get(item);
301
+
302
+ if (item instanceof BinaryTreeNode) {
303
+ inserted.push(this.put(item.id, item.val, item.count));
304
+ } else if (typeof item === 'number' && !this._autoIncrementId) {
305
+ if (!this._isDuplicatedVal) {
306
+ if (map.get(item) !== undefined) {
307
+ inserted.push(this.put(item, item, count));
308
+ map.delete(item);
309
+ }
310
+ } else {
311
+ inserted.push(this.put(item, item, 1));
312
+ }
313
+ } else {
314
+ if (item !== null) {
315
+ if (!this._isDuplicatedVal) {
316
+ if (map.get(item) !== undefined) {
317
+ inserted.push(this.put(++this._maxId, item, count));
318
+ map.delete(item);
319
+ }
320
+ } else {
321
+ inserted.push(this.put(++this._maxId, item, 1));
322
+ }
323
+ } else {
324
+ inserted.push(this.put(Number.MAX_SAFE_INTEGER, item, 0));
325
+ }
326
+ }
327
+ }
328
+ return inserted;
329
+ }
330
+
331
+ fill(data: T[] | BinaryTreeNode<T>[]): boolean {
332
+ this.clear();
333
+ return data.length === this.insertMany(data).length;
334
+ }
335
+
336
+ remove(id: BinaryTreeNodeId, ignoreCount?: boolean): BinaryTreeDeleted<T>[] {
337
+ const nodes = this.getNodes(id, 'id', true);
338
+ let node: BinaryTreeNode<T> | null | undefined = nodes[0];
339
+
340
+ if (!node) node = undefined;
341
+ else if (node.count > 1 && !ignoreCount) {
342
+ node.count--;
343
+ this.count--;
344
+ } else if (node instanceof BinaryTreeNode) {
345
+ const [subSize, subCount] = this.getSubTreeSizeAndCount(node);
346
+
347
+ switch (node.familyPosition) {
348
+ case 0:
349
+ this.size -= subSize;
350
+ this.count -= subCount;
351
+ node = undefined;
352
+ break;
353
+ case 1:
354
+ if (node.parent) {
355
+ this.size -= subSize;
356
+ this.count -= subCount;
357
+ node.parent.left = null;
358
+ }
359
+ break;
360
+ case 2:
361
+ if (node.parent) {
362
+ this.size -= subSize;
363
+ this.count -= subCount;
364
+ node.parent.right = null;
365
+ }
366
+ break;
367
+ }
368
+ }
369
+ return [{deleted: node, needBalanced: null}];
370
+ }
371
+
372
+ getDepth(node: BinaryTreeNode<T>): number {
373
+ let depth = 0;
374
+ while (node.parent) {
375
+ depth++;
376
+ node = node.parent;
377
+ }
378
+ return depth;
379
+ }
380
+
381
+ getHeight(beginRoot?: BinaryTreeNode<T> | null): number {
382
+ beginRoot = beginRoot ?? this.root;
383
+ if (!beginRoot) return -1;
384
+
385
+ if (this._loopType === LoopType.recursive) {
386
+ const _getMaxHeight = (cur: BinaryTreeNode<T> | null | undefined): number => {
387
+ if (!cur) return -1;
388
+ const leftHeight = _getMaxHeight(cur.left);
389
+ const rightHeight = _getMaxHeight(cur.right);
390
+ return Math.max(leftHeight, rightHeight) + 1;
391
+ };
392
+
393
+ return _getMaxHeight(beginRoot);
394
+ } else {
395
+ const stack: BinaryTreeNode<T>[] = [];
396
+ let node: BinaryTreeNode<T> | null | undefined = beginRoot, last: BinaryTreeNode<T> | null = null,
397
+ depths: Map<BinaryTreeNode<T>, number> = new Map();
398
+
399
+ while (stack.length > 0 || node) {
400
+ if (node) {
401
+ stack.push(node);
402
+ node = node.left;
403
+ } else {
404
+ node = stack[stack.length - 1]
405
+ if (!node.right || last === node.right) {
406
+ node = stack.pop();
407
+ if (node) {
408
+ let leftHeight = node.left ? depths.get(node.left) ?? -1 : -1;
409
+ let rightHeight = node.right ? depths.get(node.right) ?? -1 : -1;
410
+ depths.set(node, 1 + Math.max(leftHeight, rightHeight));
411
+ last = node;
412
+ node = null;
413
+ }
414
+ } else node = node.right
415
+ }
416
+ }
417
+
418
+ return depths.get(beginRoot) ?? -1;
419
+ }
420
+ }
421
+
422
+ getMinHeight(beginRoot?: BinaryTreeNode<T> | null): number {
423
+ beginRoot = beginRoot || this.root;
424
+ if (!beginRoot) return -1;
425
+
426
+ if (this._loopType === LoopType.recursive) {
427
+ const _getMinHeight = (cur: BinaryTreeNode<T> | null | undefined): number => {
428
+ if (!cur) return 0;
429
+ if (!cur.left && !cur.right) return 0;
430
+ const leftMinHeight = _getMinHeight(cur.left);
431
+ const rightMinHeight = _getMinHeight(cur.right);
432
+ return Math.min(leftMinHeight, rightMinHeight) + 1;
433
+ };
434
+
435
+ return _getMinHeight(beginRoot);
436
+ } else {
437
+ const stack: BinaryTreeNode<T>[] = [];
438
+ let node: BinaryTreeNode<T> | null | undefined = beginRoot, last: BinaryTreeNode<T> | null = null,
439
+ depths: Map<BinaryTreeNode<T>, number> = new Map();
440
+
441
+ while (stack.length > 0 || node) {
442
+ if (node) {
443
+ stack.push(node);
444
+ node = node.left;
445
+ } else {
446
+ node = stack[stack.length - 1]
447
+ if (!node.right || last === node.right) {
448
+ node = stack.pop();
449
+ if (node) {
450
+ let leftMinHeight = node.left ? depths.get(node.left) ?? -1 : -1;
451
+ let rightMinHeight = node.right ? depths.get(node.right) ?? -1 : -1;
452
+ depths.set(node, 1 + Math.min(leftMinHeight, rightMinHeight));
453
+ last = node;
454
+ node = null;
455
+ }
456
+ } else node = node.right
457
+ }
458
+ }
459
+
460
+ return depths.get(beginRoot) ?? -1;
461
+ }
462
+ }
463
+
464
+ isBalanced(beginRoot?: BinaryTreeNode<T> | null): boolean {
465
+ return (this.getMinHeight(beginRoot) + 1 >= this.getHeight(beginRoot));
466
+ }
467
+
468
+ getNodes(nodeProperty: BinaryTreeNodeId | T, propertyName ?: BinaryTreeNodePropertyName, onlyOne ?: boolean) {
469
+ if (!this.root) return [] as null[];
470
+ propertyName = propertyName ?? 'id';
471
+
472
+ const result: (BinaryTreeNode<T> | null | undefined)[] = [];
473
+
474
+ if (this._loopType === LoopType.recursive) {
475
+ const _traverse = (cur: BinaryTreeNode<T>) => {
476
+ if (this._pushByPropertyNameStopOrNot(cur, result, nodeProperty, propertyName, onlyOne)) return;
477
+ if (!cur.left && !cur.right) return;
478
+ cur.left && _traverse(cur.left);
479
+ cur.right && _traverse(cur.right);
480
+ }
481
+
482
+ _traverse(this.root);
483
+ } else {
484
+ const queue: BinaryTreeNode<T>[] = [this.root];
485
+ while (queue.length > 0) {
486
+ const cur = queue.shift();
487
+ if (cur) {
488
+ if (this._pushByPropertyNameStopOrNot(cur, result, nodeProperty, propertyName, onlyOne)) return result;
489
+ cur.left && queue.push(cur.left);
490
+ cur.right && queue.push(cur.right);
491
+ }
492
+ }
493
+ }
494
+
495
+ return result;
496
+ }
497
+
498
+ has(nodeProperty: BinaryTreeNodeId | T, propertyName ?: BinaryTreeNodePropertyName): boolean {
499
+ return this.getNodes(nodeProperty, propertyName).length > 0;
500
+ }
501
+
502
+ get(nodeProperty: BinaryTreeNodeId | T, propertyName ?: BinaryTreeNodePropertyName): BinaryTreeNode<T> | null {
503
+ propertyName = propertyName ?? 'id';
504
+ return this.getNodes(nodeProperty, propertyName, true)[0] ?? null;
505
+ }
506
+
507
+ getPathToRoot(node: BinaryTreeNode<T>): BinaryTreeNode<T>[] {
508
+ const result: BinaryTreeNode<T>[] = [];
509
+ while (node.parent) {
510
+ result.unshift(node);
511
+ node = node.parent;
512
+ }
513
+ result.unshift(node);
514
+ return result;
515
+ }
516
+
517
+ protected _pushByPropertyNameStopOrNot(cur: BinaryTreeNode<T>, result: (BinaryTreeNode<T> | null | undefined)[], nodeProperty: BinaryTreeNodeId | T, propertyName ?: BinaryTreeNodePropertyName, onlyOne ?: boolean) {
518
+ switch (propertyName) {
519
+ case 'id':
520
+ if (cur.id === nodeProperty) {
521
+ result.push(cur);
522
+ return !!onlyOne;
523
+ }
524
+ break;
525
+ case 'count':
526
+ if (cur.count === nodeProperty) {
527
+ result.push(cur);
528
+ return !!onlyOne;
529
+ }
530
+ break;
531
+ case 'val':
532
+ if (cur.val === nodeProperty) {
533
+ result.push(cur);
534
+ return !!onlyOne;
535
+ }
536
+ break;
537
+ default:
538
+ if (cur.id === nodeProperty) {
539
+ result.push(cur);
540
+ return !!onlyOne;
541
+ }
542
+ break;
543
+ }
544
+ }
545
+
546
+ protected _accumulatedByPropertyName(node: BinaryTreeNode<T>, nodeOrPropertyName ?: NodeOrPropertyName) {
547
+ nodeOrPropertyName = nodeOrPropertyName ?? 'id';
548
+
549
+ switch (nodeOrPropertyName) {
550
+ case 'id':
551
+ this._visitedId.push(node.id);
552
+ break;
553
+ case 'val':
554
+ this._visitedVal.push(node.val);
555
+ break;
556
+ case 'node':
557
+ this._visitedNode.push(node);
558
+ break;
559
+ case 'count':
560
+ this._visitedCount.push(node.count);
561
+ break;
562
+ default:
563
+ this._visitedId.push(node.id);
564
+ break;
565
+ }
566
+ }
567
+
568
+ protected _getResultByPropertyName(nodeOrPropertyName ?: NodeOrPropertyName): ResultsByProperty<T> {
569
+ nodeOrPropertyName = nodeOrPropertyName ?? 'id';
570
+
571
+ switch (nodeOrPropertyName) {
572
+ case 'id':
573
+ return this._visitedId;
574
+ case 'val':
575
+ return this._visitedVal;
576
+ case 'node':
577
+ return this._visitedNode;
578
+ case 'count':
579
+ return this._visitedCount;
580
+ default:
581
+ return this._visitedId;
582
+ }
583
+ }
584
+
585
+ getLeftMost(): BinaryTreeNode<T> | null;
586
+ getLeftMost(node: BinaryTreeNode<T>): BinaryTreeNode<T>;
587
+ getLeftMost(node?: BinaryTreeNode<T> | null): BinaryTreeNode<T> | null {
588
+ node = node ?? this.root;
589
+ if (!node) return node;
590
+
591
+ if (this._loopType === LoopType.recursive) {
592
+
593
+ const _traverse = (cur: BinaryTreeNode<T>): BinaryTreeNode<T> => {
594
+ if (!cur.left) return cur;
595
+ return _traverse(cur.left);
596
+ }
597
+
598
+ return _traverse(node);
599
+ } else {
600
+ // Indirect implementation of iteration using tail recursion optimization
601
+ const _traverse = trampoline((cur: BinaryTreeNode<T>): ThunkOrValue<BinaryTreeNode<T> | null> => {
602
+ if (!cur.left) return cur;
603
+ return _traverse.cont(cur.left);
604
+ });
605
+
606
+ return _traverse(node);
607
+ }
608
+ }
609
+
610
+ getRightMost(): BinaryTreeNode<T> | null;
611
+ getRightMost(node: BinaryTreeNode<T>): BinaryTreeNode<T>;
612
+ getRightMost(node?: BinaryTreeNode<T> | null): BinaryTreeNode<T> | null {
613
+ node = node ?? this.root;
614
+ if (!node) return node;
615
+
616
+ if (this._loopType === LoopType.recursive) {
617
+ const _traverse = (cur: BinaryTreeNode<T>): BinaryTreeNode<T> => {
618
+ if (!cur.right) return cur;
619
+ return _traverse(cur.right);
620
+ }
621
+
622
+ return _traverse(node);
623
+ } else {
624
+ // Indirect implementation of iteration using tail recursion optimization
625
+ const _traverse = trampoline((cur: BinaryTreeNode<T>): ThunkOrValue<BinaryTreeNode<T> | null> => {
626
+ if (!cur.right) return cur;
627
+ return _traverse.cont(cur.right);
628
+ });
629
+
630
+ return _traverse(node);
631
+ }
632
+ }
633
+
634
+ // --- start additional methods ---
635
+ isBST(node?: BinaryTreeNode<T> | null): boolean {
636
+ node = node ?? this.root;
637
+ if (!node) return true;
638
+
639
+ if (this._loopType === LoopType.recursive) {
640
+ const dfs = (cur: BinaryTreeNode<T> | null | undefined, min: BinaryTreeNodeId, max: BinaryTreeNodeId): boolean => {
641
+ if (!cur) return true;
642
+ if (cur.id <= min || cur.id >= max) return false;
643
+ return dfs(cur.left, min, cur.id) && dfs(cur.right, cur.id, max);
644
+ }
645
+
646
+ return dfs(node, Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER);
647
+ } else {
648
+ const stack = [];
649
+ let prev = Number.MIN_SAFE_INTEGER, curr: BinaryTreeNode<T> | null | undefined = node;
650
+ while (curr || stack.length > 0) {
651
+ while (curr) {
652
+ stack.push(curr);
653
+ curr = curr.left;
654
+ }
655
+ curr = stack.pop()!;
656
+ if (prev >= curr.id) return false;
657
+ prev = curr.id;
658
+ curr = curr.right;
659
+ }
660
+ return true;
661
+ }
662
+ }
663
+
664
+ getSubTreeSizeAndCount(subTreeRoot: BinaryTreeNode<T> | null | undefined) {
665
+ const res: [number, number] = [0, 0];
666
+ if (!subTreeRoot) return res;
667
+
668
+ if (this._loopType === LoopType.recursive) {
669
+ const _traverse = (cur: BinaryTreeNode<T>) => {
670
+ res[0]++;
671
+ res[1] += cur.count;
672
+ cur.left && _traverse(cur.left);
673
+ cur.right && _traverse(cur.right);
674
+ }
675
+
676
+ _traverse(subTreeRoot);
677
+ return res;
678
+ } else {
679
+ const stack: BinaryTreeNode<T>[] = [subTreeRoot];
680
+
681
+ while (stack.length > 0) {
682
+ const cur = stack.pop()!;
683
+ res[0]++;
684
+ res[1] += cur.count;
685
+ cur.right && stack.push(cur.right);
686
+ cur.left && stack.push(cur.left);
687
+ }
688
+
689
+ return res;
690
+ }
691
+ }
692
+
693
+ subTreeSum(subTreeRoot: BinaryTreeNode<T>, propertyName ?: BinaryTreeNodePropertyName): number {
694
+ propertyName = propertyName ?? 'val';
695
+ if (!subTreeRoot) return 0;
696
+
697
+ let sum = 0;
698
+
699
+ const _sumByProperty = (cur: BinaryTreeNode<T>) => {
700
+ let needSum: number;
701
+ switch (propertyName) {
702
+ case 'id':
703
+ needSum = cur.id;
704
+ break;
705
+ case 'count':
706
+ needSum = cur.count;
707
+ break;
708
+ case 'val':
709
+ needSum = typeof cur.val === 'number' ? cur.val : 0;
710
+ break;
711
+ default:
712
+ needSum = cur.id;
713
+ break;
714
+ }
715
+ return needSum;
716
+ }
717
+
718
+ if (this._loopType === LoopType.recursive) {
719
+ const _traverse = (cur: BinaryTreeNode<T>): void => {
720
+ sum += _sumByProperty(cur);
721
+ cur.left && _traverse(cur.left);
722
+ cur.right && _traverse(cur.right);
723
+ }
724
+
725
+ _traverse(subTreeRoot);
726
+ } else {
727
+ const stack: BinaryTreeNode<T>[] = [subTreeRoot];
728
+
729
+ while (stack.length > 0) {
730
+ const cur = stack.pop()!;
731
+ sum += _sumByProperty(cur);
732
+ cur.right && stack.push(cur.right);
733
+ cur.left && stack.push(cur.left);
734
+ }
735
+ }
736
+
737
+ return sum;
738
+ }
739
+
740
+ subTreeAdd(subTreeRoot: BinaryTreeNode<T>, delta: number, propertyName ?: BinaryTreeNodePropertyName): boolean {
741
+ propertyName = propertyName ?? 'id';
742
+ if (!subTreeRoot) return false;
743
+
744
+ const _addByProperty = (cur: BinaryTreeNode<T>) => {
745
+ switch (propertyName) {
746
+ case 'id':
747
+ cur.id += delta;
748
+ break;
749
+ case 'count':
750
+ cur.count += delta;
751
+ this.count += delta;
752
+ break;
753
+ default:
754
+ cur.id += delta;
755
+ break;
756
+ }
757
+ }
758
+
759
+ if (this._loopType === LoopType.recursive) {
760
+ const _traverse = (cur: BinaryTreeNode<T>) => {
761
+ _addByProperty(cur);
762
+ cur.left && _traverse(cur.left);
763
+ cur.right && _traverse(cur.right);
764
+ };
765
+
766
+ _traverse(subTreeRoot);
767
+ } else {
768
+ const stack: BinaryTreeNode<T>[] = [subTreeRoot];
769
+
770
+ while (stack.length > 0) {
771
+ const cur = stack.pop()!;
772
+
773
+ _addByProperty(cur);
774
+ cur.right && stack.push(cur.right);
775
+ cur.left && stack.push(cur.left);
776
+ }
777
+ }
778
+ return true;
779
+ }
780
+
781
+ BFS(): BinaryTreeNodeId[];
782
+ BFS(nodeOrPropertyName: 'id'): BinaryTreeNodeId[];
783
+ BFS(nodeOrPropertyName: 'val'): T[];
784
+ BFS(nodeOrPropertyName: 'node'): BinaryTreeNode<T>[];
785
+ BFS(nodeOrPropertyName: 'count'): number[];
786
+ BFS(nodeOrPropertyName ?: NodeOrPropertyName): ResultsByProperty<T> {
787
+ nodeOrPropertyName = nodeOrPropertyName ?? 'id';
788
+ this._resetResults();
789
+ const queue: Array<BinaryTreeNode<T> | null | undefined> = [this.root];
790
+
791
+ while (queue.length !== 0) {
792
+ const cur = queue.shift();
793
+ if (cur) {
794
+ this._accumulatedByPropertyName(cur, nodeOrPropertyName);
795
+ if (cur?.left !== null) queue.push(cur.left);
796
+ if (cur?.right !== null) queue.push(cur.right);
797
+ }
798
+ }
799
+
800
+ return this._getResultByPropertyName(nodeOrPropertyName);
801
+ }
802
+
803
+ DFS(): BinaryTreeNodeId[];
804
+ DFS(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'id'): BinaryTreeNodeId[];
805
+ DFS(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'val'): T[];
806
+ DFS(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'node'): BinaryTreeNode<T>[];
807
+ DFS(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'count'): number[];
808
+ DFS(pattern ?: 'in' | 'pre' | 'post', nodeOrPropertyName ?: NodeOrPropertyName): ResultsByProperty<T> {
809
+ pattern = pattern ?? 'in';
810
+ nodeOrPropertyName = nodeOrPropertyName ?? 'id';
811
+ this._resetResults();
812
+ const _traverse = (node: BinaryTreeNode<T>) => {
813
+ switch (pattern) {
814
+ case 'in':
815
+ if (node.left) _traverse(node.left);
816
+ this._accumulatedByPropertyName(node, nodeOrPropertyName);
817
+ if (node.right) _traverse(node.right);
818
+ break;
819
+ case 'pre':
820
+ this._accumulatedByPropertyName(node, nodeOrPropertyName);
821
+ if (node.left) _traverse(node.left);
822
+ if (node.right) _traverse(node.right);
823
+ break;
824
+ case 'post':
825
+ if (node.left) _traverse(node.left);
826
+ if (node.right) _traverse(node.right);
827
+ this._accumulatedByPropertyName(node, nodeOrPropertyName);
828
+ break;
829
+ }
830
+ };
831
+
832
+ this.root && _traverse(this.root);
833
+ return this._getResultByPropertyName(nodeOrPropertyName);
834
+ }
835
+
836
+ DFSIterative(): BinaryTreeNodeId[];
837
+ DFSIterative(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'id'): BinaryTreeNodeId[];
838
+ DFSIterative(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'val'): T[];
839
+ DFSIterative(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'node'): BinaryTreeNode<T>[];
840
+ DFSIterative(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'count'): number[];
841
+
842
+ /**
843
+ * Time complexity is O(n)
844
+ * Space complexity of Iterative DFS equals to recursive DFS which is O(n) because of the stack
845
+ * @param pattern
846
+ * @param nodeOrPropertyName
847
+ * @constructor
848
+ */
849
+ DFSIterative(pattern ?: 'in' | 'pre' | 'post', nodeOrPropertyName ?: NodeOrPropertyName): ResultsByProperty<T> {
850
+ pattern = pattern || 'in';
851
+ nodeOrPropertyName = nodeOrPropertyName || 'id';
852
+ this._resetResults();
853
+ if (!this.root) return this._getResultByPropertyName(nodeOrPropertyName);
854
+ // 0: visit, 1: print
855
+ const stack: { opt: 0 | 1, node: BinaryTreeNode<T> | null | undefined }[] = [{opt: 0, node: this.root}];
856
+
857
+ while (stack.length > 0) {
858
+ const cur = stack.pop();
859
+ if (!cur || !cur.node) continue;
860
+ if (cur.opt === 1) {
861
+ this._accumulatedByPropertyName(cur.node, nodeOrPropertyName);
862
+ } else {
863
+ switch (pattern) {
864
+ case 'in':
865
+ stack.push({opt: 0, node: cur.node.right});
866
+ stack.push({opt: 1, node: cur.node});
867
+ stack.push({opt: 0, node: cur.node.left});
868
+ break;
869
+ case 'pre':
870
+ stack.push({opt: 0, node: cur.node.right});
871
+ stack.push({opt: 0, node: cur.node.left});
872
+ stack.push({opt: 1, node: cur.node});
873
+ break;
874
+ case 'post':
875
+ stack.push({opt: 1, node: cur.node});
876
+ stack.push({opt: 0, node: cur.node.right});
877
+ stack.push({opt: 0, node: cur.node.left});
878
+ break;
879
+ default:
880
+ stack.push({opt: 0, node: cur.node.right});
881
+ stack.push({opt: 1, node: cur.node});
882
+ stack.push({opt: 0, node: cur.node.left});
883
+ break;
884
+ }
885
+ }
886
+ }
887
+
888
+ return this._getResultByPropertyName(nodeOrPropertyName);
889
+ }
890
+
891
+ levelIterative(node: BinaryTreeNode<T> | null): BinaryTreeNodeId[];
892
+ levelIterative(node: BinaryTreeNode<T> | null, nodeOrPropertyName?: 'id'): BinaryTreeNodeId[];
893
+ levelIterative(node: BinaryTreeNode<T> | null, nodeOrPropertyName?: 'val'): T[];
894
+ levelIterative(node: BinaryTreeNode<T> | null, nodeOrPropertyName?: 'node'): BinaryTreeNode<T>[];
895
+ levelIterative(node: BinaryTreeNode<T> | null, nodeOrPropertyName?: 'count'): number[];
896
+ levelIterative(node: BinaryTreeNode<T> | null, nodeOrPropertyName ?: NodeOrPropertyName): ResultsByProperty<T> {
897
+ nodeOrPropertyName = nodeOrPropertyName || 'id';
898
+ node = node || this.root;
899
+ if (!node) return [];
900
+
901
+ this._resetResults();
902
+ const queue: BinaryTreeNode<T>[] = [node];
903
+
904
+ while (queue.length > 0) {
905
+ const cur = queue.shift();
906
+ if (cur) {
907
+ this._accumulatedByPropertyName(cur, nodeOrPropertyName);
908
+ if (cur.left) {
909
+ queue.push(cur.left);
910
+ }
911
+ if (cur.right) {
912
+ queue.push(cur.right);
913
+ }
914
+ }
915
+ }
916
+
917
+ return this._getResultByPropertyName(nodeOrPropertyName);
918
+ }
919
+
920
+ listLevels(node: BinaryTreeNode<T> | null): BinaryTreeNodeId[][];
921
+ listLevels(node: BinaryTreeNode<T> | null, nodeOrPropertyName?: 'id'): BinaryTreeNodeId[][];
922
+ listLevels(node: BinaryTreeNode<T> | null, nodeOrPropertyName?: 'val'): T[][];
923
+ listLevels(node: BinaryTreeNode<T> | null, nodeOrPropertyName?: 'node'): BinaryTreeNode<T>[][];
924
+ listLevels(node: BinaryTreeNode<T> | null, nodeOrPropertyName?: 'count'): number[][];
925
+ listLevels(node: BinaryTreeNode<T> | null, nodeOrPropertyName?: NodeOrPropertyName): ResultByProperty<T>[][] {
926
+ nodeOrPropertyName = nodeOrPropertyName || 'id';
927
+ node = node || this.root;
928
+ if (!node) return [];
929
+
930
+ const levelsNodes: ResultByProperty<T>[][] = [];
931
+
932
+ const collectByProperty = (node: BinaryTreeNode<T>, level: number) => {
933
+ switch (nodeOrPropertyName) {
934
+ case 'id':
935
+ levelsNodes[level].push(node.id);
936
+ break;
937
+ case 'val':
938
+ levelsNodes[level].push(node.val);
939
+ break;
940
+ case 'node':
941
+ levelsNodes[level].push(node);
942
+ break;
943
+ case 'count':
944
+ levelsNodes[level].push(node.count);
945
+ break;
946
+ default:
947
+ levelsNodes[level].push(node.id);
948
+ break;
949
+ }
950
+ }
951
+
952
+ if (this._loopType === LoopType.recursive) {
953
+ const _recursive = (node: BinaryTreeNode<T>, level: number) => {
954
+ if (!levelsNodes[level]) levelsNodes[level] = [];
955
+ collectByProperty(node, level);
956
+ if (node.left) _recursive(node.left, level + 1);
957
+ if (node.right) _recursive(node.right, level + 1);
958
+ };
959
+
960
+ _recursive(node, 0);
961
+ } else {
962
+ const stack: [BinaryTreeNode<T>, number][] = [[node, 0]];
963
+
964
+ while (stack.length > 0) {
965
+ const head = stack.pop()!;
966
+ const [node, level] = head;
967
+
968
+ if (!levelsNodes[level]) levelsNodes[level] = [];
969
+ collectByProperty(node, level);
970
+ if (node.right) stack.push([node.right, level + 1]);
971
+ if (node.left) stack.push([node.left, level + 1]);
972
+ }
973
+ }
974
+
975
+ return levelsNodes;
976
+ }
977
+
978
+ getPredecessor(node: BinaryTreeNode<T>): BinaryTreeNode<T> {
979
+ if (node.left) {
980
+ let predecessor: BinaryTreeNode<T> | null = node.left;
981
+ while (predecessor.right && predecessor.right !== node) {
982
+ predecessor = predecessor.right;
983
+ }
984
+ return predecessor;
985
+ } else {
986
+ return node;
987
+ }
988
+ }
989
+
990
+ morris(): BinaryTreeNodeId[];
991
+ morris(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'id'): BinaryTreeNodeId[];
992
+ morris(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'val'): T[];
993
+ morris(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'node'): BinaryTreeNode<T>[];
994
+ morris(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'count'): number[];
995
+ /**
996
+ * The time complexity of Morris traversal is O(n), it's may slower than others
997
+ * The space complexity Morris traversal is O(1) because no using stack
998
+ * @param pattern
999
+ * @param nodeOrPropertyName
1000
+ */
1001
+ morris(pattern?: 'in' | 'pre' | 'post', nodeOrPropertyName?: NodeOrPropertyName): ResultsByProperty<T> {
1002
+ if (this.root === null) return [];
1003
+
1004
+ pattern = pattern || 'in';
1005
+ nodeOrPropertyName = nodeOrPropertyName || 'id';
1006
+
1007
+ this._resetResults();
1008
+
1009
+ let cur: BinaryTreeNode<T> | null | undefined = this.root;
1010
+ const _reverseEdge = (node: BinaryTreeNode<T> | null | undefined) => {
1011
+ let pre: BinaryTreeNode<T> | null | undefined = null;
1012
+ let next: BinaryTreeNode<T> | null | undefined = null;
1013
+ while (node) {
1014
+ next = node.right;
1015
+ node.right = pre;
1016
+ pre = node;
1017
+ node = next;
1018
+ }
1019
+ return pre;
1020
+ };
1021
+ const _printEdge = (node: BinaryTreeNode<T> | null) => {
1022
+ const tail: BinaryTreeNode<T> | null | undefined = _reverseEdge(node);
1023
+ let cur: BinaryTreeNode<T> | null | undefined = tail;
1024
+ while (cur) {
1025
+ this._accumulatedByPropertyName(cur, nodeOrPropertyName);
1026
+ cur = cur.right;
1027
+ }
1028
+ _reverseEdge(tail);
1029
+ };
1030
+ switch (pattern) {
1031
+ case 'in':
1032
+ while (cur) {
1033
+ if (cur.left) {
1034
+ const predecessor = this.getPredecessor(cur);
1035
+ if (!predecessor.right) {
1036
+ predecessor.right = cur;
1037
+ cur = cur.left;
1038
+ continue;
1039
+ } else {
1040
+ predecessor.right = null;
1041
+ }
1042
+ }
1043
+ this._accumulatedByPropertyName(cur, nodeOrPropertyName);
1044
+ cur = cur.right;
1045
+ }
1046
+ break;
1047
+ case 'pre':
1048
+ while (cur) {
1049
+ if (cur.left) {
1050
+ const predecessor = this.getPredecessor(cur);
1051
+ if (!predecessor.right) {
1052
+ predecessor.right = cur;
1053
+ this._accumulatedByPropertyName(cur, nodeOrPropertyName);
1054
+ cur = cur.left;
1055
+ continue;
1056
+ } else {
1057
+ predecessor.right = null;
1058
+ }
1059
+ } else {
1060
+ this._accumulatedByPropertyName(cur, nodeOrPropertyName);
1061
+ }
1062
+ cur = cur.right;
1063
+ }
1064
+ break;
1065
+ case 'post':
1066
+ while (cur) {
1067
+ if (cur.left) {
1068
+ const predecessor = this.getPredecessor(cur);
1069
+ if (predecessor.right === null) {
1070
+ predecessor.right = cur;
1071
+ cur = cur.left;
1072
+ continue;
1073
+ } else {
1074
+ predecessor.right = null;
1075
+ _printEdge(cur.left);
1076
+ }
1077
+ }
1078
+ cur = cur.right;
1079
+ }
1080
+ _printEdge(this.root);
1081
+ break;
1082
+ }
1083
+
1084
+ return this._getResultByPropertyName(nodeOrPropertyName);
1085
+ }
1086
+
1087
+ // --- end additional methods ---
1088
+ }