Swap the positions of val and id to enhance the intuitiveness of the API. Revise the design of familyPosition in AbstractBinaryTree such that the previous assignment approach is replaced with a real-time retrieval method. Standardize the BST.remove method with the AbstractBinaryTree.remove method. Eliminate the redundant attribute name from TreeNode.

This commit is contained in:
Revone 2023-08-26 10:24:31 +08:00
parent 8db8976503
commit d29ff07f40
20 changed files with 345 additions and 326 deletions

View file

@ -2,6 +2,5 @@
<project version="4">
<component name="TypeScriptCompiler">
<option name="nodeInterpreterTextField" value="$USER_HOME$/.nvm/versions/node/v19.9.0/bin/node" />
<option name="versionType" value="EMBEDDED" />
</component>
</project>

View file

@ -1,4 +1,7 @@
/.idea
/src
/tests
/tests
/notes
/docs
/backup

14
package-lock.json generated
View file

@ -1,12 +1,12 @@
{
"name": "data-structure-typed",
"version": "1.18.6",
"version": "1.18.7",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "data-structure-typed",
"version": "1.18.6",
"version": "1.18.7",
"license": "MIT",
"devDependencies": {
"@types/jest": "^29.5.3",
@ -15,7 +15,7 @@
"jest": "^29.6.2",
"ts-jest": "^29.1.1",
"typedoc": "^0.24.8",
"typescript": "^5.1.5"
"typescript": "^4.9.5"
}
},
"node_modules/@ampproject/remapping": {
@ -5409,16 +5409,16 @@
}
},
"node_modules/typescript": {
"version": "5.1.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.5.tgz",
"integrity": "sha512-FOH+WN/DQjUvN6WgW+c4Ml3yi0PH+a/8q+kNIfRehv1wLhWONedw85iu+vQ39Wp49IzTJEsZ2lyLXpBF7mkF1g==",
"version": "4.9.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
"dev": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=14.17"
"node": ">=4.2.0"
}
},
"node_modules/update-browserslist-db": {

View file

@ -62,6 +62,6 @@
"jest": "^29.6.2",
"ts-jest": "^29.1.1",
"typedoc": "^0.24.8",
"typescript": "^5.1.5"
"typescript": "^4.9.5"
}
}

View file

