@obinexusmk2/hypernum 0.1.0 → 0.1.1
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.
- package/LICENSE +21 -21
- package/README.md +355 -256
- package/dist/index.cjs +4 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +4 -7
- package/dist/index.js.map +1 -1
- package/dist/index.umd.js +2 -2
- package/dist/index.umd.js.map +1 -1
- package/dist/types/{config → src/config}/config-loader.d.ts +0 -0
- package/dist/types/src/config/config-loader.d.ts.map +1 -0
- package/dist/types/{config → src/config}/config-parser.d.ts +0 -0
- package/dist/types/src/config/config-parser.d.ts.map +1 -0
- package/dist/types/{config → src/config}/config-resolver.d.ts +0 -0
- package/dist/types/src/config/config-resolver.d.ts.map +1 -0
- package/dist/types/{config → src/config}/config-source.d.ts +0 -0
- package/dist/types/src/config/config-source.d.ts.map +1 -0
- package/dist/types/{config → src/config}/index.d.ts +0 -0
- package/dist/types/src/config/index.d.ts.map +1 -0
- package/dist/types/{core → src/core}/common.d.ts +0 -0
- package/dist/types/src/core/common.d.ts.map +1 -0
- package/dist/types/{core → src/core}/config.d.ts +0 -0
- package/dist/types/src/core/config.d.ts.map +1 -0
- package/dist/types/{core → src/core}/constants.d.ts +0 -0
- package/dist/types/src/core/constants.d.ts.map +1 -0
- package/dist/types/{core → src/core}/errors.d.ts +0 -0
- package/dist/types/src/core/errors.d.ts.map +1 -0
- package/dist/types/{core → src/core}/hypernum.d.ts +0 -0
- package/dist/types/src/core/hypernum.d.ts.map +1 -0
- package/dist/types/{core → src/core}/index.d.ts +0 -0
- package/dist/types/src/core/index.d.ts.map +1 -0
- package/dist/types/{index.d.ts → src/index.d.ts} +1 -1
- package/dist/types/src/index.d.ts.map +1 -0
- package/dist/types/{operations → src/operations}/arithmetic.d.ts +0 -0
- package/dist/types/src/operations/arithmetic.d.ts.map +1 -0
- package/dist/types/{operations → src/operations}/bitwise.d.ts +0 -0
- package/dist/types/src/operations/bitwise.d.ts.map +1 -0
- package/dist/types/{operations → src/operations}/comparison.d.ts +0 -0
- package/dist/types/src/operations/comparison.d.ts.map +1 -0
- package/dist/types/{operations → src/operations}/conversion.d.ts +0 -0
- package/dist/types/src/operations/conversion.d.ts.map +1 -0
- package/dist/types/{operations → src/operations}/factorial.d.ts +0 -0
- package/dist/types/src/operations/factorial.d.ts.map +1 -0
- package/dist/types/{operations → src/operations}/index.d.ts +0 -0
- package/dist/types/src/operations/index.d.ts.map +1 -0
- package/dist/types/{operations → src/operations}/power.d.ts +0 -0
- package/dist/types/src/operations/power.d.ts.map +1 -0
- package/dist/types/{storage → src/storage}/Heap.d.ts +0 -0
- package/dist/types/src/storage/Heap.d.ts.map +1 -0
- package/dist/types/{storage → src/storage}/index.d.ts +0 -0
- package/dist/types/src/storage/index.d.ts.map +1 -0
- package/dist/types/{structures → src/structures}/ackermann.d.ts +0 -0
- package/dist/types/src/structures/ackermann.d.ts.map +1 -0
- package/dist/types/{structures → src/structures}/big-array.d.ts +0 -0
- package/dist/types/src/structures/big-array.d.ts.map +1 -0
- package/dist/types/{structures → src/structures}/index.d.ts +0 -0
- package/dist/types/src/structures/index.d.ts.map +1 -0
- package/dist/types/{structures → src/structures}/number-tree.d.ts +0 -0
- package/dist/types/src/structures/number-tree.d.ts.map +1 -0
- package/dist/types/{structures → src/structures}/power-tower.d.ts +0 -0
- package/dist/types/src/structures/power-tower.d.ts.map +1 -0
- package/dist/types/{utils → src/utils}/formatting.d.ts +0 -0
- package/dist/types/src/utils/formatting.d.ts.map +1 -0
- package/dist/types/{utils → src/utils}/index.d.ts +0 -0
- package/dist/types/src/utils/index.d.ts.map +1 -0
- package/dist/types/{utils → src/utils}/parser.d.ts +0 -0
- package/dist/types/src/utils/parser.d.ts.map +1 -0
- package/dist/types/{utils → src/utils}/precision.d.ts +0 -0
- package/dist/types/src/utils/precision.d.ts.map +1 -0
- package/dist/types/{utils → src/utils}/validation.d.ts +0 -0
- package/dist/types/src/utils/validation.d.ts.map +1 -0
- package/package.json +169 -164
- package/rollup.config.js +163 -161
- package/src/cli/hypernum.js +272 -0
- package/src/config/config-loader.ts +0 -0
- package/src/config/config-parser.ts +160 -160
- package/src/config/config-resolver.ts +0 -0
- package/src/config/config-source.ts +0 -0
- package/src/config/index.ts +0 -0
- package/src/core/common.ts +184 -184
- package/src/core/config.ts +392 -392
- package/src/core/constants.ts +101 -101
- package/src/core/errors.ts +202 -202
- package/src/core/hypernum.ts +240 -240
- package/src/core/index.ts +4 -4
- package/src/index.ts +179 -182
- package/src/operations/arithmetic.ts +332 -332
- package/src/operations/bitwise.ts +366 -366
- package/src/operations/comparison.ts +271 -271
- package/src/operations/conversion.ts +399 -399
- package/src/operations/factorial.ts +278 -278
- package/src/operations/index.ts +4 -4
- package/src/operations/power.ts +315 -315
- package/src/storage/Heap.ts +237 -237
- package/src/storage/index.ts +0 -0
- package/src/structures/ackermann.ts +232 -232
- package/src/structures/big-array.ts +305 -305
- package/src/structures/index.ts +3 -3
- package/src/structures/number-tree.ts +403 -403
- package/src/structures/power-tower.ts +277 -277
- package/src/types/common.d.ts +356 -356
- package/src/types/core.d.ts +160 -160
- package/src/types/index.d.ts +1 -1
- package/src/utils/formatting.ts +245 -245
- package/src/utils/index.ts +4 -4
- package/src/utils/parser.ts +244 -244
- package/src/utils/precision.ts +216 -216
- package/src/utils/validation.ts +182 -182
- package/tsconfig.json +83 -83
- package/dist/types/config/config-loader.d.ts.map +0 -1
- package/dist/types/config/config-parser.d.ts.map +0 -1
- package/dist/types/config/config-resolver.d.ts.map +0 -1
- package/dist/types/config/config-source.d.ts.map +0 -1
- package/dist/types/config/index.d.ts.map +0 -1
- package/dist/types/core/common.d.ts.map +0 -1
- package/dist/types/core/config.d.ts.map +0 -1
- package/dist/types/core/constants.d.ts.map +0 -1
- package/dist/types/core/errors.d.ts.map +0 -1
- package/dist/types/core/hypernum.d.ts.map +0 -1
- package/dist/types/core/index.d.ts.map +0 -1
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/operations/arithmetic.d.ts.map +0 -1
- package/dist/types/operations/bitwise.d.ts.map +0 -1
- package/dist/types/operations/comparison.d.ts.map +0 -1
- package/dist/types/operations/conversion.d.ts.map +0 -1
- package/dist/types/operations/factorial.d.ts.map +0 -1
- package/dist/types/operations/index.d.ts.map +0 -1
- package/dist/types/operations/power.d.ts.map +0 -1
- package/dist/types/storage/Heap.d.ts.map +0 -1
- package/dist/types/storage/index.d.ts.map +0 -1
- package/dist/types/structures/ackermann.d.ts.map +0 -1
- package/dist/types/structures/big-array.d.ts.map +0 -1
- package/dist/types/structures/index.d.ts.map +0 -1
- package/dist/types/structures/number-tree.d.ts.map +0 -1
- package/dist/types/structures/power-tower.d.ts.map +0 -1
- package/dist/types/utils/formatting.d.ts.map +0 -1
- package/dist/types/utils/index.d.ts.map +0 -1
- package/dist/types/utils/parser.d.ts.map +0 -1
- package/dist/types/utils/precision.d.ts.map +0 -1
- package/dist/types/utils/validation.d.ts.map +0 -1
|
@@ -1,404 +1,404 @@
|
|
|
1
|
-
import { Comparator } from "@/core";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Interface for tree node statistics
|
|
5
|
-
*/
|
|
6
|
-
interface NodeStats {
|
|
7
|
-
height: number;
|
|
8
|
-
size: number;
|
|
9
|
-
sum: bigint;
|
|
10
|
-
min: bigint;
|
|
11
|
-
max: bigint;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Interface for tree traversal configuration
|
|
16
|
-
*/
|
|
17
|
-
interface TraversalConfig {
|
|
18
|
-
includeStats?: boolean;
|
|
19
|
-
skipSubtrees?: boolean;
|
|
20
|
-
maxDepth?: number;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Class representing a node in the number tree
|
|
25
|
-
*/
|
|
26
|
-
class NumberNode {
|
|
27
|
-
value: bigint;
|
|
28
|
-
left: NumberNode | null;
|
|
29
|
-
right: NumberNode | null;
|
|
30
|
-
parent: NumberNode | null;
|
|
31
|
-
height: number;
|
|
32
|
-
size: number;
|
|
33
|
-
sum: bigint;
|
|
34
|
-
|
|
35
|
-
constructor(value: bigint | string | number) {
|
|
36
|
-
this.value = typeof value === 'bigint' ? value : BigInt(value);
|
|
37
|
-
this.left = null;
|
|
38
|
-
this.right = null;
|
|
39
|
-
this.parent = null;
|
|
40
|
-
this.height = 1;
|
|
41
|
-
this.size = 1;
|
|
42
|
-
this.sum = this.value;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Updates node statistics based on children
|
|
47
|
-
*/
|
|
48
|
-
updateStats(): void {
|
|
49
|
-
this.height = 1 + Math.max(
|
|
50
|
-
this.left?.height ?? 0,
|
|
51
|
-
this.right?.height ?? 0
|
|
52
|
-
);
|
|
53
|
-
this.size = 1 + (this.left?.size ?? 0) + (this.right?.size ?? 0);
|
|
54
|
-
this.sum = this.value +
|
|
55
|
-
(this.left?.sum ?? BigInt(0)) +
|
|
56
|
-
(this.right?.sum ?? BigInt(0));
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Gets balance factor of the node
|
|
61
|
-
*/
|
|
62
|
-
getBalance(): number {
|
|
63
|
-
return (this.left?.height ?? 0) - (this.right?.height ?? 0);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Gets complete statistics for the node and its subtree
|
|
68
|
-
*/
|
|
69
|
-
getStats(): NodeStats {
|
|
70
|
-
return {
|
|
71
|
-
height: this.height,
|
|
72
|
-
size: this.size,
|
|
73
|
-
sum: this.sum,
|
|
74
|
-
min: this.findMin().value,
|
|
75
|
-
max: this.findMax().value
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Finds minimum value node in the subtree
|
|
81
|
-
*/
|
|
82
|
-
findMin(): NumberNode {
|
|
83
|
-
let current: NumberNode = this;
|
|
84
|
-
while (current.left) {
|
|
85
|
-
current = current.left;
|
|
86
|
-
}
|
|
87
|
-
return current;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Finds maximum value node in the subtree
|
|
92
|
-
*/
|
|
93
|
-
findMax(): NumberNode {
|
|
94
|
-
let current: NumberNode = this;
|
|
95
|
-
while (current.right) {
|
|
96
|
-
current = current.right;
|
|
97
|
-
}
|
|
98
|
-
return current;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* AVL Tree implementation specialized for handling large numbers
|
|
104
|
-
*/
|
|
105
|
-
export class NumberTree {
|
|
106
|
-
private root: NumberNode | null;
|
|
107
|
-
private readonly comparator: Comparator<bigint>;
|
|
108
|
-
|
|
109
|
-
constructor(comparator?: Comparator<bigint>) {
|
|
110
|
-
this.root = null;
|
|
111
|
-
this.comparator = comparator ?? ((a: bigint, b: bigint): -1 | 0 | 1 => {
|
|
112
|
-
if (a < b) return -1;
|
|
113
|
-
if (a > b) return 1;
|
|
114
|
-
return 0;
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Gets the root node if it exists
|
|
120
|
-
*/
|
|
121
|
-
public getRoot(): NumberNode | null {
|
|
122
|
-
return this.root;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Inserts a new value into the tree
|
|
127
|
-
*/
|
|
128
|
-
public insert(value: bigint | string | number): NumberNode {
|
|
129
|
-
const newValue = typeof value === 'bigint' ? value : BigInt(value);
|
|
130
|
-
this.root = this.insertNode(this.root, newValue);
|
|
131
|
-
return this.find(newValue)!;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Recursively inserts a new node
|
|
136
|
-
*/
|
|
137
|
-
private insertNode(node: NumberNode | null, value: bigint): NumberNode {
|
|
138
|
-
if (!node) {
|
|
139
|
-
return new NumberNode(value);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
const compareResult = this.comparator(value, node.value);
|
|
143
|
-
if (compareResult < 0) {
|
|
144
|
-
node.left = this.insertNode(node.left, value);
|
|
145
|
-
node.left.parent = node;
|
|
146
|
-
} else if (compareResult > 0) {
|
|
147
|
-
node.right = this.insertNode(node.right, value);
|
|
148
|
-
node.right.parent = node;
|
|
149
|
-
} else {
|
|
150
|
-
return node; // Duplicate value, return existing node
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
node.updateStats();
|
|
154
|
-
return this.balance(node);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Balances a node using AVL rotations
|
|
159
|
-
*/
|
|
160
|
-
private balance(node: NumberNode): NumberNode {
|
|
161
|
-
const balance = node.getBalance();
|
|
162
|
-
|
|
163
|
-
// Left heavy
|
|
164
|
-
if (balance > 1) {
|
|
165
|
-
if (node.left && node.left.getBalance() < 0) {
|
|
166
|
-
node.left = this.rotateLeft(node.left);
|
|
167
|
-
}
|
|
168
|
-
return this.rotateRight(node);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// Right heavy
|
|
172
|
-
if (balance < -1) {
|
|
173
|
-
if (node.right && node.right.getBalance() > 0) {
|
|
174
|
-
node.right = this.rotateRight(node.right);
|
|
175
|
-
}
|
|
176
|
-
return this.rotateLeft(node);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
return node;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Performs left rotation
|
|
184
|
-
*/
|
|
185
|
-
private rotateLeft(node: NumberNode): NumberNode {
|
|
186
|
-
const rightChild = node.right!;
|
|
187
|
-
const rightLeftChild = rightChild.left;
|
|
188
|
-
|
|
189
|
-
rightChild.left = node;
|
|
190
|
-
node.right = rightLeftChild;
|
|
191
|
-
|
|
192
|
-
if (rightLeftChild) {
|
|
193
|
-
rightLeftChild.parent = node;
|
|
194
|
-
}
|
|
195
|
-
rightChild.parent = node.parent;
|
|
196
|
-
node.parent = rightChild;
|
|
197
|
-
|
|
198
|
-
node.updateStats();
|
|
199
|
-
rightChild.updateStats();
|
|
200
|
-
|
|
201
|
-
return rightChild;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* Performs right rotation
|
|
206
|
-
*/
|
|
207
|
-
private rotateRight(node: NumberNode): NumberNode {
|
|
208
|
-
const leftChild = node.left!;
|
|
209
|
-
const leftRightChild = leftChild.right;
|
|
210
|
-
|
|
211
|
-
leftChild.right = node;
|
|
212
|
-
node.left = leftRightChild;
|
|
213
|
-
|
|
214
|
-
if (leftRightChild) {
|
|
215
|
-
leftRightChild.parent = node;
|
|
216
|
-
}
|
|
217
|
-
leftChild.parent = node.parent;
|
|
218
|
-
node.parent = leftChild;
|
|
219
|
-
|
|
220
|
-
node.updateStats();
|
|
221
|
-
leftChild.updateStats();
|
|
222
|
-
|
|
223
|
-
return leftChild;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
/**
|
|
227
|
-
* Removes a value from the tree
|
|
228
|
-
*/
|
|
229
|
-
public remove(value: bigint | string | number): boolean {
|
|
230
|
-
const searchValue = typeof value === 'bigint' ? value : BigInt(value);
|
|
231
|
-
const nodeToRemove = this.find(searchValue);
|
|
232
|
-
|
|
233
|
-
if (!nodeToRemove) {
|
|
234
|
-
return false;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
this.root = this.removeNode(this.root, searchValue);
|
|
238
|
-
return true;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
/**
|
|
242
|
-
* Recursively removes a node
|
|
243
|
-
*/
|
|
244
|
-
private removeNode(node: NumberNode | null, value: bigint): NumberNode | null {
|
|
245
|
-
if (!node) {
|
|
246
|
-
return null;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
const compareResult = this.comparator(value, node.value);
|
|
250
|
-
if (compareResult < 0) {
|
|
251
|
-
node.left = this.removeNode(node.left, value);
|
|
252
|
-
if (node.left) {
|
|
253
|
-
node.left.parent = node;
|
|
254
|
-
}
|
|
255
|
-
} else if (compareResult > 0) {
|
|
256
|
-
node.right = this.removeNode(node.right, value);
|
|
257
|
-
if (node.right) {
|
|
258
|
-
node.right.parent = node;
|
|
259
|
-
}
|
|
260
|
-
} else {
|
|
261
|
-
// Node to delete found
|
|
262
|
-
if (!node.left) {
|
|
263
|
-
return node.right;
|
|
264
|
-
}
|
|
265
|
-
if (!node.right) {
|
|
266
|
-
return node.left;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
// Node has two children
|
|
270
|
-
const successor = node.right.findMin();
|
|
271
|
-
node.value = successor.value;
|
|
272
|
-
node.right = this.removeNode(node.right, successor.value);
|
|
273
|
-
if (node.right) {
|
|
274
|
-
node.right.parent = node;
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
node.updateStats();
|
|
279
|
-
return this.balance(node);
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
/**
|
|
283
|
-
* Finds a node by value
|
|
284
|
-
*/
|
|
285
|
-
public find(value: bigint | string | number): NumberNode | null {
|
|
286
|
-
const searchValue = typeof value === 'bigint' ? value : BigInt(value);
|
|
287
|
-
let current = this.root;
|
|
288
|
-
|
|
289
|
-
while (current) {
|
|
290
|
-
const compareResult = this.comparator(searchValue, current.value);
|
|
291
|
-
if (compareResult === 0) {
|
|
292
|
-
return current;
|
|
293
|
-
}
|
|
294
|
-
current = compareResult < 0 ? current.left : current.right;
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
return null;
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
/**
|
|
301
|
-
* Traverses the tree in specified order and returns values
|
|
302
|
-
*/
|
|
303
|
-
public traverse(order: 'inOrder' | 'preOrder' | 'postOrder' = 'inOrder',
|
|
304
|
-
config: TraversalConfig = {}): bigint[] {
|
|
305
|
-
const result: bigint[] = [];
|
|
306
|
-
|
|
307
|
-
const traverse = (node: NumberNode | null, depth: number = 0): void => {
|
|
308
|
-
if (!node || (config.maxDepth !== undefined && depth >= config.maxDepth)) {
|
|
309
|
-
return;
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
if (order === 'preOrder') {
|
|
313
|
-
result.push(node.value);
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
if (!config.skipSubtrees) {
|
|
317
|
-
traverse(node.left, depth + 1);
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
if (order === 'inOrder') {
|
|
321
|
-
result.push(node.value);
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
if (!config.skipSubtrees) {
|
|
325
|
-
traverse(node.right, depth + 1);
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
if (order === 'postOrder') {
|
|
329
|
-
result.push(node.value);
|
|
330
|
-
}
|
|
331
|
-
};
|
|
332
|
-
|
|
333
|
-
traverse(this.root);
|
|
334
|
-
return result;
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
/**
|
|
338
|
-
* Gets overall tree statistics
|
|
339
|
-
*/
|
|
340
|
-
public getTreeStats(): NodeStats | null {
|
|
341
|
-
return this.root?.getStats() ?? null;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
/**
|
|
345
|
-
* Gets the nth smallest value in the tree
|
|
346
|
-
*/
|
|
347
|
-
public getNthValue(n: number): bigint | null {
|
|
348
|
-
if (!this.root || n < 1 || n > this.root.size) {
|
|
349
|
-
return null;
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
const findNth = (node: NumberNode | null, position: number): bigint | null => {
|
|
353
|
-
if (!node) {
|
|
354
|
-
return null;
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
const leftSize = node.left?.size ?? 0;
|
|
358
|
-
|
|
359
|
-
if (position === leftSize + 1) {
|
|
360
|
-
return node.value;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
if (position <= leftSize) {
|
|
364
|
-
return findNth(node.left, position);
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
return findNth(node.right, position - leftSize - 1);
|
|
368
|
-
};
|
|
369
|
-
|
|
370
|
-
return findNth(this.root, n);
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
/**
|
|
374
|
-
* Gets a range of values between start and end (inclusive)
|
|
375
|
-
*/
|
|
376
|
-
public getRange(start: bigint | string | number,
|
|
377
|
-
end: bigint | string | number): bigint[] {
|
|
378
|
-
const startValue = typeof start === 'bigint' ? start : BigInt(start);
|
|
379
|
-
const endValue = typeof end === 'bigint' ? end : BigInt(end);
|
|
380
|
-
const result: bigint[] = [];
|
|
381
|
-
|
|
382
|
-
const collectRange = (node: NumberNode | null): void => {
|
|
383
|
-
if (!node) {
|
|
384
|
-
return;
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
if (this.comparator(node.value, startValue) >= 0 &&
|
|
388
|
-
this.comparator(node.value, endValue) <= 0) {
|
|
389
|
-
collectRange(node.left);
|
|
390
|
-
result.push(node.value);
|
|
391
|
-
collectRange(node.right);
|
|
392
|
-
} else if (this.comparator(node.value, startValue) > 0) {
|
|
393
|
-
collectRange(node.left);
|
|
394
|
-
} else {
|
|
395
|
-
collectRange(node.right);
|
|
396
|
-
}
|
|
397
|
-
};
|
|
398
|
-
|
|
399
|
-
collectRange(this.root);
|
|
400
|
-
return result;
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
|
|
1
|
+
import { Comparator } from "@/core";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Interface for tree node statistics
|
|
5
|
+
*/
|
|
6
|
+
interface NodeStats {
|
|
7
|
+
height: number;
|
|
8
|
+
size: number;
|
|
9
|
+
sum: bigint;
|
|
10
|
+
min: bigint;
|
|
11
|
+
max: bigint;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Interface for tree traversal configuration
|
|
16
|
+
*/
|
|
17
|
+
interface TraversalConfig {
|
|
18
|
+
includeStats?: boolean;
|
|
19
|
+
skipSubtrees?: boolean;
|
|
20
|
+
maxDepth?: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Class representing a node in the number tree
|
|
25
|
+
*/
|
|
26
|
+
class NumberNode {
|
|
27
|
+
value: bigint;
|
|
28
|
+
left: NumberNode | null;
|
|
29
|
+
right: NumberNode | null;
|
|
30
|
+
parent: NumberNode | null;
|
|
31
|
+
height: number;
|
|
32
|
+
size: number;
|
|
33
|
+
sum: bigint;
|
|
34
|
+
|
|
35
|
+
constructor(value: bigint | string | number) {
|
|
36
|
+
this.value = typeof value === 'bigint' ? value : BigInt(value);
|
|
37
|
+
this.left = null;
|
|
38
|
+
this.right = null;
|
|
39
|
+
this.parent = null;
|
|
40
|
+
this.height = 1;
|
|
41
|
+
this.size = 1;
|
|
42
|
+
this.sum = this.value;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Updates node statistics based on children
|
|
47
|
+
*/
|
|
48
|
+
updateStats(): void {
|
|
49
|
+
this.height = 1 + Math.max(
|
|
50
|
+
this.left?.height ?? 0,
|
|
51
|
+
this.right?.height ?? 0
|
|
52
|
+
);
|
|
53
|
+
this.size = 1 + (this.left?.size ?? 0) + (this.right?.size ?? 0);
|
|
54
|
+
this.sum = this.value +
|
|
55
|
+
(this.left?.sum ?? BigInt(0)) +
|
|
56
|
+
(this.right?.sum ?? BigInt(0));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Gets balance factor of the node
|
|
61
|
+
*/
|
|
62
|
+
getBalance(): number {
|
|
63
|
+
return (this.left?.height ?? 0) - (this.right?.height ?? 0);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Gets complete statistics for the node and its subtree
|
|
68
|
+
*/
|
|
69
|
+
getStats(): NodeStats {
|
|
70
|
+
return {
|
|
71
|
+
height: this.height,
|
|
72
|
+
size: this.size,
|
|
73
|
+
sum: this.sum,
|
|
74
|
+
min: this.findMin().value,
|
|
75
|
+
max: this.findMax().value
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Finds minimum value node in the subtree
|
|
81
|
+
*/
|
|
82
|
+
findMin(): NumberNode {
|
|
83
|
+
let current: NumberNode = this;
|
|
84
|
+
while (current.left) {
|
|
85
|
+
current = current.left;
|
|
86
|
+
}
|
|
87
|
+
return current;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Finds maximum value node in the subtree
|
|
92
|
+
*/
|
|
93
|
+
findMax(): NumberNode {
|
|
94
|
+
let current: NumberNode = this;
|
|
95
|
+
while (current.right) {
|
|
96
|
+
current = current.right;
|
|
97
|
+
}
|
|
98
|
+
return current;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* AVL Tree implementation specialized for handling large numbers
|
|
104
|
+
*/
|
|
105
|
+
export class NumberTree {
|
|
106
|
+
private root: NumberNode | null;
|
|
107
|
+
private readonly comparator: Comparator<bigint>;
|
|
108
|
+
|
|
109
|
+
constructor(comparator?: Comparator<bigint>) {
|
|
110
|
+
this.root = null;
|
|
111
|
+
this.comparator = comparator ?? ((a: bigint, b: bigint): -1 | 0 | 1 => {
|
|
112
|
+
if (a < b) return -1;
|
|
113
|
+
if (a > b) return 1;
|
|
114
|
+
return 0;
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Gets the root node if it exists
|
|
120
|
+
*/
|
|
121
|
+
public getRoot(): NumberNode | null {
|
|
122
|
+
return this.root;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Inserts a new value into the tree
|
|
127
|
+
*/
|
|
128
|
+
public insert(value: bigint | string | number): NumberNode {
|
|
129
|
+
const newValue = typeof value === 'bigint' ? value : BigInt(value);
|
|
130
|
+
this.root = this.insertNode(this.root, newValue);
|
|
131
|
+
return this.find(newValue)!;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Recursively inserts a new node
|
|
136
|
+
*/
|
|
137
|
+
private insertNode(node: NumberNode | null, value: bigint): NumberNode {
|
|
138
|
+
if (!node) {
|
|
139
|
+
return new NumberNode(value);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const compareResult = this.comparator(value, node.value);
|
|
143
|
+
if (compareResult < 0) {
|
|
144
|
+
node.left = this.insertNode(node.left, value);
|
|
145
|
+
node.left.parent = node;
|
|
146
|
+
} else if (compareResult > 0) {
|
|
147
|
+
node.right = this.insertNode(node.right, value);
|
|
148
|
+
node.right.parent = node;
|
|
149
|
+
} else {
|
|
150
|
+
return node; // Duplicate value, return existing node
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
node.updateStats();
|
|
154
|
+
return this.balance(node);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Balances a node using AVL rotations
|
|
159
|
+
*/
|
|
160
|
+
private balance(node: NumberNode): NumberNode {
|
|
161
|
+
const balance = node.getBalance();
|
|
162
|
+
|
|
163
|
+
// Left heavy
|
|
164
|
+
if (balance > 1) {
|
|
165
|
+
if (node.left && node.left.getBalance() < 0) {
|
|
166
|
+
node.left = this.rotateLeft(node.left);
|
|
167
|
+
}
|
|
168
|
+
return this.rotateRight(node);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Right heavy
|
|
172
|
+
if (balance < -1) {
|
|
173
|
+
if (node.right && node.right.getBalance() > 0) {
|
|
174
|
+
node.right = this.rotateRight(node.right);
|
|
175
|
+
}
|
|
176
|
+
return this.rotateLeft(node);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return node;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Performs left rotation
|
|
184
|
+
*/
|
|
185
|
+
private rotateLeft(node: NumberNode): NumberNode {
|
|
186
|
+
const rightChild = node.right!;
|
|
187
|
+
const rightLeftChild = rightChild.left;
|
|
188
|
+
|
|
189
|
+
rightChild.left = node;
|
|
190
|
+
node.right = rightLeftChild;
|
|
191
|
+
|
|
192
|
+
if (rightLeftChild) {
|
|
193
|
+
rightLeftChild.parent = node;
|
|
194
|
+
}
|
|
195
|
+
rightChild.parent = node.parent;
|
|
196
|
+
node.parent = rightChild;
|
|
197
|
+
|
|
198
|
+
node.updateStats();
|
|
199
|
+
rightChild.updateStats();
|
|
200
|
+
|
|
201
|
+
return rightChild;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Performs right rotation
|
|
206
|
+
*/
|
|
207
|
+
private rotateRight(node: NumberNode): NumberNode {
|
|
208
|
+
const leftChild = node.left!;
|
|
209
|
+
const leftRightChild = leftChild.right;
|
|
210
|
+
|
|
211
|
+
leftChild.right = node;
|
|
212
|
+
node.left = leftRightChild;
|
|
213
|
+
|
|
214
|
+
if (leftRightChild) {
|
|
215
|
+
leftRightChild.parent = node;
|
|
216
|
+
}
|
|
217
|
+
leftChild.parent = node.parent;
|
|
218
|
+
node.parent = leftChild;
|
|
219
|
+
|
|
220
|
+
node.updateStats();
|
|
221
|
+
leftChild.updateStats();
|
|
222
|
+
|
|
223
|
+
return leftChild;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Removes a value from the tree
|
|
228
|
+
*/
|
|
229
|
+
public remove(value: bigint | string | number): boolean {
|
|
230
|
+
const searchValue = typeof value === 'bigint' ? value : BigInt(value);
|
|
231
|
+
const nodeToRemove = this.find(searchValue);
|
|
232
|
+
|
|
233
|
+
if (!nodeToRemove) {
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
this.root = this.removeNode(this.root, searchValue);
|
|
238
|
+
return true;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Recursively removes a node
|
|
243
|
+
*/
|
|
244
|
+
private removeNode(node: NumberNode | null, value: bigint): NumberNode | null {
|
|
245
|
+
if (!node) {
|
|
246
|
+
return null;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const compareResult = this.comparator(value, node.value);
|
|
250
|
+
if (compareResult < 0) {
|
|
251
|
+
node.left = this.removeNode(node.left, value);
|
|
252
|
+
if (node.left) {
|
|
253
|
+
node.left.parent = node;
|
|
254
|
+
}
|
|
255
|
+
} else if (compareResult > 0) {
|
|
256
|
+
node.right = this.removeNode(node.right, value);
|
|
257
|
+
if (node.right) {
|
|
258
|
+
node.right.parent = node;
|
|
259
|
+
}
|
|
260
|
+
} else {
|
|
261
|
+
// Node to delete found
|
|
262
|
+
if (!node.left) {
|
|
263
|
+
return node.right;
|
|
264
|
+
}
|
|
265
|
+
if (!node.right) {
|
|
266
|
+
return node.left;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Node has two children
|
|
270
|
+
const successor = node.right.findMin();
|
|
271
|
+
node.value = successor.value;
|
|
272
|
+
node.right = this.removeNode(node.right, successor.value);
|
|
273
|
+
if (node.right) {
|
|
274
|
+
node.right.parent = node;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
node.updateStats();
|
|
279
|
+
return this.balance(node);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Finds a node by value
|
|
284
|
+
*/
|
|
285
|
+
public find(value: bigint | string | number): NumberNode | null {
|
|
286
|
+
const searchValue = typeof value === 'bigint' ? value : BigInt(value);
|
|
287
|
+
let current = this.root;
|
|
288
|
+
|
|
289
|
+
while (current) {
|
|
290
|
+
const compareResult = this.comparator(searchValue, current.value);
|
|
291
|
+
if (compareResult === 0) {
|
|
292
|
+
return current;
|
|
293
|
+
}
|
|
294
|
+
current = compareResult < 0 ? current.left : current.right;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
return null;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Traverses the tree in specified order and returns values
|
|
302
|
+
*/
|
|
303
|
+
public traverse(order: 'inOrder' | 'preOrder' | 'postOrder' = 'inOrder',
|
|
304
|
+
config: TraversalConfig = {}): bigint[] {
|
|
305
|
+
const result: bigint[] = [];
|
|
306
|
+
|
|
307
|
+
const traverse = (node: NumberNode | null, depth: number = 0): void => {
|
|
308
|
+
if (!node || (config.maxDepth !== undefined && depth >= config.maxDepth)) {
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (order === 'preOrder') {
|
|
313
|
+
result.push(node.value);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (!config.skipSubtrees) {
|
|
317
|
+
traverse(node.left, depth + 1);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
if (order === 'inOrder') {
|
|
321
|
+
result.push(node.value);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
if (!config.skipSubtrees) {
|
|
325
|
+
traverse(node.right, depth + 1);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
if (order === 'postOrder') {
|
|
329
|
+
result.push(node.value);
|
|
330
|
+
}
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
traverse(this.root);
|
|
334
|
+
return result;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Gets overall tree statistics
|
|
339
|
+
*/
|
|
340
|
+
public getTreeStats(): NodeStats | null {
|
|
341
|
+
return this.root?.getStats() ?? null;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Gets the nth smallest value in the tree
|
|
346
|
+
*/
|
|
347
|
+
public getNthValue(n: number): bigint | null {
|
|
348
|
+
if (!this.root || n < 1 || n > this.root.size) {
|
|
349
|
+
return null;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
const findNth = (node: NumberNode | null, position: number): bigint | null => {
|
|
353
|
+
if (!node) {
|
|
354
|
+
return null;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
const leftSize = node.left?.size ?? 0;
|
|
358
|
+
|
|
359
|
+
if (position === leftSize + 1) {
|
|
360
|
+
return node.value;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
if (position <= leftSize) {
|
|
364
|
+
return findNth(node.left, position);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
return findNth(node.right, position - leftSize - 1);
|
|
368
|
+
};
|
|
369
|
+
|
|
370
|
+
return findNth(this.root, n);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Gets a range of values between start and end (inclusive)
|
|
375
|
+
*/
|
|
376
|
+
public getRange(start: bigint | string | number,
|
|
377
|
+
end: bigint | string | number): bigint[] {
|
|
378
|
+
const startValue = typeof start === 'bigint' ? start : BigInt(start);
|
|
379
|
+
const endValue = typeof end === 'bigint' ? end : BigInt(end);
|
|
380
|
+
const result: bigint[] = [];
|
|
381
|
+
|
|
382
|
+
const collectRange = (node: NumberNode | null): void => {
|
|
383
|
+
if (!node) {
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
if (this.comparator(node.value, startValue) >= 0 &&
|
|
388
|
+
this.comparator(node.value, endValue) <= 0) {
|
|
389
|
+
collectRange(node.left);
|
|
390
|
+
result.push(node.value);
|
|
391
|
+
collectRange(node.right);
|
|
392
|
+
} else if (this.comparator(node.value, startValue) > 0) {
|
|
393
|
+
collectRange(node.left);
|
|
394
|
+
} else {
|
|
395
|
+
collectRange(node.right);
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
|
|
399
|
+
collectRange(this.root);
|
|
400
|
+
return result;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
404
|
export default NumberTree;
|