undirected-graph-typed 2.0.5 → 2.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/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 +602 -873
- 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 +1 -0
- package/dist/utils/utils.d.ts +1 -1
- package/dist/utils/utils.js +2 -1
- 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 +196 -217
- package/src/data-structures/binary-tree/avl-tree-multi-map.ts +188 -102
- package/src/data-structures/binary-tree/avl-tree.ts +237 -206
- package/src/data-structures/binary-tree/binary-tree.ts +665 -896
- package/src/data-structures/binary-tree/bst.ts +565 -572
- package/src/data-structures/binary-tree/red-black-tree.ts +157 -223
- package/src/data-structures/binary-tree/tree-counter.ts +195 -219
- package/src/data-structures/binary-tree/tree-multi-map.ts +127 -98
- 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 +2 -0
- package/src/utils/utils.ts +9 -14
|
@@ -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 =
|
|
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 = any> 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,113 @@ 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 = any>(
|
|
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
|
-
const
|
|
299
|
-
|
|
300
|
-
|
|
328
|
+
protected override _createInstance<TK = K, TV = V, TR = R>(options?: Partial<BSTOptions<TK, TV, TR>>): this {
|
|
329
|
+
const Ctor = this.constructor as unknown as new (
|
|
330
|
+
iter?: Iterable<TK | BSTNode<TK, TV> | [TK | null | undefined, TV | undefined] | null | undefined | TR>,
|
|
331
|
+
opts?: BSTOptions<TK, TV, TR>
|
|
332
|
+
) => this;
|
|
333
|
+
return new Ctor([], { ...this._snapshotOptions<TK, TV, TR>(), ...(options ?? {}) }) as unknown as this;
|
|
301
334
|
}
|
|
302
335
|
|
|
303
336
|
/**
|
|
304
|
-
*
|
|
305
|
-
*
|
|
337
|
+
* (Protected) Creates a new instance of the same AVLTree constructor, potentially with different generic types.
|
|
338
|
+
* @remarks Time O(N log N) (from constructor) due to processing the iterable.
|
|
306
339
|
*
|
|
307
|
-
*
|
|
308
|
-
*
|
|
309
|
-
* @param
|
|
310
|
-
*
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
340
|
+
* @template TK, TV, TR - Generic types for the new instance.
|
|
341
|
+
* @param [iter=[]] - An iterable to populate the new tree.
|
|
342
|
+
* @param [options] - Options for the new tree.
|
|
343
|
+
* @returns A new AVLTree.
|
|
344
|
+
*/
|
|
345
|
+
protected override _createLike<TK = K, TV = V, TR = R>(
|
|
346
|
+
iter: Iterable<TK | BSTNode<TK, TV> | [TK | null | undefined, TV | undefined] | null | undefined | TR> = [],
|
|
347
|
+
options?: Partial<BSTOptions<TK, TV, TR>>
|
|
348
|
+
): AVLTree<TK, TV, TR> {
|
|
349
|
+
const Ctor = this.constructor as unknown as new (
|
|
350
|
+
iter?: Iterable<TK | BSTNode<TK, TV> | [TK | null | undefined, TV | undefined] | null | undefined | TR>,
|
|
351
|
+
opts?: BSTOptions<TK, TV, TR>
|
|
352
|
+
) => AVLTree<TK, TV, TR>;
|
|
353
|
+
return new Ctor(iter, { ...this._snapshotOptions<TK, TV, TR>(), ...(options ?? {}) });
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* (Protected) Swaps properties of two nodes, including height.
|
|
358
|
+
* @remarks Time O(H) (due to `ensureNode`), but O(1) if nodes are passed directly.
|
|
359
|
+
*
|
|
360
|
+
* @param srcNode - The source node.
|
|
361
|
+
* @param destNode - The destination node.
|
|
362
|
+
* @returns The `destNode` (now holding `srcNode`'s properties).
|
|
315
363
|
*/
|
|
316
364
|
protected override _swapProperties(
|
|
317
365
|
srcNode: BSTNOptKeyOrNode<K, AVLTreeNode<K, V>>,
|
|
@@ -322,15 +370,17 @@ export class AVLTree<K = any, V = any, R = object, MK = any, MV = any, MR = obje
|
|
|
322
370
|
|
|
323
371
|
if (srcNodeEnsured && destNodeEnsured) {
|
|
324
372
|
const { key, value, height } = destNodeEnsured;
|
|
325
|
-
const tempNode = this.
|
|
373
|
+
const tempNode = this._createNode(key, value);
|
|
326
374
|
|
|
327
375
|
if (tempNode) {
|
|
328
376
|
tempNode.height = height;
|
|
329
377
|
|
|
378
|
+
// Copy src to dest
|
|
330
379
|
destNodeEnsured.key = srcNodeEnsured.key;
|
|
331
380
|
if (!this._isMapMode) destNodeEnsured.value = srcNodeEnsured.value;
|
|
332
381
|
destNodeEnsured.height = srcNodeEnsured.height;
|
|
333
382
|
|
|
383
|
+
// Copy temp (original dest) to src
|
|
334
384
|
srcNodeEnsured.key = tempNode.key;
|
|
335
385
|
if (!this._isMapMode) srcNodeEnsured.value = tempNode.value;
|
|
336
386
|
srcNodeEnsured.height = tempNode.height;
|
|
@@ -342,57 +392,46 @@ export class AVLTree<K = any, V = any, R = object, MK = any, MV = any, MR = obje
|
|
|
342
392
|
}
|
|
343
393
|
|
|
344
394
|
/**
|
|
345
|
-
*
|
|
346
|
-
*
|
|
395
|
+
* (Protected) Calculates the balance factor (height(right) - height(left)).
|
|
396
|
+
* @remarks Time O(1) (assumes heights are stored).
|
|
347
397
|
*
|
|
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.
|
|
398
|
+
* @param node - The node to check.
|
|
399
|
+
* @returns The balance factor (positive if right-heavy, negative if left-heavy).
|
|
353
400
|
*/
|
|
354
401
|
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;
|
|
402
|
+
const left = node.left ? (node.left as AVLTreeNode<K, V>).height : -1;
|
|
403
|
+
const right = node.right ? (node.right as AVLTreeNode<K, V>).height : -1;
|
|
404
|
+
return right - left;
|
|
362
405
|
}
|
|
363
406
|
|
|
364
407
|
/**
|
|
365
|
-
*
|
|
366
|
-
*
|
|
408
|
+
* (Protected) Recalculates and updates the height of a node based on its children's heights.
|
|
409
|
+
* @remarks Time O(1) (assumes children's heights are correct).
|
|
367
410
|
*
|
|
368
|
-
*
|
|
369
|
-
* right children.
|
|
370
|
-
* @param {AVLTreeNode<K, V>} node - The parameter "node" represents a node in a binary tree data structure.
|
|
411
|
+
* @param node - The node to update.
|
|
371
412
|
*/
|
|
372
413
|
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);
|
|
414
|
+
const leftHeight = node.left ? (node.left as AVLTreeNode<K, V>).height : -1;
|
|
415
|
+
const rightHeight = node.right ? (node.right as AVLTreeNode<K, V>).height : -1;
|
|
416
|
+
node.height = 1 + Math.max(leftHeight, rightHeight);
|
|
379
417
|
}
|
|
380
418
|
|
|
381
419
|
/**
|
|
382
|
-
*
|
|
383
|
-
*
|
|
420
|
+
* (Protected) Performs a Left-Left (LL) rotation (a single right rotation).
|
|
421
|
+
* @remarks Time O(1), Space O(1)
|
|
384
422
|
*
|
|
385
|
-
*
|
|
386
|
-
* @param {AVLTreeNode<K, V>} A - A is a node in a binary tree.
|
|
423
|
+
* @param A - The unbalanced node (root of the unbalanced subtree).
|
|
387
424
|
*/
|
|
388
425
|
protected _balanceLL(A: AVLTreeNode<K, V>): void {
|
|
389
426
|
const parentOfA = A.parent;
|
|
390
|
-
const B = A.left;
|
|
427
|
+
const B = A.left; // The left child
|
|
391
428
|
if (B !== null) A.parent = B;
|
|
392
429
|
if (B && B.right) {
|
|
393
430
|
B.right.parent = A;
|
|
394
431
|
}
|
|
395
432
|
if (B) B.parent = parentOfA;
|
|
433
|
+
|
|
434
|
+
// Update parent's child pointer
|
|
396
435
|
if (A === this.root) {
|
|
397
436
|
if (B) this._setRoot(B);
|
|
398
437
|
} else {
|
|
@@ -403,6 +442,7 @@ export class AVLTree<K = any, V = any, R = object, MK = any, MV = any, MR = obje
|
|
|
403
442
|
}
|
|
404
443
|
}
|
|
405
444
|
|
|
445
|
+
// Perform rotation
|
|
406
446
|
if (B) {
|
|
407
447
|
A.left = B.right;
|
|
408
448
|
B.right = A;
|
|
@@ -412,18 +452,17 @@ export class AVLTree<K = any, V = any, R = object, MK = any, MV = any, MR = obje
|
|
|
412
452
|
}
|
|
413
453
|
|
|
414
454
|
/**
|
|
415
|
-
*
|
|
416
|
-
*
|
|
455
|
+
* (Protected) Performs a Left-Right (LR) double rotation.
|
|
456
|
+
* @remarks Time O(1), Space O(1)
|
|
417
457
|
*
|
|
418
|
-
*
|
|
419
|
-
* @param {AVLTreeNode<K, V>} A - A is a node in a binary tree.
|
|
458
|
+
* @param A - The unbalanced node (root of the unbalanced subtree).
|
|
420
459
|
*/
|
|
421
460
|
protected _balanceLR(A: AVLTreeNode<K, V>): void {
|
|
422
461
|
const parentOfA = A.parent;
|
|
423
462
|
const B = A.left;
|
|
424
463
|
let C = undefined;
|
|
425
464
|
if (B) {
|
|
426
|
-
C = B.right;
|
|
465
|
+
C = B.right; // The "middle" node
|
|
427
466
|
}
|
|
428
467
|
if (A && C !== null) A.parent = C;
|
|
429
468
|
if (B && C !== null) B.parent = C;
|
|
@@ -438,6 +477,7 @@ export class AVLTree<K = any, V = any, R = object, MK = any, MV = any, MR = obje
|
|
|
438
477
|
C.parent = parentOfA;
|
|
439
478
|
}
|
|
440
479
|
|
|
480
|
+
// Update parent's child pointer
|
|
441
481
|
if (A === this.root) {
|
|
442
482
|
if (C) this._setRoot(C);
|
|
443
483
|
} else {
|
|
@@ -450,6 +490,7 @@ export class AVLTree<K = any, V = any, R = object, MK = any, MV = any, MR = obje
|
|
|
450
490
|
}
|
|
451
491
|
}
|
|
452
492
|
|
|
493
|
+
// Perform rotation
|
|
453
494
|
if (C) {
|
|
454
495
|
A.left = C.right;
|
|
455
496
|
if (B) B.right = C.left;
|
|
@@ -463,15 +504,14 @@ export class AVLTree<K = any, V = any, R = object, MK = any, MV = any, MR = obje
|
|
|
463
504
|
}
|
|
464
505
|
|
|
465
506
|
/**
|
|
466
|
-
*
|
|
467
|
-
*
|
|
507
|
+
* (Protected) Performs a Right-Right (RR) rotation (a single left rotation).
|
|
508
|
+
* @remarks Time O(1), Space O(1)
|
|
468
509
|
*
|
|
469
|
-
*
|
|
470
|
-
* @param {AVLTreeNode<K, V>} A - A is a node in a binary tree.
|
|
510
|
+
* @param A - The unbalanced node (root of the unbalanced subtree).
|
|
471
511
|
*/
|
|
472
512
|
protected _balanceRR(A: AVLTreeNode<K, V>): void {
|
|
473
513
|
const parentOfA = A.parent;
|
|
474
|
-
const B = A.right;
|
|
514
|
+
const B = A.right; // The right child
|
|
475
515
|
if (B !== null) A.parent = B;
|
|
476
516
|
if (B) {
|
|
477
517
|
if (B.left) {
|
|
@@ -480,6 +520,7 @@ export class AVLTree<K = any, V = any, R = object, MK = any, MV = any, MR = obje
|
|
|
480
520
|
B.parent = parentOfA;
|
|
481
521
|
}
|
|
482
522
|
|
|
523
|
+
// Update parent's child pointer
|
|
483
524
|
if (A === this.root) {
|
|
484
525
|
if (B) this._setRoot(B);
|
|
485
526
|
} else {
|
|
@@ -492,6 +533,7 @@ export class AVLTree<K = any, V = any, R = object, MK = any, MV = any, MR = obje
|
|
|
492
533
|
}
|
|
493
534
|
}
|
|
494
535
|
|
|
536
|
+
// Perform rotation
|
|
495
537
|
if (B) {
|
|
496
538
|
A.right = B.left;
|
|
497
539
|
B.left = A;
|
|
@@ -501,18 +543,17 @@ export class AVLTree<K = any, V = any, R = object, MK = any, MV = any, MR = obje
|
|
|
501
543
|
}
|
|
502
544
|
|
|
503
545
|
/**
|
|
504
|
-
*
|
|
505
|
-
*
|
|
546
|
+
* (Protected) Performs a Right-Left (RL) double rotation.
|
|
547
|
+
* @remarks Time O(1), Space O(1)
|
|
506
548
|
*
|
|
507
|
-
*
|
|
508
|
-
* @param {AVLTreeNode<K, V>} A - A is a node in a binary tree.
|
|
549
|
+
* @param A - The unbalanced node (root of the unbalanced subtree).
|
|
509
550
|
*/
|
|
510
551
|
protected _balanceRL(A: AVLTreeNode<K, V>): void {
|
|
511
552
|
const parentOfA = A.parent;
|
|
512
553
|
const B = A.right;
|
|
513
554
|
let C = undefined;
|
|
514
555
|
if (B) {
|
|
515
|
-
C = B.left;
|
|
556
|
+
C = B.left; // The "middle" node
|
|
516
557
|
}
|
|
517
558
|
|
|
518
559
|
if (C !== null) A.parent = C;
|
|
@@ -528,6 +569,7 @@ export class AVLTree<K = any, V = any, R = object, MK = any, MV = any, MR = obje
|
|
|
528
569
|
C.parent = parentOfA;
|
|
529
570
|
}
|
|
530
571
|
|
|
572
|
+
// Update parent's child pointer
|
|
531
573
|
if (A === this.root) {
|
|
532
574
|
if (C) this._setRoot(C);
|
|
533
575
|
} else {
|
|
@@ -540,6 +582,7 @@ export class AVLTree<K = any, V = any, R = object, MK = any, MV = any, MR = obje
|
|
|
540
582
|
}
|
|
541
583
|
}
|
|
542
584
|
|
|
585
|
+
// Perform rotation
|
|
543
586
|
if (C) A.right = C.left;
|
|
544
587
|
if (B && C) B.left = C.right;
|
|
545
588
|
if (C) C.left = A;
|
|
@@ -551,73 +594,61 @@ export class AVLTree<K = any, V = any, R = object, MK = any, MV = any, MR = obje
|
|
|
551
594
|
}
|
|
552
595
|
|
|
553
596
|
/**
|
|
554
|
-
*
|
|
555
|
-
*
|
|
597
|
+
* (Protected) Traverses up the tree from the specified node, updating heights and performing rotations as needed.
|
|
598
|
+
* @remarks Time O(log N) (O(H)), as it traverses the path to root. Space O(H) for the path array.
|
|
556
599
|
*
|
|
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 `.
|
|
600
|
+
* @param node - The node to start balancing from (e.g., the newly inserted node or parent of the deleted node).
|
|
562
601
|
*/
|
|
563
602
|
protected _balancePath(node: K | AVLTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined): void {
|
|
603
|
+
// Get the path from the node to the root.
|
|
564
604
|
node = this.ensureNode(node);
|
|
565
|
-
const path = this.getPathToRoot(node, node => node, false);
|
|
605
|
+
const path = this.getPathToRoot(node, node => node, false);
|
|
606
|
+
|
|
607
|
+
// Iterate up the path (from node to root)
|
|
566
608
|
for (let i = 0; i < path.length; i++) {
|
|
567
|
-
// second O(log n)
|
|
568
609
|
const A = path[i];
|
|
569
610
|
if (A) {
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
// Check
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
this._balanceFactor(A) // second O(1)
|
|
576
|
-
) {
|
|
577
|
-
case -2:
|
|
611
|
+
this._updateHeight(A);
|
|
612
|
+
|
|
613
|
+
// Check the balance factor
|
|
614
|
+
switch (this._balanceFactor(A)) {
|
|
615
|
+
case -2: // Left-heavy
|
|
578
616
|
if (A && A.left) {
|
|
579
617
|
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.
|
|
618
|
+
// Left-Left case
|
|
582
619
|
this._balanceLL(A);
|
|
583
620
|
} else {
|
|
584
|
-
// Left-Right
|
|
621
|
+
// Left-Right case
|
|
585
622
|
this._balanceLR(A);
|
|
586
623
|
}
|
|
587
624
|
}
|
|
588
625
|
break;
|
|
589
|
-
case +2:
|
|
626
|
+
case +2: // Right-heavy
|
|
590
627
|
if (A && A.right) {
|
|
591
628
|
if (this._balanceFactor(A.right) >= 0) {
|
|
592
|
-
// Right
|
|
629
|
+
// Right-Right case
|
|
593
630
|
this._balanceRR(A);
|
|
594
631
|
} else {
|
|
595
|
-
// Right-Left
|
|
632
|
+
// Right-Left case
|
|
596
633
|
this._balanceRL(A);
|
|
597
634
|
}
|
|
598
635
|
}
|
|
599
636
|
}
|
|
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
637
|
}
|
|
602
638
|
}
|
|
603
639
|
}
|
|
604
640
|
|
|
605
641
|
/**
|
|
606
|
-
*
|
|
607
|
-
*
|
|
642
|
+
* (Protected) Replaces a node, ensuring height is copied.
|
|
643
|
+
* @remarks Time O(1)
|
|
608
644
|
*
|
|
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.
|
|
645
|
+
* @param oldNode - The node to be replaced.
|
|
646
|
+
* @param newNode - The node to insert.
|
|
647
|
+
* @returns The `newNode`.
|
|
617
648
|
*/
|
|
618
649
|
protected override _replaceNode(oldNode: AVLTreeNode<K, V>, newNode: AVLTreeNode<K, V>): AVLTreeNode<K, V> {
|
|
650
|
+
// When replacing a node (e.g., on duplicate key), preserve the height.
|
|
619
651
|
newNode.height = oldNode.height;
|
|
620
|
-
|
|
621
652
|
return super._replaceNode(oldNode, newNode);
|
|
622
653
|
}
|
|
623
654
|
}
|