data-structure-typed
Version:
Standard data structure
1,487 lines (1,273 loc) • 47.8 kB
text/typescript
import { BinaryTree, BinaryTreeNode, BTNEntry } from '../../../../src';
import { getRandomIntArray } from '../../../utils';
// import { isDebugTest } from '../../../config';
// const isDebug = isDebugTest;
describe('BinaryTreeNode', () => {
it('should create an instance of BinaryTreeNode', () => {
const node = new BinaryTreeNode<number>(1);
expect(node).toBeInstanceOf(BinaryTreeNode);
});
it('should set and get the ID correctly', () => {
const node = new BinaryTreeNode<number>(1);
expect(node.key).toBe(1);
node.key = 2;
expect(node.key).toBe(2);
});
it('should set and get the value correctly', () => {
const node: BinaryTreeNode<number> = new BinaryTreeNode<number>(1, 42);
expect(node.key).toBe(1);
expect(node.value).toBe(42);
node.value = 55;
expect(node.value).toBe(55);
});
it('should set and get the left child correctly', () => {
const node1 = new BinaryTreeNode<number>(1);
const node2 = new BinaryTreeNode<number>(2);
node1.left = node2;
expect(node1.left).toBe(node2);
expect(node2.parent).toBe(node1);
});
it('should set and get the right child correctly', () => {
const node1 = new BinaryTreeNode<number>(1);
const node2 = new BinaryTreeNode<number>(2);
node1.right = node2;
expect(node1.right).toBe(node2);
expect(node2.parent).toBe(node1);
});
it('should set and get the parent correctly', () => {
const node1 = new BinaryTreeNode<number>(1);
const node2 = new BinaryTreeNode<number>(2);
node1.left = node2;
expect(node2.parent).toBe(node1);
expect(node1.left).toBe(node2);
});
it('should determine family position correctly', () => {
const root = new BinaryTreeNode<number>(1);
const leftChild = new BinaryTreeNode<number>(2);
const rightChild = new BinaryTreeNode<number>(3);
root.left = leftChild;
root.right = rightChild;
expect(leftChild.familyPosition).toBe('LEFT');
leftChild.right = new BinaryTreeNode<number>(4);
expect(rightChild.familyPosition).toBe('RIGHT');
expect(root.familyPosition).toBe('ROOT');
expect(leftChild.familyPosition).toBe('ROOT_LEFT');
rightChild.left = new BinaryTreeNode<number>(5);
expect(rightChild.familyPosition).toBe('ROOT_RIGHT');
});
it('should determine only right child family position correctly', () => {
const root = new BinaryTreeNode<number>(1);
const rightChild = new BinaryTreeNode<number>(3);
const isolated = new BinaryTreeNode<number>(2);
root.right = rightChild;
expect(rightChild.familyPosition).toBe('RIGHT');
expect(isolated.familyPosition).toBe('ISOLATED');
expect(root.familyPosition).toBe('ROOT');
});
});
describe('BinaryTree addMany', () => {
it('should addMany', () => {
const binTree = new BinaryTree<number, number, { id: number; name: number }>([], {
toEntryFn: ({ id, name }) => [id, name]
});
binTree.addMany(
[
{ id: 1, name: 1 },
{ id: 2, name: 2 },
{ id: 4, name: 4 },
{ id: 3, name: 3 }
],
[undefined, 22, 44, 33]
);
expect(binTree.get(2)).toBe(22);
expect(binTree.get(binTree.getNode(3))).toBe(33);
expect(binTree.get(binTree.getNode(4))).toBe(44);
expect(binTree.get(binTree.getNode(1))).toBe(1);
});
it('should addMany undefined and null', () => {
const binaryTree = new BinaryTree<number, string>();
const addManyWithUndefined = binaryTree.addMany([1, undefined, 3]);
expect(addManyWithUndefined).toEqual([true, false, true]);
expect(binaryTree.get(undefined)).toBe(undefined);
const addManyWithNull = binaryTree.addMany([1, null, 3, 4]);
expect(addManyWithNull).toEqual([true, true, true, true]);
const addManyEntriesWithNull = binaryTree.addMany([
[1, '1'],
[null, 'null'],
[3, '3'],
[4, '4']
]);
expect(addManyEntriesWithNull).toEqual([true, true, true, true]);
expect(binaryTree.get(null)).toBe(undefined);
expect(binaryTree.getNode(null)).toBe(undefined);
// // TODO should be null instead of undefined
// expect(binaryTree.getNode(null)).toBe(null);
const node0 = binaryTree.add(0, '0');
expect(node0).toBe(true);
expect(binaryTree.get(0)).toBe('0');
});
});
describe('BinaryTree', () => {
let binTree: BinaryTree<number>;
beforeEach(() => {
binTree = new BinaryTree<number>();
});
afterEach(() => {
binTree.clear();
});
it('should add a node', () => {
const node = binTree.add(1);
expect(node).not.toBeNull();
expect(binTree.size).toBe(1);
});
it('should delete nodes', () => {
expect(binTree.getHeight(binTree.root, 'ITERATIVE')).toBe(-1);
expect(binTree.getMinHeight()).toBe(-1);
const node1 = binTree.createNode(1);
binTree.add(node1);
expect(binTree.size).toBe(1);
const leftChild = new BinaryTreeNode<number>(2);
const rightChild = new BinaryTreeNode<number>(3);
binTree.add(leftChild);
binTree.add(rightChild);
const root = binTree.root;
expect(leftChild.familyPosition).toBe('LEFT');
binTree.add(null);
binTree.add(new BinaryTreeNode<number>(4));
expect(rightChild.familyPosition).toBe('RIGHT');
expect(root?.familyPosition).toBe('ROOT');
expect(leftChild.familyPosition).toBe('ROOT_LEFT');
binTree.add(new BinaryTreeNode<number>(5));
expect(rightChild.familyPosition).toBe('ROOT_RIGHT');
binTree.delete(new BinaryTreeNode<number>(200));
binTree.delete(rightChild);
if (node1) {
const result = binTree.delete(node1);
expect(result).toHaveLength(1);
expect(binTree.size).toBe(4);
expect(binTree.getMinHeight(binTree.root, 'RECURSIVE')).toBe(1);
}
});
it('should add and find nodes', () => {
binTree.add([1, 1]);
binTree.add(undefined);
binTree.add([2, 2]);
binTree.add([3, 3]);
expect(binTree.has(1)).toBe(true);
expect(binTree.has(2)).toBe(true);
expect(binTree.has(3)).toBe(true);
expect(binTree.has(4)).toBe(false);
const node4 = binTree.getNode(4);
expect(binTree.has(node4)).toBe(false);
expect(binTree.has(node => node === node4)).toBe(false);
expect(binTree.has(node => node.key?.toString() === '3')).toBe(true);
});
it('should the clone method work fine', () => {
expect(binTree.isEmpty()).toBe(true);
binTree.addMany([4, 2, 6, null, 1, 3, null, 5, null, 7]);
expect(binTree.root?.key).toBe(4);
expect(binTree.root?.left?.key).toBe(2);
expect(binTree.root?.left?.left).toBe(null);
expect(binTree.root?.left?.right?.key).toBe(1);
expect(binTree.root?.right?.key).toBe(6);
expect(binTree.root?.right?.left?.key).toBe(3);
expect(binTree.root?.right?.right).toBe(null);
const cloned = binTree.clone();
expect(cloned.root?.key).toBe(4);
expect(cloned.root?.left?.key).toBe(2);
expect(cloned.root?.left?.left).toBe(null);
expect(cloned.root?.left?.right?.key).toBe(1);
expect(cloned.root?.right?.key).toBe(6);
expect(cloned.root?.right?.left?.key).toBe(3);
expect(cloned.root?.right?.right).toBe(null);
expect(cloned.dfs(node => node.key, 'PRE', false, cloned.getNode(6), 'ITERATIVE')).toEqual([6, 3, 7]);
expect(cloned.dfs(node => (node ? node.key : null), 'PRE', false, cloned.getNode(6), 'ITERATIVE', true)).toEqual([
6,
3,
7,
null
]);
expect(cloned.dfs(node => (node ? node.key : node), 'PRE', false, cloned.getNode(6), 'ITERATIVE', true)).toEqual([
6,
3,
7,
null
]);
expect(cloned.dfs(node => (node ? node.key : null), 'PRE', false, cloned.getNode(6), 'RECURSIVE', true)).toEqual([
6,
3,
7,
null
]);
cloned.delete(6);
cloned.delete(3);
cloned.delete(7);
cloned.delete(1);
cloned.delete(5);
cloned.delete(4);
cloned.delete(2);
// cloned.delete(null);
// cloned.delete(null);
// cloned.delete(null);
expect(binTree.size).toBe(10);
expect(cloned.size).toBe(3);
// expect(cloned.size).toBe(0);
// expect(cloned.isEmpty()).toBe(true);
});
it('should be a balance binTree after malicious manipulation', () => {
binTree.add(3);
binTree.add(12);
binTree.addMany(getRandomIntArray(100, 1, 100));
binTree.add(10);
expect(binTree.isPerfectlyBalanced()).toBe(true);
const node3 = binTree.getNode(3);
if (node3) node3.right = binTree.createNode(1);
expect(binTree.isPerfectlyBalanced()).toBe(false);
binTree.clear();
binTree.addMany([1, null, 2, null, 3, null, 4, null, 5, null, 6, null]);
expect(binTree.isPerfectlyBalanced()).toBe(false);
});
it('should getDepth return correct depth', () => {
binTree.add(1);
expect(binTree.getDepth(1)).toBe(0);
binTree.add(2);
expect(binTree.getDepth(2)).toBe(1);
binTree.add(3);
expect(binTree.getDepth(3, 1)).toBe(1);
binTree.add(4);
expect(binTree.getDepth(4, 1)).toBe(2);
expect(binTree.getDepth(4)).toBe(2);
expect(binTree.getDepth(4, 2)).toBe(1);
});
it('should traverse in-order', () => {
binTree.add(null);
binTree.delete(1);
expect(binTree.getHeight()).toBe(-1);
binTree.add(4);
binTree.add(2);
expect(binTree.getHeight()).toBe(1);
binTree.iterationType = 'RECURSIVE';
expect(binTree.getHeight()).toBe(1);
binTree.iterationType = 'ITERATIVE';
binTree.add(6);
binTree.add(1);
binTree.add(new BinaryTreeNode(3));
binTree.add(5);
binTree.add(7);
const inOrder = binTree.dfs(node => node.key);
expect(inOrder).toEqual([1, 2, 3, 4, 5, 6, 7]);
});
it('should isSubtreeBST', () => {
binTree.addMany([
new BinaryTreeNode(4, 4),
new BinaryTreeNode(2, 2),
new BinaryTreeNode(6, 6),
new BinaryTreeNode(1, 1),
new BinaryTreeNode(3, 3),
new BinaryTreeNode(5, 5),
new BinaryTreeNode(7, 7),
new BinaryTreeNode(4, 4)
]);
expect(binTree.isBST(binTree.getNode(4), 'RECURSIVE')).toBe(true);
expect(binTree.isBST(binTree.getNode(4), 'ITERATIVE')).toBe(true);
});
it('should isSubtreeBST', () => {
expect(binTree.toVisual()).toBe('');
binTree.addMany([4, 2, 6, 1, 3, 5, 7, 4]);
expect(binTree.toVisual()).toBe(
'N for null\n' +
' ___4___ \n' +
' / \\ \n' +
' _2_ _6_ \n' +
' / \\ / \\ \n' +
' 1 3 5 7 \n' +
' \n'
);
const visualized = binTree.toVisual(undefined, {
isShowUndefined: true,
isShowNull: true,
isShowRedBlackNIL: true
});
expect(visualized).toBe(
'U for undefined\n' +
'N for null\n' +
'S for Sentinel Node(NIL)\n' +
' _______4_______ \n' +
' / \\ \n' +
' ___2___ ___6___ \n' +
' / \\ / \\ \n' +
' _1_ _3_ _5_ _7_ \n' +
' / \\ / \\ / \\ / \\ \n' +
' U U U U U U U U \n' +
' \n'
);
expect(binTree.isBST(binTree.getNode(4), 'RECURSIVE')).toBe(true);
expect(binTree.isBST(binTree.getNode(4), 'ITERATIVE')).toBe(true);
expect(binTree.getNodes(2, false, null)).toEqual([]);
expect(binTree.getNodes(undefined)).toEqual([]);
expect(binTree.getNodes(binTree.getNode(2), false, binTree.root)).toEqual([binTree.getNode(2)]);
});
describe('should isValidKey', () => {
describe('primitive types', () => {
it('numbers should be a key', () => {
expect(binTree.isValidKey(42)).toBe(true);
expect(binTree.isValidKey(0)).toBe(true);
expect(binTree.isValidKey(-1)).toBe(true);
expect(binTree.isValidKey(Infinity)).toBe(true);
expect(binTree.isValidKey(-Infinity)).toBe(true);
});
// it('NaN should not be a key', () => {
// expect(binTree.isValidKey(NaN)).toBe(false);
// });
it('strings should be a key', () => {
expect(binTree.isValidKey('hello')).toBe(true);
expect(binTree.isValidKey('')).toBe(true);
expect(binTree.isValidKey('123')).toBe(true);
});
it('BigInt should be a key', () => {
expect(binTree.isValidKey(BigInt(42))).toBe(true);
expect(binTree.isValidKey(BigInt(0))).toBe(true);
expect(binTree.isValidKey(BigInt(-1))).toBe(true);
});
it('boolean should not be a key', () => {
expect(binTree.isValidKey(true)).toBe(true);
expect(binTree.isValidKey(false)).toBe(true);
});
it('null and undefined should not be a key', () => {
expect(binTree.isValidKey(null)).toBe(true);
expect(binTree.isValidKey(undefined)).toBe(false);
});
it('symbols should not be a key', () => {
expect(binTree.isValidKey(Symbol('test'))).toBe(false);
expect(binTree.isValidKey(Symbol.for('test'))).toBe(false);
});
});
describe('Date objects', () => {
it('valid Date objects should be a key', () => {
expect(binTree.isValidKey(new Date())).toBe(true);
expect(binTree.isValidKey(new Date('2024-01-01'))).toBe(true);
});
// it('invalid Date objects should not be a key', () => {
// expect(binTree.isValidKey(new Date('invalid'))).toBe(false);
// });
});
describe('arrays', () => {
it('arrays should be a key as they convert to string', () => {
expect(binTree.isValidKey([])).toBe(true);
expect(binTree.isValidKey([1, 2, 3])).toBe(true);
expect(binTree.isValidKey(['a', 'b', 'c'])).toBe(true);
});
});
describe('plain objects', () => {
it('plain objects should not be a key', () => {
expect(binTree.isValidKey({})).toBe(false);
expect(binTree.isValidKey({ a: 1 })).toBe(false);
});
});
describe('custom objects', () => {
it('objects with numeric valueOf should be a key', () => {
expect(binTree.isValidKey({ valueOf: () => 42 })).toBe(true);
});
it('objects with string valueOf should be a key', () => {
expect(binTree.isValidKey({ valueOf: () => 'test' })).toBe(true);
});
it('objects with boolean valueOf should not be a key', () => {
expect(binTree.isValidKey({ valueOf: () => true })).toBe(true);
});
it('objects with nested valueOf/toString should be a key', () => {
expect(
binTree.isValidKey({
valueOf: () => ({ toString: () => '42' })
})
).toBe(true);
});
});
describe('deeply nested objects', () => {
it('objects with deeply nested valueOf should be a key', () => {
const deeplyNested = {
valueOf: () => ({
valueOf: () => 42
})
};
expect(binTree.isValidKey(deeplyNested)).toBe(true);
});
it('objects with very deeply nested conversion should be a key', () => {
const veryDeeplyNested = {
valueOf: () => ({
valueOf: () => ({
toString: () => '42'
})
})
};
expect(binTree.isValidKey(veryDeeplyNested)).toBe(true);
});
it('objects with circular references should not be a key', () => {
const circular: any = {
valueOf: () => circular
};
expect(binTree.isValidKey(circular)).toBe(false);
});
});
describe('edge cases', () => {
it('objects returning non-primitive values should be handled correctly', () => {
const complexObject = {
valueOf: () => ({
toString: () => ({
valueOf: () => 'valid'
})
})
};
expect(binTree.isValidKey(complexObject)).toBe(false);
});
it('objects returning primitive values should be handled correctly', () => {
const complexObject = {
valueOf: () => ({
valueOf: () => ({
valueOf: () => ({
valueOf: () => ({
toString: () => `{
valueOf: () => 'valid'
}`
})
})
})
})
};
expect(binTree.isValidKey(complexObject)).toBe(true);
});
});
describe('type checking', () => {
it('should work with type guard in array methods', () => {
const values: unknown[] = [42, 'test', true, null, undefined, new Date()];
const comparableValues = values.filter(item => binTree.isValidKey(item));
expect(comparableValues.length).toBe(5);
});
});
});
it('should isLeaf', () => {
expect(binTree.getLeftMost()).toBe(undefined);
expect(binTree.getRightMost()).toBe(undefined);
binTree.addMany([4, 2, 6, 1, 3, 5, 7, 4]);
const leftMost = binTree.getLeftMost();
expect(binTree.isLeaf(leftMost)).toBe(true);
expect(binTree.isLeaf(null)).toBe(true);
const rightMost = binTree.getRightMost();
expect(binTree.isLeaf(rightMost)).toBe(true);
expect(binTree.isLeaf(null)).toBe(true);
});
it('should binTree traverse', () => {
expect(binTree.dfs()).toEqual([]);
expect([...binTree.values()]).toEqual([]);
binTree.addMany([4, 2, 6, null, 1, 3, null, 5, null, 7]);
expect(binTree.dfs(node => node.key, 'PRE', false, undefined, 'ITERATIVE')).toEqual([4, 2, 1, 5, 6, 3, 7]);
expect(binTree.dfs(node => (node !== null ? node.key : null), 'PRE', false, undefined, 'ITERATIVE', false)).toEqual(
[4, 2, 1, 5, 6, 3, 7]
);
expect(binTree.dfs(node => (node !== null ? node.key : null), 'PRE', false, undefined, 'ITERATIVE', true)).toEqual([
4,
2,
null,
1,
5,
null,
6,
3,
7,
null
]);
expect(binTree.dfs(node => node.key, 'PRE', false, undefined, 'RECURSIVE')).toEqual([4, 2, 1, 5, 6, 3, 7]);
expect(binTree.dfs(node => (node !== null ? node.key : null), 'PRE', false, undefined, 'RECURSIVE', false)).toEqual(
[4, 2, 1, 5, 6, 3, 7]
);
expect(binTree.dfs(node => (node !== null ? node.key : null), 'PRE', false, undefined, 'RECURSIVE', true)).toEqual([
4,
2,
null,
1,
5,
null,
6,
3,
7,
null
]);
expect(binTree.dfs(node => node.key, 'IN', false, undefined, 'ITERATIVE')).toEqual([2, 5, 1, 4, 7, 3, 6]);
expect(binTree.dfs(node => (node !== null ? node.key : null), 'IN', false, undefined, 'ITERATIVE', false)).toEqual([
2, 5, 1, 4, 7, 3, 6
]);
expect(binTree.dfs(node => (node !== null ? node.key : null), 'IN', false, undefined, 'ITERATIVE', true)).toEqual([
null,
2,
5,
1,
null,
4,
7,
3,
6,
null
]);
expect(binTree.dfs(node => node.key, 'IN', false, undefined, 'RECURSIVE')).toEqual([2, 5, 1, 4, 7, 3, 6]);
expect(binTree.dfs(node => (node !== null ? node.key : null), 'IN', false, undefined, 'RECURSIVE', false)).toEqual([
2, 5, 1, 4, 7, 3, 6
]);
expect(binTree.dfs(node => (node !== null ? node.key : null), 'IN', false, undefined, 'RECURSIVE', true)).toEqual([
null,
2,
5,
1,
null,
4,
7,
3,
6,
null
]);
expect(binTree.dfs(node => node.key, 'POST', false, undefined, 'ITERATIVE')).toEqual([5, 1, 2, 7, 3, 6, 4]);
expect(
binTree.dfs(node => (node !== null ? node.key : null), 'POST', false, undefined, 'ITERATIVE', false)
).toEqual([5, 1, 2, 7, 3, 6, 4]);
expect(binTree.dfs(node => (node !== null ? node.key : null), 'POST', false, undefined, 'ITERATIVE', true)).toEqual(
[null, 5, null, 1, 2, 7, 3, null, 6, 4]
);
expect(binTree.dfs(node => node.key, 'POST', false, undefined, 'RECURSIVE')).toEqual([5, 1, 2, 7, 3, 6, 4]);
expect(
binTree.dfs(node => (node !== null ? node.key : null), 'POST', false, undefined, 'RECURSIVE', false)
).toEqual([5, 1, 2, 7, 3, 6, 4]);
expect(binTree.dfs(node => (node !== null ? node.key : null), 'POST', false, undefined, 'RECURSIVE', true)).toEqual(
[null, 5, null, 1, 2, 7, 3, null, 6, 4]
);
});
it('should sub binTree traverse', () => {
binTree.addMany([4, 2, 6, null, 1, 3, null, 5, null, 7]);
expect(binTree.dfs(node => node.key, 'PRE', false, binTree.getNode(6), 'ITERATIVE')).toEqual([6, 3, 7]);
expect(
binTree.dfs(node => (node !== null ? node.key : null), 'PRE', false, binTree.getNode(6), 'ITERATIVE', false)
).toEqual([6, 3, 7]);
expect(
binTree.dfs(node => (node !== null ? node.key : null), 'PRE', false, binTree.getNode(6), 'ITERATIVE', true)
).toEqual([6, 3, 7, null]);
expect(binTree.dfs(node => node.key, 'PRE', false, binTree.getNode(6), 'RECURSIVE')).toEqual([6, 3, 7]);
expect(
binTree.dfs(node => (node !== null ? node.key : null), 'PRE', false, binTree.getNode(6), 'RECURSIVE', false)
).toEqual([6, 3, 7]);
expect(
binTree.dfs(node => (node !== null ? node.key : null), 'PRE', false, binTree.getNode(6), 'RECURSIVE', true)
).toEqual([6, 3, 7, null]);
expect(binTree.dfs(node => node.key, 'IN', false, binTree.getNode(6), 'ITERATIVE')).toEqual([7, 3, 6]);
expect(
binTree.dfs(node => (node !== null ? node.key : null), 'IN', false, binTree.getNode(6), 'ITERATIVE', false)
).toEqual([7, 3, 6]);
expect(
binTree.dfs(node => (node !== null ? node.key : null), 'IN', false, binTree.getNode(6), 'ITERATIVE', true)
).toEqual([7, 3, 6, null]);
expect(binTree.dfs(node => node.key, 'IN', false, binTree.getNode(6), 'RECURSIVE')).toEqual([7, 3, 6]);
expect(
binTree.dfs(node => (node !== null ? node.key : null), 'IN', false, binTree.getNode(6), 'RECURSIVE', false)
).toEqual([7, 3, 6]);
expect(
binTree.dfs(node => (node !== null ? node.key : null), 'IN', false, binTree.getNode(6), 'RECURSIVE', true)
).toEqual([7, 3, 6, null]);
expect(binTree.dfs(node => node.key, 'POST', false, binTree.getNode(6), 'ITERATIVE')).toEqual([7, 3, 6]);
expect(
binTree.dfs(node => (node !== null ? node.key : null), 'POST', false, binTree.getNode(6), 'ITERATIVE', false)
).toEqual([7, 3, 6]);
expect(
binTree.dfs(node => (node !== null ? node.key : null), 'POST', false, binTree.getNode(6), 'ITERATIVE', true)
).toEqual([7, 3, null, 6]);
expect(binTree.dfs(node => node.key, 'POST', false, binTree.getNode(6), 'RECURSIVE')).toEqual([7, 3, 6]);
expect(
binTree.dfs(node => (node !== null ? node.key : null), 'POST', false, binTree.getNode(6), 'RECURSIVE', false)
).toEqual([7, 3, 6]);
expect(
binTree.dfs(node => (node !== null ? node.key : null), 'POST', false, binTree.getNode(6), 'RECURSIVE', true)
).toEqual([7, 3, null, 6]);
});
it('should clear the binTree', () => {
binTree.add(1);
binTree.add(2);
expect(binTree.size).toBe(2);
binTree.clear();
expect(binTree.size).toBe(0);
expect(binTree.root).toBeUndefined();
});
it('should duplicated nodes just replace the node exists', function () {
binTree.clear();
expect(binTree.bfs()).toEqual([]);
binTree.addMany([-10, -10, -10, 9, 9, 20, null, null, 15, 7, 8, null, 2, null, 6, null, null, 8, 8, 8]);
expect(binTree.bfs(node => (node ? node.key : null), undefined, undefined, true)).toEqual([
-10,
9,
20,
null,
null,
15,
7,
8,
null,
2,
null,
6,
null,
null
]);
});
// it('should keyValueNodeEntryRawToNodeAndValue', () => {
// const binTree = new BinaryTree<number>();
// const node0 = binTree.keyValueNodeEntryRawToNodeAndValue(0);
// expect(node0).toEqual([
// {
// _left: undefined,
// _right: undefined,
// key: 0,
// parent: undefined,
// value: undefined
// },
// undefined
// ]);
//
// const nodeUndefined = binTree.keyValueNodeEntryRawToNodeAndValue(undefined);
// expect(nodeUndefined).toEqual([undefined, undefined]);
//
// const nodeNull = binTree.keyValueNodeEntryRawToNodeAndValue(null);
// expect(nodeNull).toEqual([null, undefined]);
//
// const [, nodeWithSeparateValue] = binTree.keyValueNodeEntryRawToNodeAndValue(7, 77);
// expect(nodeWithSeparateValue).toBe(77);
//
// expect(binTree.keyValueNodeEntryRawToNodeAndValue([undefined, 2])).toEqual([undefined, undefined]);
//
// expect(binTree.keyValueNodeEntryRawToNodeAndValue(Symbol('test') as unknown as number)).toEqual([
// undefined,
// undefined
// ]);
//
// const bTree = new BinaryTree<number, number, { obj: { id: number } }>([], {
// toEntryFn: (ele: { obj: { id: number } }) => [Symbol('test') as unknown as number, ele.obj.id]
// });
// expect(bTree.keyValueNodeEntryRawToNodeAndValue({ obj: { id: 1 } })).toEqual([undefined, undefined]);
// });
it('should replace value', () => {
const binTree = new BinaryTree<number, string>([4, 5, [1, '1'], 2, 3], { isMapMode: false });
expect(binTree.get(1)).toBe('1');
expect(binTree.getNode(1)?.value).toBe('1');
binTree.add(1, 'a');
expect(binTree.get(1)).toBe('a');
binTree.add([1, 'b']);
expect(binTree.getNode(1)?.value).toBe('b');
expect(binTree.get(1)).toBe('b');
const treeMap = new BinaryTree<number>([4, 5, [1, '1'], 2, 3]);
expect(treeMap.get(1)).toBe('1');
expect(treeMap.getNode(1)?.value).toBe(undefined);
treeMap.add(1, 'a');
expect(treeMap.get(1)).toBe('a');
treeMap.add([1, 'b']);
expect(treeMap.getNode(1)?.value).toBe(undefined);
expect(treeMap.get(1)).toBe('b');
});
});
describe('BinaryTree ensureNode', () => {
it('should ensureNode with toEntryFn', () => {
const binTree = new BinaryTree<
number,
string,
{
id: number;
name: string;
}
>([], { toEntryFn: rawElement => [rawElement.id, rawElement.name] });
binTree.add([1, 'Pablo']);
const node = binTree.getNode(1);
// expect(binTree.ensureNode({ id: 1, name: 'Pablo' })).toBe(node);
expect(binTree.ensureNode([1, 'Pablo'])).toBe(node);
expect(binTree.ensureNode([null, 'Pablo'])).toBe(null);
expect(binTree.ensureNode([undefined, 'Pablo'])).toBe(undefined);
expect(binTree.ensureNode(Symbol('test') as unknown as number)).toBe(undefined);
});
});
describe('BinaryTree Morris Traversal', () => {
// Create a binary binTree
const binTree = new BinaryTree<number>();
binTree.add(1);
binTree.add(2);
binTree.add(3);
binTree.add(4);
binTree.add(5);
it('should perform in-order Morris traversal correctly as dfs traversal', () => {
// Perform in-order Morris traversal
const result = binTree.morris(node => node.key, 'IN');
// Expected in-order traversal result
const expected = [4, 2, 5, 1, 3];
expect(result).toEqual(expected);
expect(binTree.dfs(node => node.key, 'IN')).toEqual(expected);
expect(binTree.dfs(node => node.key, 'IN', false, binTree.root, 'RECURSIVE')).toEqual(expected);
});
it('should perform pre-order Morris traversal correctly as dfs traversal', () => {
// Perform pre-order Morris traversal
const result = binTree.morris(node => node.key, 'PRE');
// Expected pre-order traversal result
const expected = [1, 2, 4, 5, 3];
expect(result).toEqual(expected);
expect(binTree.dfs(node => node.key, 'PRE')).toEqual(expected);
});
it('should perform post-order Morris traversal correctly as dfs traversal', () => {
// Perform post-order Morris traversal
const result = binTree.morris(node => node.key, 'POST');
// Expected post-order traversal result
const expected = [4, 5, 2, 3, 1];
expect(result).toEqual([4, 5, 2, 3, 1]);
expect(binTree.dfs(node => node.key, 'POST')).toEqual(expected);
});
it('after morris traversals should the structure of the binTree be correct', () => {
const node1 = binTree.getNode(1);
const node2 = binTree.getNode(2);
const node3 = binTree.getNode(3);
expect(node1?.left).toBe(node2);
expect(node1?.right).toBe(node3);
});
});
describe('BinaryTree toEntryFn', () => {
it('should toEntryFn throw', () => {
expect(() => {
new BinaryTree<number, number, { obj: { id: number } }>([], {
toEntryFn: `ele => [ele.obj.id, ele.obj.id]` as unknown as (rawElement: {
obj: { id: number };
}) => BTNEntry<number, number>
});
}).toThrow('toEntryFn must be a function type');
});
it('should toEntryFn with add', () => {
const binTree = new BinaryTree<number, number, { obj: { id: number } }>([], {
toEntryFn: ele => [ele.obj.id, ele.obj.id]
});
binTree.addMany([
{ obj: { id: 1 } },
{ obj: { id: 2 } },
{ obj: { id: 3 } },
{ obj: { id: 4 } },
{ obj: { id: 5 } }
]);
const expected = [4, 2, 5, 1, 3];
expect(binTree.morris(node => node.key, 'IN')).toEqual(expected);
expect(binTree.dfs(node => node.key, 'IN')).toEqual(expected);
expect(binTree.dfs(node => node.key, 'IN', false, binTree.root, 'RECURSIVE')).toEqual(expected);
});
it('should toEntryFn with initial', () => {
const binTree = new BinaryTree<number, number, { obj: { id: number } }>(
[{ obj: { id: 1 } }, { obj: { id: 2 } }, { obj: { id: 3 } }, { obj: { id: 4 } }, { obj: { id: 5 } }],
{
toEntryFn: ele => [ele.obj.id, ele.obj.id]
}
);
const expected = [4, 2, 5, 1, 3];
expect(binTree.morris(node => node.key, 'IN')).toEqual(expected);
expect(binTree.dfs(node => node.key, 'IN')).toEqual(expected);
expect(binTree.dfs(node => node.key, 'IN', false, binTree.root, 'RECURSIVE')).toEqual(expected);
});
it('should no toEntryFn', () => {
const data = [
{ obj: { id: 4 }, valueOf: () => 4 },
{ obj: { id: 2 }, valueOf: () => 2 },
{ obj: { id: 5 }, valueOf: () => 5 },
{ obj: { id: 1 }, valueOf: () => 1 },
{ obj: { id: 3 }, valueOf: () => 3 }
];
const binTree = new BinaryTree<{ obj: { id: number }; valueOf: () => number }, number>(data);
expect(binTree.morris(node => node.key, 'IN')).toEqual(data.sort((a, b) => a.obj.id - b.obj.id));
expect(binTree.dfs(node => node.key, 'IN')).toEqual(data);
expect(binTree.dfs(node => node.key, 'IN', false, binTree.root, 'RECURSIVE')).toEqual(data);
});
});
describe('BinaryTree traversals', () => {
it('traversals', () => {
const binTree = new BinaryTree<number>();
const arr = [35, 20, 40, 15, 29, null, 50, null, 16, 28, 30, 45, 55];
binTree.refill(arr);
expect(binTree.bfs(node => node, binTree.root, 'ITERATIVE', true).map(node => (node ? node.key : null))).toEqual([
35,
20,
40,
15,
29,
null,
50,
null,
16,
28,
30,
45,
55
]);
expect(binTree.bfs(node => node, binTree.root, 'RECURSIVE', true).map(node => (node ? node.key : null))).toEqual([
35,
20,
40,
15,
29,
null,
50,
null,
16,
28,
30,
45,
55
]);
expect(binTree.bfs(node => node, binTree.root, 'ITERATIVE').map(node => (node === null ? null : node.key))).toEqual(
[35, 20, 40, 15, 29, 50, 16, 28, 30, 45, 55]
);
expect(binTree.bfs(node => node, binTree.root, 'RECURSIVE').map(node => (node === null ? null : node.key))).toEqual(
[35, 20, 40, 15, 29, 50, 16, 28, 30, 45, 55]
);
expect(binTree.dfs(node => node.key, 'PRE')).toEqual([35, 20, 15, 16, 29, 28, 30, 40, 50, 45, 55]);
expect(binTree.dfs(node => node.key, 'PRE', false, binTree.root, 'RECURSIVE')).toEqual([
35, 20, 15, 16, 29, 28, 30, 40, 50, 45, 55
]);
expect(
binTree
.dfs(node => node, 'PRE', false, binTree.root, 'ITERATIVE', true)
.map(node => (node === null ? null : node.key))
).toEqual([35, 20, 15, null, 16, 29, 28, 30, 40, null, 50, 45, 55]);
expect(
binTree.dfs(node => node, 'PRE', false, binTree.root, 'RECURSIVE', true).map(node => (node ? node.key : null))
).toEqual([35, 20, 15, null, 16, 29, 28, 30, 40, null, 50, 45, 55]);
expect(binTree.dfs(node => node.key, 'IN')).toEqual([15, 16, 20, 28, 29, 30, 35, 40, 45, 50, 55]);
expect(binTree.dfs(node => node.key, 'POST')).toEqual([16, 15, 28, 30, 29, 20, 45, 55, 50, 40, 35]);
expect(binTree.dfs(node => node.key, 'POST', false, binTree.root, 'RECURSIVE')).toEqual([
16, 15, 28, 30, 29, 20, 45, 55, 50, 40, 35
]);
expect(binTree.bfs(node => node.key, binTree.root, 'RECURSIVE')).toEqual([
35, 20, 40, 15, 29, 50, 16, 28, 30, 45, 55
]);
expect(binTree.bfs(node => node.key, binTree.root, 'ITERATIVE')).toEqual([
35, 20, 40, 15, 29, 50, 16, 28, 30, 45, 55
]);
expect(binTree.listLevels(node => node.key)).toEqual([[35], [20, 40], [15, 29, 50], [16, 28, 30, 45, 55]]);
expect(binTree.listLevels(node => node.key, binTree.root, 'RECURSIVE')).toEqual([
[35],
[20, 40],
[15, 29, 50],
[16, 28, 30, 45, 55]
]);
expect(binTree.listLevels(node => (node ? node.key : null), binTree.root, 'ITERATIVE', true)).toEqual([
[35],
[20, 40],
[15, 29, null, 50],
[null, 16, 28, 30, 45, 55]
]);
expect(binTree.listLevels(node => (node ? node.key : null), binTree.root, 'RECURSIVE', true)).toEqual([
[35],
[20, 40],
[15, 29, null, 50],
[null, 16, 28, 30, 45, 55]
]);
binTree.clear();
expect(binTree.listLevels()).toEqual([]);
});
});
describe('BinaryTree', () => {
let binTree: BinaryTree<number, string>;
beforeEach(() => {
binTree = new BinaryTree<number, string>([], {
iterationType: 'RECURSIVE'
});
});
afterEach(() => {
binTree.clear();
});
it('should create an empty BinaryTree', () => {
expect(binTree.size).toBe(0);
expect(binTree.isEmpty()).toBe(true);
expect(binTree.root).toBe(undefined);
});
it('should add nodes to the binTree', () => {
binTree.add([5, 'A']);
binTree.add([3, 'B']);
binTree.add([7, 'C']);
expect(binTree.size).toBe(3);
expect(binTree.isEmpty()).toBe(false);
expect(binTree.root?.key).toBe(5);
});
it('should clear the BinaryTree', () => {
binTree.add([5, 'A']);
binTree.add([3, 'B']);
binTree.add([7, 'C']);
binTree.clear();
expect(binTree.size).toBe(0);
expect(binTree.isEmpty()).toBe(true);
expect(binTree.root).toBe(undefined);
});
it('should get nodes by key', () => {
binTree.add([5, 'A']);
binTree.add([3, 'B']);
binTree.add([7, 'C']);
const nodeA = binTree.getNode(5);
const nodeB = binTree.getNode(3);
expect(nodeA?.key).toBe(5);
expect(nodeA?.value).toBe(undefined);
expect(nodeB?.key).toBe(3);
expect(binTree.get(nodeB)).toBe('B');
});
it('should return undefined when getting a non-existent node', () => {
binTree.add([5, 'A']);
const node = binTree.getNode(3);
expect(node).toBe(undefined);
});
it('should get the depth of a node', () => {
binTree.add([5, 'A']);
binTree.add([3, 'B']);
binTree.add([7, 'C']);
expect(binTree.getDepth(7)).toBe(1);
expect(binTree.getDepth(3)).toBe(1);
});
it('should get the height of the binTree', () => {
expect(binTree.getMinHeight()).toBe(-1);
binTree.add([5, 'A']);
binTree.add(3, 'B');
binTree.add([7, 'C']);
expect(binTree.getHeight()).toBe(1);
expect(binTree.getHeight(undefined, 'RECURSIVE')).toBe(1);
expect(binTree.getMinHeight(undefined, 'RECURSIVE')).toBe(1);
});
it('should check if the binTree is a binary search binTree', () => {
binTree.add([5, 'A']);
binTree.add([3, 'B']);
binTree.add([7, 'C']);
expect(binTree.isBST()).toBe(true);
});
it('should perform a depth-first traversal', () => {
binTree.add([5, 'A']);
binTree.add([3, 'B']);
binTree.add([7, 'C']);
const result = binTree.dfs();
expect(result).toEqual([3, 5, 7]);
// Add assertions for the result of depth-first traversal
});
it('should perform a breadth-first traversal', () => {
binTree.add([5, 'A']);
binTree.add([3, 'B']);
binTree.add([7, 'C']);
const result = binTree.bfs(node => node.key);
expect(result).toEqual([5, 3, 7]);
// Add assertions for the result of breadth-first traversal
});
it('should list levels of the binTree', () => {
binTree.add([5, 'A']);
binTree.add([3, 'B']);
binTree.add([7, 'C']);
const levels = binTree.listLevels();
expect(levels).toEqual([[5], [3, 7]]);
// Add assertions for the levels of the binTree
});
it('should delete nodes from the binTree', () => {
binTree.add([5, 'A']);
binTree.add([3, 'B']);
binTree.add([7, 'C']);
binTree.delete(3);
expect(binTree.size).toBe(2);
expect(binTree.getNode(3)).toBe(undefined);
});
it('should getPathToRoot', () => {
binTree.add([5, 'A']);
binTree.add([3, 'B']);
binTree.add([7, 'C']);
expect(binTree.getPathToRoot(7)).toEqual([7, 5]);
expect(binTree.getPathToRoot(1)).toEqual([]);
});
it('should check if the binTree is perfectly balanced', () => {
binTree.add([5, 'A']);
binTree.add([3, 'B']);
binTree.add([7, 'C']);
expect(binTree.isPerfectlyBalanced()).toBe(true);
});
it('should get nodes by a custom callback', () => {
binTree.add([5, 'E']);
binTree.add([4, 'D']);
binTree.add([3, 'C']);
binTree.add([7, 'G']);
binTree.add([null, 'null']);
binTree.add([1, 'A']);
binTree.add([6, 'F']);
binTree.add([null, 'null']);
binTree.add([2, 'B']);
binTree.add([null, 'null']);
const nodes = binTree.getNodes(node => node.key === 2);
expect(nodes.length).toBe(1);
expect(nodes[0].key).toBe(2);
const nodesRec = binTree.getNodes(node => node.key === 2, false, binTree.root, 'RECURSIVE');
expect(nodesRec.length).toBe(1);
expect(nodesRec[0].key).toBe(2);
const nodesItr = binTree.getNodes(node => node.key === 2, false, binTree.root, 'ITERATIVE');
expect(nodesItr.length).toBe(1);
expect(nodesItr[0].key).toBe(2);
expect(nodesItr).toEqual(nodesRec);
});
it('should perform Morris traversal', () => {
binTree.add([5, 'A']);
binTree.add([3, 'B']);
binTree.add([7, 'C']);
binTree.iterationType = 'ITERATIVE';
expect([...binTree]).toEqual([
[3, 'B'],
[5, 'A'],
[7, 'C']
]);
binTree.iterationType = 'RECURSIVE';
expect([...binTree]).toEqual([
[3, 'B'],
[5, 'A'],
[7, 'C']
]);
binTree.iterationType = 'ITERATIVE';
const result = binTree.morris();
expect(result).toEqual([3, 5, 7]);
binTree.clear();
expect(binTree.morris()).toEqual([]);
});
it('should perform delete all', () => {
binTree.add([5, 'A']);
binTree.add([3, 'B']);
binTree.add([7, 'C']);
binTree.delete(5);
binTree.delete(7);
binTree.delete(3);
expect(binTree.root).toBe(undefined);
expect(binTree.getHeight()).toBe(-1);
});
});
describe('BinaryTree not map mode', () => {
let binTree: BinaryTree<number, string>;
beforeEach(() => {
binTree = new BinaryTree<number, string>([], {
iterationType: 'RECURSIVE',
isMapMode: false
});
});
afterEach(() => {
binTree.clear();
});
it('should add and find nodes', () => {
binTree.add([1, '1']);
binTree.add(undefined);
binTree.add([2, '2']);
binTree.add([3, '3']);
expect(binTree.has(1)).toBe(true);
expect(binTree.has(2)).toBe(true);
expect(binTree.has(3)).toBe(true);
expect(binTree.has(4)).toBe(false);
const node4 = binTree.getNode(4);
expect(binTree.has(node4)).toBe(false);
expect(binTree.has(node => node === node4)).toBe(false);
expect(binTree.has(node => node.value?.toString() === '3')).toBe(true);
});
it('should isSubtreeBST', () => {
binTree.addMany([
new BinaryTreeNode(4),
new BinaryTreeNode(2),
new BinaryTreeNode(6),
new BinaryTreeNode(1),
new BinaryTreeNode(3),
new BinaryTreeNode(5),
new BinaryTreeNode(7),
new BinaryTreeNode(4)
]);
expect(binTree.isBST(binTree.getNode(4), 'RECURSIVE')).toBe(true);
expect(binTree.isBST(binTree.getNode(4), 'ITERATIVE')).toBe(true);
});
it('should get nodes by key', () => {
binTree.add([5, 'A']);
binTree.add([3, 'B']);
binTree.add([7, 'C']);
const nodeA = binTree.getNode(5);
const nodeB = binTree.getNode(3);
expect(nodeA?.key).toBe(5);
expect(binTree.get(nodeA)).toBe('A');
expect(nodeB?.key).toBe(3);
expect(binTree.get(nodeB)).toBe('B');
});
it('should get nodes by a custom callback', () => {
binTree.add([5, 'E']);
binTree.add([4, 'D']);
binTree.add([3, 'C']);
binTree.add([7, 'G']);
binTree.add([null, 'null']);
binTree.add([1, 'A']);
binTree.add([6, 'F']);
binTree.add([null, 'null']);
binTree.add([2, 'B']);
binTree.add([null, 'null']);
const nodes = binTree.getNodes(node => node.key === 2);
expect(nodes.length).toBe(1);
expect(nodes[0].key).toBe(2);
const nodesRec = binTree.getNodes(node => node.key === 2, false, binTree.root, 'RECURSIVE');
expect(nodesRec.length).toBe(1);
expect(nodesRec[0].key).toBe(2);
const nodesItr = binTree.getNodes(node => node.key === 2, false, binTree.root, 'ITERATIVE');
expect(nodesItr.length).toBe(1);
expect(nodesItr[0].key).toBe(2);
expect(nodesItr).toEqual(nodesRec);
});
});
describe('BinaryTree iterative methods test', () => {
let binaryTree: BinaryTree<number, string>;
beforeEach(() => {
binaryTree = new BinaryTree();
binaryTree.add([1, 'a']);
binaryTree.add(2, 'b');
binaryTree.add([3, 'c']);
});
it('The node obtained by get Node should match the node type', () => {
const node3 = binaryTree.getNode(3);
expect(node3).toBeInstanceOf(BinaryTreeNode);
});
it('forEach should iterate over all elements', () => {
const mockCallback = jest.fn();
binaryTree.forEach((key, value) => {
mockCallback(key, value);
});
expect(mockCallback.mock.calls.length).toBe(3);
expect(mockCallback.mock.calls[0]).toEqual([2, 'b']);
expect(mockCallback.mock.calls[1]).toEqual([1, 'a']);
expect(mockCallback.mock.calls[2]).toEqual([3, 'c']);
});
it('filter should return a new binTree with filtered elements', () => {
const filteredTree = binaryTree.filter(key => key > 1);
expect(filteredTree.size).toBe(2);
expect([...filteredTree]).toEqual([
[3, 'c'],
[2, 'b']
]);
});
it('map should return a new binTree with modified elements', () => {
const mappedTree = binaryTree.map((key, value) => [(key * 2).toString(), value]);
expect(mappedTree.size).toBe(3);
expect([...mappedTree]).toEqual([
['2', 'a'],
['4', 'b'],
['6', 'c']
]);
});
it('reduce should accumulate values', () => {
const sum = binaryTree.reduce((acc, currentValue, currentKey) => acc + currentKey, 0);
expect(sum).toBe(6);
});
it('[Symbol.iterator] should provide an iterator', () => {
const entries = [];
for (const entry of binaryTree) {
entries.push(entry);
}
expect(entries.length).toBe(3);
expect(entries).toEqual([
[2, 'b'],
[1, 'a'],
[3, 'c']
]);
});
it('should clone work well', () => {
const cloned = binaryTree.clone();
expect(cloned.root?.left?.key).toBe(2);
expect(cloned.root?.right?.value).toBe(undefined);
expect(cloned.get(cloned.root?.right)).toBe('c');
});
it('should keys', () => {
const keys = binaryTree.keys();
expect([...keys]).toEqual([2, 1, 3]);
});
it('should values', () => {
const values = binaryTree.values();
expect([...values]).toEqual(['b', 'a', 'c']);
});
it('should leaves', () => {
const leaves = binaryTree.leaves();
expect(leaves).toEqual([2, 3]);
binaryTree.clear();
expect(binaryTree.leaves()).toEqual([]);
});
it('should iterative method return undefined when the node is null', () => {
const binTree = new BinaryTree();
binTree.addMany([-10, -10, -10, 9, 9, 20, null, null, 15, 7, 8, null, 2, null, 6, null, null, 8, 8, 8]);
const bfsResult = binTree.bfs(undefined, undefined, undefined, true);
expect(bfsResult).toEqual([
-10,
9,
20,
undefined,
undefined,
15,
7,
8,
undefined,
2,
undefined,
6,
undefined,
undefined
]);
});
});
describe('BinaryTree not map mode iterative methods test', () => {
let binaryTree: BinaryTree<number, string>;
beforeEach(() => {
binaryTree = new BinaryTree<number, string>([], { isMapMode: false });
binaryTree.add([1, 'a']);
binaryTree.add(2, 'b');
binaryTree.add([3, 'c']);
});
it('should clone work well', () => {
const cloned = binaryTree.clone();
expect(cloned.root?.left?.key).toBe(2);
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<string>(
['stableIncome', 'goodCredit', 'Rejected', 'Approved', 'Rejected'],
{ isDuplicate: true }
);
function determineLoanApproval(
node?: BinaryTreeNode<string> | 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<number | string>(['+', 3, '*', null, null, 5, '-', null, null, 2, 8]);
function evaluate(node?: BinaryTreeNode<number | string> | 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);
});
});