diff --git a/src/data-structures/binary-tree/binary-tree.ts b/src/data-structures/binary-tree/binary-tree.ts index b1a8957..f519ec6 100644 --- a/src/data-structures/binary-tree/binary-tree.ts +++ b/src/data-structures/binary-tree/binary-tree.ts @@ -102,9 +102,10 @@ export class BinaryTreeNode = BinaryTree * 8. Full Trees: Every node has either 0 or 2 children. * 9. Complete Trees: All levels are fully filled except possibly the last, filled from left to right. */ -export class BinaryTree = BinaryTreeNode>, TREE extends BinaryTree = BinaryTree>> - implements IBinaryTree { +export class BinaryTree = BinaryTreeNode>, TREE extends BinaryTree = BinaryTree>> + + implements IBinaryTree { iterationType = IterationType.ITERATIVE /** @@ -1723,6 +1724,66 @@ export class BinaryTree = BinaryTreeNode return ans; } + /** + * Time complexity: O(n) + * Space complexity: O(n) + */ + + /** + * Time complexity: O(n) + * Space complexity: O(n) + * + * The function "keys" returns an array of keys from a given object. + * @returns an array of BTNKey objects. + */ + keys(): BTNKey[] { + const keys: BTNKey[] = []; + for (const entry of this) { + keys.push(entry[0]); + } + return keys; + } + + /** + * Time complexity: O(n) + * Space complexity: O(n) + */ + + /** + * Time complexity: O(n) + * Space complexity: O(n) + * + * The function "values" returns an array of values from a map-like object. + * @returns The `values()` method is returning an array of values (`V`) from the entries in the + * object. + */ + values(): (V | undefined)[] { + const values: (V | undefined)[] = []; + for (const entry of this) { + values.push(entry[1]); + } + return values; + } + + /** + * Time complexity: O(n) + * Space complexity: O(n) + */ + + /** + * Time complexity: O(n) + * Space complexity: O(n) + * + * The `clone` function creates a new tree object and copies all the nodes from the original tree to + * the new tree. + * @returns The `clone()` method is returning a cloned instance of the `TREE` object. + */ + clone(): TREE { + const cloned = this.createTree(); + this.bfs(node => cloned.add([node.key, node.value])); + return cloned; + } + /** * Time complexity: O(n) * Space complexity: O(1) diff --git a/src/data-structures/binary-tree/tree-multimap.ts b/src/data-structures/binary-tree/tree-multimap.ts index d190489..028f269 100644 --- a/src/data-structures/binary-tree/tree-multimap.ts +++ b/src/data-structures/binary-tree/tree-multimap.ts @@ -318,6 +318,24 @@ export class TreeMultimap = TreeMultim this._count = 0; } + /** + * Time complexity: O(n) + * Space complexity: O(n) + */ + + /** + * Time complexity: O(n) + * Space complexity: O(n) + * + * The `clone` function creates a deep copy of a tree object. + * @returns The `clone()` method is returning a cloned instance of the `TREE` object. + */ + override clone(): TREE { + const cloned = this.createTree(); + this.bfs(node => cloned.add([node.key, node.value], node.count)); + return cloned; + } + /** * Time Complexity: O(1) - constant time, as it performs basic pointer assignments. * Space Complexity: O(1) - constant space, as it only uses a constant amount of memory. diff --git a/test/integration/avl-tree.test.ts b/test/integration/avl-tree.test.ts index d376256..b6dad39 100644 --- a/test/integration/avl-tree.test.ts +++ b/test/integration/avl-tree.test.ts @@ -2,7 +2,7 @@ import { AVLTree, CP } from 'avl-tree-typed'; describe('AVL Tree Test', () => { it('should perform various operations on a AVL Tree', () => { - const arr: [number, number][] = [[11, 11], [3, 3], [15, 15], [1, 1], [8, 8], [13, 13], [16, 16], [2, 2], [6, 6], [9, 9], [12,12], [14, 14], [4, 4], [7, 7], [10,10], [5,5]]; + const arr: [number, number][] = [[11, 11], [3, 3], [15, 15], [1, 1], [8, 8], [13, 13], [16, 16], [2, 2], [6, 6], [9, 9], [12, 12], [14, 14], [4, 4], [7, 7], [10, 10], [5, 5]]; const tree = new AVLTree(); for (const i of arr) tree.add(i); diff --git a/test/integration/bst.test.ts b/test/integration/bst.test.ts index 286f90e..f1fdc05 100644 --- a/test/integration/bst.test.ts +++ b/test/integration/bst.test.ts @@ -187,20 +187,20 @@ describe('Individual package BST operations test', () => { expect(objBST).toBeInstanceOf(BST); objBST.add([11, { key: 11, keyA: 11 }]); objBST.add([3, { key: 3, keyA: 3 }]); - const values:[number, { key: number; keyA: number }][] = [ - [15,{ key: 15, keyA: 15 }], + const values: [number, { key: number; keyA: number }][] = [ + [15, { key: 15, keyA: 15 }], [1, { key: 1, keyA: 1 }], [8, { key: 8, keyA: 8 }], - [13,{ key: 13, keyA: 13 }], - [16,{ key: 16, keyA: 16 }], + [13, { key: 13, keyA: 13 }], + [16, { key: 16, keyA: 16 }], [2, { key: 2, keyA: 2 }], [6, { key: 6, keyA: 6 }], [9, { key: 9, keyA: 9 }], - [12,{ key: 12, keyA: 12 }], - [14,{ key: 14, keyA: 14 }], + [12, { key: 12, keyA: 12 }], + [14, { key: 14, keyA: 14 }], [4, { key: 4, keyA: 4 }], [7, { key: 7, keyA: 7 }], - [10,{ key: 10, keyA: 10 }], + [10, { key: 10, keyA: 10 }], [5, { key: 5, keyA: 5 }] ]; diff --git a/test/performance/data-structures/binary-tree/binary-tree.test.ts b/test/performance/data-structures/binary-tree/binary-tree.test.ts index bbcf99b..b417079 100644 --- a/test/performance/data-structures/binary-tree/binary-tree.test.ts +++ b/test/performance/data-structures/binary-tree/binary-tree.test.ts @@ -4,17 +4,17 @@ import { getRandomIntArray, magnitude } from '../../../utils'; const suite = new Benchmark.Suite(); const biTree = new BinaryTree(); -const { N_LOG_N } = magnitude; -const arr = getRandomIntArray(N_LOG_N, 0, N_LOG_N, true); +const { THOUSAND } = magnitude; +const arr = getRandomIntArray(THOUSAND, 0, THOUSAND, true); suite - .add(`${N_LOG_N.toLocaleString()} add randomly`, () => { + .add(`${THOUSAND.toLocaleString()} add randomly`, () => { biTree.clear(); for (let i = 0; i < arr.length; i++) { biTree.add(arr[i]); } }) - .add(`${N_LOG_N.toLocaleString()} add & delete randomly`, () => { + .add(`${THOUSAND.toLocaleString()} add & delete randomly`, () => { biTree.clear(); for (let i = 0; i < arr.length; i++) { biTree.add(arr[i]); @@ -23,23 +23,28 @@ suite biTree.delete(arr[i]); } }) - .add(`${N_LOG_N.toLocaleString()} addMany`, () => { + .add(`${THOUSAND.toLocaleString()} addMany`, () => { biTree.clear(); biTree.addMany(arr); }) - .add(`${N_LOG_N.toLocaleString()} get`, () => { + .add(`${THOUSAND.toLocaleString()} get`, () => { for (let i = 0; i < arr.length; i++) { biTree.get(arr[i]); } }) - .add(`${N_LOG_N.toLocaleString()} dfs`, () => { - for (let i = 0; i < N_LOG_N; i++) biTree.dfs(); + .add(`${THOUSAND.toLocaleString()} has`, () => { + for (let i = 0; i < arr.length; i++) { + biTree.get(arr[i]); + } }) - .add(`${N_LOG_N.toLocaleString()} bfs`, () => { - for (let i = 0; i < N_LOG_N; i++) biTree.bfs(); + .add(`${THOUSAND.toLocaleString()} dfs`, () => { + for (let i = 0; i < THOUSAND; i++) biTree.dfs(); }) - .add(`${N_LOG_N.toLocaleString()} morris`, () => { - for (let i = 0; i < N_LOG_N; i++) biTree.morris(n => n, 'pre'); + .add(`${THOUSAND.toLocaleString()} bfs`, () => { + for (let i = 0; i < THOUSAND; i++) biTree.bfs(); + }) + .add(`${THOUSAND.toLocaleString()} morris`, () => { + for (let i = 0; i < THOUSAND; i++) biTree.morris(n => n, 'pre'); }); export { suite }; diff --git a/test/unit/data-structures/binary-tree/avl-tree.test.ts b/test/unit/data-structures/binary-tree/avl-tree.test.ts index be18fd3..674c783 100644 --- a/test/unit/data-structures/binary-tree/avl-tree.test.ts +++ b/test/unit/data-structures/binary-tree/avl-tree.test.ts @@ -341,4 +341,20 @@ describe('AVLTree iterative methods test', () => { expect(entries.length).toBe(3); expect(entries).toEqual([[1, 'a'], [2, 'b'], [3, 'c']]); }); + + test('should clone work well', () => { + const cloned = avl.clone(); + expect(cloned.root?.left?.key).toBe(1); + expect(cloned.root?.right?.value).toBe('c'); + }); + + test('should keys', () => { + const keys = avl.keys(); + expect(keys).toEqual([1, 2, 3]); + }); + + test('should values', () => { + const values = avl.values(); + expect(values).toEqual(['a', 'b', 'c']); + }); }); 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 ab9d434..f2e520f 100644 --- a/test/unit/data-structures/binary-tree/binary-tree.test.ts +++ b/test/unit/data-structures/binary-tree/binary-tree.test.ts @@ -564,7 +564,6 @@ describe('BinaryTree', () => { }); }); - describe('BinaryTree iterative methods test', () => { let binaryTree: BinaryTree; beforeEach(() => { @@ -617,4 +616,20 @@ describe('BinaryTree iterative methods test', () => { expect(entries.length).toBe(3); expect(entries).toEqual([[2, 'b'], [1, 'a'], [3, 'c']]); }); + + test('should clone work well', () => { + const cloned = binaryTree.clone(); + expect(cloned.root?.left?.key).toBe(2); + expect(cloned.root?.right?.value).toBe('c'); + }); + + test('should keys', () => { + const keys = binaryTree.keys(); + expect(keys).toEqual([2, 1, 3]); + }); + + test('should values', () => { + const values = binaryTree.values(); + expect(values).toEqual(['b', 'a', 'c']); + }); }); \ No newline at end of file diff --git a/test/unit/data-structures/binary-tree/bst.test.ts b/test/unit/data-structures/binary-tree/bst.test.ts index 981aa16..e99fd2e 100644 --- a/test/unit/data-structures/binary-tree/bst.test.ts +++ b/test/unit/data-structures/binary-tree/bst.test.ts @@ -900,4 +900,20 @@ describe('BST iterative methods test', () => { expect(entries.length).toBe(3); expect(entries).toEqual([[1, 'a'], [2, 'b'], [3, 'c']]); }); + + test('should clone work well', () => { + const cloned = bst.clone(); + expect(cloned.root?.left).toBe(undefined); + expect(cloned.root?.right?.value).toBe('b'); + }); + + test('should keys', () => { + const keys = bst.keys(); + expect(keys).toEqual([1, 2, 3]); + }); + + test('should values', () => { + const values = bst.values(); + expect(values).toEqual(['a', 'b', 'c']); + }); }); \ No newline at end of file diff --git a/test/unit/data-structures/binary-tree/tree-multimap.test.ts b/test/unit/data-structures/binary-tree/tree-multimap.test.ts index c34e0c0..1eed205 100644 --- a/test/unit/data-structures/binary-tree/tree-multimap.test.ts +++ b/test/unit/data-structures/binary-tree/tree-multimap.test.ts @@ -1,4 +1,12 @@ -import { CP, IterationType, TreeMultimap, TreeMultimapNode } from '../../../../src'; +import { + AVLTreeNode, + BinaryTreeNode, + BSTNode, + CP, + IterationType, + TreeMultimap, + TreeMultimapNode +} from '../../../../src'; import { isDebugTest } from '../../../config'; const isDebug = isDebugTest; @@ -592,3 +600,76 @@ describe('TreeMultimap Performance test', function () { isDebug && console.log('---lesserOrGreaterTraverse', performance.now() - startL); }); }); + +describe('TreeMultimap iterative methods test', () => { + let treeMM: TreeMultimap; + beforeEach(() => { + treeMM = new TreeMultimap(); + treeMM.add([1, 'a'], 10); + treeMM.add([2, 'b'], 10); + treeMM.add([3, 'c'], 1); + }); + + test('The node obtained by get Node should match the node type', () => { + const node3 = treeMM.getNode(3); + expect(node3).toBeInstanceOf(BinaryTreeNode); + expect(node3).toBeInstanceOf(BSTNode); + expect(node3).toBeInstanceOf(AVLTreeNode); + }); + + test('forEach should iterate over all elements', () => { + const mockCallback = jest.fn(); + treeMM.forEach((entry) => { + mockCallback(entry); + }); + + expect(mockCallback.mock.calls.length).toBe(3); + expect(mockCallback.mock.calls[0][0]).toEqual([1, 'a']); + expect(mockCallback.mock.calls[1][0]).toEqual([2, 'b']); + expect(mockCallback.mock.calls[2][0]).toEqual([3, 'c']); + }); + + test('filter should return a new tree with filtered elements', () => { + const filteredTree = treeMM.filter(([key]) => key > 1); + expect(filteredTree.size).toBe(2); + expect([...filteredTree]).toEqual([[2, 'b'], [3, 'c']]); + }); + + test('map should return a new tree with modified elements', () => { + const mappedTree = treeMM.map(([key]) => (key * 2).toString()); + expect(mappedTree.size).toBe(3); + expect([...mappedTree]).toEqual([[1, '2'], [2, '4'], [3, '6']]); + }); + + test('reduce should accumulate values', () => { + const sum = treeMM.reduce((acc, [key]) => acc + key, 0); + expect(sum).toBe(6); + }); + + test('[Symbol.iterator] should provide an iterator', () => { + const entries = []; + for (const entry of treeMM) { + entries.push(entry); + } + + expect(entries.length).toBe(3); + expect(entries).toEqual([[1, 'a'], [2, 'b'], [3, 'c']]); + }); + + test('should clone work well', () => { + expect(treeMM.count).toBe(21) + const cloned = treeMM.clone(); + expect(cloned.root?.left?.key).toBe(1); + expect(cloned.root?.right?.value).toBe('c'); + }); + + test('should keys', () => { + const keys = treeMM.keys(); + expect(keys).toEqual([1, 2, 3]); + }); + + test('should values', () => { + const values = treeMM.values(); + expect(values).toEqual(['a', 'b', 'c']); + }); +});