mirror of
https://github.com/zrwusa/data-structure-typed.git
synced 2024-11-23 12:54:04 +00:00
feat: Add keys, values, and clone methods to all binary tree data structures.
This commit is contained in:
parent
523221357c
commit
9a9571431c
|
@ -102,9 +102,10 @@ export class BinaryTreeNode<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode<V, BinaryTreeNodeNested<V>>, TREE extends BinaryTree<V, N, TREE> = BinaryTree<V, N, BinaryTreeNested<V, N>>>
|
||||
implements IBinaryTree<V, N, TREE> {
|
||||
|
||||
export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode<V, BinaryTreeNodeNested<V>>, TREE extends BinaryTree<V, N, TREE> = BinaryTree<V, N, BinaryTreeNested<V, N>>>
|
||||
|
||||
implements IBinaryTree<V, N, TREE> {
|
||||
iterationType = IterationType.ITERATIVE
|
||||
|
||||
/**
|
||||
|
@ -1723,6 +1724,66 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = 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)
|
||||
|
|
|
@ -318,6 +318,24 @@ export class TreeMultimap<V = any, N extends TreeMultimapNode<V, N> = 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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 }]
|
||||
];
|
||||
|
||||
|
|
|
@ -4,17 +4,17 @@ import { getRandomIntArray, magnitude } from '../../../utils';
|
|||
|
||||
const suite = new Benchmark.Suite();
|
||||
const biTree = new BinaryTree<number>();
|
||||
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 };
|
||||
|
|
|
@ -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']);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -564,7 +564,6 @@ describe('BinaryTree', () => {
|
|||
});
|
||||
});
|
||||
|
||||
|
||||
describe('BinaryTree iterative methods test', () => {
|
||||
let binaryTree: BinaryTree<string>;
|
||||
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']);
|
||||
});
|
||||
});
|
|
@ -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']);
|
||||
});
|
||||
});
|
|
@ -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<string>;
|
||||
beforeEach(() => {
|
||||
treeMM = new TreeMultimap<string>();
|
||||
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']);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue