mirror of
https://github.com/zrwusa/data-structure-typed.git
synced 2024-11-23 12:54:04 +00:00
refactor: Remove isSubtreeBST; using isBST alone is sufficient. Update BSTVariant to use STANDARD and INVERSE instead of MIN and MAX.
feat: Enhance isBST to support the detection of inverse binary search trees.
This commit is contained in:
parent
0708509f3e
commit
677340e99c
|
@ -1075,7 +1075,7 @@ export class BinaryTree<
|
|||
* possible values:
|
||||
* @returns a boolean value.
|
||||
*/
|
||||
isSubtreeBST(beginRoot: BTNKeyOrNode<K, N>, iterationType = this.iterationType): boolean {
|
||||
isBST(beginRoot: BTNKeyOrNode<K, N> = this.root, iterationType = this.iterationType): boolean {
|
||||
// TODO there is a bug
|
||||
beginRoot = this.ensureNode(beginRoot);
|
||||
if (!beginRoot) return true;
|
||||
|
@ -1088,47 +1088,34 @@ export class BinaryTree<
|
|||
return dfs(cur.left, min, numKey) && dfs(cur.right, numKey, max);
|
||||
};
|
||||
|
||||
return dfs(beginRoot, Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER);
|
||||
const isStandardBST = dfs(beginRoot, Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER);
|
||||
const isInverseBST = dfs(beginRoot, Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER);
|
||||
return isStandardBST || isInverseBST;
|
||||
} else {
|
||||
const stack = [];
|
||||
let prev = Number.MIN_SAFE_INTEGER,
|
||||
curr: N | null | undefined = beginRoot;
|
||||
while (curr || stack.length > 0) {
|
||||
while (curr) {
|
||||
stack.push(curr);
|
||||
curr = curr.left;
|
||||
const checkBST = (checkMax = false) => {
|
||||
const stack = [];
|
||||
let prev = checkMax ? Number.MAX_SAFE_INTEGER : Number.MIN_SAFE_INTEGER;
|
||||
// @ts-ignore
|
||||
let curr: N | null | undefined = beginRoot;
|
||||
while (curr || stack.length > 0) {
|
||||
while (curr) {
|
||||
stack.push(curr);
|
||||
curr = curr.left;
|
||||
}
|
||||
curr = stack.pop()!;
|
||||
const numKey = this.extractor(curr.key);
|
||||
if (!curr || (!checkMax && prev >= numKey) || (checkMax && prev <= numKey)) return false;
|
||||
prev = numKey;
|
||||
curr = curr.right;
|
||||
}
|
||||
curr = stack.pop()!;
|
||||
const numKey = this.extractor(curr.key);
|
||||
if (!curr || prev >= numKey) return false;
|
||||
prev = numKey;
|
||||
curr = curr.right;
|
||||
}
|
||||
return true;
|
||||
return true;
|
||||
};
|
||||
const isStandardBST = checkBST(false),
|
||||
isInverseBST = checkBST(true);
|
||||
return isStandardBST || isInverseBST;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Time Complexity: O(n)
|
||||
* Space Complexity: O(1)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Time Complexity: O(n)
|
||||
* Space Complexity: O(1)
|
||||
*
|
||||
* The function checks if a binary tree is a binary search tree.
|
||||
* @param iterationType - The parameter "iterationType" is used to specify the type of iteration to
|
||||
* be used when checking if the binary tree is a binary search tree (BST). It is an optional
|
||||
* parameter with a default value of "this.iterationType". The value of "this.iterationType" is
|
||||
* expected to be
|
||||
* @returns a boolean value.
|
||||
*/
|
||||
isBST(iterationType = this.iterationType): boolean {
|
||||
if (this.root === null) return true;
|
||||
return this.isSubtreeBST(this.root, iterationType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Time Complexity: O(n)
|
||||
* Space Complexity: O(1)
|
||||
|
|
|
@ -121,7 +121,7 @@ export class BST<
|
|||
return this._root;
|
||||
}
|
||||
|
||||
protected _variant = BSTVariant.MIN;
|
||||
protected _variant = BSTVariant.STANDARD;
|
||||
|
||||
get variant() {
|
||||
return this._variant;
|
||||
|
@ -390,7 +390,7 @@ export class BST<
|
|||
let current = this.ensureNode(beginRoot);
|
||||
if (!current) return undefined;
|
||||
|
||||
if (this._variant === BSTVariant.MIN) {
|
||||
if (this._variant === BSTVariant.STANDARD) {
|
||||
// For BSTVariant.MIN, find the rightmost node
|
||||
while (current.right !== undefined) {
|
||||
current = current.right;
|
||||
|
@ -761,7 +761,7 @@ export class BST<
|
|||
protected _compare(a: K, b: K): CP {
|
||||
const extractedA = this.extractor(a);
|
||||
const extractedB = this.extractor(b);
|
||||
const compared = this.variant === BSTVariant.MIN ? extractedA - extractedB : extractedB - extractedA;
|
||||
const compared = this.variant === BSTVariant.STANDARD ? extractedA - extractedB : extractedB - extractedA;
|
||||
|
||||
return compared > 0 ? CP.gt : compared < 0 ? CP.lt : CP.eq;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
export enum BSTVariant {
|
||||
MIN = 'MIN',
|
||||
MAX = 'MAX'
|
||||
STANDARD = 'STANDARD',
|
||||
INVERSE = 'INVERSE'
|
||||
}
|
||||
|
||||
export enum CP {
|
||||
|
|
|
@ -224,15 +224,15 @@ describe('BinaryTree', () => {
|
|||
new BinaryTreeNode(4, 4)
|
||||
]);
|
||||
|
||||
expect(tree.isSubtreeBST(tree.getNode(4), IterationType.RECURSIVE)).toBe(true);
|
||||
expect(tree.isSubtreeBST(tree.getNode(4), IterationType.ITERATIVE)).toBe(true);
|
||||
expect(tree.isBST(tree.getNode(4), IterationType.RECURSIVE)).toBe(true);
|
||||
expect(tree.isBST(tree.getNode(4), IterationType.ITERATIVE)).toBe(true);
|
||||
});
|
||||
|
||||
it('should isSubtreeBST', () => {
|
||||
tree.addMany([4, 2, 6, 1, 3, 5, 7, 4]);
|
||||
|
||||
expect(tree.isSubtreeBST(tree.getNode(4), IterationType.RECURSIVE)).toBe(true);
|
||||
expect(tree.isSubtreeBST(tree.getNode(4), IterationType.ITERATIVE)).toBe(true);
|
||||
expect(tree.isBST(tree.getNode(4), IterationType.RECURSIVE)).toBe(true);
|
||||
expect(tree.isBST(tree.getNode(4), IterationType.ITERATIVE)).toBe(true);
|
||||
expect(tree.getNodes(2, undefined, false, null)).toEqual([]);
|
||||
expect(tree.getNodes(tree.getNodeByKey(2), undefined, false, tree.root)).toEqual([tree.getNodeByKey(2)]);
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { BinaryTreeNode, BST, BSTNode, CP, IterationType } from '../../../../src';
|
||||
import { BinaryTreeNode, BST, BSTNode, BSTVariant, CP, IterationType } from '../../../../src';
|
||||
import { isDebugTest } from '../../../config';
|
||||
|
||||
const isDebug = isDebugTest;
|
||||
|
@ -47,6 +47,8 @@ describe('BST operations test', () => {
|
|||
const leftMost = bst.getLeftMost();
|
||||
expect(leftMost?.key).toBe(1);
|
||||
|
||||
expect(bst.isBST()).toBe(true);
|
||||
|
||||
const node15 = bst.getNode(15);
|
||||
const minNodeBySpecificNode = node15 && bst.getLeftMost(node15);
|
||||
expect(minNodeBySpecificNode?.key).toBe(12);
|
||||
|
@ -795,6 +797,20 @@ describe('BST operations test recursively', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('BST isBST', function () {
|
||||
test('isBST', () => {
|
||||
const bst = new BST<number, number>();
|
||||
bst.addMany([1, 2, 3, 9, 8, 5, 6, 7, 4]);
|
||||
expect(bst.isBST()).toBe(true);
|
||||
});
|
||||
|
||||
test('isBST when variant is Max', () => {
|
||||
const bst = new BST<number, number>([1, 2, 3, 9, 8, 5, 6, 7, 4], { variant: BSTVariant.INVERSE });
|
||||
bst.addMany([1, 2, 3, 9, 8, 5, 6, 7, 4]);
|
||||
expect(bst.isBST()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('BST Performance test', function () {
|
||||
const bst = new BST<number, number>();
|
||||
const inputSize = 10000; // Adjust input sizes as needed
|
||||
|
|
Loading…
Reference in a new issue