mirror of
https://github.com/zrwusa/data-structure-typed.git
synced 2024-11-23 12:54:04 +00:00
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:
parent
8db8976503
commit
d29ff07f40
|
@ -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>
|
|
@ -1,4 +1,7 @@
|
|||
/.idea
|
||||
|
||||
/src
|
||||
/tests
|
||||
/tests
|
||||
/notes
|
||||
/docs
|
||||
/backup
|
14
package-lock.json
generated
14
package-lock.json
generated
|
@ -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": {
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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]);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -1,2 +1 @@
|
|||
export type IdObject = { id: number; } & { [key: string]: any; };
|
||||
export type KeyValObject = { [key: string]: any };
|
||||
export {}
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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;
|
|
@ -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';
|
||||
}
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue