From b759eecf59035c24abdb81fc5a27ba4a1b5854c7 Mon Sep 17 00:00:00 2001 From: Revone Date: Mon, 2 Dec 2024 14:32:43 +1300 Subject: [PATCH] feat: Allow BinaryTree to support adding duplicate keys. docs: BinaryTree --- README.md | 2 +- .../binary-tree/binary-tree.ts | 25 ++++--- .../binary-tree/binary-tree.ts | 1 + src/types/data-structures/binary-tree/bst.ts | 2 +- .../binary-tree/binary-tree.test.ts | 66 +++++++++++++++++++ 5 files changed, 86 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 75092f0..4bb2c9d 100644 --- a/README.md +++ b/README.md @@ -1017,7 +1017,7 @@ pnpm perf:rbtree Counter - LinkedHashMap<K, V> + ES6 Map<K, V> - LinkedHashMap<K, V> OrderedDict diff --git a/src/data-structures/binary-tree/binary-tree.ts b/src/data-structures/binary-tree/binary-tree.ts index 892d434..de27a58 100644 --- a/src/data-structures/binary-tree/binary-tree.ts +++ b/src/data-structures/binary-tree/binary-tree.ts @@ -152,9 +152,10 @@ export class BinaryTree(); get store() { @@ -356,8 +363,8 @@ export class BinaryTree> | NodePredicate> | Range} - * keyNodeEntryOrPredicate - The `keyNodeEntryOrPredicate` parameter in the `isRange` function can be + * @param {BTNRep> | NodePredicate> | Range} keyNodeEntryOrPredicate + * - The `keyNodeEntryOrPredicate` parameter in the `isRange` function can be * of type `BTNRep>`, `NodePredicate>`, or * `Range`. The function checks if the `keyNodeEntry * @returns The `isRange` function is checking if the `keyNodeEntryOrPredicate` parameter is an @@ -461,11 +468,13 @@ export class BinaryTree = { iterationType?: IterationType; toEntryFn?: ToEntryFn; isMapMode?: boolean; + isDuplicate?: boolean; } export type BinaryTreePrintOptions = { isShowUndefined?: boolean; isShowNull?: boolean; isShowRedBlackNIL?: boolean }; diff --git a/src/types/data-structures/binary-tree/bst.ts b/src/types/data-structures/binary-tree/bst.ts index dac6932..1b4f741 100644 --- a/src/types/data-structures/binary-tree/bst.ts +++ b/src/types/data-structures/binary-tree/bst.ts @@ -2,7 +2,7 @@ import type { BinaryTreeOptions } from './binary-tree'; import { Comparable } from '../../utils'; import { OptValue } from '../../common'; -export type BSTOptions = BinaryTreeOptions & { +export type BSTOptions = Omit, 'isDuplicate'> & { specifyComparable?: (key: K) => Comparable isReverse?: boolean; } diff --git a/test/unit/data-structures/binary-tree/binary-tree.test.ts b/test/unit/data-structures/binary-tree/binary-tree.test.ts index 382ea30..c1c8d8e 100644 --- a/test/unit/data-structures/binary-tree/binary-tree.test.ts +++ b/test/unit/data-structures/binary-tree/binary-tree.test.ts @@ -1434,3 +1434,69 @@ describe('BinaryTree not map mode iterative methods test', () => { expect(cloned.get(cloned.root?.right)).toBe('c'); }); }); + +describe('classic use', () => { + it('@example determine loan approval using a decision tree', () => { + // Decision tree structure + const loanDecisionTree = new BinaryTree( + ['stableIncome', 'goodCredit', 'Rejected', 'Approved', 'Rejected'], + { isDuplicate: true } + ); + + function determineLoanApproval( + node?: BinaryTreeNode | null, + conditions?: { [key: string]: boolean } + ): string { + if (!node) throw new Error('Invalid node'); + + // If it's a leaf node, return the decision result + if (!node.left && !node.right) return node.key; + + // Check if a valid condition exists for the current node's key + return conditions?.[node.key] + ? determineLoanApproval(node.left, conditions) + : determineLoanApproval(node.right, conditions); + } + + // Test case 1: Stable income and good credit score + expect(determineLoanApproval(loanDecisionTree.root, { stableIncome: true, goodCredit: true })).toBe('Approved'); + + // Test case 2: Stable income but poor credit score + expect(determineLoanApproval(loanDecisionTree.root, { stableIncome: true, goodCredit: false })).toBe('Rejected'); + + // Test case 3: No stable income + expect(determineLoanApproval(loanDecisionTree.root, { stableIncome: false, goodCredit: true })).toBe('Rejected'); + + // Test case 4: No stable income and poor credit score + expect(determineLoanApproval(loanDecisionTree.root, { stableIncome: false, goodCredit: false })).toBe('Rejected'); + }); + + it('@example evaluate the arithmetic expression represented by the binary tree', () => { + const expressionTree = new BinaryTree(['+', 3, '*', null, null, 5, '-', null, null, 2, 8]); + + function evaluate(node?: BinaryTreeNode | null): number { + if (!node) return 0; + + if (typeof node.key === 'number') return node.key; + + const leftValue = evaluate(node.left); // Evaluate the left subtree + const rightValue = evaluate(node.right); // Evaluate the right subtree + + // Perform the operation based on the current node's operator + switch (node.key) { + case '+': + return leftValue + rightValue; + case '-': + return leftValue - rightValue; + case '*': + return leftValue * rightValue; + case '/': + return rightValue !== 0 ? leftValue / rightValue : 0; // Handle division by zero + default: + throw new Error(`Unsupported operator: ${node.key}`); + } + } + + expect(evaluate(expressionTree.root)).toBe(-27); + }); +});