diff --git a/CHANGELOG.md b/CHANGELOG.md index d733b89..e7eb556 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ All notable changes to this project will be documented in this file. - [Semantic Versioning](https://semver.org/spec/v2.0.0.html) - [`auto-changelog`](https://github.com/CookPete/auto-changelog) -## [v1.49.7](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) +## [v1.49.8](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) ### Changes diff --git a/package.json b/package.json index 79f8ab2..0814b5e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "data-structure-typed", - "version": "1.49.7", + "version": "1.49.8", "description": "Data Structures of Javascript & TypeScript. Heap, Binary Tree, Red Black Tree, Linked List, Deque, Trie, HashMap, Directed Graph, Undirected Graph, Binary Search Tree(BST), AVL Tree, Priority Queue, Graph, Queue, Tree Multiset, Singly Linked List, Doubly Linked List, Max Heap, Max Priority Queue, Min Heap, Min Priority Queue, Stack. Benchmark compared with C++ STL. API aligned with ES6 and Java.util. Usability is comparable to Python", "main": "dist/cjs/index.js", "module": "dist/mjs/index.js", diff --git a/src/data-structures/base/iterable-base.ts b/src/data-structures/base/iterable-base.ts index b9333e0..cf015bc 100644 --- a/src/data-structures/base/iterable-base.ts +++ b/src/data-structures/base/iterable-base.ts @@ -15,7 +15,7 @@ export abstract class IterableEntryBase { * allows the function to accept any number of arguments as an array. In this case, the `args` * parameter is used to pass any additional arguments to the `_getIterator` method. */ - * [Symbol.iterator](...args: any[]): IterableIterator<[K, V]> { + *[Symbol.iterator](...args: any[]): IterableIterator<[K, V]> { yield* this._getIterator(...args); } @@ -30,7 +30,7 @@ export abstract class IterableEntryBase { * The function returns an iterator that yields key-value pairs from the object, where the value can * be undefined. */ - * entries(): IterableIterator<[K, V | undefined]> { + *entries(): IterableIterator<[K, V | undefined]> { for (const item of this) { yield item; } @@ -46,7 +46,7 @@ export abstract class IterableEntryBase { * * The function returns an iterator that yields the keys of a data structure. */ - * keys(): IterableIterator { + *keys(): IterableIterator { for (const item of this) { yield item[0]; } @@ -62,7 +62,7 @@ export abstract class IterableEntryBase { * * The function returns an iterator that yields the values of a collection. */ - * values(): IterableIterator { + *values(): IterableIterator { for (const item of this) { yield item[1]; } @@ -212,7 +212,7 @@ export abstract class IterableElementBase { * allows the function to accept any number of arguments as an array. In this case, the `args` * parameter is used to pass any number of arguments to the `_getIterator` method. */ - * [Symbol.iterator](...args: any[]): IterableIterator { + *[Symbol.iterator](...args: any[]): IterableIterator { yield* this._getIterator(...args); } @@ -226,7 +226,7 @@ export abstract class IterableElementBase { * * The function returns an iterator that yields all the values in the object. */ - * values(): IterableIterator { + *values(): IterableIterator { for (const item of this) { yield item; } diff --git a/src/data-structures/binary-tree/avl-tree.ts b/src/data-structures/binary-tree/avl-tree.ts index b401cf3..647a671 100644 --- a/src/data-structures/binary-tree/avl-tree.ts +++ b/src/data-structures/binary-tree/avl-tree.ts @@ -40,13 +40,14 @@ export class AVLTreeNode = AVLT * 7. Path Length: The path length from the root to any leaf is longer compared to an unbalanced BST, but shorter than a linear chain of nodes. */ export class AVLTree< - K = any, - V = any, - N extends AVLTreeNode = AVLTreeNode>, - TREE extends AVLTree = AVLTree> -> + K = any, + V = any, + N extends AVLTreeNode = AVLTreeNode>, + TREE extends AVLTree = AVLTree> + > extends BST - implements IBinaryTree { + implements IBinaryTree +{ /** * The constructor function initializes an AVLTree object with optional keysOrNodesOrEntries and options. * @param [keysOrNodesOrEntries] - The `keysOrNodesOrEntries` parameter is an optional iterable of `KeyOrNodeOrEntry` @@ -277,7 +278,7 @@ export class AVLTree< // Balance Restoration: If a balance issue is discovered after inserting a node, it requires balance restoration operations. Balance restoration includes four basic cases where rotation operations need to be performed to fix the balance: switch ( this._balanceFactor(A) // second O(1) - ) { + ) { case -2: if (A && A.left) { if (this._balanceFactor(A.left) <= 0) { diff --git a/src/data-structures/binary-tree/binary-tree.ts b/src/data-structures/binary-tree/binary-tree.ts index a6b96be..939bb00 100644 --- a/src/data-structures/binary-tree/binary-tree.ts +++ b/src/data-structures/binary-tree/binary-tree.ts @@ -101,13 +101,14 @@ export class BinaryTreeNode< */ export class BinaryTree< - K = any, - V = any, - N extends BinaryTreeNode = BinaryTreeNode>, - TREE extends BinaryTree = BinaryTree> -> + K = any, + V = any, + N extends BinaryTreeNode = BinaryTreeNode>, + TREE extends BinaryTree = BinaryTree> + > extends IterableEntryBase - implements IBinaryTree { + implements IBinaryTree +{ iterationType = IterationType.ITERATIVE; /** @@ -1922,7 +1923,7 @@ export class BinaryTree< display(beginRoot); } - protected* _getIterator(node = this.root): IterableIterator<[K, V | undefined]> { + protected *_getIterator(node = this.root): IterableIterator<[K, V | undefined]> { if (!node) return; if (this.iterationType === IterationType.ITERATIVE) { diff --git a/src/data-structures/binary-tree/bst.ts b/src/data-structures/binary-tree/bst.ts index 6b38eaa..35f881d 100644 --- a/src/data-structures/binary-tree/bst.ts +++ b/src/data-structures/binary-tree/bst.ts @@ -83,13 +83,14 @@ export class BSTNode = BSTNodeNeste * 7. No Auto-Balancing: Standard BSTs don't automatically balance themselves. */ export class BST< - K = any, - V = any, - N extends BSTNode = BSTNode>, - TREE extends BST = BST> -> + K = any, + V = any, + N extends BSTNode = BSTNode>, + TREE extends BST = BST> + > extends BinaryTree - implements IBinaryTree { + implements IBinaryTree +{ /** * This is the constructor function for a binary search tree class in TypeScript, which initializes * the tree with optional keysOrNodesOrEntries and options. diff --git a/src/data-structures/binary-tree/rb-tree.ts b/src/data-structures/binary-tree/rb-tree.ts index c16d46f..2e311c5 100644 --- a/src/data-structures/binary-tree/rb-tree.ts +++ b/src/data-structures/binary-tree/rb-tree.ts @@ -41,13 +41,14 @@ export class RedBlackTreeNode< * 5. Black balance: Every path from any node to each of its leaf nodes contains the same number of black nodes. */ export class RedBlackTree< - K = any, - V = any, - N extends RedBlackTreeNode = RedBlackTreeNode>, - TREE extends RedBlackTree = RedBlackTree> -> + K = any, + V = any, + N extends RedBlackTreeNode = RedBlackTreeNode>, + TREE extends RedBlackTree = RedBlackTree> + > extends BST - implements IBinaryTree { + implements IBinaryTree +{ Sentinel: N = new RedBlackTreeNode(NaN as K) as unknown as N; /** diff --git a/src/data-structures/binary-tree/tree-multimap.ts b/src/data-structures/binary-tree/tree-multimap.ts index 8981cde..61e444d 100644 --- a/src/data-structures/binary-tree/tree-multimap.ts +++ b/src/data-structures/binary-tree/tree-multimap.ts @@ -45,13 +45,14 @@ export class TreeMultimapNode< * The only distinction between a TreeMultimap and a AVLTree lies in the ability of the former to store duplicate nodes through the utilization of counters. */ export class TreeMultimap< - K = any, - V = any, - N extends TreeMultimapNode = TreeMultimapNode>, - TREE extends TreeMultimap = TreeMultimap> -> + K = any, + V = any, + N extends TreeMultimapNode = TreeMultimapNode>, + TREE extends TreeMultimap = TreeMultimap> + > extends AVLTree - implements IBinaryTree { + implements IBinaryTree +{ constructor(keysOrNodesOrEntries: Iterable> = [], options?: TreeMultimapOptions) { super([], options); if (keysOrNodesOrEntries) this.addMany(keysOrNodesOrEntries); diff --git a/src/data-structures/graph/abstract-graph.ts b/src/data-structures/graph/abstract-graph.ts index cb70033..25b192a 100644 --- a/src/data-structures/graph/abstract-graph.ts +++ b/src/data-structures/graph/abstract-graph.ts @@ -61,13 +61,14 @@ export abstract class AbstractEdge { } export abstract class AbstractGraph< - V = any, - E = any, - VO extends AbstractVertex = AbstractVertex, - EO extends AbstractEdge = AbstractEdge -> + V = any, + E = any, + VO extends AbstractVertex = AbstractVertex, + EO extends AbstractEdge = AbstractEdge + > extends IterableEntryBase - implements IGraph { + implements IGraph +{ constructor() { super(); } @@ -610,14 +611,14 @@ export abstract class AbstractGraph< } getMinDist && - distMap.forEach((d, v) => { - if (v !== srcVertex) { - if (d < minDist) { - minDist = d; - if (genPaths) minDest = v; + distMap.forEach((d, v) => { + if (v !== srcVertex) { + if (d < minDist) { + minDist = d; + if (genPaths) minDest = v; + } } - } - }); + }); genPaths && getPaths(minDest); @@ -1272,7 +1273,7 @@ export abstract class AbstractGraph< return mapped; } - protected* _getIterator(): IterableIterator<[VertexKey, V | undefined]> { + protected *_getIterator(): IterableIterator<[VertexKey, V | undefined]> { for (const vertex of this._vertexMap.values()) { yield [vertex.key, vertex.value]; } diff --git a/src/data-structures/graph/directed-graph.ts b/src/data-structures/graph/directed-graph.ts index f9c2ff0..71ecd98 100644 --- a/src/data-structures/graph/directed-graph.ts +++ b/src/data-structures/graph/directed-graph.ts @@ -46,13 +46,14 @@ export class DirectedEdge extends AbstractEdge { } export class DirectedGraph< - V = any, - E = any, - VO extends DirectedVertex = DirectedVertex, - EO extends DirectedEdge = DirectedEdge -> + V = any, + E = any, + VO extends DirectedVertex = DirectedVertex, + EO extends DirectedEdge = DirectedEdge + > extends AbstractGraph - implements IGraph { + implements IGraph +{ /** * The constructor function initializes an instance of a class. */ diff --git a/src/data-structures/graph/undirected-graph.ts b/src/data-structures/graph/undirected-graph.ts index 20cba16..acfa125 100644 --- a/src/data-structures/graph/undirected-graph.ts +++ b/src/data-structures/graph/undirected-graph.ts @@ -43,13 +43,14 @@ export class UndirectedEdge extends AbstractEdge { } export class UndirectedGraph< - V = any, - E = any, - VO extends UndirectedVertex = UndirectedVertex, - EO extends UndirectedEdge = UndirectedEdge -> + V = any, + E = any, + VO extends UndirectedVertex = UndirectedVertex, + EO extends UndirectedEdge = UndirectedEdge + > extends AbstractGraph - implements IGraph { + implements IGraph +{ /** * The constructor initializes a new Map object to store edgeMap. */ diff --git a/src/data-structures/hash/hash-map.ts b/src/data-structures/hash/hash-map.ts index da85828..f0cedf1 100644 --- a/src/data-structures/hash/hash-map.ts +++ b/src/data-structures/hash/hash-map.ts @@ -21,28 +21,48 @@ import { isWeakKey, rangeCheck } from '../../utils'; * 3. Unique Keys: Keys are unique. If you try to insert another entry with the same key, the old entry will be replaced by the new one. * 4. Unordered Collection: HashMap does not guarantee the order of entries, and the order may change over time. */ -export class HashMap extends IterableEntryBase { +export class HashMap extends IterableEntryBase { protected _store: { [key: string]: HashMapStoreItem } = {}; protected _objMap: Map = new Map(); + protected _toEntryFn: (rawElement: R) => [K, V] = (rawElement: R) => { + if (this.isEntry(rawElement)) { + // TODO, For performance optimization, it may be necessary to only inspect the first element traversed. + return rawElement; + } else { + throw new Error( + "If the provided rawCollection does not adhere to the [key, value] type format, the toEntryFn in the constructor's options parameter needs to specified." + ); + } + }; + + get toEntryFn() { + return this._toEntryFn; + } + + isEntry(rawElement: any): rawElement is [K, V] { + return Array.isArray(rawElement) && rawElement.length === 2; + } /** - * The constructor function initializes a new instance of a class with optional entries and options. - * @param entries - The `entries` parameter is an iterable containing key-value pairs `[K, V]`. It - * is optional and defaults to an empty array `[]`. This parameter is used to initialize the map with - * key-value pairs. - * @param [options] - The `options` parameter is an optional object that can contain additional - * configuration options for the constructor. In this case, it has one property: + * The constructor function initializes a HashMap object with an optional initial collection and + * options. + * @param rawCollection - The `rawCollection` parameter is an iterable collection of elements of type + * `T`. It is an optional parameter and its default value is an empty array `[]`. + * @param [options] - The `options` parameter is an optional object that can contain two properties: */ - constructor(entries: Iterable<[K, V]> = [], options?: HashMapOptions) { + constructor(rawCollection: Iterable = [], options?: HashMapOptions) { super(); if (options) { - const { hashFn } = options; + const { hashFn, toEntryFn } = options; if (hashFn) { this._hashFn = hashFn; } + if (toEntryFn) { + this._toEntryFn = toEntryFn; + } } - if (entries) { - this.setMany(entries); + if (rawCollection) { + this.setMany(rawCollection); } } @@ -88,13 +108,18 @@ export class HashMap extends IterableEntryBase { } /** - * The function "setMany" sets multiple key-value pairs in a map. - * @param entries - The `entries` parameter is an iterable containing key-value pairs. Each - * key-value pair is represented as an array with two entries: the key and the value. + * The function `setMany` takes an iterable collection of objects, maps each object to a key-value + * pair using a mapping function, and sets each key-value pair in the current object. + * @param rawCollection - The `rawCollection` parameter is an iterable collection of elements of type + * `T`. + * @returns The `setMany` function is returning an array of booleans. */ - setMany(entries: Iterable<[K, V]>): boolean[] { + setMany(rawCollection: Iterable): boolean[] { const results: boolean[] = []; - for (const [key, value] of entries) results.push(this.set(key, value)); + for (const rawEle of rawCollection) { + const [key, value] = this.toEntryFn(rawEle); + results.push(this.set(key, value)); + } return results; } @@ -223,7 +248,7 @@ export class HashMap extends IterableEntryBase { * The function returns an iterator that yields key-value pairs from both an object store and an * object map. */ - protected* _getIterator(): IterableIterator<[K, V]> { + protected *_getIterator(): IterableIterator<[K, V]> { for (const node of Object.values(this._store)) { yield [node.key, node.value] as [K, V]; } @@ -322,7 +347,7 @@ export class LinkedHashMap extends IterableEntryBase { /** * The `begin()` function in TypeScript iterates over a linked list and yields key-value pairs. */ - * begin() { + *begin() { let node = this._head; while (node !== this._sentinel) { yield [node.key, node.value]; @@ -334,7 +359,7 @@ export class LinkedHashMap extends IterableEntryBase { * The function `reverseBegin()` iterates over a linked list in reverse order, yielding each node's * key and value. */ - * reverseBegin() { + *reverseBegin() { let node = this._tail; while (node !== this._sentinel) { yield [node.key, node.value]; @@ -635,7 +660,7 @@ export class LinkedHashMap extends IterableEntryBase { * * The above function is an iterator that yields key-value pairs from a linked list. */ - protected* _getIterator() { + protected *_getIterator() { let node = this._head; while (node !== this._sentinel) { yield [node.key, node.value] as [K, V]; diff --git a/src/data-structures/heap/heap.ts b/src/data-structures/heap/heap.ts index 8e2d9fe..d5391a3 100644 --- a/src/data-structures/heap/heap.ts +++ b/src/data-structures/heap/heap.ts @@ -391,7 +391,7 @@ export class Heap extends IterableElementBase { return mappedHeap; } - protected* _getIterator(): IterableIterator { + protected *_getIterator(): IterableIterator { for (const element of this.elements) { yield element; } diff --git a/src/data-structures/linked-list/doubly-linked-list.ts b/src/data-structures/linked-list/doubly-linked-list.ts index caaffc9..757f41e 100644 --- a/src/data-structures/linked-list/doubly-linked-list.ts +++ b/src/data-structures/linked-list/doubly-linked-list.ts @@ -808,7 +808,7 @@ export class DoublyLinkedList extends IterableElementBase { /** * The function returns an iterator that iterates over the values of a linked list. */ - protected* _getIterator(): IterableIterator { + protected *_getIterator(): IterableIterator { let current = this.head; while (current) { diff --git a/src/data-structures/linked-list/singly-linked-list.ts b/src/data-structures/linked-list/singly-linked-list.ts index aa32809..13ec341 100644 --- a/src/data-structures/linked-list/singly-linked-list.ts +++ b/src/data-structures/linked-list/singly-linked-list.ts @@ -741,7 +741,7 @@ export class SinglyLinkedList extends IterableElementBase { return mappedList; } - protected* _getIterator(): IterableIterator { + protected *_getIterator(): IterableIterator { let current = this.head; while (current) { diff --git a/src/data-structures/queue/deque.ts b/src/data-structures/queue/deque.ts index 02aa162..744bb65 100644 --- a/src/data-structures/queue/deque.ts +++ b/src/data-structures/queue/deque.ts @@ -232,7 +232,7 @@ export class Deque extends IterableElementBase { /** * The below function is a generator that yields elements from a collection one by one. */ - * begin(): Generator { + *begin(): Generator { let index = 0; while (index < this.size) { yield this.getAt(index); @@ -244,7 +244,7 @@ export class Deque extends IterableElementBase { * The function `reverseBegin()` is a generator that yields elements in reverse order starting from * the last element. */ - * reverseBegin(): Generator { + *reverseBegin(): Generator { let index = this.size - 1; while (index >= 0) { yield this.getAt(index); @@ -735,7 +735,7 @@ export class Deque extends IterableElementBase { * The above function is an implementation of the iterator protocol in TypeScript, allowing the * object to be iterated over using a for...of loop. */ - protected* _getIterator(): IterableIterator { + protected *_getIterator(): IterableIterator { for (let i = 0; i < this.size; ++i) { yield this.getAt(i); } diff --git a/src/data-structures/queue/queue.ts b/src/data-structures/queue/queue.ts index 1c2d4e7..3bcd1c6 100644 --- a/src/data-structures/queue/queue.ts +++ b/src/data-structures/queue/queue.ts @@ -345,7 +345,7 @@ export class Queue extends IterableElementBase { * Space Complexity: O(n) */ - protected* _getIterator(): IterableIterator { + protected *_getIterator(): IterableIterator { for (const item of this.elements) { yield item; } diff --git a/src/data-structures/stack/stack.ts b/src/data-structures/stack/stack.ts index 63cabfa..c1775c7 100644 --- a/src/data-structures/stack/stack.ts +++ b/src/data-structures/stack/stack.ts @@ -229,7 +229,7 @@ export class Stack extends IterableElementBase { * Custom iterator for the Stack class. * @returns An iterator object. */ - protected* _getIterator(): IterableIterator { + protected *_getIterator(): IterableIterator { for (let i = 0; i < this.elements.length; i++) { yield this.elements[i]; } diff --git a/src/data-structures/trie/trie.ts b/src/data-structures/trie/trie.ts index d4a1eb9..cb4c0a3 100644 --- a/src/data-structures/trie/trie.ts +++ b/src/data-structures/trie/trie.ts @@ -410,7 +410,7 @@ export class Trie extends IterableElementBase { return newTrie; } - protected* _getIterator(): IterableIterator { + protected *_getIterator(): IterableIterator { function* _dfs(node: TrieNode, path: string): IterableIterator { if (node.isEnd) { yield path; diff --git a/src/types/data-structures/graph/abstract-graph.ts b/src/types/data-structures/graph/abstract-graph.ts index e799019..32b6564 100644 --- a/src/types/data-structures/graph/abstract-graph.ts +++ b/src/types/data-structures/graph/abstract-graph.ts @@ -2,12 +2,12 @@ export type VertexKey = string | number; export type DijkstraResult = | { - distMap: Map; - distPaths?: Map; - preMap: Map; - seen: Set; - paths: V[][]; - minDist: number; - minPath: V[]; -} + distMap: Map; + distPaths?: Map; + preMap: Map; + seen: Set; + paths: V[][]; + minDist: number; + minPath: V[]; + } | undefined; diff --git a/src/types/data-structures/hash/hash-map.ts b/src/types/data-structures/hash/hash-map.ts index d672839..c930899 100644 --- a/src/types/data-structures/hash/hash-map.ts +++ b/src/types/data-structures/hash/hash-map.ts @@ -10,8 +10,9 @@ export type LinkedHashMapOptions = { objHashFn?: (key: K) => object; }; -export type HashMapOptions = { +export type HashMapOptions = { hashFn?: (key: K) => string; + toEntryFn?: (rawElement: T) => [K, V]; }; export type HashMapStoreItem = { key: K; value: V }; diff --git a/test/unit/data-structures/graph/abstract-graph.test.ts b/test/unit/data-structures/graph/abstract-graph.test.ts index 6c634b6..7f54d21 100644 --- a/test/unit/data-structures/graph/abstract-graph.test.ts +++ b/test/unit/data-structures/graph/abstract-graph.test.ts @@ -85,8 +85,7 @@ class MyGraph< describe('AbstractGraph Operation Test', () => { const myGraph: MyGraph = new MyGraph(); - beforeEach(() => { - }); + beforeEach(() => {}); it('should edge cases', function () { myGraph.addVertex('A', 1); myGraph.addVertex('B', 2); diff --git a/test/unit/data-structures/hash/hash-map.test.ts b/test/unit/data-structures/hash/hash-map.test.ts index 57d0111..edad1ca 100644 --- a/test/unit/data-structures/hash/hash-map.test.ts +++ b/test/unit/data-structures/hash/hash-map.test.ts @@ -128,6 +128,20 @@ describe('HashMap Test2', () => { expect(eHM.get('one')).toBe(1); }); + test('should raw elements toEntry', () => { + const rawCollection = [ + { id: 1, name: 'item 1' }, + { id: 2, name: 'item 2' } + ]; + const hm = new HashMap(rawCollection, { + toEntryFn: rawElement => [rawElement.id, rawElement.name] + }); + + expect(hm.has(1)).toBe(true); + expect(hm.get(2)).toBe('item 2'); + expect(hm.size).toBe(2); + }); + it('should update the value for an existing key', () => { hashMap.set('key1', 'value1'); hashMap.set('key1', 'newValue'); diff --git a/test/unit/data-structures/queue/deque.test.ts b/test/unit/data-structures/queue/deque.test.ts index b5830bb..e08d4f1 100644 --- a/test/unit/data-structures/queue/deque.test.ts +++ b/test/unit/data-structures/queue/deque.test.ts @@ -114,8 +114,7 @@ describe('Deque - Complex Operations', () => { expect([...deque]).toEqual([1, 2, 3]); }); - test('shrinkToFit should reduce the memory footprint', () => { - }); + test('shrinkToFit should reduce the memory footprint', () => {}); }); describe('Deque - Utility Operations', () => { let deque: Deque;