Tidying up the code and identifying any further requirements that need to be marked as TODO.

This commit is contained in:
Revone 2023-08-31 22:25:41 +08:00
parent 2d1010b352
commit 407c3b104a
8 changed files with 96 additions and 154 deletions

View file

@ -143,11 +143,15 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
if (options !== undefined) {
const {
loopType = LoopType.ITERATIVE,
isMergeDuplicatedVal = true
isMergeDuplicatedNodeById = true
} = options;
this._isMergeDuplicatedVal = isMergeDuplicatedVal;
this._isMergeDuplicatedNodeById = isMergeDuplicatedNodeById;
this._loopType = loopType;
} else {
this._isMergeDuplicatedNodeById = true;
this._loopType = LoopType.ITERATIVE;
}
this.clear();
}
private _root: N | null = null;
@ -156,7 +160,7 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
return this._root;
}
private _size = 0;
private _size: number = 0;
get size(): number {
return this._size;
@ -168,17 +172,11 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
return this._loopType;
}
private _maxId: number = -1;
get maxId(): number {
return this._maxId;
}
// TODO this variable may be moved to TreeMultiset
private _isMergeDuplicatedVal: boolean = true;
private _isMergeDuplicatedNodeById: boolean = true;
get isMergeDuplicatedVal(): boolean {
return this._isMergeDuplicatedVal;
get isMergeDuplicatedNodeById(): boolean {
return this._isMergeDuplicatedNodeById;
}
private _visitedId: BinaryTreeNodeId[] = [];
@ -187,9 +185,9 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
return this._visitedId;
}
private _visitedVal: Array<N['val']> = [];
private _visitedVal: N['val'][] = [];
get visitedVal(): Array<N['val']> {
get visitedVal(): N['val'][] {
return this._visitedVal;
}
@ -199,12 +197,6 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
return this._visitedNode;
}
private _visitedCount: number[] = [];
get visitedCount(): number[] {
return this._visitedCount;
}
private _visitedLeftSum: number[] = [];
get visitedLeftSum(): number[] {
@ -221,21 +213,19 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
* @returns The `destNode` is being returned.
*/
swapLocation(srcNode: N, destNode: N): N {
const {val, height, id} = destNode;
const {id, val, height} = destNode;
const tempNode = this.createNode(id, val);
if (tempNode) {
tempNode.height = height;
if (tempNode instanceof AbstractBinaryTreeNode) {
// TODO should we consider the left, right children?
destNode.id = srcNode.id;
destNode.val = srcNode.val;
destNode.height = srcNode.height;
destNode.id = srcNode.id;
destNode.val = srcNode.val;
destNode.height = srcNode.height;
srcNode.id = tempNode.id;
srcNode.val = tempNode.val;
srcNode.height = tempNode.height;
}
srcNode.id = tempNode.id;
srcNode.val = tempNode.val;
srcNode.height = tempNode.height;
}
return destNode;
@ -245,9 +235,9 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
* The clear() function resets the root, size, and maxId properties to their initial values.
*/
clear() {
this._setRoot(null);
this._setSize(0);
this._setMaxId(-1);
this._root = null;
this._size = 0;
this._clearResults();
}
/**
@ -259,12 +249,20 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
}
/**
* The `add` function adds a new node to a binary tree, either by updating an existing node or inserting a new node.
* @param {BinaryTreeNodeId | N} id - The `id` parameter can be either a `BinaryTreeNodeId` or `N`.
* @param [val] - The `val` parameter is an optional value that can be assigned to the node being added.
* When all leaf nodes are null, it will no longer be possible to add new entity nodes to this binary tree.
* In this scenario, null nodes serve as "sentinel nodes," "virtual nodes," or "placeholder nodes."
*/
/**
* The `add` function adds a new node to a binary tree, either by ID or by creating a new node with a given value.
* @param {BinaryTreeNodeId | N | null} idOrNode - The `idOrNode` parameter can be either a `BinaryTreeNodeId`, which
* is a number representing the ID of a binary tree node, or it can be a `N` object, which represents a binary tree
* node itself. It can also be `null` if no node is specified.
* @param [val] - The `val` parameter is an optional value that can be assigned to the `val` property of the new node
* being added to the binary tree.
* @returns The function `add` returns either the inserted node (`N`), `null`, or `undefined`.
*/
add(id: BinaryTreeNodeId | N | null, val?: N['val']): N | null | undefined {
add(idOrNode: BinaryTreeNodeId | N | null, val?: N['val']): N | null | undefined {
const _bfs = (root: N, newNode: N | null): N | undefined | null => {
const queue: Array<N | null> = [root];
while (queue.length > 0) {
@ -279,18 +277,20 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
return;
};
let inserted: N | null | undefined;
let needInsert;
if (id === null) {
let inserted: N | null | undefined, needInsert: N | null;
if (idOrNode === null) {
needInsert = null;
} else if (typeof id === 'number') {
needInsert = this.createNode(id, val);
} else if (id instanceof AbstractBinaryTreeNode) {
needInsert = id;
} else if (typeof idOrNode === 'number') {
needInsert = this.createNode(idOrNode, val);
} else if (idOrNode instanceof AbstractBinaryTreeNode) {
needInsert = idOrNode;
} else {
return;
}
const existNode = id ? this.get(id, 'id') : undefined;
const existNode = idOrNode ? this.get(idOrNode, 'id') : undefined;
if (this.root) {
if (existNode) {
existNode.val = val;
@ -321,22 +321,17 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
*/
addTo(newNode: N | null, parent: N): N | null | undefined {
if (parent) {
// When all leaf nodes are null, it will no longer be possible to add new entity nodes to this binary tree.
// In this scenario, null nodes serve as "sentinel nodes," "virtual nodes," or "placeholder nodes."
if (parent.left === undefined) {
if (newNode) {
newNode.parent = parent;
}
parent.left = newNode;
if (newNode !== null) {
if (newNode) {
this._setSize(this.size + 1);
}
return parent.left;
} else if (parent.right === undefined) {
if (newNode) {
newNode.parent = parent;
}
parent.right = newNode;
if (newNode !== null) {
if (newNode) {
this._setSize(this.size + 1);
}
return parent.right;
@ -362,7 +357,7 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
const inserted: (N | null | undefined)[] = [];
const map: Map<N | BinaryTreeNodeId | null, number> = new Map();
if (this.isMergeDuplicatedVal) {
if (this.isMergeDuplicatedNodeById) {
for (const idOrNode of idsOrNodes) map.set(idOrNode, (map.get(idOrNode) ?? 0) + 1);
}
@ -379,7 +374,7 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
}
const val = data?.[i];
if (this.isMergeDuplicatedVal) {
if (this.isMergeDuplicatedNodeById) {
if (map.has(idOrNode)) {
inserted.push(this.add(idOrNode, val));
map.delete(idOrNode);
@ -631,6 +626,7 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
*/
has(nodeProperty: BinaryTreeNodeId | N, propertyName ?: BinaryTreeNodePropertyName): boolean {
propertyName = propertyName ?? 'id';
// TODO may support finding node by value equal
return this.getNodes(nodeProperty, propertyName).length > 0;
}
@ -647,6 +643,7 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
*/
get(nodeProperty: BinaryTreeNodeId | N, propertyName ?: BinaryTreeNodePropertyName): N | null {
propertyName = propertyName ?? 'id';
// TODO may support finding node by value equal
return this.getNodes(nodeProperty, propertyName, true)[0] ?? null;
}
@ -657,6 +654,7 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
* @returns The function `getPathToRoot` returns an array of nodes (`N[]`).
*/
getPathToRoot(node: N): N[] {
// TODO to support get path through passing id
const result: N[] = [];
while (node.parent) {
result.unshift(node);
@ -720,6 +718,7 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
* function returns `null`.
*/
getRightMost(node?: N | null): N | null {
// TODO support get right most by passing id in
node = node ?? this.root;
if (!node) return node;
@ -746,7 +745,7 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
* @param {N | null} node - The `node` parameter represents the root node of a binary search tree (BST).
* @returns a boolean value.
*/
isBSTByRooted(node: N | null): boolean {
isSubtreeBST(node: N | null): boolean {
// TODO there is a bug
if (!node) return true;
@ -776,13 +775,11 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
}
/**
* The function checks if a binary tree is a binary search tree.
* @param {N | null} [node] - The `node` parameter is of type `N` or `null`. It represents the root node of a binary
* search tree (BST).
* @returns a boolean value.
* The function isBST checks if the binary search tree is valid.
* @returns The `isBST()` function is returning a boolean value.
*/
isBST(node?: N | null): boolean {
return this.isBSTByRooted(this.root);
isBST(): boolean {
return this.isSubtreeBST(this.root);
}
/**
@ -792,6 +789,7 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
* @returns the size of the subtree rooted at `subTreeRoot`.
*/
getSubTreeSize(subTreeRoot: N | null | undefined) {
// TODO support id passed in
let size = 0;
if (!subTreeRoot) return size;
@ -941,7 +939,7 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
*/
BFS(nodeOrPropertyName ?: NodeOrPropertyName): AbstractBinaryTreeNodeProperties<N> {
nodeOrPropertyName = nodeOrPropertyName ?? 'id';
this._resetResults();
this._clearResults();
const queue: Array<N | null | undefined> = [this.root];
while (queue.length !== 0) {
@ -978,7 +976,7 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
DFS(pattern ?: 'in' | 'pre' | 'post', nodeOrPropertyName ?: NodeOrPropertyName): AbstractBinaryTreeNodeProperties<N> {
pattern = pattern ?? 'in';
nodeOrPropertyName = nodeOrPropertyName ?? 'id';
this._resetResults();
this._clearResults();
const _traverse = (node: N) => {
switch (pattern) {
case 'in':
@ -1028,7 +1026,7 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
DFSIterative(pattern ?: 'in' | 'pre' | 'post', nodeOrPropertyName ?: NodeOrPropertyName): AbstractBinaryTreeNodeProperties<N> {
pattern = pattern || 'in';
nodeOrPropertyName = nodeOrPropertyName || 'id';
this._resetResults();
this._clearResults();
if (!this.root) return this._getResultByPropertyName(nodeOrPropertyName);
// 0: visit, 1: print
const stack: { opt: 0 | 1, node: N | null | undefined }[] = [{opt: 0, node: this.root}];
@ -1092,7 +1090,7 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
node = node || this.root;
if (!node) return [];
this._resetResults();
this._clearResults();
const queue: N[] = [node];
while (queue.length > 0) {
@ -1226,7 +1224,7 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
pattern = pattern || 'in';
nodeOrPropertyName = nodeOrPropertyName || 'id';
this._resetResults();
this._clearResults();
let cur: N | null | undefined = this.root;
const _reverseEdge = (node: N | null | undefined) => {
@ -1338,14 +1336,6 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
this._visitedNode = value;
}
/**
* The function sets the value of the visitedCount property.
* @param {number[]} value - The value parameter is an array of numbers.
*/
protected setVisitedCount(value: number[]) {
this._visitedCount = value;
}
/**
* The function sets the value of the `_visitedLeftSum` property to the provided array.
* @param {number[]} value - An array of numbers that represents the visited left sum.
@ -1354,22 +1344,13 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
this._visitedLeftSum = value;
}
/**
* The function sets the maximum ID value.
* @param {number} value - The value parameter is a number that represents the new maximum ID value.
*/
protected _setMaxId(value: number) {
this._maxId = value;
}
/**
* The function sets the value of a protected property called "_isMergeDuplicatedVal".
* @param {boolean} value - The value parameter is a boolean value that determines whether the isMergeDuplicatedVal
* The function sets the value of a protected property called "_isMergeDuplicatedNodeById".
* @param {boolean} value - The value parameter is a boolean value that determines whether the isMergeDuplicatedNodeById
* property should be set to true or false.
*/
protected _setIsDuplicatedVal(value: boolean) {
this._isMergeDuplicatedVal = value;
this._isMergeDuplicatedNodeById = value;
}
/**
@ -1393,10 +1374,10 @@ export abstract class AbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val
}
/**
* The function `_resetResults` resets the values of several arrays used for tracking visited nodes and their
* The function `_clearResults` resets the values of several arrays used for tracking visited nodes and their
* properties.
*/
protected _resetResults() {
protected _clearResults() {
this._visitedId = [];
this._visitedVal = [];
this._visitedNode = [];

View file

@ -46,6 +46,7 @@ export class AVLTree<N extends AVLTreeNode<N['val'], N> = AVLTreeNode> extends B
* @returns The method is returning the inserted node, or null or undefined if the insertion was not successful.
*/
override add(id: BinaryTreeNodeId, val?: N['val']): N | null | undefined {
// TODO support node as a param
const inserted = super.add(id, val);
if (inserted) this.balancePath(inserted);
return inserted;

View file

@ -53,6 +53,7 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
* If the node was not added (e.g., due to a duplicate ID), it returns `null` or `undefined`.
*/
override add(id: BinaryTreeNodeId, val?: N['val']): N | null | undefined {
// TODO support node as a param
let inserted: N | null = null;
const newNode = this.createNode(id, val);
if (this.root === null) {

View file

@ -50,7 +50,7 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
* TreeMultiset.
*/
constructor(options?: TreeMultisetOptions) {
super({...options, isMergeDuplicatedVal: true});
super({...options, isMergeDuplicatedNodeById: true});
}
private _count = 0;
@ -80,28 +80,25 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
* @returns the `destNode` after swapping its values with the `srcNode`.
*/
override swapLocation(srcNode: N, destNode: N): N {
const {val, count, height, id} = destNode;
const {id, val, count, height} = destNode;
const tempNode = this.createNode(id, val, count);
if (tempNode) {
tempNode.height = height;
if (tempNode instanceof TreeMultisetNode) {
destNode.id = srcNode.id;
destNode.val = srcNode.val;
destNode.count = srcNode.count;
destNode.height = srcNode.height;
destNode.id = srcNode.id;
destNode.val = srcNode.val;
destNode.count = srcNode.count;
destNode.height = srcNode.height;
srcNode.id = tempNode.id;
srcNode.val = tempNode.val;
srcNode.count = tempNode.count;
srcNode.height = tempNode.height;
}
srcNode.id = tempNode.id;
srcNode.val = tempNode.val;
srcNode.count = tempNode.count;
srcNode.height = tempNode.height;
}
return destNode;
}
/**
* The `add` function adds a new node to a binary search tree, maintaining the tree's properties and balancing if
* necessary.
@ -114,9 +111,7 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
*/
override add(idOrNode: BinaryTreeNodeId | N | null, val?: N['val'], count?: number): N | null | undefined {
count = count ?? 1;
let inserted: N | null | undefined = undefined;
let newNode;
let id;
let inserted: N | null | undefined = undefined, newNode: N | null;
if (idOrNode instanceof TreeMultisetNode) {
newNode = this.createNode(idOrNode.id, idOrNode.val, idOrNode.count);
} else if (idOrNode === null) {
@ -194,7 +189,6 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
override addTo(newNode: N | null, parent: N): N | null | undefined {
if (parent) {
if (parent.left === undefined) {
parent.left = newNode;
if (newNode !== null) {
this._setSize(this.size + 1);
@ -231,7 +225,7 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
const inserted: (N | null | undefined)[] = [];
const map: Map<N | BinaryTreeNodeId, number> = new Map();
if (this.isMergeDuplicatedVal) {
if (this.isMergeDuplicatedNodeById) {
for (const idOrNode of idsOrNodes) map.set(idOrNode, (map.get(idOrNode) ?? 0) + 1);
}
@ -247,9 +241,9 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
continue;
}
const count = this.isMergeDuplicatedVal ? map.get(idOrNode) : 1;
const count = this.isMergeDuplicatedNodeById ? map.get(idOrNode) : 1;
const val = data?.[i];
if (this.isMergeDuplicatedVal) {
if (this.isMergeDuplicatedNodeById) {
if (map.has(idOrNode)) {
inserted.push(this.add(idOrNode, val, count));
map.delete(idOrNode);
@ -268,9 +262,10 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
*/
override perfectlyBalance(): boolean {
const sorted = this.DFS('in', 'node'), n = sorted.length;
if (sorted.length < 1) return false;
this.clear();
if (sorted.length < 1) return false;
if (this.loopType === LoopType.RECURSIVE) {
const buildBalanceBST = (l: number, r: number) => {
if (l > r) return;

View file

@ -51,13 +51,9 @@ export interface IAbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val'],
get visitedNode(): N[]
get visitedCount(): number[]
get visitedLeftSum(): number[]
get maxId(): number
get isMergeDuplicatedVal(): boolean
get isMergeDuplicatedNodeById(): boolean
get root(): N | null
@ -107,9 +103,9 @@ export interface IAbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val'],
getRightMost(node?: N | null): N | null
isBSTByRooted(node: N | null): boolean
isSubtreeBST(node: N | null): boolean
isBST(node?: N | null): boolean
isBST(): boolean
getSubTreeSize(subTreeRoot: N | null | undefined): number
@ -193,37 +189,6 @@ export interface IAbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val'],
morris(pattern?: 'in' | 'pre' | 'post', nodeOrPropertyName?: NodeOrPropertyName): AbstractBinaryTreeNodeProperties<N>
// _setLoopType(value: LoopType): void
//
// _setVisitedId(value: BinaryTreeNodeId[]): void
//
// _setVisitedVal(value: Array<N>): void
//
// _setVisitedNode(value: N[]): void
//
// setVisitedCount(value: number[]): void
//
// _setVisitedLeftSum(value: number[]): void
//
// _setAutoIncrementId(value: boolean): void
//
// _setMaxId(value: number): void
//
// _setIsDuplicatedVal(value: boolean): void
//
// _setRoot(v: N | null): void
//
// _setSize(v: number): void
//
// _setCount(v: number): void
//
// _resetResults(): void
// _pushByPropertyNameStopOrNot(cur: N, result: (N | null | undefined)[], nodeProperty: BinaryTreeNodeId | N, propertyName ?: BinaryTreeNodePropertyName, onlyOne ?: boolean): void
//
// _accumulatedByPropertyName(node: N, nodeOrPropertyName ?: NodeOrPropertyName): void
//
// _getResultByPropertyName(nodeOrPropertyName ?: NodeOrPropertyName): AbstractBinaryTreeNodeProperties<N>
// --- end additional methods ---
}

View file

@ -37,5 +37,5 @@ export type AbstractBinaryTreeNodeNested<T> = AbstractBinaryTreeNode<T, Abstract
export type AbstractBinaryTreeOptions = {
loopType?: LoopType,
isMergeDuplicatedVal?: boolean
isMergeDuplicatedNodeById?: boolean
}

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, 'isMergeDuplicatedVal'> & {
isMergeDuplicatedVal: true,
export type TreeMultisetOptions = Omit<AVLTreeOptions, 'isMergeDuplicatedNodeById'> & {
isMergeDuplicatedNodeById: true,
}

View file

@ -5,7 +5,6 @@
"module": "commonjs",
"target": "es6",
"lib": [
// "es2015",
"esnext"
],
"strict": true,
@ -31,7 +30,7 @@
"src",
],
"exclude": [
// "node_modules/data-structure-typed",
// "node_modules/data-structure-typed",
"node_modules",
"dist"
]