undirected-graph-typed 2.0.4 → 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.
- package/dist/data-structures/base/iterable-element-base.d.ts +186 -83
- package/dist/data-structures/base/iterable-element-base.js +149 -107
- package/dist/data-structures/base/iterable-entry-base.d.ts +95 -119
- package/dist/data-structures/base/iterable-entry-base.js +59 -116
- package/dist/data-structures/base/linear-base.d.ts +250 -192
- package/dist/data-structures/base/linear-base.js +137 -274
- package/dist/data-structures/binary-tree/avl-tree-counter.d.ts +126 -158
- package/dist/data-structures/binary-tree/avl-tree-counter.js +171 -205
- package/dist/data-structures/binary-tree/avl-tree-multi-map.d.ts +100 -69
- package/dist/data-structures/binary-tree/avl-tree-multi-map.js +135 -87
- package/dist/data-structures/binary-tree/avl-tree.d.ts +138 -149
- package/dist/data-structures/binary-tree/avl-tree.js +208 -195
- package/dist/data-structures/binary-tree/binary-tree.d.ts +476 -632
- package/dist/data-structures/binary-tree/binary-tree.js +612 -879
- package/dist/data-structures/binary-tree/bst.d.ts +258 -306
- package/dist/data-structures/binary-tree/bst.js +505 -481
- package/dist/data-structures/binary-tree/red-black-tree.d.ts +107 -179
- package/dist/data-structures/binary-tree/red-black-tree.js +114 -209
- package/dist/data-structures/binary-tree/tree-counter.d.ts +132 -154
- package/dist/data-structures/binary-tree/tree-counter.js +172 -203
- package/dist/data-structures/binary-tree/tree-multi-map.d.ts +72 -69
- package/dist/data-structures/binary-tree/tree-multi-map.js +105 -85
- package/dist/data-structures/graph/abstract-graph.d.ts +238 -233
- package/dist/data-structures/graph/abstract-graph.js +267 -237
- package/dist/data-structures/graph/directed-graph.d.ts +108 -224
- package/dist/data-structures/graph/directed-graph.js +146 -233
- package/dist/data-structures/graph/map-graph.d.ts +49 -55
- package/dist/data-structures/graph/map-graph.js +56 -59
- package/dist/data-structures/graph/undirected-graph.d.ts +103 -146
- package/dist/data-structures/graph/undirected-graph.js +129 -149
- package/dist/data-structures/hash/hash-map.d.ts +164 -338
- package/dist/data-structures/hash/hash-map.js +270 -457
- package/dist/data-structures/heap/heap.d.ts +214 -289
- package/dist/data-structures/heap/heap.js +340 -349
- package/dist/data-structures/heap/max-heap.d.ts +11 -47
- package/dist/data-structures/heap/max-heap.js +11 -66
- package/dist/data-structures/heap/min-heap.d.ts +12 -47
- package/dist/data-structures/heap/min-heap.js +11 -66
- package/dist/data-structures/linked-list/doubly-linked-list.d.ts +231 -347
- package/dist/data-structures/linked-list/doubly-linked-list.js +368 -494
- package/dist/data-structures/linked-list/singly-linked-list.d.ts +261 -310
- package/dist/data-structures/linked-list/singly-linked-list.js +447 -466
- package/dist/data-structures/linked-list/skip-linked-list.d.ts +0 -107
- package/dist/data-structures/linked-list/skip-linked-list.js +0 -100
- package/dist/data-structures/priority-queue/max-priority-queue.d.ts +12 -56
- package/dist/data-structures/priority-queue/max-priority-queue.js +11 -78
- package/dist/data-structures/priority-queue/min-priority-queue.d.ts +11 -57
- package/dist/data-structures/priority-queue/min-priority-queue.js +10 -79
- package/dist/data-structures/priority-queue/priority-queue.d.ts +2 -61
- package/dist/data-structures/priority-queue/priority-queue.js +8 -83
- package/dist/data-structures/queue/deque.d.ts +227 -254
- package/dist/data-structures/queue/deque.js +309 -348
- package/dist/data-structures/queue/queue.d.ts +180 -201
- package/dist/data-structures/queue/queue.js +265 -248
- package/dist/data-structures/stack/stack.d.ts +124 -102
- package/dist/data-structures/stack/stack.js +181 -125
- package/dist/data-structures/trie/trie.d.ts +164 -165
- package/dist/data-structures/trie/trie.js +189 -172
- package/dist/interfaces/binary-tree.d.ts +56 -6
- package/dist/interfaces/graph.d.ts +16 -0
- package/dist/types/data-structures/base/base.d.ts +1 -1
- package/dist/types/data-structures/graph/abstract-graph.d.ts +4 -0
- package/dist/types/utils/utils.d.ts +6 -6
- package/dist/utils/utils.d.ts +110 -49
- package/dist/utils/utils.js +148 -73
- package/package.json +2 -2
- package/src/data-structures/base/iterable-element-base.ts +238 -115
- package/src/data-structures/base/iterable-entry-base.ts +96 -120
- package/src/data-structures/base/linear-base.ts +271 -277
- package/src/data-structures/binary-tree/avl-tree-counter.ts +198 -216
- package/src/data-structures/binary-tree/avl-tree-multi-map.ts +192 -101
- package/src/data-structures/binary-tree/avl-tree.ts +239 -206
- package/src/data-structures/binary-tree/binary-tree.ts +681 -905
- package/src/data-structures/binary-tree/bst.ts +568 -570
- package/src/data-structures/binary-tree/red-black-tree.ts +161 -222
- package/src/data-structures/binary-tree/tree-counter.ts +199 -218
- package/src/data-structures/binary-tree/tree-multi-map.ts +131 -97
- package/src/data-structures/graph/abstract-graph.ts +339 -264
- package/src/data-structures/graph/directed-graph.ts +146 -236
- package/src/data-structures/graph/map-graph.ts +63 -60
- package/src/data-structures/graph/undirected-graph.ts +129 -152
- package/src/data-structures/hash/hash-map.ts +274 -496
- package/src/data-structures/heap/heap.ts +389 -402
- package/src/data-structures/heap/max-heap.ts +12 -76
- package/src/data-structures/heap/min-heap.ts +13 -76
- package/src/data-structures/linked-list/doubly-linked-list.ts +426 -530
- package/src/data-structures/linked-list/singly-linked-list.ts +495 -517
- package/src/data-structures/linked-list/skip-linked-list.ts +1 -108
- package/src/data-structures/priority-queue/max-priority-queue.ts +12 -87
- package/src/data-structures/priority-queue/min-priority-queue.ts +11 -88
- package/src/data-structures/priority-queue/priority-queue.ts +3 -92
- package/src/data-structures/queue/deque.ts +381 -357
- package/src/data-structures/queue/queue.ts +310 -264
- package/src/data-structures/stack/stack.ts +217 -131
- package/src/data-structures/trie/trie.ts +240 -175
- package/src/interfaces/binary-tree.ts +240 -6
- package/src/interfaces/graph.ts +37 -0
- package/src/types/data-structures/base/base.ts +5 -5
- package/src/types/data-structures/graph/abstract-graph.ts +5 -0
- package/src/types/utils/utils.ts +9 -5
- package/src/utils/utils.ts +152 -86
|
@@ -5,21 +5,35 @@
|
|
|
5
5
|
* @copyright Copyright (c) 2022 Pablo Zeng <zrwusa@gmail.com>
|
|
6
6
|
* @license MIT License
|
|
7
7
|
*/
|
|
8
|
+
|
|
8
9
|
import { BST, BSTNode } from './bst';
|
|
9
|
-
import type {
|
|
10
|
+
import type {
|
|
11
|
+
AVLTreeOptions,
|
|
12
|
+
BinaryTreeDeleteResult,
|
|
13
|
+
BinaryTreeOptions,
|
|
14
|
+
BSTNOptKeyOrNode,
|
|
15
|
+
EntryCallback,
|
|
16
|
+
IterationType
|
|
17
|
+
} from '../../types';
|
|
18
|
+
import { BSTOptions } from '../../types';
|
|
10
19
|
import { IBinaryTree } from '../../interfaces';
|
|
11
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Represents a Node in an AVL (Adelson-Velsky and Landis) Tree.
|
|
23
|
+
* It extends a BSTNode and ensures the 'height' property is maintained.
|
|
24
|
+
*
|
|
25
|
+
* @template K - The type of the key.
|
|
26
|
+
* @template V - The type of the value.
|
|
27
|
+
*/
|
|
12
28
|
export class AVLTreeNode<K = any, V = any> extends BSTNode<K, V> {
|
|
13
29
|
override parent?: AVLTreeNode<K, V> = undefined;
|
|
14
30
|
|
|
15
31
|
/**
|
|
16
|
-
*
|
|
17
|
-
* @
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* @param
|
|
21
|
-
* have to be provided when creating an instance of the class. If a value is not provided, it will
|
|
22
|
-
* default to `undefined`.
|
|
32
|
+
* Creates an instance of AVLTreeNode.
|
|
33
|
+
* @remarks Time O(1), Space O(1)
|
|
34
|
+
*
|
|
35
|
+
* @param key - The key of the node.
|
|
36
|
+
* @param [value] - The value associated with the key.
|
|
23
37
|
*/
|
|
24
38
|
constructor(key: K, value?: V) {
|
|
25
39
|
super(key, value);
|
|
@@ -27,10 +41,22 @@ export class AVLTreeNode<K = any, V = any> extends BSTNode<K, V> {
|
|
|
27
41
|
|
|
28
42
|
override _left?: AVLTreeNode<K, V> | null | undefined = undefined;
|
|
29
43
|
|
|
44
|
+
/**
|
|
45
|
+
* Gets the left child of the node.
|
|
46
|
+
* @remarks Time O(1), Space O(1)
|
|
47
|
+
*
|
|
48
|
+
* @returns The left child.
|
|
49
|
+
*/
|
|
30
50
|
override get left(): AVLTreeNode<K, V> | null | undefined {
|
|
31
51
|
return this._left;
|
|
32
52
|
}
|
|
33
53
|
|
|
54
|
+
/**
|
|
55
|
+
* Sets the left child of the node and updates its parent reference.
|
|
56
|
+
* @remarks Time O(1), Space O(1)
|
|
57
|
+
*
|
|
58
|
+
* @param v - The node to set as the left child.
|
|
59
|
+
*/
|
|
34
60
|
override set left(v: AVLTreeNode<K, V> | null | undefined) {
|
|
35
61
|
if (v) {
|
|
36
62
|
v.parent = this;
|
|
@@ -40,10 +66,22 @@ export class AVLTreeNode<K = any, V = any> extends BSTNode<K, V> {
|
|
|
40
66
|
|
|
41
67
|
override _right?: AVLTreeNode<K, V> | null | undefined = undefined;
|
|
42
68
|
|
|
69
|
+
/**
|
|
70
|
+
* Gets the right child of the node.
|
|
71
|
+
* @remarks Time O(1), Space O(1)
|
|
72
|
+
*
|
|
73
|
+
* @returns The right child.
|
|
74
|
+
*/
|
|
43
75
|
override get right(): AVLTreeNode<K, V> | null | undefined {
|
|
44
76
|
return this._right;
|
|
45
77
|
}
|
|
46
78
|
|
|
79
|
+
/**
|
|
80
|
+
* Sets the right child of the node and updates its parent reference.
|
|
81
|
+
* @remarks Time O(1), Space O(1)
|
|
82
|
+
*
|
|
83
|
+
* @param v - The node to set as the right child.
|
|
84
|
+
*/
|
|
47
85
|
override set right(v: AVLTreeNode<K, V> | null | undefined) {
|
|
48
86
|
if (v) {
|
|
49
87
|
v.parent = this;
|
|
@@ -53,14 +91,20 @@ export class AVLTreeNode<K = any, V = any> extends BSTNode<K, V> {
|
|
|
53
91
|
}
|
|
54
92
|
|
|
55
93
|
/**
|
|
94
|
+
* Represents a self-balancing AVL (Adelson-Velsky and Landis) Tree.
|
|
95
|
+
* This tree extends BST and performs rotations on add/delete to maintain balance.
|
|
96
|
+
*
|
|
97
|
+
* @template K - The type of the key.
|
|
98
|
+
* @template V - The type of the value.
|
|
99
|
+
* @template R - The type of the raw data object (if using `toEntryFn`).
|
|
100
|
+
*
|
|
56
101
|
* 1. Height-Balanced: Each node's left and right subtrees differ in height by no more than one.
|
|
57
102
|
* 2. Automatic Rebalancing: AVL trees rebalance themselves automatically during insertions and deletions.
|
|
58
103
|
* 3. Rotations for Balancing: Utilizes rotations (single or double) to maintain balance after updates.
|
|
59
104
|
* 4. Order Preservation: Maintains the binary search tree property where left child values are less than the parent, and right child values are greater.
|
|
60
105
|
* 5. Efficient Lookups: Offers O(log n) search time, where 'n' is the number of nodes, due to its balanced nature.
|
|
61
106
|
* 6. Complex Insertions and Deletions: Due to rebalancing, these operations are more complex than in a regular BST.
|
|
62
|
-
* 7. Path Length: The path length from the root to any leaf is longer compared to an unbalanced BST, but shorter than a linear chain of nodes
|
|
63
|
-
* @example
|
|
107
|
+
* 7. Path Length: The path length from the root to any leaf is longer compared to an unbalanced BST, but shorter than a linear chain of nodes.@example
|
|
64
108
|
* // Find elements in a range
|
|
65
109
|
* // In interval queries, AVL trees, with their strictly balanced structure and lower height, offer better query efficiency, making them ideal for frequent and high-performance interval queries. In contrast, Red-Black trees, with lower update costs, are more suitable for scenarios involving frequent insertions and deletions where the requirements for interval queries are less demanding.
|
|
66
110
|
* type Datum = { timestamp: Date; temperature: number };
|
|
@@ -125,21 +169,13 @@ export class AVLTreeNode<K = any, V = any> extends BSTNode<K, V> {
|
|
|
125
169
|
* // { minute: 15, temperature: 58.6 }
|
|
126
170
|
* // ]
|
|
127
171
|
*/
|
|
128
|
-
export class AVLTree<K = any, V = any, R = object
|
|
129
|
-
extends BST<K, V, R, MK, MV, MR>
|
|
130
|
-
implements IBinaryTree<K, V, R, MK, MV, MR>
|
|
131
|
-
{
|
|
172
|
+
export class AVLTree<K = any, V = any, R extends object = object> extends BST<K, V, R> implements IBinaryTree<K, V, R> {
|
|
132
173
|
/**
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
* iterable
|
|
137
|
-
|
|
138
|
-
* used to initialize the AVLTree with key-value pairs or raw data entries. If provided
|
|
139
|
-
* @param [options] - The `options` parameter in the constructor is of type `AVLTreeOptions<K, V,
|
|
140
|
-
* R>`. It is an optional parameter that allows you to specify additional options for configuring the
|
|
141
|
-
* AVL tree. These options could include things like custom comparators, initial capacity, or any
|
|
142
|
-
* other configuration settings specific
|
|
174
|
+
* Creates an instance of AVLTree.
|
|
175
|
+
* @remarks Time O(N log N) (from `addMany` with balanced add). Space O(N).
|
|
176
|
+
*
|
|
177
|
+
* @param [keysNodesEntriesOrRaws=[]] - An iterable of items to add.
|
|
178
|
+
* @param [options] - Configuration options for the AVL tree.
|
|
143
179
|
*/
|
|
144
180
|
constructor(
|
|
145
181
|
keysNodesEntriesOrRaws: Iterable<
|
|
@@ -148,56 +184,28 @@ export class AVLTree<K = any, V = any, R = object, MK = any, MV = any, MR = obje
|
|
|
148
184
|
options?: AVLTreeOptions<K, V, R>
|
|
149
185
|
) {
|
|
150
186
|
super([], options);
|
|
187
|
+
// Note: super.addMany is called, which in BST defaults to balanced add.
|
|
151
188
|
if (keysNodesEntriesOrRaws) super.addMany(keysNodesEntriesOrRaws);
|
|
152
189
|
}
|
|
153
190
|
|
|
154
191
|
/**
|
|
155
|
-
*
|
|
156
|
-
*
|
|
192
|
+
* (Protected) Creates a new AVL tree node.
|
|
193
|
+
* @remarks Time O(1), Space O(1)
|
|
157
194
|
*
|
|
158
|
-
*
|
|
159
|
-
* @param
|
|
160
|
-
* created.
|
|
161
|
-
* @param {V} [value] - The "value" parameter is an optional parameter of type V. It represents the
|
|
162
|
-
* value associated with the key in the node being created.
|
|
163
|
-
* @returns The method is returning a new instance of the AVLTreeNode class, casted as the generic
|
|
164
|
-
* type AVLTreeNode<K, V>.
|
|
195
|
+
* @param key - The key for the new node.
|
|
196
|
+
* @param [value] - The value for the new node.
|
|
197
|
+
* @returns The newly created AVLTreeNode.
|
|
165
198
|
*/
|
|
166
|
-
override
|
|
199
|
+
override _createNode(key: K, value?: V): AVLTreeNode<K, V> {
|
|
167
200
|
return new AVLTreeNode<K, V>(key, this._isMapMode ? undefined : value) as AVLTreeNode<K, V>;
|
|
168
201
|
}
|
|
169
202
|
|
|
170
203
|
/**
|
|
171
|
-
*
|
|
172
|
-
*
|
|
173
|
-
*
|
|
174
|
-
* The function creates a new AVL tree with the specified options and returns it.
|
|
175
|
-
* @param {AVLTreeOptions} [options] - The `options` parameter is an optional object that can be
|
|
176
|
-
* passed to the `createTree` function. It is used to customize the behavior of the AVL tree that is
|
|
177
|
-
* being created.
|
|
178
|
-
* @returns a new AVLTree object.
|
|
179
|
-
*/
|
|
180
|
-
override createTree(options?: AVLTreeOptions<K, V, R>) {
|
|
181
|
-
return new AVLTree<K, V, R, MK, MV, MR>([], {
|
|
182
|
-
iterationType: this.iterationType,
|
|
183
|
-
isMapMode: this._isMapMode,
|
|
184
|
-
specifyComparable: this._specifyComparable,
|
|
185
|
-
toEntryFn: this._toEntryFn,
|
|
186
|
-
isReverse: this._isReverse,
|
|
187
|
-
...options
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* Time Complexity: O(1)
|
|
193
|
-
* Space Complexity: O(1)
|
|
204
|
+
* Checks if the given item is an `AVLTreeNode` instance.
|
|
205
|
+
* @remarks Time O(1), Space O(1)
|
|
194
206
|
*
|
|
195
|
-
*
|
|
196
|
-
* @
|
|
197
|
-
* `keyNodeOrEntry` can be of type `R` or `
|
|
198
|
-
K | AVLTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined `.
|
|
199
|
-
* @returns a boolean value indicating whether the input parameter `keyNodeOrEntry` is
|
|
200
|
-
* an instance of the `AVLTreeNode` class.
|
|
207
|
+
* @param keyNodeOrEntry - The item to check.
|
|
208
|
+
* @returns True if it's an AVLTreeNode, false otherwise.
|
|
201
209
|
*/
|
|
202
210
|
override isNode(
|
|
203
211
|
keyNodeOrEntry: K | AVLTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined
|
|
@@ -206,17 +214,12 @@ export class AVLTree<K = any, V = any, R = object, MK = any, MV = any, MR = obje
|
|
|
206
214
|
}
|
|
207
215
|
|
|
208
216
|
/**
|
|
209
|
-
*
|
|
210
|
-
*
|
|
217
|
+
* Adds a new node to the AVL tree and balances the tree path.
|
|
218
|
+
* @remarks Time O(log N) (O(H) for BST add + O(H) for `_balancePath`). Space O(H) for path/recursion.
|
|
211
219
|
*
|
|
212
|
-
*
|
|
213
|
-
*
|
|
214
|
-
* @
|
|
215
|
-
* `keyNodeOrEntry` can accept values of type `R`, `
|
|
216
|
-
K | AVLTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined `
|
|
217
|
-
* @param {V} [value] - The `value` parameter is an optional value that you want to associate with
|
|
218
|
-
* the key or node being added to the data structure.
|
|
219
|
-
* @returns The method is returning a boolean value.
|
|
220
|
+
* @param keyNodeOrEntry - The key, node, or entry to add.
|
|
221
|
+
* @param [value] - The value, if providing just a key.
|
|
222
|
+
* @returns True if the addition was successful, false otherwise.
|
|
220
223
|
*/
|
|
221
224
|
override add(
|
|
222
225
|
keyNodeOrEntry: K | AVLTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined,
|
|
@@ -224,27 +227,23 @@ export class AVLTree<K = any, V = any, R = object, MK = any, MV = any, MR = obje
|
|
|
224
227
|
): boolean {
|
|
225
228
|
if (keyNodeOrEntry === null) return false;
|
|
226
229
|
const inserted = super.add(keyNodeOrEntry, value);
|
|
230
|
+
// If insertion was successful, balance the path from the new node up to the root.
|
|
227
231
|
if (inserted) this._balancePath(keyNodeOrEntry);
|
|
228
232
|
return inserted;
|
|
229
233
|
}
|
|
230
234
|
|
|
231
235
|
/**
|
|
232
|
-
*
|
|
233
|
-
*
|
|
236
|
+
* Deletes a node from the AVL tree and re-balances the tree.
|
|
237
|
+
* @remarks Time O(log N) (O(H) for BST delete + O(H) for `_balancePath`). Space O(H) for path/recursion.
|
|
234
238
|
*
|
|
235
|
-
*
|
|
236
|
-
*
|
|
237
|
-
* @param { K | AVLTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } keyNodeOrEntry - The `keyNodeOrEntry`
|
|
238
|
-
* parameter in the `override delete` method can be one of the following types:
|
|
239
|
-
* @returns The `delete` method is being overridden in this code snippet. It first calls the `delete`
|
|
240
|
-
* method from the superclass (presumably a parent class) with the provided `predicate`, which could
|
|
241
|
-
* be a key, node, entry, or a custom predicate. The result of this deletion operation is stored in
|
|
242
|
-
* `deletedResults`, which is an array of `BinaryTreeDeleteResult` objects.
|
|
239
|
+
* @param keyNodeOrEntry - The node to delete.
|
|
240
|
+
* @returns An array containing deletion results.
|
|
243
241
|
*/
|
|
244
242
|
override delete(
|
|
245
243
|
keyNodeOrEntry: K | AVLTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined
|
|
246
244
|
): BinaryTreeDeleteResult<AVLTreeNode<K, V>>[] {
|
|
247
245
|
const deletedResults = super.delete(keyNodeOrEntry);
|
|
246
|
+
// After deletion, balance the path from the parent of the *physically deleted* node.
|
|
248
247
|
for (const { needBalanced } of deletedResults) {
|
|
249
248
|
if (needBalanced) {
|
|
250
249
|
this._balancePath(needBalanced);
|
|
@@ -254,64 +253,115 @@ export class AVLTree<K = any, V = any, R = object, MK = any, MV = any, MR = obje
|
|
|
254
253
|
}
|
|
255
254
|
|
|
256
255
|
/**
|
|
257
|
-
*
|
|
258
|
-
*
|
|
256
|
+
* Rebuilds the tree to be perfectly balanced.
|
|
257
|
+
* @remarks AVL trees are already height-balanced, but this makes them *perfectly* balanced (minimal height and all leaves at N or N-1).
|
|
258
|
+
* Time O(N) (O(N) for DFS, O(N) for sorted build). Space O(N) for node array and recursion stack.
|
|
259
259
|
*
|
|
260
|
-
*
|
|
261
|
-
*
|
|
262
|
-
* @param callback - A function that will be called for each entry in the AVLTree. It takes four
|
|
263
|
-
* arguments: the key, the value (which can be undefined), the index of the entry, and a reference to
|
|
264
|
-
* the AVLTree itself.
|
|
265
|
-
* @param [options] - The `options` parameter in the `override map` function is of type
|
|
266
|
-
* `AVLTreeOptions<MK, MV, MR>`. It is an optional parameter that allows you to specify additional
|
|
267
|
-
* options for the AVL tree being created during the mapping process. These options could include
|
|
268
|
-
* custom comparators, initial
|
|
269
|
-
* @param {any} [thisArg] - The `thisArg` parameter in the `override map` function is used to specify
|
|
270
|
-
* the value of `this` when executing the `callback` function. It allows you to set the context
|
|
271
|
-
* (value of `this`) within the callback function. This can be useful when you want to access
|
|
272
|
-
* properties or
|
|
273
|
-
* @returns The `map` method is returning a new AVLTree instance (`newTree`) with the entries
|
|
274
|
-
* modified by the provided callback function.
|
|
260
|
+
* @param [iterationType=this.iterationType] - The traversal method for the initial node export.
|
|
261
|
+
* @returns True if successful, false if the tree was empty.
|
|
275
262
|
*/
|
|
276
|
-
override
|
|
263
|
+
override perfectlyBalance(iterationType: IterationType = this.iterationType): boolean {
|
|
264
|
+
const nodes = this.dfs(node => node, 'IN', false, this._root, iterationType);
|
|
265
|
+
const n = nodes.length;
|
|
266
|
+
if (n === 0) return false;
|
|
267
|
+
|
|
268
|
+
this._clearNodes();
|
|
269
|
+
|
|
270
|
+
// Build balanced tree from sorted array
|
|
271
|
+
const build = (l: number, r: number, parent?: AVLTreeNode<K, V>): AVLTreeNode<K, V> | undefined => {
|
|
272
|
+
if (l > r) return undefined;
|
|
273
|
+
const m = l + ((r - l) >> 1);
|
|
274
|
+
const root = nodes[m]!;
|
|
275
|
+
root.left = build(l, m - 1, root);
|
|
276
|
+
root.right = build(m + 1, r, root);
|
|
277
|
+
root.parent = parent;
|
|
278
|
+
|
|
279
|
+
// Update height during the build
|
|
280
|
+
const lh = root.left ? (root.left as AVLTreeNode<K, V>).height : -1;
|
|
281
|
+
const rh = root.right ? (root.right as AVLTreeNode<K, V>).height : -1;
|
|
282
|
+
root.height = Math.max(lh, rh) + 1;
|
|
283
|
+
return root;
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
const newRoot = build(0, n - 1, undefined);
|
|
287
|
+
this._setRoot(newRoot);
|
|
288
|
+
this._size = n;
|
|
289
|
+
return true;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Creates a new AVLTree by mapping each [key, value] pair.
|
|
294
|
+
* @remarks Time O(N log N) (O(N) iteration + O(log M) `add` for each item into the new tree). Space O(N) for the new tree.
|
|
295
|
+
*
|
|
296
|
+
* @template MK - New key type.
|
|
297
|
+
* @template MV - New value type.
|
|
298
|
+
* @template MR - New raw type.
|
|
299
|
+
* @param callback - A function to map each [key, value] pair.
|
|
300
|
+
* @param [options] - Options for the new AVLTree.
|
|
301
|
+
* @param [thisArg] - `this` context for the callback.
|
|
302
|
+
* @returns A new, mapped AVLTree.
|
|
303
|
+
*/
|
|
304
|
+
override map<MK = K, MV = V, MR extends object = object>(
|
|
277
305
|
callback: EntryCallback<K, V | undefined, [MK, MV]>,
|
|
278
|
-
options?:
|
|
279
|
-
thisArg?:
|
|
306
|
+
options?: Partial<BinaryTreeOptions<MK, MV, MR>>,
|
|
307
|
+
thisArg?: unknown
|
|
280
308
|
): AVLTree<MK, MV, MR> {
|
|
281
|
-
const
|
|
309
|
+
const out = this._createLike<MK, MV, MR>([], options);
|
|
310
|
+
|
|
282
311
|
let index = 0;
|
|
312
|
+
// Iterates in-order
|
|
283
313
|
for (const [key, value] of this) {
|
|
284
|
-
|
|
314
|
+
// `add` on the new tree will be O(log N) and will self-balance.
|
|
315
|
+
out.add(callback.call(thisArg, key, value, index++, this));
|
|
285
316
|
}
|
|
286
|
-
return
|
|
317
|
+
return out;
|
|
287
318
|
}
|
|
288
319
|
|
|
289
320
|
/**
|
|
290
|
-
*
|
|
291
|
-
*
|
|
321
|
+
* (Protected) Creates a new, empty instance of the same AVLTree constructor.
|
|
322
|
+
* @remarks Time O(1)
|
|
292
323
|
*
|
|
293
|
-
*
|
|
294
|
-
*
|
|
295
|
-
* @returns A
|
|
324
|
+
* @template TK, TV, TR - Generic types for the new instance.
|
|
325
|
+
* @param [options] - Options for the new tree.
|
|
326
|
+
* @returns A new, empty tree.
|
|
296
327
|
*/
|
|
297
|
-
override
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
328
|
+
protected override _createInstance<TK = K, TV = V, TR extends object = R>(
|
|
329
|
+
options?: Partial<BSTOptions<TK, TV, TR>>
|
|
330
|
+
): this {
|
|
331
|
+
const Ctor = this.constructor as unknown as new (
|
|
332
|
+
iter?: Iterable<TK | BSTNode<TK, TV> | [TK | null | undefined, TV | undefined] | null | undefined | TR>,
|
|
333
|
+
opts?: BSTOptions<TK, TV, TR>
|
|
334
|
+
) => this;
|
|
335
|
+
return new Ctor([], { ...this._snapshotOptions<TK, TV, TR>(), ...(options ?? {}) }) as unknown as this;
|
|
301
336
|
}
|
|
302
337
|
|
|
303
338
|
/**
|
|
304
|
-
*
|
|
305
|
-
*
|
|
339
|
+
* (Protected) Creates a new instance of the same AVLTree constructor, potentially with different generic types.
|
|
340
|
+
* @remarks Time O(N log N) (from constructor) due to processing the iterable.
|
|
306
341
|
*
|
|
307
|
-
*
|
|
308
|
-
*
|
|
309
|
-
* @param
|
|
310
|
-
*
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
342
|
+
* @template TK, TV, TR - Generic types for the new instance.
|
|
343
|
+
* @param [iter=[]] - An iterable to populate the new tree.
|
|
344
|
+
* @param [options] - Options for the new tree.
|
|
345
|
+
* @returns A new AVLTree.
|
|
346
|
+
*/
|
|
347
|
+
protected override _createLike<TK = K, TV = V, TR extends object = R>(
|
|
348
|
+
iter: Iterable<TK | BSTNode<TK, TV> | [TK | null | undefined, TV | undefined] | null | undefined | TR> = [],
|
|
349
|
+
options?: Partial<BSTOptions<TK, TV, TR>>
|
|
350
|
+
): AVLTree<TK, TV, TR> {
|
|
351
|
+
const Ctor = this.constructor as unknown as new (
|
|
352
|
+
iter?: Iterable<TK | BSTNode<TK, TV> | [TK | null | undefined, TV | undefined] | null | undefined | TR>,
|
|
353
|
+
opts?: BSTOptions<TK, TV, TR>
|
|
354
|
+
) => AVLTree<TK, TV, TR>;
|
|
355
|
+
return new Ctor(iter, { ...this._snapshotOptions<TK, TV, TR>(), ...(options ?? {}) });
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* (Protected) Swaps properties of two nodes, including height.
|
|
360
|
+
* @remarks Time O(H) (due to `ensureNode`), but O(1) if nodes are passed directly.
|
|
361
|
+
*
|
|
362
|
+
* @param srcNode - The source node.
|
|
363
|
+
* @param destNode - The destination node.
|
|
364
|
+
* @returns The `destNode` (now holding `srcNode`'s properties).
|
|
315
365
|
*/
|
|
316
366
|
protected override _swapProperties(
|
|
317
367
|
srcNode: BSTNOptKeyOrNode<K, AVLTreeNode<K, V>>,
|
|
@@ -322,15 +372,17 @@ export class AVLTree<K = any, V = any, R = object, MK = any, MV = any, MR = obje
|
|
|
322
372
|
|
|
323
373
|
if (srcNodeEnsured && destNodeEnsured) {
|
|
324
374
|
const { key, value, height } = destNodeEnsured;
|
|
325
|
-
const tempNode = this.
|
|
375
|
+
const tempNode = this._createNode(key, value);
|
|
326
376
|
|
|
327
377
|
if (tempNode) {
|
|
328
378
|
tempNode.height = height;
|
|
329
379
|
|
|
380
|
+
// Copy src to dest
|
|
330
381
|
destNodeEnsured.key = srcNodeEnsured.key;
|
|
331
382
|
if (!this._isMapMode) destNodeEnsured.value = srcNodeEnsured.value;
|
|
332
383
|
destNodeEnsured.height = srcNodeEnsured.height;
|
|
333
384
|
|
|
385
|
+
// Copy temp (original dest) to src
|
|
334
386
|
srcNodeEnsured.key = tempNode.key;
|
|
335
387
|
if (!this._isMapMode) srcNodeEnsured.value = tempNode.value;
|
|
336
388
|
srcNodeEnsured.height = tempNode.height;
|
|
@@ -342,57 +394,46 @@ export class AVLTree<K = any, V = any, R = object, MK = any, MV = any, MR = obje
|
|
|
342
394
|
}
|
|
343
395
|
|
|
344
396
|
/**
|
|
345
|
-
*
|
|
346
|
-
*
|
|
397
|
+
* (Protected) Calculates the balance factor (height(right) - height(left)).
|
|
398
|
+
* @remarks Time O(1) (assumes heights are stored).
|
|
347
399
|
*
|
|
348
|
-
*
|
|
349
|
-
* @
|
|
350
|
-
* binary tree data structure.
|
|
351
|
-
* @returns the balance factor of a given node. The balance factor is calculated by subtracting the
|
|
352
|
-
* height of the left subtree from the height of the right subtree.
|
|
400
|
+
* @param node - The node to check.
|
|
401
|
+
* @returns The balance factor (positive if right-heavy, negative if left-heavy).
|
|
353
402
|
*/
|
|
354
403
|
protected _balanceFactor(node: AVLTreeNode<K, V>): number {
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
else if (!node.left)
|
|
359
|
-
// node has no left subtree
|
|
360
|
-
return +node.height;
|
|
361
|
-
else return node.right.height - node.left.height;
|
|
404
|
+
const left = node.left ? (node.left as AVLTreeNode<K, V>).height : -1;
|
|
405
|
+
const right = node.right ? (node.right as AVLTreeNode<K, V>).height : -1;
|
|
406
|
+
return right - left;
|
|
362
407
|
}
|
|
363
408
|
|
|
364
409
|
/**
|
|
365
|
-
*
|
|
366
|
-
*
|
|
410
|
+
* (Protected) Recalculates and updates the height of a node based on its children's heights.
|
|
411
|
+
* @remarks Time O(1) (assumes children's heights are correct).
|
|
367
412
|
*
|
|
368
|
-
*
|
|
369
|
-
* right children.
|
|
370
|
-
* @param {AVLTreeNode<K, V>} node - The parameter "node" represents a node in a binary tree data structure.
|
|
413
|
+
* @param node - The node to update.
|
|
371
414
|
*/
|
|
372
415
|
protected _updateHeight(node: AVLTreeNode<K, V>): void {
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
node.height = 1 + rightHeight;
|
|
377
|
-
} else if (!node.right) node.height = 1 + node.left.height;
|
|
378
|
-
else node.height = 1 + Math.max(node.right.height, node.left.height);
|
|
416
|
+
const leftHeight = node.left ? (node.left as AVLTreeNode<K, V>).height : -1;
|
|
417
|
+
const rightHeight = node.right ? (node.right as AVLTreeNode<K, V>).height : -1;
|
|
418
|
+
node.height = 1 + Math.max(leftHeight, rightHeight);
|
|
379
419
|
}
|
|
380
420
|
|
|
381
421
|
/**
|
|
382
|
-
*
|
|
383
|
-
*
|
|
422
|
+
* (Protected) Performs a Left-Left (LL) rotation (a single right rotation).
|
|
423
|
+
* @remarks Time O(1), Space O(1)
|
|
384
424
|
*
|
|
385
|
-
*
|
|
386
|
-
* @param {AVLTreeNode<K, V>} A - A is a node in a binary tree.
|
|
425
|
+
* @param A - The unbalanced node (root of the unbalanced subtree).
|
|
387
426
|
*/
|
|
388
427
|
protected _balanceLL(A: AVLTreeNode<K, V>): void {
|
|
389
428
|
const parentOfA = A.parent;
|
|
390
|
-
const B = A.left;
|
|
429
|
+
const B = A.left; // The left child
|
|
391
430
|
if (B !== null) A.parent = B;
|
|
392
431
|
if (B && B.right) {
|
|
393
432
|
B.right.parent = A;
|
|
394
433
|
}
|
|
395
434
|
if (B) B.parent = parentOfA;
|
|
435
|
+
|
|
436
|
+
// Update parent's child pointer
|
|
396
437
|
if (A === this.root) {
|
|
397
438
|
if (B) this._setRoot(B);
|
|
398
439
|
} else {
|
|
@@ -403,6 +444,7 @@ export class AVLTree<K = any, V = any, R = object, MK = any, MV = any, MR = obje
|
|
|
403
444
|
}
|
|
404
445
|
}
|
|
405
446
|
|
|
447
|
+
// Perform rotation
|
|
406
448
|
if (B) {
|
|
407
449
|
A.left = B.right;
|
|
408
450
|
B.right = A;
|
|
@@ -412,18 +454,17 @@ export class AVLTree<K = any, V = any, R = object, MK = any, MV = any, MR = obje
|
|
|
412
454
|
}
|
|
413
455
|
|
|
414
456
|
/**
|
|
415
|
-
*
|
|
416
|
-
*
|
|
457
|
+
* (Protected) Performs a Left-Right (LR) double rotation.
|
|
458
|
+
* @remarks Time O(1), Space O(1)
|
|
417
459
|
*
|
|
418
|
-
*
|
|
419
|
-
* @param {AVLTreeNode<K, V>} A - A is a node in a binary tree.
|
|
460
|
+
* @param A - The unbalanced node (root of the unbalanced subtree).
|
|
420
461
|
*/
|
|
421
462
|
protected _balanceLR(A: AVLTreeNode<K, V>): void {
|
|
422
463
|
const parentOfA = A.parent;
|
|
423
464
|
const B = A.left;
|
|
424
465
|
let C = undefined;
|
|
425
466
|
if (B) {
|
|
426
|
-
C = B.right;
|
|
467
|
+
C = B.right; // The "middle" node
|
|
427
468
|
}
|
|
428
469
|
if (A && C !== null) A.parent = C;
|
|
429
470
|
if (B && C !== null) B.parent = C;
|
|
@@ -438,6 +479,7 @@ export class AVLTree<K = any, V = any, R = object, MK = any, MV = any, MR = obje
|
|
|
438
479
|
C.parent = parentOfA;
|
|
439
480
|
}
|
|
440
481
|
|
|
482
|
+
// Update parent's child pointer
|
|
441
483
|
if (A === this.root) {
|
|
442
484
|
if (C) this._setRoot(C);
|
|
443
485
|
} else {
|
|
@@ -450,6 +492,7 @@ export class AVLTree<K = any, V = any, R = object, MK = any, MV = any, MR = obje
|
|
|
450
492
|
}
|
|
451
493
|
}
|
|
452
494
|
|
|
495
|
+
// Perform rotation
|
|
453
496
|
if (C) {
|
|
454
497
|
A.left = C.right;
|
|
455
498
|
if (B) B.right = C.left;
|
|
@@ -463,15 +506,14 @@ export class AVLTree<K = any, V = any, R = object, MK = any, MV = any, MR = obje
|
|
|
463
506
|
}
|
|
464
507
|
|
|
465
508
|
/**
|
|
466
|
-
*
|
|
467
|
-
*
|
|
509
|
+
* (Protected) Performs a Right-Right (RR) rotation (a single left rotation).
|
|
510
|
+
* @remarks Time O(1), Space O(1)
|
|
468
511
|
*
|
|
469
|
-
*
|
|
470
|
-
* @param {AVLTreeNode<K, V>} A - A is a node in a binary tree.
|
|
512
|
+
* @param A - The unbalanced node (root of the unbalanced subtree).
|
|
471
513
|
*/
|
|
472
514
|
protected _balanceRR(A: AVLTreeNode<K, V>): void {
|
|
473
515
|
const parentOfA = A.parent;
|
|
474
|
-
const B = A.right;
|
|
516
|
+
const B = A.right; // The right child
|
|
475
517
|
if (B !== null) A.parent = B;
|
|
476
518
|
if (B) {
|
|
477
519
|
if (B.left) {
|
|
@@ -480,6 +522,7 @@ export class AVLTree<K = any, V = any, R = object, MK = any, MV = any, MR = obje
|
|
|
480
522
|
B.parent = parentOfA;
|
|
481
523
|
}
|
|
482
524
|
|
|
525
|
+
// Update parent's child pointer
|
|
483
526
|
if (A === this.root) {
|
|
484
527
|
if (B) this._setRoot(B);
|
|
485
528
|
} else {
|
|
@@ -492,6 +535,7 @@ export class AVLTree<K = any, V = any, R = object, MK = any, MV = any, MR = obje
|
|
|
492
535
|
}
|
|
493
536
|
}
|
|
494
537
|
|
|
538
|
+
// Perform rotation
|
|
495
539
|
if (B) {
|
|
496
540
|
A.right = B.left;
|
|
497
541
|
B.left = A;
|
|
@@ -501,18 +545,17 @@ export class AVLTree<K = any, V = any, R = object, MK = any, MV = any, MR = obje
|
|
|
501
545
|
}
|
|
502
546
|
|
|
503
547
|
/**
|
|
504
|
-
*
|
|
505
|
-
*
|
|
548
|
+
* (Protected) Performs a Right-Left (RL) double rotation.
|
|
549
|
+
* @remarks Time O(1), Space O(1)
|
|
506
550
|
*
|
|
507
|
-
*
|
|
508
|
-
* @param {AVLTreeNode<K, V>} A - A is a node in a binary tree.
|
|
551
|
+
* @param A - The unbalanced node (root of the unbalanced subtree).
|
|
509
552
|
*/
|
|
510
553
|
protected _balanceRL(A: AVLTreeNode<K, V>): void {
|
|
511
554
|
const parentOfA = A.parent;
|
|
512
555
|
const B = A.right;
|
|
513
556
|
let C = undefined;
|
|
514
557
|
if (B) {
|
|
515
|
-
C = B.left;
|
|
558
|
+
C = B.left; // The "middle" node
|
|
516
559
|
}
|
|
517
560
|
|
|
518
561
|
if (C !== null) A.parent = C;
|
|
@@ -528,6 +571,7 @@ export class AVLTree<K = any, V = any, R = object, MK = any, MV = any, MR = obje
|
|
|
528
571
|
C.parent = parentOfA;
|
|
529
572
|
}
|
|
530
573
|
|
|
574
|
+
// Update parent's child pointer
|
|
531
575
|
if (A === this.root) {
|
|
532
576
|
if (C) this._setRoot(C);
|
|
533
577
|
} else {
|
|
@@ -540,6 +584,7 @@ export class AVLTree<K = any, V = any, R = object, MK = any, MV = any, MR = obje
|
|
|
540
584
|
}
|
|
541
585
|
}
|
|
542
586
|
|
|
587
|
+
// Perform rotation
|
|
543
588
|
if (C) A.right = C.left;
|
|
544
589
|
if (B && C) B.left = C.right;
|
|
545
590
|
if (C) C.left = A;
|
|
@@ -551,73 +596,61 @@ export class AVLTree<K = any, V = any, R = object, MK = any, MV = any, MR = obje
|
|
|
551
596
|
}
|
|
552
597
|
|
|
553
598
|
/**
|
|
554
|
-
*
|
|
555
|
-
*
|
|
599
|
+
* (Protected) Traverses up the tree from the specified node, updating heights and performing rotations as needed.
|
|
600
|
+
* @remarks Time O(log N) (O(H)), as it traverses the path to root. Space O(H) for the path array.
|
|
556
601
|
*
|
|
557
|
-
*
|
|
558
|
-
* to restore balance in an AVL tree after inserting a node.
|
|
559
|
-
* @param { K | AVLTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } node - The `node` parameter can be of type `R` or
|
|
560
|
-
* `
|
|
561
|
-
K | AVLTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined `.
|
|
602
|
+
* @param node - The node to start balancing from (e.g., the newly inserted node or parent of the deleted node).
|
|
562
603
|
*/
|
|
563
604
|
protected _balancePath(node: K | AVLTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined): void {
|
|
605
|
+
// Get the path from the node to the root.
|
|
564
606
|
node = this.ensureNode(node);
|
|
565
|
-
const path = this.getPathToRoot(node, node => node, false);
|
|
607
|
+
const path = this.getPathToRoot(node, node => node, false);
|
|
608
|
+
|
|
609
|
+
// Iterate up the path (from node to root)
|
|
566
610
|
for (let i = 0; i < path.length; i++) {
|
|
567
|
-
// second O(log n)
|
|
568
611
|
const A = path[i];
|
|
569
612
|
if (A) {
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
// Check
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
this._balanceFactor(A) // second O(1)
|
|
576
|
-
) {
|
|
577
|
-
case -2:
|
|
613
|
+
this._updateHeight(A);
|
|
614
|
+
|
|
615
|
+
// Check the balance factor
|
|
616
|
+
switch (this._balanceFactor(A)) {
|
|
617
|
+
case -2: // Left-heavy
|
|
578
618
|
if (A && A.left) {
|
|
579
619
|
if (this._balanceFactor(A.left) <= 0) {
|
|
580
|
-
//
|
|
581
|
-
// Left Rotation (LL Rotation): When the inserted node is in the left subtree of the left subtree, causing an imbalance.
|
|
620
|
+
// Left-Left case
|
|
582
621
|
this._balanceLL(A);
|
|
583
622
|
} else {
|
|
584
|
-
// Left-Right
|
|
623
|
+
// Left-Right case
|
|
585
624
|
this._balanceLR(A);
|
|
586
625
|
}
|
|
587
626
|
}
|
|
588
627
|
break;
|
|
589
|
-
case +2:
|
|
628
|
+
case +2: // Right-heavy
|
|
590
629
|
if (A && A.right) {
|
|
591
630
|
if (this._balanceFactor(A.right) >= 0) {
|
|
592
|
-
// Right
|
|
631
|
+
// Right-Right case
|
|
593
632
|
this._balanceRR(A);
|
|
594
633
|
} else {
|
|
595
|
-
// Right-Left
|
|
634
|
+
// Right-Left case
|
|
596
635
|
this._balanceRL(A);
|
|
597
636
|
}
|
|
598
637
|
}
|
|
599
638
|
}
|
|
600
|
-
// TODO So far, no sure if this is necessary that Recursive Repair: Once rotation operations are executed, it may cause imbalance issues at higher levels of the tree. Therefore, you need to recursively check and repair imbalance problems upwards until you reach the root node.
|
|
601
639
|
}
|
|
602
640
|
}
|
|
603
641
|
}
|
|
604
642
|
|
|
605
643
|
/**
|
|
606
|
-
*
|
|
607
|
-
*
|
|
644
|
+
* (Protected) Replaces a node, ensuring height is copied.
|
|
645
|
+
* @remarks Time O(1)
|
|
608
646
|
*
|
|
609
|
-
*
|
|
610
|
-
*
|
|
611
|
-
* @
|
|
612
|
-
* the data structure.
|
|
613
|
-
* @param {AVLTreeNode<K, V>} newNode - The `newNode` parameter is the new node that will replace the `oldNode` in
|
|
614
|
-
* the data structure.
|
|
615
|
-
* @returns The method is returning the result of calling the `_replaceNode` method from the
|
|
616
|
-
* superclass, with the `oldNode` and `newNode` as arguments.
|
|
647
|
+
* @param oldNode - The node to be replaced.
|
|
648
|
+
* @param newNode - The node to insert.
|
|
649
|
+
* @returns The `newNode`.
|
|
617
650
|
*/
|
|
618
651
|
protected override _replaceNode(oldNode: AVLTreeNode<K, V>, newNode: AVLTreeNode<K, V>): AVLTreeNode<K, V> {
|
|
652
|
+
// When replacing a node (e.g., on duplicate key), preserve the height.
|
|
619
653
|
newNode.height = oldNode.height;
|
|
620
|
-
|
|
621
654
|
return super._replaceNode(oldNode, newNode);
|
|
622
655
|
}
|
|
623
656
|
}
|