refactor: Add an isNotNodeInstance method to every binary tree data structure to prevent node type errors. The getSuccessor method of Red-Black trees uniformly utilizes the getSuccessor method from BinaryTree.

This commit is contained in:
Revone 2023-12-11 09:02:26 +08:00
parent 26208e9157
commit 1fc47918d2
5 changed files with 80 additions and 59 deletions

View file

@ -14,7 +14,7 @@ import type {
BSTNodeKeyOrNode,
BTNodeExemplar
} from '../../types';
import { BTNCallback } from '../../types';
import { BTNCallback, BTNodeKeyOrNode } from '../../types';
import { IBinaryTree } from '../../interfaces';
export class AVLTreeNode<K = any, V = any, N extends AVLTreeNode<K, V, N> = AVLTreeNodeNested<K, V>> extends BSTNode<K, V, N> {
@ -90,6 +90,16 @@ export class AVLTree<K = any, V = any, N extends AVLTreeNode<K, V, N> = AVLTreeN
return exemplar instanceof AVLTreeNode;
}
/**
* The function "isNotNodeInstance" checks if a potential key is a K.
* @param {any} potentialKey - The potentialKey parameter is of type any, which means it can be any
* data type.
* @returns a boolean value indicating whether the potentialKey is of type number or not.
*/
override isNotNodeInstance(potentialKey: BTNodeKeyOrNode<K, N>): potentialKey is K {
return !(potentialKey instanceof AVLTreeNode)
}
/**
* Time Complexity: O(log n) - logarithmic time, where "n" is the number of nodes in the tree. The add method of the superclass (BST) has logarithmic time complexity.
* Space Complexity: O(1) - constant space, as it doesn't use additional data structures that scale with input size.

View file

@ -1236,8 +1236,8 @@ export class BinaryTree<K = any, V = any, N extends BinaryTreeNode<K, V, N> = Bi
* @param {any} node - The parameter `node` is of type `any`, which means it can be any data type.
* @returns a boolean value.
*/
isRealNode(node: any): node is N {
return node instanceof BinaryTreeNode && node.key.toString() !== 'NaN';
isRealNode(node: BTNodeExemplar<K, V, N>): node is N {
return node instanceof BinaryTreeNode && String(node.key) !== 'NaN';
}
/**
@ -1245,8 +1245,8 @@ export class BinaryTree<K = any, V = any, N extends BinaryTreeNode<K, V, N> = Bi
* @param {any} node - The parameter `node` is of type `any`, which means it can be any data type.
* @returns a boolean value.
*/
isNIL(node: any) {
return node instanceof BinaryTreeNode && node.key.toString() === 'NaN';
isNIL(node: BTNodeExemplar<K, V, N>) {
return node instanceof BinaryTreeNode && String(node.key) === 'NaN';
}
/**
@ -1254,12 +1254,12 @@ export class BinaryTree<K = any, V = any, N extends BinaryTreeNode<K, V, N> = Bi
* @param {any} node - The parameter `node` is of type `any`, which means it can be any data type.
* @returns a boolean value.
*/
isNodeOrNull(node: any): node is N | null {
isNodeOrNull(node: BTNodeExemplar<K, V, N>): node is N | null {
return this.isRealNode(node) || node === null;
}
/**
* The function "isNotNodeInstance" checks if a potential key is a number.
* The function "isNotNodeInstance" checks if a potential key is a K.
* @param {any} potentialKey - The potentialKey parameter is of type any, which means it can be any
* data type.
* @returns a boolean value indicating whether the potentialKey is of type number or not.
@ -1606,26 +1606,24 @@ export class BinaryTree<K = any, V = any, N extends BinaryTreeNode<K, V, N> = Bi
}
/**
* Time complexity: O(n)
* Space complexity: O(n)
* Time Complexity: O(log n)
* Space Complexity: O(1)
*/
getPredecessor(node: N): N;
/**
* The function `getPredecessor` returns the predecessor node of a given node in a binary tree.
* @param {K | N | null | undefined} node - The `node` parameter can be of type `K`, `N`,
* `null`, or `undefined`.
* @returns The function `getPredecessor` returns a value of type `N | undefined`.
* Time Complexity: O(log n)
* Space Complexity: O(1)
*
* The function returns the predecessor of a given node in a tree.
* @param {N} node - The parameter `node` is of type `RedBlackTreeNode`, which represents a node in a
* tree.
* @returns the predecessor of the given 'node'.
*/
getPredecessor(node: BTNodeKeyOrNode<K, N>): N | undefined {
node = this.ensureNode(node);
if (!this.isRealNode(node)) return undefined;
if (node.left) {
getPredecessor(node: N): N {
if (this.isRealNode(node.left)) {
let predecessor: N | null | undefined = node.left;
while (!this.isRealNode(predecessor) || (this.isRealNode(predecessor.right) && predecessor.right !== node)) {
if (predecessor) {
if (this.isRealNode(predecessor)) {
predecessor = predecessor.right;
}
}
@ -1642,15 +1640,16 @@ export class BinaryTree<K = any, V = any, N extends BinaryTreeNode<K, V, N> = Bi
* after the given node in the inorder traversal of the binary tree.
*/
getSuccessor(x?: K | N | null): N | null | undefined {
x = this.ensureNode(x);
if (!x) return undefined;
if (x.right) {
x = this.ensureNode(x);
if (!this.isRealNode(x)) return undefined;
if (this.isRealNode(x.right)) {
return this.getLeftMost(x.right);
}
let y: N | null | undefined = x.parent;
while (y && y && x === y.right) {
while (this.isRealNode(y) && x === y.right) {
x = y;
y = y.parent;
}

View file

@ -14,7 +14,7 @@ import type {
BTNodeExemplar,
BTNodePureExemplar
} from '../../types';
import { BSTVariant, CP, IterationType } from '../../types';
import { BSTVariant, BTNodeKeyOrNode, CP, IterationType } from '../../types';
import { BinaryTree, BinaryTreeNode } from './binary-tree';
import { IBinaryTree } from '../../interfaces';
import { Queue } from '../queue';
@ -442,6 +442,16 @@ export class BST<K = any, V = any, N extends BSTNode<K, V, N> = BSTNode<K, V, BS
}
}
/**
* The function "isNotNodeInstance" checks if a potential key is a K.
* @param {any} potentialKey - The potentialKey parameter is of type any, which means it can be any
* data type.
* @returns a boolean value indicating whether the potentialKey is of type number or not.
*/
override isNotNodeInstance(potentialKey: BTNodeKeyOrNode<K, N>): potentialKey is K {
return !(potentialKey instanceof BSTNode)
}
/**
* Time Complexity: O(log n) - Average case for a balanced tree.
* Space Complexity: O(log n) - Space for the recursive call stack in the worst case.

View file

@ -11,6 +11,7 @@ import {
BSTNodeKeyOrNode,
BTNCallback,
BTNodeExemplar,
BTNodeKeyOrNode,
IterationType,
RBTNColor,
RBTreeOptions,
@ -115,6 +116,16 @@ export class RedBlackTree<K = any, V = any, N extends RedBlackTreeNode<K, V, N>
return exemplar instanceof RedBlackTreeNode;
}
/**
* The function "isNotNodeInstance" checks if a potential key is a K.
* @param {any} potentialKey - The potentialKey parameter is of type any, which means it can be any
* data type.
* @returns a boolean value indicating whether the potentialKey is of type number or not.
*/
override isNotNodeInstance(potentialKey: BTNodeKeyOrNode<K, N>): potentialKey is K {
return !(potentialKey instanceof RedBlackTreeNode)
}
/**
* The function `exemplarToNode` takes an exemplar and converts it into a node object if possible.
* @param exemplar - The `exemplar` parameter is of type `BTNodeExemplar<K, V, N>`, where:
@ -300,7 +311,8 @@ export class RedBlackTree<K = any, V = any, N extends RedBlackTreeNode<K, V, N>
*/
override isRealNode(node: N | undefined): node is N {
return node !== this.Sentinel && node !== undefined;
if (node === this.Sentinel || node === undefined) return false;
return node instanceof RedBlackTreeNode;
}
getNode<C extends BTNCallback<N, K>>(
@ -362,38 +374,12 @@ export class RedBlackTree<K = any, V = any, N extends RedBlackTreeNode<K, V, N>
}
/**
* Time Complexity: O(log n) on average (where n is the number of nodes in the tree)
* Time Complexity: O(log n)
* Space Complexity: O(1)
*/
/**
* Time Complexity: O(log n) on average (where n is the number of nodes in the tree)
* Space Complexity: O(1)
*
* The function returns the successor of a given node in a red-black tree.
* @param {RedBlackTreeNode} x - RedBlackTreeNode - The node for which we want to find the successor.
* @returns the successor of the given RedBlackTreeNode.
*/
override getSuccessor(x: N): N | undefined {
if (x.right !== this.Sentinel) {
return this.getLeftMost(x.right) ?? undefined;
}
let y: N | undefined = x.parent;
while (y !== this.Sentinel && y !== undefined && x === y.right) {
x = y;
y = y.parent;
}
return y;
}
/**
* Time Complexity: O(log n) on average (where n is the number of nodes in the tree)
* Space Complexity: O(1)
*/
/**
* Time Complexity: O(log n) on average (where n is the number of nodes in the tree)
* Time Complexity: O(log n)
* Space Complexity: O(1)
*
* The function returns the predecessor of a given node in a red-black tree.
@ -402,12 +388,12 @@ export class RedBlackTree<K = any, V = any, N extends RedBlackTreeNode<K, V, N>
* @returns the predecessor of the given RedBlackTreeNode 'x'.
*/
override getPredecessor(x: N): N {
if (x.left !== this.Sentinel) {
return this.getRightMost(x.left!)!;
if (this.isRealNode(x.left)) {
return this.getRightMost(x.left)!;
}
let y: N | undefined = x.parent;
while (y !== this.Sentinel && x === y!.left) {
while (this.isRealNode(y) && x === y.left) {
x = y!;
y = y!.parent;
}

View file

@ -6,7 +6,14 @@
* @license MIT License
*/
import type { BSTNodeKeyOrNode, BTNodeExemplar, TreeMultimapNodeNested, TreeMultimapOptions } from '../../types';
import { BiTreeDeleteResult, BTNCallback, FamilyPosition, IterationType, TreeMultimapNested } from '../../types';
import {
BiTreeDeleteResult,
BTNCallback,
BTNodeKeyOrNode,
FamilyPosition,
IterationType,
TreeMultimapNested
} from '../../types';
import { IBinaryTree } from '../../interfaces';
import { AVLTree, AVLTreeNode } from './avl-tree';
@ -85,6 +92,15 @@ export class TreeMultimap<K = any, V = any, N extends TreeMultimapNode<K, V, N>
return exemplar instanceof TreeMultimapNode;
}
/**
* The function "isNotNodeInstance" checks if a potential key is a K.
* @param {any} potentialKey - The potentialKey parameter is of type any, which means it can be any
* data type.
* @returns a boolean value indicating whether the potentialKey is of type number or not.
*/
override isNotNodeInstance(potentialKey: BTNodeKeyOrNode<K, N>): potentialKey is K {
return !(potentialKey instanceof TreeMultimapNode)
}
/**
* The function `exemplarToNode` converts an exemplar object into a node object.