diff --git a/CHANGELOG.md b/CHANGELOG.md
index 24b7ea9..79e99aa 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.5](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming)
+## [v1.49.6](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming)
### Changes
diff --git a/README.md b/README.md
index 5d08812..a03f376 100644
--- a/README.md
+++ b/README.md
@@ -984,43 +984,43 @@ avl2.print();
[//]: # (No deletion!!! Start of Replace Section)
avl-tree
-
test name time taken (ms) executions per sec sample deviation 10,000 add randomly 122.81 8.14 0.00 10,000 add & delete randomly 184.27 5.43 0.00 10,000 addMany 132.27 7.56 0.00 10,000 get 51.04 19.59 7.82e-4
+
test name time taken (ms) executions per sec sample deviation 10,000 add randomly 126.82 7.88 0.01 10,000 add & delete randomly 186.36 5.37 0.00 10,000 addMany 133.15 7.51 0.00 10,000 get 50.65 19.74 5.59e-4
binary-tree-overall
-
test name time taken (ms) executions per sec sample deviation 10,000 RBTree add 5.81 172.09 8.66e-5 10,000 RBTree add & delete randomly 15.03 66.54 2.26e-4 10,000 RBTree get 18.76 53.30 4.08e-4 10,000 AVLTree add 125.39 7.98 0.00 10,000 AVLTree add & delete randomly 189.09 5.29 0.00 10,000 AVLTree get 0.92 1087.75 2.99e-5
+
test name time taken (ms) executions per sec sample deviation 10,000 RBTree add 6.12 163.48 1.94e-4 10,000 RBTree add & delete randomly 15.46 64.70 3.64e-4 10,000 RBTree get 19.98 50.06 0.00 10,000 AVLTree add 130.40 7.67 0.02 10,000 AVLTree add & delete randomly 193.64 5.16 0.01 10,000 AVLTree get 0.99 1005.44 3.95e-5
rb-tree
-
test name time taken (ms) executions per sec sample deviation 100,000 add 81.23 12.31 0.00 100,000 add & delete randomly 205.00 4.88 0.00 100,000 getNode 178.14 5.61 8.78e-4 100,000 add & iterator 110.77 9.03 0.00
+
test name time taken (ms) executions per sec sample deviation 100,000 add 90.72 11.02 0.03 100,000 add & delete randomly 228.77 4.37 0.02 100,000 getNode 192.25 5.20 5.16e-4 100,000 add & iterator 112.49 8.89 0.01
directed-graph
-
test name time taken (ms) executions per sec sample deviation 1,000 addVertex 0.10 9863.41 1.37e-6 1,000 addEdge 6.29 159.07 1.77e-4 1,000 getVertex 0.05 2.15e+4 4.86e-7 1,000 getEdge 23.46 42.63 0.00 tarjan 216.87 4.61 0.01 tarjan all 6549.75 0.15 0.03 topologicalSort 182.67 5.47 0.00
+
test name time taken (ms) executions per sec sample deviation 1,000 addVertex 0.11 9250.94 1.22e-5 1,000 addEdge 6.35 157.51 2.88e-4 1,000 getVertex 0.05 2.06e+4 8.69e-6 1,000 getEdge 23.02 43.43 0.00 tarjan 213.85 4.68 0.01 tarjan all 6674.11 0.15 0.28 topologicalSort 179.09 5.58 0.00
hash-map
-
test name time taken (ms) executions per sec sample deviation 1,000,000 set 119.49 8.37 0.04 Native Map 1,000,000 set 222.50 4.49 0.02 Native Set 1,000,000 add 173.11 5.78 0.01 1,000,000 set & get 118.37 8.45 0.02 Native Map 1,000,000 set & get 273.63 3.65 0.01 Native Set 1,000,000 add & has 175.42 5.70 0.02 1,000,000 ObjKey set & get 345.12 2.90 0.05 Native Map 1,000,000 ObjKey set & get 495.13 2.02 0.05 Native Set 1,000,000 ObjKey add & has 276.79 3.61 0.04
+
test name time taken (ms) executions per sec sample deviation 1,000,000 set 131.27 7.62 0.05 Native Map 1,000,000 set 267.34 3.74 0.04 Native Set 1,000,000 add 207.03 4.83 0.06 1,000,000 set & get 132.19 7.56 0.03 Native Map 1,000,000 set & get 276.30 3.62 0.01 Native Set 1,000,000 add & has 187.74 5.33 0.02 1,000,000 ObjKey set & get 336.39 2.97 0.03 Native Map 1,000,000 ObjKey set & get 394.47 2.54 0.09 Native Set 1,000,000 ObjKey add & has 295.48 3.38 0.04
heap
-
test name time taken (ms) executions per sec sample deviation 100,000 add & poll 27.57 36.27 0.00 100,000 add & dfs 34.44 29.04 2.58e-4 10,000 fib add & pop 361.99 2.76 0.00
+
test name time taken (ms) executions per sec sample deviation 100,000 add & poll 24.18 41.35 6.43e-4 100,000 add & dfs 33.64 29.72 0.00 10,000 fib add & pop 363.38 2.75 0.00
doubly-linked-list
-
test name time taken (ms) executions per sec sample deviation 1,000,000 push 214.62 4.66 0.03 1,000,000 unshift 223.53 4.47 0.03 1,000,000 unshift & shift 173.70 5.76 0.03 1,000,000 addBefore 341.89 2.92 0.09
+
test name time taken (ms) executions per sec sample deviation 1,000,000 push 220.16 4.54 0.03 1,000,000 unshift 210.84 4.74 0.05 1,000,000 unshift & shift 189.59 5.27 0.07 1,000,000 addBefore 412.74 2.42 0.17
singly-linked-list
-
test name time taken (ms) executions per sec sample deviation 1,000,000 push & shift 195.74 5.11 0.04 10,000 push & pop 239.88 4.17 0.01 10,000 addBefore 257.45 3.88 0.01
+
test name time taken (ms) executions per sec sample deviation 1,000,000 push & shift 252.06 3.97 0.09 10,000 push & pop 230.29 4.34 0.01 10,000 addBefore 261.57 3.82 0.01
priority-queue
-
test name time taken (ms) executions per sec sample deviation 100,000 add & poll 79.62 12.56 5.34e-4
+
test name time taken (ms) executions per sec sample deviation 100,000 add & poll 75.71 13.21 8.95e-4
deque
-
test name time taken (ms) executions per sec sample deviation 1,000,000 push 14.20 70.43 1.32e-4 1,000,000 push & pop 23.13 43.22 1.71e-4 100,000 push & shift 2.40 416.67 2.68e-5 Native Array 100,000 push & shift 3050.20 0.33 0.25 100,000 unshift & shift 2.24 446.26 5.35e-5 Native Array 100,000 unshift & shift 5037.86 0.20 0.17
+
test name time taken (ms) executions per sec sample deviation 1,000,000 push 25.18 39.71 0.01 1,000,000 push & pop 33.52 29.83 0.01 100,000 push & shift 3.61 276.96 5.50e-4 Native Array 100,000 push & shift 2703.16 0.37 0.11 100,000 unshift & shift 3.73 268.14 8.29e-4 Native Array 100,000 unshift & shift 4767.61 0.21 0.40
queue
-
test name time taken (ms) executions per sec sample deviation 1,000,000 push 47.09 21.23 0.01 100,000 push & shift 5.06 197.72 1.25e-4 Native Array 100,000 push & shift 3038.51 0.33 0.12 Native Array 100,000 push & pop 4.44 225.23 1.51e-4
+
test name time taken (ms) executions per sec sample deviation 1,000,000 push 50.56 19.78 0.01 100,000 push & shift 5.99 166.85 0.00 Native Array 100,000 push & shift 2962.43 0.34 0.29 Native Array 100,000 push & pop 4.49 222.69 3.01e-4
stack
-
test name time taken (ms) executions per sec sample deviation 1,000,000 push 45.16 22.14 0.01 1,000,000 push & pop 51.35 19.47 0.01
+
test name time taken (ms) executions per sec sample deviation 1,000,000 push 59.68 16.76 0.03 1,000,000 push & pop 52.04 19.22 0.01
trie
-
test name time taken (ms) executions per sec sample deviation 100,000 push 44.20 22.63 5.61e-4 100,000 getWords 91.81 10.89 0.00
+
test name time taken (ms) executions per sec sample deviation 100,000 push 47.70 20.96 0.00 100,000 getWords 66.53 15.03 0.00
[//]: # (No deletion!!! End of Replace Section)
diff --git a/src/data-structures/binary-tree/avl-tree.ts b/src/data-structures/binary-tree/avl-tree.ts
index 487c5e2..b401cf3 100644
--- a/src/data-structures/binary-tree/avl-tree.ts
+++ b/src/data-structures/binary-tree/avl-tree.ts
@@ -48,17 +48,17 @@ export class AVLTree<
extends BST
implements IBinaryTree {
/**
- * The constructor function initializes an AVLTree object with optional nodes and options.
- * @param [nodes] - The `nodes` parameter is an optional iterable of `KeyOrNodeOrEntry`
+ * The constructor function initializes an AVLTree object with optional keysOrNodesOrEntries and options.
+ * @param [keysOrNodesOrEntries] - The `keysOrNodesOrEntries` parameter is an optional iterable of `KeyOrNodeOrEntry`
* objects. It represents a collection of nodes that will be added to the AVL tree during
* initialization.
* @param [options] - The `options` parameter is an optional object that allows you to customize the
* behavior of the AVL tree. It is of type `Partial`, which means that you can
* provide only a subset of the properties defined in the `AVLTreeOptions` interface.
*/
- constructor(nodes?: Iterable>, options?: Partial>) {
+ constructor(keysOrNodesOrEntries: Iterable> = [], options?: AVLTreeOptions) {
super([], options);
- if (nodes) super.addMany(nodes);
+ if (keysOrNodesOrEntries) super.addMany(keysOrNodesOrEntries);
}
/**
diff --git a/src/data-structures/binary-tree/binary-tree.ts b/src/data-structures/binary-tree/binary-tree.ts
index d1d720a..501f8c3 100644
--- a/src/data-structures/binary-tree/binary-tree.ts
+++ b/src/data-structures/binary-tree/binary-tree.ts
@@ -111,29 +111,25 @@ export class BinaryTree<
iterationType = IterationType.ITERATIVE;
/**
- * The constructor function initializes a binary tree object with optional nodes and options.
- * @param [nodes] - An optional iterable of KeyOrNodeOrEntry objects. These objects represent the
+ * The constructor function initializes a binary tree object with optional keysOrNodesOrEntries and options.
+ * @param [keysOrNodesOrEntries] - An optional iterable of KeyOrNodeOrEntry objects. These objects represent the
* nodes to be added to the binary tree.
* @param [options] - The `options` parameter is an optional object that can contain additional
* configuration options for the binary tree. In this case, it is of type
* `Partial`, which means that not all properties of `BinaryTreeOptions` are
* required.
*/
- constructor(nodes?: Iterable>, options?: Partial>) {
+ constructor(keysOrNodesOrEntries: Iterable> = [], options?: BinaryTreeOptions) {
super();
if (options) {
const { iterationType, extractor } = options;
- if (iterationType) {
- this.iterationType = iterationType;
- }
- if (extractor) {
- this._extractor = extractor;
- }
+ if (iterationType) this.iterationType = iterationType;
+ if (extractor) this._extractor = extractor;
}
this._size = 0;
- if (nodes) this.addMany(nodes);
+ if (keysOrNodesOrEntries) this.addMany(keysOrNodesOrEntries);
}
protected _extractor = (key: K) => Number(key);
diff --git a/src/data-structures/binary-tree/bst.ts b/src/data-structures/binary-tree/bst.ts
index 77a058f..6b38eaa 100644
--- a/src/data-structures/binary-tree/bst.ts
+++ b/src/data-structures/binary-tree/bst.ts
@@ -92,25 +92,23 @@ export class BST<
implements IBinaryTree {
/**
* This is the constructor function for a binary search tree class in TypeScript, which initializes
- * the tree with optional nodes and options.
- * @param [nodes] - An optional iterable of KeyOrNodeOrEntry objects that will be added to the
+ * the tree with optional keysOrNodesOrEntries and options.
+ * @param [keysOrNodesOrEntries] - An optional iterable of KeyOrNodeOrEntry objects that will be added to the
* binary search tree.
* @param [options] - The `options` parameter is an optional object that can contain additional
* configuration options for the binary search tree. It can have the following properties:
*/
- constructor(nodes?: Iterable>, options?: Partial>) {
+ constructor(keysOrNodesOrEntries: Iterable> = [], options?: BSTOptions) {
super([], options);
if (options) {
const { variant } = options;
- if (variant) {
- this._variant = variant;
- }
+ if (variant) this._variant = variant;
}
this._root = undefined;
- if (nodes) this.addMany(nodes);
+ if (keysOrNodesOrEntries) this.addMany(keysOrNodesOrEntries);
}
protected override _root?: N;
diff --git a/src/data-structures/binary-tree/rb-tree.ts b/src/data-structures/binary-tree/rb-tree.ts
index 7b06226..3c233d2 100644
--- a/src/data-structures/binary-tree/rb-tree.ts
+++ b/src/data-structures/binary-tree/rb-tree.ts
@@ -53,7 +53,7 @@ export class RedBlackTree<
/**
* This is the constructor function for a Red-Black Tree data structure in TypeScript, which
* initializes the tree with optional nodes and options.
- * @param [nodes] - The `nodes` parameter is an optional iterable of `KeyOrNodeOrEntry`
+ * @param [keysOrNodesOrEntries] - The `keysOrNodesOrEntries` parameter is an optional iterable of `KeyOrNodeOrEntry`
* objects. It represents the initial nodes that will be added to the RBTree during its
* construction. If this parameter is provided, the `addMany` method is called to add all the
* nodes to the
@@ -61,11 +61,11 @@ export class RedBlackTree<
* behavior of the RBTree. It is of type `Partial`, which means that you can provide
* only a subset of the properties defined in the `RBTreeOptions` interface.
*/
- constructor(nodes?: Iterable>, options?: Partial>) {
+ constructor(keysOrNodesOrEntries: Iterable> = [], options?: RBTreeOptions) {
super([], options);
this._root = this.Sentinel;
- if (nodes) super.addMany(nodes);
+ if (keysOrNodesOrEntries) super.addMany(keysOrNodesOrEntries);
}
protected _root: N;
diff --git a/src/data-structures/binary-tree/tree-multimap.ts b/src/data-structures/binary-tree/tree-multimap.ts
index 4a7ddba..8981cde 100644
--- a/src/data-structures/binary-tree/tree-multimap.ts
+++ b/src/data-structures/binary-tree/tree-multimap.ts
@@ -52,9 +52,9 @@ export class TreeMultimap<
>
extends AVLTree
implements IBinaryTree {
- constructor(nodes?: Iterable>, options?: Partial>) {
+ constructor(keysOrNodesOrEntries: Iterable> = [], options?: TreeMultimapOptions) {
super([], options);
- if (nodes) this.addMany(nodes);
+ if (keysOrNodesOrEntries) this.addMany(keysOrNodesOrEntries);
}
private _count = 0;
diff --git a/src/data-structures/hash/hash-map.ts b/src/data-structures/hash/hash-map.ts
index b91b5d9..da85828 100644
--- a/src/data-structures/hash/hash-map.ts
+++ b/src/data-structures/hash/hash-map.ts
@@ -5,34 +5,35 @@
* @copyright Copyright (c) 2022 Tyler Zeng
* @license MIT License
*/
-import type { EntryCallback, HashMapLinkedNode, HashMapOptions, HashMapStoreItem } from '../../types';
+import type {
+ EntryCallback,
+ HashMapLinkedNode,
+ HashMapOptions,
+ HashMapStoreItem,
+ LinkedHashMapOptions
+} from '../../types';
import { IterableEntryBase } from '../base';
import { isWeakKey, rangeCheck } from '../../utils';
/**
* 1. Key-Value Pair Storage: HashMap stores key-value pairs. Each key maps to a value.
- * 2. Fast Lookup: It's used when you need to quickly find, insert, or delete elements based on a key.
+ * 2. Fast Lookup: It's used when you need to quickly find, insert, or delete entries based on a key.
* 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 elements, and the order may change over time.
+ * 4. Unordered Collection: HashMap does not guarantee the order of entries, and the order may change over time.
*/
export class HashMap extends IterableEntryBase {
protected _store: { [key: string]: HashMapStoreItem } = {};
protected _objMap: Map = new Map();
/**
- * The constructor function initializes a new instance of a class with optional elements and options.
- * @param elements - The `elements` parameter is an iterable containing key-value pairs `[K, V]`. It
+ * 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:
*/
- constructor(
- elements: Iterable<[K, V]> = [],
- options?: {
- hashFn: (key: K) => string;
- }
- ) {
+ constructor(entries: Iterable<[K, V]> = [], options?: HashMapOptions) {
super();
if (options) {
const { hashFn } = options;
@@ -40,8 +41,8 @@ export class HashMap extends IterableEntryBase {
this._hashFn = hashFn;
}
}
- if (elements) {
- this.setMany(elements);
+ if (entries) {
+ this.setMany(entries);
}
}
@@ -88,12 +89,12 @@ export class HashMap extends IterableEntryBase {
/**
* The function "setMany" sets multiple key-value pairs in a map.
- * @param elements - The `elements` parameter is an iterable containing key-value pairs. Each
- * key-value pair is represented as an array with two elements: the key and the value.
+ * @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.
*/
- setMany(elements: Iterable<[K, V]>): boolean[] {
+ setMany(entries: Iterable<[K, V]>): boolean[] {
const results: boolean[] = [];
- for (const [key, value] of elements) results.push(this.set(key, value));
+ for (const [key, value] of entries) results.push(this.set(key, value));
return results;
}
@@ -214,10 +215,6 @@ export class HashMap extends IterableEntryBase {
return filteredMap;
}
- print(): void {
- console.log([...this.entries()]);
- }
-
put(key: K, value: V): boolean {
return this.set(key, value);
}
@@ -261,8 +258,8 @@ export class HashMap extends IterableEntryBase {
}
/**
- * 1. Maintaining the Order of Element Insertion: Unlike HashMap, LinkedHashMap maintains the order in which elements are inserted. Therefore, when you traverse it, elements will be returned in the order they were inserted into the map.
- * 2. Based on Hash Table and Linked List: It combines the structures of a hash table and a linked list, using the hash table to ensure fast access, while maintaining the order of elements through the linked list.
+ * 1. Maintaining the Order of Element Insertion: Unlike HashMap, LinkedHashMap maintains the order in which entries are inserted. Therefore, when you traverse it, entries will be returned in the order they were inserted into the map.
+ * 2. Based on Hash Table and Linked List: It combines the structures of a hash table and a linked list, using the hash table to ensure fast access, while maintaining the order of entries through the linked list.
* 3. Time Complexity: Similar to HashMap, LinkedHashMap offers constant-time performance for get and put operations in most cases.
*/
export class LinkedHashMap extends IterableEntryBase {
@@ -271,25 +268,20 @@ export class LinkedHashMap extends IterableEntryBase {
protected _head: HashMapLinkedNode;
protected _tail: HashMapLinkedNode;
protected readonly _sentinel: HashMapLinkedNode;
- protected _hashFn: (key: K) => string;
- protected _objHashFn: (key: K) => object;
- constructor(
- elements?: Iterable<[K, V]>,
- options: HashMapOptions = {
- hashFn: (key: K) => String(key),
- objHashFn: (key: K) => key
- }
- ) {
+ constructor(entries?: Iterable<[K, V]>, options?: LinkedHashMapOptions) {
super();
this._sentinel = >{};
this._sentinel.prev = this._sentinel.next = this._head = this._tail = this._sentinel;
- const { hashFn, objHashFn } = options;
- this._hashFn = hashFn;
- this._objHashFn = objHashFn;
- if (elements) {
- for (const el of elements) {
+ if (options) {
+ const { hashFn, objHashFn } = options;
+ if (hashFn) this._hashFn = hashFn;
+ if (objHashFn) this._objHashFn = objHashFn;
+ }
+
+ if (entries) {
+ for (const el of entries) {
this.set(el[0], el[1]);
}
}
@@ -547,7 +539,7 @@ export class LinkedHashMap extends IterableEntryBase {
* Time Complexity: O(1)
* Space Complexity: O(1)
*
- * The `clear` function clears all the elements in a data structure and resets its properties.
+ * The `clear` function clears all the entries in a data structure and resets its properties.
*/
clear(): void {
this._noObjMap = {};
@@ -564,11 +556,6 @@ export class LinkedHashMap extends IterableEntryBase {
return cloned;
}
- /**
- * Time Complexity: O(n)
- * Space Complexity: O(n)
- */
-
/**
* Time Complexity: O(n)
* Space Complexity: O(n)
@@ -596,11 +583,6 @@ export class LinkedHashMap extends IterableEntryBase {
return filteredMap;
}
- /**
- * Time Complexity: O(n)
- * Space Complexity: O(n)
- */
-
/**
* Time Complexity: O(n)
* Space Complexity: O(n)
@@ -629,12 +611,26 @@ export class LinkedHashMap extends IterableEntryBase {
return mappedMap;
}
+ /**
+ * Time Complexity: O(n)
+ * Space Complexity: O(n)
+ */
+
put(key: K, value: V): boolean {
return this.set(key, value);
}
/**
- * Time Complexity: O(n), where n is the number of elements in the LinkedHashMap.
+ * Time Complexity: O(n)
+ * Space Complexity: O(n)
+ */
+
+ protected _hashFn: (key: K) => string = (key: K) => String(key);
+
+ protected _objHashFn: (key: K) => object = (key: K) => key;
+
+ /**
+ * Time Complexity: O(n), where n is the number of entries in the LinkedHashMap.
* Space Complexity: O(1)
*
* The above function is an iterator that yields key-value pairs from a linked list.
diff --git a/src/data-structures/hash/hash-table.ts b/src/data-structures/hash/hash-table.ts
deleted file mode 100644
index 58bf6eb..0000000
--- a/src/data-structures/hash/hash-table.ts
+++ /dev/null
@@ -1,318 +0,0 @@
-/**
- * data-structure-typed
- *
- * @author Tyler Zeng
- * @copyright Copyright (c) 2022 Tyler Zeng
- * @license MIT License
- */
-
-import type { HashFunction } from '../../types';
-
-export class HashTableNode {
- key: K;
- value: V;
- next: HashTableNode | undefined;
-
- constructor(key: K, value: V) {
- this.key = key;
- this.value = value;
- this.next = undefined;
- }
-}
-
-export class HashTable {
- protected static readonly DEFAULT_CAPACITY = 16;
- protected static readonly LOAD_FACTOR = 0.75;
-
- constructor(capacity: number = HashTable.DEFAULT_CAPACITY, hashFn?: HashFunction) {
- this._hashFn = hashFn || this._defaultHashFn;
- this._capacity = Math.max(capacity, HashTable.DEFAULT_CAPACITY);
- this._size = 0;
- this._buckets = new Array | undefined>(this._capacity).fill(undefined);
- }
-
- protected _capacity: number;
-
- get capacity(): number {
- return this._capacity;
- }
-
- protected _size: number;
-
- get size(): number {
- return this._size;
- }
-
- protected _buckets: Array | undefined>;
-
- get buckets(): Array | undefined> {
- return this._buckets;
- }
-
- protected _hashFn: HashFunction;
-
- get hashFn(): HashFunction {
- return this._hashFn;
- }
-
- /**
- * The set function adds a key-value pair to the hash table, handling collisions and resizing if necessary.
- * @param {K} key - The key parameter represents the key of the key-value pair that you want to insert into the hash
- * table. It is of type K, which is a generic type representing the key's data type.
- * @param {V} value - The parameter `value` represents the value that you want to associate with the given key in the hash
- * table.
- * @returns Nothing is being returned. The return type of the `put` method is `void`, which means it does not return any
- * value.
- */
- set(key: K, value: V): void {
- const index = this._hash(key);
- const newNode = new HashTableNode(key, value);
-
- if (!this._buckets[index]) {
- this._buckets[index] = newNode;
- } else {
- // Handle collisions, consider using open addressing, etc.
- let currentNode = this._buckets[index]!;
- while (currentNode) {
- if (currentNode.key === key) {
- // If the key already exists, update the value
- currentNode.value = value;
- return;
- }
- if (!currentNode.next) {
- break;
- }
- currentNode = currentNode.next;
- }
- // Add to the end of the linked list
- currentNode.next = newNode;
- }
- this._size++;
-
- // If the load factor is too high, resize the hash table
- if (this._size / this._capacity >= HashTable.LOAD_FACTOR) {
- this._expand();
- }
- }
-
- /**
- * The `get` function retrieves the value associated with a given key from a hash table.
- * @param {K} key - The `key` parameter represents the key of the element that we want to retrieve from the data
- * structure.
- * @returns The method is returning the value associated with the given key if it exists in the hash table. If the key is
- * not found, it returns `undefined`.
- */
- get(key: K): V | undefined {
- const index = this._hash(key);
- let currentNode = this._buckets[index];
-
- while (currentNode) {
- if (currentNode.key === key) {
- return currentNode.value;
- }
- currentNode = currentNode.next;
- }
- return undefined; // Key not found
- }
-
- /**
- * The delete function removes a key-value pair from a hash table.
- * @param {K} key - The `key` parameter represents the key of the key-value pair that needs to be removed from the hash
- * table.
- * @returns Nothing is being returned. The `delete` method has a return type of `void`, which means it does not return
- * any value.
- */
- delete(key: K): void {
- const index = this._hash(key);
- let currentNode = this._buckets[index];
- let prevNode: HashTableNode | undefined = undefined;
-
- while (currentNode) {
- if (currentNode.key === key) {
- if (prevNode) {
- prevNode.next = currentNode.next;
- } else {
- this._buckets[index] = currentNode.next;
- }
- this._size--;
- currentNode.next = undefined; // Release memory
- return;
- }
- prevNode = currentNode;
- currentNode = currentNode.next;
- }
- }
-
- * [Symbol.iterator](): Generator<[K, V], void, undefined> {
- for (const bucket of this._buckets) {
- let currentNode = bucket;
- while (currentNode) {
- yield [currentNode.key, currentNode.value];
- currentNode = currentNode.next;
- }
- }
- }
-
- forEach(callback: (entry: [K, V], index: number, table: HashTable) => void): void {
- let index = 0;
- for (const entry of this) {
- callback(entry, index, this);
- index++;
- }
- }
-
- filter(predicate: (entry: [K, V], index: number, table: HashTable) => boolean): HashTable {
- const newTable = new HashTable();
- let index = 0;
- for (const [key, value] of this) {
- if (predicate([key, value], index, this)) {
- newTable.set(key, value);
- }
- index++;
- }
- return newTable;
- }
-
- map(callback: (entry: [K, V], index: number, table: HashTable) => T): HashTable {
- const newTable = new HashTable();
- let index = 0;
- for (const [key, value] of this) {
- newTable.set(key, callback([key, value], index, this));
- index++;
- }
- return newTable;
- }
-
- reduce(callback: (accumulator: T, entry: [K, V], index: number, table: HashTable) => T, initialValue: T): T {
- let accumulator = initialValue;
- let index = 0;
- for (const entry of this) {
- accumulator = callback(accumulator, entry, index, this);
- index++;
- }
- return accumulator;
- }
-
- /**
- * The function `_defaultHashFn` calculates the hash value of a given key and returns the remainder when divided by the
- * capacity of the data structure.
- * @param {K} key - The `key` parameter is the input value that needs to be hashed. It can be of any type, but in this
- * code snippet, it is checked whether the key is a string or an object. If it is a string, the `_murmurStringHashFn`
- * function is used to
- * @returns the hash value of the key modulo the capacity of the data structure.
- */
- protected _defaultHashFn(key: K): number {
- // Can be replaced with other hash functions as needed
- const hashValue = typeof key === 'string' ? this._murmurStringHashFn(key) : this._objectHash(key);
- return hashValue % this._capacity;
- }
-
- /**
- * The `_multiplicativeStringHashFn` function calculates a hash value for a given string key using the multiplicative
- * string hash function.
- * @param {K} key - The `key` parameter is the input value for which we want to calculate the hash. It can be of any
- * type, as it is generic (`K`). The function converts the `key` to a string using the `String()` function.
- * @returns a number, which is the result of the multiplicative string hash function applied to the input key.
- */
- protected _multiplicativeStringHashFn(key: K): number {
- const keyString = String(key);
- let hash = 0;
- for (let i = 0; i < keyString.length; i++) {
- const charCode = keyString.charCodeAt(i);
- // Some constants for adjusting the hash function
- const A = 0.618033988749895;
- const M = 1 << 30; // 2^30
- hash = (hash * A + charCode) % M;
- }
- return Math.abs(hash); // Take absolute value to ensure non-negative numbers
- }
-
- /**
- * The function `_murmurStringHashFn` calculates a hash value for a given string key using the MurmurHash algorithm.
- * @param {K} key - The `key` parameter is the input value for which you want to calculate the hash. It can be of any
- * type, but it will be converted to a string using the `String()` function before calculating the hash.
- * @returns a number, which is the hash value calculated for the given key.
- */
- protected _murmurStringHashFn(key: K): number {
- const keyString = String(key);
- const seed = 0;
- let hash = seed;
-
- for (let i = 0; i < keyString.length; i++) {
- const char = keyString.charCodeAt(i);
- hash = (hash ^ char) * 0x5bd1e995;
- hash = (hash ^ (hash >>> 15)) * 0x27d4eb2d;
- hash = hash ^ (hash >>> 15);
- }
-
- return Math.abs(hash);
- }
-
- /**
- * The _hash function takes a key and returns a number.
- * @param {K} key - The parameter "key" is of type K, which represents the type of the key that will be hashed.
- * @returns The hash function is returning a number.
- */
- protected _hash(key: K): number {
- return this.hashFn(key);
- }
-
- /**
- * The function calculates a hash value for a given string using the djb2 algorithm.
- * @param {string} key - The `key` parameter in the `stringHash` function is a string value that represents the input for
- * which we want to calculate the hash value.
- * @returns a number, which is the hash value of the input string.
- */
- protected _stringHash(key: string): number {
- let hash = 0;
- for (let i = 0; i < key.length; i++) {
- hash = (hash * 31 + key.charCodeAt(i)) & 0xffffffff;
- }
- return hash;
- }
-
- /**
- * The function `_objectHash` takes a key and returns a hash value, using a custom hash function for objects.
- * @param {K} key - The parameter "key" is of type "K", which means it can be any type. It could be a string, number,
- * boolean, object, or any other type of value. The purpose of the objectHash function is to generate a hash value for
- * the key, which can be used for
- * @returns a number, which is the hash value of the key.
- */
- protected _objectHash(key: K): number {
- // If the key is an object, you can write a custom hash function
- // For example, convert the object's properties to a string and use string hashing
- // This is just an example; you should write a specific object hash function as needed
- return this._stringHash(JSON.stringify(key));
- }
-
- /**
- * The `expand` function increases the capacity of a hash table by creating a new array of buckets with double the
- * capacity and rehashing all the existing key-value pairs into the new buckets.
- */
- protected _expand(): void {
- const newCapacity = this._capacity * 2;
- const newBuckets = new Array | undefined>(newCapacity).fill(undefined);
-
- for (const bucket of this._buckets) {
- let currentNode = bucket;
- while (currentNode) {
- const newIndex = this._hash(currentNode.key);
- const newNode = new HashTableNode(currentNode.key, currentNode.value);
-
- if (!newBuckets[newIndex]) {
- newBuckets[newIndex] = newNode;
- } else {
- let currentNewNode = newBuckets[newIndex]!;
- while (currentNewNode.next) {
- currentNewNode = currentNewNode.next;
- }
- currentNewNode.next = newNode;
- }
- currentNode = currentNode.next;
- }
- }
-
- this._buckets = newBuckets;
- this._capacity = newCapacity;
- }
-}
diff --git a/src/data-structures/hash/index.ts b/src/data-structures/hash/index.ts
index 5d7849d..e4fd2c4 100644
--- a/src/data-structures/hash/index.ts
+++ b/src/data-structures/hash/index.ts
@@ -1,2 +1 @@
-export * from './hash-table';
export * from './hash-map';
diff --git a/src/data-structures/heap/heap.ts b/src/data-structures/heap/heap.ts
index 5914ef0..8e2d9fe 100644
--- a/src/data-structures/heap/heap.ts
+++ b/src/data-structures/heap/heap.ts
@@ -21,23 +21,12 @@ import { IterableElementBase } from '../base';
* 8. Graph Algorithms: Such as Dijkstra's shortest path algorithm and Prim's minimum spanning tree algorithm, which use heaps to improve performance.
*/
export class Heap extends IterableElementBase {
- options: HeapOptions;
-
- constructor(elements?: Iterable, options?: HeapOptions) {
+ constructor(elements: Iterable = [], options?: HeapOptions) {
super();
- const defaultComparator = (a: E, b: E) => {
- if (!(typeof a === 'number' && typeof b === 'number')) {
- throw new Error('The a, b params of compare function must be number');
- } else {
- return a - b;
- }
- };
+
if (options) {
- this.options = options;
- } else {
- this.options = {
- comparator: defaultComparator
- };
+ const { comparator } = options;
+ if (comparator) this._comparator = comparator;
}
if (elements) {
@@ -48,6 +37,18 @@ export class Heap extends IterableElementBase {
}
}
+ protected _comparator = (a: E, b: E) => {
+ if (!(typeof a === 'number' && typeof b === 'number')) {
+ throw new Error('The a, b params of compare function must be number');
+ } else {
+ return a - b;
+ }
+ };
+
+ get comparator() {
+ return this._comparator;
+ }
+
protected _elements: E[] = [];
get elements(): E[] {
@@ -278,7 +279,7 @@ export class Heap extends IterableElementBase {
* @returns A new Heap instance containing the same elements.
*/
clone(): Heap {
- const clonedHeap = new Heap([], this.options);
+ const clonedHeap = new Heap([], { comparator: this.comparator });
clonedHeap._elements = [...this.elements];
return clonedHeap;
}
@@ -413,7 +414,7 @@ export class Heap extends IterableElementBase {
while (index > 0) {
const parent = (index - 1) >> 1;
const parentItem = this.elements[parent];
- if (this.options.comparator(parentItem, element) <= 0) break;
+ if (this.comparator(parentItem, element) <= 0) break;
this.elements[index] = parentItem;
index = parent;
}
@@ -435,11 +436,11 @@ export class Heap extends IterableElementBase {
let left = (index << 1) | 1;
const right = left + 1;
let minItem = this.elements[left];
- if (right < this.elements.length && this.options.comparator(minItem, this.elements[right]) > 0) {
+ if (right < this.elements.length && this.comparator(minItem, this.elements[right]) > 0) {
left = right;
minItem = this.elements[right];
}
- if (this.options.comparator(minItem, element) >= 0) break;
+ if (this.comparator(minItem, element) >= 0) break;
this.elements[index] = minItem;
index = left;
}
diff --git a/src/data-structures/heap/max-heap.ts b/src/data-structures/heap/max-heap.ts
index d8def84..89ebef2 100644
--- a/src/data-structures/heap/max-heap.ts
+++ b/src/data-structures/heap/max-heap.ts
@@ -20,7 +20,7 @@ import { Heap } from './heap';
*/
export class MaxHeap extends Heap {
constructor(
- elements?: Iterable,
+ elements: Iterable = [],
options: HeapOptions = {
comparator: (a: E, b: E) => {
if (!(typeof a === 'number' && typeof b === 'number')) {
diff --git a/src/data-structures/heap/min-heap.ts b/src/data-structures/heap/min-heap.ts
index e43dc9e..2ddce15 100644
--- a/src/data-structures/heap/min-heap.ts
+++ b/src/data-structures/heap/min-heap.ts
@@ -20,7 +20,7 @@ import { Heap } from './heap';
*/
export class MinHeap extends Heap {
constructor(
- elements?: Iterable,
+ elements: Iterable = [],
options: HeapOptions = {
comparator: (a: E, b: E) => {
if (!(typeof a === 'number' && typeof b === 'number')) {
diff --git a/src/data-structures/linked-list/doubly-linked-list.ts b/src/data-structures/linked-list/doubly-linked-list.ts
index 89273b4..caaffc9 100644
--- a/src/data-structures/linked-list/doubly-linked-list.ts
+++ b/src/data-structures/linked-list/doubly-linked-list.ts
@@ -35,7 +35,7 @@ export class DoublyLinkedList extends IterableElementBase {
/**
* The constructor initializes the linked list with an empty head, tail, and size.
*/
- constructor(elements?: Iterable) {
+ constructor(elements: Iterable = []) {
super();
this._head = undefined;
this._tail = undefined;
diff --git a/src/data-structures/linked-list/singly-linked-list.ts b/src/data-structures/linked-list/singly-linked-list.ts
index a29bcc5..aa32809 100644
--- a/src/data-structures/linked-list/singly-linked-list.ts
+++ b/src/data-structures/linked-list/singly-linked-list.ts
@@ -27,11 +27,8 @@ export class SinglyLinkedList extends IterableElementBase {
/**
* The constructor initializes the linked list with an empty head, tail, and length.
*/
- constructor(elements?: Iterable) {
+ constructor(elements: Iterable = []) {
super();
- this._head = undefined;
- this._tail = undefined;
- this._size = 0;
if (elements) {
for (const el of elements) this.push(el);
}
@@ -49,7 +46,7 @@ export class SinglyLinkedList extends IterableElementBase {
return this._tail;
}
- protected _size: number;
+ protected _size: number = 0;
get size(): number {
return this._size;
diff --git a/src/data-structures/linked-list/skip-linked-list.ts b/src/data-structures/linked-list/skip-linked-list.ts
index 8759a63..da03ad4 100644
--- a/src/data-structures/linked-list/skip-linked-list.ts
+++ b/src/data-structures/linked-list/skip-linked-list.ts
@@ -5,6 +5,7 @@
* @copyright Copyright (c) 2022 Tyler Zeng
* @license MIT License
*/
+import type { SkipLinkedListOptions } from '../../types';
export class SkipListNode {
key: K;
@@ -19,39 +20,37 @@ export class SkipListNode {
}
export class SkipList {
- /**
- * The constructor initializes a SkipList with a specified maximum level and probability.
- * @param [maxLevel=16] - The `maxLevel` parameter represents the maximum level that a skip list can have. It determines
- * the maximum number of levels that can be created in the skip list.
- * @param [probability=0.5] - The probability parameter represents the probability of a node being promoted to a higher
- * level in the skip list. It is used to determine the height of each node in the skip list.
- */
- constructor(maxLevel = 16, probability = 0.5) {
- this._head = new SkipListNode(undefined as any, undefined as any, maxLevel);
- this._level = 0;
- this._maxLevel = maxLevel;
- this._probability = probability;
+ constructor(elements: Iterable<[K, V]> = [], options?: SkipLinkedListOptions) {
+ if (options) {
+ const { maxLevel, probability } = options;
+ if (typeof maxLevel === 'number') this._maxLevel = maxLevel;
+ if (typeof probability === 'number') this._probability = probability;
+ }
+
+ if (elements) {
+ for (const [key, value] of elements) this.add(key, value);
+ }
}
- protected _head: SkipListNode;
+ protected _head: SkipListNode = new SkipListNode(undefined as any, undefined as any, this.maxLevel);
get head(): SkipListNode {
return this._head;
}
- protected _level: number;
+ protected _level: number = 0;
get level(): number {
return this._level;
}
- protected _maxLevel: number;
+ protected _maxLevel: number = 16;
get maxLevel(): number {
return this._maxLevel;
}
- protected _probability: number;
+ protected _probability: number = 0.5;
get probability(): number {
return this._probability;
diff --git a/src/data-structures/matrix/matrix.ts b/src/data-structures/matrix/matrix.ts
index 9ad7bd0..21a988d 100644
--- a/src/data-structures/matrix/matrix.ts
+++ b/src/data-structures/matrix/matrix.ts
@@ -5,6 +5,7 @@
* @copyright Copyright (c) 2022 Tyler Zeng
* @license MIT License
*/
+import type { MatrixOptions } from '../../types';
export class Matrix {
/**
@@ -14,16 +15,7 @@ export class Matrix {
* @param [options] - The `options` parameter is an optional object that can contain the following
* properties:
*/
- constructor(
- data: number[][],
- options?: {
- rows?: number;
- cols?: number;
- addFn?: (a: number, b: number) => any;
- subtractFn?: (a: number, b: number) => any;
- multiplyFn?: (a: number, b: number) => any;
- }
- ) {
+ constructor(data: number[][], options?: MatrixOptions) {
if (options) {
const { rows, cols, addFn, subtractFn, multiplyFn } = options;
if (typeof rows === 'number' && rows > 0) this._rows = rows;
diff --git a/src/data-structures/priority-queue/max-priority-queue.ts b/src/data-structures/priority-queue/max-priority-queue.ts
index bb5c5c5..287b206 100644
--- a/src/data-structures/priority-queue/max-priority-queue.ts
+++ b/src/data-structures/priority-queue/max-priority-queue.ts
@@ -10,7 +10,7 @@ import { PriorityQueue } from './priority-queue';
export class MaxPriorityQueue extends PriorityQueue {
constructor(
- elements?: Iterable,
+ elements: Iterable = [],
options: PriorityQueueOptions = {
comparator: (a: E, b: E) => {
if (!(typeof a === 'number' && typeof b === 'number')) {
diff --git a/src/data-structures/priority-queue/min-priority-queue.ts b/src/data-structures/priority-queue/min-priority-queue.ts
index 93d5278..8e12bce 100644
--- a/src/data-structures/priority-queue/min-priority-queue.ts
+++ b/src/data-structures/priority-queue/min-priority-queue.ts
@@ -10,7 +10,7 @@ import { PriorityQueue } from './priority-queue';
export class MinPriorityQueue extends PriorityQueue {
constructor(
- elements?: Iterable,
+ elements: Iterable = [],
options: PriorityQueueOptions = {
comparator: (a: E, b: E) => {
if (!(typeof a === 'number' && typeof b === 'number')) {
diff --git a/src/data-structures/priority-queue/priority-queue.ts b/src/data-structures/priority-queue/priority-queue.ts
index 6e454a6..d4c15e7 100644
--- a/src/data-structures/priority-queue/priority-queue.ts
+++ b/src/data-structures/priority-queue/priority-queue.ts
@@ -17,7 +17,7 @@ import { Heap } from '../heap';
* 6. Kth Largest Element in a Data Stream: Used to maintain a min-heap of size K for quickly finding the Kth largest element in stream data
*/
export class PriorityQueue extends Heap {
- constructor(elements?: Iterable, options?: PriorityQueueOptions) {
+ constructor(elements: Iterable = [], options?: PriorityQueueOptions) {
super(elements, options);
}
}
diff --git a/src/data-structures/queue/deque.ts b/src/data-structures/queue/deque.ts
index 25b0cb5..02aa162 100644
--- a/src/data-structures/queue/deque.ts
+++ b/src/data-structures/queue/deque.ts
@@ -5,7 +5,7 @@
* @copyright Copyright (c) 2022 Tyler Zeng
* @license MIT License
*/
-import type { ElementCallback, IterableWithSizeOrLength } from '../../types';
+import type { DequeOptions, ElementCallback, IterableWithSizeOrLength } from '../../types';
import { IterableElementBase } from '../base';
import { calcMinUnitsRequired, rangeCheck } from '../../utils';
@@ -22,19 +22,16 @@ export class Deque extends IterableElementBase {
protected _bucketLast = 0;
protected _lastInBucket = 0;
protected _bucketCount = 0;
- protected readonly _bucketSize: number;
+ protected readonly _bucketSize: number = 1 << 12;
- /**
- * The constructor initializes a data structure with a specified bucket size and populates it with
- * elements from an iterable.
- * @param elements - The `elements` parameter is an iterable object (such as an array or a Set) that
- * contains the initial elements to be stored in the data structure. It can also be an object with a
- * `length` property or a `size` property, which represents the number of elements in the iterable.
- * @param bucketSize - The `bucketSize` parameter is the maximum number of elements that can be
- * stored in each bucket. It determines the size of each bucket in the data structure.
- */
- constructor(elements: IterableWithSizeOrLength = [], bucketSize = 1 << 12) {
+ constructor(elements: IterableWithSizeOrLength = [], options?: DequeOptions) {
super();
+
+ if (options) {
+ const { bucketSize } = options;
+ if (typeof bucketSize === 'number') this._bucketSize = bucketSize;
+ }
+
let _size: number;
if ('length' in elements) {
if (elements.length instanceof Function) _size = elements.length();
@@ -44,7 +41,6 @@ export class Deque extends IterableElementBase {
else _size = elements.size;
}
- this._bucketSize = bucketSize;
this._bucketCount = calcMinUnitsRequired(_size, this._bucketSize) || 1;
for (let i = 0; i < this._bucketCount; ++i) {
this._buckets.push(new Array(this._bucketSize));
@@ -637,7 +633,7 @@ export class Deque extends IterableElementBase {
* satisfy the given predicate function.
*/
filter(predicate: ElementCallback, thisArg?: any): Deque {
- const newDeque = new Deque([], this._bucketSize);
+ const newDeque = new Deque([], { bucketSize: this._bucketSize });
let index = 0;
for (const el of this) {
if (predicate.call(thisArg, el, index, this)) {
@@ -666,7 +662,7 @@ export class Deque extends IterableElementBase {
* @returns a new Deque object with the mapped values.
*/
map(callback: ElementCallback, thisArg?: any): Deque {
- const newDeque = new Deque([], this._bucketSize);
+ const newDeque = new Deque([], { bucketSize: this._bucketSize });
let index = 0;
for (const el of this) {
newDeque.push(callback.call(thisArg, el, index, this));
diff --git a/src/data-structures/queue/queue.ts b/src/data-structures/queue/queue.ts
index f23a669..1c2d4e7 100644
--- a/src/data-structures/queue/queue.ts
+++ b/src/data-structures/queue/queue.ts
@@ -13,29 +13,30 @@ import { SinglyLinkedList } from '../linked-list';
* 3. Uses: Queues are commonly used to manage a series of tasks or elements that need to be processed in order. For example, managing task queues in a multi-threaded environment, or in algorithms for data structures like trees and graphs for breadth-first search.
* 4. Task Scheduling: Managing the order of task execution in operating systems or applications.
* 5. Data Buffering: Acting as a buffer for data packets in network communication.
- * 6. Breadth-First Search (BFS): In traversal algorithms for graphs and trees, queues store nodes that are to be visited.
+ * 6. Breadth-First Search (BFS): In traversal algorithms for graphs and trees, queues store elements that are to be visited.
* 7. Real-time Queuing: Like queuing systems in banks or supermarkets.
*/
export class Queue extends IterableElementBase {
/**
* The constructor initializes an instance of a class with an optional array of elements and sets the offset to 0.
* @param {E[]} [elements] - The `elements` parameter is an optional array of elements of type `E`. If provided, it
- * will be used to initialize the `_nodes` property of the class. If not provided, the `_nodes` property will be
+ * will be used to initialize the `_elements` property of the class. If not provided, the `_elements` property will be
* initialized as an empty array.
*/
- constructor(elements?: E[]) {
+ constructor(elements: Iterable = []) {
super();
- this._nodes = elements || [];
- this._offset = 0;
+ if (elements) {
+ for (const el of elements) this.push(el);
+ }
}
- protected _nodes: E[];
+ protected _elements: E[] = [];
- get nodes(): E[] {
- return this._nodes;
+ get elements(): E[] {
+ return this._elements;
}
- protected _offset: number;
+ protected _offset: number = 0;
get offset(): number {
return this._offset;
@@ -46,19 +47,19 @@ export class Queue extends IterableElementBase {
* @returns {number} The size of the array, which is the difference between the length of the array and the offset.
*/
get size(): number {
- return this.nodes.length - this.offset;
+ return this.elements.length - this.offset;
}
/**
* Time Complexity: O(1) - constant time as it retrieves the value at the current offset.
* Space Complexity: O(1) - no additional space is used.
*
- * The `first` function returns the first element of the array `_nodes` if it exists, otherwise it returns `undefined`.
- * @returns The `get first()` method returns the first element of the data structure, represented by the `_nodes` array at
+ * The `first` function returns the first element of the array `_elements` if it exists, otherwise it returns `undefined`.
+ * @returns The `get first()` method returns the first element of the data structure, represented by the `_elements` array at
* the `_offset` index. If the data structure is empty (size is 0), it returns `undefined`.
*/
get first(): E | undefined {
- return this.size > 0 ? this.nodes[this.offset] : undefined;
+ return this.size > 0 ? this.elements[this.offset] : undefined;
}
/**
@@ -71,11 +72,11 @@ export class Queue extends IterableElementBase {
* Space Complexity: O(1) - no additional space is used.
*
* The `last` function returns the last element in an array-like data structure, or undefined if the structure is empty.
- * @returns The method `get last()` returns the last element of the `_nodes` array if the array is not empty. If the
+ * @returns The method `get last()` returns the last element of the `_elements` array if the array is not empty. If the
* array is empty, it returns `undefined`.
*/
get last(): E | undefined {
- return this.size > 0 ? this.nodes[this.nodes.length - 1] : undefined;
+ return this.size > 0 ? this.elements[this.elements.length - 1] : undefined;
}
/**
@@ -109,7 +110,7 @@ export class Queue extends IterableElementBase {
* @returns The `add` method is returning a `Queue` object.
*/
push(element: E): boolean {
- this.nodes.push(element);
+ this.elements.push(element);
return true;
}
@@ -132,11 +133,11 @@ export class Queue extends IterableElementBase {
const first = this.first;
this._offset += 1;
- if (this.offset * 2 < this.nodes.length) return first;
+ if (this.offset * 2 < this.elements.length) return first;
// only delete dequeued elements when reaching half size
// to decrease latency of shifting elements.
- this._nodes = this.nodes.slice(this.offset);
+ this._elements = this.elements.slice(this.offset);
this._offset = 0;
return first;
}
@@ -150,8 +151,8 @@ export class Queue extends IterableElementBase {
* Time Complexity: O(1) - constant time as it retrieves the value at the current offset.
* Space Complexity: O(1) - no additional space is used.
*
- * The `peek` function returns the first element of the array `_nodes` if it exists, otherwise it returns `undefined`.
- * @returns The `peek()` method returns the first element of the data structure, represented by the `_nodes` array at
+ * The `peek` function returns the first element of the array `_elements` if it exists, otherwise it returns `undefined`.
+ * @returns The `peek()` method returns the first element of the data structure, represented by the `_elements` array at
* the `_offset` index. If the data structure is empty (size is 0), it returns `undefined`.
*/
peek(): E | undefined {
@@ -168,7 +169,7 @@ export class Queue extends IterableElementBase {
* Space Complexity: O(1) - no additional space is used.
*
* The `peekLast` function returns the last element in an array-like data structure, or undefined if the structure is empty.
- * @returns The method `peekLast()` returns the last element of the `_nodes` array if the array is not empty. If the
+ * @returns The method `peekLast()` returns the last element of the `_elements` array if the array is not empty. If the
* array is empty, it returns `undefined`.
*/
peekLast(): E | undefined {
@@ -219,7 +220,7 @@ export class Queue extends IterableElementBase {
* @param index
*/
getAt(index: number): E | undefined {
- return this.nodes[index];
+ return this.elements[index];
}
/**
@@ -247,18 +248,18 @@ export class Queue extends IterableElementBase {
* Time Complexity: O(1) - constant time as it returns a shallow copy of the internal array.
* Space Complexity: O(n) - where n is the number of elements in the queue.
*
- * The toArray() function returns an array of elements from the current offset to the end of the _nodes array.
+ * The toArray() function returns an array of elements from the current offset to the end of the _elements array.
* @returns An array of type E is being returned.
*/
toArray(): E[] {
- return this.nodes.slice(this.offset);
+ return this.elements.slice(this.offset);
}
/**
- * The clear function resets the nodes array and offset to their initial values.
+ * The clear function resets the elements array and offset to their initial values.
*/
clear(): void {
- this._nodes = [];
+ this._elements = [];
this._offset = 0;
}
@@ -275,7 +276,7 @@ export class Queue extends IterableElementBase {
* @returns The `clone()` method is returning a new instance of the `Queue` class.
*/
clone(): Queue {
- return new Queue(this.nodes.slice(this.offset));
+ return new Queue(this.elements.slice(this.offset));
}
/**
@@ -345,7 +346,7 @@ export class Queue extends IterableElementBase {
*/
protected* _getIterator(): IterableIterator {
- for (const item of this.nodes) {
+ 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 d3adcbd..63cabfa 100644
--- a/src/data-structures/stack/stack.ts
+++ b/src/data-structures/stack/stack.ts
@@ -23,17 +23,14 @@ export class Stack extends IterableElementBase {
* of elements of type `E`. It is used to initialize the `_elements` property of the class. If the `elements` parameter
* is provided and is an array, it is assigned to the `_elements
*/
- constructor(elements?: Iterable) {
+ constructor(elements: Iterable = []) {
super();
- this._elements = [];
if (elements) {
- for (const el of elements) {
- this.push(el);
- }
+ for (const el of elements) this.push(el);
}
}
- protected _elements: E[];
+ protected _elements: E[] = [];
get elements(): E[] {
return this._elements;
diff --git a/src/data-structures/trie/trie.ts b/src/data-structures/trie/trie.ts
index d87d6e8..d4a1eb9 100644
--- a/src/data-structures/trie/trie.ts
+++ b/src/data-structures/trie/trie.ts
@@ -5,7 +5,7 @@
* @copyright Copyright (c) 2022 Tyler Zeng
* @license MIT License
*/
-import type { ElementCallback } from '../../types';
+import type { ElementCallback, TrieOptions } from '../../types';
import { IterableElementBase } from '../base';
/**
@@ -38,31 +38,30 @@ export class TrieNode {
* 11. Text Word Frequency Count: Counting and storing the frequency of words in a large amount of text data."
*/
export class Trie extends IterableElementBase {
- constructor(words?: string[], caseSensitive = true) {
+ constructor(words: Iterable = [], options?: TrieOptions) {
super();
- this._root = new TrieNode('');
- this._caseSensitive = caseSensitive;
- this._size = 0;
+ if (options) {
+ const { caseSensitive } = options;
+ if (caseSensitive !== undefined) this._caseSensitive = caseSensitive;
+ }
if (words) {
- for (const word of words) {
- this.add(word);
- }
+ for (const word of words) this.add(word);
}
}
- protected _size: number;
+ protected _size: number = 0;
get size(): number {
return this._size;
}
- protected _caseSensitive: boolean;
+ protected _caseSensitive: boolean = true;
get caseSensitive(): boolean {
return this._caseSensitive;
}
- protected _root: TrieNode;
+ protected _root: TrieNode = new TrieNode('');
get root() {
return this._root;
diff --git a/src/types/data-structures/binary-tree/binary-tree.ts b/src/types/data-structures/binary-tree/binary-tree.ts
index afbf50b..0d86710 100644
--- a/src/types/data-structures/binary-tree/binary-tree.ts
+++ b/src/types/data-structures/binary-tree/binary-tree.ts
@@ -6,6 +6,6 @@ export type BinaryTreeNodeNested = BinaryTreeNode> = BinaryTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
export type BinaryTreeOptions = {
- iterationType: IterationType,
- extractor: (key: K) => number
+ iterationType?: IterationType,
+ extractor?: (key: K) => number
}
diff --git a/src/types/data-structures/binary-tree/bst.ts b/src/types/data-structures/binary-tree/bst.ts
index 73f50ba..131f9a2 100644
--- a/src/types/data-structures/binary-tree/bst.ts
+++ b/src/types/data-structures/binary-tree/bst.ts
@@ -7,5 +7,5 @@ export type BSTNodeNested = BSTNode> = BST>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
export type BSTOptions = BinaryTreeOptions & {
- variant: BSTVariant
+ variant?: BSTVariant
}
diff --git a/src/types/data-structures/binary-tree/tree-multimap.ts b/src/types/data-structures/binary-tree/tree-multimap.ts
index ffc7172..c1bb3c0 100644
--- a/src/types/data-structures/binary-tree/tree-multimap.ts
+++ b/src/types/data-structures/binary-tree/tree-multimap.ts
@@ -5,4 +5,4 @@ export type TreeMultimapNodeNested = TreeMultimapNode> = TreeMultimap>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
-export type TreeMultimapOptions = Omit, 'isMergeDuplicatedNodeByKey'> & {}
+export type TreeMultimapOptions = AVLTreeOptions & {}
diff --git a/src/types/data-structures/hash/hash-map.ts b/src/types/data-structures/hash/hash-map.ts
index f5d749b..d672839 100644
--- a/src/types/data-structures/hash/hash-map.ts
+++ b/src/types/data-structures/hash/hash-map.ts
@@ -5,9 +5,13 @@ export type HashMapLinkedNode = {
prev: HashMapLinkedNode;
};
+export type LinkedHashMapOptions = {
+ hashFn?: (key: K) => string;
+ objHashFn?: (key: K) => object;
+};
+
export type HashMapOptions = {
- hashFn: (key: K) => string;
- objHashFn: (key: K) => object;
+ hashFn?: (key: K) => string;
};
export type HashMapStoreItem = { key: K; value: V };
diff --git a/src/types/data-structures/hash/hash-table.ts b/src/types/data-structures/hash/hash-table.ts
deleted file mode 100644
index cb0ff5c..0000000
--- a/src/types/data-structures/hash/hash-table.ts
+++ /dev/null
@@ -1 +0,0 @@
-export {};
diff --git a/src/types/data-structures/hash/index.ts b/src/types/data-structures/hash/index.ts
index bda3af6..e07d6cd 100644
--- a/src/types/data-structures/hash/index.ts
+++ b/src/types/data-structures/hash/index.ts
@@ -1,4 +1,3 @@
export * from './hash-map';
-export * from './hash-table';
export type HashFunction = (key: K) => number;
diff --git a/src/types/data-structures/heap/heap.ts b/src/types/data-structures/heap/heap.ts
index 86602f4..4631285 100644
--- a/src/types/data-structures/heap/heap.ts
+++ b/src/types/data-structures/heap/heap.ts
@@ -1,3 +1,3 @@
import { Comparator } from '../../common';
-export type HeapOptions = { comparator: Comparator };
+export type HeapOptions = { comparator?: Comparator };
diff --git a/src/types/data-structures/linked-list/index.ts b/src/types/data-structures/linked-list/index.ts
index 0bdd0b6..e489ecc 100644
--- a/src/types/data-structures/linked-list/index.ts
+++ b/src/types/data-structures/linked-list/index.ts
@@ -1,2 +1,3 @@
export * from './singly-linked-list';
export * from './doubly-linked-list';
+export * from './skip-linked-list';
diff --git a/src/types/data-structures/linked-list/skip-linked-list.ts b/src/types/data-structures/linked-list/skip-linked-list.ts
index cb0ff5c..f581911 100644
--- a/src/types/data-structures/linked-list/skip-linked-list.ts
+++ b/src/types/data-structures/linked-list/skip-linked-list.ts
@@ -1 +1 @@
-export {};
+export type SkipLinkedListOptions = { maxLevel?: number; probability?: number };
diff --git a/src/types/data-structures/matrix/index.ts b/src/types/data-structures/matrix/index.ts
index 8716d60..64c4fa3 100644
--- a/src/types/data-structures/matrix/index.ts
+++ b/src/types/data-structures/matrix/index.ts
@@ -1 +1,2 @@
export * from './navigator';
+export * from './matrix';
diff --git a/src/types/data-structures/matrix/matrix.ts b/src/types/data-structures/matrix/matrix.ts
index cb0ff5c..4f9cc77 100644
--- a/src/types/data-structures/matrix/matrix.ts
+++ b/src/types/data-structures/matrix/matrix.ts
@@ -1 +1,7 @@
-export {};
+export type MatrixOptions = {
+ rows?: number;
+ cols?: number;
+ addFn?: (a: number, b: number) => any;
+ subtractFn?: (a: number, b: number) => any;
+ multiplyFn?: (a: number, b: number) => any;
+};
diff --git a/src/types/data-structures/matrix/matrix2d.ts b/src/types/data-structures/matrix/matrix2d.ts
deleted file mode 100644
index cb0ff5c..0000000
--- a/src/types/data-structures/matrix/matrix2d.ts
+++ /dev/null
@@ -1 +0,0 @@
-export {};
diff --git a/src/types/data-structures/matrix/vector2d.ts b/src/types/data-structures/matrix/vector2d.ts
deleted file mode 100644
index cb0ff5c..0000000
--- a/src/types/data-structures/matrix/vector2d.ts
+++ /dev/null
@@ -1 +0,0 @@
-export {};
diff --git a/src/types/data-structures/queue/deque.ts b/src/types/data-structures/queue/deque.ts
index cb0ff5c..8134e3e 100644
--- a/src/types/data-structures/queue/deque.ts
+++ b/src/types/data-structures/queue/deque.ts
@@ -1 +1 @@
-export {};
+export type DequeOptions = { bucketSize?: number };
diff --git a/src/types/data-structures/trie/trie.ts b/src/types/data-structures/trie/trie.ts
index cb0ff5c..bbdd970 100644
--- a/src/types/data-structures/trie/trie.ts
+++ b/src/types/data-structures/trie/trie.ts
@@ -1 +1 @@
-export {};
+export type TrieOptions = { caseSensitive?: boolean };
diff --git a/test/unit/data-structures/hash/hash-table.test.ts b/test/unit/data-structures/hash/hash-table.test.ts
deleted file mode 100644
index ae88b48..0000000
--- a/test/unit/data-structures/hash/hash-table.test.ts
+++ /dev/null
@@ -1,238 +0,0 @@
-import { HashTable, HashTableNode } from '../../../../src';
-
-describe('HashNode', () => {
- it('should create a HashNode with key and value', () => {
- const key = 'testKey';
- const value = 'testValue';
- const hashNode = new HashTableNode(key, value);
-
- expect(hashNode.key).toBe(key);
- expect(hashNode.value).toBe(value);
- expect(hashNode.next).toBe(undefined);
- });
-});
-
-describe('HashTable', () => {
- it('should initialize with default capacity', () => {
- const hashTable = new HashTable();
- expect(hashTable.capacity).toBe(16);
- expect(hashTable.buckets).toEqual(new Array(16).fill(undefined));
- expect(hashTable.hashFn('a')).toBe(6);
- expect(hashTable.capacity).toBe(16);
- expect(hashTable.size).toBe(0);
- expect(hashTable.buckets.length).toBe(16);
- });
-
- it('should initialize with custom capacity', () => {
- const customCapacity = 500;
- const hashTable = new HashTable(customCapacity);
-
- expect(hashTable.capacity).toBe(customCapacity);
- expect(hashTable.size).toBe(0);
- expect(hashTable.buckets.length).toBe(customCapacity);
- });
-
- it('should put and get values correctly', () => {
- const hashTable = new HashTable();
- const key = 'testKey';
- const value = 'testValue';
-
- hashTable.set(key, value);
- const retrievedValue = hashTable.get(key);
-
- expect(retrievedValue).toBe(value);
- });
-
- it('should handle collisions by chaining', () => {
- const hashTable = new HashTable();
- const key1 = 'testKey1';
- const value1 = 'testValue1';
- const key2 = 'testKey2';
- const value2 = 'testValue2';
-
- hashTable.set(key1, value1);
- hashTable.set(key2, value2);
-
- const retrievedValue1 = hashTable.get(key1);
- const retrievedValue2 = hashTable.get(key2);
-
- expect(retrievedValue1).toBe(value1);
- expect(retrievedValue2).toBe(value2);
- });
-
- it('should update value for an existing key', () => {
- const hashTable = new HashTable();
- const key = 'testKey';
- const initialValue = 'testValue1';
- const updatedValue = 'testValue2';
-
- hashTable.set(key, initialValue);
- hashTable.set(key, updatedValue);
-
- const retrievedValue = hashTable.get(key);
-
- expect(retrievedValue).toBe(updatedValue);
- });
-
- it('should return undefined for non-existent key', () => {
- const hashTable = new HashTable();
- const key = 'nonExistentKey';
-
- const retrievedValue = hashTable.get(key);
-
- expect(retrievedValue).toBeUndefined();
- });
-
- it('should delete key-value pair correctly', () => {
- const hashTable = new HashTable();
- const key = 'testKey';
- const value = 'testValue';
-
- hashTable.set(key, value);
- hashTable.delete(key);
-
- const retrievedValue = hashTable.get(key);
-
- expect(retrievedValue).toBeUndefined();
- expect(hashTable.size).toBe(0);
- });
-});
-
-describe('HashTable', () => {
- let hashTable: HashTable;
-
- beforeEach(() => {
- hashTable = new HashTable();
- });
-
- it('should insert and retrieve values correctly', () => {
- hashTable.set('one', 1);
- hashTable.set('two', 2);
-
- expect(hashTable.get('one')).toBe(1);
- expect(hashTable.get('two')).toBe(2);
- });
-
- it('should update values correctly', () => {
- hashTable.set('one', 1);
- expect(hashTable.get('one')).toBe(1);
-
- hashTable.set('one', 100); // Update the value
- expect(hashTable.get('one')).toBe(100);
- });
-
- it('should handle collisions correctly', () => {
- hashTable = new HashTable(1); // Set a small capacity to force collisions
- hashTable.set('one', 1);
- hashTable.set('two', 2);
-
- expect(hashTable.get('one')).toBe(1);
- expect(hashTable.get('two')).toBe(2);
- });
-
- it('should delete values correctly', () => {
- hashTable.set('one', 1);
- hashTable.set('two', 2);
- hashTable.delete('one');
-
- expect(hashTable.get('one')).toBeUndefined();
- expect(hashTable.get('two')).toBe(2);
- });
-
- it('should handle non-existent keys correctly', () => {
- expect(hashTable.get('non-existent')).toBeUndefined();
- hashTable.delete('non-existent'); // Removing a non-existent key should not cause errors
- });
-
- it('should handle custom hash function correctly', () => {
- // const customHashFn = () => {
- // // Custom hash function that returns a fixed value for all keys
- // return 42;
- // };
-
- hashTable = new HashTable(16);
- hashTable.set('one', 1);
- expect(hashTable.get('one')).toBe(1);
- expect(hashTable.get('two')).toBeUndefined();
- });
-
- it('should expand when load factor exceeds threshold', () => {
- hashTable = new HashTable(2); // Set a small capacity to trigger expansion
- hashTable.set('one', 1);
- hashTable.set('two', 2);
- hashTable.set('three', 3); // This should trigger an expansion
-
- expect(hashTable.capacity).toBe(16);
- expect(hashTable.get('one')).toBe(1);
- expect(hashTable.get('two')).toBe(2);
- expect(hashTable.get('three')).toBe(3);
- });
-});
-
-describe('HashTable performance', function () {
- it('Items set performance', function () {
- const mag = 100000;
- const ht = new HashTable();
- // const s = performance.now();
- for (let i = 0; i < mag; i++) {
- ht.set(i, i);
- }
- // const s1 = performance.now();
- const map = new Map();
- for (let i = 0; i < mag; i++) {
- map.set(i, i);
- }
- });
-});
-
-describe('HashTable methods', () => {
- let hashTable: HashTable;
-
- beforeEach(() => {
- hashTable = new HashTable();
- for (let i = 0; i < 10; i++) {
- hashTable.set(`key${i}`, `value${i}`);
- }
- });
-
- test('should retrieve correct values with get method', () => {
- for (let i = 0; i < 10; i++) {
- expect(hashTable.get(`key${i}`)).toBe(`value${i}`);
- }
- });
-
- // test('forEach should apply a function to each key-value pair', () => {
- // const mockCallback = jest.fn();
- // hashTable.forEach(mockCallback);
- //
- // expect(mockCallback.mock.calls.length).toBe(10);
- // for (let i = 0; i < 10; i++) {
- // // Check whether each key-value pair has been called before, regardless of the order
- // const call = mockCallback.mock.calls.find(call => call[1] === `value${i}`);
- // expect(call).toBeTruthy();
- // expect(call[0]).toBe(`key${i}`);
- // }
- // });
-
- test('filter should return a new HashTable with elements that satisfy the condition', () => {
- const filtered = hashTable.filter(([key]) => key.endsWith('1') || key.endsWith('3'));
-
- expect(filtered.size).toBe(2);
- expect(filtered.get('key1')).toBe('value1');
- expect(filtered.get('key3')).toBe('value3');
- });
-
- test('map should return a new HashTable with mapped values', () => {
- const mapped = hashTable.map(([, value]) => value.toUpperCase());
-
- for (let i = 0; i < 10; i++) {
- expect(mapped.get(`key${i}`)).toBe(`value${i}`.toUpperCase());
- }
- });
-
- test('reduce should accumulate values based on the reducer function', () => {
- const result = hashTable.reduce((acc, [, value]) => `${acc}-${value}`, '');
-
- expect(result).toBe('-value5-value7-value3-value4-value6-value0-value2-value8-value1-value9');
- });
-});
diff --git a/test/unit/data-structures/linked-list/skip-list.test.ts b/test/unit/data-structures/linked-list/skip-list.test.ts
index 1afc111..435758e 100644
--- a/test/unit/data-structures/linked-list/skip-list.test.ts
+++ b/test/unit/data-structures/linked-list/skip-list.test.ts
@@ -32,7 +32,7 @@ describe('SkipList', () => {
skipList.delete(2);
- expect(skipList.get(2)).toBeUndefined(); // 修改这里的断言
+ expect(skipList.get(2)).toBeUndefined();
});
it('should handle random data correctly', () => {
diff --git a/test/unit/data-structures/queue/deque.test.ts b/test/unit/data-structures/queue/deque.test.ts
index 2d4946a..b5830bb 100644
--- a/test/unit/data-structures/queue/deque.test.ts
+++ b/test/unit/data-structures/queue/deque.test.ts
@@ -231,10 +231,10 @@ describe('Deque - Additional Operations', () => {
});
describe('Deque - push Method', () => {
let deque: Deque;
- const bucketSize = 10; // 假设的 bucket 大小
+ const bucketSize = 10;
beforeEach(() => {
- deque = new Deque([], bucketSize);
+ deque = new Deque([], { bucketSize });
});
test('push should add an element when deque is empty', () => {
@@ -276,7 +276,7 @@ describe('Deque - pop Method', () => {
const bucketSize = 10;
beforeEach(() => {
- deque = new Deque([], bucketSize);
+ deque = new Deque([], { bucketSize });
});
test('pop should remove and return the last element', () => {
@@ -307,7 +307,7 @@ describe('Deque - unshift Method', () => {
const bucketSize = 10;
beforeEach(() => {
- deque = new Deque