@ -6,16 +6,15 @@
* @license MIT License
*/
import {trampoline} from '../../utils';
import {ObjectWithNumberId, trampoline} from '../../utils';
import type {
AbstractBinaryTreeNodeNested,
AbstractBinaryTreeNodeProperties,
AbstractBinaryTreeNodeProperty,
AbstractBinaryTreeNodeNested,
BinaryTreeDeletedResult,
BinaryTreeNodeId,
BinaryTreeNodePropertyName,
DFSOrderPattern,
KeyValObject,
NodeOrPropertyName
} from '../types';
import {AbstractBinaryTreeOptions, FamilyPosition, LoopType} from '../types';
@ -32,7 +31,7 @@ export abstract class AbstractBinaryTreeNode<T = any, FAMILY extends AbstractBin
* @param {number} [count] - The `count` parameter is an optional parameter that represents the number of times the
* value `val` appears in the binary tree node. If the `count` parameter is not provided, it defaults to 1.
*/
constructor(id: BinaryTreeNodeId, val?: T, count?: number) {
constructor(val: T, id: BinaryTreeNodeId, count?: number) {
this._id = id;
this._val = val;
this._count = count ?? 1;
@ -48,13 +47,13 @@ export abstract class AbstractBinaryTreeNode<T = any, FAMILY extends AbstractBin
this._id = v;
}
private _val: T | undefined;
private _val: T;
get val(): T | undefined {
return this._val as T;
get val(): T {
return this._val;
}
set val(value: T | undefined) {
set val(value: T) {
this._val = value;
}
@ -67,11 +66,11 @@ export abstract class AbstractBinaryTreeNode<T = any, FAMILY extends AbstractBin
set left(v: FAMILY | null | undefined) {
if (v) {
v.parent = this as unknown as FAMILY;
v.familyPosition = FamilyPosition.LEFT;
}
this._left = v;
}
private _right?: FAMILY | null;
get right(): FAMILY | null | undefined {
@ -81,7 +80,6 @@ export abstract class AbstractBinaryTreeNode<T = any, FAMILY extends AbstractBin
set right(v: FAMILY | null | undefined) {
if (v) {
v.parent = this as unknown as FAMILY;
v.familyPosition = FamilyPosition.RIGHT;
}
this._right = v;
}
@ -96,16 +94,6 @@ export abstract class AbstractBinaryTreeNode<T = any, FAMILY extends AbstractBin
this._parent = v;
}
private _familyPosition: FamilyPosition = FamilyPosition.ROOT;
get familyPosition(): FamilyPosition {
return this._familyPosition;
}
set familyPosition(v: FamilyPosition) {
this._familyPosition = v;
}
private _count = 1;
get count(): number {
@ -126,32 +114,60 @@ export abstract class AbstractBinaryTreeNode<T = any, FAMILY extends AbstractBin
this._height = v;
}
abstract createNode(id: BinaryTreeNodeId, val?: T, count?: number): FAMILY
get familyPosition(): FamilyPosition {
const that = this as unknown as FAMILY;
if (that.parent) {
if (that.parent.left === that) {
if (that.left || that.right) {
return FamilyPosition.ROOT_LEFT;
} else {
return FamilyPosition.LEFT;
}
} else if (that.parent.right === that) {
if (that.left || that.right) {
return FamilyPosition.ROOT_RIGHT;
} else {
return FamilyPosition.RIGHT;
}
} else {
return FamilyPosition.MAL_NODE;
}
} else {
if (that.left || that.right) {
return FamilyPosition.ROOT;
} else {
return FamilyPosition.ISOLATED;
}
}
}
abstract createNode(val: T, id: BinaryTreeNodeId, count?: number): FAMILY
/**
* The function swaps the location of two nodes in a binary tree.
* @param {FAMILY} swapNode - The `swapNode` parameter is of type `FAMILY`, which represents a node in a family tree.
* @param {FAMILY} destNode - The `swapNode` parameter is of type `FAMILY`, which represents a node in a family tree.
* @returns the `swapNode` object after swapping its properties with the properties of `this` object.
*/
swapLocation(swapNode: FAMILY): FAMILY {
const {val, count, height} = swapNode;
const tempNode = this.createNode(swapNode.id, val);
if (tempNode instanceof AbstractBinaryTreeNode) {
tempNode.val = val;
tempNode.count = count;
tempNode.height = height;
swapLocation(destNode: FAMILY): FAMILY {
const {val, count, height, id} = destNode;
const tempNode = this.createNode(val, id, count);
tempNode.height = height;
swapNode.id = this.id;
swapNode.val = this.val;
swapNode.count = this.count;
swapNode.height = this.height;
if (tempNode instanceof AbstractBinaryTreeNode) {
// TODO should we consider the left, right children?
destNode.id = this.id;
destNode.val = this.val;
destNode.count = this.count;
destNode.height = this.height;
this.id = tempNode.id;
this.val = tempNode.val;
this.count = tempNode.count;
this.height = tempNode.height;
}
return swapNode;
return destNode;
}
/**
@ -160,7 +176,7 @@ export abstract class AbstractBinaryTreeNode<T = any, FAMILY extends AbstractBin
* `count` values as the current instance.
*/
clone(): FAMILY | null {
return this.createNode(this.id, this.val, this.count);
return this.createNode(this.val, this.id, this.count);
}
}
@ -176,9 +192,9 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
const {
loopType = LoopType.ITERATIVE,
autoIncrementId = false,
isDuplicatedVal = false
isMergeDuplicatedVal = true
} = options;
this._isDuplicatedVal = isDuplicatedVal;
this._isMergeDuplicatedVal = isMergeDuplicatedVal;
this._autoIncrementId = autoIncrementId;
this._loopType = loopType;
}
@ -231,10 +247,10 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
return this._maxId;
}
private _isDuplicatedVal: boolean = false;
private _isMergeDuplicatedVal: boolean = true;
get isDuplicatedVal(): boolean {
return this._isDuplicatedVal;
get isMergeDuplicatedVal(): boolean {
return this._isMergeDuplicatedVal;
}
private _root: N | null = null;
@ -255,7 +271,7 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
return this._count;
}
abstract createNode(id: BinaryTreeNodeId, val: N['val'] | null, count?: number): N | null ;
abstract createNode(val: N['val'], id: BinaryTreeNodeId, count?: number): N | null ;
/**
* The clear function resets the state of an object by setting its properties to their initial values.
@ -286,7 +302,7 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
* @returns The function `add` returns a `N` object if a new node is inserted, or `null` if no new node
* is inserted, or `undefined` if the insertion fails.
*/
add(id: BinaryTreeNodeId, val?: N['val'], count?: number): N | null | undefined {
add(val: N['val'], id: BinaryTreeNodeId, count?: number): N | null | undefined {
count = count ?? 1;
const _bfs = (root: N, newNode: N | null): N | undefined | null => {
@ -304,7 +320,7 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
};
let inserted: N | null | undefined;
const needInsert = val !== null ? this.createNode(id, val ?? id, count) : null;
const needInsert = val !== null ? this.createNode(val, id, count) : null;
const existNode = val !== null ? this.get(id, 'id') : null;
if (this.root) {
if (existNode) {
@ -318,7 +334,7 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
inserted = _bfs(this.root, needInsert);
}
} else {
this._setRoot(val !== null ? this.createNode(id, val ?? id, count) : null);
this._setRoot(val !== null ? this.createNode(val, id, count) : null);
if (needInsert !== null) {
this._setSize(1);
this._setCount(count);
@ -342,7 +358,6 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
if (parent.left === undefined) {
if (newNode) {
newNode.parent = parent;
newNode.familyPosition = FamilyPosition.LEFT;
}
parent.left = newNode;
if (newNode !== null) {
@ -354,7 +369,6 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
} else if (parent.right === undefined) {
if (newNode) {
newNode.parent = parent;
newNode.familyPosition = FamilyPosition.RIGHT;
}
parent.right = newNode;
if (newNode !== null) {
@ -378,55 +392,58 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
* @returns The function `addMany` returns an array of `N`, `null`, or `undefined` values.
*/
addMany(data: N[] | Array<N['val']>): (N | null | undefined)[] {
// TODO not sure addMany not be run multi times
const inserted: (N | null | undefined)[] = [];
const map: Map<N | N['val'], number> = new Map();
if (!this._isDuplicatedVal) {
for (const i of data) map.set(i, (map.get(i) ?? 0) + 1);
if (this.isMergeDuplicatedVal) {
for (const nodeOrVal of data) map.set(nodeOrVal, (map.get(nodeOrVal) ?? 0) + 1);
}
for (const item of data) {
// TODO will this cause an issue?
const count = this._isDuplicatedVal ? 1 : map.get(item);
for (const nodeOrVal of data) {
if (item instanceof AbstractBinaryTreeNode) {
inserted.push(this.add(item.id, item.val, item.count));
} else if (typeof item === 'number') {
if (!this._autoIncrementId) {
if (!this._isDuplicatedVal) {
if (map.get(item) !== undefined) {
inserted.push(this.add(item, item, count));
map.delete(item);
}
} else {
inserted.push(this.add(item, item, 1));
}
}
} else if (item instanceof Object) {
if (!this._isDuplicatedVal) {
if (map.has(item)) {
let newId: number;
if (!this._autoIncrementId) {
if (Object.keys(item).includes('id')) {
newId = (item as KeyValObject).id;
} else {
console.warn('Object value must has an id property when the autoIncrementId is false');
break;
}
} else {
newId = this.maxId + 1;
this._setMaxId(newId);
}
inserted.push(this.add(newId, item, count));
map.delete(item);
}
} else {
inserted.push(this.add(++this._maxId, item, 1));
}
} else if (item === null) {
inserted.push(this.add(Number.MAX_SAFE_INTEGER, item, 0));
if (nodeOrVal instanceof AbstractBinaryTreeNode) {
inserted.push(this.add(nodeOrVal.val, nodeOrVal.id, nodeOrVal.count));
continue;
}
if (nodeOrVal === null) {
inserted.push(this.add(null, NaN, 0));
continue;
}
// TODO will this cause an issue?
const count = this.isMergeDuplicatedVal ? map.get(nodeOrVal) : 1;
let newId: BinaryTreeNodeId;
if (typeof nodeOrVal === 'number') {
newId = this.autoIncrementId ? this.maxId + 1 : nodeOrVal;
} else if (nodeOrVal instanceof Object) {
if (this.autoIncrementId) {
newId = this.maxId + 1;
} else {
if (Object.keys(nodeOrVal).includes('id')) {
newId = (nodeOrVal as ObjectWithNumberId).id;
} else {
console.warn(nodeOrVal, 'Object value must has an id property when the autoIncrementId is false');
continue;
}
}
} else {
console.warn(nodeOrVal, ` is not added`);
continue;
}
if (this.isMergeDuplicatedVal) {
if (map.has(nodeOrVal)) {
inserted.push(this.add(nodeOrVal, newId, count));
map.delete(nodeOrVal);
}
} else {
inserted.push(this.add(nodeOrVal, newId, 1));
}
this._setMaxId(newId);
}
return inserted;
}
@ -455,39 +472,49 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
* "needBalanced" property is always null.
*/
remove(id: BinaryTreeNodeId, ignoreCount?: boolean): BinaryTreeDeletedResult<N>[] {
const nodes = this.getNodes(id, 'id', true);
let node: N | null | undefined = nodes[0];
const bstDeletedResult: BinaryTreeDeletedResult<N>[] = [];
if (!this.root) return bstDeletedResult;
if (!node) node = undefined;
else if (node.count > 1 && !ignoreCount) {
node.count--;
const curr: N | null = this.get(id);
if (!curr) return bstDeletedResult;
const parent: N | null = curr?.parent ? curr.parent : null;
let needBalanced: N | null = null, orgCurrent = curr;
if (curr.count > 1 && !ignoreCount) {
curr.count--;
this._setCount(this.count - 1);
} else if (node instanceof AbstractBinaryTreeNode) {
const [subSize, subCount] = this.getSubTreeSizeAndCount(node);
switch (node.familyPosition) {
case 0:
this._setSize(this.size - subSize);
this._setCount(this.count - subCount);
node = undefined;
break;
case 1:
if (node.parent) {
this._setSize(this.size - subSize);
this._setCount(this.count - subCount);
node.parent.left = null;
} else {
if (!curr.left) {
if (!parent) {
if (curr.right !== undefined) this._setRoot(curr.right);
} else {
const {familyPosition: fp} = curr;
if (fp === FamilyPosition.LEFT || fp === FamilyPosition.ROOT_LEFT) {
parent.left = curr.right;
} else if (fp === FamilyPosition.RIGHT || fp === FamilyPosition.ROOT_RIGHT) {
parent.right = curr.right;
}
break;
case 2:
if (node.parent) {
this._setSize(this.size - subSize);
this._setCount(this.count - subCount);
node.parent.right = null;
needBalanced = parent;
}
} else {
const leftSubTreeRightMost = curr.left ? this.getRightMost(curr.left) : null;
if (leftSubTreeRightMost) {
const parentOfLeftSubTreeMax = leftSubTreeRightMost.parent;
orgCurrent = curr.swapLocation(leftSubTreeRightMost);
if (parentOfLeftSubTreeMax) {
if (parentOfLeftSubTreeMax.right === leftSubTreeRightMost) parentOfLeftSubTreeMax.right = leftSubTreeRightMost.left;
else parentOfLeftSubTreeMax.left = leftSubTreeRightMost.left;
needBalanced = parentOfLeftSubTreeMax;
}
break;
}
}
this._setSize(this.size - 1);
this._setCount(this.count - orgCurrent.count);
}
return [{deleted: node, needBalanced: null}];
bstDeletedResult.push({deleted: orgCurrent, needBalanced});
return bstDeletedResult;
}
/**
@ -776,7 +803,7 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
* @returns a boolean value.
*/
isBSTByRooted(node: N | null): boolean {
// TODO there is a bug
if (!node) return true;
if (this._loopType === LoopType.RECURSIVE) {
@ -1383,13 +1410,12 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
}
protected _setIsDuplicatedVal(value: boolean) {
this._isDuplicatedVal = value;
this._isMergeDuplicatedVal = value;
}
protected _setRoot(v: N | null) {
if (v) {
v.parent = null;
v.familyPosition = FamilyPosition.ROOT;
v.parent = undefined;
}
this._root = v;
}

View file

@ -6,12 +6,12 @@
* @license MIT License
*/
import {BST, BSTNode} from './bst';
import type {AVLTreeOptions, BinaryTreeDeletedResult, BinaryTreeNodeId, AVLTreeNodeNested} from '../types';
import type {AVLTreeNodeNested, AVLTreeOptions, BinaryTreeDeletedResult, BinaryTreeNodeId} from '../types';
import {IAVLTree, IAVLTreeNode} from '../interfaces';
export class AVLTreeNode<T = any, FAMILY extends AVLTreeNode<T, FAMILY> = AVLTreeNodeNested<T>> extends BSTNode<T, FAMILY> implements IAVLTreeNode<T, FAMILY> {
override createNode(id: BinaryTreeNodeId, val?: T, count?: number): FAMILY {
return new AVLTreeNode(id, (val === undefined ? id : val) as T, count) as FAMILY;
override createNode(val: T, id: BinaryTreeNodeId, count?: number): FAMILY {
return new AVLTreeNode(val, id, count) as FAMILY;
}
}
@ -20,8 +20,8 @@ export class AVLTree<N extends AVLTreeNode<N['val'], N> = AVLTreeNode> extends B
super(options);
}
override createNode(id: BinaryTreeNodeId, val?: N['val'], count?: number): N {
return new AVLTreeNode<N['val'], N>(id, (val === undefined ? id : val), count) as N;
override createNode(val: N['val'], id: BinaryTreeNodeId, count?: number): N {
return new AVLTreeNode<N['val'], N>(val, id, count) as N;
}
/**
@ -36,8 +36,8 @@ export class AVLTree<N extends AVLTreeNode<N['val'], N> = AVLTreeNode> extends B
* to `1`, indicating that the value should be inserted once.
* @returns The method is returning either an N object or null.
*/
override add(id: BinaryTreeNodeId, val: N['val'] | null, count?: number): N | null {
const inserted = super.add(id, val, count);
override add(val: N['val'], id: BinaryTreeNodeId, count?: number): N | null {
const inserted = super.add(val, id, count);
if (inserted) this.balancePath(inserted);
return inserted;
}

View file

@ -23,8 +23,8 @@ export class BinaryTreeNode<T = any, FAMILY extends BinaryTreeNode<T, FAMILY> =
* appears in the binary tree node.
* @returns a new instance of the BinaryTreeNode class, casted as the FAMILY type.
*/
createNode(id: BinaryTreeNodeId, val?: T, count?: number): FAMILY {
return new BinaryTreeNode<T, FAMILY>(id, (val === undefined ? id : val) as T, count) as FAMILY;
createNode(val: T, id: BinaryTreeNodeId, count?: number): FAMILY {
return new BinaryTreeNode<T, FAMILY>(val, id, count) as FAMILY;
}
}
@ -33,11 +33,11 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
/**
* The constructor function accepts an optional options object and sets the values of loopType, autoIncrementId, and
* isDuplicatedVal based on the provided options.
* isMergeDuplicatedVal based on the provided options.
* @param [options] - An optional object that can contain the following properties:
*/
constructor(options?: BinaryTreeOptions) {
super();
super(options);
}
@ -52,8 +52,8 @@ export class BinaryTree<N extends BinaryTreeNode<N['val'], N> = BinaryTreeNode>
* of occurrences of the value in the binary tree node. If not provided, the default value is `undefined`.
* @returns a BinaryTreeNode object if the value is not null, otherwise it returns null.
*/
createNode(id: BinaryTreeNodeId, val?: N['val'], count?: number): N {
return new BinaryTreeNode<N['val'], N>(id, val === undefined ? id : val, count) as N;
createNode(val: N['val'], id: BinaryTreeNodeId, count?: number): N {
return new BinaryTreeNode<N['val'], N>(val, id, count) as N;
}
}

View file

@ -6,7 +6,7 @@
* @license MIT License
*/
import type {BinaryTreeNodeId, BinaryTreeNodePropertyName, BSTComparator, BSTNodeNested} from '../types';
import {BinaryTreeDeletedResult, BSTOptions, CP, FamilyPosition, LoopType} from '../types';
import {BSTOptions, CP, LoopType} from '../types';
import {BinaryTree, BinaryTreeNode} from './binary-tree';
import {IBST, IBSTNode} from '../interfaces';
@ -21,8 +21,8 @@ export class BSTNode<T = any, FAMILY extends BSTNode<T, FAMILY> = BSTNodeNested<
* search tree node. It is an optional parameter, so it can be omitted when calling the `createNode` method.
* @returns The method is returning a new instance of the BSTNode class, casted as the FAMILY type.
*/
override createNode(id: BinaryTreeNodeId, val?: T, count?: number): FAMILY {
return new BSTNode<T, FAMILY>(id, (val === undefined ? id : val) as T, count) as FAMILY;
override createNode(val: T, id: BinaryTreeNodeId, count?: number): FAMILY {
return new BSTNode<T, FAMILY>(val, id, count) as FAMILY;
}
}
@ -51,8 +51,8 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
* of a particular value in the binary search tree node.
* @returns a new instance of the BSTNode class, casted as type N.
*/
override createNode(id: BinaryTreeNodeId, val?: N['val'], count?: number): N {
return new BSTNode<N['val'], N>(id, val === undefined ? id : val, count) as N;
override createNode(val: N['val'], id: BinaryTreeNodeId, count?: number): N {
return new BSTNode<N['val'], N>(val, id, count) as N;
}
/**
@ -67,9 +67,9 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
* inserted once.
* @returns The method `add` returns a `N` object or `null`.
*/
override add(id: BinaryTreeNodeId, val: N['val'] | null, count: number = 1): N | null {
override add(val: N['val'], id: BinaryTreeNodeId, count: number = 1): N | null {
let inserted: N | null = null;
const newNode = this.createNode(id, val, count);
const newNode = this.createNode(val, id, count);
if (this.root === null) {
this._setRoot(newNode);
this._setSize(this.size + 1);
@ -94,7 +94,6 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
if (cur.left === undefined) {
if (newNode) {
newNode.parent = cur;
newNode.familyPosition = FamilyPosition.LEFT;
}
//Add to the left of the current node
cur.left = newNode;
@ -111,7 +110,6 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
if (cur.right === undefined) {
if (newNode) {
newNode.parent = cur;
newNode.familyPosition = FamilyPosition.RIGHT;
}
//Add to the right of the current node
cur.right = newNode;
@ -160,64 +158,6 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
else return this.getRightMost()?.id ?? 0;
}
/**
* The `remove` function in this TypeScript code removes a node from a binary search tree and returns information about
* the deleted node and any nodes that need to be balanced.
* @param {BinaryTreeNodeId} id - The `id` parameter is the identifier of the binary tree node that needs to be removed
* from the binary search tree.
* @param {boolean} [ignoreCount] - A boolean flag indicating whether to ignore the count of the node being removed. If
* set to true, the count of the node will not be considered and the node will be removed regardless of its count. If
* set to false or not provided, the count of the node will be taken into account and the
* @returns an array of `BSTDeletedResult<N>` objects.
*/
override remove(id: BinaryTreeNodeId, ignoreCount?: boolean): BinaryTreeDeletedResult<N>[] {
const bstDeletedResult: BinaryTreeDeletedResult<N>[] = [];
if (!this.root) return bstDeletedResult;
const curr: N | null = this.get(id);
if (!curr) return bstDeletedResult;
const parent: N | null = curr?.parent ? curr.parent : null;
let needBalanced: N | null = null, orgCurrent = curr;
if (curr.count > 1 && !ignoreCount) {
curr.count--;
this._setCount(this.count - 1);
} else {
if (!curr.left) {
if (!parent) {
if (curr.right !== undefined) this._setRoot(curr.right);
} else {
switch (curr.familyPosition) {
case FamilyPosition.LEFT:
parent.left = curr.right;
break;
case FamilyPosition.RIGHT:
parent.right = curr.right;
break;
}
needBalanced = parent;
}
} else {
const leftSubTreeMax = curr.left ? this.getRightMost(curr.left) : null;
if (leftSubTreeMax) {
const parentOfLeftSubTreeMax = leftSubTreeMax.parent;
orgCurrent = curr.swapLocation(leftSubTreeMax);
if (parentOfLeftSubTreeMax) {
if (parentOfLeftSubTreeMax.right === leftSubTreeMax) parentOfLeftSubTreeMax.right = leftSubTreeMax.left;
else parentOfLeftSubTreeMax.left = leftSubTreeMax.left;
needBalanced = parentOfLeftSubTreeMax;
}
}
}
this._setSize(this.size - 1);
this._setCount(this.count - curr.count);
}
bstDeletedResult.push({deleted: orgCurrent, needBalanced});
return bstDeletedResult;
}
/**
* The function `getNodes` returns an array of binary search tree nodes that match a given property value, with the
* option to specify the property name and whether to return only one node.
@ -420,7 +360,7 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
if (l > r) return;
const m = l + Math.floor((r - l) / 2);
const midNode = sorted[m];
this.add(midNode.id, midNode.val, midNode.count);
this.add(midNode.val, midNode.id, midNode.count);
buildBalanceBST(l, m - 1);
buildBalanceBST(m + 1, r);
};
@ -436,7 +376,7 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
if (l <= r) {
const m = l + Math.floor((r - l) / 2);
const midNode = sorted[m];
this.add(midNode.id, midNode.val, midNode.count);
this.add(midNode.val, midNode.id, midNode.count);
stack.push([m + 1, r]);
stack.push([l, m - 1]);
}

View file

@ -1,11 +1,11 @@
import {BinaryTreeNodeId, RBColor, RBTreeOptions, RBTreeNodeNested} from '../types';
import {BinaryTreeNodeId, RBColor, RBTreeNodeNested, RBTreeOptions} from '../types';
import {IRBTree, IRBTreeNode} from '../interfaces/rb-tree';
import {BST, BSTNode} from './bst';
export class RBTreeNode<T = any, FAMILY extends RBTreeNode<T, FAMILY> =RBTreeNodeNested<T>> extends BSTNode<T, FAMILY> implements IRBTreeNode<T, FAMILY> {
constructor(id: number, val: T, count?: number) {
super(id, val, count);
export class RBTreeNode<T = any, FAMILY extends RBTreeNode<T, FAMILY> = RBTreeNodeNested<T>> extends BSTNode<T, FAMILY> implements IRBTreeNode<T, FAMILY> {
constructor(val: T, id: BinaryTreeNodeId, count?: number) {
super(val, id, count);
}
private _color: RBColor = RBColor.RED;
@ -28,8 +28,8 @@ export class RBTreeNode<T = any, FAMILY extends RBTreeNode<T, FAMILY> =RBTreeNod
* node.
* @returns The method is returning a new instance of the RBTreeNode class, casted as a FAMILY type.
*/
override createNode(id: BinaryTreeNodeId, val?: T | null, count?: number): FAMILY {
return new RBTreeNode(id, val, count) as FAMILY;
override createNode(val: T, id: BinaryTreeNodeId, count?: number): FAMILY {
return new RBTreeNode(val, id, count) as FAMILY;
}
// private override _parent: RBNode<T> | null;
@ -48,7 +48,6 @@ export class RBTreeNode<T = any, FAMILY extends RBTreeNode<T, FAMILY> =RBTreeNod
// override set left(v: RBNode<T> | null | undefined) {
// if (v) {
// v.parent = this;
// v.familyPosition = FamilyPosition.LEFT;
// }
// this._left = v;
// }
@ -62,7 +61,6 @@ export class RBTreeNode<T = any, FAMILY extends RBTreeNode<T, FAMILY> =RBTreeNod
// override set right(v: RBNode<T> | null | undefined) {
// if (v) {
// v.parent = this;
// v.familyPosition = FamilyPosition.RIGHT;
// }
// this._right = v;
// }
@ -73,8 +71,8 @@ export class RBTree<N extends RBTreeNode<N['val'], N> = RBTreeNode> extends BST<
super(options);
}
override createNode(id: BinaryTreeNodeId, val?: N['val'], count?: number): N {
return new RBTreeNode(id, val, count) as N;
override createNode(val: N['val'], id: BinaryTreeNodeId, count?: number): N {
return new RBTreeNode(val, id, count) as N;
}
// private override _root: BinaryTreeNode<N> | null = null;

View file

@ -20,8 +20,8 @@ export class TreeMultiSetNode<T = any, FAMILY extends TreeMultiSetNode<T, FAMILY
* node. It is an optional parameter, so it can be omitted when calling the `createNode` method.
* @returns The method is returning a new instance of the TreeMultiSetNode class, casted as the FAMILY type.
*/
override createNode(id: BinaryTreeNodeId, val?: T, count?: number): FAMILY {
return new TreeMultiSetNode(id, (val === undefined ? id : val) as T, count) as FAMILY;
override createNode(val: T, id: BinaryTreeNodeId, count?: number): FAMILY {
return new TreeMultiSetNode(val, id, count) as FAMILY;
}
}
@ -30,7 +30,7 @@ export class TreeMultiSetNode<T = any, FAMILY extends TreeMultiSetNode<T, FAMILY
*/
export class TreeMultiSet<N extends TreeMultiSetNode<N['val'], N> = TreeMultiSetNode> extends AVLTree<N> implements ITreeMultiSet<N> {
constructor(options?: TreeMultiSetOptions) {
super({...options, isDuplicatedVal: true});
super({...options, isMergeDuplicatedVal: true});
}
/**
@ -42,7 +42,7 @@ export class TreeMultiSet<N extends TreeMultiSetNode<N['val'], N> = TreeMultiSet
* occurrences of the value in the binary search tree node. If not provided, the count will default to 1.
* @returns A new instance of the BSTNode class with the specified id, value, and count (if provided).
*/
override createNode(id: BinaryTreeNodeId, val?: N['val'], count?: number): N {
return new TreeMultiSetNode(id, val === undefined ? id : val, count) as N;
override createNode(val: N['val'], id: BinaryTreeNodeId, count?: number): N {
return new TreeMultiSetNode(val, id, count) as N;
}
}

View file

@ -4,8 +4,7 @@ import {
BinaryTreeDeletedResult,
BinaryTreeNodeId,
BinaryTreeNodePropertyName,
DFSOrderPattern,
FamilyPosition,
DFSOrderPattern, FamilyPosition,
LoopType,
NodeOrPropertyName
} from '../types';
@ -13,7 +12,7 @@ import {AbstractBinaryTreeNode} from '../binary-tree';
export interface IAbstractBinaryTreeNode<T, FAMILY extends IAbstractBinaryTreeNode<T, FAMILY>> {
createNode(id: BinaryTreeNodeId, val?: T, count?: number): FAMILY;
createNode(val: T, id: BinaryTreeNodeId, count?: number): FAMILY;
get id(): BinaryTreeNodeId
@ -37,8 +36,6 @@ export interface IAbstractBinaryTreeNode<T, FAMILY extends IAbstractBinaryTreeNo
get familyPosition(): FamilyPosition
set familyPosition(v: FamilyPosition)
get count(): number
set count(v: number)
@ -53,7 +50,7 @@ export interface IAbstractBinaryTreeNode<T, FAMILY extends IAbstractBinaryTreeNo
}
export interface IAbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val'], N>> {
createNode(id: BinaryTreeNodeId, val: N['val'] | null, count?: number): N | null
createNode(val: N['val'], id: BinaryTreeNodeId, count?: number): N | null
get loopType(): LoopType
@ -71,7 +68,7 @@ export interface IAbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val'],
get maxId(): number
get isDuplicatedVal(): boolean
get isMergeDuplicatedVal(): boolean
get root(): N | null
@ -83,7 +80,7 @@ export interface IAbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val'],
isEmpty(): boolean
add(id: BinaryTreeNodeId, val?: N['val'], count?: number): N | null | undefined
add(val: N['val'], id: BinaryTreeNodeId, count?: number): N | null | undefined
addTo(newNode: N | null, parent: N): N | null | undefined

View file

@ -3,11 +3,11 @@ import {IBinaryTree, IBinaryTreeNode} from './binary-tree';
import {BinaryTreeDeletedResult, BinaryTreeNodeId, BinaryTreeNodePropertyName} from '../types';
export interface IBSTNode<T, FAMILY extends IBSTNode<T, FAMILY>> extends IBinaryTreeNode<T, FAMILY> {
createNode(id: BinaryTreeNodeId, val?: T, count?: number): FAMILY
createNode(val: T, id: BinaryTreeNodeId, count?: number): FAMILY
}
export interface IBST<N extends BSTNode<N['val'], N>> extends IBinaryTree<N> {
createNode(id: BinaryTreeNodeId, val?: N['val'] | null, count?: number): N
createNode(val: N['val'], id: BinaryTreeNodeId, count?: number): N
add(id: BinaryTreeNodeId, val: N['val'] | null, count: number): N | null

View file

@ -3,10 +3,10 @@ import {IBST, IBSTNode} from './bst';
import {BinaryTreeNodeId} from '../types';
export interface IRBTreeNode<T, FAMILY extends IRBTreeNode<T, FAMILY>> extends IBSTNode<T, FAMILY> {
createNode(id: BinaryTreeNodeId, val?: T | null, count?: number): FAMILY
createNode(val: T, id: BinaryTreeNodeId, count?: number): FAMILY
}
export interface IRBTree<N extends RBTreeNode<N['val'], N>> extends IBST<N> {
createNode(id: BinaryTreeNodeId, val?: N | null, count?: number): N
createNode(val: N['val'], id: BinaryTreeNodeId, count?: number): N
}

View file

@ -1,7 +1,6 @@
export class TreeNode<T = number> {
constructor(id: string, name?: string, value?: T, children?: TreeNode<T>[]) {
constructor(id: string, value?: T, children?: TreeNode<T>[]) {
this._id = id;
this._name = name || '';
this._value = value || undefined;
this._children = children || [];
}
@ -16,16 +15,6 @@ export class TreeNode<T = number> {
this._id = value;
}
private _name?: string | undefined;
get name(): string | undefined {
return this._name;
}
set name(value: string | undefined) {
this._name = value;
}
private _value?: T | undefined;
get value(): T | undefined {

View file

@ -9,7 +9,15 @@ import {AbstractBinaryTreeNode} from '../binary-tree';
export enum LoopType { ITERATIVE = 'ITERATIVE', RECURSIVE = 'RECURSIVE'}
/* This enumeration defines the position of a node within a family tree composed of three associated nodes, where 'root' represents the root node of the family tree, 'left' represents the left child node, and 'right' represents the right child node. */
export enum FamilyPosition {ROOT, LEFT, RIGHT}
export enum FamilyPosition {
ROOT = 'ROOT',
LEFT = 'LEFT',
RIGHT = 'RIGHT',
ROOT_LEFT = 'ROOT_LEFT',
ROOT_RIGHT = 'ROOT_RIGHT',
ISOLATED = 'ISOLATED',
MAL_NODE = 'MAL_NODE'
}
export type BinaryTreeNodePropertyName = 'id' | 'val' | 'count';
export type NodeOrPropertyName = 'node' | BinaryTreeNodePropertyName;
@ -27,5 +35,5 @@ export type AbstractBinaryTreeNodeNested<T> = AbstractBinaryTreeNode<T, Abstract
export type AbstractBinaryTreeOptions = {
loopType?: LoopType,
autoIncrementId?: boolean,
isDuplicatedVal?: boolean
isMergeDuplicatedVal?: boolean
}

View file

@ -1,2 +1 @@
export type IdObject = { id: number; } & { [key: string]: any; };
export type KeyValObject = { [key: string]: any };
export {}

View file

@ -3,6 +3,6 @@ import {AVLTreeOptions} from './avl-tree';
export type TreeMultiSetNodeNested<T> = TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
export type TreeMultiSetOptions = Omit<AVLTreeOptions, 'isDuplicatedVal'> & {
isDuplicatedVal: true,
export type TreeMultiSetOptions = Omit<AVLTreeOptions, 'isMergeDuplicatedVal'> & {
isMergeDuplicatedVal: true,
}

View file

@ -4,3 +4,30 @@ export type TrlFn = (...args: any[]) => any;
export type TrlAsyncFn = (...args: any[]) => any;
export type SpecifyOptional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
export type KeyValueObject = { [key: string]: any };
export type KeyValueObjectWithId = { [key: string]: any, id: string | number | symbol };
export type NonNumberNonObjectButDefined = string | boolean | symbol | null;
// export type ObjectWithoutId = Omit<object, 'id'>;
export type ObjectWithoutId = Omit<KeyValueObject, 'id'>;
// export type ObjectWithNonNumberId = object & {
// id: string | boolean | symbol | null | object | undefined;
// }
export type ObjectWithNonNumberId = {
[key: string]: any,
id: string | boolean | symbol | null | object | undefined;
}
// export type ObjectWithNumberId = object & {
// id: number;
// }
export type ObjectWithNumberId = {
[key: string]: any,
id: number;
}
export type DummyAny = string | number | boolean | null | undefined | object | symbol | void | Function | never;

View file

@ -29,7 +29,16 @@ export const arrayRemove = function <T>(array: T[], predicate: (item: T, index:
* @copyright Copyright (c) 2022 Tyler Zeng <zrwusa@gmail.com>
* @license MIT License
*/
import type {Thunk, ToThunkFn, TrlAsyncFn, TrlFn} from './types';
import type {
NonNumberNonObjectButDefined,
ObjectWithNonNumberId,
ObjectWithNumberId,
ObjectWithoutId,
Thunk,
ToThunkFn,
TrlAsyncFn,
TrlFn
} from './types';
export const THUNK_SYMBOL = Symbol('thunk')
@ -138,4 +147,24 @@ export const trampolineAsync = (fn: TrlAsyncFn) => {
// super.delete(key);
// }
// }
// }
// }
export function isNonNumberNonObjectButDefined(val: any): val is NonNumberNonObjectButDefined {
return typeof val !== 'number' && typeof val !== 'object' && val !== undefined;
}
export function isObjectWithoutId(val: any): val is ObjectWithoutId {
return typeof val === 'object' && !('id' in val);
}
export function isObjectWithNonNumberId(val: any): val is ObjectWithNonNumberId {
return typeof val === 'object' && 'id' in val && typeof val.id !== 'number';
}
export function isObjectWithNumberId(val: any): val is ObjectWithNumberId {
return typeof val === 'object' && 'id' in val && typeof val.id === 'number';
}
export function isNumber(val: any): val is number {
return typeof val === 'number';
}

View file

@ -2,193 +2,195 @@ import {BST, BSTNode} from '../../../../src';
describe('BST operations test', () => {
it('should perform various operations on a Binary Search Tree with numeric values', () => {
const tree = new BST();
expect(tree).toBeInstanceOf(BST);
const bst = new BST();
expect(bst).toBeInstanceOf(BST);
const values = [11, 3, 15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5];
tree.addMany(values);
expect(tree.root).toBeInstanceOf(BSTNode);
bst.addMany(values);
expect(bst.root).toBeInstanceOf(BSTNode);
if (tree.root) expect(tree.root.id).toBe(11);
if (bst.root) expect(bst.root.id).toBe(11);
expect(tree.count).toBe(16);
expect(bst.count).toBe(16);
expect(tree.has(6)).toBe(true);
expect(bst.has(6)).toBe(true);
const node6 = tree.get(6);
expect(node6 && tree.getHeight(node6)).toBe(2);
expect(node6 && tree.getDepth(node6)).toBe(3);
const node6 = bst.get(6);
expect(node6 && bst.getHeight(node6)).toBe(2);
expect(node6 && bst.getDepth(node6)).toBe(3);
const nodeId10 = tree.get(10, 'id');
const nodeId10 = bst.get(10, 'id');
expect(nodeId10?.id).toBe(10);
const nodeVal9 = tree.get(9, 'val');
const nodeVal9 = bst.get(9, 'val');
expect(nodeVal9?.id).toBe(9);
const nodesByCount1 = tree.getNodes(1, 'count');
const nodesByCount1 = bst.getNodes(1, 'count');
expect(nodesByCount1.length).toBe(16);
const leftMost = tree.getLeftMost();
const leftMost = bst.getLeftMost();
expect(leftMost?.id).toBe(1);
const node15 = tree.get(15);
const minNodeBySpecificNode = node15 && tree.getLeftMost(node15);
const node15 = bst.get(15);
const minNodeBySpecificNode = node15 && bst.getLeftMost(node15);
expect(minNodeBySpecificNode?.id).toBe(12);
const subTreeSum = node15 && tree.subTreeSum(node15);
const subTreeSum = node15 && bst.subTreeSum(node15);
expect(subTreeSum).toBe(70);
const lesserSum = tree.lesserSum(10);
const lesserSum = bst.lesserSum(10);
expect(lesserSum).toBe(45);
expect(node15).toBeInstanceOf(BSTNode);
if (node15 instanceof BSTNode) {
const subTreeAdd = tree.subTreeAdd(node15, 1, 'count');
const subTreeAdd = bst.subTreeAdd(node15, 1, 'count');
expect(subTreeAdd).toBeDefined();
}
const node11 = tree.get(11);
const node11 = bst.get(11);
expect(node11).toBeInstanceOf(BSTNode);
if (node11 instanceof BSTNode) {
const allGreaterNodesAdded = tree.allGreaterNodesAdd(node11, 2, 'count');
const allGreaterNodesAdded = bst.allGreaterNodesAdd(node11, 2, 'count');
expect(allGreaterNodesAdded).toBeDefined();
}
const dfsInorderNodes = tree.DFS('in', 'node');
const dfsInorderNodes = bst.DFS('in', 'node');
expect(dfsInorderNodes[0].id).toBe(1);
expect(dfsInorderNodes[dfsInorderNodes.length - 1].id).toBe(16);
tree.balance();
expect(tree.isBalanced()).toBe(true);
bst.balance();
expect(bst.isBalanced()).toBe(true);
const bfsNodesAfterBalanced = tree.BFS('node');
const bfsNodesAfterBalanced = bst.BFS('node');
expect(bfsNodesAfterBalanced[0].id).toBe(8);
expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].id).toBe(16);
const removed11 = tree.remove(11, true);
const removed11 = bst.remove(11, true);
expect(removed11).toBeInstanceOf(Array);
expect(removed11[0]).toBeDefined();
expect(removed11[0].deleted).toBeDefined();
if (removed11[0].deleted) expect(removed11[0].deleted.id).toBe(11);
expect(tree.isAVLBalanced()).toBe(true);
expect(bst.isAVLBalanced()).toBe(true);
expect(node15 && tree.getHeight(node15)).toBe(2);
expect(node15 && bst.getHeight(node15)).toBe(2);
const removed1 = tree.remove(1, true);
const removed1 = bst.remove(1, true);
expect(removed1).toBeInstanceOf(Array);
expect(removed1[0]).toBeDefined();
expect(removed1[0].deleted).toBeDefined();
if (removed1[0].deleted) expect(removed1[0].deleted.id).toBe(1);
expect(tree.isAVLBalanced()).toBe(true);
expect(bst.isAVLBalanced()).toBe(true);
expect(tree.getHeight()).toBe(4);
expect(bst.getHeight()).toBe(4);
const removed4 = tree.remove(4, true);
const removed4 = bst.remove(4, true);
expect(removed4).toBeInstanceOf(Array);
expect(removed4[0]).toBeDefined();
expect(removed4[0].deleted).toBeDefined();
if (removed4[0].deleted) expect(removed4[0].deleted.id).toBe(4);
expect(tree.isAVLBalanced()).toBe(true);
expect(tree.getHeight()).toBe(4);
expect(bst.isAVLBalanced()).toBe(true);
expect(bst.getHeight()).toBe(4);
const removed10 = tree.remove(10, true);
const removed10 = bst.remove(10, true);
expect(removed10).toBeInstanceOf(Array);
expect(removed10[0]).toBeDefined();
expect(removed10[0].deleted).toBeDefined();
if (removed10[0].deleted) expect(removed10[0].deleted.id).toBe(10);
expect(tree.isAVLBalanced()).toBe(false);
expect(tree.getHeight()).toBe(4);
expect(bst.isAVLBalanced()).toBe(false);
expect(bst.getHeight()).toBe(4);
const removed15 = tree.remove(15, true);
const removed15 = bst.remove(15, true);
expect(removed15).toBeInstanceOf(Array);
expect(removed15[0]).toBeDefined();
expect(removed15[0].deleted).toBeDefined();
if (removed15[0].deleted) expect(removed15[0].deleted.id).toBe(15);
expect(tree.isAVLBalanced()).toBe(true);
expect(tree.getHeight()).toBe(3);
expect(bst.isAVLBalanced()).toBe(true);
expect(bst.getHeight()).toBe(3);
const removed5 = tree.remove(5, true);
const removed5 = bst.remove(5, true);
expect(removed5).toBeInstanceOf(Array);
expect(removed5[0]).toBeDefined();
expect(removed5[0].deleted).toBeDefined();
if (removed5[0].deleted) expect(removed5[0].deleted.id).toBe(5);
expect(tree.isAVLBalanced()).toBe(true);
expect(tree.getHeight()).toBe(3);
expect(bst.isAVLBalanced()).toBe(true);
expect(bst.getHeight()).toBe(3);
const removed13 = tree.remove(13, true);
const removed13 = bst.remove(13, true);
expect(removed13).toBeInstanceOf(Array);
expect(removed13[0]).toBeDefined();
expect(removed13[0].deleted).toBeDefined();
if (removed13[0].deleted) expect(removed13[0].deleted.id).toBe(13);
expect(tree.isAVLBalanced()).toBe(true);
expect(tree.getHeight()).toBe(3);
expect(bst.isAVLBalanced()).toBe(true);
expect(bst.getHeight()).toBe(3);
const removed3 = tree.remove(3, true);
const removed3 = bst.remove(3, true);
expect(removed3).toBeInstanceOf(Array);
expect(removed3[0]).toBeDefined();
expect(removed3[0].deleted).toBeDefined();
if (removed3[0].deleted) expect(removed3[0].deleted.id).toBe(3);
expect(tree.isAVLBalanced()).toBe(false);
expect(tree.getHeight()).toBe(3);
expect(bst.isAVLBalanced()).toBe(false);
expect(bst.getHeight()).toBe(3);
const removed8 = tree.remove(8, true);
const removed8 = bst.remove(8, true);
expect(removed8).toBeInstanceOf(Array);
expect(removed8[0]).toBeDefined();
expect(removed8[0].deleted).toBeDefined();
if (removed8[0].deleted) expect(removed8[0].deleted.id).toBe(8);
expect(tree.isAVLBalanced()).toBe(true);
expect(tree.getHeight()).toBe(3);
expect(bst.isAVLBalanced()).toBe(true);
expect(bst.getHeight()).toBe(3);
const removed6 = tree.remove(6, true);
const removed6 = bst.remove(6, true);
expect(removed6).toBeInstanceOf(Array);
expect(removed6[0]).toBeDefined();
expect(removed6[0].deleted).toBeDefined();
if (removed6[0].deleted) expect(removed6[0].deleted.id).toBe(6);
expect(tree.remove(6, true).length).toBe(0);
expect(tree.isAVLBalanced()).toBe(false);
expect(tree.getHeight()).toBe(3);
expect(bst.remove(6, true).length).toBe(0);
expect(bst.isAVLBalanced()).toBe(false);
expect(bst.getHeight()).toBe(3);
const removed7 = tree.remove(7, true);
const removed7 = bst.remove(7, true);
expect(removed7).toBeInstanceOf(Array);
expect(removed7[0]).toBeDefined();
expect(removed7[0].deleted).toBeDefined();
if (removed7[0].deleted) expect(removed7[0].deleted.id).toBe(7);
expect(tree.isAVLBalanced()).toBe(false);
expect(tree.getHeight()).toBe(3);
expect(bst.isAVLBalanced()).toBe(false);
expect(bst.getHeight()).toBe(3);
const removed9 = tree.remove(9, true);
const removed9 = bst.remove(9, true);
expect(removed9).toBeInstanceOf(Array);
expect(removed9[0]).toBeDefined();
expect(removed9[0].deleted).toBeDefined();
if (removed9[0].deleted) expect(removed9[0].deleted.id).toBe(9);
expect(tree.isAVLBalanced()).toBe(false);
expect(tree.getHeight()).toBe(3);
expect(bst.isAVLBalanced()).toBe(false);
expect(bst.getHeight()).toBe(3);
const removed14 = tree.remove(14, true);
const removed14 = bst.remove(14, true);
expect(removed14).toBeInstanceOf(Array);
expect(removed14[0]).toBeDefined();
expect(removed14[0].deleted).toBeDefined();
if (removed14[0].deleted) expect(removed14[0].deleted.id).toBe(14);
expect(tree.isAVLBalanced()).toBe(false);
expect(tree.getHeight()).toBe(2);
expect(bst.isAVLBalanced()).toBe(false);
expect(bst.getHeight()).toBe(2);
expect(tree.isAVLBalanced()).toBe(false);
expect(bst.isAVLBalanced()).toBe(false);
const bfsIDs = tree.BFS();
const bfsIDs = bst.BFS();
expect(bfsIDs[0]).toBe(2);
expect(bfsIDs[1]).toBe(12);
expect(bfsIDs[2]).toBe(16);
const bfsNodes = tree.BFS('node');
const bfsNodes = bst.BFS('node');
expect(bfsNodes[0].id).toBe(2);
expect(bfsNodes[1].id).toBe(12);
expect(bfsNodes[2].id).toBe(16);
expect(bst.count).toBe(5);
});
it('should perform various operations on a Binary Search Tree with object values', () => {
@ -388,5 +390,7 @@ describe('BST operations test', () => {
expect(bfsNodes[0].id).toBe(2);
expect(bfsNodes[1].id).toBe(12);
expect(bfsNodes[2].id).toBe(16);
expect(objBST.count).toBe(5);
});
});