From 4fa08162234a6e776e85b509914706bb3ae1cc0b Mon Sep 17 00:00:00 2001 From: Revone Date: Fri, 20 Oct 2023 11:43:26 +0800 Subject: [PATCH 01/46] [core] Shared Comparator and DFSOrderPattern among multiple data structures. ESLint config improved --- .eslintrc.js | 10 ++++++---- package.json | 1 + src/data-structures/binary-tree/binary-tree.ts | 4 ++-- src/data-structures/heap/heap.ts | 11 ++++++----- src/data-structures/heap/max-heap.ts | 4 ++-- src/data-structures/heap/min-heap.ts | 4 ++-- .../priority-queue/max-priority-queue.ts | 4 ++-- .../priority-queue/min-priority-queue.ts | 4 ++-- src/data-structures/priority-queue/priority-queue.ts | 4 ++-- src/types/data-structures/binary-tree.ts | 2 -- src/types/data-structures/heap.ts | 4 +--- src/types/helpers.ts | 5 ++++- test/unit/data-structures/heap/max-heap.test.ts | 4 ++-- test/unit/data-structures/heap/min-heap.test.ts | 4 ++-- 14 files changed, 34 insertions(+), 31 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 8a44df5..3b46646 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,9 +1,14 @@ module.exports = { + "parser": "@typescript-eslint/parser", + "plugins": [ + "import", + "@typescript-eslint" + ], "extends": [ "plugin:@typescript-eslint/recommended", "prettier" ], - ignorePatterns: ["lib/", "dist/", "umd/", "coverage/", "docs/"], + "ignorePatterns": ["lib/", "dist/", "umd/", "coverage/", "docs/"], "rules": { "import/no-anonymous-default-export": "off", "@typescript-eslint/no-unused-vars": "error", @@ -39,9 +44,6 @@ module.exports = { } ] }, - "plugins": [ - "import" - ], "settings": { "import/parsers": { "@typescript-eslint/parser": [ diff --git a/package.json b/package.json index 292e221..f40e5f1 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "build:commonjs": "rm -rf dist && tsc --project tsconfig.prod.json", "build:umd": "webpack", "build:docs": "typedoc --out docs ./src", + "check": "tsc --noEmit", "lint:src": "eslint --fix 'src/**/*.{js,ts}'", "lint:test": "eslint --fix 'test/**/*.{js,ts}'", "lint": "npm run lint:src && npm run lint:test", diff --git a/src/data-structures/binary-tree/binary-tree.ts b/src/data-structures/binary-tree/binary-tree.ts index 4f1e942..fef5769 100644 --- a/src/data-structures/binary-tree/binary-tree.ts +++ b/src/data-structures/binary-tree/binary-tree.ts @@ -13,7 +13,6 @@ import type { BinaryTreeNodeProperty, BinaryTreeOptions } from '../../types'; -import {IBinaryTree} from '../../interfaces'; import { BinaryTreeDeletedResult, BinaryTreeNodePropertyName, @@ -22,6 +21,7 @@ import { LoopType, NodeOrPropertyName } from '../../types'; +import {IBinaryTree} from '../../interfaces'; import {trampoline} from '../../utils'; export class BinaryTreeNode = BinaryTreeNodeNested> { @@ -574,7 +574,7 @@ export class BinaryTree = BinaryTreeNode> /** * The function `getLeftMost` returns the leftmost node in a binary tree, starting from a specified node or the root if * no node is specified. - * generic type representing a node in a binary tree), `BinaryTreeNodeKey` (a type representing the ID of a binary tree + * generic type representing a node in a binary tree, `BinaryTreeNodeKey` (a type representing the ID of a binary tree * node), or `null`. * @returns The function `getLeftMost` returns the leftmost node in a binary tree. If the `beginRoot` parameter is * provided, it starts the traversal from that node. If `beginRoot` is not provided or is `null`, it starts the traversal diff --git a/src/data-structures/heap/heap.ts b/src/data-structures/heap/heap.ts index c6e0afd..4205333 100644 --- a/src/data-structures/heap/heap.ts +++ b/src/data-structures/heap/heap.ts @@ -5,13 +5,14 @@ * @license MIT License */ -import type {HeapComparator, HeapDFSOrderPattern} from '../../types'; +import type {Comparator} from '../../types'; +import {DFSOrderPattern} from '../../types'; export class Heap { protected nodes: E[] = []; - private readonly comparator: HeapComparator; + private readonly comparator: Comparator; - constructor(comparator: HeapComparator) { + constructor(comparator: Comparator) { this.comparator = comparator; } @@ -158,7 +159,7 @@ export class Heap { * @param order - Traversal order parameter: 'in' (in-order), 'pre' (pre-order) or 'post' (post-order). * @returns An array containing elements traversed in the specified order. */ - dfs(order: HeapDFSOrderPattern): E[] { + dfs(order: DFSOrderPattern): E[] { const result: E[] = []; // Auxiliary recursive function, traverses the binary heap according to the traversal order @@ -227,7 +228,7 @@ export class Heap { * @param comparator - Comparison function. * @returns A new Heap instance. */ - static heapify(nodes: E[], comparator: HeapComparator): Heap { + static heapify(nodes: E[], comparator: Comparator): Heap { const binaryHeap = new Heap(comparator); binaryHeap.nodes = [...nodes]; binaryHeap.fix(); // Fix heap properties diff --git a/src/data-structures/heap/max-heap.ts b/src/data-structures/heap/max-heap.ts index 410b166..55ace08 100644 --- a/src/data-structures/heap/max-heap.ts +++ b/src/data-structures/heap/max-heap.ts @@ -7,11 +7,11 @@ */ import {Heap} from './heap'; -import type {HeapComparator} from '../../types'; +import type {Comparator} from '../../types'; export class MaxHeap extends Heap { constructor( - comparator: HeapComparator = (a: E, b: E) => { + comparator: 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 { diff --git a/src/data-structures/heap/min-heap.ts b/src/data-structures/heap/min-heap.ts index 2998199..fcc809b 100644 --- a/src/data-structures/heap/min-heap.ts +++ b/src/data-structures/heap/min-heap.ts @@ -7,11 +7,11 @@ */ import {Heap} from './heap'; -import type {HeapComparator} from '../../types'; +import type {Comparator} from '../../types'; export class MinHeap extends Heap { constructor( - comparator: HeapComparator = (a: E, b: E) => { + comparator: 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 { diff --git a/src/data-structures/priority-queue/max-priority-queue.ts b/src/data-structures/priority-queue/max-priority-queue.ts index 2418a76..49f016e 100644 --- a/src/data-structures/priority-queue/max-priority-queue.ts +++ b/src/data-structures/priority-queue/max-priority-queue.ts @@ -6,11 +6,11 @@ * @license MIT License */ import {PriorityQueue} from './priority-queue'; -import type {HeapComparator} from '../../types'; +import type {Comparator} from '../../types'; export class MaxPriorityQueue extends PriorityQueue { constructor( - compare: HeapComparator = (a: E, b: E) => { + compare: 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 { diff --git a/src/data-structures/priority-queue/min-priority-queue.ts b/src/data-structures/priority-queue/min-priority-queue.ts index 9635a1d..0e1b3e8 100644 --- a/src/data-structures/priority-queue/min-priority-queue.ts +++ b/src/data-structures/priority-queue/min-priority-queue.ts @@ -6,11 +6,11 @@ * @license MIT License */ import {PriorityQueue} from './priority-queue'; -import type {HeapComparator} from '../../types'; +import type {Comparator} from '../../types'; export class MinPriorityQueue extends PriorityQueue { constructor( - compare: HeapComparator = (a: E, b: E) => { + compare: 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 { diff --git a/src/data-structures/priority-queue/priority-queue.ts b/src/data-structures/priority-queue/priority-queue.ts index 9f4585c..2bc2769 100644 --- a/src/data-structures/priority-queue/priority-queue.ts +++ b/src/data-structures/priority-queue/priority-queue.ts @@ -7,10 +7,10 @@ */ import {Heap} from '../heap'; -import {HeapComparator} from '../../types'; +import {Comparator} from '../../types'; export class PriorityQueue extends Heap { - constructor(comparator: HeapComparator) { + constructor(comparator: Comparator) { super(comparator); } } diff --git a/src/types/data-structures/binary-tree.ts b/src/types/data-structures/binary-tree.ts index a5f8f04..a296960 100644 --- a/src/types/data-structures/binary-tree.ts +++ b/src/types/data-structures/binary-tree.ts @@ -26,8 +26,6 @@ export type BinaryTreeNodePropertyName = 'key' | 'val'; export type NodeOrPropertyName = 'node' | BinaryTreeNodePropertyName; -export type DFSOrderPattern = 'in' | 'pre' | 'post'; - export type BinaryTreeNodeKey = number; export type BinaryTreeNodeProperty> = diff --git a/src/types/data-structures/heap.ts b/src/types/data-structures/heap.ts index 55bf2b6..cb0ff5c 100644 --- a/src/types/data-structures/heap.ts +++ b/src/types/data-structures/heap.ts @@ -1,3 +1 @@ -export type HeapComparator = (a: T, b: T) => number; - -export type HeapDFSOrderPattern = 'pre' | 'in' | 'post'; +export {}; diff --git a/src/types/helpers.ts b/src/types/helpers.ts index cb0ff5c..f1991de 100644 --- a/src/types/helpers.ts +++ b/src/types/helpers.ts @@ -1 +1,4 @@ -export {}; +export type Comparator = (a: T, b: T) => number; + +// export enum DFSOrderPattern {'pre' = 'pre', 'in' = 'in', 'post' = 'post'} +export type DFSOrderPattern = 'pre' | 'in' | 'post'; diff --git a/test/unit/data-structures/heap/max-heap.test.ts b/test/unit/data-structures/heap/max-heap.test.ts index 744406f..b6dd044 100644 --- a/test/unit/data-structures/heap/max-heap.test.ts +++ b/test/unit/data-structures/heap/max-heap.test.ts @@ -1,7 +1,7 @@ -import {HeapComparator, MaxHeap} from '../../../../src'; +import {Comparator, MaxHeap} from '../../../../src'; describe('MaxHeap', () => { - const numberComparator: HeapComparator = (a, b) => b - a; + const numberComparator: Comparator = (a, b) => b - a; let maxHeap: MaxHeap; beforeEach(() => { diff --git a/test/unit/data-structures/heap/min-heap.test.ts b/test/unit/data-structures/heap/min-heap.test.ts index 2425162..be8d548 100644 --- a/test/unit/data-structures/heap/min-heap.test.ts +++ b/test/unit/data-structures/heap/min-heap.test.ts @@ -1,7 +1,7 @@ -import {HeapComparator, MinHeap} from '../../../../src'; +import {Comparator, MinHeap} from '../../../../src'; describe('MinHeap', () => { - const numberComparator: HeapComparator = (a, b) => a - b; + const numberComparator: Comparator = (a, b) => a - b; let minHeap: MinHeap; beforeEach(() => { From b7a7e3656304099c2f94d92d5c3ce6b461057a7c Mon Sep 17 00:00:00 2001 From: Revone Date: Fri, 20 Oct 2023 11:51:26 +0800 Subject: [PATCH 02/46] [project] added publish:all command --- CHANGELOG.md | 3 ++- package-lock.json | 50 +++++++++++++++++++++++------------------------ package.json | 13 ++++++------ 3 files changed, 34 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 82c2509..9c65758 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,10 +8,11 @@ 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.36.5](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) +## [v1.36.7](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) ### Changes +- [rbtree] implemented, but with bugs [`#13`](https://github.com/zrwusa/data-structure-typed/pull/13) - [trie] renamed ambiguous methods and add comments to all methods. [`#12`](https://github.com/zrwusa/data-structure-typed/pull/12) - [binarytree] modified the getDepth method to adhere to the proper def… [`#11`](https://github.com/zrwusa/data-structure-typed/pull/11) - Trie [`#10`](https://github.com/zrwusa/data-structure-typed/pull/10) diff --git a/package-lock.json b/package-lock.json index e055039..f46acf4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "data-structure-typed", - "version": "1.36.5", + "version": "1.36.7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "data-structure-typed", - "version": "1.36.5", + "version": "1.36.7", "license": "MIT", "devDependencies": { "@types/benchmark": "^2.1.3", @@ -15,17 +15,17 @@ "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", "auto-changelog": "^2.4.0", - "avl-tree-typed": "^1.36.4", + "avl-tree-typed": "^1.36.6", "benchmark": "^2.1.4", - "binary-tree-typed": "^1.36.4", - "bst-typed": "^1.36.4", + "binary-tree-typed": "^1.36.6", + "bst-typed": "^1.36.6", "dependency-cruiser": "^14.1.0", "eslint": "^8.50.0", "eslint-config-prettier": "^9.0.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.28.1", - "heap-typed": "^1.36.4", + "heap-typed": "^1.36.6", "istanbul-badges-readme": "^1.8.5", "jest": "^29.7.0", "prettier": "^3.0.3", @@ -2396,12 +2396,12 @@ } }, "node_modules/avl-tree-typed": { - "version": "1.36.4", - "resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.36.4.tgz", - "integrity": "sha512-iUTsr9dfxTb4aGBxv93Teh77cCEZBsJpk7MgzvTfUwIgdO3qskj3H8xmgAxzkeRSJqIvfEGC4jil6BNP6NfSBA==", + "version": "1.36.6", + "resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.36.6.tgz", + "integrity": "sha512-RoQASIXmEzMiVfLJDFDf+l34vBNpXOwn4t3XnZpkYKdSfaSgGAAIFH/2DTWiJuGEYIOz5vXRCPIVbk0b5VgPKQ==", "dev": true, "dependencies": { - "data-structure-typed": "^1.36.4" + "data-structure-typed": "^1.36.6" } }, "node_modules/babel-jest": { @@ -2586,12 +2586,12 @@ } }, "node_modules/binary-tree-typed": { - "version": "1.36.4", - "resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.36.4.tgz", - "integrity": "sha512-fDoK2eAm+rdur+oJMBJvyjjjiQ12GpnMmbT+Bgce3tz4wnrQca6sVSEXo1uuAKTIMgDEGeVtsJmD+J6xQLqH/A==", + "version": "1.36.6", + "resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.36.6.tgz", + "integrity": "sha512-E8HoO6dQ+xUOtFQm1eCW1AT2Jjug7z1/uOY6XeBXn7JEMaByPj4IYIx6v5IUKKdBRyj5TPBXr0CvxxL3nLHqTA==", "dev": true, "dependencies": { - "data-structure-typed": "^1.36.4" + "data-structure-typed": "^1.36.6" } }, "node_modules/brace-expansion": { @@ -2670,12 +2670,12 @@ } }, "node_modules/bst-typed": { - "version": "1.36.4", - "resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.36.4.tgz", - "integrity": "sha512-3soCZc7lJV5ZhC4owO8PLx6VlHrbaFuwOWcpuiQtIDpeVh/mgAHH3M/r/YCiAxLVWXjewerG7TB4T8CBhpo1AA==", + "version": "1.36.6", + "resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.36.6.tgz", + "integrity": "sha512-6AjjYvNZkXiDKW52l7wKe/E2EBmjXVLbuLI8d9bX6EdIxQ/OAwgkvMXTvIHBD0N5ws7zHca0KhwM7nLkl50FMg==", "dev": true, "dependencies": { - "data-structure-typed": "^1.36.4" + "data-structure-typed": "^1.36.6" } }, "node_modules/buffer-from": { @@ -3027,9 +3027,9 @@ } }, "node_modules/data-structure-typed": { - "version": "1.36.4", - "resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.36.4.tgz", - "integrity": "sha512-mX+KiaCJ9apd+X7M1dJhtxvUZlV15S36QGawoQhsmhwkHdDsBT06/sGca4vE7I20pZdoX5b34GW+3z4fUJI+/g==", + "version": "1.36.6", + "resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.36.6.tgz", + "integrity": "sha512-9puuDXinho/WreP7DDNjnreL0wpMQgO+kM74A+/uqkyOcJ0abtNdKNLiTOLMfuDJjk/GvhuxM5RexwaC/6JDpw==", "dev": true }, "node_modules/debug": { @@ -4362,12 +4362,12 @@ } }, "node_modules/heap-typed": { - "version": "1.36.4", - "resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.36.4.tgz", - "integrity": "sha512-A5gAttFYkaXXnAjNl7gIyulmoEYB4+usGhsb1QDD2LeHGfe1Pd0wNc/mX5iLFO2feIRcl3hbRw70SQoC+/V3Fg==", + "version": "1.36.6", + "resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.36.6.tgz", + "integrity": "sha512-ylui085xL2GIewkT2SZyjGLpvJakcYbm+/qB68QWKlwPqG2JJobHRFTFxZpccnyN9QakslsJ8o7SJhpWHu8/ZA==", "dev": true, "dependencies": { - "data-structure-typed": "^1.36.4" + "data-structure-typed": "^1.36.6" } }, "node_modules/html-escaper": { diff --git a/package.json b/package.json index f40e5f1..535d6ed 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "data-structure-typed", - "version": "1.36.6", + "version": "1.36.7", "description": "Data Structures of Javascript & TypeScript. Binary Tree, BST, Graph, Heap, Priority Queue, Linked List, Queue, Deque, Stack, AVL Tree, Tree Multiset, Trie, Directed Graph, Undirected Graph, Singly Linked List, Doubly Linked List, Max Heap, Max Priority Queue, Min Heap, Min Priority Queue.", "main": "dist/index.js", "module": "lib/index.js", @@ -33,7 +33,8 @@ "check:deps": "dependency-cruiser src", "changelog": "auto-changelog", "coverage:badge": "istanbul-badges-readme", - "ci": "env && npm run lint && npm run build && npm run update:individuals && npm run test && git fetch --tags && npm run changelog" + "ci": "env && npm run lint && npm run build && npm run update:individuals && npm run test && git fetch --tags && npm run changelog", + "publish:all": "npm run ci && npm publish && sh /scripts/publish_all_subs.sh && sh /scripts/publish_docs.sh" }, "repository": { "type": "git", @@ -55,17 +56,17 @@ "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", "auto-changelog": "^2.4.0", - "avl-tree-typed": "^1.36.4", + "avl-tree-typed": "^1.36.6", "benchmark": "^2.1.4", - "binary-tree-typed": "^1.36.4", - "bst-typed": "^1.36.4", + "binary-tree-typed": "^1.36.6", + "bst-typed": "^1.36.6", "dependency-cruiser": "^14.1.0", "eslint": "^8.50.0", "eslint-config-prettier": "^9.0.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.28.1", - "heap-typed": "^1.36.4", + "heap-typed": "^1.36.6", "istanbul-badges-readme": "^1.8.5", "jest": "^29.7.0", "prettier": "^3.0.3", From 961e4e5f8c199d57a42d037a9f67fc8a5a904205 Mon Sep 17 00:00:00 2001 From: Revone Date: Sat, 21 Oct 2023 01:59:10 +0800 Subject: [PATCH 03/46] [heap] fibonacci heap implemented. [test] big O estimate. [project] no-unused-vars config to warn --- .eslintrc.js | 2 +- src/data-structures/heap/heap.ts | 353 +++++++++++++++++++- test/types/index.ts | 1 + test/types/utils/big-o.ts | 1 + test/types/utils/index.ts | 1 + test/unit/data-structures/heap/heap.test.ts | 190 ++++++++++- test/utils/big-o.ts | 193 +++++++++++ test/utils/index.ts | 2 +- test/utils/magnitude.ts | 21 -- 9 files changed, 724 insertions(+), 40 deletions(-) create mode 100644 test/types/index.ts create mode 100644 test/types/utils/big-o.ts create mode 100644 test/types/utils/index.ts create mode 100644 test/utils/big-o.ts delete mode 100644 test/utils/magnitude.ts diff --git a/.eslintrc.js b/.eslintrc.js index 3b46646..05afdb4 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -11,7 +11,7 @@ module.exports = { "ignorePatterns": ["lib/", "dist/", "umd/", "coverage/", "docs/"], "rules": { "import/no-anonymous-default-export": "off", - "@typescript-eslint/no-unused-vars": "error", + "@typescript-eslint/no-unused-vars": "warn", "@typescript-eslint/ban-ts-comment": "off", "@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/no-var-requires": "off", diff --git a/src/data-structures/heap/heap.ts b/src/data-structures/heap/heap.ts index 4205333..8134703 100644 --- a/src/data-structures/heap/heap.ts +++ b/src/data-structures/heap/heap.ts @@ -10,7 +10,7 @@ import {DFSOrderPattern} from '../../types'; export class Heap { protected nodes: E[] = []; - private readonly comparator: Comparator; + protected readonly comparator: Comparator; constructor(comparator: Comparator) { this.comparator = comparator; @@ -18,21 +18,29 @@ export class Heap { /** * Insert an element into the heap and maintain the heap properties. - * @param value - The element to be inserted. + * @param element - The element to be inserted. */ - add(value: E): Heap { - this.nodes.push(value); + add(element: E): Heap { + return this.push(element); + } + + /** + * Insert an element into the heap and maintain the heap properties. + * @param element - The element to be inserted. + */ + push(element: E): Heap { + this.nodes.push(element); this.bubbleUp(this.nodes.length - 1); return this; } /** * Remove and return the top element (smallest or largest element) from the heap. - * @returns The top element or null if the heap is empty. + * @returns The top element or undefined if the heap is empty. */ - poll(): E | null { + poll(): E | undefined { if (this.nodes.length === 0) { - return null; + return undefined; } if (this.nodes.length === 1) { return this.nodes.pop() as E; @@ -44,6 +52,14 @@ export class Heap { return topValue; } + /** + * Remove and return the top element (smallest or largest element) from the heap. + * @returns The top element or undefined if the heap is empty. + */ + pop(): E | undefined { + return this.poll(); + } + /** * Float operation to maintain heap properties after adding an element. * @param index - The index of the newly added element. @@ -97,11 +113,11 @@ export class Heap { /** * Peek at the top element of the heap without removing it. - * @returns The top element or null if the heap is empty. + * @returns The top element or undefined if the heap is empty. */ - peek(): E | null { + peek(): E | undefined { if (this.nodes.length === 0) { - return null; + return undefined; } return this.nodes[0]; } @@ -115,10 +131,10 @@ export class Heap { /** * Get the last element in the heap, which is not necessarily a leaf node. - * @returns The last element or null if the heap is empty. + * @returns The last element or undefined if the heap is empty. */ - get leaf(): E | null { - return this.nodes[this.size - 1] ?? null; + get leaf(): E | undefined { + return this.nodes[this.size - 1] ?? undefined; } /** @@ -147,11 +163,11 @@ export class Heap { /** * Use a comparison function to check whether a binary heap contains a specific element. - * @param value - the element to check. + * @param element - the element to check. * @returns Returns true if the specified element is contained; otherwise, returns false. */ - has(value: E): boolean { - return this.nodes.includes(value); + has(element: E): boolean { + return this.nodes.includes(element); } /** @@ -235,3 +251,308 @@ export class Heap { return binaryHeap; } } + +export class FibonacciHeapNode { + element: E; + degree: number; + left?: FibonacciHeapNode; + right?: FibonacciHeapNode; + child?: FibonacciHeapNode; + parent?: FibonacciHeapNode; + marked: boolean; + constructor(element: E, degree = 0) { + this.element = element; + this.degree = degree; + this.marked = false; + } +} + +export class FibonacciHeap { + root?: FibonacciHeapNode; + protected min?: FibonacciHeapNode; + size: number = 0; + protected readonly comparator: Comparator; + + constructor(comparator?: Comparator) { + this.clear(); + this.comparator = comparator || this.defaultComparator; + + if (typeof this.comparator !== 'function') { + throw new Error('FibonacciHeap constructor: given comparator should be a function.'); + } + } + + /** + * Default comparator function used by the heap. + * @param {E} a + * @param {E} b + * @protected + */ + protected defaultComparator(a: E, b: E): number { + if (a < b) return -1; + if (a > b) return 1; + return 0; + } + + /** + * Get the size (number of elements) of the heap. + * @returns {number} The size of the heap. Returns 0 if the heap is empty. Returns -1 if the heap is invalid. + */ + clear(): void { + this.root = undefined; + this.min = undefined; + this.size = 0; + } + + /** + * Create a new node. + * @param element + * @protected + */ + protected createNode(element: E): FibonacciHeapNode { + return new FibonacciHeapNode(element); + } + + /** + * Merge the given node with the root list. + * @param node - The node to be merged. + */ + protected mergeWithRoot(node: FibonacciHeapNode): void { + if (!this.root) { + this.root = node; + } else { + node.right = this.root.right; + node.left = this.root; + this.root.right!.left = node; + this.root.right = node; + } + } + + /** + * O(1) time operation. + * Insert an element into the heap and maintain the heap properties. + * @param element + * @returns {FibonacciHeap} FibonacciHeap - The heap itself. + */ + add(element: E): FibonacciHeap { + return this.push(element); + } + + /** + * O(1) time operation. + * Insert an element into the heap and maintain the heap properties. + * @param element + * @returns {FibonacciHeap} FibonacciHeap - The heap itself. + */ + push(element: E): FibonacciHeap { + const node = this.createNode(element); + node.left = node; + node.right = node; + this.mergeWithRoot(node); + + if (!this.min || this.comparator(node.element, this.min.element) <= 0) { + this.min = node; + } + + this.size++; + return this; + } + + /** + * O(1) time operation. + * Peek at the top element of the heap without removing it. + * @returns The top element or undefined if the heap is empty. + * @protected + */ + peek(): E | undefined { + return this.min ? this.min.element : undefined; + } + + /** + * O(1) time operation. + * Get the size (number of elements) of the heap. + * @param {FibonacciHeapNode} head - The head of the linked list. + * @protected + * @returns FibonacciHeapNode[] - An array containing the nodes of the linked list. + */ + consumeLinkedList(head?: FibonacciHeapNode): FibonacciHeapNode[] { + const nodes: FibonacciHeapNode[] = []; + if (!head) return nodes; + + let node: FibonacciHeapNode | undefined = head; + let flag = false; + + while (true) { + if (node === head && flag) break; + else if (node === head) flag = true; + + if (node) { + nodes.push(node); + node = node.right; + } + } + + return nodes; + } + + /** + * O(log n) time operation. + * Remove and return the top element (smallest or largest element) from the heap. + * @param node - The node to be removed. + * @protected + */ + protected removeFromRoot(node: FibonacciHeapNode): void { + if (this.root === node) this.root = node.right; + if (node.left) node.left.right = node.right; + if (node.right) node.right.left = node.left; + } + + /** + * O(log n) time operation. + * Remove and return the top element (smallest or largest element) from the heap. + * @param parent + * @param node + */ + mergeWithChild(parent: FibonacciHeapNode, node: FibonacciHeapNode): void { + if (!parent.child) { + parent.child = node; + } else { + node.right = parent.child.right; + node.left = parent.child; + parent.child.right!.left = node; + parent.child.right = node; + } + } + + /** + * O(log n) time operation. + * Remove and return the top element (smallest or largest element) from the heap. + * @param y + * @param x + * @protected + */ + protected link(y: FibonacciHeapNode, x: FibonacciHeapNode): void { + this.removeFromRoot(y); + y.left = y; + y.right = y; + this.mergeWithChild(x, y); + x.degree++; + y.parent = x; + } + + /** + * O(log n) time operation. + * Remove and return the top element (smallest or largest element) from the heap. + * @protected + */ + protected consolidate(): void { + const A: (FibonacciHeapNode | undefined)[] = new Array(this.size); + const nodes = this.consumeLinkedList(this.root); + let x: FibonacciHeapNode | undefined, y: FibonacciHeapNode | undefined, d: number, t: FibonacciHeapNode | undefined; + + for (const node of nodes) { + x = node; + d = x.degree; + + while (A[d]) { + y = A[d] as FibonacciHeapNode; + + if (this.comparator(x.element, y.element) > 0) { + t = x; + x = y; + y = t; + } + + this.link(y, x); + A[d] = undefined; + d++; + } + + A[d] = x; + } + + for (let i = 0; i < this.size; i++) { + if (A[i] && this.comparator(A[i]!.element, this.min!.element) <= 0) { + this.min = A[i]!; + } + } + } + + /** + * O(log n) time operation. + * Remove and return the top element (smallest or largest element) from the heap. + * @returns The top element or undefined if the heap is empty. + */ + poll(): E | undefined { + return this.pop(); + } + + /** + * O(log n) time operation. + * Remove and return the top element (smallest or largest element) from the heap. + * @returns The top element or undefined if the heap is empty. + */ + pop(): E | undefined { + if (this.size === 0) return undefined; + + const z = this.min!; + if (z.child) { + const nodes = this.consumeLinkedList(z.child); + for (const node of nodes) { + this.mergeWithRoot(node); + node.parent = undefined; + } + } + + this.removeFromRoot(z); + + if (z === z.right) { + this.min = undefined; + this.root = undefined; + } else { + this.min = z.right; + this.consolidate(); + } + + this.size--; + + return z.element; + } + + /** + * O(log n) time operation. + * merge two heaps. The heap that is merged will be cleared. The heap that is merged into will remain. + * @param heapToMerge + */ + merge(heapToMerge: FibonacciHeap): void { + if (heapToMerge.size === 0) { + return; // Nothing to merge + } + + // Merge the root lists of the two heaps + if (this.root && heapToMerge.root) { + const thisRoot = this.root; + const otherRoot = heapToMerge.root; + + const thisRootRight = thisRoot.right!; + const otherRootLeft = otherRoot.left!; + + thisRoot.right = otherRoot; + otherRoot.left = thisRoot; + + thisRootRight.left = otherRootLeft; + otherRootLeft.right = thisRootRight; + } + + // Update the minimum node + if (!this.min || (heapToMerge.min && this.comparator(heapToMerge.min.element, this.min.element) < 0)) { + this.min = heapToMerge.min; + } + + // Update the size + this.size += heapToMerge.size; + + // Clear the heap that was merged + heapToMerge.clear(); + } +} diff --git a/test/types/index.ts b/test/types/index.ts new file mode 100644 index 0000000..04bca77 --- /dev/null +++ b/test/types/index.ts @@ -0,0 +1 @@ +export * from './utils'; diff --git a/test/types/utils/big-o.ts b/test/types/utils/big-o.ts new file mode 100644 index 0000000..7c015ba --- /dev/null +++ b/test/types/utils/big-o.ts @@ -0,0 +1 @@ +export type AnyFunction = (...args: any[]) => any; diff --git a/test/types/utils/index.ts b/test/types/utils/index.ts new file mode 100644 index 0000000..1a1fd5d --- /dev/null +++ b/test/types/utils/index.ts @@ -0,0 +1 @@ +export * from './big-o'; diff --git a/test/unit/data-structures/heap/heap.test.ts b/test/unit/data-structures/heap/heap.test.ts index d987c02..5c3f3c3 100644 --- a/test/unit/data-structures/heap/heap.test.ts +++ b/test/unit/data-structures/heap/heap.test.ts @@ -1,4 +1,5 @@ -import {MaxHeap, MinHeap} from '../../../../src'; +import {FibonacciHeap, MaxHeap, MinHeap} from '../../../../src'; +import {logBigOMetricsWrap} from "../../../utils"; describe('Heap Operation Test', () => { it('should numeric heap work well', function () { @@ -60,3 +61,190 @@ describe('Heap Operation Test', () => { } }); }); + +describe('FibonacciHeap', () => { + let heap: FibonacciHeap; + + beforeEach(() => { + heap = new FibonacciHeap(); + }); + + test('push & peek', () => { + heap.push(10); + heap.push(5); + expect(heap.peek()).toBe(5); + }); + + test('pop', () => { + heap.push(10); + heap.push(5); + heap.push(15); + expect(heap.pop()).toBe(5); + expect(heap.pop()).toBe(10); + expect(heap.pop()).toBe(15); + }); + + test('pop on an empty heap', () => { + expect(heap.pop()).toBeUndefined(); + }); + + test('size', () => { + expect(heap.size).toBe(0); + heap.push(10); + expect(heap.size).toBe(1); + heap.pop(); + expect(heap.size).toBe(0); + }); + + test('clear', () => { + heap.push(10); + heap.push(5); + heap.clear(); + expect(heap.size).toBe(0); + expect(heap.peek()).toBeUndefined(); + }); + + test('custom comparator', () => { + const maxHeap = new FibonacciHeap((a, b) => b - a); + maxHeap.push(10); + maxHeap.push(5); + expect(maxHeap.peek()).toBe(10); + }); +}); + +describe('FibonacciHeap', () => { + let heap: FibonacciHeap; + + beforeEach(() => { + heap = new FibonacciHeap(); + }); + + it('should initialize an empty heap', () => { + expect(heap.size).toBe(0); + expect(heap.peek()).toBeUndefined(); + }); + + it('should push items into the heap and update size', () => { + heap.push(10); + heap.push(5); + + expect(heap.size).toBe(2); + }); + + it('should peek the minimum item', () => { + heap.push(10); + heap.push(5); + heap.push(15); + + expect(heap.peek()).toBe(5); + }); + + it('should pop the minimum item and update size', () => { + heap.push(10); + heap.push(5); + heap.push(15); + + const minItem = heap.pop(); + + expect(minItem).toBe(5); + expect(heap.size).toBe(2); + }); + + it('should correctly merge two heaps', () => { + const heap1 = new FibonacciHeap(); + const heap2 = new FibonacciHeap(); + + heap1.push(10); + heap2.push(5); + + heap1.merge(heap2); + + expect(heap1.size).toBe(2); + expect(heap1.peek()).toBe(5); + }); + + it('should clear the heap', () => { + heap.push(10); + heap.push(5); + + heap.clear(); + + expect(heap.size).toBe(0); + expect(heap.peek()).toBeUndefined(); + }); + + it('should handle custom comparators', () => { + const customComparator = (a: number, b: number) => b - a; + const customHeap = new FibonacciHeap(customComparator); + + customHeap.push(10); + customHeap.push(5); + customHeap.push(15); + + expect(customHeap.peek()).toBe(15); + }); + + describe('FibonacciHeap Merge', () => { + it('should merge two Fibonacci heaps correctly', () => { + const heap1 = new FibonacciHeap(); + heap1.push(5).push(10); + + const heap2 = new FibonacciHeap(); + heap2.push(3).push(7); + + heap1.merge(heap2); + + expect(heap1.size).toBe(4); // Combined size of both heaps + expect(heap2.size).toBe(0); // Merged heap should be empty + expect(heap1.peek()).toBe(3); // Minimum element should be 3 + }); + }); +}); + + +describe('FibonacciHeap Stress Test', () => { + it('should handle a large number of elements efficiently', () => { + + const testByMagnitude = (magnitude: number) => { + const heap = new FibonacciHeap(); + + // Add 1000 elements to the heap + for (let i = 1; i <= magnitude; i++) { + heap.push(i); + } + + // Verify that the minimum element is 1 (smallest element) + expect(heap.peek()).toBe(1); + + // Remove all 1000 elements from the heap + const elements = []; + while (heap.size > 0) { + elements.push(heap.pop()); + } + + // Verify that all elements were removed in ascending order + for (let i = 1; i <= magnitude; i++) { + expect(elements[i - 1]).toBe(i); + } + + // Verify that the heap is now empty + expect(heap.size).toBe(0); + } + + testByMagnitude(1000); + + // [ + // 10, 100, 1000, 5000, 10000, 20000, 50000, 75000, 100000, + // 150000, 200000, 250000, 300000, 400000, 500000, 600000, 700000, 800000, 900000, 1000000 + // ].forEach(m => logBigOMetricsWrap(testByMagnitude, [m])); + [ + 10, 100, 1000, 5000, 10000, 20000, 50000, 75000, 100000, + 150000, 200000, 250000, 300000, 400000, 500000, 600000, 700000, 800000, 900000, 1000000 + ].forEach(m => logBigOMetricsWrap((c: number) => { + const result: number[] = []; + for (let i = 0; i < c; i++) result.push(i); + return result; + } , [m], 'loopPush')); + + }); +}); diff --git a/test/utils/big-o.ts b/test/utils/big-o.ts new file mode 100644 index 0000000..2f18aba --- /dev/null +++ b/test/utils/big-o.ts @@ -0,0 +1,193 @@ +import {AnyFunction} from "../types"; + +const orderReducedBy = 2; // reduction of bigO's order compared to the baseline bigO + +export const magnitude = { + CONSTANT: Math.floor(Number.MAX_SAFE_INTEGER / Math.pow(10, orderReducedBy)), + LOG_N: Math.pow(10, 9 - orderReducedBy), + LINEAR: Math.pow(10, 6 - orderReducedBy), + N_LOG_N: Math.pow(10, 5 - orderReducedBy), + SQUARED: Math.pow(10, 4 - orderReducedBy), + CUBED: Math.pow(10, 3 - orderReducedBy), + FACTORIAL: 20 - orderReducedBy +}; + +export const bigO = { + CONSTANT: magnitude.CONSTANT / 100000, + LOG_N: Math.log2(magnitude.LOG_N) / 1000, + LINEAR: magnitude.LINEAR / 1000, + N_LOG_N: (magnitude.N_LOG_N * Math.log2(magnitude.LOG_N)) / 1000, + SQUARED: Math.pow(magnitude.SQUARED, 2) / 1000, + CUBED: Math.pow(magnitude.SQUARED, 3) / 1000, + FACTORIAL: 10000 +}; + +function findPotentialN(input: any): number { + let longestArray: any[] = []; + let mostProperties: { [key: string]: any } = {}; + + function recurse(obj: any) { + if (Array.isArray(obj)) { + if (obj.length > longestArray.length) { + longestArray = obj; + } + } else if (typeof obj === 'object' && obj !== null) { + const keys = Object.keys(obj); + if (keys.length > Object.keys(mostProperties).length) { + mostProperties = obj; + } + keys.forEach((key) => { + recurse(obj[key]); + }); + } + } + + if (Array.isArray(input)) { + input.forEach((item) => { + recurse(item); + }); + } else { + recurse(input); + } + + // return [longestArray, mostProperties] : [any[], { [key: string]: any }]; + return Math.max(longestArray.length, Object.keys(mostProperties).length); +} + +function linearRegression(x: number[], y: number[]) { + const n = x.length; + + const sumX = x.reduce((acc, val) => acc + val, 0); + const sumY = y.reduce((acc, val) => acc + val, 0); + + const sumXSquared = x.reduce((acc, val) => acc + val ** 2, 0); + const sumXY = x.reduce((acc, val, i) => acc + val * y[i], 0); + + const slope = (n * sumXY - sumX * sumY) / (n * sumXSquared - sumX ** 2); + const intercept = (sumY - slope * sumX) / n; + + const yHat = x.map((val) => slope * val + intercept); + + const totalVariation = y.map((val, i) => (val - yHat[i]) ** 2).reduce((acc, val) => acc + val, 0); + const explainedVariation = y.map((val) => (val - (sumY / n)) ** 2).reduce((acc, val) => acc + val, 0); + + const rSquared = 1 - totalVariation / explainedVariation; + + return { slope, intercept, rSquared }; +} + +function estimateBigO(runtimes: number[], dataSizes: number[]): string { + // Make sure the input runtimes and data sizes have the same length + if (runtimes.length !== dataSizes.length) { + return "输入数组的长度不匹配"; + } + + // Create an array to store the computational complexity of each data point + const complexities: string[] = []; + + // Traverse different possible complexities + const complexitiesToCheck: string[] = [ + "O(1)", // constant time complexity + "O(log n)", // Logarithmic time complexity + "O(n)", // linear time complexity + "O(n log n)", // linear logarithmic time complexity + "O(n^2)", // squared time complexity + ]; + + for (const complexity of complexitiesToCheck) { + // Calculate data points for fitting + const fittedData: number[] = dataSizes.map((size) => { + if (complexity === "O(1)") { + return 1; // constant time complexity + } else if (complexity === "O(log n)") { + return Math.log(size); + } else if (complexity === "O(n)") { + return size; + } else if (complexity === "O(n log n)") { + return size * Math.log(size); + } else if (complexity === "O(n^2)") { + return size ** 2; + } else { + return size ** 10 + } + }); + + // Fit the data points using linear regression analysis + const regressionResult = linearRegression(fittedData, runtimes); + + // Check the R-squared value of the fit. It is usually considered a valid fit if it is greater than 0.9. + if (regressionResult.rSquared >= 0.9) { + complexities.push(complexity); + } + } + + // If there is no valid fitting result, return "cannot estimate", otherwise return the estimated time complexity + if (complexities.length === 0) { + return "Unable to estimate"; + } else { + return complexities.join(" or "); + } +} + +const methodLogs: Map = new Map(); + +export function logBigOMetrics(target: any, propertyKey: string, descriptor: PropertyDescriptor) { + const originalMethod = descriptor.value; + + descriptor.value = function (...args: any[]) { + const startTime = performance.now(); + const result = originalMethod.apply(this, args); + const endTime = performance.now(); + const runTime = endTime - startTime; + + const methodName = `${target.constructor.name}.${propertyKey}`; + if (!methodLogs.has(methodName)) { + methodLogs.set(methodName, []); + } + + const methodLog = methodLogs.get(methodName); + + const maxDataSize = args.length === 1 && typeof args[0] === "number" ? args[0] : findPotentialN(args); + if (methodLog) { + methodLog.push([runTime, maxDataSize]); + + if (methodLog.length >= 20) { + console.log('triggered', methodName, methodLog); + const bigO = estimateBigO(methodLog.map(([runTime,]) => runTime), methodLog.map(([runTime,]) => runTime)); + console.log(`Estimated Big O: ${bigO}`); + methodLogs.delete(methodName) + } + } + + return result; + }; + + return descriptor; +} + +export function logBigOMetricsWrap(fn: F, args: Parameters, fnName: string) { + const startTime = performance.now(); + const result = fn(args); + const endTime = performance.now(); + const runTime = endTime - startTime; + const methodName = `${fnName}`; + if (!methodLogs.has(methodName)) { + methodLogs.set(methodName, []); + } + + const methodLog = methodLogs.get(methodName); + + const maxDataSize = args.length === 1 && typeof args[0] === "number" ? args[0] : findPotentialN(args); + if (methodLog) { + methodLog.push([runTime, maxDataSize]); + + if (methodLog.length >= 20) { + console.log('triggered', methodName, methodLog); + const bigO = estimateBigO(methodLog.map(([runTime,]) => runTime), methodLog.map(([runTime,]) => runTime)); + console.log(`Estimated Big O: ${bigO}`); + methodLogs.delete(methodName) + } + } + + return result; +} diff --git a/test/utils/index.ts b/test/utils/index.ts index f605d40..8ac34d1 100644 --- a/test/utils/index.ts +++ b/test/utils/index.ts @@ -1,2 +1,2 @@ export * from './number'; -export * from './magnitude'; +export * from './big-o'; diff --git a/test/utils/magnitude.ts b/test/utils/magnitude.ts deleted file mode 100644 index b32f1cd..0000000 --- a/test/utils/magnitude.ts +++ /dev/null @@ -1,21 +0,0 @@ -const orderReducedBy = 2; // reduction of magnitude's order compared to the baseline magnitude - -export const magnitude = { - CONSTANT: Math.floor(Number.MAX_SAFE_INTEGER / Math.pow(10, orderReducedBy)), - LOG_N: Math.pow(10, 9 - orderReducedBy), - LINEAR: Math.pow(10, 6 - orderReducedBy), - N_LOG_N: Math.pow(10, 5 - orderReducedBy), - SQUARED: Math.pow(10, 4 - orderReducedBy), - CUBED: Math.pow(10, 3 - orderReducedBy), - FACTORIAL: 20 - orderReducedBy -}; - -export const bigO = { - CONSTANT: magnitude.CONSTANT / 100000, - LOG_N: Math.log2(magnitude.LOG_N) / 1000, - LINEAR: magnitude.LINEAR / 1000, - N_LOG_N: (magnitude.N_LOG_N * Math.log2(magnitude.LOG_N)) / 1000, - SQUARED: Math.pow(magnitude.SQUARED, 2) / 1000, - CUBED: Math.pow(magnitude.SQUARED, 3) / 1000, - FACTORIAL: 10000 -}; From 39baccd17c9a4f36411f32ad34ad8364c2c435a2 Mon Sep 17 00:00:00 2001 From: Revone Date: Sat, 21 Oct 2023 02:02:13 +0800 Subject: [PATCH 04/46] [pkg] v1.36.8 published --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 535d6ed..a0e641d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "data-structure-typed", - "version": "1.36.7", + "version": "1.36.8", "description": "Data Structures of Javascript & TypeScript. Binary Tree, BST, Graph, Heap, Priority Queue, Linked List, Queue, Deque, Stack, AVL Tree, Tree Multiset, Trie, Directed Graph, Undirected Graph, Singly Linked List, Doubly Linked List, Max Heap, Max Priority Queue, Min Heap, Min Priority Queue.", "main": "dist/index.js", "module": "lib/index.js", From cb56b04af5073d61a03a23c9987247c218239d36 Mon Sep 17 00:00:00 2001 From: Revone Date: Sat, 21 Oct 2023 14:46:41 +0800 Subject: [PATCH 05/46] [test] big o estimate refined --- CHANGELOG.md | 3 ++- package-lock.json | 4 ++-- package.json | 2 +- test/utils/big-o.ts | 57 +++++++++++++++++++++++---------------------- 4 files changed, 34 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c65758..16c259d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,10 +8,11 @@ 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.36.7](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) +## [v1.36.8](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) ### Changes +- [heap] fibonacci heap implemented. [test] big O estimate. [project] n… [`#15`](https://github.com/zrwusa/data-structure-typed/pull/15) - [rbtree] implemented, but with bugs [`#13`](https://github.com/zrwusa/data-structure-typed/pull/13) - [trie] renamed ambiguous methods and add comments to all methods. [`#12`](https://github.com/zrwusa/data-structure-typed/pull/12) - [binarytree] modified the getDepth method to adhere to the proper def… [`#11`](https://github.com/zrwusa/data-structure-typed/pull/11) diff --git a/package-lock.json b/package-lock.json index f46acf4..72d4355 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "data-structure-typed", - "version": "1.36.7", + "version": "1.36.8", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "data-structure-typed", - "version": "1.36.7", + "version": "1.36.8", "license": "MIT", "devDependencies": { "@types/benchmark": "^2.1.3", diff --git a/package.json b/package.json index a0e641d..4e13f50 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "changelog": "auto-changelog", "coverage:badge": "istanbul-badges-readme", "ci": "env && npm run lint && npm run build && npm run update:individuals && npm run test && git fetch --tags && npm run changelog", - "publish:all": "npm run ci && npm publish && sh /scripts/publish_all_subs.sh && sh /scripts/publish_docs.sh" + "publish:all": "npm run ci && npm publish && sh scripts/publish_all_subs.sh && sh scripts/publish_docs.sh" }, "repository": { "type": "git", diff --git a/test/utils/big-o.ts b/test/utils/big-o.ts index 2f18aba..755bdb1 100644 --- a/test/utils/big-o.ts +++ b/test/utils/big-o.ts @@ -22,6 +22,7 @@ export const bigO = { FACTORIAL: 10000 }; + function findPotentialN(input: any): number { let longestArray: any[] = []; let mostProperties: { [key: string]: any } = {}; @@ -79,7 +80,7 @@ function linearRegression(x: number[], y: number[]) { function estimateBigO(runtimes: number[], dataSizes: number[]): string { // Make sure the input runtimes and data sizes have the same length if (runtimes.length !== dataSizes.length) { - return "输入数组的长度不匹配"; + return "Lengths of input arrays do not match"; } // Create an array to store the computational complexity of each data point @@ -131,6 +132,33 @@ function estimateBigO(runtimes: number[], dataSizes: number[]): string { const methodLogs: Map = new Map(); +export function logBigOMetricsWrap(fn: F, args: Parameters, fnName: string) { + const startTime = performance.now(); + const result = fn(args); + const endTime = performance.now(); + const runTime = endTime - startTime; + const methodName = `${fnName}`; + if (!methodLogs.has(methodName)) { + methodLogs.set(methodName, []); + } + + const methodLog = methodLogs.get(methodName); + + const maxDataSize = args.length === 1 && typeof args[0] === "number" ? args[0] : findPotentialN(args); + if (methodLog) { + methodLog.push([runTime, maxDataSize]); + + if (methodLog.length >= 20) { + console.log('triggered', methodName, methodLog); + const bigO = estimateBigO(methodLog.map(([runTime,]) => runTime), methodLog.map(([runTime,]) => runTime)); + console.log(`Estimated Big O: ${bigO}`); + methodLogs.delete(methodName) + } + } + + return result; +} + export function logBigOMetrics(target: any, propertyKey: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; @@ -164,30 +192,3 @@ export function logBigOMetrics(target: any, propertyKey: string, descriptor: Pro return descriptor; } - -export function logBigOMetricsWrap(fn: F, args: Parameters, fnName: string) { - const startTime = performance.now(); - const result = fn(args); - const endTime = performance.now(); - const runTime = endTime - startTime; - const methodName = `${fnName}`; - if (!methodLogs.has(methodName)) { - methodLogs.set(methodName, []); - } - - const methodLog = methodLogs.get(methodName); - - const maxDataSize = args.length === 1 && typeof args[0] === "number" ? args[0] : findPotentialN(args); - if (methodLog) { - methodLog.push([runTime, maxDataSize]); - - if (methodLog.length >= 20) { - console.log('triggered', methodName, methodLog); - const bigO = estimateBigO(methodLog.map(([runTime,]) => runTime), methodLog.map(([runTime,]) => runTime)); - console.log(`Estimated Big O: ${bigO}`); - methodLogs.delete(methodName) - } - } - - return result; -} From a6329163f76391f11d197cf59baff99e69806179 Mon Sep 17 00:00:00 2001 From: Revone Date: Sat, 21 Oct 2023 20:03:54 +0800 Subject: [PATCH 06/46] 1. No need for dfsIterative; integrate it directly into the dfs method. 2. Allow for public configuration of setLoopType. 3. Replace subTreeAdd with subTreeForeach for improved clarity and flexibility; provide a callback for enhanced versatility. 4. Standardize the naming of certain methods and parameters. --- README.md | 8 + src/data-structures/binary-tree/avl-tree.ts | 12 +- .../binary-tree/binary-tree.ts | 319 +++++------------- src/data-structures/binary-tree/rb-tree.ts | 6 +- .../binary-tree/tree-multiset.ts | 31 +- src/data-structures/hash/hash-map.ts | 2 +- src/data-structures/hash/hash-table.ts | 6 +- src/data-structures/heap/heap.ts | 7 +- .../linked-list/skip-linked-list.ts | 6 +- src/data-structures/queue/deque.ts | 4 +- src/data-structures/queue/queue.ts | 2 +- src/data-structures/trie/trie.ts | 4 +- src/interfaces/binary-tree.ts | 2 +- .../binary-tree/avl-tree.test.ts | 28 +- .../binary-tree/binary-tree.test.ts | 4 +- .../data-structures/binary-tree/bst.test.ts | 56 +-- .../binary-tree/overall.test.ts | 6 +- .../binary-tree/rb-tree.test.ts | 2 +- .../binary-tree/tree-multiset.test.ts | 56 +-- .../graph/directed-graph.test.ts | 2 +- .../graph/undirected-graph.test.ts | 2 +- .../data-structures/hash/hash-map.test.ts | 4 +- .../data-structures/hash/hash-table.test.ts | 10 +- test/unit/data-structures/heap/heap.test.ts | 27 +- .../linked-list/singly-linked-list.test.ts | 14 +- .../linked-list/skip-list.test.ts | 4 +- .../priority-queue/max-priority-queue.test.ts | 2 +- test/unit/data-structures/queue/deque.test.ts | 6 +- test/unit/data-structures/trie/trie.test.ts | 10 +- test/utils/big-o.ts | 107 +++--- 30 files changed, 311 insertions(+), 438 deletions(-) diff --git a/README.md b/README.md index 7c22027..169fefd 100644 --- a/README.md +++ b/README.md @@ -641,6 +641,14 @@ Array.from(dijkstraResult?.seen ?? []).map(vertex => vertex.id) // ['A', 'B', 'D ## Code design +### Adhere to ES6 standard naming conventions for APIs. + +Standardize API conventions by using 'add' and 'delete' for element manipulation methods in all data structures. + +Opt for concise and clear method names, avoiding excessive length while ensuring explicit intent. + +### Object-oriented programming(OOP) + By strictly adhering to object-oriented design (BinaryTree -> BST -> AVLTree -> TreeMultiset), you can seamlessly inherit the existing data structures to implement the customized ones you need. Object-oriented design stands as the optimal approach to data structure design. diff --git a/src/data-structures/binary-tree/avl-tree.ts b/src/data-structures/binary-tree/avl-tree.ts index 32cb1d1..f5d5aca 100644 --- a/src/data-structures/binary-tree/avl-tree.ts +++ b/src/data-structures/binary-tree/avl-tree.ts @@ -33,13 +33,13 @@ export class AVLTree = AVLTreeNode> extends B } /** - * The `swapLocation` function swaps the location of two nodes in a binary tree. - * @param {N} srcNode - The source node that you want to swap with the destination node. + * The `_swap` function swaps the location of two nodes in a binary tree. + * @param {N} srcNode - The source node that you want to _swap with the destination node. * @param {N} destNode - The `destNode` parameter represents the destination node where the values from `srcNode` will * be swapped to. * @returns The `destNode` is being returned. */ - override swapLocation(srcNode: N, destNode: N): N { + protected override _swap(srcNode: N, destNode: N): N { const {key, val, height} = destNode; const tempNode = this.createNode(key, val); @@ -85,14 +85,14 @@ export class AVLTree = AVLTreeNode> extends B } /** - * The function overrides the remove method of a binary tree and performs additional operations to balance the tree after + * The function overrides the delete method of a binary tree and performs additional operations to balance the tree after * deletion. * @param {BinaryTreeNodeKey} key - The `key` parameter represents the identifier of the binary tree node that needs to be * removed. * @returns The method is returning an array of `BinaryTreeDeletedResult` objects. */ - override remove(key: BinaryTreeNodeKey): BinaryTreeDeletedResult[] { - const deletedResults = super.remove(key); + override delete(key: BinaryTreeNodeKey): BinaryTreeDeletedResult[] { + const deletedResults = super.delete(key); for (const {needBalanced} of deletedResults) { if (needBalanced) { this._balancePath(needBalanced); diff --git a/src/data-structures/binary-tree/binary-tree.ts b/src/data-structures/binary-tree/binary-tree.ts index fef5769..54b600e 100644 --- a/src/data-structures/binary-tree/binary-tree.ts +++ b/src/data-structures/binary-tree/binary-tree.ts @@ -145,6 +145,10 @@ export class BinaryTree = BinaryTreeNode> return this._loopType; } + set loopType(v: LoopType) { + this._loopType = v; + } + visitedKey: BinaryTreeNodeKey[] = []; visitedVal: N['val'][] = []; @@ -152,13 +156,13 @@ export class BinaryTree = BinaryTreeNode> visitedNode: N[] = []; /** - * The `swapLocation` function swaps the location of two nodes in a binary tree. - * @param {N} srcNode - The source node that you want to swap with the destination node. + * The `_swap` function swaps the location of two nodes in a binary tree. + * @param {N} srcNode - The source node that you want to _swap with the destination node. * @param {N} destNode - The `destNode` parameter represents the destination node where the values from `srcNode` will * be swapped to. * @returns The `destNode` is being returned. */ - swapLocation(srcNode: N, destNode: N): N { + protected _swap(srcNode: N, destNode: N): N { const {key, val} = destNode; const tempNode = this.createNode(key, val); @@ -300,13 +304,13 @@ export class BinaryTree = BinaryTreeNode> } /** - * The `remove` function in TypeScript is used to delete a node from a binary search tree and returns an array of objects + * The `delete` function in TypeScript is used to delete a node from a binary search tree and returns an array of objects * containing the deleted node and the node that needs to be balanced. * @param {N | BinaryTreeNodeKey} nodeOrKey - The `nodeOrKey` parameter can be either a node object (`N`) or a binary tree * node ID (`BinaryTreeNodeKey`). - * @returns The function `remove` returns an array of `BinaryTreeDeletedResult` objects. + * @returns The function `delete` returns an array of `BinaryTreeDeletedResult` objects. */ - remove(nodeOrKey: N | BinaryTreeNodeKey): BinaryTreeDeletedResult[] { + delete(nodeOrKey: N | BinaryTreeNodeKey): BinaryTreeDeletedResult[] { const bstDeletedResult: BinaryTreeDeletedResult[] = []; if (!this.root) return bstDeletedResult; @@ -333,7 +337,7 @@ export class BinaryTree = BinaryTreeNode> const leftSubTreeRightMost = curr.left ? this.getRightMost(curr.left) : null; if (leftSubTreeRightMost) { const parentOfLeftSubTreeMax = leftSubTreeRightMost.parent; - orgCurrent = this.swapLocation(curr, leftSubTreeRightMost); + orgCurrent = this._swap(curr, leftSubTreeRightMost); if (parentOfLeftSubTreeMax) { if (parentOfLeftSubTreeMax.right === leftSubTreeRightMost) parentOfLeftSubTreeMax.right = leftSubTreeRightMost.left; @@ -683,12 +687,12 @@ export class BinaryTree = BinaryTreeNode> /** * The function checks if a binary search tree is valid by traversing it either recursively or iteratively. - * @param {N | null} node - The `node` parameter represents the root node of a binary search tree (BST). + * @param {N | null} subTreeRoot - The `node` parameter represents the root node of a binary search tree (BST). * @returns a boolean value. */ - isSubtreeBST(node: N | null): boolean { + isSubtreeBST(subTreeRoot: N | null): boolean { // TODO there is a bug - if (!node) return true; + if (!subTreeRoot) return true; if (this._loopType === LoopType.RECURSIVE) { const dfs = (cur: N | null | undefined, min: BinaryTreeNodeKey, max: BinaryTreeNodeKey): boolean => { @@ -697,11 +701,11 @@ export class BinaryTree = BinaryTreeNode> return dfs(cur.left, min, cur.key) && dfs(cur.right, cur.key, max); }; - return dfs(node, Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER); + return dfs(subTreeRoot, Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER); } else { const stack = []; let prev = Number.MIN_SAFE_INTEGER, - curr: N | null | undefined = node; + curr: N | null | undefined = subTreeRoot; while (curr || stack.length > 0) { while (curr) { stack.push(curr); @@ -813,38 +817,21 @@ export class BinaryTree = BinaryTreeNode> } /** - * The function `subTreeAdd` adds a delta value to a specified property of each node in a subtree. + * The function `subTreeForeach` adds a delta value to a specified property of each node in a subtree. * @param {N | BinaryTreeNodeKey | null} subTreeRoot - The `subTreeRoot` parameter represents the root node of a binary * tree or the ID of a node in the binary tree. It can also be `null` if there is no subtree to add to. - * @param {number} delta - The `delta` parameter is a number that represents the amount by which the property value of - * each node in the subtree should be incremented. - * @param {BinaryTreeNodePropertyName} [propertyName] - The `propertyName` parameter is an optional parameter that + * @param callBack - The `callBack` parameter is a function that takes a node as a parameter and returns a number. * specifies the property of the binary tree node that should be modified. If not provided, it defaults to 'key'. * @returns a boolean value. */ - subTreeAdd( - subTreeRoot: N | BinaryTreeNodeKey | null, - delta: number, - propertyName: BinaryTreeNodePropertyName = 'key' - ): boolean { + subTreeForeach(subTreeRoot: N | BinaryTreeNodeKey | null, callback: (node: N) => any): boolean { if (typeof subTreeRoot === 'number') subTreeRoot = this.get(subTreeRoot, 'key'); if (!subTreeRoot) return false; - const _addByProperty = (cur: N) => { - switch (propertyName) { - case 'key': - cur.key += delta; - break; - default: - cur.key += delta; - break; - } - }; - if (this._loopType === LoopType.RECURSIVE) { const _traverse = (cur: N) => { - _addByProperty(cur); + callback(cur); cur.left && _traverse(cur.left); cur.right && _traverse(cur.right); }; @@ -856,7 +843,7 @@ export class BinaryTree = BinaryTreeNode> while (stack.length > 0) { const cur = stack.pop()!; - _addByProperty(cur); + callback(cur); cur.right && stack.push(cur.right); cur.left && stack.push(cur.left); } @@ -903,6 +890,7 @@ export class BinaryTree = BinaryTreeNode> const queue: Array = [this.root]; while (queue.length !== 0) { + // TODO Array.shift is not efficient, consider using Deque const cur = queue.shift(); if (cur) { this._accumulatedByPropertyName(cur, nodeOrPropertyName); @@ -931,222 +919,107 @@ export class BinaryTree = BinaryTreeNode> * Performs a depth-first search (dfs) traversal on a binary tree and accumulates properties of each node based on the specified property name. * @param {'in' | 'pre' | 'post'} [pattern] - The traversal pattern: 'in' (in-order), 'pre' (pre-order), or 'post' (post-order). * @param {string} nodeOrPropertyName - The name of the property to accumulate. + * @param loopType - The type of loop to use for the depth-first search traversal. The default value is `LoopType.ITERATIVE`. * @returns An array of values corresponding to the specified property. */ - dfs(pattern: DFSOrderPattern, nodeOrPropertyName: 'key'): BinaryTreeNodeKey[]; + dfs(pattern: DFSOrderPattern, nodeOrPropertyName: 'key', loopType?: LoopType): BinaryTreeNodeKey[]; /** * Performs a depth-first search (dfs) traversal on a binary tree and accumulates the 'val' property of each node. * @param {'in' | 'pre' | 'post'} [pattern] - The traversal pattern: 'in' (in-order), 'pre' (pre-order), or 'post' (post-order). * @param {'val'} nodeOrPropertyName - The name of the property to accumulate. + * @param loopType - The type of loop to use for the depth-first search traversal. The default value is `LoopType.ITERATIVE`. * @returns An array of 'val' properties from each node. */ - dfs(pattern: DFSOrderPattern, nodeOrPropertyName: 'val'): N[]; + dfs(pattern: DFSOrderPattern, nodeOrPropertyName: 'val', loopType?: LoopType): N[]; /** * Performs a depth-first search (dfs) traversal on a binary tree and accumulates nodes themselves. * @param {'in' | 'pre' | 'post'} [pattern] - The traversal pattern: 'in' (in-order), 'pre' (pre-order), or 'post' (post-order). * @param {'node'} nodeOrPropertyName - The name of the property to accumulate. + * @param loopType - The type of loop to use for the depth-first search traversal. The default value is `LoopType.ITERATIVE`. * @returns An array of binary tree nodes. */ - dfs(pattern: DFSOrderPattern, nodeOrPropertyName: 'node'): N[]; + dfs(pattern: DFSOrderPattern, nodeOrPropertyName: 'node', loopType?: LoopType): N[]; /** * The dfs function performs a depth-first search traversal on a binary tree and returns the accumulated properties of * each node based on the specified pattern and property name. * @param {'in' | 'pre' | 'post'} [pattern] - The traversal pattern: 'in' (in-order), 'pre' (pre-order), or 'post' (post-order). * @param {NodeOrPropertyName} [nodeOrPropertyName] - The name of a property of the nodes in the binary tree. This property will be used to accumulate values during the depth-first search traversal. If no `nodeOrPropertyName` is provided, the default value is `'key'`. + * @param loopType - The type of loop to use for the depth-first search traversal. The default value is `LoopType.ITERATIVE`. * @returns an instance of the BinaryTreeNodeProperties class, which contains the accumulated properties of the binary tree nodes based on the specified pattern and node or property name. */ - dfs(pattern: DFSOrderPattern = 'in', nodeOrPropertyName: NodeOrPropertyName = 'key'): BinaryTreeNodeProperties { + dfs( + pattern: DFSOrderPattern = 'in', + nodeOrPropertyName: NodeOrPropertyName = 'key', + loopType: LoopType = LoopType.ITERATIVE + ): BinaryTreeNodeProperties { this._clearResults(); - const _traverse = (node: N) => { - switch (pattern) { - case 'in': - if (node.left) _traverse(node.left); - this._accumulatedByPropertyName(node, nodeOrPropertyName); - if (node.right) _traverse(node.right); - break; - case 'pre': - this._accumulatedByPropertyName(node, nodeOrPropertyName); - if (node.left) _traverse(node.left); - if (node.right) _traverse(node.right); - break; - case 'post': - if (node.left) _traverse(node.left); - if (node.right) _traverse(node.right); - this._accumulatedByPropertyName(node, nodeOrPropertyName); - break; - } - }; + if (loopType === LoopType.RECURSIVE) { + const _traverse = (node: N) => { + switch (pattern) { + case 'in': + if (node.left) _traverse(node.left); + this._accumulatedByPropertyName(node, nodeOrPropertyName); + if (node.right) _traverse(node.right); + break; + case 'pre': + this._accumulatedByPropertyName(node, nodeOrPropertyName); + if (node.left) _traverse(node.left); + if (node.right) _traverse(node.right); + break; + case 'post': + if (node.left) _traverse(node.left); + if (node.right) _traverse(node.right); + this._accumulatedByPropertyName(node, nodeOrPropertyName); + break; + } + }; + + this.root && _traverse(this.root); + } else { + if (!this.root) return this._getResultByPropertyName(nodeOrPropertyName); + // 0: visit, 1: print + const stack: {opt: 0 | 1; node: N | null | undefined}[] = [{opt: 0, node: this.root}]; + + while (stack.length > 0) { + const cur = stack.pop(); + if (!cur || !cur.node) continue; + if (cur.opt === 1) { + this._accumulatedByPropertyName(cur.node, nodeOrPropertyName); + } else { + switch (pattern) { + case 'in': + stack.push({opt: 0, node: cur.node.right}); + stack.push({opt: 1, node: cur.node}); + stack.push({opt: 0, node: cur.node.left}); + break; + case 'pre': + stack.push({opt: 0, node: cur.node.right}); + stack.push({opt: 0, node: cur.node.left}); + stack.push({opt: 1, node: cur.node}); + break; + case 'post': + stack.push({opt: 1, node: cur.node}); + stack.push({opt: 0, node: cur.node.right}); + stack.push({opt: 0, node: cur.node.left}); + break; + default: + stack.push({opt: 0, node: cur.node.right}); + stack.push({opt: 1, node: cur.node}); + stack.push({opt: 0, node: cur.node.left}); + break; + } + } + } + } - this.root && _traverse(this.root); return this._getResultByPropertyName(nodeOrPropertyName); } // --- start additional methods --- - /** - * Performs an iterative depth-first search (dfs) traversal on a binary tree and accumulates properties of each node based on their 'key' property. - * @returns An array of binary tree node IDs. - */ - dfsIterative(): BinaryTreeNodeKey[]; - - /** - * Performs an iterative depth-first search (dfs) traversal on a binary tree and accumulates properties of each node based on their 'key' property. - * @param {'in' | 'pre' | 'post'} [pattern] - The traversal pattern: 'in' (in-order), 'pre' (pre-order), or 'post' (post-order). - * @returns An array of values corresponding to the specified property. - */ - dfsIterative(pattern: DFSOrderPattern): BinaryTreeNodeKey[]; - - /** - * Performs an iterative depth-first search (dfs) traversal on a binary tree and accumulates properties of each node based on the specified property name. - * @param {'in' | 'pre' | 'post'} [pattern] - The traversal pattern: 'in' (in-order), 'pre' (pre-order), or 'post' (post-order). - * @param {string} nodeOrPropertyName - The name of the property to accumulate. - * @returns An array of values corresponding to the specified property. - */ - dfsIterative(pattern: DFSOrderPattern, nodeOrPropertyName: 'key'): BinaryTreeNodeKey[]; - - /** - * Performs an iterative depth-first search (dfs) traversal on a binary tree and accumulates the 'val' property of each node. - * @param {'in' | 'pre' | 'post'} [pattern] - The traversal pattern: 'in' (in-order), 'pre' (pre-order), or 'post' (post-order). - * @param {'val'} nodeOrPropertyName - The name of the property to accumulate. - * @returns An array of 'val' properties from each node. - */ - dfsIterative(pattern: DFSOrderPattern, nodeOrPropertyName: 'val'): N['val'][]; - - /** - * Performs an iterative depth-first search (dfs) traversal on a binary tree and accumulates nodes themselves. - * @param {'in' | 'pre' | 'post'} [pattern] - The traversal pattern: 'in' (in-order), 'pre' (pre-order), or 'post' (post-order). - * @param {'node'} nodeOrPropertyName - The name of the property to accumulate. - * @returns An array of binary tree nodes. - */ - dfsIterative(pattern: DFSOrderPattern, nodeOrPropertyName: 'node'): N[]; - - /** - * The dfsIterative function performs an iterative depth-first search traversal on a binary tree, with the option to - * specify the traversal pattern and the property name to accumulate results by. - * @param {'in' | 'pre' | 'post'} [pattern] - The traversal pattern: 'in' (in-order), 'pre' (pre-order), or 'post' (post-order). - * @param {NodeOrPropertyName} [nodeOrPropertyName] - The name of a property of the nodes in the binary tree. This property will be used to accumulate values during the depth-first search traversal. By default, it is set to `'key'`. - * @returns An object of type BinaryTreeNodeProperties. - */ - dfsIterative( - pattern: DFSOrderPattern = 'in', - nodeOrPropertyName: NodeOrPropertyName = 'key' - ): BinaryTreeNodeProperties { - this._clearResults(); - if (!this.root) return this._getResultByPropertyName(nodeOrPropertyName); - // 0: visit, 1: print - const stack: {opt: 0 | 1; node: N | null | undefined}[] = [{opt: 0, node: this.root}]; - - while (stack.length > 0) { - const cur = stack.pop(); - if (!cur || !cur.node) continue; - if (cur.opt === 1) { - this._accumulatedByPropertyName(cur.node, nodeOrPropertyName); - } else { - switch (pattern) { - case 'in': - stack.push({opt: 0, node: cur.node.right}); - stack.push({opt: 1, node: cur.node}); - stack.push({opt: 0, node: cur.node.left}); - break; - case 'pre': - stack.push({opt: 0, node: cur.node.right}); - stack.push({opt: 0, node: cur.node.left}); - stack.push({opt: 1, node: cur.node}); - break; - case 'post': - stack.push({opt: 1, node: cur.node}); - stack.push({opt: 0, node: cur.node.right}); - stack.push({opt: 0, node: cur.node.left}); - break; - default: - stack.push({opt: 0, node: cur.node.right}); - stack.push({opt: 1, node: cur.node}); - stack.push({opt: 0, node: cur.node.left}); - break; - } - } - } - - return this._getResultByPropertyName(nodeOrPropertyName); - } - - /** - * Performs a level-order traversal on a binary tree starting from the specified node and accumulates properties of each node based on their 'key' property. - * @returns An array of binary tree node IDs. - */ - levelIterative(): BinaryTreeNodeKey[]; - - /** - * Performs a level-order traversal on a binary tree starting from the specified node and accumulates properties of each node based on their 'key' property. - * @param {N | null} node - The starting node for the level order traversal. If null, the root node of the tree is used as the starting node. - * @returns An array of binary tree node IDs. - */ - levelIterative(node: N | null): BinaryTreeNodeKey[]; - - /** - * Performs a level-order traversal on a binary tree starting from the specified node and accumulates properties of each node based on the specified property name. - * @param {N | null} node - The starting node for the level order traversal. If null, the root node of the tree is used as the starting node. - * @param {string} nodeOrPropertyName - The name of the property to accumulate. - * @returns An array of values corresponding to the specified property. - */ - levelIterative(node: N | null, nodeOrPropertyName: 'key'): BinaryTreeNodeKey[]; - - /** - * Performs a level-order traversal on a binary tree starting from the specified node and accumulates the 'val' property of each node. - * @param {N | null} node - The starting node for the level order traversal. If null, the root node of the tree is used as the starting node. - * @param {'val'} nodeOrPropertyName - The name of the property to accumulate. - * @returns An array of 'val' properties from each node. - */ - levelIterative(node: N | null, nodeOrPropertyName: 'val'): N['val'][]; - - /** - * Performs a level-order traversal on a binary tree starting from the specified node and accumulates nodes themselves. - * @param {N | null} node - The starting node for the level order traversal. If null, the root node of the tree is used as the starting node. - * @param {'node'} nodeOrPropertyName - The name of the property to accumulate. - * @returns An array of binary tree nodes. - */ - levelIterative(node: N | null, nodeOrPropertyName: 'node'): N[]; - - /** - * The `levelIterative` function performs a level-order traversal on a binary tree and returns the values of the nodes - * in an array, based on a specified property name. - * @param {N | null} node - The `node` parameter is a BinaryTreeNode object representing the starting - * node for the level order traversal. It can be null if no specific node is provided, in which case the root node of - * the tree is used as the starting node. - * @param {NodeOrPropertyName} [nodeOrPropertyName] - The `nodeOrPropertyName` parameter is an optional parameter that - * can be either a `BinaryTreeNode` property name or the string `'key'`. If a property name is provided, the function - * will accumulate results based on that property. If no property name is provided, the function will default to - * accumulating results based on the 'key' property. - * @returns An object of type `BinaryTreeNodeProperties`. - */ - levelIterative( - node: N | null = this.root, - nodeOrPropertyName: NodeOrPropertyName = 'key' - ): BinaryTreeNodeProperties { - if (!node) return []; - - this._clearResults(); - const queue: N[] = [node]; - - while (queue.length > 0) { - const cur = queue.shift(); - if (cur) { - this._accumulatedByPropertyName(cur, nodeOrPropertyName); - if (cur.left) { - queue.push(cur.left); - } - if (cur.right) { - queue.push(cur.right); - } - } - } - - return this._getResultByPropertyName(nodeOrPropertyName); - } - /** * Collects nodes from a binary tree by a specified property and organizes them into levels. * @returns A 2D array of AbstractBinaryTreeNodeProperty objects. @@ -1425,14 +1298,6 @@ export class BinaryTree = BinaryTreeNode> } } - /** - * The function sets the loop type for a protected variable. - * @param {LoopType} value - The value parameter is of type LoopType. - */ - protected _setLoopType(value: LoopType) { - this._loopType = value; - } - /** * The function sets the root property of an object to a given value, and if the value is not null, it also sets the * parent property of the value to undefined. diff --git a/src/data-structures/binary-tree/rb-tree.ts b/src/data-structures/binary-tree/rb-tree.ts index 7266828..fafb4f1 100644 --- a/src/data-structures/binary-tree/rb-tree.ts +++ b/src/data-structures/binary-tree/rb-tree.ts @@ -164,10 +164,10 @@ export class RBTree = RBTreeNode> extends BST< // // Remove a node // private _removeNode(node: N, replacement: N | null | undefined): void { // if (node === this.root && !replacement) { - // // If there's only the root node and no replacement, simply remove the root node + // // If there's only the root node and no replacement, simply delete the root node // this._setRoot(null); // } else if (node === this.root || this._isNodeRed(node)) { - // // If the node is the root or a red node, remove it directly + // // If the node is the root or a red node, delete it directly // if (node.parent!.left === node) { // node.parent!.left = replacement; // } else { @@ -205,7 +205,7 @@ export class RBTree = RBTreeNode> extends BST< // node.right = null; // } // - // override remove(nodeOrKey: BinaryTreeNodeKey | N): BinaryTreeDeletedResult[] { + // override delete(nodeOrKey: BinaryTreeNodeKey | N): BinaryTreeDeletedResult[] { // const node = this.get(nodeOrKey); // const result: BinaryTreeDeletedResult[] = [{deleted: undefined, needBalanced: null}]; // if (!node) return result; // Node does not exist diff --git a/src/data-structures/binary-tree/tree-multiset.ts b/src/data-structures/binary-tree/tree-multiset.ts index f048cbf..06294b6 100644 --- a/src/data-structures/binary-tree/tree-multiset.ts +++ b/src/data-structures/binary-tree/tree-multiset.ts @@ -70,12 +70,12 @@ export class TreeMultiset = TreeMultiset /** * The function swaps the location of two nodes in a tree data structure. - * @param {N} srcNode - The source node that we want to swap with the destination node. + * @param {N} srcNode - The source node that we want to _swap with the destination node. * @param {N} destNode - The `destNode` parameter represents the destination node where the values from `srcNode` will * be swapped with. * @returns the `destNode` after swapping its values with the `srcNode`. */ - override swapLocation(srcNode: N, destNode: N): N { + protected override _swap(srcNode: N, destNode: N): N { const {key, val, count, height} = destNode; const tempNode = this.createNode(key, val, count); if (tempNode) { @@ -285,15 +285,15 @@ export class TreeMultiset = TreeMultiset } /** - * The `remove` function removes a node from a binary search tree and returns the deleted node along with the parent + * The `delete` function removes a node from a binary search tree and returns the deleted node along with the parent * node that needs to be balanced. * @param {N | BinaryTreeNodeKey | null} nodeOrKey - The `nodeOrKey` parameter can be one of the following: * @param {boolean} [ignoreCount] - The `ignoreCount` parameter is an optional boolean parameter that determines * whether to ignore the count of the node being removed. If `ignoreCount` is set to `true`, the count of the node will * not be taken into account when removing it. If `ignoreCount` is set to `false - * @returns The function `remove` returns an array of `BinaryTreeDeletedResult` objects. + * @returns The function `delete` returns an array of `BinaryTreeDeletedResult` objects. */ - override remove(nodeOrKey: N | BinaryTreeNodeKey, ignoreCount = false): BinaryTreeDeletedResult[] { + override delete(nodeOrKey: N | BinaryTreeNodeKey, ignoreCount = false): BinaryTreeDeletedResult[] { const bstDeletedResult: BinaryTreeDeletedResult[] = []; if (!this.root) return bstDeletedResult; @@ -324,7 +324,7 @@ export class TreeMultiset = TreeMultiset const leftSubTreeRightMost = curr.left ? this.getRightMost(curr.left) : null; if (leftSubTreeRightMost) { const parentOfLeftSubTreeMax = leftSubTreeRightMost.parent; - orgCurrent = this.swapLocation(curr, leftSubTreeRightMost); + orgCurrent = this._swap(curr, leftSubTreeRightMost); if (parentOfLeftSubTreeMax) { if (parentOfLeftSubTreeMax.right === leftSubTreeRightMost) { parentOfLeftSubTreeMax.right = leftSubTreeRightMost.left; @@ -515,7 +515,7 @@ export class TreeMultiset = TreeMultiset * @returns The BFSCount() function returns an array of numbers, specifically the count property of each node in the * bfs traversal. */ - BFSCount(): number[] { + bfsCount(): number[] { const nodes = super.bfs('node'); return nodes.map(node => node.count); } @@ -550,23 +550,12 @@ export class TreeMultiset = TreeMultiset * the specified traversal pattern. * @param {'in' | 'pre' | 'post'} [pattern] - The pattern parameter is a string that specifies the traversal order for * the Depth-First Search (dfs) algorithm. It can have three possible values: 'in', 'pre', or 'post'. + * @param loopType - The loopType parameter is a string that specifies the type of loop to use when traversing the * @returns The dfsCountIterative function returns an array of numbers, which represents the count property of each node * in the dfs traversal. */ - dfsCountIterative(pattern: DFSOrderPattern = 'in'): number[] { - const nodes = super.dfsIterative(pattern, 'node'); - return nodes.map(node => node.count); - } - - /** - * The dfsCount function returns an array of counts for each node in a depth-first search traversal. - * @param {DFSOrderPattern} [pattern] - The pattern parameter is an optional parameter that specifies the order in which - * the Depth-First Search (dfs) algorithm should traverse the nodes. It can have one of the following values: - * @returns The dfsCount function returns an array of numbers, specifically the count property of each node in the dfs - * traversal. - */ - dfsCount(pattern: DFSOrderPattern = 'in'): number[] { - const nodes = super.dfs(pattern, 'node'); + dfsCount(pattern: DFSOrderPattern = 'in', loopType: LoopType = LoopType.ITERATIVE): number[] { + const nodes = super.dfs(pattern, 'node', loopType); return nodes.map(node => node.count); } diff --git a/src/data-structures/hash/hash-map.ts b/src/data-structures/hash/hash-map.ts index 7dc52fe..7661bf0 100644 --- a/src/data-structures/hash/hash-map.ts +++ b/src/data-structures/hash/hash-map.ts @@ -157,7 +157,7 @@ export class HashMap { return undefined; } - remove(key: K): void { + delete(key: K): void { const index = this._hash(key); if (!this.table[index]) { return; diff --git a/src/data-structures/hash/hash-table.ts b/src/data-structures/hash/hash-table.ts index 21e38e9..00ac8da 100644 --- a/src/data-structures/hash/hash-table.ts +++ b/src/data-structures/hash/hash-table.ts @@ -213,13 +213,13 @@ export class HashTable { } /** - * The remove function removes a key-value pair from a hash table. + * 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 `remove` method has a return type of `void`, which means it does not return + * @returns Nothing is being returned. The `delete` method has a return type of `void`, which means it does not return * any value. */ - remove(key: K): void { + delete(key: K): void { const index = this._hash(key); let currentNode = this._buckets[index]; let prevNode: HashTableNode | null = null; diff --git a/src/data-structures/heap/heap.ts b/src/data-structures/heap/heap.ts index 8134703..95b16ea 100644 --- a/src/data-structures/heap/heap.ts +++ b/src/data-structures/heap/heap.ts @@ -375,7 +375,7 @@ export class FibonacciHeap { * @protected * @returns FibonacciHeapNode[] - An array containing the nodes of the linked list. */ - consumeLinkedList(head?: FibonacciHeapNode): FibonacciHeapNode[] { + consumeLinkedList(head?: FibonacciHeapNode): FibonacciHeapNode[] { const nodes: FibonacciHeapNode[] = []; if (!head) return nodes; @@ -448,7 +448,10 @@ export class FibonacciHeap { protected consolidate(): void { const A: (FibonacciHeapNode | undefined)[] = new Array(this.size); const nodes = this.consumeLinkedList(this.root); - let x: FibonacciHeapNode | undefined, y: FibonacciHeapNode | undefined, d: number, t: FibonacciHeapNode | undefined; + let x: FibonacciHeapNode | undefined, + y: FibonacciHeapNode | undefined, + d: number, + t: FibonacciHeapNode | undefined; for (const node of nodes) { x = node; diff --git a/src/data-structures/linked-list/skip-linked-list.ts b/src/data-structures/linked-list/skip-linked-list.ts index c1f0ebc..23778eb 100644 --- a/src/data-structures/linked-list/skip-linked-list.ts +++ b/src/data-structures/linked-list/skip-linked-list.ts @@ -130,12 +130,12 @@ export class SkipList { } /** - * The `remove` function removes a node with a specific key from a Skip List data structure. + * The `delete` function removes a node with a specific key from a Skip List data structure. * @param {K} key - The key parameter represents the key of the node that needs to be removed from the skip list. - * @returns The `remove` method returns a boolean value. It returns `true` if the key was successfully removed from the + * @returns The `delete` method returns a boolean value. It returns `true` if the key was successfully removed from the * skip list, and `false` if the key was not found in the skip list. */ - remove(key: K): boolean { + delete(key: K): boolean { const update: SkipListNode[] = new Array(this.maxLevel).fill(this.head); let current = this.head; diff --git a/src/data-structures/queue/deque.ts b/src/data-structures/queue/deque.ts index 7f23c8e..3290ab1 100644 --- a/src/data-structures/queue/deque.ts +++ b/src/data-structures/queue/deque.ts @@ -277,12 +277,12 @@ export class ArrayDeque { } /** - * The remove function removes an element from an array at a specified index. + * The delete function removes an element from an array at a specified index. * @param {number} index - The index parameter specifies the position of the element to be removed from the array. It * is a number that represents the index of the element to be removed. * @returns The method is returning an array containing the removed element. */ - remove(index: number) { + delete(index: number) { return this._nodes.splice(index, 1); } diff --git a/src/data-structures/queue/queue.ts b/src/data-structures/queue/queue.ts index a2f8bb4..4549b31 100644 --- a/src/data-structures/queue/queue.ts +++ b/src/data-structures/queue/queue.ts @@ -106,7 +106,7 @@ export class Queue { if (this.offset * 2 < this.nodes.length) return first; - // only remove dequeued elements when reaching half size + // only delete dequeued elements when reaching half size // to decrease latency of shifting elements. this.nodes = this.nodes.slice(this.offset); this.offset = 0; diff --git a/src/data-structures/trie/trie.ts b/src/data-structures/trie/trie.ts index 9549984..83f71c7 100644 --- a/src/data-structures/trie/trie.ts +++ b/src/data-structures/trie/trie.ts @@ -119,10 +119,10 @@ export class Trie { /** * Remove a word from the Trie structure. - * @param{string} word - The word to remove. + * @param{string} word - The word to delete. * @returns {boolean} True if the word was successfully removed. */ - remove(word: string) { + delete(word: string) { word = this._caseProcess(word); let isDeleted = false; const dfs = (cur: TrieNode, i: number): boolean => { diff --git a/src/interfaces/binary-tree.ts b/src/interfaces/binary-tree.ts index 6f159fb..62a788b 100644 --- a/src/interfaces/binary-tree.ts +++ b/src/interfaces/binary-tree.ts @@ -6,5 +6,5 @@ export interface IBinaryTree> { add(keyOrNode: BinaryTreeNodeKey | N | null, val?: N['val']): N | null | undefined; - remove(nodeOrKey: N | BinaryTreeNodeKey): BinaryTreeDeletedResult[]; + delete(nodeOrKey: N | BinaryTreeNodeKey): BinaryTreeDeletedResult[]; } diff --git a/test/unit/data-structures/binary-tree/avl-tree.test.ts b/test/unit/data-structures/binary-tree/avl-tree.test.ts index a5eb88c..358132a 100644 --- a/test/unit/data-structures/binary-tree/avl-tree.test.ts +++ b/test/unit/data-structures/binary-tree/avl-tree.test.ts @@ -41,56 +41,56 @@ describe('AVL Tree Test', () => { expect(bfs[0].key).toBe(8); expect(bfs[bfs.length - 1].key).toBe(16); - expect(tree.remove(11)[0].deleted?.key).toBe(11); + expect(tree.delete(11)[0].deleted?.key).toBe(11); expect(tree.isAVLBalanced()).toBe(true); expect(node15 && tree.getHeight(node15)).toBe(2); - expect(tree.remove(1)[0].deleted?.key).toBe(1); + expect(tree.delete(1)[0].deleted?.key).toBe(1); expect(tree.isAVLBalanced()).toBe(true); expect(tree.getHeight()).toBe(4); - expect(tree.remove(4)[0].deleted?.key).toBe(4); + expect(tree.delete(4)[0].deleted?.key).toBe(4); expect(tree.isAVLBalanced()).toBe(true); expect(tree.getHeight()).toBe(4); - expect(tree.remove(10)[0].deleted?.key).toBe(10); + expect(tree.delete(10)[0].deleted?.key).toBe(10); expect(tree.isAVLBalanced()).toBe(true); expect(tree.getHeight()).toBe(3); - expect(tree.remove(15)[0].deleted?.key).toBe(15); + expect(tree.delete(15)[0].deleted?.key).toBe(15); expect(tree.isAVLBalanced()).toBe(true); expect(tree.getHeight()).toBe(3); - expect(tree.remove(5)[0].deleted?.key).toBe(5); + expect(tree.delete(5)[0].deleted?.key).toBe(5); expect(tree.isAVLBalanced()).toBe(true); expect(tree.getHeight()).toBe(3); - expect(tree.remove(13)[0].deleted?.key).toBe(13); + expect(tree.delete(13)[0].deleted?.key).toBe(13); expect(tree.isAVLBalanced()).toBe(true); expect(tree.getHeight()).toBe(3); - expect(tree.remove(3)[0].deleted?.key).toBe(3); + expect(tree.delete(3)[0].deleted?.key).toBe(3); expect(tree.isAVLBalanced()).toBe(true); expect(tree.getHeight()).toBe(3); - expect(tree.remove(8)[0].deleted?.key).toBe(8); + expect(tree.delete(8)[0].deleted?.key).toBe(8); expect(tree.isAVLBalanced()).toBe(true); expect(tree.getHeight()).toBe(3); - expect(tree.remove(6)[0].deleted?.key).toBe(6); - expect(tree.remove(6).length).toBe(0); + expect(tree.delete(6)[0].deleted?.key).toBe(6); + expect(tree.delete(6).length).toBe(0); expect(tree.isAVLBalanced()).toBe(true); expect(tree.getHeight()).toBe(2); - expect(tree.remove(7)[0].deleted?.key).toBe(7); + expect(tree.delete(7)[0].deleted?.key).toBe(7); expect(tree.isAVLBalanced()).toBe(true); expect(tree.getHeight()).toBe(2); - expect(tree.remove(9)[0].deleted?.key).toBe(9); + expect(tree.delete(9)[0].deleted?.key).toBe(9); expect(tree.isAVLBalanced()).toBe(true); expect(tree.getHeight()).toBe(2); - expect(tree.remove(14)[0].deleted?.key).toBe(14); + expect(tree.delete(14)[0].deleted?.key).toBe(14); expect(tree.isAVLBalanced()).toBe(true); expect(tree.getHeight()).toBe(1); diff --git a/test/unit/data-structures/binary-tree/binary-tree.test.ts b/test/unit/data-structures/binary-tree/binary-tree.test.ts index ab16be2..4574a9e 100644 --- a/test/unit/data-structures/binary-tree/binary-tree.test.ts +++ b/test/unit/data-structures/binary-tree/binary-tree.test.ts @@ -83,12 +83,12 @@ describe('BinaryTree', () => { expect(binaryTree.size).toBe(1); }); - test('should remove a node', () => { + test('should delete a node', () => { const node = binaryTree.add(1); expect(binaryTree.size).toBe(1); if (node) { - const result = binaryTree.remove(node); + const result = binaryTree.delete(node); expect(result).toHaveLength(1); expect(binaryTree.size).toBe(0); } diff --git a/test/unit/data-structures/binary-tree/bst.test.ts b/test/unit/data-structures/binary-tree/bst.test.ts index 84ac377..bd5d06f 100644 --- a/test/unit/data-structures/binary-tree/bst.test.ts +++ b/test/unit/data-structures/binary-tree/bst.test.ts @@ -55,7 +55,7 @@ describe('BST operations test', () => { expect(bfsNodesAfterBalanced[0].key).toBe(8); expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16); - const removed11 = bst.remove(11); + const removed11 = bst.delete(11); expect(removed11).toBeInstanceOf(Array); expect(removed11[0]).toBeDefined(); expect(removed11[0].deleted).toBeDefined(); @@ -66,7 +66,7 @@ describe('BST operations test', () => { expect(bst.getHeight(15)).toBe(1); - const removed1 = bst.remove(1); + const removed1 = bst.delete(1); expect(removed1).toBeInstanceOf(Array); expect(removed1[0]).toBeDefined(); expect(removed1[0].deleted).toBeDefined(); @@ -76,7 +76,7 @@ describe('BST operations test', () => { expect(bst.getHeight()).toBe(4); - const removed4 = bst.remove(4); + const removed4 = bst.delete(4); expect(removed4).toBeInstanceOf(Array); expect(removed4[0]).toBeDefined(); expect(removed4[0].deleted).toBeDefined(); @@ -84,7 +84,7 @@ describe('BST operations test', () => { expect(bst.isAVLBalanced()).toBe(true); expect(bst.getHeight()).toBe(4); - const removed10 = bst.remove(10); + const removed10 = bst.delete(10); expect(removed10).toBeInstanceOf(Array); expect(removed10[0]).toBeDefined(); expect(removed10[0].deleted).toBeDefined(); @@ -92,7 +92,7 @@ describe('BST operations test', () => { expect(bst.isAVLBalanced()).toBe(false); expect(bst.getHeight()).toBe(4); - const removed15 = bst.remove(15); + const removed15 = bst.delete(15); expect(removed15).toBeInstanceOf(Array); expect(removed15[0]).toBeDefined(); expect(removed15[0].deleted).toBeDefined(); @@ -101,7 +101,7 @@ describe('BST operations test', () => { expect(bst.isAVLBalanced()).toBe(true); expect(bst.getHeight()).toBe(3); - const removed5 = bst.remove(5); + const removed5 = bst.delete(5); expect(removed5).toBeInstanceOf(Array); expect(removed5[0]).toBeDefined(); expect(removed5[0].deleted).toBeDefined(); @@ -110,7 +110,7 @@ describe('BST operations test', () => { expect(bst.isAVLBalanced()).toBe(true); expect(bst.getHeight()).toBe(3); - const removed13 = bst.remove(13); + const removed13 = bst.delete(13); expect(removed13).toBeInstanceOf(Array); expect(removed13[0]).toBeDefined(); expect(removed13[0].deleted).toBeDefined(); @@ -118,7 +118,7 @@ describe('BST operations test', () => { expect(bst.isAVLBalanced()).toBe(true); expect(bst.getHeight()).toBe(3); - const removed3 = bst.remove(3); + const removed3 = bst.delete(3); expect(removed3).toBeInstanceOf(Array); expect(removed3[0]).toBeDefined(); expect(removed3[0].deleted).toBeDefined(); @@ -126,7 +126,7 @@ describe('BST operations test', () => { expect(bst.isAVLBalanced()).toBe(false); expect(bst.getHeight()).toBe(3); - const removed8 = bst.remove(8); + const removed8 = bst.delete(8); expect(removed8).toBeInstanceOf(Array); expect(removed8[0]).toBeDefined(); expect(removed8[0].deleted).toBeDefined(); @@ -134,16 +134,16 @@ describe('BST operations test', () => { expect(bst.isAVLBalanced()).toBe(true); expect(bst.getHeight()).toBe(3); - const removed6 = bst.remove(6); + const removed6 = bst.delete(6); expect(removed6).toBeInstanceOf(Array); expect(removed6[0]).toBeDefined(); expect(removed6[0].deleted).toBeDefined(); if (removed6[0].deleted) expect(removed6[0].deleted.key).toBe(6); - expect(bst.remove(6).length).toBe(0); + expect(bst.delete(6).length).toBe(0); expect(bst.isAVLBalanced()).toBe(false); expect(bst.getHeight()).toBe(3); - const removed7 = bst.remove(7); + const removed7 = bst.delete(7); expect(removed7).toBeInstanceOf(Array); expect(removed7[0]).toBeDefined(); expect(removed7[0].deleted).toBeDefined(); @@ -151,7 +151,7 @@ describe('BST operations test', () => { expect(bst.isAVLBalanced()).toBe(false); expect(bst.getHeight()).toBe(3); - const removed9 = bst.remove(9); + const removed9 = bst.delete(9); expect(removed9).toBeInstanceOf(Array); expect(removed9[0]).toBeDefined(); expect(removed9[0].deleted).toBeDefined(); @@ -159,7 +159,7 @@ describe('BST operations test', () => { expect(bst.isAVLBalanced()).toBe(false); expect(bst.getHeight()).toBe(3); - const removed14 = bst.remove(14); + const removed14 = bst.delete(14); expect(removed14).toBeInstanceOf(Array); expect(removed14[0]).toBeDefined(); expect(removed14[0].deleted).toBeDefined(); @@ -253,7 +253,7 @@ describe('BST operations test', () => { expect(bfsNodesAfterBalanced[0].key).toBe(8); expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16); - const removed11 = objBST.remove(11); + const removed11 = objBST.delete(11); expect(removed11).toBeInstanceOf(Array); expect(removed11[0]).toBeDefined(); expect(removed11[0].deleted).toBeDefined(); @@ -264,7 +264,7 @@ describe('BST operations test', () => { expect(node15 && objBST.getHeight(node15)).toBe(2); - const removed1 = objBST.remove(1); + const removed1 = objBST.delete(1); expect(removed1).toBeInstanceOf(Array); expect(removed1[0]).toBeDefined(); expect(removed1[0].deleted).toBeDefined(); @@ -274,7 +274,7 @@ describe('BST operations test', () => { expect(objBST.getHeight()).toBe(4); - const removed4 = objBST.remove(4); + const removed4 = objBST.delete(4); expect(removed4).toBeInstanceOf(Array); expect(removed4[0]).toBeDefined(); expect(removed4[0].deleted).toBeDefined(); @@ -282,7 +282,7 @@ describe('BST operations test', () => { expect(objBST.isAVLBalanced()).toBe(true); expect(objBST.getHeight()).toBe(4); - const removed10 = objBST.remove(10); + const removed10 = objBST.delete(10); expect(removed10).toBeInstanceOf(Array); expect(removed10[0]).toBeDefined(); expect(removed10[0].deleted).toBeDefined(); @@ -290,7 +290,7 @@ describe('BST operations test', () => { expect(objBST.isAVLBalanced()).toBe(false); expect(objBST.getHeight()).toBe(4); - const removed15 = objBST.remove(15); + const removed15 = objBST.delete(15); expect(removed15).toBeInstanceOf(Array); expect(removed15[0]).toBeDefined(); expect(removed15[0].deleted).toBeDefined(); @@ -299,7 +299,7 @@ describe('BST operations test', () => { expect(objBST.isAVLBalanced()).toBe(true); expect(objBST.getHeight()).toBe(3); - const removed5 = objBST.remove(5); + const removed5 = objBST.delete(5); expect(removed5).toBeInstanceOf(Array); expect(removed5[0]).toBeDefined(); expect(removed5[0].deleted).toBeDefined(); @@ -308,7 +308,7 @@ describe('BST operations test', () => { expect(objBST.isAVLBalanced()).toBe(true); expect(objBST.getHeight()).toBe(3); - const removed13 = objBST.remove(13); + const removed13 = objBST.delete(13); expect(removed13).toBeInstanceOf(Array); expect(removed13[0]).toBeDefined(); expect(removed13[0].deleted).toBeDefined(); @@ -316,7 +316,7 @@ describe('BST operations test', () => { expect(objBST.isAVLBalanced()).toBe(true); expect(objBST.getHeight()).toBe(3); - const removed3 = objBST.remove(3); + const removed3 = objBST.delete(3); expect(removed3).toBeInstanceOf(Array); expect(removed3[0]).toBeDefined(); expect(removed3[0].deleted).toBeDefined(); @@ -324,7 +324,7 @@ describe('BST operations test', () => { expect(objBST.isAVLBalanced()).toBe(false); expect(objBST.getHeight()).toBe(3); - const removed8 = objBST.remove(8); + const removed8 = objBST.delete(8); expect(removed8).toBeInstanceOf(Array); expect(removed8[0]).toBeDefined(); expect(removed8[0].deleted).toBeDefined(); @@ -332,16 +332,16 @@ describe('BST operations test', () => { expect(objBST.isAVLBalanced()).toBe(true); expect(objBST.getHeight()).toBe(3); - const removed6 = objBST.remove(6); + const removed6 = objBST.delete(6); expect(removed6).toBeInstanceOf(Array); expect(removed6[0]).toBeDefined(); expect(removed6[0].deleted).toBeDefined(); if (removed6[0].deleted) expect(removed6[0].deleted.key).toBe(6); - expect(objBST.remove(6).length).toBe(0); + expect(objBST.delete(6).length).toBe(0); expect(objBST.isAVLBalanced()).toBe(false); expect(objBST.getHeight()).toBe(3); - const removed7 = objBST.remove(7); + const removed7 = objBST.delete(7); expect(removed7).toBeInstanceOf(Array); expect(removed7[0]).toBeDefined(); expect(removed7[0].deleted).toBeDefined(); @@ -349,7 +349,7 @@ describe('BST operations test', () => { expect(objBST.isAVLBalanced()).toBe(false); expect(objBST.getHeight()).toBe(3); - const removed9 = objBST.remove(9); + const removed9 = objBST.delete(9); expect(removed9).toBeInstanceOf(Array); expect(removed9[0]).toBeDefined(); expect(removed9[0].deleted).toBeDefined(); @@ -357,7 +357,7 @@ describe('BST operations test', () => { expect(objBST.isAVLBalanced()).toBe(false); expect(objBST.getHeight()).toBe(3); - const removed14 = objBST.remove(14); + const removed14 = objBST.delete(14); expect(removed14).toBeInstanceOf(Array); expect(removed14[0]).toBeDefined(); expect(removed14[0].deleted).toBeDefined(); diff --git a/test/unit/data-structures/binary-tree/overall.test.ts b/test/unit/data-structures/binary-tree/overall.test.ts index 206a071..9fd298b 100644 --- a/test/unit/data-structures/binary-tree/overall.test.ts +++ b/test/unit/data-structures/binary-tree/overall.test.ts @@ -19,7 +19,7 @@ describe('Overall BinaryTree Test', () => { const leftMost = bst.getLeftMost(); leftMost?.key === 1; // true expect(leftMost?.key).toBe(1); - bst.remove(6); + bst.delete(6); bst.get(6); // null expect(bst.get(6)).toBeNull(); bst.isAVLBalanced(); // true or false @@ -52,13 +52,13 @@ describe('Overall BinaryTree Test', () => { ] ); - objBST.remove(11); + objBST.delete(11); const avlTree = new AVLTree(); avlTree.addMany([11, 3, 15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5]); avlTree.isAVLBalanced(); // true expect(avlTree.isAVLBalanced()).toBe(true); // true - avlTree.remove(10); + avlTree.delete(10); avlTree.isAVLBalanced(); // true expect(avlTree.isAVLBalanced()).toBe(true); // true }); diff --git a/test/unit/data-structures/binary-tree/rb-tree.test.ts b/test/unit/data-structures/binary-tree/rb-tree.test.ts index 55899bd..1d3a5ac 100644 --- a/test/unit/data-structures/binary-tree/rb-tree.test.ts +++ b/test/unit/data-structures/binary-tree/rb-tree.test.ts @@ -31,7 +31,7 @@ describe('Red-Black Tree Tests', () => { // tree.add(8); // // // Delete a node (e.g., 3) and check if it's gone - // tree.remove(3); + // tree.delete(3); // expect(tree.has(3)).toBe(false); // // // Perform in-order traversal to check if the tree is still balanced diff --git a/test/unit/data-structures/binary-tree/tree-multiset.test.ts b/test/unit/data-structures/binary-tree/tree-multiset.test.ts index 8b926c3..c2eb7a6 100644 --- a/test/unit/data-structures/binary-tree/tree-multiset.test.ts +++ b/test/unit/data-structures/binary-tree/tree-multiset.test.ts @@ -70,7 +70,7 @@ describe('TreeMultiset operations test', () => { expect(bfsNodesAfterBalanced[0].key).toBe(8); expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16); - const removed11 = treeMultiset.remove(11, true); + const removed11 = treeMultiset.delete(11, true); expect(removed11 instanceof Array); expect(removed11[0]); expect(removed11[0].deleted); @@ -81,7 +81,7 @@ describe('TreeMultiset operations test', () => { expect(treeMultiset.getHeight(15)).toBe(1); - const removed1 = treeMultiset.remove(1, true); + const removed1 = treeMultiset.delete(1, true); expect(removed1 instanceof Array); expect(removed1[0]); expect(removed1[0].deleted); @@ -91,7 +91,7 @@ describe('TreeMultiset operations test', () => { expect(treeMultiset.getHeight()).toBe(4); - const removed4 = treeMultiset.remove(4, true); + const removed4 = treeMultiset.delete(4, true); expect(removed4 instanceof Array); expect(removed4[0]); expect(removed4[0].deleted); @@ -100,7 +100,7 @@ describe('TreeMultiset operations test', () => { expect(treeMultiset.isAVLBalanced()).toBe(true); expect(treeMultiset.getHeight()).toBe(4); - const removed10 = treeMultiset.remove(10, true); + const removed10 = treeMultiset.delete(10, true); expect(removed10 instanceof Array); expect(removed10[0]); expect(removed10[0].deleted); @@ -109,7 +109,7 @@ describe('TreeMultiset operations test', () => { expect(treeMultiset.getHeight()).toBe(3); - const removed15 = treeMultiset.remove(15, true); + const removed15 = treeMultiset.delete(15, true); expect(removed15 instanceof Array); expect(removed15[0]); expect(removed15[0].deleted); @@ -118,7 +118,7 @@ describe('TreeMultiset operations test', () => { expect(treeMultiset.isAVLBalanced()).toBe(true); expect(treeMultiset.getHeight()).toBe(3); - const removed5 = treeMultiset.remove(5, true); + const removed5 = treeMultiset.delete(5, true); expect(removed5 instanceof Array); expect(removed5[0]); expect(removed5[0].deleted); @@ -127,7 +127,7 @@ describe('TreeMultiset operations test', () => { expect(treeMultiset.isAVLBalanced()).toBe(true); expect(treeMultiset.getHeight()).toBe(3); - const removed13 = treeMultiset.remove(13, true); + const removed13 = treeMultiset.delete(13, true); expect(removed13 instanceof Array); expect(removed13[0]); expect(removed13[0].deleted); @@ -135,7 +135,7 @@ describe('TreeMultiset operations test', () => { expect(treeMultiset.isAVLBalanced()).toBe(true); expect(treeMultiset.getHeight()).toBe(3); - const removed3 = treeMultiset.remove(3, true); + const removed3 = treeMultiset.delete(3, true); expect(removed3 instanceof Array); expect(removed3[0]); expect(removed3[0].deleted); @@ -143,7 +143,7 @@ describe('TreeMultiset operations test', () => { expect(treeMultiset.isAVLBalanced()).toBe(true); expect(treeMultiset.getHeight()).toBe(3); - const removed8 = treeMultiset.remove(8, true); + const removed8 = treeMultiset.delete(8, true); expect(removed8 instanceof Array); expect(removed8[0]); expect(removed8[0].deleted); @@ -151,17 +151,17 @@ describe('TreeMultiset operations test', () => { expect(treeMultiset.isAVLBalanced()).toBe(true); expect(treeMultiset.getHeight()).toBe(3); - const removed6 = treeMultiset.remove(6, true); + const removed6 = treeMultiset.delete(6, true); expect(removed6 instanceof Array); expect(removed6[0]); expect(removed6[0].deleted); if (removed6[0].deleted) expect(removed6[0].deleted.key).toBe(6); - expect(treeMultiset.remove(6, true).length).toBe(0); + expect(treeMultiset.delete(6, true).length).toBe(0); expect(treeMultiset.isAVLBalanced()).toBe(true); expect(treeMultiset.getHeight()).toBe(2); - const removed7 = treeMultiset.remove(7, true); + const removed7 = treeMultiset.delete(7, true); expect(removed7 instanceof Array); expect(removed7[0]); expect(removed7[0].deleted); @@ -169,7 +169,7 @@ describe('TreeMultiset operations test', () => { expect(treeMultiset.isAVLBalanced()).toBe(true); expect(treeMultiset.getHeight()).toBe(2); - const removed9 = treeMultiset.remove(9, true); + const removed9 = treeMultiset.delete(9, true); expect(removed9 instanceof Array); expect(removed9[0]); expect(removed9[0].deleted); @@ -177,7 +177,7 @@ describe('TreeMultiset operations test', () => { expect(treeMultiset.isAVLBalanced()).toBe(true); expect(treeMultiset.getHeight()).toBe(2); - const removed14 = treeMultiset.remove(14, true); + const removed14 = treeMultiset.delete(14, true); expect(removed14 instanceof Array); expect(removed14[0]); expect(removed14[0].deleted); @@ -288,7 +288,7 @@ describe('TreeMultiset operations test', () => { // expect(bfsNodesAfterBalanced[0].key).toBe(8); // expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16); // - // const removed11 = objTreeMultiset.remove(11, true); + // const removed11 = objTreeMultiset.delete(11, true); // expect(removed11).toBeInstanceOf(Array); // expect(removed11[0]).toBeDefined(); // expect(removed11[0].deleted).toBeDefined(); @@ -299,7 +299,7 @@ describe('TreeMultiset operations test', () => { // // expect(node15 && objTreeMultiset.getHeight(node15)).toBe(2); // - // const removed1 = objTreeMultiset.remove(1, true); + // const removed1 = objTreeMultiset.delete(1, true); // expect(removed1).toBeInstanceOf(Array); // expect(removed1[0]).toBeDefined(); // expect(removed1[0].deleted).toBeDefined(); @@ -309,7 +309,7 @@ describe('TreeMultiset operations test', () => { // // expect(objTreeMultiset.getHeight()).toBe(4); // - // const removed4 = objTreeMultiset.remove(4, true); + // const removed4 = objTreeMultiset.delete(4, true); // expect(removed4).toBeInstanceOf(Array); // expect(removed4[0]).toBeDefined(); // expect(removed4[0].deleted).toBeDefined(); @@ -317,7 +317,7 @@ describe('TreeMultiset operations test', () => { // expect(objTreeMultiset.isAVLBalanced()).toBe(true); // expect(objTreeMultiset.getHeight()).toBe(4); // - // const removed10 = objTreeMultiset.remove(10, true); + // const removed10 = objTreeMultiset.delete(10, true); // expect(removed10).toBeInstanceOf(Array); // expect(removed10[0]).toBeDefined(); // expect(removed10[0].deleted).toBeDefined(); @@ -325,7 +325,7 @@ describe('TreeMultiset operations test', () => { // expect(objTreeMultiset.isAVLBalanced()).toBe(false); // expect(objTreeMultiset.getHeight()).toBe(4); // - // const removed15 = objTreeMultiset.remove(15, true); + // const removed15 = objTreeMultiset.delete(15, true); // expect(removed15).toBeInstanceOf(Array); // expect(removed15[0]).toBeDefined(); // expect(removed15[0].deleted).toBeDefined(); @@ -334,7 +334,7 @@ describe('TreeMultiset operations test', () => { // expect(objTreeMultiset.isAVLBalanced()).toBe(true); // expect(objTreeMultiset.getHeight()).toBe(3); // - // const removed5 = objTreeMultiset.remove(5, true); + // const removed5 = objTreeMultiset.delete(5, true); // expect(removed5).toBeInstanceOf(Array); // expect(removed5[0]).toBeDefined(); // expect(removed5[0].deleted).toBeDefined(); @@ -343,7 +343,7 @@ describe('TreeMultiset operations test', () => { // expect(objTreeMultiset.isAVLBalanced()).toBe(true); // expect(objTreeMultiset.getHeight()).toBe(3); // - // const removed13 = objTreeMultiset.remove(13, true); + // const removed13 = objTreeMultiset.delete(13, true); // expect(removed13).toBeInstanceOf(Array); // expect(removed13[0]).toBeDefined(); // expect(removed13[0].deleted).toBeDefined(); @@ -351,7 +351,7 @@ describe('TreeMultiset operations test', () => { // expect(objTreeMultiset.isAVLBalanced()).toBe(true); // expect(objTreeMultiset.getHeight()).toBe(3); // - // const removed3 = objTreeMultiset.remove(3, true); + // const removed3 = objTreeMultiset.delete(3, true); // expect(removed3).toBeInstanceOf(Array); // expect(removed3[0]).toBeDefined(); // expect(removed3[0].deleted).toBeDefined(); @@ -359,7 +359,7 @@ describe('TreeMultiset operations test', () => { // expect(objTreeMultiset.isAVLBalanced()).toBe(false); // expect(objTreeMultiset.getHeight()).toBe(3); // - // const removed8 = objTreeMultiset.remove(8, true); + // const removed8 = objTreeMultiset.delete(8, true); // expect(removed8).toBeInstanceOf(Array); // expect(removed8[0]).toBeDefined(); // expect(removed8[0].deleted).toBeDefined(); @@ -367,16 +367,16 @@ describe('TreeMultiset operations test', () => { // expect(objTreeMultiset.isAVLBalanced()).toBe(true); // expect(objTreeMultiset.getHeight()).toBe(3); // - // const removed6 = objTreeMultiset.remove(6, true); + // const removed6 = objTreeMultiset.delete(6, true); // expect(removed6).toBeInstanceOf(Array); // expect(removed6[0]).toBeDefined(); // expect(removed6[0].deleted).toBeDefined(); // if (removed6[0].deleted) expect(removed6[0].deleted.key).toBe(6); - // expect(objTreeMultiset.remove(6, true).length).toBe(0); + // expect(objTreeMultiset.delete(6, true).length).toBe(0); // expect(objTreeMultiset.isAVLBalanced()).toBe(false); // expect(objTreeMultiset.getHeight()).toBe(3); // - // const removed7 = objTreeMultiset.remove(7, true); + // const removed7 = objTreeMultiset.delete(7, true); // expect(removed7).toBeInstanceOf(Array); // expect(removed7[0]).toBeDefined(); // expect(removed7[0].deleted).toBeDefined(); @@ -384,7 +384,7 @@ describe('TreeMultiset operations test', () => { // expect(objTreeMultiset.isAVLBalanced()).toBe(false); // expect(objTreeMultiset.getHeight()).toBe(3); // - // const removed9 = objTreeMultiset.remove(9, true); + // const removed9 = objTreeMultiset.delete(9, true); // expect(removed9).toBeInstanceOf(Array); // expect(removed9[0]).toBeDefined(); // expect(removed9[0].deleted).toBeDefined(); @@ -392,7 +392,7 @@ describe('TreeMultiset operations test', () => { // expect(objTreeMultiset.isAVLBalanced()).toBe(false); // expect(objTreeMultiset.getHeight()).toBe(3); // - // const removed14 = objTreeMultiset.remove(14, true); + // const removed14 = objTreeMultiset.delete(14, true); // expect(removed14).toBeInstanceOf(Array); // expect(removed14[0]).toBeDefined(); // expect(removed14[0].deleted).toBeDefined(); diff --git a/test/unit/data-structures/graph/directed-graph.test.ts b/test/unit/data-structures/graph/directed-graph.test.ts index ce89d66..e942041 100644 --- a/test/unit/data-structures/graph/directed-graph.test.ts +++ b/test/unit/data-structures/graph/directed-graph.test.ts @@ -31,7 +31,7 @@ describe('DirectedGraph Operation Test', () => { expect(graph.hasEdge('B', 'A')).toBe(false); }); - it('should remove edges', () => { + it('should delete edges', () => { const vertex1 = new DirectedVertex('A'); const vertex2 = new DirectedVertex('B'); const edge = new DirectedEdge('A', 'B'); diff --git a/test/unit/data-structures/graph/undirected-graph.test.ts b/test/unit/data-structures/graph/undirected-graph.test.ts index 4ea9cf7..3d0eb6e 100644 --- a/test/unit/data-structures/graph/undirected-graph.test.ts +++ b/test/unit/data-structures/graph/undirected-graph.test.ts @@ -31,7 +31,7 @@ describe('UndirectedGraph Operation Test', () => { expect(graph.hasEdge('B', 'A')).toBe(true); }); - it('should remove edges', () => { + it('should delete edges', () => { const vertex1 = new UndirectedVertex('A'); const vertex2 = new UndirectedVertex('B'); const edge = new UndirectedEdge('A', 'B'); diff --git a/test/unit/data-structures/hash/hash-map.test.ts b/test/unit/data-structures/hash/hash-map.test.ts index bb18770..6cb66e2 100644 --- a/test/unit/data-structures/hash/hash-map.test.ts +++ b/test/unit/data-structures/hash/hash-map.test.ts @@ -36,11 +36,11 @@ describe('HashMap', () => { expect(hashMap.get('key2')).toBe(2); }); - it('should remove values', () => { + it('should delete values', () => { hashMap.set('one', 1); hashMap.set('two', 2); - hashMap.remove('one'); + hashMap.delete('one'); expect(hashMap.get('one')).toBeUndefined(); expect(hashMap.size).toBe(1); }); diff --git a/test/unit/data-structures/hash/hash-table.test.ts b/test/unit/data-structures/hash/hash-table.test.ts index 2c252d6..bf77d1a 100644 --- a/test/unit/data-structures/hash/hash-table.test.ts +++ b/test/unit/data-structures/hash/hash-table.test.ts @@ -81,13 +81,13 @@ describe('HashTable', () => { expect(retrievedValue).toBeUndefined(); }); - it('should remove key-value pair correctly', () => { + it('should delete key-value pair correctly', () => { const hashTable = new HashTable(); const key = 'testKey'; const value = 'testValue'; hashTable.set(key, value); - hashTable.remove(key); + hashTable.delete(key); const retrievedValue = hashTable.get(key); @@ -128,10 +128,10 @@ describe('HashTable', () => { expect(hashTable.get('two')).toBe(2); }); - it('should remove values correctly', () => { + it('should delete values correctly', () => { hashTable.set('one', 1); hashTable.set('two', 2); - hashTable.remove('one'); + hashTable.delete('one'); expect(hashTable.get('one')).toBeUndefined(); expect(hashTable.get('two')).toBe(2); @@ -139,7 +139,7 @@ describe('HashTable', () => { it('should handle non-existent keys correctly', () => { expect(hashTable.get('non-existent')).toBeUndefined(); - hashTable.remove('non-existent'); // Removing a non-existent key should not cause errors + hashTable.delete('non-existent'); // Removing a non-existent key should not cause errors }); it('should handle custom hash function correctly', () => { diff --git a/test/unit/data-structures/heap/heap.test.ts b/test/unit/data-structures/heap/heap.test.ts index 5c3f3c3..8745402 100644 --- a/test/unit/data-structures/heap/heap.test.ts +++ b/test/unit/data-structures/heap/heap.test.ts @@ -1,5 +1,5 @@ import {FibonacciHeap, MaxHeap, MinHeap} from '../../../../src'; -import {logBigOMetricsWrap} from "../../../utils"; +import {logBigOMetricsWrap} from '../../../utils'; describe('Heap Operation Test', () => { it('should numeric heap work well', function () { @@ -201,10 +201,8 @@ describe('FibonacciHeap', () => { }); }); - describe('FibonacciHeap Stress Test', () => { it('should handle a large number of elements efficiently', () => { - const testByMagnitude = (magnitude: number) => { const heap = new FibonacciHeap(); @@ -229,7 +227,7 @@ describe('FibonacciHeap Stress Test', () => { // Verify that the heap is now empty expect(heap.size).toBe(0); - } + }; testByMagnitude(1000); @@ -238,13 +236,18 @@ describe('FibonacciHeap Stress Test', () => { // 150000, 200000, 250000, 300000, 400000, 500000, 600000, 700000, 800000, 900000, 1000000 // ].forEach(m => logBigOMetricsWrap(testByMagnitude, [m])); [ - 10, 100, 1000, 5000, 10000, 20000, 50000, 75000, 100000, - 150000, 200000, 250000, 300000, 400000, 500000, 600000, 700000, 800000, 900000, 1000000 - ].forEach(m => logBigOMetricsWrap((c: number) => { - const result: number[] = []; - for (let i = 0; i < c; i++) result.push(i); - return result; - } , [m], 'loopPush')); - + 10, 100, 1000, 5000, 10000, 20000, 50000, 75000, 100000, 150000, 200000, 250000, 300000, 400000, 500000, 600000, + 700000, 800000, 900000, 1000000 + ].forEach(m => + logBigOMetricsWrap( + (c: number) => { + const result: number[] = []; + for (let i = 0; i < c; i++) result.push(i); + return result; + }, + [m], + 'loopPush' + ) + ); }); }); diff --git a/test/unit/data-structures/linked-list/singly-linked-list.test.ts b/test/unit/data-structures/linked-list/singly-linked-list.test.ts index fd0d696..74a3de8 100644 --- a/test/unit/data-structures/linked-list/singly-linked-list.test.ts +++ b/test/unit/data-structures/linked-list/singly-linked-list.test.ts @@ -18,7 +18,7 @@ describe('SinglyLinkedList Operation Test', () => { }); describe('pop', () => { - it('should remove and return the last element of the list', () => { + it('should delete and return the last element of the list', () => { list.push(1); list.push(2); const popped = list.pop(); @@ -33,7 +33,7 @@ describe('SinglyLinkedList Operation Test', () => { }); describe('shift', () => { - it('should remove and return the first element of the list', () => { + it('should delete and return the first element of the list', () => { list.push(1); list.push(2); const shifted = list.shift(); @@ -109,7 +109,7 @@ describe('SinglyLinkedList Operation Test', () => { }); describe('removeValue', () => { - it('should remove the first occurrence of a value from the list', () => { + it('should delete the first occurrence of a value from the list', () => { list.push(1); list.push(2); list.push(3); @@ -240,8 +240,8 @@ describe('SinglyLinkedList Operation Test', () => { }); }); - describe('remove', () => { - it('should remove and return the element at the specified index', () => { + describe('delete', () => { + it('should delete and return the element at the specified index', () => { list.push(1); list.push(2); list.push(3); @@ -256,7 +256,7 @@ describe('SinglyLinkedList Operation Test', () => { expect(removed).toBeUndefined(); }); - it('should remove and return the first element', () => { + it('should delete and return the first element', () => { list.push(1); list.push(2); const removed = list.deleteAt(0); @@ -264,7 +264,7 @@ describe('SinglyLinkedList Operation Test', () => { expect(list.toArray()).toEqual([2]); }); - it('should remove and return the last element', () => { + it('should delete and return the last element', () => { list.push(1); list.push(2); const removed = list.deleteAt(1); 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 442d6bd..24c041e 100644 --- a/test/unit/data-structures/linked-list/skip-list.test.ts +++ b/test/unit/data-structures/linked-list/skip-list.test.ts @@ -25,12 +25,12 @@ describe('SkipList', () => { expect(skipList.get(0)).toBeUndefined(); }); - it('should remove elements correctly', () => { + it('should delete elements correctly', () => { skipList.add(1, 'One'); skipList.add(2, 'Two'); skipList.add(3, 'Three'); - skipList.remove(2); + skipList.delete(2); expect(skipList.get(2)).toBeUndefined(); // 修改这里的断言 }); diff --git a/test/unit/data-structures/priority-queue/max-priority-queue.test.ts b/test/unit/data-structures/priority-queue/max-priority-queue.test.ts index 1e75f15..ff486cd 100644 --- a/test/unit/data-structures/priority-queue/max-priority-queue.test.ts +++ b/test/unit/data-structures/priority-queue/max-priority-queue.test.ts @@ -27,7 +27,7 @@ describe('MaxPriorityQueue Operation Test', () => { expect(priorityQueue.poll()?.keyA).toBe(1); }); - it('should return and remove the smallest element', () => { + it('should return and delete the smallest element', () => { const priorityQueue = new MaxPriorityQueue(); priorityQueue.add(5); priorityQueue.add(3); diff --git a/test/unit/data-structures/queue/deque.test.ts b/test/unit/data-structures/queue/deque.test.ts index 04e4882..6fabba0 100644 --- a/test/unit/data-structures/queue/deque.test.ts +++ b/test/unit/data-structures/queue/deque.test.ts @@ -16,7 +16,7 @@ describe('Deque Tests', () => { expect(deque.peekLast()).toBe(2); }); - it('should remove elements from the beginning and end', () => { + it('should delete elements from the beginning and end', () => { deque.addFirst(1); deque.addLast(2); deque.pollFirst(); @@ -69,7 +69,7 @@ describe('Deque Tests', () => { expect(objectDeque.peekLast()).toBe('two'); }); - it('should remove elements from the beginning and end', () => { + it('should delete elements from the beginning and end', () => { objectDeque.addFirst('one'); objectDeque.addLast('two'); objectDeque.pollFirst(); @@ -106,7 +106,7 @@ describe('Deque Tests', () => { expect(arrayDeque.peekLast()).toBe(2); }); - it('should remove elements from the beginning and end', () => { + it('should delete elements from the beginning and end', () => { arrayDeque.addFirst(1); arrayDeque.addLast(2); arrayDeque.pollFirst(); diff --git a/test/unit/data-structures/trie/trie.test.ts b/test/unit/data-structures/trie/trie.test.ts index edeaec8..4034adf 100644 --- a/test/unit/data-structures/trie/trie.test.ts +++ b/test/unit/data-structures/trie/trie.test.ts @@ -81,15 +81,15 @@ describe('Trie', () => { expect(words).toEqual(['apple', 'application', 'app']); }); - it('should remove words from Trie', () => { + it('should delete words from Trie', () => { const trie = new Trie(); trie.add('apple'); trie.add('app'); expect(trie.has('apple')).toBe(true); - trie.remove('apple'); + trie.delete('apple'); expect(trie.has('apple')).toBe(false); expect(trie.has('app')).toBe(true); - trie.remove('app'); + trie.delete('app'); expect(trie.has('app')).toBe(false); }); @@ -772,9 +772,9 @@ describe('Trie operations', () => { test('Remove Words', () => { trie.add('apple'); trie.add('banana'); - expect(trie.remove('apple')).toBe(true); + expect(trie.delete('apple')).toBe(true); expect(trie.has('apple')).toBe(false); - expect(trie.remove('cherry')).toBe(false); + expect(trie.delete('cherry')).toBe(false); }); test('Case Sensitivity', () => { diff --git a/test/utils/big-o.ts b/test/utils/big-o.ts index 755bdb1..9c40770 100644 --- a/test/utils/big-o.ts +++ b/test/utils/big-o.ts @@ -1,4 +1,4 @@ -import {AnyFunction} from "../types"; +import {AnyFunction} from '../types'; const orderReducedBy = 2; // reduction of bigO's order compared to the baseline bigO @@ -22,10 +22,9 @@ export const bigO = { FACTORIAL: 10000 }; - function findPotentialN(input: any): number { let longestArray: any[] = []; - let mostProperties: { [key: string]: any } = {}; + let mostProperties: {[key: string]: any} = {}; function recurse(obj: any) { if (Array.isArray(obj)) { @@ -37,14 +36,14 @@ function findPotentialN(input: any): number { if (keys.length > Object.keys(mostProperties).length) { mostProperties = obj; } - keys.forEach((key) => { + keys.forEach(key => { recurse(obj[key]); }); } } if (Array.isArray(input)) { - input.forEach((item) => { + input.forEach(item => { recurse(item); }); } else { @@ -67,20 +66,20 @@ function linearRegression(x: number[], y: number[]) { const slope = (n * sumXY - sumX * sumY) / (n * sumXSquared - sumX ** 2); const intercept = (sumY - slope * sumX) / n; - const yHat = x.map((val) => slope * val + intercept); + const yHat = x.map(val => slope * val + intercept); const totalVariation = y.map((val, i) => (val - yHat[i]) ** 2).reduce((acc, val) => acc + val, 0); - const explainedVariation = y.map((val) => (val - (sumY / n)) ** 2).reduce((acc, val) => acc + val, 0); + const explainedVariation = y.map(val => (val - sumY / n) ** 2).reduce((acc, val) => acc + val, 0); const rSquared = 1 - totalVariation / explainedVariation; - return { slope, intercept, rSquared }; + return {slope, intercept, rSquared}; } function estimateBigO(runtimes: number[], dataSizes: number[]): string { // Make sure the input runtimes and data sizes have the same length if (runtimes.length !== dataSizes.length) { - return "Lengths of input arrays do not match"; + return 'Lengths of input arrays do not match'; } // Create an array to store the computational complexity of each data point @@ -88,32 +87,32 @@ function estimateBigO(runtimes: number[], dataSizes: number[]): string { // Traverse different possible complexities const complexitiesToCheck: string[] = [ - "O(1)", // constant time complexity - "O(log n)", // Logarithmic time complexity - "O(n)", // linear time complexity - "O(n log n)", // linear logarithmic time complexity - "O(n^2)", // squared time complexity + 'O(1)', // constant time complexity + 'O(log n)', // Logarithmic time complexity + 'O(n)', // linear time complexity + 'O(n log n)', // linear logarithmic time complexity + 'O(n^2)' // squared time complexity ]; for (const complexity of complexitiesToCheck) { - // Calculate data points for fitting - const fittedData: number[] = dataSizes.map((size) => { - if (complexity === "O(1)") { + // Calculate data points for fitting + const fittedData: number[] = dataSizes.map(size => { + if (complexity === 'O(1)') { return 1; // constant time complexity - } else if (complexity === "O(log n)") { + } else if (complexity === 'O(log n)') { return Math.log(size); - } else if (complexity === "O(n)") { + } else if (complexity === 'O(n)') { return size; - } else if (complexity === "O(n log n)") { + } else if (complexity === 'O(n log n)') { return size * Math.log(size); - } else if (complexity === "O(n^2)") { + } else if (complexity === 'O(n^2)') { return size ** 2; } else { - return size ** 10 + return size ** 10; } }); - // Fit the data points using linear regression analysis + // Fit the data points using linear regression analysis const regressionResult = linearRegression(fittedData, runtimes); // Check the R-squared value of the fit. It is usually considered a valid fit if it is greater than 0.9. @@ -124,39 +123,42 @@ function estimateBigO(runtimes: number[], dataSizes: number[]): string { // If there is no valid fitting result, return "cannot estimate", otherwise return the estimated time complexity if (complexities.length === 0) { - return "Unable to estimate"; + return 'Unable to estimate'; } else { - return complexities.join(" or "); + return complexities.join(' or '); } } -const methodLogs: Map = new Map(); +const methodLogs: Map = new Map(); export function logBigOMetricsWrap(fn: F, args: Parameters, fnName: string) { - const startTime = performance.now(); - const result = fn(args); - const endTime = performance.now(); - const runTime = endTime - startTime; - const methodName = `${fnName}`; - if (!methodLogs.has(methodName)) { - methodLogs.set(methodName, []); + const startTime = performance.now(); + const result = fn(args); + const endTime = performance.now(); + const runTime = endTime - startTime; + const methodName = `${fnName}`; + if (!methodLogs.has(methodName)) { + methodLogs.set(methodName, []); + } + + const methodLog = methodLogs.get(methodName); + + const maxDataSize = args.length === 1 && typeof args[0] === 'number' ? args[0] : findPotentialN(args); + if (methodLog) { + methodLog.push([runTime, maxDataSize]); + + if (methodLog.length >= 20) { + console.log('triggered', methodName, methodLog); + const bigO = estimateBigO( + methodLog.map(([runTime]) => runTime), + methodLog.map(([runTime]) => runTime) + ); + console.log(`Estimated Big O: ${bigO}`); + methodLogs.delete(methodName); } + } - const methodLog = methodLogs.get(methodName); - - const maxDataSize = args.length === 1 && typeof args[0] === "number" ? args[0] : findPotentialN(args); - if (methodLog) { - methodLog.push([runTime, maxDataSize]); - - if (methodLog.length >= 20) { - console.log('triggered', methodName, methodLog); - const bigO = estimateBigO(methodLog.map(([runTime,]) => runTime), methodLog.map(([runTime,]) => runTime)); - console.log(`Estimated Big O: ${bigO}`); - methodLogs.delete(methodName) - } - } - - return result; + return result; } export function logBigOMetrics(target: any, propertyKey: string, descriptor: PropertyDescriptor) { @@ -175,15 +177,18 @@ export function logBigOMetrics(target: any, propertyKey: string, descriptor: Pro const methodLog = methodLogs.get(methodName); - const maxDataSize = args.length === 1 && typeof args[0] === "number" ? args[0] : findPotentialN(args); + const maxDataSize = args.length === 1 && typeof args[0] === 'number' ? args[0] : findPotentialN(args); if (methodLog) { methodLog.push([runTime, maxDataSize]); if (methodLog.length >= 20) { console.log('triggered', methodName, methodLog); - const bigO = estimateBigO(methodLog.map(([runTime,]) => runTime), methodLog.map(([runTime,]) => runTime)); + const bigO = estimateBigO( + methodLog.map(([runTime]) => runTime), + methodLog.map(([runTime]) => runTime) + ); console.log(`Estimated Big O: ${bigO}`); - methodLogs.delete(methodName) + methodLogs.delete(methodName); } } From 284e85e76b9ccb384cfc61d4dbdecd84e1d35dec Mon Sep 17 00:00:00 2001 From: Revone Date: Sat, 21 Oct 2023 20:19:35 +0800 Subject: [PATCH 07/46] [pkg] v1.36.9 published --- CHANGELOG.md | 3 ++- package-lock.json | 50 +++++++++++++++++++++++------------------------ package.json | 16 ++++++++------- 3 files changed, 36 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 16c259d..b31a5de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,10 +8,11 @@ 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.36.8](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) +## [v1.36.9](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) ### Changes +- 1. No need for dfsIterative; integrate it directly into the dfs metho… [`#17`](https://github.com/zrwusa/data-structure-typed/pull/17) - [heap] fibonacci heap implemented. [test] big O estimate. [project] n… [`#15`](https://github.com/zrwusa/data-structure-typed/pull/15) - [rbtree] implemented, but with bugs [`#13`](https://github.com/zrwusa/data-structure-typed/pull/13) - [trie] renamed ambiguous methods and add comments to all methods. [`#12`](https://github.com/zrwusa/data-structure-typed/pull/12) diff --git a/package-lock.json b/package-lock.json index 72d4355..34a1209 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "data-structure-typed", - "version": "1.36.8", + "version": "1.36.9", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "data-structure-typed", - "version": "1.36.8", + "version": "1.36.9", "license": "MIT", "devDependencies": { "@types/benchmark": "^2.1.3", @@ -15,17 +15,17 @@ "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", "auto-changelog": "^2.4.0", - "avl-tree-typed": "^1.36.6", + "avl-tree-typed": "^1.36.8", "benchmark": "^2.1.4", - "binary-tree-typed": "^1.36.6", - "bst-typed": "^1.36.6", + "binary-tree-typed": "^1.36.8", + "bst-typed": "^1.36.8", "dependency-cruiser": "^14.1.0", "eslint": "^8.50.0", "eslint-config-prettier": "^9.0.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.28.1", - "heap-typed": "^1.36.6", + "heap-typed": "^1.36.8", "istanbul-badges-readme": "^1.8.5", "jest": "^29.7.0", "prettier": "^3.0.3", @@ -2396,12 +2396,12 @@ } }, "node_modules/avl-tree-typed": { - "version": "1.36.6", - "resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.36.6.tgz", - "integrity": "sha512-RoQASIXmEzMiVfLJDFDf+l34vBNpXOwn4t3XnZpkYKdSfaSgGAAIFH/2DTWiJuGEYIOz5vXRCPIVbk0b5VgPKQ==", + "version": "1.36.8", + "resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.36.8.tgz", + "integrity": "sha512-cdzKqEFMfCE9D54wqnKvNaFn5RQI4reRcKg1CHPN2a5PicJn6uXcoULGPX9b4TKI35PJNhZ+7Blq4Y+5olsUsw==", "dev": true, "dependencies": { - "data-structure-typed": "^1.36.6" + "data-structure-typed": "^1.36.8" } }, "node_modules/babel-jest": { @@ -2586,12 +2586,12 @@ } }, "node_modules/binary-tree-typed": { - "version": "1.36.6", - "resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.36.6.tgz", - "integrity": "sha512-E8HoO6dQ+xUOtFQm1eCW1AT2Jjug7z1/uOY6XeBXn7JEMaByPj4IYIx6v5IUKKdBRyj5TPBXr0CvxxL3nLHqTA==", + "version": "1.36.8", + "resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.36.8.tgz", + "integrity": "sha512-Brh3DLTcm17ZmJoDNVWG3f6aeD448ANjv5EQi19ZrwPwMddlLRdvEn08lfdheq78lzw3x2rOU7GgFA4W+fbeFw==", "dev": true, "dependencies": { - "data-structure-typed": "^1.36.6" + "data-structure-typed": "^1.36.8" } }, "node_modules/brace-expansion": { @@ -2670,12 +2670,12 @@ } }, "node_modules/bst-typed": { - "version": "1.36.6", - "resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.36.6.tgz", - "integrity": "sha512-6AjjYvNZkXiDKW52l7wKe/E2EBmjXVLbuLI8d9bX6EdIxQ/OAwgkvMXTvIHBD0N5ws7zHca0KhwM7nLkl50FMg==", + "version": "1.36.8", + "resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.36.8.tgz", + "integrity": "sha512-bjWACK4u+qXIetBrOcs8GRLucxsshnxcP8FDnPXzDr2sl84aVITvt+yQ4hpuft7t3C3Z2X2PtTp2alSiE3gquw==", "dev": true, "dependencies": { - "data-structure-typed": "^1.36.6" + "data-structure-typed": "^1.36.8" } }, "node_modules/buffer-from": { @@ -3027,9 +3027,9 @@ } }, "node_modules/data-structure-typed": { - "version": "1.36.6", - "resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.36.6.tgz", - "integrity": "sha512-9puuDXinho/WreP7DDNjnreL0wpMQgO+kM74A+/uqkyOcJ0abtNdKNLiTOLMfuDJjk/GvhuxM5RexwaC/6JDpw==", + "version": "1.36.8", + "resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.36.8.tgz", + "integrity": "sha512-mDm4rww/jzmmVtqtb+A63Ri3Aeau3FzNKwxGKtZd20xRPz7FVDm/fciCIxtv1TWTTLjDSpDZcpBGs/tB0i61QA==", "dev": true }, "node_modules/debug": { @@ -4362,12 +4362,12 @@ } }, "node_modules/heap-typed": { - "version": "1.36.6", - "resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.36.6.tgz", - "integrity": "sha512-ylui085xL2GIewkT2SZyjGLpvJakcYbm+/qB68QWKlwPqG2JJobHRFTFxZpccnyN9QakslsJ8o7SJhpWHu8/ZA==", + "version": "1.36.8", + "resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.36.8.tgz", + "integrity": "sha512-hk/W8DIgU8jTDdD2fbjVxnYUha30DCJrkt7LDnA0V1yWiMt1/YgJOToQVodMcPh3yN25dNQLGo8MVGnonlYhZQ==", "dev": true, "dependencies": { - "data-structure-typed": "^1.36.6" + "data-structure-typed": "^1.36.8" } }, "node_modules/html-escaper": { diff --git a/package.json b/package.json index 4e13f50..61f1290 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "data-structure-typed", - "version": "1.36.8", + "version": "1.36.9", "description": "Data Structures of Javascript & TypeScript. Binary Tree, BST, Graph, Heap, Priority Queue, Linked List, Queue, Deque, Stack, AVL Tree, Tree Multiset, Trie, Directed Graph, Undirected Graph, Singly Linked List, Doubly Linked List, Max Heap, Max Priority Queue, Min Heap, Min Priority Queue.", "main": "dist/index.js", "module": "lib/index.js", @@ -33,8 +33,10 @@ "check:deps": "dependency-cruiser src", "changelog": "auto-changelog", "coverage:badge": "istanbul-badges-readme", - "ci": "env && npm run lint && npm run build && npm run update:individuals && npm run test && git fetch --tags && npm run changelog", - "publish:all": "npm run ci && npm publish && sh scripts/publish_all_subs.sh && sh scripts/publish_docs.sh" + "ci": "env && git fetch --tags && npm run lint && npm run build && npm run update:individuals && npm run test && npm run changelog", + "publish:individuals": "sh scripts/publish_all_subs.sh", + "publish:docs": "sh scripts/publish_docs.sh", + "publish:all": "npm run ci && npm publish && npm run publish:individuals && npm run publish:docs" }, "repository": { "type": "git", @@ -56,17 +58,17 @@ "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", "auto-changelog": "^2.4.0", - "avl-tree-typed": "^1.36.6", + "avl-tree-typed": "^1.36.8", "benchmark": "^2.1.4", - "binary-tree-typed": "^1.36.6", - "bst-typed": "^1.36.6", + "binary-tree-typed": "^1.36.8", + "bst-typed": "^1.36.8", "dependency-cruiser": "^14.1.0", "eslint": "^8.50.0", "eslint-config-prettier": "^9.0.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.28.1", - "heap-typed": "^1.36.6", + "heap-typed": "^1.36.8", "istanbul-badges-readme": "^1.8.5", "jest": "^29.7.0", "prettier": "^3.0.3", From 3a86a5c37daf2656d2a03509df69ac394250b81b Mon Sep 17 00:00:00 2001 From: Revone Date: Sat, 21 Oct 2023 23:56:14 +0800 Subject: [PATCH 08/46] [binary-tree, graph] Replace all code that uses Arrays as makeshift Queues with actual Queues to improve efficiency. [binary-tree] Remove most methods for calculating sums and modifying properties, adopting a generic callback-based design. [bst] Enable default batch addition in BST using sorted binary insertion to maintain tree balance as much as possible. --- .../binary-tree/binary-tree.ts | 70 +----- src/data-structures/binary-tree/bst.ts | 128 ++-------- .../binary-tree/tree-multiset.ts | 234 +----------------- src/data-structures/graph/abstract-graph.ts | 7 +- .../binary-tree/avl-tree.test.ts | 8 +- .../data-structures/binary-tree/bst.test.ts | 51 +++- .../binary-tree/overall.test.ts | 2 +- .../binary-tree/tree-multiset.test.ts | 48 +++- test/unit/data-structures/queue/deque.test.ts | 17 ++ test/unit/data-structures/queue/queue.test.ts | 42 ++++ 10 files changed, 185 insertions(+), 422 deletions(-) diff --git a/src/data-structures/binary-tree/binary-tree.ts b/src/data-structures/binary-tree/binary-tree.ts index 54b600e..8f4037f 100644 --- a/src/data-structures/binary-tree/binary-tree.ts +++ b/src/data-structures/binary-tree/binary-tree.ts @@ -23,6 +23,7 @@ import { } from '../../types'; import {IBinaryTree} from '../../interfaces'; import {trampoline} from '../../utils'; +import {Queue} from '../queue'; export class BinaryTreeNode = BinaryTreeNodeNested> { /** @@ -210,8 +211,8 @@ export class BinaryTree = BinaryTreeNode> */ add(keyOrNode: BinaryTreeNodeKey | N | null, val?: N['val']): N | null | undefined { const _bfs = (root: N, newNode: N | null): N | undefined | null => { - const queue: Array = [root]; - while (queue.length > 0) { + const queue = new Queue([root]); + while (queue.size > 0) { const cur = queue.shift(); if (cur) { if (newNode && cur.key === newNode.key) return; @@ -509,8 +510,8 @@ export class BinaryTree = BinaryTreeNode> _traverse(this.root); } else { - const queue: N[] = [this.root]; - while (queue.length > 0) { + const queue = new Queue([this.root]); + while (queue.size > 0) { const cur = queue.shift(); if (cur) { if (this._pushByPropertyNameStopOrNot(cur, result, nodeProperty, propertyName, onlyOne)) return result; @@ -762,65 +763,11 @@ export class BinaryTree = BinaryTreeNode> } } - /** - * The function `subTreeSum` calculates the sum of a specified property in a binary tree or subtree. - * @param {N | BinaryTreeNodeKey | null} subTreeRoot - The `subTreeRoot` parameter represents the root node of a binary - * tree or the ID of a binary tree node. It can also be `null` if there is no subtree. - * @param {BinaryTreeNodePropertyName} [propertyName] - propertyName is an optional parameter that specifies the - * property of the binary tree node to use for calculating the sum. It can be either 'key' or 'val'. If propertyName is - * not provided, it defaults to 'key'. - * @returns a number, which is the sum of the values of the specified property in the subtree rooted at `subTreeRoot`. - */ - subTreeSum(subTreeRoot: N | BinaryTreeNodeKey | null, propertyName: BinaryTreeNodePropertyName = 'key'): number { - if (typeof subTreeRoot === 'number') subTreeRoot = this.get(subTreeRoot, 'key'); - - if (!subTreeRoot) return 0; - - let sum = 0; - - const _sumByProperty = (cur: N) => { - let needSum: number; - switch (propertyName) { - case 'key': - needSum = cur.key; - break; - case 'val': - needSum = typeof cur.val === 'number' ? cur.val : 0; - break; - default: - needSum = cur.key; - break; - } - return needSum; - }; - - if (this._loopType === LoopType.RECURSIVE) { - const _traverse = (cur: N): void => { - sum += _sumByProperty(cur); - cur.left && _traverse(cur.left); - cur.right && _traverse(cur.right); - }; - - _traverse(subTreeRoot); - } else { - const stack: N[] = [subTreeRoot]; - - while (stack.length > 0) { - const cur = stack.pop()!; - sum += _sumByProperty(cur); - cur.right && stack.push(cur.right); - cur.left && stack.push(cur.left); - } - } - - return sum; - } - /** * The function `subTreeForeach` adds a delta value to a specified property of each node in a subtree. * @param {N | BinaryTreeNodeKey | null} subTreeRoot - The `subTreeRoot` parameter represents the root node of a binary * tree or the ID of a node in the binary tree. It can also be `null` if there is no subtree to add to. - * @param callBack - The `callBack` parameter is a function that takes a node as a parameter and returns a number. + * @param callback - The `callback` parameter is a function that takes a node as a parameter and returns a value. * specifies the property of the binary tree node that should be modified. If not provided, it defaults to 'key'. * @returns a boolean value. */ @@ -887,10 +834,9 @@ export class BinaryTree = BinaryTreeNode> */ bfs(nodeOrPropertyName: NodeOrPropertyName = 'key'): BinaryTreeNodeProperties { this._clearResults(); - const queue: Array = [this.root]; + const queue = new Queue([this.root]); - while (queue.length !== 0) { - // TODO Array.shift is not efficient, consider using Deque + while (queue.size !== 0) { const cur = queue.shift(); if (cur) { this._accumulatedByPropertyName(cur, nodeOrPropertyName); diff --git a/src/data-structures/binary-tree/bst.ts b/src/data-structures/binary-tree/bst.ts index 22b1af6..c4b49ed 100644 --- a/src/data-structures/binary-tree/bst.ts +++ b/src/data-structures/binary-tree/bst.ts @@ -15,6 +15,7 @@ import type { import {CP, LoopType} from '../../types'; import {BinaryTree, BinaryTreeNode} from './binary-tree'; import {IBinaryTree} from '../../interfaces'; +import {Queue} from '../queue'; export class BSTNode = BSTNodeNested> extends BinaryTreeNode { constructor(key: BinaryTreeNodeKey, val?: V) { @@ -59,7 +60,7 @@ export class BST = BSTNode> extends BinaryTree * @returns The function `add` returns the inserted node (`inserted`) which can be of type `N`, `null`, or `undefined`. */ override add(keyOrNode: BinaryTreeNodeKey | N | null, val?: N['val']): N | null | undefined { - // TODO support node as a param + // TODO support node as a parameter let inserted: N | null = null; let newNode: N | null = null; if (keyOrNode instanceof BSTNode) { @@ -137,8 +138,9 @@ export class BST = BSTNode> extends BinaryTree override addMany( keysOrNodes: (BinaryTreeNodeKey | null)[] | (N | null)[], data?: N['val'][], - isBalanceAdd = false + isBalanceAdd = true ): (N | null | undefined)[] { + // TODO this addMany function is inefficient, it should be optimized function hasNoNull(arr: (BinaryTreeNodeKey | null)[] | (N | null)[]): arr is BinaryTreeNodeKey[] | N[] { return arr.indexOf(null) === -1; } @@ -265,8 +267,8 @@ export class BST = BSTNode> extends BinaryTree _traverse(this.root); } else { - const queue: N[] = [this.root]; - while (queue.length > 0) { + const queue = new Queue([this.root]); + while (queue.size > 0) { const cur = queue.shift(); if (cur) { if (this._pushByPropertyNameStopOrNot(cur, result, nodeProperty, propertyName, onlyOne)) return result; @@ -285,133 +287,47 @@ export class BST = BSTNode> extends BinaryTree } // --- start additional functions - /** - * The `lesserSum` function calculates the sum of property values in a binary tree for nodes that have a property value - * less than a given node. - * @param {N | BinaryTreeNodeKey | null} beginNode - The `beginNode` parameter can be one of the following: - * @param {BinaryTreeNodePropertyName} [propertyName] - The `propertyName` parameter is an optional parameter that - * specifies the property name to use for calculating the sum. If not provided, it defaults to `'key'`. - * @returns The function `lesserSum` returns a number, which represents the sum of the values of the nodes in the - * binary tree that have a lesser value than the specified `beginNode` based on the `propertyName`. - */ - lesserSum(beginNode: N | BinaryTreeNodeKey | null, propertyName: BinaryTreeNodePropertyName = 'key'): number { - if (typeof beginNode === 'number') beginNode = this.get(beginNode, 'key'); - if (!beginNode) return 0; - if (!this.root) return 0; - const key = beginNode.key; - const getSumByPropertyName = (cur: N) => { - let needSum: number; - switch (propertyName) { - case 'key': - needSum = cur.key; - break; - default: - needSum = cur.key; - break; - } - return needSum; - }; - - let sum = 0; - - if (this.loopType === LoopType.RECURSIVE) { - const _traverse = (cur: N): void => { - const compared = this._compare(cur.key, key); - if (compared === CP.eq) { - if (cur.right) sum += this.subTreeSum(cur.right, propertyName); - return; - } else if (compared === CP.lt) { - if (cur.left) sum += this.subTreeSum(cur.left, propertyName); - sum += getSumByPropertyName(cur); - if (cur.right) _traverse(cur.right); - else return; - } else { - if (cur.left) _traverse(cur.left); - else return; - } - }; - - _traverse(this.root); - } else { - const queue: N[] = [this.root]; - while (queue.length > 0) { - const cur = queue.shift(); - if (cur) { - const compared = this._compare(cur.key, key); - if (compared === CP.eq) { - if (cur.right) sum += this.subTreeSum(cur.right, propertyName); - return sum; - } else if (compared === CP.lt) { - // todo maybe a bug - if (cur.left) sum += this.subTreeSum(cur.left, propertyName); - sum += getSumByPropertyName(cur); - if (cur.right) queue.push(cur.right); - else return sum; - } else { - if (cur.left) queue.push(cur.left); - else return sum; - } - } - } - } - - return sum; - } /** - * The `allGreaterNodesAdd` function adds a delta value to the specified property of all nodes in a binary tree that + * The `lesserOrGreaterForeach` function adds a delta value to the specified property of all nodes in a binary tree that * have a greater value than a given node. - * @param {N | BinaryTreeNodeKey | null} node - The `node` parameter can be either of type `N` (a generic type), - * `BinaryTreeNodeKey`, or `null`. It represents the node in the binary tree to which the delta value will be added. - * @param {number} delta - The `delta` parameter is a number that represents the amount by which the property value of - * each greater node should be increased. - * @param {BinaryTreeNodePropertyName} [propertyName] - The `propertyName` parameter is an optional parameter that - * specifies the property name of the nodes in the binary tree that you want to update. If not provided, it defaults to - * 'key'. - * @returns a boolean value. + * @param {N | BinaryTreeNodeKey | null} node - The `node` parameter can be either of type `N` (a generic type), `BinaryTreeNodeKey`, or `null`. It + * represents the node in the binary tree to which the delta value will be added. + * @param lesserOrGreater - The `lesserOrGreater` parameter is an optional parameter that specifies whether the delta + * @param callback - The `callback` parameter is a function that takes a node as a parameter and returns a boolean */ - allGreaterNodesAdd( + lesserOrGreaterForeach( node: N | BinaryTreeNodeKey | null, - delta: number, - propertyName: BinaryTreeNodePropertyName = 'key' + lesserOrGreater: CP = CP.lt, + callback: (node: N) => void ): boolean { if (typeof node === 'number') node = this.get(node, 'key'); if (!node) return false; const key = node.key; if (!this.root) return false; - const _sumByPropertyName = (cur: N) => { - switch (propertyName) { - case 'key': - cur.key += delta; - break; - default: - cur.key += delta; - break; - } - }; if (this.loopType === LoopType.RECURSIVE) { const _traverse = (cur: N) => { const compared = this._compare(cur.key, key); - if (compared === CP.gt) _sumByPropertyName(cur); + if (compared === lesserOrGreater) callback(cur); if (!cur.left && !cur.right) return; - if (cur.left && this._compare(cur.left.key, key) === CP.gt) _traverse(cur.left); - if (cur.right && this._compare(cur.right.key, key) === CP.gt) _traverse(cur.right); + if (cur.left && this._compare(cur.left.key, key) === lesserOrGreater) _traverse(cur.left); + if (cur.right && this._compare(cur.right.key, key) === lesserOrGreater) _traverse(cur.right); }; _traverse(this.root); return true; } else { - const queue: N[] = [this.root]; - while (queue.length > 0) { + const queue = new Queue([this.root]); + while (queue.size > 0) { const cur = queue.shift(); if (cur) { const compared = this._compare(cur.key, key); - if (compared === CP.gt) _sumByPropertyName(cur); + if (compared === lesserOrGreater) callback(cur); - if (cur.left && this._compare(cur.left.key, key) === CP.gt) queue.push(cur.left); - if (cur.right && this._compare(cur.right.key, key) === CP.gt) queue.push(cur.right); + if (cur.left && this._compare(cur.left.key, key) === lesserOrGreater) queue.push(cur.left); + if (cur.right && this._compare(cur.right.key, key) === lesserOrGreater) queue.push(cur.right); } } return true; diff --git a/src/data-structures/binary-tree/tree-multiset.ts b/src/data-structures/binary-tree/tree-multiset.ts index 06294b6..1e62b91 100644 --- a/src/data-structures/binary-tree/tree-multiset.ts +++ b/src/data-structures/binary-tree/tree-multiset.ts @@ -9,6 +9,7 @@ import type {BinaryTreeNodeKey, TreeMultisetNodeNested, TreeMultisetOptions} fro import {BinaryTreeDeletedResult, CP, DFSOrderPattern, FamilyPosition, LoopType} from '../../types'; import {IBinaryTree} from '../../interfaces'; import {AVLTree, AVLTreeNode} from './avl-tree'; +import {Queue} from '../queue'; export class TreeMultisetNode< V = any, @@ -349,121 +350,6 @@ export class TreeMultiset = TreeMultiset return bstDeletedResult; } - /** - * The function `getSubTreeCount` calculates the number of nodes and the sum of their counts in a subtree, using either - * recursive or iterative traversal. - * @param {N | null | undefined} subTreeRoot - The `subTreeRoot` parameter represents the root node of a subtree in a - * binary tree. - * @returns The function `getSubTreeCount` returns an array `[number, number]`. - */ - getSubTreeCount(subTreeRoot: N | null | undefined) { - const res: [number, number] = [0, 0]; - if (!subTreeRoot) return res; - - if (this.loopType === LoopType.RECURSIVE) { - const _traverse = (cur: N) => { - res[0]++; - res[1] += cur.count; - cur.left && _traverse(cur.left); - cur.right && _traverse(cur.right); - }; - - _traverse(subTreeRoot); - return res; - } else { - const stack: N[] = [subTreeRoot]; - - while (stack.length > 0) { - const cur = stack.pop()!; - res[0]++; - res[1] += cur.count; - cur.right && stack.push(cur.right); - cur.left && stack.push(cur.left); - } - - return res; - } - } - - /** - * The function `subTreeSumCount` calculates the sum of the `count` property of each node in a subtree, either - * recursively or iteratively. - * @param {N | BinaryTreeNodeKey | null} subTreeRoot - The `subTreeRoot` parameter represents the root node of a subtree - * in a binary tree. It can be either a `BinaryTreeNodeKey` (a unique identifier for a node in the binary tree) or - * `null` if the subtree is empty. - * @returns the sum of the count values of all nodes in the subtree rooted at `subTreeRoot`. - */ - subTreeSumCount(subTreeRoot: N | BinaryTreeNodeKey | null): number { - if (typeof subTreeRoot === 'number') subTreeRoot = this.get(subTreeRoot, 'key'); - - if (!subTreeRoot) return 0; - - let sum = 0; - - if (this.loopType === LoopType.RECURSIVE) { - const _traverse = (cur: N): void => { - sum += cur.count; - cur.left && _traverse(cur.left); - cur.right && _traverse(cur.right); - }; - - _traverse(subTreeRoot); - } else { - const stack: N[] = [subTreeRoot]; - - while (stack.length > 0) { - const cur = stack.pop()!; - sum += cur.count; - cur.right && stack.push(cur.right); - cur.left && stack.push(cur.left); - } - } - - return sum; - } - - /** - * The function `subTreeAddCount` recursively or iteratively traverses a binary tree and adds a given delta value to - * the `count` property of each node. - * @param {N | BinaryTreeNodeKey | null} subTreeRoot - The `subTreeRoot` parameter represents the root node of a subtree - * in a binary tree. It can be either a `BinaryTreeNodeKey` (a unique identifier for a node in the binary tree), a - * `BinaryTreeNode` object, or `null` if the subtree is empty. - * @param {number} delta - The delta parameter is a number that represents the amount by which the count of each node - * in the subtree should be increased or decreased. - * @returns a boolean value. - */ - subTreeAddCount(subTreeRoot: N | BinaryTreeNodeKey | null, delta: number): boolean { - if (typeof subTreeRoot === 'number') subTreeRoot = this.get(subTreeRoot, 'key'); - - if (!subTreeRoot) return false; - - const _addByProperty = (cur: N) => { - cur.count += delta; - this._setCount(this.count + delta); - }; - - if (this.loopType === LoopType.RECURSIVE) { - const _traverse = (cur: N) => { - _addByProperty(cur); - cur.left && _traverse(cur.left); - cur.right && _traverse(cur.right); - }; - - _traverse(subTreeRoot); - } else { - const stack: N[] = [subTreeRoot]; - - while (stack.length > 0) { - const cur = stack.pop()!; - - _addByProperty(cur); - cur.right && stack.push(cur.right); - cur.left && stack.push(cur.left); - } - } - return true; - } - /** * The function `getNodesByCount` returns an array of nodes that have a specific count property, either recursively or * using a queue. @@ -492,8 +378,8 @@ export class TreeMultiset = TreeMultiset _traverse(this.root); } else { - const queue: N[] = [this.root]; - while (queue.length > 0) { + const queue = new Queue([this.root]); + while (queue.size > 0) { const cur = queue.shift(); if (cur) { if (cur.count === nodeProperty) { @@ -545,120 +431,6 @@ export class TreeMultiset = TreeMultiset return nodes.map(node => node.count); } - /** - * The function dfsCountIterative performs an iterative depth-first search and returns an array of node counts based on - * the specified traversal pattern. - * @param {'in' | 'pre' | 'post'} [pattern] - The pattern parameter is a string that specifies the traversal order for - * the Depth-First Search (dfs) algorithm. It can have three possible values: 'in', 'pre', or 'post'. - * @param loopType - The loopType parameter is a string that specifies the type of loop to use when traversing the - * @returns The dfsCountIterative function returns an array of numbers, which represents the count property of each node - * in the dfs traversal. - */ - dfsCount(pattern: DFSOrderPattern = 'in', loopType: LoopType = LoopType.ITERATIVE): number[] { - const nodes = super.dfs(pattern, 'node', loopType); - return nodes.map(node => node.count); - } - - /** - * The `lesserSumCount` function calculates the sum of the counts of all nodes in a binary tree that have a lesser - * value than a given node. - * @param {N | BinaryTreeNodeKey | null} beginNode - The `beginNode` parameter can be one of the following: - * @returns the sum of the counts of nodes in the binary tree that have a lesser value than the given beginNode. - */ - lesserSumCount(beginNode: N | BinaryTreeNodeKey | null): number { - if (typeof beginNode === 'number') beginNode = this.get(beginNode, 'key'); - if (!beginNode) return 0; - if (!this.root) return 0; - const key = beginNode.key; - - let sum = 0; - - if (this.loopType === LoopType.RECURSIVE) { - const _traverse = (cur: N): void => { - const compared = this._compare(cur.key, key); - if (compared === CP.eq) { - if (cur.right) sum += this.subTreeSumCount(cur.right); - return; - } else if (compared === CP.lt) { - if (cur.left) sum += this.subTreeSumCount(cur.left); - sum += cur.count; - if (cur.right) _traverse(cur.right); - else return; - } else { - if (cur.left) _traverse(cur.left); - else return; - } - }; - - _traverse(this.root); - } else { - const queue: N[] = [this.root]; - while (queue.length > 0) { - const cur = queue.shift(); - if (cur) { - const compared = this._compare(cur.key, key); - if (compared === CP.eq) { - if (cur.right) sum += this.subTreeSumCount(cur.right); - return sum; - } else if (compared === CP.lt) { - // todo maybe a bug - if (cur.left) sum += this.subTreeSumCount(cur.left); - sum += cur.count; - if (cur.right) queue.push(cur.right); - else return sum; - } else { - if (cur.left) queue.push(cur.left); - else return sum; - } - } - } - } - - return sum; - } - - /** - * The function `allGreaterNodesAddCount` updates the count property of all nodes in a binary tree that have an ID - * greater than a given ID by a specified delta value. - * @param {N | BinaryTreeNodeKey | null} node - The `node` parameter can be one of the following: - * @param {number} delta - The `delta` parameter is a number that represents the amount by which the `count` property - * of each node should be increased. - * @returns a boolean value. - */ - allGreaterNodesAddCount(node: N | BinaryTreeNodeKey | null, delta: number): boolean { - if (typeof node === 'number') node = this.get(node, 'key'); - if (!node) return false; - const key = node.key; - if (!this.root) return false; - - if (this.loopType === LoopType.RECURSIVE) { - const _traverse = (cur: N) => { - const compared = this._compare(cur.key, key); - if (compared === CP.gt) cur.count += delta; - - if (!cur.left && !cur.right) return; - if (cur.left && this._compare(cur.left.key, key) === CP.gt) _traverse(cur.left); - if (cur.right && this._compare(cur.right.key, key) === CP.gt) _traverse(cur.right); - }; - - _traverse(this.root); - return true; - } else { - const queue: N[] = [this.root]; - while (queue.length > 0) { - const cur = queue.shift(); - if (cur) { - const compared = this._compare(cur.key, key); - if (compared === CP.gt) cur.count += delta; - - if (cur.left && this._compare(cur.left.key, key) === CP.gt) queue.push(cur.left); - if (cur.right && this._compare(cur.right.key, key) === CP.gt) queue.push(cur.right); - } - } - return true; - } - } - /** * The clear() function clears the data and sets the count to 0. */ diff --git a/src/data-structures/graph/abstract-graph.ts b/src/data-structures/graph/abstract-graph.ts index 92b5380..e820f6b 100644 --- a/src/data-structures/graph/abstract-graph.ts +++ b/src/data-structures/graph/abstract-graph.ts @@ -9,6 +9,7 @@ import {arrayRemove, uuidV4} from '../../utils'; import {PriorityQueue} from '../priority-queue'; import type {DijkstraResult, VertexKey} from '../../types'; import {IGraph} from '../../interfaces'; +import {Queue} from '../queue'; export abstract class AbstractVertex { /** @@ -342,11 +343,11 @@ export abstract class AbstractGraph< } const visited: Map = new Map(); - const queue: V[] = [vertex1]; + const queue = new Queue([vertex1]); visited.set(vertex1, true); let cost = 0; - while (queue.length > 0) { - for (let i = 0; i < queue.length; i++) { + while (queue.size > 0) { + for (let i = 0; i < queue.size; i++) { const cur = queue.shift(); if (cur === vertex2) { return cost; diff --git a/test/unit/data-structures/binary-tree/avl-tree.test.ts b/test/unit/data-structures/binary-tree/avl-tree.test.ts index 358132a..fd2fb41 100644 --- a/test/unit/data-structures/binary-tree/avl-tree.test.ts +++ b/test/unit/data-structures/binary-tree/avl-tree.test.ts @@ -1,4 +1,4 @@ -import {AVLTree} from '../../../../src'; +import {AVLTree, CP} from '../../../../src'; describe('AVL Tree Test', () => { it('should perform various operations on a AVL Tree', () => { @@ -22,10 +22,12 @@ describe('AVL Tree Test', () => { const getMinNodeBySpecificNode = node15 && tree.getLeftMost(node15); expect(getMinNodeBySpecificNode?.key).toBe(12); - const subTreeSum = node15 && tree.subTreeSum(node15); + let subTreeSum = 0; + node15 && tree.subTreeForeach(node15, node => (subTreeSum += node.key)); expect(subTreeSum).toBe(70); - const lesserSum = tree.lesserSum(10); + let lesserSum = 0; + tree.lesserOrGreaterForeach(10, CP.lt, node => (lesserSum += node.key)); expect(lesserSum).toBe(45); // node15 has type problem. After the uniform design, the generics of containers (DirectedGraph, BST) are based on the type of value. However, this design has a drawback: when I attempt to inherit from the Vertex or BSTNode classes, the types of the results obtained by all methods are those of the parent class. diff --git a/test/unit/data-structures/binary-tree/bst.test.ts b/test/unit/data-structures/binary-tree/bst.test.ts index bd5d06f..84c0d79 100644 --- a/test/unit/data-structures/binary-tree/bst.test.ts +++ b/test/unit/data-structures/binary-tree/bst.test.ts @@ -1,4 +1,6 @@ -import {BST, BSTNode} from '../../../../src'; +import {BST, BSTNode, CP} from '../../../../src'; + +const isDebug = false; describe('BST operations test', () => { it('should perform various operations on a Binary Search Tree with numeric values', () => { @@ -7,7 +9,7 @@ describe('BST operations test', () => { bst.add(11, 11); bst.add(3, 3); const idsAndValues = [15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5]; - bst.addMany(idsAndValues, idsAndValues); + bst.addMany(idsAndValues, idsAndValues, false); expect(bst.root).toBeInstanceOf(BSTNode); if (bst.root) expect(bst.root.key).toBe(11); @@ -33,10 +35,12 @@ describe('BST operations test', () => { const minNodeBySpecificNode = node15 && bst.getLeftMost(node15); expect(minNodeBySpecificNode?.key).toBe(12); - const subTreeSum = node15 && bst.subTreeSum(15); + let subTreeSum = 0; + node15 && bst.subTreeForeach(15, node => (subTreeSum += node.key)); expect(subTreeSum).toBe(70); - const lesserSum = bst.lesserSum(10); + let lesserSum = 0; + bst.lesserOrGreaterForeach(10, CP.lt, node => (lesserSum += node.key)); expect(lesserSum).toBe(45); expect(node15).toBeInstanceOf(BSTNode); @@ -204,7 +208,8 @@ describe('BST operations test', () => { objBST.addMany( values.map(item => item.key), - values + values, + false ); expect(objBST.root).toBeInstanceOf(BSTNode); @@ -231,10 +236,12 @@ describe('BST operations test', () => { const minNodeBySpecificNode = node15 && objBST.getLeftMost(node15); expect(minNodeBySpecificNode?.key).toBe(12); - const subTreeSum = node15 && objBST.subTreeSum(node15); + let subTreeSum = 0; + node15 && objBST.subTreeForeach(node15, node => (subTreeSum += node.key)); expect(subTreeSum).toBe(70); - const lesserSum = objBST.lesserSum(10); + let lesserSum = 0; + objBST.lesserOrGreaterForeach(10, CP.lt, node => (lesserSum += node.key)); expect(lesserSum).toBe(45); expect(node15).toBeInstanceOf(BSTNode); @@ -378,3 +385,33 @@ describe('BST operations test', () => { expect(bfsNodes[2].key).toBe(16); }); }); + +describe('BST Performance test', function () { + const bst = new BST>(); + const inputSize = 10000; // Adjust input sizes as needed + + beforeEach(() => { + bst.clear(); + }); + + it(`Observe the time consumption of BST.dfs be good`, function () { + const startDFS = performance.now(); + const dfs = bst.dfs(); + isDebug && console.log('---bfs', performance.now() - startDFS, dfs.length); + }); + + it('Should the time consumption of lesserOrGreaterForeach fitting O(n log n)', function () { + const nodes: number[] = []; + for (let i = 0; i < inputSize; i++) { + nodes.push(i); + } + const start = performance.now(); + bst.addMany(nodes); + isDebug && console.log('---add', performance.now() - start); + const startL = performance.now(); + bst.lesserOrGreaterForeach(inputSize / 2, CP.lt, node => { + return node.key - 1; + }); + isDebug && console.log('---lesserOrGreaterForeach', performance.now() - startL); + }); +}); diff --git a/test/unit/data-structures/binary-tree/overall.test.ts b/test/unit/data-structures/binary-tree/overall.test.ts index 9fd298b..2cdffee 100644 --- a/test/unit/data-structures/binary-tree/overall.test.ts +++ b/test/unit/data-structures/binary-tree/overall.test.ts @@ -5,7 +5,7 @@ describe('Overall BinaryTree Test', () => { const bst = new BST(); bst.add(11); bst.add(3); - bst.addMany([15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5]); + bst.addMany([15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5], undefined, false); bst.size === 16; // true expect(bst.size).toBe(16); // true bst.has(6); // true diff --git a/test/unit/data-structures/binary-tree/tree-multiset.test.ts b/test/unit/data-structures/binary-tree/tree-multiset.test.ts index c2eb7a6..4be9ce1 100644 --- a/test/unit/data-structures/binary-tree/tree-multiset.test.ts +++ b/test/unit/data-structures/binary-tree/tree-multiset.test.ts @@ -1,5 +1,6 @@ -import {TreeMultiset, TreeMultisetNode} from '../../../../src'; +import {CP, TreeMultiset, TreeMultisetNode} from '../../../../src'; +const isDebug = false; describe('TreeMultiset operations test', () => { it('should perform various operations on a Binary Search Tree with numeric values', () => { const treeMultiset = new TreeMultiset(); @@ -39,20 +40,26 @@ describe('TreeMultiset operations test', () => { const minNodeBySpecificNode = node15 && treeMultiset.getLeftMost(node15); expect(minNodeBySpecificNode?.key).toBe(12); - const subTreeSum = node15 && treeMultiset.subTreeSum(15); + let subTreeSum = 0; + node15 && treeMultiset.subTreeForeach(15, (node: TreeMultisetNode) => (subTreeSum += node.key)); expect(subTreeSum).toBe(70); - const lesserSum = treeMultiset.lesserSum(10); + let lesserSum = 0; + treeMultiset.lesserOrGreaterForeach(10, CP.lt, (node: TreeMultisetNode) => (lesserSum += node.key)); expect(lesserSum).toBe(45); expect(node15 instanceof TreeMultisetNode); if (node15 instanceof TreeMultisetNode) { - const subTreeAdd = treeMultiset.subTreeAddCount(15, 1); + const subTreeAdd = treeMultiset.subTreeForeach(15, (node: TreeMultisetNode) => (node.count += 1)); expect(subTreeAdd); } const node11 = treeMultiset.get(11); expect(node11 instanceof TreeMultisetNode); if (node11 instanceof TreeMultisetNode) { - const allGreaterNodesAdded = treeMultiset.allGreaterNodesAddCount(11, 2); + const allGreaterNodesAdded = treeMultiset.lesserOrGreaterForeach( + 11, + CP.gt, + (node: TreeMultisetNode) => (node.count += 2) + ); expect(allGreaterNodesAdded); } @@ -419,13 +426,19 @@ describe('TreeMultiset operations test', () => { describe('TreeMultiset Performance test', function () { // const treeMS = new TreeMultiset>(); - // const inputSizes = [100]; // Adjust input sizes as needed + // const inputSize = [100]; // Adjust input sizes as needed // // // Define a function to calculate the expected O(n log n) time // function expectedTime(n: number): number { // return n * Math.log(n); // } + const treeMS = new TreeMultiset>(); + const inputSize = 100000; // Adjust input sizes as needed + + beforeEach(() => { + treeMS.clear(); + }); it(`Observe the time consumption of TreeMultiset.add fitting O(n log n)`, function () { // // Create a benchmark suite // const suite = new Benchmark.Suite(); @@ -437,9 +450,9 @@ describe('TreeMultiset Performance test', function () { // } // return arr; // } - // const inputArray = generateRandomArray(inputSizes[0]); + // const inputArray = generateRandomArray(inputSize[0]); // - // suite.add(`TreeMultiset addMany (n=${inputSizes[0]})`, () => { + // suite.add(`TreeMultiset addMany (n=${inputSize[0]})`, () => { // treeMS.addMany([...inputArray]); // }); // @@ -453,9 +466,26 @@ describe('TreeMultiset Performance test', function () { // console.log(`Input size (n): ${n}, Observed time: ${observedTime.toFixed(2)}ms, Expected time: ${expected.toFixed(2)}ms`); // }) // .on('complete', () => { - // console.log(`Benchmark (n=${inputSizes[0]}) completed.`); + // console.log(`Benchmark (n=${inputSize[0]}) completed.`); // done(); // Call done to indicate the test is complete // }) // .run({async: true}); }); + + it(`Observe the time consumption of TreeMultiset.dfs be good`, function () { + const startDFS = performance.now(); + const dfs = treeMS.dfs(); + isDebug && console.log('---bfs', performance.now() - startDFS, dfs.length); + }); + + it('Should the time consumption of lesserOrGreaterForeach fitting O(n log n)', function () { + const start = performance.now(); + for (let i = 0; i < inputSize; i++) { + treeMS.add(i); + } + isDebug && console.log('---add', performance.now() - start); + const startL = performance.now(); + treeMS.lesserOrGreaterForeach(inputSize / 2, CP.lt, (node: TreeMultisetNode) => (node.count += 1)); + isDebug && console.log('---lesserOrGreaterForeach', performance.now() - startL); + }); }); diff --git a/test/unit/data-structures/queue/deque.test.ts b/test/unit/data-structures/queue/deque.test.ts index 6fabba0..9e4b275 100644 --- a/test/unit/data-structures/queue/deque.test.ts +++ b/test/unit/data-structures/queue/deque.test.ts @@ -1,4 +1,5 @@ import {Deque, ArrayDeque, ObjectDeque} from '../../../../src'; +import {bigO} from '../../../utils'; describe('Deque Tests', () => { // Test cases for the Deque class (DoublyLinkedList-based) @@ -128,3 +129,19 @@ describe('Deque Tests', () => { // Add more test cases as needed }); }); + +describe('Deque Performance Test', () => { + const dataSize = 10000; + it('should numeric queue be efficient', function () { + const startTime = performance.now(); + const queue = new Deque(); + for (let i = 0; i < dataSize; i++) { + queue.unshift(i); + } + for (let i = 0; i < dataSize; i++) { + queue.pop(); + } + console.log(`Queue Deque Test: ${performance.now() - startTime} ms`); + expect(performance.now() - startTime).toBeLessThan(bigO.LINEAR * 100); + }); +}); diff --git a/test/unit/data-structures/queue/queue.test.ts b/test/unit/data-structures/queue/queue.test.ts index 2a4470a..7f35cab 100644 --- a/test/unit/data-structures/queue/queue.test.ts +++ b/test/unit/data-structures/queue/queue.test.ts @@ -197,3 +197,45 @@ describe('LinkedListQueue', () => { // Add more test cases for other methods of LinkedListQueue. }); + +describe('Queue Performance Test', () => { + const dataSize = 10000; + it('should numeric queue be efficient', function () { + const startTime = performance.now(); + const queue = new Queue(); + for (let i = 0; i < dataSize; i++) { + queue.enqueue(i); + } + for (let i = 0; i < dataSize; i++) { + queue.dequeue(); + } + console.log(`Queue Performance Test: ${performance.now() - startTime} ms`); + expect(performance.now() - startTime).toBeLessThan(bigO.LINEAR * 100); + }); + + it('should numeric Array be more efficient than Queue when the data size is 10000', function () { + const startTime2 = performance.now(); + const queue2: number[] = []; + for (let i = 0; i < dataSize; i++) { + queue2.push(i); + } + for (let i = 0; i < dataSize; i++) { + queue2.shift(); + } + console.log(`Array Performance Test: ${performance.now() - startTime2} ms`); + expect(performance.now() - startTime2).toBeLessThan(bigO.CUBED * 100); + }); + + it('should numeric LinkedListQueue be efficient', function () { + const startTime = performance.now(); + const queue = new LinkedListQueue(); + for (let i = 0; i < dataSize; i++) { + queue.enqueue(i); + } + for (let i = 0; i < dataSize; i++) { + queue.dequeue(); + } + console.log(`LinkedListQueue Performance Test: ${performance.now() - startTime} ms`); + expect(performance.now() - startTime).toBeLessThan(bigO.LINEAR * 100); + }); +}); From af7372ba30f27825a4e01f1aeb2378f08e1450de Mon Sep 17 00:00:00 2001 From: Revone Date: Sun, 22 Oct 2023 00:00:22 +0800 Subject: [PATCH 09/46] [pkg] ready to publish v1.37.0 --- CHANGELOG.md | 3 ++- package-lock.json | 36 ++++++++++++++++++------------------ package.json | 10 +++++----- test/utils/big-o.ts | 9 +++++---- 4 files changed, 30 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b31a5de..0d60600 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,10 +8,11 @@ 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.36.9](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) +## [v1.37.0](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) ### Changes +- [binary-tree, graph] Replace all code that uses Arrays as makeshift Q… [`#18`](https://github.com/zrwusa/data-structure-typed/pull/18) - 1. No need for dfsIterative; integrate it directly into the dfs metho… [`#17`](https://github.com/zrwusa/data-structure-typed/pull/17) - [heap] fibonacci heap implemented. [test] big O estimate. [project] n… [`#15`](https://github.com/zrwusa/data-structure-typed/pull/15) - [rbtree] implemented, but with bugs [`#13`](https://github.com/zrwusa/data-structure-typed/pull/13) diff --git a/package-lock.json b/package-lock.json index 34a1209..0d4a720 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "data-structure-typed", - "version": "1.36.9", + "version": "1.37.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "data-structure-typed", - "version": "1.36.9", + "version": "1.37.0", "license": "MIT", "devDependencies": { "@types/benchmark": "^2.1.3", @@ -15,17 +15,17 @@ "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", "auto-changelog": "^2.4.0", - "avl-tree-typed": "^1.36.8", + "avl-tree-typed": "^1.36.9", "benchmark": "^2.1.4", - "binary-tree-typed": "^1.36.8", - "bst-typed": "^1.36.8", + "binary-tree-typed": "^1.36.9", + "bst-typed": "^1.36.9", "dependency-cruiser": "^14.1.0", "eslint": "^8.50.0", "eslint-config-prettier": "^9.0.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.28.1", - "heap-typed": "^1.36.8", + "heap-typed": "^1.36.9", "istanbul-badges-readme": "^1.8.5", "jest": "^29.7.0", "prettier": "^3.0.3", @@ -2396,9 +2396,9 @@ } }, "node_modules/avl-tree-typed": { - "version": "1.36.8", - "resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.36.8.tgz", - "integrity": "sha512-cdzKqEFMfCE9D54wqnKvNaFn5RQI4reRcKg1CHPN2a5PicJn6uXcoULGPX9b4TKI35PJNhZ+7Blq4Y+5olsUsw==", + "version": "1.36.9", + "resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.36.9.tgz", + "integrity": "sha512-JCcrzwqotdd62ojLQZR74kTcmlgn+Y0w+Ws2l58ZzStW8dWVZUY/KybRxVJnY1XT50DTYY6RzAf1UFgj52anvw==", "dev": true, "dependencies": { "data-structure-typed": "^1.36.8" @@ -2586,9 +2586,9 @@ } }, "node_modules/binary-tree-typed": { - "version": "1.36.8", - "resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.36.8.tgz", - "integrity": "sha512-Brh3DLTcm17ZmJoDNVWG3f6aeD448ANjv5EQi19ZrwPwMddlLRdvEn08lfdheq78lzw3x2rOU7GgFA4W+fbeFw==", + "version": "1.36.9", + "resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.36.9.tgz", + "integrity": "sha512-3YBodVs6gpGkgyY7vhDL+m20G/RyRFnu5Yqgf6xYvabwoChc8Yzv+UrxMqD7CVDt2o/WvvEuC/M7U5GYSNLY2A==", "dev": true, "dependencies": { "data-structure-typed": "^1.36.8" @@ -2670,9 +2670,9 @@ } }, "node_modules/bst-typed": { - "version": "1.36.8", - "resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.36.8.tgz", - "integrity": "sha512-bjWACK4u+qXIetBrOcs8GRLucxsshnxcP8FDnPXzDr2sl84aVITvt+yQ4hpuft7t3C3Z2X2PtTp2alSiE3gquw==", + "version": "1.36.9", + "resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.36.9.tgz", + "integrity": "sha512-FAQ6KiVuF6RCakPIgZwtZ/VdfKj2gL64rO/CN6DWP0jWYWoYvsqDW3pr83PvUhjNsxLQW5q92GT17wMOmjwDog==", "dev": true, "dependencies": { "data-structure-typed": "^1.36.8" @@ -4362,9 +4362,9 @@ } }, "node_modules/heap-typed": { - "version": "1.36.8", - "resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.36.8.tgz", - "integrity": "sha512-hk/W8DIgU8jTDdD2fbjVxnYUha30DCJrkt7LDnA0V1yWiMt1/YgJOToQVodMcPh3yN25dNQLGo8MVGnonlYhZQ==", + "version": "1.36.9", + "resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.36.9.tgz", + "integrity": "sha512-Dy7W2SooiSAc3+2Kcdb7/GvJXkguUc+hz2qLKvSbdisH6z4siOoNYoVmZJjSrc11udW1JpEINK+LqjOBlLAxiw==", "dev": true, "dependencies": { "data-structure-typed": "^1.36.8" diff --git a/package.json b/package.json index 61f1290..5b20ca9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "data-structure-typed", - "version": "1.36.9", + "version": "1.37.0", "description": "Data Structures of Javascript & TypeScript. Binary Tree, BST, Graph, Heap, Priority Queue, Linked List, Queue, Deque, Stack, AVL Tree, Tree Multiset, Trie, Directed Graph, Undirected Graph, Singly Linked List, Doubly Linked List, Max Heap, Max Priority Queue, Min Heap, Min Priority Queue.", "main": "dist/index.js", "module": "lib/index.js", @@ -58,17 +58,17 @@ "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", "auto-changelog": "^2.4.0", - "avl-tree-typed": "^1.36.8", + "avl-tree-typed": "^1.36.9", "benchmark": "^2.1.4", - "binary-tree-typed": "^1.36.8", - "bst-typed": "^1.36.8", + "binary-tree-typed": "^1.36.9", + "bst-typed": "^1.36.9", "dependency-cruiser": "^14.1.0", "eslint": "^8.50.0", "eslint-config-prettier": "^9.0.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.28.1", - "heap-typed": "^1.36.8", + "heap-typed": "^1.36.9", "istanbul-badges-readme": "^1.8.5", "jest": "^29.7.0", "prettier": "^3.0.3", diff --git a/test/utils/big-o.ts b/test/utils/big-o.ts index 9c40770..e9082a8 100644 --- a/test/utils/big-o.ts +++ b/test/utils/big-o.ts @@ -1,5 +1,6 @@ import {AnyFunction} from '../types'; +const isDebug = false; const orderReducedBy = 2; // reduction of bigO's order compared to the baseline bigO export const magnitude = { @@ -148,12 +149,12 @@ export function logBigOMetricsWrap(fn: F, args: Parameter methodLog.push([runTime, maxDataSize]); if (methodLog.length >= 20) { - console.log('triggered', methodName, methodLog); + isDebug && console.log('triggered', methodName, methodLog); const bigO = estimateBigO( methodLog.map(([runTime]) => runTime), methodLog.map(([runTime]) => runTime) ); - console.log(`Estimated Big O: ${bigO}`); + isDebug && console.log(`Estimated Big O: ${bigO}`); methodLogs.delete(methodName); } } @@ -182,12 +183,12 @@ export function logBigOMetrics(target: any, propertyKey: string, descriptor: Pro methodLog.push([runTime, maxDataSize]); if (methodLog.length >= 20) { - console.log('triggered', methodName, methodLog); + isDebug && console.log('triggered', methodName, methodLog); const bigO = estimateBigO( methodLog.map(([runTime]) => runTime), methodLog.map(([runTime]) => runTime) ); - console.log(`Estimated Big O: ${bigO}`); + isDebug && console.log(`Estimated Big O: ${bigO}`); methodLogs.delete(methodName); } } From 0417ee50099877dfda209e78400a10d1ac88625a Mon Sep 17 00:00:00 2001 From: Revone Date: Mon, 23 Oct 2023 03:02:12 +0800 Subject: [PATCH 10/46] [binary-tree] Translate all traversal methods into callback function forms to enhance API convenience and readability. --- .../binary-tree/binary-tree.ts | 538 +++--------------- src/data-structures/binary-tree/bst.ts | 72 ++- .../binary-tree/tree-multiset.ts | 86 +-- src/data-structures/heap/heap.ts | 2 +- src/types/data-structures/binary-tree.ts | 4 + src/types/data-structures/index.ts | 3 + .../binary-tree/avl-tree.test.ts | 21 +- .../binary-tree/binary-tree.test.ts | 2 +- .../data-structures/binary-tree/bst.test.ts | 74 ++- .../binary-tree/overall.test.ts | 3 +- .../binary-tree/rb-tree.test.ts | 10 +- .../binary-tree/tree-multiset.test.ts | 37 +- 12 files changed, 235 insertions(+), 617 deletions(-) diff --git a/src/data-structures/binary-tree/binary-tree.ts b/src/data-structures/binary-tree/binary-tree.ts index 8f4037f..e49f9e2 100644 --- a/src/data-structures/binary-tree/binary-tree.ts +++ b/src/data-structures/binary-tree/binary-tree.ts @@ -7,19 +7,19 @@ */ import type { + BFSCallback, + BFSCallbackReturn, BinaryTreeNodeKey, BinaryTreeNodeNested, - BinaryTreeNodeProperties, - BinaryTreeNodeProperty, - BinaryTreeOptions + BinaryTreeOptions, + MapCallback, + MapCallbackReturn } from '../../types'; import { BinaryTreeDeletedResult, - BinaryTreeNodePropertyName, DFSOrderPattern, FamilyPosition, - LoopType, - NodeOrPropertyName + LoopType } from '../../types'; import {IBinaryTree} from '../../interfaces'; import {trampoline} from '../../utils'; @@ -127,6 +127,7 @@ export class BinaryTree = BinaryTreeNode> createNode(key: BinaryTreeNodeKey, val?: N['val']): N { return new BinaryTreeNode(key, val) as N; } + // TODO placeholder node may need redesigned private _root: N | null = null; @@ -150,12 +151,6 @@ export class BinaryTree = BinaryTreeNode> this._loopType = v; } - visitedKey: BinaryTreeNodeKey[] = []; - - visitedVal: N['val'][] = []; - - visitedNode: N[] = []; - /** * The `_swap` function swaps the location of two nodes in a binary tree. * @param {N} srcNode - The source node that you want to _swap with the destination node. @@ -184,7 +179,6 @@ export class BinaryTree = BinaryTreeNode> clear() { this._root = null; this._size = 0; - this._clearResults(); } /** @@ -237,7 +231,7 @@ export class BinaryTree = BinaryTreeNode> return; } - const existNode = keyOrNode ? this.get(keyOrNode, 'key') : undefined; + const existNode = keyOrNode ? this.get(keyOrNode, this._defaultCallbackByKey) : undefined; if (this.root) { if (existNode) { @@ -360,8 +354,8 @@ export class BinaryTree = BinaryTreeNode> * @returns the depth of the given node or binary tree. */ getDepth(distNode: N | BinaryTreeNodeKey | null, beginRoot: N | BinaryTreeNodeKey | null = this.root): number { - if (typeof distNode === 'number') distNode = this.get(distNode, 'key'); - if (typeof beginRoot === 'number') beginRoot = this.get(beginRoot, 'key'); + if (typeof distNode === 'number') distNode = this.get(distNode); + if (typeof beginRoot === 'number') beginRoot = this.get(beginRoot); let depth = 0; while (distNode?.parent) { if (distNode === beginRoot) { @@ -381,7 +375,7 @@ export class BinaryTree = BinaryTreeNode> * @returns the height of the binary tree. */ getHeight(beginRoot: N | BinaryTreeNodeKey | null = this.root): number { - if (typeof beginRoot === 'number') beginRoot = this.get(beginRoot, 'key'); + if (typeof beginRoot === 'number') beginRoot = this.get(beginRoot); if (!beginRoot) return -1; if (this._loopType === LoopType.RECURSIVE) { @@ -419,6 +413,8 @@ export class BinaryTree = BinaryTreeNode> } } + protected _defaultCallbackByKey: MapCallback = node => node.key; + /** * The `getMinHeight` function calculates the minimum height of a binary tree using either a recursive or iterative * approach. @@ -482,125 +478,108 @@ export class BinaryTree = BinaryTreeNode> /** * The function `getNodes` returns an array of nodes that match a given property name and value in a binary tree. + * @param callback * @param {BinaryTreeNodeKey | N} nodeProperty - The `nodeProperty` parameter can be either a `BinaryTreeNodeKey` or a * generic type `N`. It represents the property of the binary tree node that you want to search for. - * @param {BinaryTreeNodePropertyName} [propertyName] - The `propertyName` parameter is an optional parameter that * specifies the property name to use when searching for nodes. If not provided, it defaults to 'key'. * @param {boolean} [onlyOne] - The `onlyOne` parameter is an optional boolean parameter that determines whether to * return only one node that matches the given `nodeProperty` or `propertyName`. If `onlyOne` is set to `true`, the * function will stop traversing the tree and return the first matching node. If `only + * @param beginRoot * @returns an array of nodes (type N). */ getNodes( nodeProperty: BinaryTreeNodeKey | N, - propertyName: BinaryTreeNodePropertyName = 'key', - onlyOne = false + callback: MapCallback = this._defaultCallbackByKey, + onlyOne = false, + beginRoot: N | null = this.root ): N[] { - if (!this.root) return []; + if (!beginRoot) return []; - const result: N[] = []; + const ans: N[] = []; if (this.loopType === LoopType.RECURSIVE) { const _traverse = (cur: N) => { - if (this._pushByPropertyNameStopOrNot(cur, result, nodeProperty, propertyName, onlyOne)) return; + if (callback(cur) === nodeProperty) { + ans.push(cur); + if (onlyOne) return; + } if (!cur.left && !cur.right) return; cur.left && _traverse(cur.left); cur.right && _traverse(cur.right); }; - _traverse(this.root); + _traverse(beginRoot); } else { - const queue = new Queue([this.root]); + const queue = new Queue([beginRoot]); while (queue.size > 0) { const cur = queue.shift(); if (cur) { - if (this._pushByPropertyNameStopOrNot(cur, result, nodeProperty, propertyName, onlyOne)) return result; + if (callback(cur) === nodeProperty) { + ans.push(cur); + if (onlyOne) return ans; + } cur.left && queue.push(cur.left); cur.right && queue.push(cur.right); } } } - return result; + return ans; } /** * The function checks if a binary tree node has a specific property. + * @param callback - The `callback` parameter is a function that takes a node as a parameter and returns a value. * @param {BinaryTreeNodeKey | N} nodeProperty - The `nodeProperty` parameter can be either a `BinaryTreeNodeKey` or `N`. * It represents the property of the binary tree node that you want to check. - * @param {BinaryTreeNodePropertyName} [propertyName] - The `propertyName` parameter is an optional parameter that * specifies the name of the property to be checked in the nodes. If not provided, it defaults to 'key'. * @returns a boolean value. */ - has(nodeProperty: BinaryTreeNodeKey | N, propertyName: BinaryTreeNodePropertyName = 'key'): boolean { + has(nodeProperty: BinaryTreeNodeKey | N, callback: MapCallback = this._defaultCallbackByKey): boolean { // TODO may support finding node by value equal - return this.getNodes(nodeProperty, propertyName).length > 0; + return this.getNodes(nodeProperty, callback, true).length > 0; } /** * The function returns the first node that matches the given property name and value, or null if no matching node is * found. + * @param callback - The `callback` parameter is a function that takes a node as a parameter and returns a value. * @param {BinaryTreeNodeKey | N} nodeProperty - The `nodeProperty` parameter can be either a `BinaryTreeNodeKey` or `N`. * It represents the property of the binary tree node that you want to search for. - * @param {BinaryTreeNodePropertyName} [propertyName] - The `propertyName` parameter is an optional parameter that * specifies the property name to be used for searching the binary tree nodes. If this parameter is not provided, the * default value is set to `'key'`. * @returns either the value of the specified property of the node, or the node itself if no property name is provided. * If no matching node is found, it returns null. */ - get(nodeProperty: BinaryTreeNodeKey | N, propertyName: BinaryTreeNodePropertyName = 'key'): N | null { + get(nodeProperty: BinaryTreeNodeKey | N, callback: MapCallback = this._defaultCallbackByKey): N | null { // TODO may support finding node by value equal - return this.getNodes(nodeProperty, propertyName, true)[0] ?? null; + return this.getNodes(nodeProperty, callback, true)[0] ?? null; } /** * The function `getPathToRoot` returns an array of nodes representing the path from a given node to the root node, with * an option to reverse the order of the nodes. - * @param {N} node - The `node` parameter represents a node in a tree structure. It is of type `N`, which could be any * type that represents a node in your specific implementation. + * @param beginRoot - The `beginRoot` parameter is of type `N` and represents the starting node from which you want to * @param {boolean} [isReverse=true] - The `isReverse` parameter is a boolean flag that determines whether the resulting * path should be reversed or not. If `isReverse` is set to `true`, the path will be reversed before returning it. If * `isReverse` is set to `false` or not provided, the path will * @returns The function `getPathToRoot` returns an array of nodes (`N[]`). */ - getPathToRoot(node: N, isReverse = true): N[] { + getPathToRoot(beginRoot: N, isReverse = true): N[] { // TODO to support get path through passing key const result: N[] = []; - while (node.parent) { + while (beginRoot.parent) { // Array.push + Array.reverse is more efficient than Array.unshift // TODO may consider using Deque, so far this is not the performance bottleneck - result.push(node); - node = node.parent; + result.push(beginRoot); + beginRoot = beginRoot.parent; } - result.push(node); + result.push(beginRoot); return isReverse ? result.reverse() : result; } - /** - * The function `getLeftMost` returns the leftmost node in a binary tree, starting from a specified node or the root if - * no node is specified. - * generic type representing a node in a binary tree, `BinaryTreeNodeKey` (a type representing the ID of a binary tree - * node), or `null`. - * @returns The function `getLeftMost` returns the leftmost node in a binary tree. If the `beginRoot` parameter is - * provided, it starts the traversal from that node. If `beginRoot` is not provided or is `null`, it starts the traversal - * from the root of the binary tree. The function returns the leftmost node found during the traversal. If no leftmost - * node is found ( - */ - getLeftMost(): N | null; - - /** - * The function `getLeftMost` returns the leftmost node in a binary tree, starting from a specified node or the root if - * no node is specified. - * @param {N | BinaryTreeNodeKey | null} [node] - The `beginRoot` parameter is optional and can be of type `N` (a - * generic type representing a node in a binary tree), `BinaryTreeNodeKey` (a type representing the ID of a binary tree - * node). - * @returns The function `getLeftMost` returns the leftmost node in a binary tree. If the `beginRoot` parameter is - * provided, it starts the traversal from that node. If `beginRoot` is not provided or is `null`, it starts the traversal - * from the root of the binary tree. The function returns the leftmost node found during the traversal. If no leftmost - * node is found ( - */ - getLeftMost(node: N): N; - /** * The function `getLeftMost` returns the leftmost node in a binary tree, starting from a specified node or the root if * no node is specified. @@ -613,7 +592,7 @@ export class BinaryTree = BinaryTreeNode> * node is found ( */ getLeftMost(beginRoot: N | BinaryTreeNodeKey | null = this.root): N | null { - if (typeof beginRoot === 'number') beginRoot = this.get(beginRoot, 'key'); + if (typeof beginRoot === 'number') beginRoot = this.get(beginRoot); if (!beginRoot) return beginRoot; @@ -635,25 +614,6 @@ export class BinaryTree = BinaryTreeNode> } } - /** - * The `getRightMost` function returns the rightmost node in a binary tree, either recursively or iteratively using tail - * recursion optimization. - * @returns The `getRightMost` function returns the rightmost node in a binary tree. It returns the - * rightmost node starting from the root of the binary tree. - */ - getRightMost(): N | null; - - /** - * The `getRightMost` function returns the rightmost node in a binary tree, either recursively or iteratively using tail - * recursion optimization. - * @param {N | null} [beginRoot] - The `node` parameter is an optional parameter of type `N` or `null`. It represents the - * starting node from which we want to find the rightmost node. If no node is provided, the function will default to - * using the root node of the data structure. - * @returns The `getRightMost` function returns the rightmost node in a binary tree. It returns the rightmost node - * starting from that node. - */ - getRightMost(beginRoot: N): N; - /** * The `getRightMost` function returns the rightmost node in a binary tree, either recursively or iteratively using tail * recursion optimization. @@ -730,55 +690,25 @@ export class BinaryTree = BinaryTreeNode> } /** - * The function calculates the size of a subtree by traversing it either recursively or iteratively. - * @param {N | null | undefined} subTreeRoot - The `subTreeRoot` parameter represents the root node of a subtree in a - * binary tree. - * @returns the size of the subtree rooted at `subTreeRoot`. - */ - getSubTreeSize(subTreeRoot: N | null | undefined) { - // TODO support key passed in - let size = 0; - if (!subTreeRoot) return size; - - if (this._loopType === LoopType.RECURSIVE) { - const _traverse = (cur: N) => { - size++; - cur.left && _traverse(cur.left); - cur.right && _traverse(cur.right); - }; - - _traverse(subTreeRoot); - return size; - } else { - const stack: N[] = [subTreeRoot]; - - while (stack.length > 0) { - const cur = stack.pop()!; - size++; - cur.right && stack.push(cur.right); - cur.left && stack.push(cur.left); - } - - return size; - } - } - - /** - * The function `subTreeForeach` adds a delta value to a specified property of each node in a subtree. + * The function `subTreeTraverse` adds a delta value to a specified property of each node in a subtree. * @param {N | BinaryTreeNodeKey | null} subTreeRoot - The `subTreeRoot` parameter represents the root node of a binary * tree or the ID of a node in the binary tree. It can also be `null` if there is no subtree to add to. * @param callback - The `callback` parameter is a function that takes a node as a parameter and returns a value. * specifies the property of the binary tree node that should be modified. If not provided, it defaults to 'key'. * @returns a boolean value. */ - subTreeForeach(subTreeRoot: N | BinaryTreeNodeKey | null, callback: (node: N) => any): boolean { - if (typeof subTreeRoot === 'number') subTreeRoot = this.get(subTreeRoot, 'key'); + subTreeTraverse( + callback: MapCallback = this._defaultCallbackByKey, + subTreeRoot: N | BinaryTreeNodeKey | null = this.root + ): MapCallbackReturn[] { + if (typeof subTreeRoot === 'number') subTreeRoot = this.get(subTreeRoot); - if (!subTreeRoot) return false; + const ans: MapCallbackReturn[] = []; + if (!subTreeRoot) return ans; if (this._loopType === LoopType.RECURSIVE) { const _traverse = (cur: N) => { - callback(cur); + ans.push(callback(cur)); cur.left && _traverse(cur.left); cur.right && _traverse(cur.right); }; @@ -790,150 +720,64 @@ export class BinaryTree = BinaryTreeNode> while (stack.length > 0) { const cur = stack.pop()!; - callback(cur); + ans.push(callback(cur)); cur.right && stack.push(cur.right); cur.left && stack.push(cur.left); } } - return true; + return ans; } - /** - * Performs a breadth-first search (bfs) on a binary tree, accumulating properties of each node based on their 'key' property. - * @returns An array of binary tree node IDs. - */ - bfs(): BinaryTreeNodeKey[]; - - /** - * Performs a breadth-first search (bfs) on a binary tree, accumulating properties of each node based on the specified property name. - * @param {'key'} nodeOrPropertyName - The name of the property to accumulate. - * @returns An array of values corresponding to the specified property. - */ - bfs(nodeOrPropertyName: 'key'): BinaryTreeNodeKey[]; - - /** - * Performs a breadth-first search (bfs) on a binary tree, accumulating the 'val' property of each node. - * @param {'val'} nodeOrPropertyName - The name of the property to accumulate. - * @returns An array of 'val' properties from each node. - */ - bfs(nodeOrPropertyName: 'val'): N['val'][]; - - /** - * Performs a breadth-first search (bfs) on a binary tree, accumulating nodes themselves. - * @param {'node'} nodeOrPropertyName - The name of the property to accumulate. - * @returns An array of binary tree nodes. - */ - bfs(nodeOrPropertyName: 'node'): N[]; - - /** - * The bfs function performs a breadth-first search on a binary tree, accumulating properties of each node based on a specified property name. - * @param {NodeOrPropertyName} [nodeOrPropertyName] - An optional parameter that represents either a node or a property name. - * If a node is provided, the bfs algorithm will be performed starting from that node. - * If a property name is provided, the bfs algorithm will be performed starting from the root node, accumulating the specified property. - * @returns An instance of the `BinaryTreeNodeProperties` class with generic type `N`. - */ - bfs(nodeOrPropertyName: NodeOrPropertyName = 'key'): BinaryTreeNodeProperties { - this._clearResults(); - const queue = new Queue([this.root]); - - while (queue.size !== 0) { - const cur = queue.shift(); - if (cur) { - this._accumulatedByPropertyName(cur, nodeOrPropertyName); - if (cur?.left !== null) queue.push(cur.left); - if (cur?.right !== null) queue.push(cur.right); - } - } - - return this._getResultByPropertyName(nodeOrPropertyName); - } - - /** - * Performs a depth-first search (dfs) traversal on a binary tree and accumulates properties of each node based on their 'key' property. - * @returns An array of binary tree node IDs. - */ - dfs(): BinaryTreeNodeKey[]; - - /** - * Performs a depth-first search (dfs) traversal on a binary tree and accumulates properties of each node based on the specified property name. - * @param {'in' | 'pre' | 'post'} [pattern] - The traversal pattern: 'in' (in-order), 'pre' (pre-order), or 'post' (post-order). - * @returns An array of values corresponding to the specified property. - */ - dfs(pattern: DFSOrderPattern): BinaryTreeNodeKey[]; - - /** - * Performs a depth-first search (dfs) traversal on a binary tree and accumulates properties of each node based on the specified property name. - * @param {'in' | 'pre' | 'post'} [pattern] - The traversal pattern: 'in' (in-order), 'pre' (pre-order), or 'post' (post-order). - * @param {string} nodeOrPropertyName - The name of the property to accumulate. - * @param loopType - The type of loop to use for the depth-first search traversal. The default value is `LoopType.ITERATIVE`. - * @returns An array of values corresponding to the specified property. - */ - dfs(pattern: DFSOrderPattern, nodeOrPropertyName: 'key', loopType?: LoopType): BinaryTreeNodeKey[]; - - /** - * Performs a depth-first search (dfs) traversal on a binary tree and accumulates the 'val' property of each node. - * @param {'in' | 'pre' | 'post'} [pattern] - The traversal pattern: 'in' (in-order), 'pre' (pre-order), or 'post' (post-order). - * @param {'val'} nodeOrPropertyName - The name of the property to accumulate. - * @param loopType - The type of loop to use for the depth-first search traversal. The default value is `LoopType.ITERATIVE`. - * @returns An array of 'val' properties from each node. - */ - dfs(pattern: DFSOrderPattern, nodeOrPropertyName: 'val', loopType?: LoopType): N[]; - - /** - * Performs a depth-first search (dfs) traversal on a binary tree and accumulates nodes themselves. - * @param {'in' | 'pre' | 'post'} [pattern] - The traversal pattern: 'in' (in-order), 'pre' (pre-order), or 'post' (post-order). - * @param {'node'} nodeOrPropertyName - The name of the property to accumulate. - * @param loopType - The type of loop to use for the depth-first search traversal. The default value is `LoopType.ITERATIVE`. - * @returns An array of binary tree nodes. - */ - dfs(pattern: DFSOrderPattern, nodeOrPropertyName: 'node', loopType?: LoopType): N[]; - /** * The dfs function performs a depth-first search traversal on a binary tree and returns the accumulated properties of * each node based on the specified pattern and property name. + * @param callback + * @param beginRoot - The `beginRoot` parameter is an optional parameter of type `N` or `null`. It represents the * @param {'in' | 'pre' | 'post'} [pattern] - The traversal pattern: 'in' (in-order), 'pre' (pre-order), or 'post' (post-order). - * @param {NodeOrPropertyName} [nodeOrPropertyName] - The name of a property of the nodes in the binary tree. This property will be used to accumulate values during the depth-first search traversal. If no `nodeOrPropertyName` is provided, the default value is `'key'`. * @param loopType - The type of loop to use for the depth-first search traversal. The default value is `LoopType.ITERATIVE`. * @returns an instance of the BinaryTreeNodeProperties class, which contains the accumulated properties of the binary tree nodes based on the specified pattern and node or property name. */ dfs( + callback: MapCallback = this._defaultCallbackByKey, pattern: DFSOrderPattern = 'in', - nodeOrPropertyName: NodeOrPropertyName = 'key', + beginRoot: N | null = this.root, loopType: LoopType = LoopType.ITERATIVE - ): BinaryTreeNodeProperties { - this._clearResults(); + ): MapCallbackReturn[] { + if (!beginRoot) return []; + const ans: MapCallbackReturn[] = []; if (loopType === LoopType.RECURSIVE) { const _traverse = (node: N) => { switch (pattern) { case 'in': if (node.left) _traverse(node.left); - this._accumulatedByPropertyName(node, nodeOrPropertyName); + ans.push(callback(node)); if (node.right) _traverse(node.right); break; case 'pre': - this._accumulatedByPropertyName(node, nodeOrPropertyName); + ans.push(callback(node)); + if (node.left) _traverse(node.left); if (node.right) _traverse(node.right); break; case 'post': if (node.left) _traverse(node.left); if (node.right) _traverse(node.right); - this._accumulatedByPropertyName(node, nodeOrPropertyName); + ans.push(callback(node)); + break; } }; - this.root && _traverse(this.root); + _traverse(beginRoot); } else { - if (!this.root) return this._getResultByPropertyName(nodeOrPropertyName); // 0: visit, 1: print - const stack: {opt: 0 | 1; node: N | null | undefined}[] = [{opt: 0, node: this.root}]; + const stack: {opt: 0 | 1; node: N | null | undefined}[] = [{opt: 0, node: beginRoot}]; while (stack.length > 0) { const cur = stack.pop(); if (!cur || !cur.node) continue; if (cur.opt === 1) { - this._accumulatedByPropertyName(cur.node, nodeOrPropertyName); + ans.push(callback(cur.node)); } else { switch (pattern) { case 'in': @@ -961,83 +805,30 @@ export class BinaryTree = BinaryTreeNode> } } - return this._getResultByPropertyName(nodeOrPropertyName); + return ans; } // --- start additional methods --- - /** - * Collects nodes from a binary tree by a specified property and organizes them into levels. - * @returns A 2D array of AbstractBinaryTreeNodeProperty objects. - */ - listLevels(): BinaryTreeNodeKey[][]; - - /** - * Collects nodes from a binary tree by a specified property and organizes them into levels. - * @param {N | null} node - The root node of the binary tree or null. If null, the function will use the root node of the current binary tree instance. - * @returns A 2D array of AbstractBinaryTreeNodeProperty objects. - */ - listLevels(node: N | null): BinaryTreeNodeKey[][]; - - /** - * Collects nodes from a binary tree by a specified property and organizes them into levels. - * @param {N | null} node - The root node of the binary tree or null. If null, the function will use the root node of the current binary tree instance. - * @param {'key} nodeOrPropertyName - The property of the BinaryTreeNode object to collect at each level. - * @returns A 2D array of values corresponding to the specified property. - */ - listLevels(node: N | null, nodeOrPropertyName: 'key'): BinaryTreeNodeKey[][]; - - /** - * Collects nodes from a binary tree by a specified property and organizes them into levels. - * @param {N | null} node - The root node of the binary tree or null. If null, the function will use the root node of the current binary tree instance. - * @param {'val'} nodeOrPropertyName - The property of the BinaryTreeNode object to collect at each level. - * @returns A 2D array of 'val' properties from each node. - */ - listLevels(node: N | null, nodeOrPropertyName: 'val'): N['val'][][]; - - /** - * Collects nodes from a binary tree by a specified property and organizes them into levels. - * @param {N | null} node - The root node of the binary tree or null. If null, the function will use the root node of the current binary tree instance. - * @param {'node'} nodeOrPropertyName - The property of the BinaryTreeNode object to collect at each level. - * @returns A 2D array of binary tree nodes. - */ - listLevels(node: N | null, nodeOrPropertyName: 'node'): N[][]; - /** * The `listLevels` function collects nodes from a binary tree by a specified property and organizes them into levels. * @param {N | null} node - The `node` parameter is a BinaryTreeNode object or null. It represents the root node of a binary tree. If it is null, the function will use the root node of the current binary tree instance. - * @param {NodeOrPropertyName} [nodeOrPropertyName] - The `nodeOrPropertyName` parameter is an optional parameter that specifies the property of the `BinaryTreeNode` object to collect at each level. It can be one of the following values: 'key', 'val', or 'node'. If not provided, it defaults to 'key'. - * @returns A 2D array of `AbstractBinaryTreeNodeProperty` objects. + * @param callback - The `callback` parameter is a function that takes a node and a level as parameters and returns a value. + * @param withLevel - The `withLevel` parameter is a boolean flag that determines whether to include the level of each node in the result. If `withLevel` is set to `true`, the function will include the level of each node in the result. If `withLevel` is set to `false` or not provided, the function will not include the level of each node in the result. */ - listLevels( - node: N | null = this.root, - nodeOrPropertyName: NodeOrPropertyName = 'key' - ): BinaryTreeNodeProperty[][] { + bfs( + callback: BFSCallback = this._defaultCallbackByKey, + withLevel: boolean = false, + node?: N | null + ): BFSCallbackReturn[] { + if (!node) node = this.root; if (!node) return []; - const levelsNodes: BinaryTreeNodeProperty[][] = []; - - const collectByProperty = (node: N, level: number) => { - switch (nodeOrPropertyName) { - case 'key': - levelsNodes[level].push(node.key); - break; - case 'val': - levelsNodes[level].push(node.val); - break; - case 'node': - levelsNodes[level].push(node); - break; - default: - levelsNodes[level].push(node.key); - break; - } - }; + const ans: BFSCallbackReturn[] = []; if (this.loopType === LoopType.RECURSIVE) { const _recursive = (node: N, level: number) => { - if (!levelsNodes[level]) levelsNodes[level] = []; - collectByProperty(node, level); + callback && ans.push(callback(node, withLevel ? level : undefined)); if (node.left) _recursive(node.left, level + 1); if (node.right) _recursive(node.right, level + 1); }; @@ -1050,14 +841,12 @@ export class BinaryTree = BinaryTreeNode> const head = stack.pop()!; const [node, level] = head; - if (!levelsNodes[level]) levelsNodes[level] = []; - collectByProperty(node, level); + callback && ans.push(callback(node, withLevel ? level : undefined)); if (node.right) stack.push([node.right, level + 1]); if (node.left) stack.push([node.left, level + 1]); } } - - return levelsNodes; + return ans; } /** @@ -1084,53 +873,18 @@ export class BinaryTree = BinaryTreeNode> * Space complexity of Iterative dfs equals to recursive dfs which is O(n) because of the stack */ - /** - * Performs an in-order, pre-order, or post-order traversal on a binary tree using the Morris traversal algorithm. - * @returns An array of binary tree node IDs. - */ - morris(): BinaryTreeNodeKey[]; - - /** - * Performs an in-order, pre-order, or post-order traversal on a binary tree using the Morris traversal algorithm and accumulates properties of each node based on the specified property name. - * @param {'in' | 'pre' | 'post'} [pattern] - The traversal pattern: 'in' (in-order), 'pre' (pre-order), or 'post' (post-order). - * @param {'key'} nodeOrPropertyName - The name of the property to accumulate. - * @returns An array of values corresponding to the specified property. - */ - morris(pattern: DFSOrderPattern, nodeOrPropertyName: 'key'): BinaryTreeNodeKey[]; - - /** - * Performs an in-order, pre-order, or post-order traversal on a binary tree using the Morris traversal algorithm and accumulates properties of each node based on the specified property name. - * @param {'in' | 'pre' | 'post'} [pattern] - The traversal pattern: 'in' (in-order), 'pre' (pre-order), or 'post' (post-order). - * @returns An array of values corresponding to the specified property. - */ - morris(pattern: DFSOrderPattern): BinaryTreeNodeKey[]; - - /** - * Performs an in-order, pre-order, or post-order traversal on a binary tree using the Morris traversal algorithm and accumulates the 'val' property of each node. - * @param {'in' | 'pre' | 'post'} [pattern] - The traversal pattern: 'in' (in-order), 'pre' (pre-order), or 'post' (post-order). - * @param {'val'} nodeOrPropertyName - The property of the BinaryTreeNode object to collect at each level. - * @returns An array of 'val' properties from each node. - */ - morris(pattern: DFSOrderPattern, nodeOrPropertyName: 'val'): N[]; - - /** - * Performs an in-order, pre-order, or post-order traversal on a binary tree using the Morris traversal algorithm and accumulates nodes themselves. - * @param {'in' | 'pre' | 'post'} [pattern] - The traversal pattern: 'in' (in-order), 'pre' (pre-order), or 'post' (post-order). - * @param {'node'} nodeOrPropertyName - The property of the BinaryTreeNode object to collect at each level. - * @returns An array of binary tree nodes. - */ - morris(pattern: DFSOrderPattern, nodeOrPropertyName: 'node'): N[]; - /** * The `morris` function performs an in-order, pre-order, or post-order traversal on a binary tree using the Morris traversal algorithm. * @param {'in' | 'pre' | 'post'} [pattern] - The traversal pattern: 'in' (in-order), 'pre' (pre-order), or 'post' (post-order). - * @param {NodeOrPropertyName} [nodeOrPropertyName] - The property name of the nodes to retrieve or perform operations on during the traversal. It can be any valid property name of the nodes in the binary tree. If not provided, it defaults to 'key'. + * @param callback - The `callback` parameter is a function that takes a node as a parameter and returns a value. * @returns An array of BinaryTreeNodeProperties objects. */ - morris(pattern: DFSOrderPattern = 'in', nodeOrPropertyName: NodeOrPropertyName = 'key'): BinaryTreeNodeProperties { + morris( + callback: MapCallback = this._defaultCallbackByKey, + pattern: DFSOrderPattern = 'in' + ): MapCallbackReturn[] { if (this.root === null) return []; - - this._clearResults(); + const ans: MapCallbackReturn[] = []; let cur: N | null | undefined = this.root; const _reverseEdge = (node: N | null | undefined) => { @@ -1148,7 +902,7 @@ export class BinaryTree = BinaryTreeNode> const tail: N | null | undefined = _reverseEdge(node); let cur: N | null | undefined = tail; while (cur) { - this._accumulatedByPropertyName(cur, nodeOrPropertyName); + ans.push(callback(cur)); cur = cur.right; } _reverseEdge(tail); @@ -1166,7 +920,7 @@ export class BinaryTree = BinaryTreeNode> predecessor.right = null; } } - this._accumulatedByPropertyName(cur, nodeOrPropertyName); + ans.push(callback(cur)); cur = cur.right; } break; @@ -1176,14 +930,14 @@ export class BinaryTree = BinaryTreeNode> const predecessor = this.getPredecessor(cur); if (!predecessor.right) { predecessor.right = cur; - this._accumulatedByPropertyName(cur, nodeOrPropertyName); + ans.push(callback(cur)); cur = cur.left; continue; } else { predecessor.right = null; } } else { - this._accumulatedByPropertyName(cur, nodeOrPropertyName); + ans.push(callback(cur)); } cur = cur.right; } @@ -1206,8 +960,7 @@ export class BinaryTree = BinaryTreeNode> _printEdge(this.root); break; } - - return this._getResultByPropertyName(nodeOrPropertyName); + return ans; } /** @@ -1264,108 +1017,5 @@ export class BinaryTree = BinaryTreeNode> this._size = v; } - /** - * The function `_clearResults` resets the values of several arrays used for tracking visited nodes and their - * properties. - */ - protected _clearResults() { - this.visitedKey = []; - this.visitedVal = []; - this.visitedNode = []; - } - - /** - * The function checks if a given property of a binary tree node matches a specified value, and if so, adds the node to - * a result array. - * @param {N} cur - The current node being processed. - * @param {(N | null | undefined)[]} result - An array that stores the matching nodes. - * @param {BinaryTreeNodeKey | N} nodeProperty - The `nodeProperty` parameter is either a `BinaryTreeNodeKey` or a `N` - * type. It represents the property value that we are comparing against in the switch statement. - * @param {BinaryTreeNodePropertyName} [propertyName] - The `propertyName` parameter is an optional parameter that - * specifies the property name to compare against when pushing nodes into the `result` array. It can be either `'key'` - * or `'val'`. If it is not provided or is not equal to `'key'` or `'val'`, the - * @param {boolean} [onlyOne] - The `onlyOne` parameter is an optional boolean parameter that determines whether to - * stop after finding the first matching node or continue searching for all matching nodes. If `onlyOne` is set to - * `true`, the function will stop after finding the first matching node and return `true`. If `onlyOne - * @returns a boolean value indicating whether only one matching node should be pushed into the result array. - */ - protected _pushByPropertyNameStopOrNot( - cur: N, - result: (N | null | undefined)[], - nodeProperty: BinaryTreeNodeKey | N, - propertyName: BinaryTreeNodePropertyName = 'key', - onlyOne = false - ) { - switch (propertyName) { - case 'key': - if (cur.key === nodeProperty) { - result.push(cur); - return onlyOne; - } - break; - case 'val': - if (cur.val === nodeProperty) { - result.push(cur); - return onlyOne; - } - break; - default: - if (cur.key === nodeProperty) { - result.push(cur); - return onlyOne; - } - break; - } - } - - /** - * The function `_accumulatedByPropertyName` accumulates values from a given node based on the specified property name. - * @param {N} node - The `node` parameter is of type `N`, which represents a node in a data structure. - * @param {NodeOrPropertyName} [nodeOrPropertyName] - The `nodeOrPropertyName` parameter is an optional parameter that - * can be either a string representing a property name or a reference to a `Node` object. If it is a string, it - * specifies the property name to be used for accumulating values. If it is a `Node` object, it specifies - */ - protected _accumulatedByPropertyName(node: N, nodeOrPropertyName: NodeOrPropertyName = 'key') { - switch (nodeOrPropertyName) { - case 'key': - this.visitedKey.push(node.key); - break; - case 'val': - this.visitedVal.push(node.val); - break; - case 'node': - this.visitedNode.push(node); - break; - default: - this.visitedKey.push(node.key); - break; - } - } - - /** - * The time complexity of Morris traversal is O(n), it may slower than others - * The space complexity Morris traversal is O(1) because no using stack - */ - - /** - * The function `_getResultByPropertyName` returns the corresponding property value based on the given node or property - * name. - * @param {NodeOrPropertyName} [nodeOrPropertyName] - The parameter `nodeOrPropertyName` is an optional parameter that - * can accept either a `NodeOrPropertyName` type or be undefined. - * @returns The method `_getResultByPropertyName` returns an instance of `BinaryTreeNodeProperties`. - */ - protected _getResultByPropertyName(nodeOrPropertyName: NodeOrPropertyName = 'key'): BinaryTreeNodeProperties { - switch (nodeOrPropertyName) { - case 'key': - return this.visitedKey; - case 'val': - return this.visitedVal; - case 'node': - return this.visitedNode; - default: - return this.visitedKey; - } - } - // --- end additional methods --- } diff --git a/src/data-structures/binary-tree/bst.ts b/src/data-structures/binary-tree/bst.ts index c4b49ed..e5ae80c 100644 --- a/src/data-structures/binary-tree/bst.ts +++ b/src/data-structures/binary-tree/bst.ts @@ -7,10 +7,11 @@ */ import type { BinaryTreeNodeKey, - BinaryTreeNodePropertyName, BSTComparator, BSTNodeNested, - BSTOptions + BSTOptions, + MapCallback, + MapCallbackReturn } from '../../types'; import {CP, LoopType} from '../../types'; import {BinaryTree, BinaryTreeNode} from './binary-tree'; @@ -211,12 +212,12 @@ export class BST = BSTNode> extends BinaryTree * The function returns the first node in a binary tree that matches the given property name and value. * @param {BinaryTreeNodeKey | N} nodeProperty - The `nodeProperty` parameter can be either a `BinaryTreeNodeKey` or a * generic type `N`. It represents the property of the binary tree node that you want to search for. - * @param {BinaryTreeNodePropertyName} [propertyName] - The `propertyName` parameter is an optional parameter that + * @param callback - The `callback` parameter is a function that takes a node as a parameter and returns a value. * specifies the property name to use for searching the binary tree nodes. If not provided, it defaults to `'key'`. * @returns The method is returning either a BinaryTreeNodeKey or N (generic type) or null. */ - override get(nodeProperty: BinaryTreeNodeKey | N, propertyName: BinaryTreeNodePropertyName = 'key'): N | null { - return this.getNodes(nodeProperty, propertyName, true)[0] ?? null; + override get(nodeProperty: BinaryTreeNodeKey | N, callback: MapCallback = this._defaultCallbackByKey): N | null { + return this.getNodes(nodeProperty, callback, true)[0] ?? null; } /** @@ -236,27 +237,34 @@ export class BST = BSTNode> extends BinaryTree * The function `getNodes` returns an array of nodes in a binary tree that match a given property value. * @param {BinaryTreeNodeKey | N} nodeProperty - The `nodeProperty` parameter can be either a `BinaryTreeNodeKey` or an * `N` type. It represents the property of the binary tree node that you want to compare with. - * @param {BinaryTreeNodePropertyName} [propertyName] - The `propertyName` parameter is an optional parameter that + * @param callback - The `callback` parameter is a function that takes a node as a parameter and returns a value. * specifies the property name to use for comparison. If not provided, it defaults to `'key'`. * @param {boolean} [onlyOne] - The `onlyOne` parameter is an optional boolean parameter that determines whether to * return only one node that matches the given `nodeProperty` or all nodes that match the `nodeProperty`. If `onlyOne` * is set to `true`, the function will return an array with only one node (if + * @param beginRoot - The `beginRoot` parameter is an optional parameter that specifies the root node from which to * @returns an array of nodes (type N). */ override getNodes( nodeProperty: BinaryTreeNodeKey | N, - propertyName: BinaryTreeNodePropertyName = 'key', - onlyOne = false + callback: MapCallback = this._defaultCallbackByKey, + onlyOne = false, + beginRoot: N | null = this.root ): N[] { - if (!this.root) return []; - const result: N[] = []; + if (!beginRoot) return []; + const ans: N[] = []; if (this.loopType === LoopType.RECURSIVE) { const _traverse = (cur: N) => { - if (this._pushByPropertyNameStopOrNot(cur, result, nodeProperty, propertyName, onlyOne)) return; + const callbackResult = callback(cur); + if (callbackResult === nodeProperty) { + ans.push(cur); + if (onlyOne) return; + } if (!cur.left && !cur.right) return; - if (propertyName === 'key') { + // TODO potential bug + if (callback === this._defaultCallbackByKey) { if (this._compare(cur.key, nodeProperty as number) === CP.gt) cur.left && _traverse(cur.left); if (this._compare(cur.key, nodeProperty as number) === CP.lt) cur.right && _traverse(cur.right); } else { @@ -265,14 +273,19 @@ export class BST = BSTNode> extends BinaryTree } }; - _traverse(this.root); + _traverse(beginRoot); } else { - const queue = new Queue([this.root]); + const queue = new Queue([beginRoot]); while (queue.size > 0) { const cur = queue.shift(); if (cur) { - if (this._pushByPropertyNameStopOrNot(cur, result, nodeProperty, propertyName, onlyOne)) return result; - if (propertyName === 'key') { + const callbackResult = callback(cur); + if (callbackResult === nodeProperty) { + ans.push(cur); + if (onlyOne) return ans; + } + // TODO potential bug + if (callback === this._defaultCallbackByKey) { if (this._compare(cur.key, nodeProperty as number) === CP.gt) cur.left && queue.push(cur.left); if (this._compare(cur.key, nodeProperty as number) === CP.lt) cur.right && queue.push(cur.right); } else { @@ -283,33 +296,34 @@ export class BST = BSTNode> extends BinaryTree } } - return result; + return ans; } // --- start additional functions /** - * The `lesserOrGreaterForeach` function adds a delta value to the specified property of all nodes in a binary tree that + * The `lesserOrGreaterTraverse` function adds a delta value to the specified property of all nodes in a binary tree that * have a greater value than a given node. + * @param callback - The `callback` parameter is a function that takes a node as a parameter and returns a value. * @param {N | BinaryTreeNodeKey | null} node - The `node` parameter can be either of type `N` (a generic type), `BinaryTreeNodeKey`, or `null`. It * represents the node in the binary tree to which the delta value will be added. * @param lesserOrGreater - The `lesserOrGreater` parameter is an optional parameter that specifies whether the delta - * @param callback - The `callback` parameter is a function that takes a node as a parameter and returns a boolean */ - lesserOrGreaterForeach( - node: N | BinaryTreeNodeKey | null, + lesserOrGreaterTraverse( + callback: MapCallback = this._defaultCallbackByKey, lesserOrGreater: CP = CP.lt, - callback: (node: N) => void - ): boolean { - if (typeof node === 'number') node = this.get(node, 'key'); - if (!node) return false; + node: N | BinaryTreeNodeKey | null + ): MapCallbackReturn { + if (typeof node === 'number') node = this.get(node); + const ans: MapCallbackReturn[] = []; + if (!node) return []; const key = node.key; if (!this.root) return false; if (this.loopType === LoopType.RECURSIVE) { const _traverse = (cur: N) => { const compared = this._compare(cur.key, key); - if (compared === lesserOrGreater) callback(cur); + if (compared === lesserOrGreater) ans.push(callback(cur)); if (!cur.left && !cur.right) return; if (cur.left && this._compare(cur.left.key, key) === lesserOrGreater) _traverse(cur.left); @@ -324,13 +338,13 @@ export class BST = BSTNode> extends BinaryTree const cur = queue.shift(); if (cur) { const compared = this._compare(cur.key, key); - if (compared === lesserOrGreater) callback(cur); + if (compared === lesserOrGreater) ans.push(callback(cur)); if (cur.left && this._compare(cur.left.key, key) === lesserOrGreater) queue.push(cur.left); if (cur.right && this._compare(cur.right.key, key) === lesserOrGreater) queue.push(cur.right); } } - return true; + return ans; } } @@ -350,7 +364,7 @@ export class BST = BSTNode> extends BinaryTree * @returns The function `perfectlyBalance()` returns a boolean value. */ perfectlyBalance(): boolean { - const sorted = this.dfs('in', 'node'), + const sorted = this.dfs(node => node, 'in'), n = sorted.length; this.clear(); diff --git a/src/data-structures/binary-tree/tree-multiset.ts b/src/data-structures/binary-tree/tree-multiset.ts index 1e62b91..c2ea9fa 100644 --- a/src/data-structures/binary-tree/tree-multiset.ts +++ b/src/data-structures/binary-tree/tree-multiset.ts @@ -6,10 +6,9 @@ * @license MIT License */ import type {BinaryTreeNodeKey, TreeMultisetNodeNested, TreeMultisetOptions} from '../../types'; -import {BinaryTreeDeletedResult, CP, DFSOrderPattern, FamilyPosition, LoopType} from '../../types'; +import {BinaryTreeDeletedResult, CP, FamilyPosition, LoopType} from '../../types'; import {IBinaryTree} from '../../interfaces'; import {AVLTree, AVLTreeNode} from './avl-tree'; -import {Queue} from '../queue'; export class TreeMultisetNode< V = any, @@ -248,7 +247,7 @@ export class TreeMultiset = TreeMultiset * @returns The function `perfectlyBalance()` returns a boolean value. */ override perfectlyBalance(): boolean { - const sorted = this.dfs('in', 'node'), + const sorted = this.dfs(node => node, 'in'), n = sorted.length; if (sorted.length < 1) return false; @@ -350,87 +349,6 @@ export class TreeMultiset = TreeMultiset return bstDeletedResult; } - /** - * The function `getNodesByCount` returns an array of nodes that have a specific count property, either recursively or - * using a queue. - * @param {BinaryTreeNodeKey | N} nodeProperty - The `nodeProperty` parameter can be either a `BinaryTreeNodeKey` or a - * `N`. It represents the property of the nodes that you want to search for. - * @param {boolean} [onlyOne] - The `onlyOne` parameter is an optional boolean parameter that determines whether to - * return only one node that matches the `nodeProperty` or all nodes that match the `nodeProperty`. If `onlyOne` is set - * to `true`, the function will return only one node. If `onlyOne` - * @returns an array of nodes that match the given nodeProperty. - */ - getNodesByCount(nodeProperty: BinaryTreeNodeKey | N, onlyOne = false): N[] { - if (!this.root) return []; - const result: N[] = []; - - if (this.loopType === LoopType.RECURSIVE) { - const _traverse = (cur: N) => { - if (cur.count === nodeProperty) { - result.push(cur); - if (onlyOne) return; - } - - if (!cur.left && !cur.right) return; - cur.left && _traverse(cur.left); - cur.right && _traverse(cur.right); - }; - - _traverse(this.root); - } else { - const queue = new Queue([this.root]); - while (queue.size > 0) { - const cur = queue.shift(); - if (cur) { - if (cur.count === nodeProperty) { - result.push(cur); - if (onlyOne) return result; - } - - cur.left && queue.push(cur.left); - cur.right && queue.push(cur.right); - } - } - } - - return result; - } - - /** - * The BFSCount function returns an array of counts from a breadth-first search of nodes. - * @returns The BFSCount() function returns an array of numbers, specifically the count property of each node in the - * bfs traversal. - */ - bfsCount(): number[] { - const nodes = super.bfs('node'); - return nodes.map(node => node.count); - } - - /** - * The function "listLevelsCount" takes a node and returns an array of arrays, where each inner array contains the - * count property of each node at that level. - * @param {N | null} node - The parameter `node` is of type `N | null`. This means that it can either be an instance of - * the class `N` or `null`. - * @returns a 2D array of numbers. Each inner array represents a level in the binary tree, and each number in the inner - * array represents the count property of a node in that level. - */ - listLevelsCount(node: N | null): number[][] { - const levels = super.listLevels(node, 'node'); - return levels.map(level => level.map(node => node.count)); - } - - /** - * The `morrisCount` function returns an array of counts for each node in a binary tree, based on a specified traversal - * pattern. - * @param {'in' | 'pre' | 'post'} [pattern] - The `pattern` parameter is an optional parameter that specifies the - * traversal pattern for the Morris traversal algorithm. It can have one of three values: 'in', 'pre', or 'post'. - * @returns The function `morrisCount` returns an array of numbers. - */ - morrisCount(pattern: DFSOrderPattern = 'in'): number[] { - const nodes = super.morris(pattern, 'node'); - return nodes.map(node => node.count); - } - /** * The clear() function clears the data and sets the count to 0. */ diff --git a/src/data-structures/heap/heap.ts b/src/data-structures/heap/heap.ts index 95b16ea..09cc63c 100644 --- a/src/data-structures/heap/heap.ts +++ b/src/data-structures/heap/heap.ts @@ -172,7 +172,7 @@ export class Heap { /** * Depth-first search (DFS) method, different traversal orders can be selected。 - * @param order - Traversal order parameter: 'in' (in-order), 'pre' (pre-order) or 'post' (post-order). + * @param order - Traverse order parameter: 'in' (in-order), 'pre' (pre-order) or 'post' (post-order). * @returns An array containing elements traversed in the specified order. */ dfs(order: DFSOrderPattern): E[] { diff --git a/src/types/data-structures/binary-tree.ts b/src/types/data-structures/binary-tree.ts index a296960..0371633 100644 --- a/src/types/data-structures/binary-tree.ts +++ b/src/types/data-structures/binary-tree.ts @@ -28,6 +28,10 @@ export type NodeOrPropertyName = 'node' | BinaryTreeNodePropertyName; export type BinaryTreeNodeKey = number; +export type BFSCallback = (node: N, level?: number) => any; + +export type BFSCallbackReturn = ReturnType>; + export type BinaryTreeNodeProperty> = | N['val'] | N diff --git a/src/types/data-structures/index.ts b/src/types/data-structures/index.ts index 8a60614..8ad00d7 100644 --- a/src/types/data-structures/index.ts +++ b/src/types/data-structures/index.ts @@ -12,3 +12,6 @@ export * from './singly-linked-list'; export * from './doubly-linked-list'; export * from './navigator'; export * from './hash'; + +export type MapCallback = (node: N) => any; +export type MapCallbackReturn = ReturnType>; diff --git a/test/unit/data-structures/binary-tree/avl-tree.test.ts b/test/unit/data-structures/binary-tree/avl-tree.test.ts index fd2fb41..e606423 100644 --- a/test/unit/data-structures/binary-tree/avl-tree.test.ts +++ b/test/unit/data-structures/binary-tree/avl-tree.test.ts @@ -1,9 +1,9 @@ -import {AVLTree, CP} from '../../../../src'; +import {AVLTree, CP, AVLTreeNode} from '../../../../src'; describe('AVL Tree Test', () => { it('should perform various operations on a AVL Tree', () => { const arr = [11, 3, 15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5]; - const tree = new AVLTree(); + const tree = new AVLTree>(); for (const i of arr) tree.add(i, i); @@ -12,7 +12,7 @@ describe('AVL Tree Test', () => { expect(node6 && tree.getHeight(node6)).toBe(3); expect(node6 && tree.getDepth(node6)).toBe(1); - const getNodeById = tree.get(10, 'key'); + const getNodeById = tree.get(10); expect(getNodeById?.key).toBe(10); const getMinNodeByRoot = tree.getLeftMost(); @@ -23,22 +23,23 @@ describe('AVL Tree Test', () => { expect(getMinNodeBySpecificNode?.key).toBe(12); let subTreeSum = 0; - node15 && tree.subTreeForeach(node15, node => (subTreeSum += node.key)); + node15 && tree.subTreeTraverse(node => (subTreeSum += node.key), node15); expect(subTreeSum).toBe(70); let lesserSum = 0; - tree.lesserOrGreaterForeach(10, CP.lt, node => (lesserSum += node.key)); + tree.lesserOrGreaterTraverse(node => (lesserSum += node.key), CP.lt, 10); expect(lesserSum).toBe(45); // node15 has type problem. After the uniform design, the generics of containers (DirectedGraph, BST) are based on the type of value. However, this design has a drawback: when I attempt to inherit from the Vertex or BSTNode classes, the types of the results obtained by all methods are those of the parent class. expect(node15?.val).toBe(15); - const dfs = tree.dfs('in', 'node'); + const dfs = tree.dfs(node => node, 'in'); expect(dfs[0].key).toBe(1); expect(dfs[dfs.length - 1].key).toBe(16); tree.perfectlyBalance(); - const bfs = tree.bfs('node'); + const bfs: AVLTreeNode[] = []; + tree.bfs(node => bfs.push(node)); expect(tree.isPerfectlyBalanced()).toBe(true); expect(bfs[0].key).toBe(8); expect(bfs[bfs.length - 1].key).toBe(16); @@ -97,12 +98,14 @@ describe('AVL Tree Test', () => { expect(tree.getHeight()).toBe(1); expect(tree.isAVLBalanced()).toBe(true); - const lastBFSIds = tree.bfs(); + const lastBFSIds = new Array(); + tree.bfs(node => lastBFSIds.push(node.key)); expect(lastBFSIds[0]).toBe(12); expect(lastBFSIds[1]).toBe(2); expect(lastBFSIds[2]).toBe(16); - const lastBFSNodes = tree.bfs('node'); + const lastBFSNodes: AVLTreeNode[] = []; + tree.bfs(node => lastBFSNodes.push(node)); expect(lastBFSNodes[0].key).toBe(12); expect(lastBFSNodes[1].key).toBe(2); expect(lastBFSNodes[2].key).toBe(16); diff --git a/test/unit/data-structures/binary-tree/binary-tree.test.ts b/test/unit/data-structures/binary-tree/binary-tree.test.ts index 4574a9e..acd8368 100644 --- a/test/unit/data-structures/binary-tree/binary-tree.test.ts +++ b/test/unit/data-structures/binary-tree/binary-tree.test.ts @@ -127,7 +127,7 @@ describe('BinaryTree', () => { binaryTree.add(5); binaryTree.add(7); - const inOrder = binaryTree.dfs('in'); + const inOrder = binaryTree.dfs(node => node.key); expect(inOrder).toEqual([1, 2, 3, 4, 5, 6, 7]); }); diff --git a/test/unit/data-structures/binary-tree/bst.test.ts b/test/unit/data-structures/binary-tree/bst.test.ts index 84c0d79..75d4e2d 100644 --- a/test/unit/data-structures/binary-tree/bst.test.ts +++ b/test/unit/data-structures/binary-tree/bst.test.ts @@ -1,6 +1,6 @@ import {BST, BSTNode, CP} from '../../../../src'; -const isDebug = false; +const isDebug = true; describe('BST operations test', () => { it('should perform various operations on a Binary Search Tree with numeric values', () => { @@ -25,7 +25,7 @@ describe('BST operations test', () => { const nodeId10 = bst.get(10); expect(nodeId10?.key).toBe(10); - const nodeVal9 = bst.get(9, 'val'); + const nodeVal9 = bst.get(9, node => node.val); expect(nodeVal9?.key).toBe(9); const leftMost = bst.getLeftMost(); @@ -36,11 +36,11 @@ describe('BST operations test', () => { expect(minNodeBySpecificNode?.key).toBe(12); let subTreeSum = 0; - node15 && bst.subTreeForeach(15, node => (subTreeSum += node.key)); + node15 && bst.subTreeTraverse(node => (subTreeSum += node.key), 15); expect(subTreeSum).toBe(70); let lesserSum = 0; - bst.lesserOrGreaterForeach(10, CP.lt, node => (lesserSum += node.key)); + bst.lesserOrGreaterTraverse(node => (lesserSum += node.key), CP.lt, 10); expect(lesserSum).toBe(45); expect(node15).toBeInstanceOf(BSTNode); @@ -48,14 +48,15 @@ describe('BST operations test', () => { const node11 = bst.get(11); expect(node11).toBeInstanceOf(BSTNode); - const dfsInorderNodes = bst.dfs('in', 'node'); + const dfsInorderNodes = bst.dfs(node => node, 'in'); expect(dfsInorderNodes[0].key).toBe(1); expect(dfsInorderNodes[dfsInorderNodes.length - 1].key).toBe(16); bst.perfectlyBalance(); expect(bst.isPerfectlyBalanced()).toBe(true); - const bfsNodesAfterBalanced = bst.bfs('node'); + const bfsNodesAfterBalanced: BSTNode[] = []; + bst.bfs(node => bfsNodesAfterBalanced.push(node)); expect(bfsNodesAfterBalanced[0].key).toBe(8); expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16); @@ -173,12 +174,14 @@ describe('BST operations test', () => { expect(bst.isAVLBalanced()).toBe(false); - const bfsIDs = bst.bfs(); + const bfsIDs: number[] = []; + bst.bfs(node => bfsIDs.push(node.key)); expect(bfsIDs[0]).toBe(2); expect(bfsIDs[1]).toBe(12); expect(bfsIDs[2]).toBe(16); - const bfsNodes = bst.bfs('node'); + const bfsNodes: BSTNode[] = []; + bst.bfs(node => bfsNodes.push(node)); expect(bfsNodes[0].key).toBe(2); expect(bfsNodes[1].key).toBe(12); expect(bfsNodes[2].key).toBe(16); @@ -222,10 +225,10 @@ describe('BST operations test', () => { expect(node6 && objBST.getHeight(node6)).toBe(2); expect(node6 && objBST.getDepth(node6)).toBe(3); - const nodeId10 = objBST.get(10, 'key'); + const nodeId10 = objBST.get(10); expect(nodeId10?.key).toBe(10); - const nodeVal9 = objBST.get(9, 'key'); + const nodeVal9 = objBST.get(9); expect(nodeVal9?.key).toBe(9); const leftMost = objBST.getLeftMost(); @@ -237,11 +240,11 @@ describe('BST operations test', () => { expect(minNodeBySpecificNode?.key).toBe(12); let subTreeSum = 0; - node15 && objBST.subTreeForeach(node15, node => (subTreeSum += node.key)); + node15 && objBST.subTreeTraverse(node => (subTreeSum += node.key), node15); expect(subTreeSum).toBe(70); let lesserSum = 0; - objBST.lesserOrGreaterForeach(10, CP.lt, node => (lesserSum += node.key)); + objBST.lesserOrGreaterTraverse(node => (lesserSum += node.key), CP.lt, 10); expect(lesserSum).toBe(45); expect(node15).toBeInstanceOf(BSTNode); @@ -249,14 +252,15 @@ describe('BST operations test', () => { const node11 = objBST.get(11); expect(node11).toBeInstanceOf(BSTNode); - const dfsInorderNodes = objBST.dfs('in', 'node'); + const dfsInorderNodes = objBST.dfs(node => node, 'in'); expect(dfsInorderNodes[0].key).toBe(1); expect(dfsInorderNodes[dfsInorderNodes.length - 1].key).toBe(16); objBST.perfectlyBalance(); expect(objBST.isPerfectlyBalanced()).toBe(true); - const bfsNodesAfterBalanced = objBST.bfs('node'); + const bfsNodesAfterBalanced: BSTNode<{key: number; keyA: number}>[] = []; + objBST.bfs(node => bfsNodesAfterBalanced.push(node)); expect(bfsNodesAfterBalanced[0].key).toBe(8); expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16); @@ -374,12 +378,14 @@ describe('BST operations test', () => { expect(objBST.isAVLBalanced()).toBe(false); - const bfsIDs = objBST.bfs(); + const bfsIDs: number[] = []; + objBST.bfs(node => bfsIDs.push(node.key)); expect(bfsIDs[0]).toBe(2); expect(bfsIDs[1]).toBe(12); expect(bfsIDs[2]).toBe(16); - const bfsNodes = objBST.bfs('node'); + const bfsNodes: BSTNode<{key: number; keyA: number}>[] = []; + objBST.bfs(node => bfsNodes.push(node)); expect(bfsNodes[0].key).toBe(2); expect(bfsNodes[1].key).toBe(12); expect(bfsNodes[2].key).toBe(16); @@ -396,11 +402,11 @@ describe('BST Performance test', function () { it(`Observe the time consumption of BST.dfs be good`, function () { const startDFS = performance.now(); - const dfs = bst.dfs(); + const dfs = bst.dfs(node => node); isDebug && console.log('---bfs', performance.now() - startDFS, dfs.length); }); - it('Should the time consumption of lesserOrGreaterForeach fitting O(n log n)', function () { + it('Should the time consumption of lesserOrGreaterTraverse fitting O(n log n)', function () { const nodes: number[] = []; for (let i = 0; i < inputSize; i++) { nodes.push(i); @@ -409,9 +415,33 @@ describe('BST Performance test', function () { bst.addMany(nodes); isDebug && console.log('---add', performance.now() - start); const startL = performance.now(); - bst.lesserOrGreaterForeach(inputSize / 2, CP.lt, node => { - return node.key - 1; - }); - isDebug && console.log('---lesserOrGreaterForeach', performance.now() - startL); + bst.lesserOrGreaterTraverse( + node => { + node.key - 1; + }, + CP.lt, + inputSize / 2 + ); + isDebug && console.log('---lesserOrGreaterTraverse', performance.now() - startL); + }); + + it('Should the time consumption of listLevels fitting well', function () { + const nodes: number[] = []; + for (let i = 0; i < inputSize; i++) { + nodes.push(i); + } + const start = performance.now(); + bst.addMany(nodes); + isDebug && console.log('---add', performance.now() - start); + const startL = performance.now(); + const arr: number[][] = []; + bst.bfs((node, level) => { + if (level !== undefined) { + if (!arr[level]) arr[level] = []; + arr[level].push(node.key); + } + }, true); + isDebug && console.log('---listLevels', arr); + isDebug && console.log('---listLevels', performance.now() - startL); }); }); diff --git a/test/unit/data-structures/binary-tree/overall.test.ts b/test/unit/data-structures/binary-tree/overall.test.ts index 2cdffee..5325180 100644 --- a/test/unit/data-structures/binary-tree/overall.test.ts +++ b/test/unit/data-structures/binary-tree/overall.test.ts @@ -24,7 +24,8 @@ describe('Overall BinaryTree Test', () => { expect(bst.get(6)).toBeNull(); bst.isAVLBalanced(); // true or false expect(bst.isAVLBalanced()).toBe(true); - const bfsIDs = bst.bfs(); + const bfsIDs: number[] = []; + bst.bfs(node => bfsIDs.push(node.key)); bfsIDs[0] === 11; // true expect(bfsIDs[0]).toBe(11); diff --git a/test/unit/data-structures/binary-tree/rb-tree.test.ts b/test/unit/data-structures/binary-tree/rb-tree.test.ts index 1d3a5ac..884e126 100644 --- a/test/unit/data-structures/binary-tree/rb-tree.test.ts +++ b/test/unit/data-structures/binary-tree/rb-tree.test.ts @@ -7,7 +7,7 @@ describe('Red-Black Tree Tests', () => { // tree = new RBTree>(); // }); - test('Insertion and In-order Traversal', () => { + test('Insertion and In-order Traverse', () => { // tree.add(5); // tree.add(3); // tree.add(7); @@ -16,9 +16,9 @@ describe('Red-Black Tree Tests', () => { // tree.add(6); // tree.add(8); // - // const inOrderTraversal: number[] = tree.DFS('in') + // const inOrderTraverse: number[] = tree.DFS('in') // - // expect(inOrderTraversal).toEqual([2, 3, 4, 5, 6, 7, 8]); + // expect(inOrderTraverse).toEqual([2, 3, 4, 5, 6, 7, 8]); }); test('Deletion', () => { @@ -35,9 +35,9 @@ describe('Red-Black Tree Tests', () => { // expect(tree.has(3)).toBe(false); // // // Perform in-order traversal to check if the tree is still balanced - // const inOrderTraversal: number[] = tree.DFS('in'); + // const inOrderTraverse: number[] = tree.DFS('in'); // // - // expect(inOrderTraversal).toEqual([2, 4, 5, 6, 7, 8]); + // expect(inOrderTraverse).toEqual([2, 4, 5, 6, 7, 8]); }); }); diff --git a/test/unit/data-structures/binary-tree/tree-multiset.test.ts b/test/unit/data-structures/binary-tree/tree-multiset.test.ts index 4be9ce1..4a9a101 100644 --- a/test/unit/data-structures/binary-tree/tree-multiset.test.ts +++ b/test/unit/data-structures/binary-tree/tree-multiset.test.ts @@ -16,7 +16,6 @@ describe('TreeMultiset operations test', () => { expect(treeMultiset.size).toBe(16); expect(treeMultiset.count).toBe(18); - expect(treeMultiset.bfs('key')); expect(treeMultiset.has(6)); @@ -25,13 +24,13 @@ describe('TreeMultiset operations test', () => { const nodeId10 = treeMultiset.get(10); expect(nodeId10?.key).toBe(10); - const nodeVal9 = treeMultiset.get(9, 'val'); + const nodeVal9 = treeMultiset.get(9, node => node.val); expect(nodeVal9?.key).toBe(9); - const nodesByCount1 = treeMultiset.getNodesByCount(1); + const nodesByCount1 = treeMultiset.getNodes(1, node => node.count); expect(nodesByCount1.length).toBe(14); - const nodesByCount2 = treeMultiset.getNodesByCount(2); + const nodesByCount2 = treeMultiset.getNodes(2, node => node.count); expect(nodesByCount2.length).toBe(2); const leftMost = treeMultiset.getLeftMost(); expect(leftMost?.key).toBe(1); @@ -41,29 +40,25 @@ describe('TreeMultiset operations test', () => { expect(minNodeBySpecificNode?.key).toBe(12); let subTreeSum = 0; - node15 && treeMultiset.subTreeForeach(15, (node: TreeMultisetNode) => (subTreeSum += node.key)); + node15 && treeMultiset.subTreeTraverse((node: TreeMultisetNode) => (subTreeSum += node.key), 15); expect(subTreeSum).toBe(70); let lesserSum = 0; - treeMultiset.lesserOrGreaterForeach(10, CP.lt, (node: TreeMultisetNode) => (lesserSum += node.key)); + treeMultiset.lesserOrGreaterTraverse((node: TreeMultisetNode) => (lesserSum += node.key), CP.lt, 10); expect(lesserSum).toBe(45); expect(node15 instanceof TreeMultisetNode); if (node15 instanceof TreeMultisetNode) { - const subTreeAdd = treeMultiset.subTreeForeach(15, (node: TreeMultisetNode) => (node.count += 1)); + const subTreeAdd = treeMultiset.subTreeTraverse((node: TreeMultisetNode) => (node.count += 1), 15); expect(subTreeAdd); } const node11 = treeMultiset.get(11); expect(node11 instanceof TreeMultisetNode); if (node11 instanceof TreeMultisetNode) { - const allGreaterNodesAdded = treeMultiset.lesserOrGreaterForeach( - 11, - CP.gt, - (node: TreeMultisetNode) => (node.count += 2) - ); + const allGreaterNodesAdded = treeMultiset.lesserOrGreaterTraverse(node => (node.count += 2), CP.gt, 11); expect(allGreaterNodesAdded); } - const dfsInorderNodes = treeMultiset.dfs('in', 'node'); + const dfsInorderNodes = treeMultiset.dfs(node => node, 'in'); expect(dfsInorderNodes[0].key).toBe(1); expect(dfsInorderNodes[dfsInorderNodes.length - 1].key).toBe(16); expect(treeMultiset.isPerfectlyBalanced()).toBe(false); @@ -73,7 +68,7 @@ describe('TreeMultiset operations test', () => { expect(treeMultiset.isPerfectlyBalanced()).toBe(true); expect(treeMultiset.isAVLBalanced()).toBe(true); - const bfsNodesAfterBalanced = treeMultiset.bfs('node'); + const bfsNodesAfterBalanced = treeMultiset.bfs(node => node); expect(bfsNodesAfterBalanced[0].key).toBe(8); expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16); @@ -194,13 +189,13 @@ describe('TreeMultiset operations test', () => { expect(treeMultiset.isAVLBalanced()).toBe(true); - const bfsIDs = treeMultiset.bfs(); + const bfsIDs = treeMultiset.bfs(node => node.key); expect(bfsIDs[0]).toBe(12); expect(bfsIDs[1]).toBe(2); expect(bfsIDs[2]).toBe(16); - const bfsNodes = treeMultiset.bfs('node'); + const bfsNodes = treeMultiset.bfs(node => node); expect(bfsNodes[0].key).toBe(12); expect(bfsNodes[1].key).toBe(2); @@ -284,7 +279,7 @@ describe('TreeMultiset operations test', () => { // expect(allGreaterNodesAdded).toBeDefined(); // } // - // const dfsInorderNodes = objTreeMultiset.dfs('in', 'node'); + // const dfsInorderNodes = objTreeMultiset.dfs(node => node, 'in'); // expect(dfsInorderNodes[0].key).toBe(1); // expect(dfsInorderNodes[dfsInorderNodes.length - 1].key).toBe(16); // @@ -474,18 +469,18 @@ describe('TreeMultiset Performance test', function () { it(`Observe the time consumption of TreeMultiset.dfs be good`, function () { const startDFS = performance.now(); - const dfs = treeMS.dfs(); + const dfs = treeMS.dfs(node => node); isDebug && console.log('---bfs', performance.now() - startDFS, dfs.length); }); - it('Should the time consumption of lesserOrGreaterForeach fitting O(n log n)', function () { + it('Should the time consumption of lesserOrGreaterTraverse fitting O(n log n)', function () { const start = performance.now(); for (let i = 0; i < inputSize; i++) { treeMS.add(i); } isDebug && console.log('---add', performance.now() - start); const startL = performance.now(); - treeMS.lesserOrGreaterForeach(inputSize / 2, CP.lt, (node: TreeMultisetNode) => (node.count += 1)); - isDebug && console.log('---lesserOrGreaterForeach', performance.now() - startL); + treeMS.lesserOrGreaterTraverse((node: TreeMultisetNode) => (node.count += 1), CP.lt, inputSize / 2); + isDebug && console.log('---lesserOrGreaterTraverse', performance.now() - startL); }); }); From c177a4f87d61c448b310cb9b29bdb36b298ed4c9 Mon Sep 17 00:00:00 2001 From: Revone Date: Mon, 23 Oct 2023 03:06:55 +0800 Subject: [PATCH 11/46] [pkg] v1.37.1 publishing --- package.json | 2 +- .../data-structures/priority-queue/max-priority-queue.test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 5b20ca9..997a320 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "data-structure-typed", - "version": "1.37.0", + "version": "1.37.1", "description": "Data Structures of Javascript & TypeScript. Binary Tree, BST, Graph, Heap, Priority Queue, Linked List, Queue, Deque, Stack, AVL Tree, Tree Multiset, Trie, Directed Graph, Undirected Graph, Singly Linked List, Doubly Linked List, Max Heap, Max Priority Queue, Min Heap, Min Priority Queue.", "main": "dist/index.js", "module": "lib/index.js", diff --git a/test/unit/data-structures/priority-queue/max-priority-queue.test.ts b/test/unit/data-structures/priority-queue/max-priority-queue.test.ts index ff486cd..f8a63bc 100644 --- a/test/unit/data-structures/priority-queue/max-priority-queue.test.ts +++ b/test/unit/data-structures/priority-queue/max-priority-queue.test.ts @@ -90,7 +90,7 @@ describe('MaxPriorityQueue Performance Test', () => { } } const cost = performance.now() - startTime; - expect(cost).toBeLessThan(bigO.LINEAR * 20); + expect(cost).toBeLessThan(bigO.LINEAR * 30); expect(prev).toBeGreaterThan(0); }); From 48e94f29ed91e522455a6b831a18c4b9e87a004a Mon Sep 17 00:00:00 2001 From: Revone Date: Mon, 23 Oct 2023 21:22:07 +0800 Subject: [PATCH 12/46] [binary-tree] Update the testing API to the new version. --- package-lock.json | 50 +++++----- package.json | 12 +-- .../binary-tree/binary-tree.ts | 7 +- test/integration/avl-tree.test.ts | 44 ++++----- test/integration/bst.test.ts | 93 ++++++++++--------- 5 files changed, 104 insertions(+), 102 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0d4a720..1c7187c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "data-structure-typed", - "version": "1.37.0", + "version": "1.37.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "data-structure-typed", - "version": "1.37.0", + "version": "1.37.2", "license": "MIT", "devDependencies": { "@types/benchmark": "^2.1.3", @@ -15,17 +15,17 @@ "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", "auto-changelog": "^2.4.0", - "avl-tree-typed": "^1.36.9", + "avl-tree-typed": "^1.37.2", "benchmark": "^2.1.4", - "binary-tree-typed": "^1.36.9", - "bst-typed": "^1.36.9", + "binary-tree-typed": "^1.37.2", + "bst-typed": "^1.37.2", "dependency-cruiser": "^14.1.0", "eslint": "^8.50.0", "eslint-config-prettier": "^9.0.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.28.1", - "heap-typed": "^1.36.9", + "heap-typed": "^1.37.2", "istanbul-badges-readme": "^1.8.5", "jest": "^29.7.0", "prettier": "^3.0.3", @@ -2396,12 +2396,12 @@ } }, "node_modules/avl-tree-typed": { - "version": "1.36.9", - "resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.36.9.tgz", - "integrity": "sha512-JCcrzwqotdd62ojLQZR74kTcmlgn+Y0w+Ws2l58ZzStW8dWVZUY/KybRxVJnY1XT50DTYY6RzAf1UFgj52anvw==", + "version": "1.37.2", + "resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.37.2.tgz", + "integrity": "sha512-nwQjVhtKeVnMA6J1ZQwgMo/cubZEIhOFXCZfwu/tzKCklr8WTXAdCyysOVuT52SwKhzkdNjjSeAevDhfH7m05g==", "dev": true, "dependencies": { - "data-structure-typed": "^1.36.8" + "data-structure-typed": "^1.37.2" } }, "node_modules/babel-jest": { @@ -2586,12 +2586,12 @@ } }, "node_modules/binary-tree-typed": { - "version": "1.36.9", - "resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.36.9.tgz", - "integrity": "sha512-3YBodVs6gpGkgyY7vhDL+m20G/RyRFnu5Yqgf6xYvabwoChc8Yzv+UrxMqD7CVDt2o/WvvEuC/M7U5GYSNLY2A==", + "version": "1.37.2", + "resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.37.2.tgz", + "integrity": "sha512-bCdPFOAm5eMiuDiJLfnj1g6dR2Ib2p4NLrhTvSzCWVjf/o/LLCjzpS0HfXHZ+sjhqfs7yxthgbW4SeHgDO5MPw==", "dev": true, "dependencies": { - "data-structure-typed": "^1.36.8" + "data-structure-typed": "^1.37.2" } }, "node_modules/brace-expansion": { @@ -2670,12 +2670,12 @@ } }, "node_modules/bst-typed": { - "version": "1.36.9", - "resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.36.9.tgz", - "integrity": "sha512-FAQ6KiVuF6RCakPIgZwtZ/VdfKj2gL64rO/CN6DWP0jWYWoYvsqDW3pr83PvUhjNsxLQW5q92GT17wMOmjwDog==", + "version": "1.37.2", + "resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.37.2.tgz", + "integrity": "sha512-6WBCmwIX5ibA5i8B/WyL3aXv4m0Pi2xU/6uPTIHfkQAfBSpdMUxrmwRJ5G6aBBJ6wwZ+KkRKezZj6DbklY2FRA==", "dev": true, "dependencies": { - "data-structure-typed": "^1.36.8" + "data-structure-typed": "^1.37.2" } }, "node_modules/buffer-from": { @@ -3027,9 +3027,9 @@ } }, "node_modules/data-structure-typed": { - "version": "1.36.8", - "resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.36.8.tgz", - "integrity": "sha512-mDm4rww/jzmmVtqtb+A63Ri3Aeau3FzNKwxGKtZd20xRPz7FVDm/fciCIxtv1TWTTLjDSpDZcpBGs/tB0i61QA==", + "version": "1.37.2", + "resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.37.2.tgz", + "integrity": "sha512-eVU6Bd2G2xPkdO3SVqo8R+nUkWrdgDbOTR3OYtoldZbNH6Hp2lbv49goDrMYeFBxbsdJ9+k9bNI6WNTpC728uA==", "dev": true }, "node_modules/debug": { @@ -4362,12 +4362,12 @@ } }, "node_modules/heap-typed": { - "version": "1.36.9", - "resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.36.9.tgz", - "integrity": "sha512-Dy7W2SooiSAc3+2Kcdb7/GvJXkguUc+hz2qLKvSbdisH6z4siOoNYoVmZJjSrc11udW1JpEINK+LqjOBlLAxiw==", + "version": "1.37.2", + "resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.37.2.tgz", + "integrity": "sha512-zQXBfpZdCNnWETGKkxQmd14l8hiIk2HZ1rfmzjCb/OgfLDW3GiKVg5SPcn6FacsTqxLx8Y/ClQzpPeXZCOXtAQ==", "dev": true, "dependencies": { - "data-structure-typed": "^1.36.8" + "data-structure-typed": "^1.37.2" } }, "node_modules/html-escaper": { diff --git a/package.json b/package.json index 997a320..9881c8a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "data-structure-typed", - "version": "1.37.1", + "version": "1.37.2", "description": "Data Structures of Javascript & TypeScript. Binary Tree, BST, Graph, Heap, Priority Queue, Linked List, Queue, Deque, Stack, AVL Tree, Tree Multiset, Trie, Directed Graph, Undirected Graph, Singly Linked List, Doubly Linked List, Max Heap, Max Priority Queue, Min Heap, Min Priority Queue.", "main": "dist/index.js", "module": "lib/index.js", @@ -28,7 +28,7 @@ "fix:test": "npm run lint:test && npm run format:test", "fix": "npm run fix:src && npm run fix:test", "update:individuals": "npm i avl-tree-typed binary-tree-typed bst-typed heap-typed --save-dev", - "install:individuals": "npm i avl-tree-typed binary-tree-typed bst-typed deque-typed directed-graph-typed doubly-linked-list-typed graph-typed heap-typed linked-list-typed max-heap-typed max-priority-queue-typed min-heap-typed min-priority-queue-typed priority-queue-typed singly-linked-list-typed stack-typed tree-multiset-typed trie-typed undirected-graph-typed queue-typed --save-dev", + "install:all-individuals": "npm i avl-tree-typed binary-tree-typed bst-typed deque-typed directed-graph-typed doubly-linked-list-typed graph-typed heap-typed linked-list-typed max-heap-typed max-priority-queue-typed min-heap-typed min-priority-queue-typed priority-queue-typed singly-linked-list-typed stack-typed tree-multiset-typed trie-typed undirected-graph-typed queue-typed --save-dev", "test": "jest", "check:deps": "dependency-cruiser src", "changelog": "auto-changelog", @@ -58,17 +58,17 @@ "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", "auto-changelog": "^2.4.0", - "avl-tree-typed": "^1.36.9", + "avl-tree-typed": "^1.37.2", "benchmark": "^2.1.4", - "binary-tree-typed": "^1.36.9", - "bst-typed": "^1.36.9", + "binary-tree-typed": "^1.37.2", + "bst-typed": "^1.37.2", "dependency-cruiser": "^14.1.0", "eslint": "^8.50.0", "eslint-config-prettier": "^9.0.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.28.1", - "heap-typed": "^1.36.9", + "heap-typed": "^1.37.2", "istanbul-badges-readme": "^1.8.5", "jest": "^29.7.0", "prettier": "^3.0.3", diff --git a/src/data-structures/binary-tree/binary-tree.ts b/src/data-structures/binary-tree/binary-tree.ts index e49f9e2..3c58236 100644 --- a/src/data-structures/binary-tree/binary-tree.ts +++ b/src/data-structures/binary-tree/binary-tree.ts @@ -15,12 +15,7 @@ import type { MapCallback, MapCallbackReturn } from '../../types'; -import { - BinaryTreeDeletedResult, - DFSOrderPattern, - FamilyPosition, - LoopType -} from '../../types'; +import {BinaryTreeDeletedResult, DFSOrderPattern, FamilyPosition, LoopType} from '../../types'; import {IBinaryTree} from '../../interfaces'; import {trampoline} from '../../utils'; import {Queue} from '../queue'; diff --git a/test/integration/avl-tree.test.ts b/test/integration/avl-tree.test.ts index 6064a97..b6832db 100644 --- a/test/integration/avl-tree.test.ts +++ b/test/integration/avl-tree.test.ts @@ -1,4 +1,4 @@ -import {AVLTree} from 'avl-tree-typed'; +import {AVLTree, CP} from 'avl-tree-typed'; describe('AVL Tree Test', () => { it('should perform various operations on a AVL Tree', () => { @@ -12,7 +12,7 @@ describe('AVL Tree Test', () => { expect(node6 && tree.getHeight(node6)).toBe(3); expect(node6 && tree.getDepth(node6)).toBe(1); - const getNodeById = tree.get(10, 'key'); + const getNodeById = tree.get(10); expect(getNodeById?.key).toBe(10); const getMinNodeByRoot = tree.getLeftMost(); @@ -22,75 +22,77 @@ describe('AVL Tree Test', () => { const getMinNodeBySpecificNode = node15 && tree.getLeftMost(node15); expect(getMinNodeBySpecificNode?.key).toBe(12); - const subTreeSum = node15 && tree.subTreeSum(node15); + let subTreeSum = 0; + node15 && tree.subTreeTraverse(node => (subTreeSum += node.key), 15); expect(subTreeSum).toBe(70); - const lesserSum = tree.lesserSum(10); + let lesserSum = 0; + tree.lesserOrGreaterTraverse(node => (lesserSum += node.key), CP.lt, 10); expect(lesserSum).toBe(45); // node15 has type problem. After the uniform design, the generics of containers (DirectedGraph, BST) are based on the type of value. However, this design has a drawback: when I attempt to inherit from the Vertex or BSTNode classes, the types of the results obtained by all methods are those of the parent class. expect(node15?.val).toBe(15); - const dfs = tree.dfs('in', 'node'); + const dfs = tree.dfs(node => node, 'in'); expect(dfs[0].key).toBe(1); expect(dfs[dfs.length - 1].key).toBe(16); tree.perfectlyBalance(); - const bfs = tree.bfs('node'); + const bfs = tree.bfs(node => node); expect(tree.isPerfectlyBalanced()).toBe(true); expect(bfs[0].key).toBe(8); expect(bfs[bfs.length - 1].key).toBe(16); - expect(tree.remove(11)[0].deleted?.key).toBe(11); + expect(tree.delete(11)[0].deleted?.key).toBe(11); expect(tree.isAVLBalanced()).toBe(true); expect(node15 && tree.getHeight(node15)).toBe(2); - expect(tree.remove(1)[0].deleted?.key).toBe(1); + expect(tree.delete(1)[0].deleted?.key).toBe(1); expect(tree.isAVLBalanced()).toBe(true); expect(tree.getHeight()).toBe(4); - expect(tree.remove(4)[0].deleted?.key).toBe(4); + expect(tree.delete(4)[0].deleted?.key).toBe(4); expect(tree.isAVLBalanced()).toBe(true); expect(tree.getHeight()).toBe(4); - expect(tree.remove(10)[0].deleted?.key).toBe(10); + expect(tree.delete(10)[0].deleted?.key).toBe(10); expect(tree.isAVLBalanced()).toBe(true); expect(tree.getHeight()).toBe(3); - expect(tree.remove(15)[0].deleted?.key).toBe(15); + expect(tree.delete(15)[0].deleted?.key).toBe(15); expect(tree.isAVLBalanced()).toBe(true); expect(tree.getHeight()).toBe(3); - expect(tree.remove(5)[0].deleted?.key).toBe(5); + expect(tree.delete(5)[0].deleted?.key).toBe(5); expect(tree.isAVLBalanced()).toBe(true); expect(tree.getHeight()).toBe(3); - expect(tree.remove(13)[0].deleted?.key).toBe(13); + expect(tree.delete(13)[0].deleted?.key).toBe(13); expect(tree.isAVLBalanced()).toBe(true); expect(tree.getHeight()).toBe(3); - expect(tree.remove(3)[0].deleted?.key).toBe(3); + expect(tree.delete(3)[0].deleted?.key).toBe(3); expect(tree.isAVLBalanced()).toBe(true); expect(tree.getHeight()).toBe(3); - expect(tree.remove(8)[0].deleted?.key).toBe(8); + expect(tree.delete(8)[0].deleted?.key).toBe(8); expect(tree.isAVLBalanced()).toBe(true); expect(tree.getHeight()).toBe(3); - expect(tree.remove(6)[0].deleted?.key).toBe(6); - expect(tree.remove(6).length).toBe(0); + expect(tree.delete(6)[0].deleted?.key).toBe(6); + expect(tree.delete(6).length).toBe(0); expect(tree.isAVLBalanced()).toBe(true); expect(tree.getHeight()).toBe(2); - expect(tree.remove(7)[0].deleted?.key).toBe(7); + expect(tree.delete(7)[0].deleted?.key).toBe(7); expect(tree.isAVLBalanced()).toBe(true); expect(tree.getHeight()).toBe(2); - expect(tree.remove(9)[0].deleted?.key).toBe(9); + expect(tree.delete(9)[0].deleted?.key).toBe(9); expect(tree.isAVLBalanced()).toBe(true); expect(tree.getHeight()).toBe(2); - expect(tree.remove(14)[0].deleted?.key).toBe(14); + expect(tree.delete(14)[0].deleted?.key).toBe(14); expect(tree.isAVLBalanced()).toBe(true); expect(tree.getHeight()).toBe(1); @@ -100,7 +102,7 @@ describe('AVL Tree Test', () => { expect(lastBFSIds[1]).toBe(2); expect(lastBFSIds[2]).toBe(16); - const lastBFSNodes = tree.bfs('node'); + const lastBFSNodes = tree.bfs(node => node); expect(lastBFSNodes[0].key).toBe(12); expect(lastBFSNodes[1].key).toBe(2); expect(lastBFSNodes[2].key).toBe(16); diff --git a/test/integration/bst.test.ts b/test/integration/bst.test.ts index 51abf5a..a482a37 100644 --- a/test/integration/bst.test.ts +++ b/test/integration/bst.test.ts @@ -1,4 +1,4 @@ -import {BST, BSTNode} from 'bst-typed'; +import {BST, BSTNode, CP} from 'bst-typed'; describe('Individual package BST operations test', () => { it('should perform various operations on a Binary Search Tree with numeric values', () => { @@ -7,7 +7,7 @@ describe('Individual package BST operations test', () => { bst.add(11, 11); bst.add(3, 3); const idsOrVals = [15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5]; - bst.addMany(idsOrVals, idsOrVals); + bst.addMany(idsOrVals, idsOrVals, false); expect(bst.root).toBeInstanceOf(BSTNode); if (bst.root) expect(bst.root.key).toBe(11); @@ -23,7 +23,7 @@ describe('Individual package BST operations test', () => { const nodeId10 = bst.get(10); expect(nodeId10?.key).toBe(10); - const nodeVal9 = bst.get(9, 'val'); + const nodeVal9 = bst.get(9, node => node.val); expect(nodeVal9?.key).toBe(9); const leftMost = bst.getLeftMost(); @@ -33,10 +33,12 @@ describe('Individual package BST operations test', () => { const minNodeBySpecificNode = node15 && bst.getLeftMost(node15); expect(minNodeBySpecificNode?.key).toBe(12); - const subTreeSum = node15 && bst.subTreeSum(15); + let subTreeSum = 0; + node15 && bst.subTreeTraverse(node => (subTreeSum += node.key), 15); expect(subTreeSum).toBe(70); - const lesserSum = bst.lesserSum(10); + let lesserSum = 0; + bst.lesserOrGreaterTraverse(node => (lesserSum += node.key), CP.lt, 10); expect(lesserSum).toBe(45); expect(node15).toBeInstanceOf(BSTNode); @@ -44,18 +46,18 @@ describe('Individual package BST operations test', () => { const node11 = bst.get(11); expect(node11).toBeInstanceOf(BSTNode); - const dfsInorderNodes = bst.dfs('in', 'node'); + const dfsInorderNodes = bst.dfs(node => node, 'in'); expect(dfsInorderNodes[0].key).toBe(1); expect(dfsInorderNodes[dfsInorderNodes.length - 1].key).toBe(16); bst.perfectlyBalance(); expect(bst.isPerfectlyBalanced()).toBe(true); - const bfsNodesAfterBalanced = bst.bfs('node'); + const bfsNodesAfterBalanced = bst.bfs(node => node); expect(bfsNodesAfterBalanced[0].key).toBe(8); expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16); - const removed11 = bst.remove(11); + const removed11 = bst.delete(11); expect(removed11).toBeInstanceOf(Array); expect(removed11[0]).toBeDefined(); expect(removed11[0].deleted).toBeDefined(); @@ -66,7 +68,7 @@ describe('Individual package BST operations test', () => { expect(bst.getHeight(15)).toBe(1); - const removed1 = bst.remove(1); + const removed1 = bst.delete(1); expect(removed1).toBeInstanceOf(Array); expect(removed1[0]).toBeDefined(); expect(removed1[0].deleted).toBeDefined(); @@ -76,7 +78,7 @@ describe('Individual package BST operations test', () => { expect(bst.getHeight()).toBe(4); - const removed4 = bst.remove(4); + const removed4 = bst.delete(4); expect(removed4).toBeInstanceOf(Array); expect(removed4[0]).toBeDefined(); expect(removed4[0].deleted).toBeDefined(); @@ -84,7 +86,7 @@ describe('Individual package BST operations test', () => { expect(bst.isAVLBalanced()).toBe(true); expect(bst.getHeight()).toBe(4); - const removed10 = bst.remove(10); + const removed10 = bst.delete(10); expect(removed10).toBeInstanceOf(Array); expect(removed10[0]).toBeDefined(); expect(removed10[0].deleted).toBeDefined(); @@ -92,7 +94,7 @@ describe('Individual package BST operations test', () => { expect(bst.isAVLBalanced()).toBe(false); expect(bst.getHeight()).toBe(4); - const removed15 = bst.remove(15); + const removed15 = bst.delete(15); expect(removed15).toBeInstanceOf(Array); expect(removed15[0]).toBeDefined(); expect(removed15[0].deleted).toBeDefined(); @@ -101,7 +103,7 @@ describe('Individual package BST operations test', () => { expect(bst.isAVLBalanced()).toBe(true); expect(bst.getHeight()).toBe(3); - const removed5 = bst.remove(5); + const removed5 = bst.delete(5); expect(removed5).toBeInstanceOf(Array); expect(removed5[0]).toBeDefined(); expect(removed5[0].deleted).toBeDefined(); @@ -110,7 +112,7 @@ describe('Individual package BST operations test', () => { expect(bst.isAVLBalanced()).toBe(true); expect(bst.getHeight()).toBe(3); - const removed13 = bst.remove(13); + const removed13 = bst.delete(13); expect(removed13).toBeInstanceOf(Array); expect(removed13[0]).toBeDefined(); expect(removed13[0].deleted).toBeDefined(); @@ -118,7 +120,7 @@ describe('Individual package BST operations test', () => { expect(bst.isAVLBalanced()).toBe(true); expect(bst.getHeight()).toBe(3); - const removed3 = bst.remove(3); + const removed3 = bst.delete(3); expect(removed3).toBeInstanceOf(Array); expect(removed3[0]).toBeDefined(); expect(removed3[0].deleted).toBeDefined(); @@ -126,7 +128,7 @@ describe('Individual package BST operations test', () => { expect(bst.isAVLBalanced()).toBe(false); expect(bst.getHeight()).toBe(3); - const removed8 = bst.remove(8); + const removed8 = bst.delete(8); expect(removed8).toBeInstanceOf(Array); expect(removed8[0]).toBeDefined(); expect(removed8[0].deleted).toBeDefined(); @@ -134,16 +136,16 @@ describe('Individual package BST operations test', () => { expect(bst.isAVLBalanced()).toBe(true); expect(bst.getHeight()).toBe(3); - const removed6 = bst.remove(6); + const removed6 = bst.delete(6); expect(removed6).toBeInstanceOf(Array); expect(removed6[0]).toBeDefined(); expect(removed6[0].deleted).toBeDefined(); if (removed6[0].deleted) expect(removed6[0].deleted.key).toBe(6); - expect(bst.remove(6).length).toBe(0); + expect(bst.delete(6).length).toBe(0); expect(bst.isAVLBalanced()).toBe(false); expect(bst.getHeight()).toBe(3); - const removed7 = bst.remove(7); + const removed7 = bst.delete(7); expect(removed7).toBeInstanceOf(Array); expect(removed7[0]).toBeDefined(); expect(removed7[0].deleted).toBeDefined(); @@ -151,7 +153,7 @@ describe('Individual package BST operations test', () => { expect(bst.isAVLBalanced()).toBe(false); expect(bst.getHeight()).toBe(3); - const removed9 = bst.remove(9); + const removed9 = bst.delete(9); expect(removed9).toBeInstanceOf(Array); expect(removed9[0]).toBeDefined(); expect(removed9[0].deleted).toBeDefined(); @@ -159,7 +161,7 @@ describe('Individual package BST operations test', () => { expect(bst.isAVLBalanced()).toBe(false); expect(bst.getHeight()).toBe(3); - const removed14 = bst.remove(14); + const removed14 = bst.delete(14); expect(removed14).toBeInstanceOf(Array); expect(removed14[0]).toBeDefined(); expect(removed14[0].deleted).toBeDefined(); @@ -174,7 +176,7 @@ describe('Individual package BST operations test', () => { expect(bfsIDs[1]).toBe(12); expect(bfsIDs[2]).toBe(16); - const bfsNodes = bst.bfs('node'); + const bfsNodes = bst.bfs(node => node); expect(bfsNodes[0].key).toBe(2); expect(bfsNodes[1].key).toBe(12); expect(bfsNodes[2].key).toBe(16); @@ -204,7 +206,8 @@ describe('Individual package BST operations test', () => { objBST.addMany( values.map(item => item.key), - values + values, + false ); expect(objBST.root).toBeInstanceOf(BSTNode); @@ -217,10 +220,10 @@ describe('Individual package BST operations test', () => { expect(node6 && objBST.getHeight(node6)).toBe(2); expect(node6 && objBST.getDepth(node6)).toBe(3); - const nodeId10 = objBST.get(10, 'key'); + const nodeId10 = objBST.get(10); expect(nodeId10?.key).toBe(10); - const nodeVal9 = objBST.get(9, 'key'); + const nodeVal9 = objBST.get(9); expect(nodeVal9?.key).toBe(9); const leftMost = objBST.getLeftMost(); @@ -231,10 +234,12 @@ describe('Individual package BST operations test', () => { const minNodeBySpecificNode = node15 && objBST.getLeftMost(node15); expect(minNodeBySpecificNode?.key).toBe(12); - const subTreeSum = node15 && objBST.subTreeSum(node15); + let subTreeSum = 0; + node15 && objBST.subTreeTraverse(node => (subTreeSum += node.key), node15); expect(subTreeSum).toBe(70); - const lesserSum = objBST.lesserSum(10); + let lesserSum = 0; + objBST.lesserOrGreaterTraverse(node => (lesserSum += node.key), CP.lt, 10); expect(lesserSum).toBe(45); expect(node15).toBeInstanceOf(BSTNode); @@ -242,18 +247,18 @@ describe('Individual package BST operations test', () => { const node11 = objBST.get(11); expect(node11).toBeInstanceOf(BSTNode); - const dfsInorderNodes = objBST.dfs('in', 'node'); + const dfsInorderNodes = objBST.dfs(node => node, 'in'); expect(dfsInorderNodes[0].key).toBe(1); expect(dfsInorderNodes[dfsInorderNodes.length - 1].key).toBe(16); objBST.perfectlyBalance(); expect(objBST.isPerfectlyBalanced()).toBe(true); - const bfsNodesAfterBalanced = objBST.bfs('node'); + const bfsNodesAfterBalanced = objBST.bfs(node => node); expect(bfsNodesAfterBalanced[0].key).toBe(8); expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16); - const removed11 = objBST.remove(11); + const removed11 = objBST.delete(11); expect(removed11).toBeInstanceOf(Array); expect(removed11[0]).toBeDefined(); expect(removed11[0].deleted).toBeDefined(); @@ -264,7 +269,7 @@ describe('Individual package BST operations test', () => { expect(node15 && objBST.getHeight(node15)).toBe(2); - const removed1 = objBST.remove(1); + const removed1 = objBST.delete(1); expect(removed1).toBeInstanceOf(Array); expect(removed1[0]).toBeDefined(); expect(removed1[0].deleted).toBeDefined(); @@ -274,7 +279,7 @@ describe('Individual package BST operations test', () => { expect(objBST.getHeight()).toBe(4); - const removed4 = objBST.remove(4); + const removed4 = objBST.delete(4); expect(removed4).toBeInstanceOf(Array); expect(removed4[0]).toBeDefined(); expect(removed4[0].deleted).toBeDefined(); @@ -282,7 +287,7 @@ describe('Individual package BST operations test', () => { expect(objBST.isAVLBalanced()).toBe(true); expect(objBST.getHeight()).toBe(4); - const removed10 = objBST.remove(10); + const removed10 = objBST.delete(10); expect(removed10).toBeInstanceOf(Array); expect(removed10[0]).toBeDefined(); expect(removed10[0].deleted).toBeDefined(); @@ -290,7 +295,7 @@ describe('Individual package BST operations test', () => { expect(objBST.isAVLBalanced()).toBe(false); expect(objBST.getHeight()).toBe(4); - const removed15 = objBST.remove(15); + const removed15 = objBST.delete(15); expect(removed15).toBeInstanceOf(Array); expect(removed15[0]).toBeDefined(); expect(removed15[0].deleted).toBeDefined(); @@ -299,7 +304,7 @@ describe('Individual package BST operations test', () => { expect(objBST.isAVLBalanced()).toBe(true); expect(objBST.getHeight()).toBe(3); - const removed5 = objBST.remove(5); + const removed5 = objBST.delete(5); expect(removed5).toBeInstanceOf(Array); expect(removed5[0]).toBeDefined(); expect(removed5[0].deleted).toBeDefined(); @@ -308,7 +313,7 @@ describe('Individual package BST operations test', () => { expect(objBST.isAVLBalanced()).toBe(true); expect(objBST.getHeight()).toBe(3); - const removed13 = objBST.remove(13); + const removed13 = objBST.delete(13); expect(removed13).toBeInstanceOf(Array); expect(removed13[0]).toBeDefined(); expect(removed13[0].deleted).toBeDefined(); @@ -316,7 +321,7 @@ describe('Individual package BST operations test', () => { expect(objBST.isAVLBalanced()).toBe(true); expect(objBST.getHeight()).toBe(3); - const removed3 = objBST.remove(3); + const removed3 = objBST.delete(3); expect(removed3).toBeInstanceOf(Array); expect(removed3[0]).toBeDefined(); expect(removed3[0].deleted).toBeDefined(); @@ -324,7 +329,7 @@ describe('Individual package BST operations test', () => { expect(objBST.isAVLBalanced()).toBe(false); expect(objBST.getHeight()).toBe(3); - const removed8 = objBST.remove(8); + const removed8 = objBST.delete(8); expect(removed8).toBeInstanceOf(Array); expect(removed8[0]).toBeDefined(); expect(removed8[0].deleted).toBeDefined(); @@ -332,16 +337,16 @@ describe('Individual package BST operations test', () => { expect(objBST.isAVLBalanced()).toBe(true); expect(objBST.getHeight()).toBe(3); - const removed6 = objBST.remove(6); + const removed6 = objBST.delete(6); expect(removed6).toBeInstanceOf(Array); expect(removed6[0]).toBeDefined(); expect(removed6[0].deleted).toBeDefined(); if (removed6[0].deleted) expect(removed6[0].deleted.key).toBe(6); - expect(objBST.remove(6).length).toBe(0); + expect(objBST.delete(6).length).toBe(0); expect(objBST.isAVLBalanced()).toBe(false); expect(objBST.getHeight()).toBe(3); - const removed7 = objBST.remove(7); + const removed7 = objBST.delete(7); expect(removed7).toBeInstanceOf(Array); expect(removed7[0]).toBeDefined(); expect(removed7[0].deleted).toBeDefined(); @@ -349,7 +354,7 @@ describe('Individual package BST operations test', () => { expect(objBST.isAVLBalanced()).toBe(false); expect(objBST.getHeight()).toBe(3); - const removed9 = objBST.remove(9); + const removed9 = objBST.delete(9); expect(removed9).toBeInstanceOf(Array); expect(removed9[0]).toBeDefined(); expect(removed9[0].deleted).toBeDefined(); @@ -357,7 +362,7 @@ describe('Individual package BST operations test', () => { expect(objBST.isAVLBalanced()).toBe(false); expect(objBST.getHeight()).toBe(3); - const removed14 = objBST.remove(14); + const removed14 = objBST.delete(14); expect(removed14).toBeInstanceOf(Array); expect(removed14[0]).toBeDefined(); expect(removed14[0].deleted).toBeDefined(); @@ -372,7 +377,7 @@ describe('Individual package BST operations test', () => { expect(bfsIDs[1]).toBe(12); expect(bfsIDs[2]).toBe(16); - const bfsNodes = objBST.bfs('node'); + const bfsNodes = objBST.bfs(node => node); expect(bfsNodes[0].key).toBe(2); expect(bfsNodes[1].key).toBe(12); expect(bfsNodes[2].key).toBe(16); From 3983ab089c10adb97053258a937816c597c8a8c1 Mon Sep 17 00:00:00 2001 From: Revone Date: Mon, 23 Oct 2023 22:36:49 +0800 Subject: [PATCH 13/46] [binary-tree] Each method that traverses based on the root node can specify any node within the tree as the root node. --- src/data-structures/binary-tree/avl-tree.ts | 16 +++--- .../binary-tree/binary-tree.ts | 18 ++++--- src/data-structures/binary-tree/bst.ts | 16 +++--- .../binary-tree/tree-multiset.ts | 2 +- test/config.ts | 1 + .../binary-tree/binary-tree.test.ts | 50 +++++++++++++++++++ .../data-structures/binary-tree/bst.test.ts | 9 +++- .../binary-tree/tree-multiset.test.ts | 3 +- test/utils/big-o.ts | 3 +- 9 files changed, 91 insertions(+), 27 deletions(-) create mode 100644 test/config.ts diff --git a/src/data-structures/binary-tree/avl-tree.ts b/src/data-structures/binary-tree/avl-tree.ts index f5d5aca..3081725 100644 --- a/src/data-structures/binary-tree/avl-tree.ts +++ b/src/data-structures/binary-tree/avl-tree.ts @@ -72,27 +72,25 @@ export class AVLTree = AVLTreeNode> extends B /** * The function overrides the add method of a binary tree node and balances the tree after inserting a new node. - * @param {BinaryTreeNodeKey} key - The `key` parameter is the identifier of the binary tree node that we want to add. + * @param keyOrNode - The `keyOrNode` parameter is either a key or a node that needs to be added to the binary tree. * @param [val] - The `val` parameter is an optional value that can be assigned to the node being added. It is of type * `N['val']`, which means it should be of the same type as the `val` property of the nodes in the binary tree. * @returns The method is returning the inserted node, or null or undefined if the insertion was not successful. */ - override add(key: BinaryTreeNodeKey, val?: N['val']): N | null | undefined { + override add(keyOrNode: BinaryTreeNodeKey | N | null, val?: N['val']): N | null | undefined { // TODO support node as a param - const inserted = super.add(key, val); + const inserted = super.add(keyOrNode, val); if (inserted) this._balancePath(inserted); return inserted; } /** - * The function overrides the delete method of a binary tree and performs additional operations to balance the tree after - * deletion. - * @param {BinaryTreeNodeKey} key - The `key` parameter represents the identifier of the binary tree node that needs to be - * removed. + * The function overrides the delete method of a binary tree and performs additional operations to balance the tree after deletion. * @returns The method is returning an array of `BinaryTreeDeletedResult` objects. + * @param nodeOrKey - The `nodeOrKey` parameter is either a node or a key that needs to be deleted from the binary tree. */ - override delete(key: BinaryTreeNodeKey): BinaryTreeDeletedResult[] { - const deletedResults = super.delete(key); + override delete(nodeOrKey: N | BinaryTreeNodeKey): BinaryTreeDeletedResult[] { + const deletedResults = super.delete(nodeOrKey); for (const {needBalanced} of deletedResults) { if (needBalanced) { this._balancePath(needBalanced); diff --git a/src/data-structures/binary-tree/binary-tree.ts b/src/data-structures/binary-tree/binary-tree.ts index 3c58236..515e526 100644 --- a/src/data-structures/binary-tree/binary-tree.ts +++ b/src/data-structures/binary-tree/binary-tree.ts @@ -646,7 +646,7 @@ export class BinaryTree = BinaryTreeNode> * @param {N | null} subTreeRoot - The `node` parameter represents the root node of a binary search tree (BST). * @returns a boolean value. */ - isSubtreeBST(subTreeRoot: N | null): boolean { + isSubtreeBST(subTreeRoot: N): boolean { // TODO there is a bug if (!subTreeRoot) return true; @@ -681,6 +681,7 @@ export class BinaryTree = BinaryTreeNode> * @returns The `isBST()` function is returning a boolean value. */ isBST(): boolean { + if (this.root === null) return true; return this.isSubtreeBST(this.root); } @@ -814,7 +815,7 @@ export class BinaryTree = BinaryTreeNode> bfs( callback: BFSCallback = this._defaultCallbackByKey, withLevel: boolean = false, - node?: N | null + node: N | null = this.root ): BFSCallbackReturn[] { if (!node) node = this.root; if (!node) return []; @@ -870,18 +871,23 @@ export class BinaryTree = BinaryTreeNode> /** * The `morris` function performs an in-order, pre-order, or post-order traversal on a binary tree using the Morris traversal algorithm. + * The Morris algorithm only modifies the tree's structure during traversal; once the traversal is complete, + * the tree's structure should be restored to its original state to maintain the tree's integrity. + * This is because the purpose of the Morris algorithm is to save space rather than permanently alter the tree's shape. * @param {'in' | 'pre' | 'post'} [pattern] - The traversal pattern: 'in' (in-order), 'pre' (pre-order), or 'post' (post-order). * @param callback - The `callback` parameter is a function that takes a node as a parameter and returns a value. + * @param beginRoot - The `beginRoot` parameter is an optional parameter of type `N` or `null`. It represents the * @returns An array of BinaryTreeNodeProperties objects. */ morris( callback: MapCallback = this._defaultCallbackByKey, - pattern: DFSOrderPattern = 'in' + pattern: DFSOrderPattern = 'in', + beginRoot: N | null = this.root ): MapCallbackReturn[] { - if (this.root === null) return []; + if (beginRoot === null) return []; const ans: MapCallbackReturn[] = []; - let cur: N | null | undefined = this.root; + let cur: N | null | undefined = beginRoot; const _reverseEdge = (node: N | null | undefined) => { let pre: N | null | undefined = null; let next: N | null | undefined = null; @@ -952,7 +958,7 @@ export class BinaryTree = BinaryTreeNode> } cur = cur.right; } - _printEdge(this.root); + _printEdge(beginRoot); break; } return ans; diff --git a/src/data-structures/binary-tree/bst.ts b/src/data-structures/binary-tree/bst.ts index e5ae80c..eb245f0 100644 --- a/src/data-structures/binary-tree/bst.ts +++ b/src/data-structures/binary-tree/bst.ts @@ -227,10 +227,10 @@ export class BST = BSTNode> extends BinaryTree * the values at index 0 and 1 is less than, otherwise it returns the key of the leftmost node. If the comparison is * equal, it returns the key of the rightmost node. If there are no nodes in the tree, it returns 0. */ - lastKey(): BinaryTreeNodeKey { - if (this._compare(0, 1) === CP.lt) return this.getRightMost()?.key ?? 0; - else if (this._compare(0, 1) === CP.gt) return this.getLeftMost()?.key ?? 0; - else return this.getRightMost()?.key ?? 0; + lastKey(beginRoot: N | null = this.root): BinaryTreeNodeKey { + if (this._compare(0, 1) === CP.lt) return this.getRightMost(beginRoot)?.key ?? 0; + else if (this._compare(0, 1) === CP.gt) return this.getLeftMost(beginRoot)?.key ?? 0; + else return this.getRightMost(beginRoot)?.key ?? 0; } /** @@ -312,13 +312,13 @@ export class BST = BSTNode> extends BinaryTree lesserOrGreaterTraverse( callback: MapCallback = this._defaultCallbackByKey, lesserOrGreater: CP = CP.lt, - node: N | BinaryTreeNodeKey | null + node: N | BinaryTreeNodeKey | null = this.root ): MapCallbackReturn { if (typeof node === 'number') node = this.get(node); const ans: MapCallbackReturn[] = []; - if (!node) return []; + if (!node) return ans; const key = node.key; - if (!this.root) return false; + if (!this.root) return ans; if (this.loopType === LoopType.RECURSIVE) { const _traverse = (cur: N) => { @@ -331,7 +331,7 @@ export class BST = BSTNode> extends BinaryTree }; _traverse(this.root); - return true; + return ans; } else { const queue = new Queue([this.root]); while (queue.size > 0) { diff --git a/src/data-structures/binary-tree/tree-multiset.ts b/src/data-structures/binary-tree/tree-multiset.ts index c2ea9fa..b3fcbb1 100644 --- a/src/data-structures/binary-tree/tree-multiset.ts +++ b/src/data-structures/binary-tree/tree-multiset.ts @@ -293,7 +293,7 @@ export class TreeMultiset = TreeMultiset * not be taken into account when removing it. If `ignoreCount` is set to `false * @returns The function `delete` returns an array of `BinaryTreeDeletedResult` objects. */ - override delete(nodeOrKey: N | BinaryTreeNodeKey, ignoreCount = false): BinaryTreeDeletedResult[] { + override delete(nodeOrKey: N | BinaryTreeNodeKey, ignoreCount = false): BinaryTreeDeletedResult[]{ const bstDeletedResult: BinaryTreeDeletedResult[] = []; if (!this.root) return bstDeletedResult; diff --git a/test/config.ts b/test/config.ts new file mode 100644 index 0000000..2316e5e --- /dev/null +++ b/test/config.ts @@ -0,0 +1 @@ +export const isDebugTest = true; diff --git a/test/unit/data-structures/binary-tree/binary-tree.test.ts b/test/unit/data-structures/binary-tree/binary-tree.test.ts index acd8368..21cbe99 100644 --- a/test/unit/data-structures/binary-tree/binary-tree.test.ts +++ b/test/unit/data-structures/binary-tree/binary-tree.test.ts @@ -144,3 +144,53 @@ describe('BinaryTree', () => { expect(binaryTree.root).toBeNull(); }); }); + +describe('BinaryTree Morris Traversal', () => { + // Create a binary tree + const tree = new BinaryTree>(); + tree.add(1); + tree.add(2); + tree.add(3); + tree.add(4); + tree.add(5); + it('should perform in-order Morris traversal correctly as dfs traversal', () => { + // Perform in-order Morris traversal + const result = tree.morris(node => node.key, 'in'); + + // Expected in-order traversal result + const expected = [4, 2, 5, 1, 3]; + + expect(result).toEqual(expected); + expect(tree.dfs(node => node.key, 'in')).toEqual(expected); + }); + + it('should perform pre-order Morris traversal correctly as dfs traversal', () => { + // Perform pre-order Morris traversal + const result = tree.morris(node => node.key, 'pre'); + + // Expected pre-order traversal result + const expected = [1, 2, 4, 5, 3]; + + expect(result).toEqual(expected); + expect(tree.dfs(node => node.key, 'pre')).toEqual(expected); + }); + + it('should perform post-order Morris traversal correctly as dfs traversal', () => { + // Perform post-order Morris traversal + const result = tree.morris(node => node.key, 'post'); + + // Expected post-order traversal result + const expected = [4, 5, 2, 3, 1]; + + expect(result).toEqual([4, 5, 2, 3, 1]); + expect(tree.dfs(node => node.key, 'post')).toEqual(expected); + }); + + it('after morris traversals should the structure of the tree be correct', () => { + const node1 = tree.get(1); + const node2 = tree.get(2); + const node3 = tree.get(3); + expect(node1?.left).toBe(node2); + expect(node1?.right).toBe(node3); + }); +}); diff --git a/test/unit/data-structures/binary-tree/bst.test.ts b/test/unit/data-structures/binary-tree/bst.test.ts index 75d4e2d..9683af9 100644 --- a/test/unit/data-structures/binary-tree/bst.test.ts +++ b/test/unit/data-structures/binary-tree/bst.test.ts @@ -1,6 +1,7 @@ import {BST, BSTNode, CP} from '../../../../src'; +import {isDebugTest} from '../../../config'; -const isDebug = true; +const isDebug = isDebugTest; describe('BST operations test', () => { it('should perform various operations on a Binary Search Tree with numeric values', () => { @@ -444,4 +445,10 @@ describe('BST Performance test', function () { isDebug && console.log('---listLevels', arr); isDebug && console.log('---listLevels', performance.now() - startL); }); + + it('should the lastKey of a BST to be the largest key', function () { + const bst = new BST(); + bst.addMany([9, 8, 7, 3, 1, 2, 5, 4, 6], undefined, false); + expect(bst.lastKey()).toBe(9); + }); }); diff --git a/test/unit/data-structures/binary-tree/tree-multiset.test.ts b/test/unit/data-structures/binary-tree/tree-multiset.test.ts index 4a9a101..6812143 100644 --- a/test/unit/data-structures/binary-tree/tree-multiset.test.ts +++ b/test/unit/data-structures/binary-tree/tree-multiset.test.ts @@ -1,6 +1,7 @@ import {CP, TreeMultiset, TreeMultisetNode} from '../../../../src'; +import {isDebugTest} from '../../../config'; -const isDebug = false; +const isDebug = isDebugTest; describe('TreeMultiset operations test', () => { it('should perform various operations on a Binary Search Tree with numeric values', () => { const treeMultiset = new TreeMultiset(); diff --git a/test/utils/big-o.ts b/test/utils/big-o.ts index e9082a8..43d7eca 100644 --- a/test/utils/big-o.ts +++ b/test/utils/big-o.ts @@ -1,6 +1,7 @@ import {AnyFunction} from '../types'; +import {isDebugTest} from '../config'; -const isDebug = false; +const isDebug = isDebugTest; const orderReducedBy = 2; // reduction of bigO's order compared to the baseline bigO export const magnitude = { From 6c9578368c9215f7c9b936b192f7e12e062d1b58 Mon Sep 17 00:00:00 2001 From: Revone Date: Tue, 24 Oct 2023 00:03:48 +0800 Subject: [PATCH 14/46] [binary-tree] Add an 'iterationType' parameter to all methods compatible with both recursion and iteration, allowing for specifying a particular iteration method in each method. --- .../binary-tree/binary-tree.ts | 114 +++++++++++------- src/data-structures/binary-tree/bst.ts | 65 +++++----- .../binary-tree/tree-multiset.ts | 8 +- src/types/data-structures/binary-tree.ts | 4 +- 4 files changed, 110 insertions(+), 81 deletions(-) diff --git a/src/data-structures/binary-tree/binary-tree.ts b/src/data-structures/binary-tree/binary-tree.ts index 515e526..d5000b8 100644 --- a/src/data-structures/binary-tree/binary-tree.ts +++ b/src/data-structures/binary-tree/binary-tree.ts @@ -15,7 +15,7 @@ import type { MapCallback, MapCallbackReturn } from '../../types'; -import {BinaryTreeDeletedResult, DFSOrderPattern, FamilyPosition, LoopType} from '../../types'; +import {BinaryTreeDeletedResult, DFSOrderPattern, FamilyPosition, IterationType} from '../../types'; import {IBinaryTree} from '../../interfaces'; import {trampoline} from '../../utils'; import {Queue} from '../queue'; @@ -106,8 +106,8 @@ export class BinaryTree = BinaryTreeNode> */ constructor(options?: BinaryTreeOptions) { if (options !== undefined) { - const {loopType = LoopType.ITERATIVE} = options; - this._loopType = loopType; + const {iterationType = IterationType.ITERATIVE} = options; + this._loopType = iterationType; } } @@ -136,13 +136,13 @@ export class BinaryTree = BinaryTreeNode> return this._size; } - private _loopType: LoopType = LoopType.ITERATIVE; + private _loopType: IterationType = IterationType.ITERATIVE; - get loopType(): LoopType { + get iterationType(): IterationType { return this._loopType; } - set loopType(v: LoopType) { + set iterationType(v: IterationType) { this._loopType = v; } @@ -367,13 +367,14 @@ export class BinaryTree = BinaryTreeNode> * @param {N | BinaryTreeNodeKey | null} [beginRoot] - The `beginRoot` parameter is optional and can be of type `N` (a * generic type representing a node in a binary tree), `BinaryTreeNodeKey` (a type representing the ID of a binary tree * node), or `null`. + * @param iterationType - The `iterationType` parameter is an optional parameter of type `IterationType`. It represents the type of * @returns the height of the binary tree. */ - getHeight(beginRoot: N | BinaryTreeNodeKey | null = this.root): number { + getHeight(beginRoot: N | BinaryTreeNodeKey | null = this.root, iterationType = this.iterationType): number { if (typeof beginRoot === 'number') beginRoot = this.get(beginRoot); if (!beginRoot) return -1; - if (this._loopType === LoopType.RECURSIVE) { + if (iterationType === IterationType.RECURSIVE) { const _getMaxHeight = (cur: N | null | undefined): number => { if (!cur) return -1; const leftHeight = _getMaxHeight(cur.left); @@ -416,12 +417,13 @@ export class BinaryTree = BinaryTreeNode> * @param {N | null} [beginRoot] - The `beginRoot` parameter is an optional parameter of type `N` or `null`. It * represents the starting node from which to calculate the minimum height of a binary tree. If no value is provided * for `beginRoot`, the `this.root` property is used as the default value. + * @param iterationType - The `iterationType` parameter is an optional parameter of type `IterationType`. It represents the type of loop * @returns The function `getMinHeight` returns the minimum height of the binary tree. */ - getMinHeight(beginRoot: N | null = this.root): number { + getMinHeight(beginRoot: N | null = this.root, iterationType = this.iterationType): number { if (!beginRoot) return -1; - if (this._loopType === LoopType.RECURSIVE) { + if (iterationType === IterationType.RECURSIVE) { const _getMinHeight = (cur: N | null | undefined): number => { if (!cur) return 0; if (!cur.left && !cur.right) return 0; @@ -481,19 +483,21 @@ export class BinaryTree = BinaryTreeNode> * return only one node that matches the given `nodeProperty` or `propertyName`. If `onlyOne` is set to `true`, the * function will stop traversing the tree and return the first matching node. If `only * @param beginRoot + * @param iterationType - The `iterationType` parameter is an optional parameter of type `IterationType`. It represents the type of loop * @returns an array of nodes (type N). */ getNodes( nodeProperty: BinaryTreeNodeKey | N, callback: MapCallback = this._defaultCallbackByKey, onlyOne = false, - beginRoot: N | null = this.root + beginRoot: N | null = this.root, + iterationType = this.iterationType ): N[] { if (!beginRoot) return []; const ans: N[] = []; - if (this.loopType === LoopType.RECURSIVE) { + if (iterationType === IterationType.RECURSIVE) { const _traverse = (cur: N) => { if (callback(cur) === nodeProperty) { ans.push(cur); @@ -529,11 +533,18 @@ export class BinaryTree = BinaryTreeNode> * @param {BinaryTreeNodeKey | N} nodeProperty - The `nodeProperty` parameter can be either a `BinaryTreeNodeKey` or `N`. * It represents the property of the binary tree node that you want to check. * specifies the name of the property to be checked in the nodes. If not provided, it defaults to 'key'. + * @param beginRoot - The `beginRoot` parameter is an optional parameter of type `N` or `null`. It represents the root node of a tree or null if the tree is empty. + * @param iterationType - The `iterationType` parameter is an optional parameter of type `IterationType`. It represents the type of loop * @returns a boolean value. */ - has(nodeProperty: BinaryTreeNodeKey | N, callback: MapCallback = this._defaultCallbackByKey): boolean { + has( + nodeProperty: BinaryTreeNodeKey | N, + callback: MapCallback = this._defaultCallbackByKey, + beginRoot = this.root, + iterationType = this.iterationType + ): boolean { // TODO may support finding node by value equal - return this.getNodes(nodeProperty, callback, true).length > 0; + return this.getNodes(nodeProperty, callback, true, beginRoot, iterationType).length > 0; } /** @@ -544,12 +555,19 @@ export class BinaryTree = BinaryTreeNode> * It represents the property of the binary tree node that you want to search for. * specifies the property name to be used for searching the binary tree nodes. If this parameter is not provided, the * default value is set to `'key'`. + * @param beginRoot - The `beginRoot` parameter is an optional parameter of type `N` or `null`. It represents the root node of a tree or null if the tree is empty. + * @param iterationType - The `iterationType` parameter is an optional parameter of type `IterationType`. It represents the type of loop used to traverse the binary tree. * @returns either the value of the specified property of the node, or the node itself if no property name is provided. * If no matching node is found, it returns null. */ - get(nodeProperty: BinaryTreeNodeKey | N, callback: MapCallback = this._defaultCallbackByKey): N | null { + get( + nodeProperty: BinaryTreeNodeKey | N, + callback: MapCallback = this._defaultCallbackByKey, + beginRoot = this.root, + iterationType = this.iterationType + ): N | null { // TODO may support finding node by value equal - return this.getNodes(nodeProperty, callback, true)[0] ?? null; + return this.getNodes(nodeProperty, callback, true, beginRoot, iterationType)[0] ?? null; } /** @@ -581,17 +599,18 @@ export class BinaryTree = BinaryTreeNode> * @param {N | BinaryTreeNodeKey | null} [beginRoot] - The `beginRoot` parameter is optional and can be of type `N` (a * generic type representing a node in a binary tree), `BinaryTreeNodeKey` (a type representing the ID of a binary tree * node), or `null`. + * @param iterationType - The `iterationType` parameter is an optional parameter of type `IterationType`. It represents the type of loop used to traverse the binary tree. * @returns The function `getLeftMost` returns the leftmost node in a binary tree. If the `beginRoot` parameter is * provided, it starts the traversal from that node. If `beginRoot` is not provided or is `null`, it starts the traversal * from the root of the binary tree. The function returns the leftmost node found during the traversal. If no leftmost * node is found ( */ - getLeftMost(beginRoot: N | BinaryTreeNodeKey | null = this.root): N | null { + getLeftMost(beginRoot: N | BinaryTreeNodeKey | null = this.root, iterationType = this.iterationType): N | null { if (typeof beginRoot === 'number') beginRoot = this.get(beginRoot); if (!beginRoot) return beginRoot; - if (this._loopType === LoopType.RECURSIVE) { + if (iterationType === IterationType.RECURSIVE) { const _traverse = (cur: N): N => { if (!cur.left) return cur; return _traverse(cur.left); @@ -615,15 +634,16 @@ export class BinaryTree = BinaryTreeNode> * @param {N | null} [beginRoot] - The `node` parameter is an optional parameter of type `N` or `null`. It represents the * starting node from which we want to find the rightmost node. If no node is provided, the function will default to * using the root node of the data structure. + * @param iterationType - The `iterationType` parameter is an optional parameter of type `IterationType`. It represents the type of loop * @returns The `getRightMost` function returns the rightmost node in a binary tree. If the `node` parameter is provided, * it returns the rightmost node starting from that node. If the `node` parameter is not provided, it returns the * rightmost node starting from the root of the binary tree. */ - getRightMost(beginRoot: N | null = this.root): N | null { + getRightMost(beginRoot: N | null = this.root, iterationType = this.iterationType): N | null { // TODO support get right most by passing key in if (!beginRoot) return beginRoot; - if (this._loopType === LoopType.RECURSIVE) { + if (iterationType === IterationType.RECURSIVE) { const _traverse = (cur: N): N => { if (!cur.right) return cur; return _traverse(cur.right); @@ -643,25 +663,26 @@ export class BinaryTree = BinaryTreeNode> /** * The function checks if a binary search tree is valid by traversing it either recursively or iteratively. - * @param {N | null} subTreeRoot - The `node` parameter represents the root node of a binary search tree (BST). + * @param {N | null} beginRoot - The `node` parameter represents the root node of a binary search tree (BST). + * @param iterationType - The `iterationType` parameter is an optional parameter of type `IterationType`. It represents the type of loop * @returns a boolean value. */ - isSubtreeBST(subTreeRoot: N): boolean { + isSubtreeBST(beginRoot: N, iterationType = this.iterationType): boolean { // TODO there is a bug - if (!subTreeRoot) return true; + if (!beginRoot) return true; - if (this._loopType === LoopType.RECURSIVE) { + if (iterationType === IterationType.RECURSIVE) { const dfs = (cur: N | null | undefined, min: BinaryTreeNodeKey, max: BinaryTreeNodeKey): boolean => { if (!cur) return true; if (cur.key <= min || cur.key >= max) return false; return dfs(cur.left, min, cur.key) && dfs(cur.right, cur.key, max); }; - return dfs(subTreeRoot, Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER); + return dfs(beginRoot, Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER); } else { const stack = []; let prev = Number.MIN_SAFE_INTEGER, - curr: N | null | undefined = subTreeRoot; + curr: N | null | undefined = beginRoot; while (curr || stack.length > 0) { while (curr) { stack.push(curr); @@ -680,38 +701,40 @@ export class BinaryTree = BinaryTreeNode> * The function isBST checks if the binary tree is valid binary search tree. * @returns The `isBST()` function is returning a boolean value. */ - isBST(): boolean { + isBST(iterationType = this.iterationType): boolean { if (this.root === null) return true; - return this.isSubtreeBST(this.root); + return this.isSubtreeBST(this.root, iterationType); } /** * The function `subTreeTraverse` adds a delta value to a specified property of each node in a subtree. - * @param {N | BinaryTreeNodeKey | null} subTreeRoot - The `subTreeRoot` parameter represents the root node of a binary + * @param {N | BinaryTreeNodeKey | null} beginRoot - The `beginRoot` parameter represents the root node of a binary * tree or the ID of a node in the binary tree. It can also be `null` if there is no subtree to add to. * @param callback - The `callback` parameter is a function that takes a node as a parameter and returns a value. * specifies the property of the binary tree node that should be modified. If not provided, it defaults to 'key'. + * @param iterationType - The `iterationType` parameter is an optional parameter of type `IterationType`. It represents the type of loop * @returns a boolean value. */ subTreeTraverse( callback: MapCallback = this._defaultCallbackByKey, - subTreeRoot: N | BinaryTreeNodeKey | null = this.root + beginRoot: N | BinaryTreeNodeKey | null = this.root, + iterationType = this.iterationType ): MapCallbackReturn[] { - if (typeof subTreeRoot === 'number') subTreeRoot = this.get(subTreeRoot); + if (typeof beginRoot === 'number') beginRoot = this.get(beginRoot); const ans: MapCallbackReturn[] = []; - if (!subTreeRoot) return ans; + if (!beginRoot) return ans; - if (this._loopType === LoopType.RECURSIVE) { + if (iterationType === IterationType.RECURSIVE) { const _traverse = (cur: N) => { ans.push(callback(cur)); cur.left && _traverse(cur.left); cur.right && _traverse(cur.right); }; - _traverse(subTreeRoot); + _traverse(beginRoot); } else { - const stack: N[] = [subTreeRoot]; + const stack: N[] = [beginRoot]; while (stack.length > 0) { const cur = stack.pop()!; @@ -730,18 +753,18 @@ export class BinaryTree = BinaryTreeNode> * @param callback * @param beginRoot - The `beginRoot` parameter is an optional parameter of type `N` or `null`. It represents the * @param {'in' | 'pre' | 'post'} [pattern] - The traversal pattern: 'in' (in-order), 'pre' (pre-order), or 'post' (post-order). - * @param loopType - The type of loop to use for the depth-first search traversal. The default value is `LoopType.ITERATIVE`. + * @param iterationType - The type of loop to use for the depth-first search traversal. The default value is `IterationType.ITERATIVE`. * @returns an instance of the BinaryTreeNodeProperties class, which contains the accumulated properties of the binary tree nodes based on the specified pattern and node or property name. */ dfs( callback: MapCallback = this._defaultCallbackByKey, pattern: DFSOrderPattern = 'in', beginRoot: N | null = this.root, - loopType: LoopType = LoopType.ITERATIVE + iterationType: IterationType = IterationType.ITERATIVE ): MapCallbackReturn[] { if (!beginRoot) return []; const ans: MapCallbackReturn[] = []; - if (loopType === LoopType.RECURSIVE) { + if (iterationType === IterationType.RECURSIVE) { const _traverse = (node: N) => { switch (pattern) { case 'in': @@ -808,30 +831,31 @@ export class BinaryTree = BinaryTreeNode> /** * The `listLevels` function collects nodes from a binary tree by a specified property and organizes them into levels. - * @param {N | null} node - The `node` parameter is a BinaryTreeNode object or null. It represents the root node of a binary tree. If it is null, the function will use the root node of the current binary tree instance. * @param callback - The `callback` parameter is a function that takes a node and a level as parameters and returns a value. * @param withLevel - The `withLevel` parameter is a boolean flag that determines whether to include the level of each node in the result. If `withLevel` is set to `true`, the function will include the level of each node in the result. If `withLevel` is set to `false` or not provided, the function will not include the level of each node in the result. + * @param beginRoot - The `beginRoot` parameter is an optional parameter of type `N` or `null`. It represents the root node of a tree or null if the tree is empty. + * @param iterationType */ bfs( callback: BFSCallback = this._defaultCallbackByKey, withLevel: boolean = false, - node: N | null = this.root + beginRoot: N | null = this.root, + iterationType = this.iterationType ): BFSCallbackReturn[] { - if (!node) node = this.root; - if (!node) return []; + if (!beginRoot) return []; const ans: BFSCallbackReturn[] = []; - if (this.loopType === LoopType.RECURSIVE) { + if (iterationType === IterationType.RECURSIVE) { const _recursive = (node: N, level: number) => { callback && ans.push(callback(node, withLevel ? level : undefined)); if (node.left) _recursive(node.left, level + 1); if (node.right) _recursive(node.right, level + 1); }; - _recursive(node, 0); + _recursive(beginRoot, 0); } else { - const stack: [N, number][] = [[node, 0]]; + const stack: [N, number][] = [[beginRoot, 0]]; while (stack.length > 0) { const head = stack.pop()!; diff --git a/src/data-structures/binary-tree/bst.ts b/src/data-structures/binary-tree/bst.ts index eb245f0..6cb619a 100644 --- a/src/data-structures/binary-tree/bst.ts +++ b/src/data-structures/binary-tree/bst.ts @@ -13,7 +13,7 @@ import type { MapCallback, MapCallbackReturn } from '../../types'; -import {CP, LoopType} from '../../types'; +import {CP, IterationType} from '../../types'; import {BinaryTree, BinaryTreeNode} from './binary-tree'; import {IBinaryTree} from '../../interfaces'; import {Queue} from '../queue'; @@ -134,12 +134,14 @@ export class BST = BSTNode> extends BinaryTree * to the binary search tree. * @param {N['val'][]} data - The values of tree nodes * @param {boolean} isBalanceAdd - If true the nodes will be balance inserted in binary search method. + * @param iterationType - The `iterationType` parameter is an optional parameter that specifies whether to use a * @returns The function `addMany` returns an array of `N`, `null`, or `undefined` values. */ override addMany( keysOrNodes: (BinaryTreeNodeKey | null)[] | (N | null)[], data?: N['val'][], - isBalanceAdd = true + isBalanceAdd = true, + iterationType = this.iterationType ): (N | null | undefined)[] { // TODO this addMany function is inefficient, it should be optimized function hasNoNull(arr: (BinaryTreeNodeKey | null)[] | (N | null)[]): arr is BinaryTreeNodeKey[] | N[] { @@ -199,7 +201,7 @@ export class BST = BSTNode> extends BinaryTree } } }; - if (this.loopType === LoopType.RECURSIVE) { + if (iterationType === IterationType.RECURSIVE) { recursive(sortedKeysOrNodes, sortedData); } else { iterative(); @@ -221,16 +223,15 @@ export class BST = BSTNode> extends BinaryTree } /** - * The function returns the key of the rightmost node if the comparison between two values is less than, the key of the - * leftmost node if the comparison is greater than, and the key of the rightmost node otherwise. - * @returns The method `lastKey()` returns the key of the rightmost node in the binary tree if the comparison between - * the values at index 0 and 1 is less than, otherwise it returns the key of the leftmost node. If the comparison is - * equal, it returns the key of the rightmost node. If there are no nodes in the tree, it returns 0. + * lastKey returns the last key in a binary tree. If the binary tree is empty, it returns 0. + * @param beginRoot - The `beginRoot` parameter is an optional parameter that specifies the root node from which to begin + * the search for the last key. + * @param iterationType - The `iterationType` parameter is an optional parameter that specifies whether to use a recursive or iterative approach to search for the last key. */ - lastKey(beginRoot: N | null = this.root): BinaryTreeNodeKey { - if (this._compare(0, 1) === CP.lt) return this.getRightMost(beginRoot)?.key ?? 0; - else if (this._compare(0, 1) === CP.gt) return this.getLeftMost(beginRoot)?.key ?? 0; - else return this.getRightMost(beginRoot)?.key ?? 0; + lastKey(beginRoot: N | null = this.root, iterationType = this.iterationType): BinaryTreeNodeKey { + if (this._compare(0, 1) === CP.lt) return this.getRightMost(beginRoot, iterationType)?.key ?? 0; + else if (this._compare(0, 1) === CP.gt) return this.getLeftMost(beginRoot, iterationType)?.key ?? 0; + else return this.getRightMost(beginRoot, iterationType)?.key ?? 0; } /** @@ -243,18 +244,20 @@ export class BST = BSTNode> extends BinaryTree * return only one node that matches the given `nodeProperty` or all nodes that match the `nodeProperty`. If `onlyOne` * is set to `true`, the function will return an array with only one node (if * @param beginRoot - The `beginRoot` parameter is an optional parameter that specifies the root node from which to + * @param iterationType * @returns an array of nodes (type N). */ override getNodes( nodeProperty: BinaryTreeNodeKey | N, callback: MapCallback = this._defaultCallbackByKey, onlyOne = false, - beginRoot: N | null = this.root + beginRoot: N | null = this.root, + iterationType = this.iterationType ): N[] { if (!beginRoot) return []; const ans: N[] = []; - if (this.loopType === LoopType.RECURSIVE) { + if (iterationType === IterationType.RECURSIVE) { const _traverse = (cur: N) => { const callbackResult = callback(cur); if (callbackResult === nodeProperty) { @@ -305,29 +308,31 @@ export class BST = BSTNode> extends BinaryTree * The `lesserOrGreaterTraverse` function adds a delta value to the specified property of all nodes in a binary tree that * have a greater value than a given node. * @param callback - The `callback` parameter is a function that takes a node as a parameter and returns a value. - * @param {N | BinaryTreeNodeKey | null} node - The `node` parameter can be either of type `N` (a generic type), `BinaryTreeNodeKey`, or `null`. It * represents the node in the binary tree to which the delta value will be added. * @param lesserOrGreater - The `lesserOrGreater` parameter is an optional parameter that specifies whether the delta + * @param targetNode - The `targetNode` parameter is an optional parameter that specifies the node in the binary tree + * @param iterationType - The `iterationType` parameter is an optional parameter that specifies whether to use a */ lesserOrGreaterTraverse( callback: MapCallback = this._defaultCallbackByKey, lesserOrGreater: CP = CP.lt, - node: N | BinaryTreeNodeKey | null = this.root + targetNode: N | BinaryTreeNodeKey | null = this.root, + iterationType = this.iterationType ): MapCallbackReturn { - if (typeof node === 'number') node = this.get(node); + if (typeof targetNode === 'number') targetNode = this.get(targetNode); const ans: MapCallbackReturn[] = []; - if (!node) return ans; - const key = node.key; + if (!targetNode) return ans; + const targetKey = targetNode.key; if (!this.root) return ans; - if (this.loopType === LoopType.RECURSIVE) { + if (iterationType === IterationType.RECURSIVE) { const _traverse = (cur: N) => { - const compared = this._compare(cur.key, key); + const compared = this._compare(cur.key, targetKey); if (compared === lesserOrGreater) ans.push(callback(cur)); if (!cur.left && !cur.right) return; - if (cur.left && this._compare(cur.left.key, key) === lesserOrGreater) _traverse(cur.left); - if (cur.right && this._compare(cur.right.key, key) === lesserOrGreater) _traverse(cur.right); + if (cur.left && this._compare(cur.left.key, targetKey) === lesserOrGreater) _traverse(cur.left); + if (cur.right && this._compare(cur.right.key, targetKey) === lesserOrGreater) _traverse(cur.right); }; _traverse(this.root); @@ -337,11 +342,11 @@ export class BST = BSTNode> extends BinaryTree while (queue.size > 0) { const cur = queue.shift(); if (cur) { - const compared = this._compare(cur.key, key); + const compared = this._compare(cur.key, targetKey); if (compared === lesserOrGreater) ans.push(callback(cur)); - if (cur.left && this._compare(cur.left.key, key) === lesserOrGreater) queue.push(cur.left); - if (cur.right && this._compare(cur.right.key, key) === lesserOrGreater) queue.push(cur.right); + if (cur.left && this._compare(cur.left.key, targetKey) === lesserOrGreater) queue.push(cur.left); + if (cur.right && this._compare(cur.right.key, targetKey) === lesserOrGreater) queue.push(cur.right); } } return ans; @@ -363,13 +368,13 @@ export class BST = BSTNode> extends BinaryTree * constructs a balanced binary search tree using either a recursive or iterative approach. * @returns The function `perfectlyBalance()` returns a boolean value. */ - perfectlyBalance(): boolean { + perfectlyBalance(iterationType = this.iterationType): boolean { const sorted = this.dfs(node => node, 'in'), n = sorted.length; this.clear(); if (sorted.length < 1) return false; - if (this.loopType === LoopType.RECURSIVE) { + if (iterationType === IterationType.RECURSIVE) { const buildBalanceBST = (l: number, r: number) => { if (l > r) return; const m = l + Math.floor((r - l) / 2); @@ -404,12 +409,12 @@ export class BST = BSTNode> extends BinaryTree * The function `isAVLBalanced` checks if a binary tree is balanced according to the AVL tree property. * @returns a boolean value. */ - isAVLBalanced(): boolean { + isAVLBalanced(iterationType = this.iterationType): boolean { if (!this.root) return true; let balanced = true; - if (this.loopType === LoopType.RECURSIVE) { + if (iterationType === IterationType.RECURSIVE) { const _height = (cur: N | null | undefined): number => { if (!cur) return 0; const leftHeight = _height(cur.left), diff --git a/src/data-structures/binary-tree/tree-multiset.ts b/src/data-structures/binary-tree/tree-multiset.ts index b3fcbb1..aa51cc0 100644 --- a/src/data-structures/binary-tree/tree-multiset.ts +++ b/src/data-structures/binary-tree/tree-multiset.ts @@ -6,7 +6,7 @@ * @license MIT License */ import type {BinaryTreeNodeKey, TreeMultisetNodeNested, TreeMultisetOptions} from '../../types'; -import {BinaryTreeDeletedResult, CP, FamilyPosition, LoopType} from '../../types'; +import {BinaryTreeDeletedResult, CP, FamilyPosition, IterationType} from '../../types'; import {IBinaryTree} from '../../interfaces'; import {AVLTree, AVLTreeNode} from './avl-tree'; @@ -246,14 +246,14 @@ export class TreeMultiset = TreeMultiset * constructs a balanced binary search tree using either a recursive or iterative approach. * @returns The function `perfectlyBalance()` returns a boolean value. */ - override perfectlyBalance(): boolean { + override perfectlyBalance(iterationType = this.iterationType): boolean { const sorted = this.dfs(node => node, 'in'), n = sorted.length; if (sorted.length < 1) return false; this.clear(); - if (this.loopType === LoopType.RECURSIVE) { + if (iterationType === IterationType.RECURSIVE) { const buildBalanceBST = (l: number, r: number) => { if (l > r) return; const m = l + Math.floor((r - l) / 2); @@ -293,7 +293,7 @@ export class TreeMultiset = TreeMultiset * not be taken into account when removing it. If `ignoreCount` is set to `false * @returns The function `delete` returns an array of `BinaryTreeDeletedResult` objects. */ - override delete(nodeOrKey: N | BinaryTreeNodeKey, ignoreCount = false): BinaryTreeDeletedResult[]{ + override delete(nodeOrKey: N | BinaryTreeNodeKey, ignoreCount = false): BinaryTreeDeletedResult[] { const bstDeletedResult: BinaryTreeDeletedResult[] = []; if (!this.root) return bstDeletedResult; diff --git a/src/types/data-structures/binary-tree.ts b/src/types/data-structures/binary-tree.ts index 0371633..e392a52 100644 --- a/src/types/data-structures/binary-tree.ts +++ b/src/types/data-structures/binary-tree.ts @@ -7,7 +7,7 @@ import {BinaryTreeNode} from '../../data-structures/binary-tree'; * - `recursive`: Indicates the recursive loop type (with loops that call themselves). */ -export enum LoopType { +export enum IterationType { ITERATIVE = 'ITERATIVE', RECURSIVE = 'RECURSIVE' } @@ -44,4 +44,4 @@ export type BinaryTreeNodeProperties> = export type BinaryTreeNodeNested = BinaryTreeNode>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -export type BinaryTreeOptions = { loopType?: LoopType } +export type BinaryTreeOptions = { iterationType?: IterationType } From 74d4294320cbaebab9b139d0f0f3191a6930dce8 Mon Sep 17 00:00:00 2001 From: Revone Date: Tue, 24 Oct 2023 09:25:33 +0800 Subject: [PATCH 15/46] [binary-tree] Provide comprehensive JSDoc comments for the enhanced APIs. --- CHANGELOG.md | 4 +- package-lock.json | 4 +- package.json | 2 +- src/data-structures/binary-tree/avl-tree.ts | 76 +-- .../binary-tree/binary-tree.ts | 444 +++++++++++------- src/data-structures/binary-tree/bst.ts | 174 ++++--- .../binary-tree/tree-multiset.ts | 86 ++-- .../linked-list/linked-list.test.ts | 2 +- 8 files changed, 474 insertions(+), 318 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d60600..eb6646d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,10 +8,12 @@ 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.37.0](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) +## [v1.37.3](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) ### Changes +- Optimization [`#23`](https://github.com/zrwusa/data-structure-typed/pull/23) +- Optimization [`#20`](https://github.com/zrwusa/data-structure-typed/pull/20) - [binary-tree, graph] Replace all code that uses Arrays as makeshift Q… [`#18`](https://github.com/zrwusa/data-structure-typed/pull/18) - 1. No need for dfsIterative; integrate it directly into the dfs metho… [`#17`](https://github.com/zrwusa/data-structure-typed/pull/17) - [heap] fibonacci heap implemented. [test] big O estimate. [project] n… [`#15`](https://github.com/zrwusa/data-structure-typed/pull/15) diff --git a/package-lock.json b/package-lock.json index 1c7187c..e3fe225 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "data-structure-typed", - "version": "1.37.2", + "version": "1.37.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "data-structure-typed", - "version": "1.37.2", + "version": "1.37.3", "license": "MIT", "devDependencies": { "@types/benchmark": "^2.1.3", diff --git a/package.json b/package.json index 9881c8a..2fb8b95 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "data-structure-typed", - "version": "1.37.2", + "version": "1.37.3", "description": "Data Structures of Javascript & TypeScript. Binary Tree, BST, Graph, Heap, Priority Queue, Linked List, Queue, Deque, Stack, AVL Tree, Tree Multiset, Trie, Directed Graph, Undirected Graph, Singly Linked List, Doubly Linked List, Max Heap, Max Priority Queue, Min Heap, Min Priority Queue.", "main": "dist/index.js", "module": "lib/index.js", diff --git a/src/data-structures/binary-tree/avl-tree.ts b/src/data-structures/binary-tree/avl-tree.ts index 3081725..a1f8fb0 100644 --- a/src/data-structures/binary-tree/avl-tree.ts +++ b/src/data-structures/binary-tree/avl-tree.ts @@ -33,11 +33,12 @@ export class AVLTree = AVLTreeNode> extends B } /** - * The `_swap` function swaps the location of two nodes in a binary tree. - * @param {N} srcNode - The source node that you want to _swap with the destination node. - * @param {N} destNode - The `destNode` parameter represents the destination node where the values from `srcNode` will - * be swapped to. - * @returns The `destNode` is being returned. + * The function swaps the key, value, and height properties between two nodes in a binary tree. + * @param {N} srcNode - The `srcNode` parameter represents the source node that needs to be swapped + * with the `destNode`. + * @param {N} destNode - The `destNode` parameter represents the destination node where the values + * from the source node (`srcNode`) will be swapped to. + * @returns The method is returning the `destNode` after swapping its properties with the `srcNode`. */ protected override _swap(srcNode: N, destNode: N): N { const {key, val, height} = destNode; @@ -59,11 +60,12 @@ export class AVLTree = AVLTreeNode> extends B } /** - * The function creates a new AVL tree node with the given key and value. - * @param {BinaryTreeNodeKey} key - The `key` parameter is the identifier for the binary tree node. It is used to uniquely - * identify each node in the tree. - * @param [val] - The `val` parameter is an optional value that can be assigned to the node. It represents the value - * that will be stored in the node. + * The function creates a new AVL tree node with the specified key and value. + * @param {BinaryTreeNodeKey} key - The key parameter is the key value that will be associated with + * the new node. It is used to determine the position of the node in the binary search tree. + * @param [val] - The parameter `val` is an optional value that can be assigned to the node. It is of + * type `N['val']`, which means it can be any value that is assignable to the `val` property of the + * node type `N`. * @returns a new AVLTreeNode object with the specified key and value. */ override createNode(key: BinaryTreeNodeKey, val?: N['val']): N { @@ -71,11 +73,13 @@ export class AVLTree = AVLTreeNode> extends B } /** - * The function overrides the add method of a binary tree node and balances the tree after inserting a new node. - * @param keyOrNode - The `keyOrNode` parameter is either a key or a node that needs to be added to the binary tree. - * @param [val] - The `val` parameter is an optional value that can be assigned to the node being added. It is of type - * `N['val']`, which means it should be of the same type as the `val` property of the nodes in the binary tree. - * @returns The method is returning the inserted node, or null or undefined if the insertion was not successful. + * The function overrides the add method of a binary tree node and balances the tree after inserting + * a new node. + * @param {BinaryTreeNodeKey | N | null} keyOrNode - The `keyOrNode` parameter can accept either a + * `BinaryTreeNodeKey` or a `N` (which represents a node in the binary tree) or `null`. + * @param [val] - The `val` parameter is the value that you want to assign to the new node that you + * are adding to the binary search tree. + * @returns The method is returning the inserted node (`N`), `null`, or `undefined`. */ override add(keyOrNode: BinaryTreeNodeKey | N | null, val?: N['val']): N | null | undefined { // TODO support node as a param @@ -85,9 +89,11 @@ export class AVLTree = AVLTreeNode> extends B } /** - * The function overrides the delete method of a binary tree and performs additional operations to balance the tree after deletion. + * The function overrides the delete method of a binary tree and balances the tree after deleting a + * node if necessary. + * @param {N | BinaryTreeNodeKey} nodeOrKey - The `nodeOrKey` parameter can be either a node object + * (`N`) or a key value (`BinaryTreeNodeKey`). * @returns The method is returning an array of `BinaryTreeDeletedResult` objects. - * @param nodeOrKey - The `nodeOrKey` parameter is either a node or a key that needs to be deleted from the binary tree. */ override delete(nodeOrKey: N | BinaryTreeNodeKey): BinaryTreeDeletedResult[] { const deletedResults = super.delete(nodeOrKey); @@ -100,10 +106,10 @@ export class AVLTree = AVLTreeNode> extends B } /** - * The balance factor of a given AVL tree node is calculated by subtracting the height of its left subtree from the - * height of its right subtree. - * @param node - The parameter "node" is of type N, which represents a node in an AVL tree. - * @returns The balance factor of the given AVL tree node. + * The function calculates the balance factor of a node in a binary tree. + * @param {N} node - The parameter "node" represents a node in a binary tree data structure. + * @returns the balance factor of a given node. The balance factor is calculated by subtracting the + * height of the left subtree from the height of the right subtree. */ protected _balanceFactor(node: N): number { if (!node.right) @@ -116,8 +122,9 @@ export class AVLTree = AVLTreeNode> extends B } /** - * The function updates the height of a node in an AVL tree based on the heights of its left and right subtrees. - * @param node - The parameter `node` is an AVLTreeNode object, which represents a node in an AVL tree. + * The function updates the height of a node in a binary tree based on the heights of its left and + * right children. + * @param {N} node - The parameter "node" represents a node in a binary tree data structure. */ protected _updateHeight(node: N): void { if (!node.left && !node.right) node.height = 0; @@ -129,9 +136,10 @@ export class AVLTree = AVLTreeNode> extends B } /** - * The `_balancePath` function balances the AVL tree by performing appropriate rotations based on the balance factor of - * each node in the path from the given node to the root. - * @param node - The `node` parameter is an AVLTreeNode object, which represents a node in an AVL tree. + * The `_balancePath` function is used to update the heights of nodes and perform rotation operations + * to restore balance in an AVL tree after inserting a node. + * @param {N} node - The `node` parameter in the `_balancePath` function represents the node in the + * AVL tree that needs to be balanced. */ protected _balancePath(node: N): void { const path = this.getPathToRoot(node, false); // first O(log n) + O(log n) @@ -173,8 +181,8 @@ export class AVLTree = AVLTreeNode> extends B } /** - * The `_balanceLL` function performs a left-left rotation on an AVL tree to balance it. - * @param A - The parameter A is an AVLTreeNode object. + * The function `_balanceLL` performs a left-left rotation to balance a binary tree. + * @param {N} A - A is a node in a binary tree. */ protected _balanceLL(A: N): void { const parentOfA = A.parent; @@ -203,8 +211,8 @@ export class AVLTree = AVLTreeNode> extends B } /** - * The `_balanceLR` function performs a left-right rotation to balance an AVL tree. - * @param A - A is an AVLTreeNode object. + * The `_balanceLR` function performs a left-right rotation to balance a binary tree. + * @param {N} A - A is a node in a binary tree. */ protected _balanceLR(A: N): void { const parentOfA = A.parent; @@ -251,8 +259,8 @@ export class AVLTree = AVLTreeNode> extends B } /** - * The `_balanceRR` function performs a right-right rotation on an AVL tree to balance it. - * @param A - The parameter A is an AVLTreeNode object. + * The function `_balanceRR` performs a right-right rotation to balance a binary tree. + * @param {N} A - A is a node in a binary tree. */ protected _balanceRR(A: N): void { const parentOfA = A.parent; @@ -286,8 +294,8 @@ export class AVLTree = AVLTreeNode> extends B } /** - * The `_balanceRL` function performs a right-left rotation to balance an AVL tree. - * @param A - A is an AVLTreeNode object. + * The function `_balanceRL` performs a right-left rotation to balance a binary tree. + * @param {N} A - A is a node in a binary tree. */ protected _balanceRL(A: N): void { const parentOfA = A.parent; diff --git a/src/data-structures/binary-tree/binary-tree.ts b/src/data-structures/binary-tree/binary-tree.ts index d5000b8..7de5b1c 100644 --- a/src/data-structures/binary-tree/binary-tree.ts +++ b/src/data-structures/binary-tree/binary-tree.ts @@ -20,29 +20,45 @@ import {IBinaryTree} from '../../interfaces'; import {trampoline} from '../../utils'; import {Queue} from '../queue'; +/** + * Represents a node in a binary tree. + * @template V - The type of data stored in the node. + * @template FAMILY - The type of the family relationship in the binary tree. + */ export class BinaryTreeNode = BinaryTreeNodeNested> { /** - * The constructor function initializes a BinaryTreeNode object with a key and an optional value. - * @param {BinaryTreeNodeKey} key - The `key` parameter is of type `BinaryTreeNodeKey` and represents the unique identifier - * of the binary tree node. It is used to distinguish one node from another in the binary tree. - * @param {V} [val] - The "val" parameter is an optional parameter of type V. It represents the value that will be - * stored in the binary tree node. If no value is provided, it will be set to undefined. + * Creates a new instance of BinaryTreeNode. + * @param {BinaryTreeNodeKey} key - The key associated with the node. + * @param {V} val - The value stored in the node. */ constructor(key: BinaryTreeNodeKey, val?: V) { this.key = key; this.val = val; } + /** + * The key associated with the node. + */ key: BinaryTreeNodeKey; + /** + * The value stored in the node. + */ val: V | undefined; private _left: FAMILY | null | undefined; + /** + * Get the left child node. + */ get left(): FAMILY | null | undefined { return this._left; } + /** + * Set the left child node. + * @param {FAMILY | null | undefined} v - The left child node. + */ set left(v: FAMILY | null | undefined) { if (v) { v.parent = this as unknown as FAMILY; @@ -52,10 +68,17 @@ export class BinaryTreeNode = private _right: FAMILY | null | undefined; + /** + * Get the right child node. + */ get right(): FAMILY | null | undefined { return this._right; } + /** + * Set the right child node. + * @param {FAMILY | null | undefined} v - The right child node. + */ set right(v: FAMILY | null | undefined) { if (v) { v.parent = this as unknown as FAMILY; @@ -63,11 +86,14 @@ export class BinaryTreeNode = this._right = v; } + /** + * The parent node of the current node. + */ parent: FAMILY | null | undefined; /** - * The function determines the position of a node in a family tree structure. - * @returns a value of type `FamilyPosition`. + * Get the position of the node within its family. + * @returns {FamilyPosition} - The family position of the node. */ get familyPosition(): FamilyPosition { const that = this as unknown as FAMILY; @@ -97,64 +123,75 @@ export class BinaryTreeNode = } } +/** + * Represents a binary tree data structure. + * @template N - The type of the binary tree's nodes. + */ export class BinaryTree = BinaryTreeNode> implements IBinaryTree { /** - * This is a constructor function for a binary tree class that takes an optional options parameter. - * @param {BinaryTreeOptions} [options] - The `options` parameter is an optional object that can be passed to the - * constructor of the `BinaryTree` class. It allows you to customize the behavior of the binary tree by providing - * different configuration options. + * Creates a new instance of BinaryTree. + * @param {BinaryTreeOptions} [options] - The options for the binary tree. */ constructor(options?: BinaryTreeOptions) { if (options !== undefined) { - const {iterationType = IterationType.ITERATIVE} = options; + const { iterationType = IterationType.ITERATIVE } = options; this._loopType = iterationType; } } /** - * The function creates a new binary tree node with an optional value. - * @param {BinaryTreeNodeKey} key - The `key` parameter is the identifier for the binary tree node. It is of type - * `BinaryTreeNodeKey`, which represents the unique identifier for each node in the binary tree. - * @param [val] - The `val` parameter is an optional value that can be assigned to the node. It represents the value - * stored in the node. - * @returns a new instance of a BinaryTreeNode with the specified key and value. + * Creates a new instance of BinaryTreeNode with the given key and value. + * @param {BinaryTreeNodeKey} key - The key for the new node. + * @param {N['val']} val - The value for the new node. + * @returns {N} - The newly created BinaryTreeNode. */ createNode(key: BinaryTreeNodeKey, val?: N['val']): N { return new BinaryTreeNode(key, val) as N; } - // TODO placeholder node may need redesigned private _root: N | null = null; + /** + * Get the root node of the binary tree. + */ get root(): N | null { return this._root; } private _size = 0; + /** + * Get the number of nodes in the binary tree. + */ get size(): number { return this._size; } private _loopType: IterationType = IterationType.ITERATIVE; + /** + * Get the iteration type used in the binary tree. + */ get iterationType(): IterationType { return this._loopType; } + /** + * Set the iteration type for the binary tree. + * @param {IterationType} v - The new iteration type to set. + */ set iterationType(v: IterationType) { this._loopType = v; } /** - * The `_swap` function swaps the location of two nodes in a binary tree. - * @param {N} srcNode - The source node that you want to _swap with the destination node. - * @param {N} destNode - The `destNode` parameter represents the destination node where the values from `srcNode` will - * be swapped to. - * @returns The `destNode` is being returned. + * Swap the data of two nodes in the binary tree. + * @param {N} srcNode - The source node to swap. + * @param {N} destNode - The destination node to swap. + * @returns {N} - The destination node after the swap. */ protected _swap(srcNode: N, destNode: N): N { - const {key, val} = destNode; + const { key, val } = destNode; const tempNode = this.createNode(key, val); if (tempNode) { @@ -169,7 +206,7 @@ export class BinaryTree = BinaryTreeNode> } /** - * The clear() function resets the root, size, and maxKey properties to their initial values. + * Clear the binary tree, removing all nodes. */ clear() { this._root = null; @@ -177,26 +214,18 @@ export class BinaryTree = BinaryTreeNode> } /** - * The function checks if the size of an object is equal to zero and returns a boolean value. - * @returns A boolean value indicating whether the size of the object is 0 or not. + * Check if the binary tree is empty. + * @returns {boolean} - True if the binary tree is empty, false otherwise. */ isEmpty(): boolean { return this.size === 0; } /** - * When all leaf nodes are null, it will no longer be possible to add new entity nodes to this binary tree. - * In this scenario, null nodes serve as "sentinel nodes," "virtual nodes," or "placeholder nodes." - */ - - /** - * The `add` function adds a new node to a binary tree, either by ID or by creating a new node with a given value. - * @param {BinaryTreeNodeKey | N | null} keyOrNode - The `keyOrNode` parameter can be either a `BinaryTreeNodeKey`, which - * is a number representing the ID of a binary tree node, or it can be a `N` object, which represents a binary tree - * node itself. It can also be `null` if no node is specified. - * @param [val] - The `val` parameter is an optional value that can be assigned to the `val` property of the new node - * being added to the binary tree. - * @returns The function `add` returns either the inserted node (`N`), `null`, or `undefined`. + * Add a node with the given key and value to the binary tree. + * @param {BinaryTreeNodeKey | N | null} keyOrNode - The key or node to add to the binary tree. + * @param {N['val']} val - The value for the new node (optional). + * @returns {N | null | undefined} - The inserted node, or null if nothing was inserted, or undefined if the operation failed. */ add(keyOrNode: BinaryTreeNodeKey | N | null, val?: N['val']): N | null | undefined { const _bfs = (root: N, newNode: N | null): N | undefined | null => { @@ -252,12 +281,12 @@ export class BinaryTree = BinaryTreeNode> * values, and adds them to the binary tree. * @param {(BinaryTreeNodeKey | null)[] | (N | null)[]} keysOrNodes - An array of BinaryTreeNodeKey or BinaryTreeNode * objects, or null values. - * @param {N['val'][]} [data] - The `data` parameter is an optional array of values (`N['val'][]`) that corresponds to - * the nodes or node IDs being added. It is used to set the value of each node being added. If `data` is not provided, + * @param {N['val'][]} [values] - The `values` parameter is an optional array of values (`N['val'][]`) that corresponds to + * the nodes or node IDs being added. It is used to set the value of each node being added. If `values` is not provided, * the value of the nodes will be `undefined`. * @returns The function `addMany` returns an array of `N`, `null`, or `undefined` values. */ - addMany(keysOrNodes: (BinaryTreeNodeKey | null)[] | (N | null)[], data?: N['val'][]): (N | null | undefined)[] { + addMany(keysOrNodes: (BinaryTreeNodeKey | null)[] | (N | null)[], values?: N['val'][]): (N | null | undefined)[] { // TODO not sure addMany not be run multi times const inserted: (N | null | undefined)[] = []; @@ -273,7 +302,7 @@ export class BinaryTree = BinaryTreeNode> continue; } - const val = data?.[i]; + const val = values?.[i]; inserted.push(this.add(keyOrNode, val)); } return inserted; @@ -293,12 +322,14 @@ export class BinaryTree = BinaryTreeNode> return keysOrNodes.length === this.addMany(keysOrNodes, data).length; } + /** - * The `delete` function in TypeScript is used to delete a node from a binary search tree and returns an array of objects - * containing the deleted node and the node that needs to be balanced. - * @param {N | BinaryTreeNodeKey} nodeOrKey - The `nodeOrKey` parameter can be either a node object (`N`) or a binary tree - * node ID (`BinaryTreeNodeKey`). - * @returns The function `delete` returns an array of `BinaryTreeDeletedResult` objects. + * The `delete` function removes a node from a binary search tree and returns the deleted node along + * with the parent node that needs to be balanced. + * @param {N | BinaryTreeNodeKey} nodeOrKey - The `nodeOrKey` parameter can be either a node (`N`) or + * a key (`BinaryTreeNodeKey`). If it is a key, the function will find the corresponding node in the + * binary tree. + * @returns an array of `BinaryTreeDeletedResult` objects. */ delete(nodeOrKey: N | BinaryTreeNodeKey): BinaryTreeDeletedResult[] { const bstDeletedResult: BinaryTreeDeletedResult[] = []; @@ -343,10 +374,16 @@ export class BinaryTree = BinaryTreeNode> } /** - * The function calculates the depth of a node in a binary tree. - * @param {N | BinaryTreeNodeKey | null} distNode - The `distNode` parameter can be any node of the tree - * @param {N | BinaryTreeNodeKey | null} beginRoot - The `beginRoot` parameter can be the predecessor node of distNode - * @returns the depth of the given node or binary tree. + * The function `getDepth` calculates the depth of a given node in a binary tree relative to a + * specified root node. + * @param {N | BinaryTreeNodeKey | null} distNode - The `distNode` parameter represents the node + * whose depth we want to find in the binary tree. It can be either a node object (`N`), a key value + * of the node (`BinaryTreeNodeKey`), or `null`. + * @param {N | BinaryTreeNodeKey | null} beginRoot - The `beginRoot` parameter represents the + * starting node from which we want to calculate the depth. It can be either a node object or the key + * of a node in the binary tree. If no value is provided for `beginRoot`, it defaults to the root + * node of the binary tree. + * @returns the depth of the `distNode` relative to the `beginRoot`. */ getDepth(distNode: N | BinaryTreeNodeKey | null, beginRoot: N | BinaryTreeNodeKey | null = this.root): number { if (typeof distNode === 'number') distNode = this.get(distNode); @@ -363,11 +400,15 @@ export class BinaryTree = BinaryTreeNode> } /** - * The `getHeight` function calculates the maximum height of a binary tree, either recursively or iteratively. - * @param {N | BinaryTreeNodeKey | null} [beginRoot] - The `beginRoot` parameter is optional and can be of type `N` (a - * generic type representing a node in a binary tree), `BinaryTreeNodeKey` (a type representing the ID of a binary tree - * node), or `null`. - * @param iterationType - The `iterationType` parameter is an optional parameter of type `IterationType`. It represents the type of + * The `getHeight` function calculates the maximum height of a binary tree using either recursive or + * iterative approach. + * @param {N | BinaryTreeNodeKey | null} beginRoot - The `beginRoot` parameter represents the + * starting node from which the height of the binary tree is calculated. It can be either a node + * object (`N`), a key value of a node in the tree (`BinaryTreeNodeKey`), or `null` if no starting + * node is specified. If ` + * @param iterationType - The `iterationType` parameter is used to determine whether to calculate the + * height of the binary tree using a recursive approach or an iterative approach. It can have two + * possible values: * @returns the height of the binary tree. */ getHeight(beginRoot: N | BinaryTreeNodeKey | null = this.root, iterationType = this.iterationType): number { @@ -412,13 +453,14 @@ export class BinaryTree = BinaryTreeNode> protected _defaultCallbackByKey: MapCallback = node => node.key; /** - * The `getMinHeight` function calculates the minimum height of a binary tree using either a recursive or iterative - * approach. - * @param {N | null} [beginRoot] - The `beginRoot` parameter is an optional parameter of type `N` or `null`. It - * represents the starting node from which to calculate the minimum height of a binary tree. If no value is provided - * for `beginRoot`, the `this.root` property is used as the default value. - * @param iterationType - The `iterationType` parameter is an optional parameter of type `IterationType`. It represents the type of loop - * @returns The function `getMinHeight` returns the minimum height of the binary tree. + * The `getMinHeight` function calculates the minimum height of a binary tree using either a + * recursive or iterative approach. + * @param {N | null} beginRoot - The `beginRoot` parameter is the starting node from which we want to + * calculate the minimum height of the tree. It is optional and defaults to the root of the tree if + * not provided. + * @param iterationType - The `iterationType` parameter is used to determine the method of iteration + * to calculate the minimum height of a binary tree. It can have two possible values: + * @returns The function `getMinHeight` returns the minimum height of a binary tree. */ getMinHeight(beginRoot: N | null = this.root, iterationType = this.iterationType): number { if (!beginRoot) return -1; @@ -463,10 +505,10 @@ export class BinaryTree = BinaryTreeNode> } /** - * The function checks if a binary tree is perfectly balanced by comparing the minimum height and the height of the - * tree. - * @param {N | null} [beginRoot] - The parameter `beginRoot` is of type `N` or `null`. It represents the root node of a - * tree or null if the tree is empty. + * The function checks if a binary tree is perfectly balanced by comparing the minimum height and the + * height of the tree. + * @param {N | null} beginRoot - The parameter `beginRoot` is of type `N | null`, which means it can + * either be of type `N` (representing a node in a tree) or `null` (representing an empty tree). * @returns The method is returning a boolean value. */ isPerfectlyBalanced(beginRoot: N | null = this.root): boolean { @@ -474,17 +516,25 @@ export class BinaryTree = BinaryTreeNode> } /** - * The function `getNodes` returns an array of nodes that match a given property name and value in a binary tree. - * @param callback - * @param {BinaryTreeNodeKey | N} nodeProperty - The `nodeProperty` parameter can be either a `BinaryTreeNodeKey` or a - * generic type `N`. It represents the property of the binary tree node that you want to search for. - * specifies the property name to use when searching for nodes. If not provided, it defaults to 'key'. - * @param {boolean} [onlyOne] - The `onlyOne` parameter is an optional boolean parameter that determines whether to - * return only one node that matches the given `nodeProperty` or `propertyName`. If `onlyOne` is set to `true`, the - * function will stop traversing the tree and return the first matching node. If `only - * @param beginRoot - * @param iterationType - The `iterationType` parameter is an optional parameter of type `IterationType`. It represents the type of loop - * @returns an array of nodes (type N). + * The function `getNodes` returns an array of nodes that match a given node property, using either + * recursive or iterative traversal. + * @param {BinaryTreeNodeKey | N} nodeProperty - The `nodeProperty` parameter is either a + * `BinaryTreeNodeKey` or a generic type `N`. It represents the property of the node that we are + * searching for. It can be a specific key value or any other property of the node. + * @param callback - The `callback` parameter is a function that takes a node as input and returns a + * value. This value is compared with the `nodeProperty` parameter to determine if the node should be + * included in the result. The `callback` parameter has a default value of + * `this._defaultCallbackByKey`, which + * @param [onlyOne=false] - A boolean value indicating whether to stop searching after finding the + * first node that matches the nodeProperty. If set to true, the function will return an array with + * only one element (or an empty array if no matching node is found). If set to false (default), the + * function will continue searching for all + * @param {N | null} beginRoot - The `beginRoot` parameter is the starting node from which the + * traversal of the binary tree will begin. It is optional and defaults to the root of the binary + * tree. + * @param iterationType - The `iterationType` parameter determines the type of iteration used to + * traverse the binary tree. It can have two possible values: + * @returns The function `getNodes` returns an array of nodes (`N[]`). */ getNodes( nodeProperty: BinaryTreeNodeKey | N, @@ -528,13 +578,20 @@ export class BinaryTree = BinaryTreeNode> } /** - * The function checks if a binary tree node has a specific property. - * @param callback - The `callback` parameter is a function that takes a node as a parameter and returns a value. - * @param {BinaryTreeNodeKey | N} nodeProperty - The `nodeProperty` parameter can be either a `BinaryTreeNodeKey` or `N`. - * It represents the property of the binary tree node that you want to check. - * specifies the name of the property to be checked in the nodes. If not provided, it defaults to 'key'. - * @param beginRoot - The `beginRoot` parameter is an optional parameter of type `N` or `null`. It represents the root node of a tree or null if the tree is empty. - * @param iterationType - The `iterationType` parameter is an optional parameter of type `IterationType`. It represents the type of loop + * The function checks if a binary tree has a node with a given property or key. + * @param {BinaryTreeNodeKey | N} nodeProperty - The `nodeProperty` parameter is the key or value of + * the node that you want to find in the binary tree. It can be either a `BinaryTreeNodeKey` or a + * generic type `N`. + * @param callback - The `callback` parameter is a function that is used to determine whether a node + * matches the desired criteria. It takes a node as input and returns a boolean value indicating + * whether the node matches the criteria or not. The default callback function + * `this._defaultCallbackByKey` is used if no callback function is + * @param beginRoot - The `beginRoot` parameter is the starting point for the search. It specifies + * the node from which the search should begin. By default, it is set to `this.root`, which means the + * search will start from the root node of the binary tree. However, you can provide a different node + * as + * @param iterationType - The `iterationType` parameter specifies the type of iteration to be + * performed when searching for nodes in the binary tree. It can have one of the following values: * @returns a boolean value. */ has( @@ -548,17 +605,19 @@ export class BinaryTree = BinaryTreeNode> } /** - * The function returns the first node that matches the given property name and value, or null if no matching node is - * found. - * @param callback - The `callback` parameter is a function that takes a node as a parameter and returns a value. - * @param {BinaryTreeNodeKey | N} nodeProperty - The `nodeProperty` parameter can be either a `BinaryTreeNodeKey` or `N`. - * It represents the property of the binary tree node that you want to search for. - * specifies the property name to be used for searching the binary tree nodes. If this parameter is not provided, the - * default value is set to `'key'`. - * @param beginRoot - The `beginRoot` parameter is an optional parameter of type `N` or `null`. It represents the root node of a tree or null if the tree is empty. - * @param iterationType - The `iterationType` parameter is an optional parameter of type `IterationType`. It represents the type of loop used to traverse the binary tree. - * @returns either the value of the specified property of the node, or the node itself if no property name is provided. - * If no matching node is found, it returns null. + * The function `get` returns the first node in a binary tree that matches the given property or key. + * @param {BinaryTreeNodeKey | N} nodeProperty - The `nodeProperty` parameter is the key or value of + * the node that you want to find in the binary tree. It can be either a `BinaryTreeNodeKey` or `N` + * type. + * @param callback - The `callback` parameter is a function that is used to determine whether a node + * matches the desired criteria. It takes a node as input and returns a boolean value indicating + * whether the node matches the criteria or not. The default callback function + * (`this._defaultCallbackByKey`) is used if no callback function is + * @param beginRoot - The `beginRoot` parameter is the starting point for the search. It specifies + * the root node from which the search should begin. + * @param iterationType - The `iterationType` parameter specifies the type of iteration to be + * performed when searching for a node in the binary tree. It can have one of the following values: + * @returns either the found node (of type N) or null if no node is found. */ get( nodeProperty: BinaryTreeNodeKey | N, @@ -571,14 +630,14 @@ export class BinaryTree = BinaryTreeNode> } /** - * The function `getPathToRoot` returns an array of nodes representing the path from a given node to the root node, with - * an option to reverse the order of the nodes. - * type that represents a node in your specific implementation. - * @param beginRoot - The `beginRoot` parameter is of type `N` and represents the starting node from which you want to - * @param {boolean} [isReverse=true] - The `isReverse` parameter is a boolean flag that determines whether the resulting - * path should be reversed or not. If `isReverse` is set to `true`, the path will be reversed before returning it. If - * `isReverse` is set to `false` or not provided, the path will - * @returns The function `getPathToRoot` returns an array of nodes (`N[]`). + * The function `getPathToRoot` returns an array of nodes starting from a given node and traversing + * up to the root node, with the option to reverse the order of the nodes. + * @param {N} beginRoot - The `beginRoot` parameter represents the starting node from which you want + * to find the path to the root node. + * @param [isReverse=true] - The `isReverse` parameter is a boolean flag that determines whether the + * resulting path should be reversed or not. If `isReverse` is set to `true`, the path will be + * reversed before returning it. If `isReverse` is set to `false` or not provided, the path will + * @returns The function `getPathToRoot` returns an array of type `N[]`. */ getPathToRoot(beginRoot: N, isReverse = true): N[] { // TODO to support get path through passing key @@ -594,16 +653,15 @@ export class BinaryTree = BinaryTreeNode> } /** - * The function `getLeftMost` returns the leftmost node in a binary tree, starting from a specified node or the root if - * no node is specified. - * @param {N | BinaryTreeNodeKey | null} [beginRoot] - The `beginRoot` parameter is optional and can be of type `N` (a - * generic type representing a node in a binary tree), `BinaryTreeNodeKey` (a type representing the ID of a binary tree - * node), or `null`. - * @param iterationType - The `iterationType` parameter is an optional parameter of type `IterationType`. It represents the type of loop used to traverse the binary tree. - * @returns The function `getLeftMost` returns the leftmost node in a binary tree. If the `beginRoot` parameter is - * provided, it starts the traversal from that node. If `beginRoot` is not provided or is `null`, it starts the traversal - * from the root of the binary tree. The function returns the leftmost node found during the traversal. If no leftmost - * node is found ( + * The function `getLeftMost` returns the leftmost node in a binary tree, either using recursive or + * iterative traversal. + * @param {N | BinaryTreeNodeKey | null} beginRoot - The `beginRoot` parameter is the starting point + * for finding the leftmost node in a binary tree. It can be either a node object (`N`), a key value + * of a node (`BinaryTreeNodeKey`), or `null` if the tree is empty. + * @param iterationType - The `iterationType` parameter is used to determine the type of iteration to + * be performed when finding the leftmost node in a binary tree. It can have two possible values: + * @returns The function `getLeftMost` returns the leftmost node (`N`) in a binary tree. If there is + * no leftmost node, it returns `null`. */ getLeftMost(beginRoot: N | BinaryTreeNodeKey | null = this.root, iterationType = this.iterationType): N | null { if (typeof beginRoot === 'number') beginRoot = this.get(beginRoot); @@ -629,15 +687,15 @@ export class BinaryTree = BinaryTreeNode> } /** - * The `getRightMost` function returns the rightmost node in a binary tree, either recursively or iteratively using tail - * recursion optimization. - * @param {N | null} [beginRoot] - The `node` parameter is an optional parameter of type `N` or `null`. It represents the - * starting node from which we want to find the rightmost node. If no node is provided, the function will default to - * using the root node of the data structure. - * @param iterationType - The `iterationType` parameter is an optional parameter of type `IterationType`. It represents the type of loop - * @returns The `getRightMost` function returns the rightmost node in a binary tree. If the `node` parameter is provided, - * it returns the rightmost node starting from that node. If the `node` parameter is not provided, it returns the - * rightmost node starting from the root of the binary tree. + * The function `getRightMost` returns the rightmost node in a binary tree, either recursively or + * iteratively. + * @param {N | null} beginRoot - The `beginRoot` parameter is the starting node from which we want to + * find the rightmost node. It is of type `N | null`, which means it can either be a node of type `N` + * or `null`. If it is `null`, it means there is no starting node + * @param iterationType - The `iterationType` parameter is used to determine the type of iteration to + * be performed when finding the rightmost node in a binary tree. It can have two possible values: + * @returns The function `getRightMost` returns the rightmost node (`N`) in a binary tree. If the + * `beginRoot` parameter is `null`, it returns `null`. */ getRightMost(beginRoot: N | null = this.root, iterationType = this.iterationType): N | null { // TODO support get right most by passing key in @@ -662,10 +720,13 @@ export class BinaryTree = BinaryTreeNode> } /** - * The function checks if a binary search tree is valid by traversing it either recursively or iteratively. - * @param {N | null} beginRoot - The `node` parameter represents the root node of a binary search tree (BST). - * @param iterationType - The `iterationType` parameter is an optional parameter of type `IterationType`. It represents the type of loop - * @returns a boolean value. + * The function `isSubtreeBST` checks if a given binary tree is a valid binary search tree. + * @param {N} beginRoot - The `beginRoot` parameter is the root node of the binary tree that you want + * to check if it is a binary search tree (BST) subtree. + * @param iterationType - The `iterationType` parameter is an optional parameter that specifies the + * type of iteration to use when checking if a subtree is a binary search tree (BST). It can have two + * possible values: + * @returns The function `isSubtreeBST` returns a boolean value. */ isSubtreeBST(beginRoot: N, iterationType = this.iterationType): boolean { // TODO there is a bug @@ -698,8 +759,12 @@ export class BinaryTree = BinaryTreeNode> } /** - * The function isBST checks if the binary tree is valid binary search tree. - * @returns The `isBST()` function is returning a boolean value. + * The function checks if a binary tree is a binary search tree. + * @param iterationType - The parameter "iterationType" is used to specify the type of iteration to + * be used when checking if the binary tree is a binary search tree (BST). It is an optional + * parameter with a default value of "this.iterationType". The value of "this.iterationType" is not + * provided in + * @returns a boolean value. */ isBST(iterationType = this.iterationType): boolean { if (this.root === null) return true; @@ -707,13 +772,18 @@ export class BinaryTree = BinaryTreeNode> } /** - * The function `subTreeTraverse` adds a delta value to a specified property of each node in a subtree. - * @param {N | BinaryTreeNodeKey | null} beginRoot - The `beginRoot` parameter represents the root node of a binary - * tree or the ID of a node in the binary tree. It can also be `null` if there is no subtree to add to. - * @param callback - The `callback` parameter is a function that takes a node as a parameter and returns a value. - * specifies the property of the binary tree node that should be modified. If not provided, it defaults to 'key'. - * @param iterationType - The `iterationType` parameter is an optional parameter of type `IterationType`. It represents the type of loop - * @returns a boolean value. + * The function `subTreeTraverse` traverses a binary tree and applies a callback function to each + * node, either recursively or iteratively. + * @param callback - The `callback` parameter is a function that will be called on each node in the + * subtree traversal. It takes a single argument, which is the current node being traversed, and + * returns a value. The return values from each callback invocation will be collected and returned as + * an array. + * @param {N | BinaryTreeNodeKey | null} beginRoot - The `beginRoot` parameter is the starting point + * for traversing the subtree. It can be either a node object, a key value of a node, or `null` to + * start from the root of the tree. + * @param iterationType - The `iterationType` parameter determines the type of traversal to be + * performed on the binary tree. It can have two possible values: + * @returns The function `subTreeTraverse` returns an array of `MapCallbackReturn`. */ subTreeTraverse( callback: MapCallback = this._defaultCallbackByKey, @@ -748,13 +818,19 @@ export class BinaryTree = BinaryTreeNode> } /** - * The dfs function performs a depth-first search traversal on a binary tree and returns the accumulated properties of - * each node based on the specified pattern and property name. - * @param callback - * @param beginRoot - The `beginRoot` parameter is an optional parameter of type `N` or `null`. It represents the - * @param {'in' | 'pre' | 'post'} [pattern] - The traversal pattern: 'in' (in-order), 'pre' (pre-order), or 'post' (post-order). - * @param iterationType - The type of loop to use for the depth-first search traversal. The default value is `IterationType.ITERATIVE`. - * @returns an instance of the BinaryTreeNodeProperties class, which contains the accumulated properties of the binary tree nodes based on the specified pattern and node or property name. + * The `dfs` function performs a depth-first search traversal on a binary tree, executing a callback + * function on each node according to a specified order pattern. + * @param callback - The `callback` parameter is a function that will be called on each node during + * the depth-first search traversal. It takes a node as input and returns a value. The default value + * is `this._defaultCallbackByKey`, which is a callback function defined elsewhere in the code. + * @param {DFSOrderPattern} [pattern=in] - The `pattern` parameter determines the order in which the + * nodes are visited during the depth-first search. There are three possible values for `pattern`: + * @param {N | null} beginRoot - The `beginRoot` parameter is the starting node for the depth-first + * search. It determines where the search will begin in the tree or graph structure. If `beginRoot` + * is `null`, an empty array will be returned. + * @param {IterationType} iterationType - The `iterationType` parameter determines the type of + * iteration used in the depth-first search algorithm. It can have two possible values: + * @returns The function `dfs` returns an array of `MapCallbackReturn` values. */ dfs( callback: MapCallback = this._defaultCallbackByKey, @@ -830,11 +906,21 @@ export class BinaryTree = BinaryTreeNode> // --- start additional methods --- /** - * The `listLevels` function collects nodes from a binary tree by a specified property and organizes them into levels. - * @param callback - The `callback` parameter is a function that takes a node and a level as parameters and returns a value. - * @param withLevel - The `withLevel` parameter is a boolean flag that determines whether to include the level of each node in the result. If `withLevel` is set to `true`, the function will include the level of each node in the result. If `withLevel` is set to `false` or not provided, the function will not include the level of each node in the result. - * @param beginRoot - The `beginRoot` parameter is an optional parameter of type `N` or `null`. It represents the root node of a tree or null if the tree is empty. - * @param iterationType + * The bfs function performs a breadth-first search traversal on a binary tree, executing a callback + * function on each node. + * @param callback - The `callback` parameter is a function that will be called for each node in the + * breadth-first search. It takes a node of type `N` as its argument and returns a value of type + * `BFSCallbackReturn`. The default value for this parameter is `this._defaultCallbackByKey + * @param {boolean} [withLevel=false] - The `withLevel` parameter is a boolean flag that determines + * whether or not to include the level of each node in the callback function. If `withLevel` is set + * to `true`, the level of each node will be passed as an argument to the callback function. If + * `withLevel` is + * @param {N | null} beginRoot - The `beginRoot` parameter is the starting node for the breadth-first + * search. It determines from which node the search will begin. If `beginRoot` is `null`, the search + * will not be performed and an empty array will be returned. + * @param iterationType - The `iterationType` parameter determines the type of iteration to be used + * in the breadth-first search (BFS) algorithm. It can have two possible values: + * @returns The function `bfs` returns an array of `BFSCallbackReturn[]`. */ bfs( callback: BFSCallback = this._defaultCallbackByKey, @@ -870,9 +956,9 @@ export class BinaryTree = BinaryTreeNode> } /** - * The function returns the predecessor of a given node in a binary tree. - * @param node - The parameter `node` is a BinaryTreeNode object, representing a node in a binary tree. - * @returns the predecessor of the given node in a binary tree. + * The function returns the predecessor node of a given node in a binary tree. + * @param {N} node - The parameter "node" represents a node in a binary tree. + * @returns The function `getPredecessor` returns the predecessor node of the given node `node`. */ getPredecessor(node: N): N { if (node.left) { @@ -891,17 +977,24 @@ export class BinaryTree = BinaryTreeNode> /** * Time complexity is O(n) * Space complexity of Iterative dfs equals to recursive dfs which is O(n) because of the stack - */ - - /** - * The `morris` function performs an in-order, pre-order, or post-order traversal on a binary tree using the Morris traversal algorithm. * The Morris algorithm only modifies the tree's structure during traversal; once the traversal is complete, * the tree's structure should be restored to its original state to maintain the tree's integrity. * This is because the purpose of the Morris algorithm is to save space rather than permanently alter the tree's shape. - * @param {'in' | 'pre' | 'post'} [pattern] - The traversal pattern: 'in' (in-order), 'pre' (pre-order), or 'post' (post-order). - * @param callback - The `callback` parameter is a function that takes a node as a parameter and returns a value. - * @param beginRoot - The `beginRoot` parameter is an optional parameter of type `N` or `null`. It represents the - * @returns An array of BinaryTreeNodeProperties objects. + */ + + /** + * The `morris` function performs a depth-first traversal of a binary tree using the Morris traversal + * algorithm and returns an array of values obtained by applying a callback function to each node. + * @param callback - The `callback` parameter is a function that will be called on each node in the + * tree. It takes a node of type `N` as input and returns a value of type `MapCallbackReturn`. The + * default value for this parameter is `this._defaultCallbackByKey`. + * @param {DFSOrderPattern} [pattern=in] - The `pattern` parameter in the `morris` function + * determines the order in which the nodes of a binary tree are traversed. It can have one of the + * following values: + * @param {N | null} beginRoot - The `beginRoot` parameter is the starting node for the Morris + * traversal. It specifies the root node of the tree from which the traversal should begin. If + * `beginRoot` is `null`, an empty array will be returned. + * @returns The `morris` function returns an array of `MapCallbackReturn` values. */ morris( callback: MapCallback = this._defaultCallbackByKey, @@ -989,14 +1082,15 @@ export class BinaryTree = BinaryTreeNode> } /** - * The function adds a new node to a binary tree if there is an available position. - * @param {N | null} newNode - The `newNode` parameter is of type `N | null`, which means it can either be a node of - * type `N` or `null`. It represents the node that you want to add to the binary tree. - * @param {N} parent - The parent parameter is of type N, which represents a node in a binary tree. - * @returns either the left or right child node of the parent node, depending on which child is available for adding - * the new node. If a new node is added, the function also updates the size of the binary tree. If neither the left nor - * right child is available, the function returns undefined. If the parent node is null, the function also returns - * undefined. + * The function `_addTo` adds a new node to a binary tree if there is an available position. + * @param {N | null} newNode - The `newNode` parameter represents the node that you want to add to + * the binary tree. It can be either a node object or `null`. + * @param {N} parent - The `parent` parameter represents the parent node to which the new node will + * be added as a child. + * @returns either the left or right child node of the parent node, depending on which child is + * available for adding the new node. If a new node is added, the function also updates the size of + * the binary tree. If neither the left nor right child is available, the function returns undefined. + * If the parent node is null, the function also returns undefined. */ protected _addTo(newNode: N | null, parent: N): N | null | undefined { if (parent) { @@ -1023,9 +1117,10 @@ export class BinaryTree = BinaryTreeNode> } /** - * The function sets the root property of an object to a given value, and if the value is not null, it also sets the - * parent property of the value to undefined. - * @param {N | null} v - The parameter `v` is of type `N | null`, which means it can either be of type `N` or `null`. + * The function sets the root property of an object to a given value, and if the value is not null, + * it also sets the parent property of the value to undefined. + * @param {N | null} v - The parameter `v` is of type `N | null`, which means it can either be of + * type `N` or `null`. */ protected _setRoot(v: N | null) { if (v) { @@ -1035,8 +1130,9 @@ export class BinaryTree = BinaryTreeNode> } /** - * The function sets the size of a protected variable. - * @param {number} v - number + * The function sets the value of the protected property "_size" to the given number. + * @param {number} v - The parameter "v" is a number that represents the size value that we want to + * set. */ protected _setSize(v: number) { this._size = v; diff --git a/src/data-structures/binary-tree/bst.ts b/src/data-structures/binary-tree/bst.ts index 6cb619a..82ff5df 100644 --- a/src/data-structures/binary-tree/bst.ts +++ b/src/data-structures/binary-tree/bst.ts @@ -25,9 +25,12 @@ export class BSTNode = BSTNodeNested< } export class BST = BSTNode> extends BinaryTree implements IBinaryTree { + /** - * The constructor function initializes a binary search tree object with an optional comparator function. - * @param {BSTOptions} [options] - An optional object that contains configuration options for the binary search tree. + * The constructor function initializes a binary search tree object with an optional comparator + * function. + * @param {BSTOptions} [options] - An optional object that contains configuration options for the + * binary search tree. */ constructor(options?: BSTOptions) { super(options); @@ -41,10 +44,10 @@ export class BST = BSTNode> extends BinaryTree /** * The function creates a new binary search tree node with the given key and value. - * @param {BinaryTreeNodeKey} key - The `key` parameter is the identifier for the binary tree node. It is used to uniquely - * identify each node in the binary tree. - * @param [val] - The `val` parameter is an optional value that can be assigned to the node. It represents the value - * that will be stored in the node. + * @param {BinaryTreeNodeKey} key - The key parameter is the key value that will be associated with + * the new node. It is used to determine the position of the node in the binary search tree. + * @param [val] - The parameter `val` is an optional value that can be assigned to the node. It + * represents the value associated with the node in a binary search tree. * @returns a new instance of the BSTNode class with the specified key and value. */ override createNode(key: BinaryTreeNodeKey, val?: N['val']): N { @@ -52,13 +55,14 @@ export class BST = BSTNode> extends BinaryTree } /** - * The `add` function adds a new node to a binary search tree, either by creating a new node or by updating an existing - * node with the same ID. - * @param {BinaryTreeNodeKey | N | null} keyOrNode - The `keyOrNode` parameter can be either a `BinaryTreeNodeKey` or a `N` - * (which represents a binary tree node) or `null`. - * @param [val] - The `val` parameter is an optional value that can be assigned to the `val` property of the new node - * being added to the binary search tree. - * @returns The function `add` returns the inserted node (`inserted`) which can be of type `N`, `null`, or `undefined`. + * The `add` function in a binary search tree class inserts a new node with a given key and value + * into the tree. + * @param {BinaryTreeNodeKey | N | null} keyOrNode - The `keyOrNode` parameter can be either a + * `BinaryTreeNodeKey` (which can be a number or a string), a `BSTNode` object, or `null`. + * @param [val] - The `val` parameter is the value to be assigned to the new node being added to the + * binary search tree. + * @returns the inserted node (N) if it was successfully added to the binary search tree. If the node + * was not added or if the parameters were invalid, it returns null or undefined. */ override add(keyOrNode: BinaryTreeNodeKey | N | null, val?: N['val']): N | null | undefined { // TODO support node as a parameter @@ -127,22 +131,20 @@ export class BST = BSTNode> extends BinaryTree } /** - * The `addMany` function overrides the base class method to add multiple nodes to a binary search tree in a balanced - * manner. - * @param {[BinaryTreeNodeKey | N , N['val']][]} keysOrNodes - The `keysOrNodes` parameter in the `addMany` function is an array of - * `BinaryTreeNodeKey` or `N` (node) objects, or `null` values. It represents the nodes or node IDs that need to be added - * to the binary search tree. + * The `addMany` function is used to efficiently add multiple nodes to a binary search tree while + * maintaining balance. + * @param {[BinaryTreeNodeKey | N, N['val']][]} arr - The `arr` parameter in the `addMany` function + * represents an array of keys or nodes that need to be added to the binary search tree. It can be an + * array of `BinaryTreeNodeKey` or `N` (which represents the node type in the binary search tree) or + * `null * @param {N['val'][]} data - The values of tree nodes * @param {boolean} isBalanceAdd - If true the nodes will be balance inserted in binary search method. - * @param iterationType - The `iterationType` parameter is an optional parameter that specifies whether to use a - * @returns The function `addMany` returns an array of `N`, `null`, or `undefined` values. + * @param iterationType - The `iterationType` parameter determines the type of iteration to be used. + * It can have two possible values: + * @returns The `addMany` function returns an array of `N`, `null`, or `undefined` values. */ - override addMany( - keysOrNodes: (BinaryTreeNodeKey | null)[] | (N | null)[], - data?: N['val'][], - isBalanceAdd = true, - iterationType = this.iterationType - ): (N | null | undefined)[] { + + override addMany(keysOrNodes: (BinaryTreeNodeKey | null)[] | (N | null)[], data?: N['val'][], isBalanceAdd = true, iterationType = this.iterationType): (N | null | undefined)[] { // TODO this addMany function is inefficient, it should be optimized function hasNoNull(arr: (BinaryTreeNodeKey | null)[] | (N | null)[]): arr is BinaryTreeNodeKey[] | N[] { return arr.indexOf(null) === -1; @@ -211,22 +213,41 @@ export class BST = BSTNode> extends BinaryTree } /** - * The function returns the first node in a binary tree that matches the given property name and value. - * @param {BinaryTreeNodeKey | N} nodeProperty - The `nodeProperty` parameter can be either a `BinaryTreeNodeKey` or a - * generic type `N`. It represents the property of the binary tree node that you want to search for. - * @param callback - The `callback` parameter is a function that takes a node as a parameter and returns a value. - * specifies the property name to use for searching the binary tree nodes. If not provided, it defaults to `'key'`. - * @returns The method is returning either a BinaryTreeNodeKey or N (generic type) or null. + * The function returns the first node in the binary tree that matches the given node property and + * callback. + * @param {BinaryTreeNodeKey | N} nodeProperty - The `nodeProperty` parameter is used to specify the + * property of the binary tree node that you want to search for. It can be either a specific key + * value (`BinaryTreeNodeKey`) or a custom callback function (`MapCallback`) that determines + * whether a node matches the desired property. + * @param callback - The `callback` parameter is a function that is used to determine whether a node + * matches the desired property. It takes a node as input and returns a boolean value indicating + * whether the node matches the property or not. If no callback function is provided, the default + * callback function `_defaultCallbackByKey` is used + * @param beginRoot - The `beginRoot` parameter is the starting point for the search. It specifies + * the root node from which the search should begin. + * @param iterationType - The `iterationType` parameter is used to specify the type of iteration to + * be performed when searching for nodes in the binary tree. It can have one of the following values: + * @returns either the first node that matches the given nodeProperty and callback, or null if no + * matching node is found. */ - override get(nodeProperty: BinaryTreeNodeKey | N, callback: MapCallback = this._defaultCallbackByKey): N | null { - return this.getNodes(nodeProperty, callback, true)[0] ?? null; + override get(nodeProperty: BinaryTreeNodeKey | N, callback: MapCallback = this._defaultCallbackByKey,beginRoot = this.root, iterationType = this.iterationType): N | null { + return this.getNodes(nodeProperty, callback, true, beginRoot, iterationType)[0] ?? null; } /** - * lastKey returns the last key in a binary tree. If the binary tree is empty, it returns 0. - * @param beginRoot - The `beginRoot` parameter is an optional parameter that specifies the root node from which to begin - * the search for the last key. - * @param iterationType - The `iterationType` parameter is an optional parameter that specifies whether to use a recursive or iterative approach to search for the last key. + * The function `lastKey` returns the key of the rightmost node if the comparison result is less + * than, the key of the leftmost node if the comparison result is greater than, and the key of the + * rightmost node otherwise. + * @param {N | null} beginRoot - The `beginRoot` parameter is the starting point for finding the last + * key in a binary tree. It represents the root node of the subtree from which the search for the + * last key should begin. If no specific `beginRoot` is provided, the search will start from the root + * of the entire binary + * @param iterationType - The `iterationType` parameter is used to specify the type of iteration to + * be performed when finding the last key. It determines whether the iteration should be performed in + * pre-order, in-order, or post-order. + * @returns the key of the rightmost node in the binary tree if the comparison result is less than, + * the key of the leftmost node if the comparison result is greater than, and the key of the + * rightmost node otherwise. If no node is found, it returns 0. */ lastKey(beginRoot: N | null = this.root, iterationType = this.iterationType): BinaryTreeNodeKey { if (this._compare(0, 1) === CP.lt) return this.getRightMost(beginRoot, iterationType)?.key ?? 0; @@ -235,17 +256,25 @@ export class BST = BSTNode> extends BinaryTree } /** - * The function `getNodes` returns an array of nodes in a binary tree that match a given property value. - * @param {BinaryTreeNodeKey | N} nodeProperty - The `nodeProperty` parameter can be either a `BinaryTreeNodeKey` or an - * `N` type. It represents the property of the binary tree node that you want to compare with. - * @param callback - The `callback` parameter is a function that takes a node as a parameter and returns a value. - * specifies the property name to use for comparison. If not provided, it defaults to `'key'`. - * @param {boolean} [onlyOne] - The `onlyOne` parameter is an optional boolean parameter that determines whether to - * return only one node that matches the given `nodeProperty` or all nodes that match the `nodeProperty`. If `onlyOne` - * is set to `true`, the function will return an array with only one node (if - * @param beginRoot - The `beginRoot` parameter is an optional parameter that specifies the root node from which to - * @param iterationType - * @returns an array of nodes (type N). + * The function `getNodes` retrieves nodes from a binary tree based on a given node property or key, + * using either recursive or iterative traversal. + * @param {BinaryTreeNodeKey | N} nodeProperty - The `nodeProperty` parameter represents the property + * of the binary tree node that you want to search for. It can be either a `BinaryTreeNodeKey` or a + * generic type `N`. + * @param callback - The `callback` parameter is a function that takes a node as input and returns a + * value. This value is compared with the `nodeProperty` parameter to determine if the node should be + * included in the result. The default value for `callback` is `this._defaultCallbackByKey`, which is + * a + * @param [onlyOne=false] - A boolean value indicating whether to stop the traversal after finding + * the first node that matches the nodeProperty. If set to true, the function will return an array + * containing only that node. If set to false (default), the function will continue the traversal and + * return an array containing all nodes that match the node + * @param {N | null} beginRoot - The `beginRoot` parameter is the starting node for the traversal. It + * specifies the root node of the binary tree from which the traversal should begin. If `beginRoot` + * is `null`, an empty array will be returned. + * @param iterationType - The `iterationType` parameter determines the type of iteration used to + * traverse the binary tree. It can have one of the following values: + * @returns an array of nodes (N[]). */ override getNodes( nodeProperty: BinaryTreeNodeKey | N, @@ -305,13 +334,21 @@ export class BST = BSTNode> extends BinaryTree // --- start additional functions /** - * The `lesserOrGreaterTraverse` function adds a delta value to the specified property of all nodes in a binary tree that - * have a greater value than a given node. - * @param callback - The `callback` parameter is a function that takes a node as a parameter and returns a value. - * represents the node in the binary tree to which the delta value will be added. - * @param lesserOrGreater - The `lesserOrGreater` parameter is an optional parameter that specifies whether the delta - * @param targetNode - The `targetNode` parameter is an optional parameter that specifies the node in the binary tree - * @param iterationType - The `iterationType` parameter is an optional parameter that specifies whether to use a + * The `lesserOrGreaterTraverse` function traverses a binary tree and applies a callback function to + * nodes that have a key value lesser or greater than a target key value. + * @param callback - The `callback` parameter is a function that will be called for each node that + * meets the condition specified by the `lesserOrGreater` parameter. It takes a node as an argument + * and returns a value. + * @param {CP} lesserOrGreater - The `lesserOrGreater` parameter is used to determine whether to + * traverse nodes that are lesser than, greater than, or equal to the `targetNode`. It can take one + * of the following values: + * @param {N | BinaryTreeNodeKey | null} targetNode - The `targetNode` parameter in the + * `lesserOrGreaterTraverse` function is used to specify the node from which the traversal should + * start. It can be either a reference to a specific node (`N`), the key of a node + * (`BinaryTreeNodeKey`), or `null` to + * @param iterationType - The `iterationType` parameter determines whether the traversal should be + * done recursively or iteratively. It can have two possible values: + * @returns The function `lesserOrGreaterTraverse` returns an array of `MapCallbackReturn`. */ lesserOrGreaterTraverse( callback: MapCallback = this._defaultCallbackByKey, @@ -364,9 +401,12 @@ export class BST = BSTNode> extends BinaryTree */ /** - * The `perfectlyBalance` function takes a binary tree, performs a depth-first search to sort the nodes, and then - * constructs a balanced binary search tree using either a recursive or iterative approach. - * @returns The function `perfectlyBalance()` returns a boolean value. + * The `perfectlyBalance` function balances a binary search tree by adding nodes in a way that + * ensures the tree is perfectly balanced. + * @param iterationType - The `iterationType` parameter is an optional parameter that specifies the + * type of iteration to use when building a balanced binary search tree. It can have two possible + * values: + * @returns The function `perfectlyBalance` returns a boolean value. */ perfectlyBalance(iterationType = this.iterationType): boolean { const sorted = this.dfs(node => node, 'in'), @@ -406,7 +446,9 @@ export class BST = BSTNode> extends BinaryTree } /** - * The function `isAVLBalanced` checks if a binary tree is balanced according to the AVL tree property. + * The function checks if a binary tree is AVL balanced using either recursive or iterative approach. + * @param iterationType - The `iterationType` parameter is used to determine the method of iteration + * to check if the AVL tree is balanced. It can have two possible values: * @returns a boolean value. */ isAVLBalanced(iterationType = this.iterationType): boolean { @@ -456,12 +498,12 @@ export class BST = BSTNode> extends BinaryTree protected _comparator: BSTComparator = (a, b) => a - b; /** - * The function compares two binary tree node IDs using a comparator function and returns whether the first ID is - * greater than, less than, or equal to the second ID. - * @param {BinaryTreeNodeKey} a - "a" is a BinaryTreeNodeKey, which represents the identifier of a binary tree node. - * @param {BinaryTreeNodeKey} b - The parameter "b" in the above code refers to a BinaryTreeNodeKey. - * @returns a value of type CP (ComparisonResult). The possible return values are CP.gt (greater than), CP.lt (less - * than), or CP.eq (equal). + * The function compares two values using a comparator function and returns whether the first value + * is greater than, less than, or equal to the second value. + * @param {BinaryTreeNodeKey} a - The parameter "a" is of type BinaryTreeNodeKey. + * @param {BinaryTreeNodeKey} b - The parameter "b" in the above code represents a BinaryTreeNodeKey. + * @returns a value of type CP (ComparisonResult). The possible return values are CP.gt (greater + * than), CP.lt (less than), or CP.eq (equal). */ protected _compare(a: BinaryTreeNodeKey, b: BinaryTreeNodeKey): CP { const compared = this._comparator(a, b); diff --git a/src/data-structures/binary-tree/tree-multiset.ts b/src/data-structures/binary-tree/tree-multiset.ts index aa51cc0..7dce900 100644 --- a/src/data-structures/binary-tree/tree-multiset.ts +++ b/src/data-structures/binary-tree/tree-multiset.ts @@ -69,11 +69,11 @@ export class TreeMultiset = TreeMultiset } /** - * The function swaps the location of two nodes in a tree data structure. - * @param {N} srcNode - The source node that we want to _swap with the destination node. - * @param {N} destNode - The `destNode` parameter represents the destination node where the values from `srcNode` will - * be swapped with. - * @returns the `destNode` after swapping its values with the `srcNode`. + * The function swaps the values of two nodes in a binary tree. + * @param {N} srcNode - The source node that needs to be swapped with the destination node. + * @param {N} destNode - The `destNode` parameter represents the destination node where the values + * from `srcNode` will be swapped into. + * @returns The method is returning the `destNode` after swapping its properties with the `srcNode`. */ protected override _swap(srcNode: N, destNode: N): N { const {key, val, count, height} = destNode; @@ -96,14 +96,17 @@ export class TreeMultiset = TreeMultiset } /** - * The `add` function adds a new node to a binary search tree, maintaining the tree's properties and balancing if - * necessary. - * @param {BinaryTreeNodeKey | N} keyOrNode - The `keyOrNode` parameter can be either a `BinaryTreeNodeKey` or a `N` (which - * represents a `BinaryTreeNode`). - * @param [val] - The `val` parameter represents the value to be added to the binary tree node. - * @param {number} [count] - The `count` parameter is an optional parameter that specifies the number of times the - * value should be added to the binary tree. If the `count` parameter is not provided, it defaults to 1. - * @returns The method `add` returns either the inserted node (`N`), `null`, or `undefined`. + * The `add` function adds a new node to a binary search tree, updating the count if the key already + * exists, and balancing the tree if necessary. + * @param {BinaryTreeNodeKey | N | null} keyOrNode - The `keyOrNode` parameter can be either a + * `BinaryTreeNodeKey` (which represents the key of the node to be added), a `N` (which represents a + * node to be added), or `null` (which represents a null node). + * @param [val] - The `val` parameter represents the value associated with the key that is being + * added to the binary tree. + * @param [count=1] - The `count` parameter represents the number of occurrences of the key/value + * pair that will be added to the binary tree. It has a default value of 1, which means that if no + * count is specified, the default count will be 1. + * @returns The function `add` returns a value of type `N | null | undefined`. */ override add(keyOrNode: BinaryTreeNodeKey | N | null, val?: N['val'], count = 1): N | null | undefined { let inserted: N | null | undefined = undefined, @@ -174,13 +177,12 @@ export class TreeMultiset = TreeMultiset } /** - * The function adds a new node to a binary tree if there is an available slot on the left or right side of the parent - * node. - * @param {N | null} newNode - The `newNode` parameter represents the node that needs to be added to the tree. It can - * be either a node object (`N`) or `null`. - * @param {N} parent - The `parent` parameter represents the parent node to which the new node will be added as a - * child. - * @returns The method returns either the `parent.left`, `parent.right`, or `undefined`. + * The function adds a new node to a binary tree if there is an available slot in the parent node. + * @param {N | null} newNode - The `newNode` parameter represents the node that needs to be added to + * the tree. It can be either a node object (`N`) or `null`. + * @param {N} parent - The `parent` parameter represents the parent node to which the new node will + * be added as a child. + * @returns The method `_addTo` returns either the `parent.left`, `parent.right`, or `undefined`. */ override _addTo(newNode: N | null, parent: N): N | null | undefined { if (parent) { @@ -208,13 +210,13 @@ export class TreeMultiset = TreeMultiset } /** - * The `addMany` function takes an array of node IDs or nodes and adds them to the tree multiset, returning an array of - * the inserted nodes. - * @param {(BinaryTreeNodeKey | null)[] | (N | null)[]} keysOrNodes - An array of BinaryTreeNodeKey or BinaryTreeNode - * objects, or null values. - * @param {N['val'][]} [data] - The `data` parameter is an optional array of values (`N['val'][]`) that corresponds to - * the nodes being added. It is used when adding nodes using the `keyOrNode` and `data` arguments in the `this.add()` - * method. If provided, the `data` array should + * The `addMany` function adds multiple keys or nodes to a TreeMultiset and returns an array of the + * inserted nodes. + * @param {(BinaryTreeNodeKey | null)[] | (N | null)[]} keysOrNodes - An array of keys or nodes to be + * added to the multiset. Each element can be either a BinaryTreeNodeKey or a TreeMultisetNode. + * @param {N['val'][]} [data] - The `data` parameter is an optional array of values that correspond + * to the keys or nodes being added to the multiset. It is used to associate additional data with + * each key or node. * @returns The function `addMany` returns an array of `N`, `null`, or `undefined` values. */ override addMany( @@ -242,9 +244,12 @@ export class TreeMultiset = TreeMultiset } /** - * The `perfectlyBalance` function takes a binary tree, performs a depth-first search to sort the nodes, and then - * constructs a balanced binary search tree using either a recursive or iterative approach. - * @returns The function `perfectlyBalance()` returns a boolean value. + * The `perfectlyBalance` function in TypeScript takes a sorted array of nodes and builds a balanced + * binary search tree using either a recursive or iterative approach. + * @param iterationType - The `iterationType` parameter is an optional parameter that specifies the + * type of iteration to use when building a balanced binary search tree. It can have two possible + * values: + * @returns a boolean value. */ override perfectlyBalance(iterationType = this.iterationType): boolean { const sorted = this.dfs(node => node, 'in'), @@ -285,13 +290,16 @@ export class TreeMultiset = TreeMultiset } /** - * The `delete` function removes a node from a binary search tree and returns the deleted node along with the parent - * node that needs to be balanced. - * @param {N | BinaryTreeNodeKey | null} nodeOrKey - The `nodeOrKey` parameter can be one of the following: - * @param {boolean} [ignoreCount] - The `ignoreCount` parameter is an optional boolean parameter that determines - * whether to ignore the count of the node being removed. If `ignoreCount` is set to `true`, the count of the node will - * not be taken into account when removing it. If `ignoreCount` is set to `false - * @returns The function `delete` returns an array of `BinaryTreeDeletedResult` objects. + * The `delete` function in a binary search tree deletes a node from the tree and returns the deleted + * node along with the parent node that needs to be balanced. + * @param {N | BinaryTreeNodeKey} nodeOrKey - The `nodeOrKey` parameter can be either a node object + * (`N`) or a key value (`BinaryTreeNodeKey`). It represents the node or key that needs to be deleted + * from the binary tree. + * @param [ignoreCount=false] - A boolean flag indicating whether to ignore the count of the node + * being deleted. If set to true, the count of the node will not be considered and the node will be + * deleted regardless of its count. If set to false (default), the count of the node will be + * decremented by 1 and + * @returns The method `delete` returns an array of `BinaryTreeDeletedResult` objects. */ override delete(nodeOrKey: N | BinaryTreeNodeKey, ignoreCount = false): BinaryTreeDeletedResult[] { const bstDeletedResult: BinaryTreeDeletedResult[] = []; @@ -350,7 +358,7 @@ export class TreeMultiset = TreeMultiset } /** - * The clear() function clears the data and sets the count to 0. + * The clear() function clears the contents of a data structure and sets the count to zero. */ clear() { super.clear(); @@ -358,7 +366,7 @@ export class TreeMultiset = TreeMultiset } /** - * The function "_setCount" is used to set the value of the "_count" property. + * The function sets the value of the "_count" property. * @param {number} v - number */ protected _setCount(v: number) { diff --git a/test/unit/data-structures/linked-list/linked-list.test.ts b/test/unit/data-structures/linked-list/linked-list.test.ts index 75b2875..d7178f1 100644 --- a/test/unit/data-structures/linked-list/linked-list.test.ts +++ b/test/unit/data-structures/linked-list/linked-list.test.ts @@ -30,6 +30,6 @@ describe('LinkedList Performance Test', () => { } } - expect(doublyListPushCost).toBeLessThan(bigO.SQUARED * 5); + expect(doublyListPushCost).toBeLessThan(bigO.SQUARED * 10); }); }); From c8f0e23704902a211d20b855c07d7be11f7e96dc Mon Sep 17 00:00:00 2001 From: Revone Date: Wed, 25 Oct 2023 09:57:04 +0800 Subject: [PATCH 16/46] [project] Ensure the type files in the "types" directory match those in the "src" directory. --- .prettierignore | 10 +- package-lock.json | 509 ++++++++++-------- package.json | 25 +- scripts/config.json | 5 + scripts/publish_all_subs.sh | 11 +- scripts/publish_docs.sh | 14 +- .../binary-tree/binary-indexed-tree.ts | 306 +++++++++-- .../binary-tree/binary-tree.ts | 5 +- src/data-structures/binary-tree/bst.ts | 15 +- src/data-structures/heap/heap.ts | 3 +- .../{ => binary-tree}/avl-tree.ts | 2 +- .../binary-indexed-tree.ts} | 0 .../{ => binary-tree}/binary-tree.ts | 14 +- .../data-structures/{ => binary-tree}/bst.ts | 4 +- .../data-structures/binary-tree/index.ts | 6 + .../{ => binary-tree}/rb-tree.ts | 4 +- .../{ => binary-tree}/segment-tree.ts | 0 .../{ => binary-tree}/tree-multiset.ts | 2 +- .../{ => graph}/abstract-graph.ts | 0 .../{ => graph}/directed-graph.ts | 0 src/types/data-structures/graph/index.ts | 3 + .../data-structures/{ => graph}/map-graph.ts | 0 .../{heap.ts => graph/undirected-graph.ts} | 0 .../coordinate-map.ts} | 0 .../data-structures/hash/coordinate-set.ts | 1 + src/types/data-structures/hash/hash-map.ts | 1 + src/types/data-structures/hash/hash-table.ts | 1 + .../{hash.ts => hash/index.ts} | 0 src/types/data-structures/hash/tree-map.ts | 1 + src/types/data-structures/hash/tree-set.ts | 1 + src/types/data-structures/heap/heap.ts | 1 + src/types/data-structures/heap/index.ts | 1 + src/types/data-structures/heap/max-heap.ts | 1 + src/types/data-structures/heap/min-heap.ts | 1 + src/types/data-structures/index.ts | 22 +- .../linked-list/doubly-linked-list.ts | 1 + .../data-structures/linked-list/index.ts | 2 + .../linked-list/singly-linked-list.ts | 1 + .../linked-list/skip-linked-list.ts | 1 + src/types/data-structures/matrix/index.ts | 1 + src/types/data-structures/matrix/matrix.ts | 1 + src/types/data-structures/matrix/matrix2d.ts | 1 + .../data-structures/{ => matrix}/navigator.ts | 0 src/types/data-structures/matrix/vector2d.ts | 1 + .../data-structures/priority-queue/index.ts | 3 + .../priority-queue/max-priority-queue.ts | 1 + .../priority-queue/min-priority-queue.ts | 1 + .../priority-queue/priority-queue.ts | 1 + src/types/data-structures/queue/deque.ts | 1 + src/types/data-structures/queue/index.ts | 2 + src/types/data-structures/queue/queue.ts | 1 + src/types/data-structures/stack/index.ts | 1 + src/types/data-structures/stack/stack.ts | 1 + src/types/data-structures/tree/index.ts | 1 + src/types/data-structures/tree/tree.ts | 1 + src/types/data-structures/trie/index.ts | 1 + src/types/data-structures/trie/trie.ts | 1 + src/types/helpers.ts | 7 +- src/utils/utils.ts | 7 + test/config.js | 4 + test/types/index.js | 29 + test/types/utils/big-o.js | 2 + test/types/utils/index.js | 29 + .../binary-tree/binary-index-tree.test.ts | 284 ++++++++++ test/utils/big-o.js | 212 ++++++++ test/utils/index.js | 30 ++ test/utils/number.js | 14 + 67 files changed, 1272 insertions(+), 340 deletions(-) create mode 100644 scripts/config.json rename src/types/data-structures/{ => binary-tree}/avl-tree.ts (94%) rename src/types/data-structures/{doubly-linked-list.ts => binary-tree/binary-indexed-tree.ts} (100%) rename src/types/data-structures/{ => binary-tree}/binary-tree.ts (80%) rename src/types/data-structures/{ => binary-tree}/bst.ts (88%) create mode 100644 src/types/data-structures/binary-tree/index.ts rename src/types/data-structures/{ => binary-tree}/rb-tree.ts (88%) rename src/types/data-structures/{ => binary-tree}/segment-tree.ts (100%) rename src/types/data-structures/{ => binary-tree}/tree-multiset.ts (94%) rename src/types/data-structures/{ => graph}/abstract-graph.ts (100%) rename src/types/data-structures/{ => graph}/directed-graph.ts (100%) create mode 100644 src/types/data-structures/graph/index.ts rename src/types/data-structures/{ => graph}/map-graph.ts (100%) rename src/types/data-structures/{heap.ts => graph/undirected-graph.ts} (100%) rename src/types/data-structures/{singly-linked-list.ts => hash/coordinate-map.ts} (100%) create mode 100644 src/types/data-structures/hash/coordinate-set.ts create mode 100644 src/types/data-structures/hash/hash-map.ts create mode 100644 src/types/data-structures/hash/hash-table.ts rename src/types/data-structures/{hash.ts => hash/index.ts} (100%) create mode 100644 src/types/data-structures/hash/tree-map.ts create mode 100644 src/types/data-structures/hash/tree-set.ts create mode 100644 src/types/data-structures/heap/heap.ts create mode 100644 src/types/data-structures/heap/index.ts create mode 100644 src/types/data-structures/heap/max-heap.ts create mode 100644 src/types/data-structures/heap/min-heap.ts create mode 100644 src/types/data-structures/linked-list/doubly-linked-list.ts create mode 100644 src/types/data-structures/linked-list/index.ts create mode 100644 src/types/data-structures/linked-list/singly-linked-list.ts create mode 100644 src/types/data-structures/linked-list/skip-linked-list.ts create mode 100644 src/types/data-structures/matrix/index.ts create mode 100644 src/types/data-structures/matrix/matrix.ts create mode 100644 src/types/data-structures/matrix/matrix2d.ts rename src/types/data-structures/{ => matrix}/navigator.ts (100%) create mode 100644 src/types/data-structures/matrix/vector2d.ts create mode 100644 src/types/data-structures/priority-queue/index.ts create mode 100644 src/types/data-structures/priority-queue/max-priority-queue.ts create mode 100644 src/types/data-structures/priority-queue/min-priority-queue.ts create mode 100644 src/types/data-structures/priority-queue/priority-queue.ts create mode 100644 src/types/data-structures/queue/deque.ts create mode 100644 src/types/data-structures/queue/index.ts create mode 100644 src/types/data-structures/queue/queue.ts create mode 100644 src/types/data-structures/stack/index.ts create mode 100644 src/types/data-structures/stack/stack.ts create mode 100644 src/types/data-structures/tree/index.ts create mode 100644 src/types/data-structures/tree/tree.ts create mode 100644 src/types/data-structures/trie/index.ts create mode 100644 src/types/data-structures/trie/trie.ts create mode 100644 test/config.js create mode 100644 test/types/index.js create mode 100644 test/types/utils/big-o.js create mode 100644 test/types/utils/index.js create mode 100644 test/unit/data-structures/binary-tree/binary-index-tree.test.ts create mode 100644 test/utils/big-o.js create mode 100644 test/utils/index.js create mode 100644 test/utils/number.js diff --git a/.prettierignore b/.prettierignore index 1938daa..e459c2d 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,5 +1,5 @@ -src/types/data-structures/binary-tree.ts -src/types/data-structures/bst.ts -src/types/data-structures/avl-tree.ts -src/types/data-structures/rb-tree.ts -src/types/data-structures/tree-multiset.ts +src/types/data-structures/binary-tree/binary-tree.ts +src/types/data-structures/binary-tree/bst.ts +src/types/data-structures/binary-tree/avl-tree.ts +src/types/data-structures/binary-tree/rb-tree.ts +src/types/data-structures/binary-tree/tree-multiset.ts diff --git a/package-lock.json b/package-lock.json index e3fe225..3f14577 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,13 +1,16 @@ { "name": "data-structure-typed", - "version": "1.37.3", + "version": "1.37.9", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "data-structure-typed", - "version": "1.37.3", + "version": "1.37.9", "license": "MIT", + "dependencies": { + "data-structure-typed": "^1.37.5" + }, "devDependencies": { "@types/benchmark": "^2.1.3", "@types/jest": "^29.5.5", @@ -15,17 +18,17 @@ "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", "auto-changelog": "^2.4.0", - "avl-tree-typed": "^1.37.2", + "avl-tree-typed": "^1.37.9", "benchmark": "^2.1.4", - "binary-tree-typed": "^1.37.2", - "bst-typed": "^1.37.2", + "binary-tree-typed": "^1.37.9", + "bst-typed": "^1.37.9", "dependency-cruiser": "^14.1.0", "eslint": "^8.50.0", "eslint-config-prettier": "^9.0.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.28.1", - "heap-typed": "^1.37.2", + "heap-typed": "^1.37.9", "istanbul-badges-readme": "^1.8.5", "jest": "^29.7.0", "prettier": "^3.0.3", @@ -757,21 +760,21 @@ "dev": true }, "node_modules/@eslint/js": { - "version": "8.51.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.51.0.tgz", - "integrity": "sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg==", + "version": "8.52.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.52.0.tgz", + "integrity": "sha512-mjZVbpaeMZludF2fsWLD0Z9gCref1Tk4i9+wddjRvpUNqqcndPkBD09N/Mapey0b3jaXbLm2kICwFv2E64QinA==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.11", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz", - "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==", + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", + "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", + "@humanwhocodes/object-schema": "^2.0.1", "debug": "^4.1.1", "minimatch": "^3.0.5" }, @@ -793,9 +796,9 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", + "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", "dev": true }, "node_modules/@istanbuljs/load-nyc-config": { @@ -1478,9 +1481,9 @@ "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.19", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", - "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -1547,9 +1550,9 @@ } }, "node_modules/@types/babel__core": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.2.tgz", - "integrity": "sha512-pNpr1T1xLUc2l3xJKuPtsEky3ybxN3m4fJkknfIpTCTfIZCDW57oAg+EfCgIIp2rvCe0Wn++/FfodDS4YXxBwA==", + "version": "7.20.3", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.3.tgz", + "integrity": "sha512-54fjTSeSHwfan8AyHWrKbfBWiEUrNTZsUwPTDSNaaP1QDQIZbeNUg3a59E9D+375MzUw/x1vx2/0F5LBz+AeYA==", "dev": true, "dependencies": { "@babel/parser": "^7.20.7", @@ -1560,18 +1563,18 @@ } }, "node_modules/@types/babel__generator": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.5.tgz", - "integrity": "sha512-h9yIuWbJKdOPLJTbmSpPzkF67e659PbQDba7ifWm5BJ8xTv+sDmS7rFmywkWOvXedGTivCdeGSIIX8WLcRTz8w==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.6.tgz", + "integrity": "sha512-66BXMKb/sUWbMdBNdMvajU7i/44RkrA3z/Yt1c7R5xejt8qh84iU54yUWCtm0QwGJlDcf/gg4zd/x4mpLAlb/w==", "dev": true, "dependencies": { "@babel/types": "^7.0.0" } }, "node_modules/@types/babel__template": { - "version": "7.4.2", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.2.tgz", - "integrity": "sha512-/AVzPICMhMOMYoSx9MoKpGDKdBRsIXMNByh1PXSZoa+v6ZoLa8xxtsT/uLQ/NJm0XVAWl/BvId4MlDeXJaeIZQ==", + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.3.tgz", + "integrity": "sha512-ciwyCLeuRfxboZ4isgdNZi/tkt06m8Tw6uGbBSBgWrnnZGNXiEyM27xc/PjXGQLqlZ6ylbgHMnm7ccF9tCkOeQ==", "dev": true, "dependencies": { "@babel/parser": "^7.1.0", @@ -1579,24 +1582,24 @@ } }, "node_modules/@types/babel__traverse": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.2.tgz", - "integrity": "sha512-ojlGK1Hsfce93J0+kn3H5R73elidKUaZonirN33GSmgTUMpzI/MIFfSpF3haANe3G1bEBS9/9/QEqwTzwqFsKw==", + "version": "7.20.3", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.3.tgz", + "integrity": "sha512-Lsh766rGEFbaxMIDH7Qa+Yha8cMVI3qAK6CHt3OR0YfxOIn5Z54iHiyDRycHrBqeIiqGa20Kpsv1cavfBKkRSw==", "dev": true, "dependencies": { "@babel/types": "^7.20.7" } }, "node_modules/@types/benchmark": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@types/benchmark/-/benchmark-2.1.3.tgz", - "integrity": "sha512-psuUawgwIy/hSjO4AUDiPBJhJx72e3cBL+YzmVK/5ofRJC02R0NmvrSenGRuSmJc++0j95y2T01xKKNz50FGZw==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@types/benchmark/-/benchmark-2.1.4.tgz", + "integrity": "sha512-rVCCileCU5NhP9Ix1e03sIn4gd0mpjh7VNULVQAxzF+9vddk6A5QAHzp2h5kXH8pkv1Ow45fUf3QP3wOEiISvA==", "dev": true }, "node_modules/@types/eslint": { - "version": "8.44.4", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.4.tgz", - "integrity": "sha512-lOzjyfY/D9QR4hY9oblZ76B90MYTB3RrQ4z2vBIJKj9ROCRqdkYl2gSUx1x1a4IWPjKJZLL4Aw1Zfay7eMnmnA==", + "version": "8.44.6", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.6.tgz", + "integrity": "sha512-P6bY56TVmX8y9J87jHNgQh43h6VVU+6H7oN7hgvivV81K2XY8qJZ5vqPy/HdUoVIelii2kChYVzQanlswPWVFw==", "dev": true, "dependencies": { "@types/estree": "*", @@ -1604,9 +1607,9 @@ } }, "node_modules/@types/eslint-scope": { - "version": "3.7.5", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.5.tgz", - "integrity": "sha512-JNvhIEyxVW6EoMIFIvj93ZOywYFatlpu9deeH6eSx6PE3WHYvHaQtmHmQeNw7aA81bYGBPPQqdtBm6b1SsQMmA==", + "version": "3.7.6", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.6.tgz", + "integrity": "sha512-zfM4ipmxVKWdxtDaJ3MP3pBurDXOCoyjvlpE3u6Qzrmw4BPbfm4/ambIeTk/r/J0iq/+2/xp0Fmt+gFvXJY2PQ==", "dev": true, "dependencies": { "@types/eslint": "*", @@ -1614,48 +1617,48 @@ } }, "node_modules/@types/estree": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.2.tgz", - "integrity": "sha512-VeiPZ9MMwXjO32/Xu7+OwflfmeoRwkE/qzndw42gGtgJwZopBnzy2gD//NN1+go1mADzkDcqf/KnFRSjTJ8xJA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.3.tgz", + "integrity": "sha512-CS2rOaoQ/eAgAfcTfq6amKG7bsN+EMcgGY4FAFQdvSj2y1ixvOZTUA9mOtCai7E1SYu283XNw7urKK30nP3wkQ==", "dev": true }, "node_modules/@types/graceful-fs": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.7.tgz", - "integrity": "sha512-MhzcwU8aUygZroVwL2jeYk6JisJrPl/oov/gsgGCue9mkgl9wjGbzReYQClxiUgFDnib9FuHqTndccKeZKxTRw==", + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.8.tgz", + "integrity": "sha512-NhRH7YzWq8WiNKVavKPBmtLYZHxNY19Hh+az28O/phfp68CF45pMFud+ZzJ8ewnxnC5smIdF3dqFeiSUQ5I+pw==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-zONci81DZYCZjiLe0r6equvZut0b+dBRPBN5kBDjsONnutYNtJMoWQ9uR2RkL1gLG9NMTzvf+29e5RFfPbeKhQ==", "dev": true }, "node_modules/@types/istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-gPQuzaPR5h/djlAv2apEG1HVOyj1IUs7GpfMZixU0/0KXT3pm64ylHuMUI1/Akh+sq/iikxg6Z2j+fcMDXaaTQ==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.2.tgz", + "integrity": "sha512-8toY6FgdltSdONav1XtUHl4LN1yTmLza+EuDazb/fEmRNCwjyqNVIQWs2IfC74IqjHkREs/nQ2FWq5kZU9IC0w==", "dev": true, "dependencies": { "@types/istanbul-lib-coverage": "*" } }, "node_modules/@types/istanbul-reports": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.2.tgz", - "integrity": "sha512-kv43F9eb3Lhj+lr/Hn6OcLCs/sSM8bt+fIaP11rCYngfV6NVjzWXJ17owQtDQTL9tQ8WSLUrGsSJ6rJz0F1w1A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.3.tgz", + "integrity": "sha512-1nESsePMBlf0RPRffLZi5ujYh7IH1BWL4y9pr+Bn3cJBdxz+RTP8bUFljLz9HvzhhOSWKdyBZ4DIivdL6rvgZg==", "dev": true, "dependencies": { "@types/istanbul-lib-report": "*" } }, "node_modules/@types/jest": { - "version": "29.5.5", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.5.tgz", - "integrity": "sha512-ebylz2hnsWR9mYvmBFbXJXr+33UPc4+ZdxyDXh5w0FlPBTfCVN3wPL+kuOiQt3xvrK419v7XWeAs+AeOksafXg==", + "version": "29.5.6", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.6.tgz", + "integrity": "sha512-/t9NnzkOpXb4Nfvg17ieHE6EeSjDS2SGSpNYfoLbUAeL/EOueU/RSdOWFpfQTXBEM7BguYW1XQ0EbM+6RlIh6w==", "dev": true, "dependencies": { "expect": "^29.0.0", @@ -1663,9 +1666,9 @@ } }, "node_modules/@types/json-schema": { - "version": "7.0.13", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.13.tgz", - "integrity": "sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ==", + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.14.tgz", + "integrity": "sha512-U3PUjAudAdJBeC2pgN8uTIKgxrb4nlDF3SF0++EldXQvQBGkpFZMSnwQiIoDU77tv45VgNkl/L4ouD+rEomujw==", "dev": true }, "node_modules/@types/json5": { @@ -1675,52 +1678,52 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.8.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.6.tgz", - "integrity": "sha512-eWO4K2Ji70QzKUqRy6oyJWUeB7+g2cRagT3T/nxYibYcT4y2BDL8lqolRXjTHmkZCdJfIPaY73KbJAZmcryxTQ==", + "version": "20.8.8", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.8.tgz", + "integrity": "sha512-YRsdVxq6OaLfmR9Hy816IMp33xOBjfyOgUd77ehqg96CFywxAPbDbXvAsuN2KVg2HOT8Eh6uAfU+l4WffwPVrQ==", "dev": true, "dependencies": { "undici-types": "~5.25.1" } }, "node_modules/@types/semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-OxepLK9EuNEIPxWNME+C6WwbRAOOI2o2BaQEGzz5Lu2e4Z5eDnEo+/aVEDMIXywoJitJ7xWd641wrGLZdtwRyw==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ==", "dev": true }, "node_modules/@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.2.tgz", + "integrity": "sha512-g7CK9nHdwjK2n0ymT2CW698FuWJRIx+RP6embAzZ2Qi8/ilIrA1Imt2LVSeHUzKvpoi7BhmmQcXz95eS0f2JXw==", "dev": true }, "node_modules/@types/yargs": { - "version": "17.0.28", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.28.tgz", - "integrity": "sha512-N3e3fkS86hNhtk6BEnc0rj3zcehaxx8QWhCROJkqpl5Zaoi7nAic3jH8q94jVD3zu5LGk+PUB6KAiDmimYOEQw==", + "version": "17.0.29", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.29.tgz", + "integrity": "sha512-nacjqA3ee9zRF/++a3FUY1suHTFKZeHba2n8WeDw9cCVdmzmHpIxyzOJBcpHvvEmS8E9KqWlSnWHUkOrkhWcvA==", "dev": true, "dependencies": { "@types/yargs-parser": "*" } }, "node_modules/@types/yargs-parser": { - "version": "21.0.1", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.1.tgz", - "integrity": "sha512-axdPBuLuEJt0c4yI5OZssC19K2Mq1uKdrfZBzuxLvaztgqUtFYZUNw7lETExPYJR9jdEoIg4mb7RQKRQzOkeGQ==", + "version": "21.0.2", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.2.tgz", + "integrity": "sha512-5qcvofLPbfjmBfKaLfj/+f+Sbd6pN4zl7w7VSVI5uz7m9QZTuB2aZAa2uo1wHFBNN2x6g/SoTkXmd8mQnQF2Cw==", "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.7.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.5.tgz", - "integrity": "sha512-JhtAwTRhOUcP96D0Y6KYnwig/MRQbOoLGXTON2+LlyB/N35SP9j1boai2zzwXb7ypKELXMx3DVk9UTaEq1vHEw==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.9.0.tgz", + "integrity": "sha512-lgX7F0azQwRPB7t7WAyeHWVfW1YJ9NIgd9mvGhfQpRY56X6AVf8mwM8Wol+0z4liE7XX3QOt8MN1rUKCfSjRIA==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.7.5", - "@typescript-eslint/type-utils": "6.7.5", - "@typescript-eslint/utils": "6.7.5", - "@typescript-eslint/visitor-keys": "6.7.5", + "@typescript-eslint/scope-manager": "6.9.0", + "@typescript-eslint/type-utils": "6.9.0", + "@typescript-eslint/utils": "6.9.0", + "@typescript-eslint/visitor-keys": "6.9.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -1746,15 +1749,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "6.7.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.7.5.tgz", - "integrity": "sha512-bIZVSGx2UME/lmhLcjdVc7ePBwn7CLqKarUBL4me1C5feOd663liTGjMBGVcGr+BhnSLeP4SgwdvNnnkbIdkCw==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.9.0.tgz", + "integrity": "sha512-GZmjMh4AJ/5gaH4XF2eXA8tMnHWP+Pm1mjQR2QN4Iz+j/zO04b9TOvJYOX2sCNIQHtRStKTxRY1FX7LhpJT4Gw==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.7.5", - "@typescript-eslint/types": "6.7.5", - "@typescript-eslint/typescript-estree": "6.7.5", - "@typescript-eslint/visitor-keys": "6.7.5", + "@typescript-eslint/scope-manager": "6.9.0", + "@typescript-eslint/types": "6.9.0", + "@typescript-eslint/typescript-estree": "6.9.0", + "@typescript-eslint/visitor-keys": "6.9.0", "debug": "^4.3.4" }, "engines": { @@ -1774,13 +1777,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.7.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.5.tgz", - "integrity": "sha512-GAlk3eQIwWOJeb9F7MKQ6Jbah/vx1zETSDw8likab/eFcqkjSD7BI75SDAeC5N2L0MmConMoPvTsmkrg71+B1A==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.9.0.tgz", + "integrity": "sha512-1R8A9Mc39n4pCCz9o79qRO31HGNDvC7UhPhv26TovDsWPBDx+Sg3rOZdCELIA3ZmNoWAuxaMOT7aWtGRSYkQxw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.7.5", - "@typescript-eslint/visitor-keys": "6.7.5" + "@typescript-eslint/types": "6.9.0", + "@typescript-eslint/visitor-keys": "6.9.0" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1791,13 +1794,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.7.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.7.5.tgz", - "integrity": "sha512-Gs0qos5wqxnQrvpYv+pf3XfcRXW6jiAn9zE/K+DlmYf6FcpxeNYN0AIETaPR7rHO4K2UY+D0CIbDP9Ut0U4m1g==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.9.0.tgz", + "integrity": "sha512-XXeahmfbpuhVbhSOROIzJ+b13krFmgtc4GlEuu1WBT+RpyGPIA4Y/eGnXzjbDj5gZLzpAXO/sj+IF/x2GtTMjQ==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.7.5", - "@typescript-eslint/utils": "6.7.5", + "@typescript-eslint/typescript-estree": "6.9.0", + "@typescript-eslint/utils": "6.9.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -1818,9 +1821,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.7.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.5.tgz", - "integrity": "sha512-WboQBlOXtdj1tDFPyIthpKrUb+kZf2VroLZhxKa/VlwLlLyqv/PwUNgL30BlTVZV1Wu4Asu2mMYPqarSO4L5ZQ==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.9.0.tgz", + "integrity": "sha512-+KB0lbkpxBkBSiVCuQvduqMJy+I1FyDbdwSpM3IoBS7APl4Bu15lStPjgBIdykdRqQNYqYNMa8Kuidax6phaEw==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1831,13 +1834,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.7.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.5.tgz", - "integrity": "sha512-NhJiJ4KdtwBIxrKl0BqG1Ur+uw7FiOnOThcYx9DpOGJ/Abc9z2xNzLeirCG02Ig3vkvrc2qFLmYSSsaITbKjlg==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.9.0.tgz", + "integrity": "sha512-NJM2BnJFZBEAbCfBP00zONKXvMqihZCrmwCaik0UhLr0vAgb6oguXxLX1k00oQyD+vZZ+CJn3kocvv2yxm4awQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.7.5", - "@typescript-eslint/visitor-keys": "6.7.5", + "@typescript-eslint/types": "6.9.0", + "@typescript-eslint/visitor-keys": "6.9.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1858,17 +1861,17 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "6.7.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.7.5.tgz", - "integrity": "sha512-pfRRrH20thJbzPPlPc4j0UNGvH1PjPlhlCMq4Yx7EGjV7lvEeGX0U6MJYe8+SyFutWgSHsdbJ3BXzZccYggezA==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.9.0.tgz", + "integrity": "sha512-5Wf+Jsqya7WcCO8me504FBigeQKVLAMPmUzYgDbWchINNh1KJbxCgVya3EQ2MjvJMVeXl3pofRmprqX6mfQkjQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.7.5", - "@typescript-eslint/types": "6.7.5", - "@typescript-eslint/typescript-estree": "6.7.5", + "@typescript-eslint/scope-manager": "6.9.0", + "@typescript-eslint/types": "6.9.0", + "@typescript-eslint/typescript-estree": "6.9.0", "semver": "^7.5.4" }, "engines": { @@ -1883,12 +1886,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.7.5", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.5.tgz", - "integrity": "sha512-3MaWdDZtLlsexZzDSdQWsFQ9l9nL8B80Z4fImSpyllFC/KLqWQRdEcB+gGGO+N3Q2uL40EsG66wZLsohPxNXvg==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.9.0.tgz", + "integrity": "sha512-dGtAfqjV6RFOtIP8I0B4ZTBRrlTT8NHHlZZSchQx3qReaoDeXhYM++M4So2AgFK9ZB0emRPA6JI1HkafzA2Ibg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.7.5", + "@typescript-eslint/types": "6.9.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -1899,6 +1902,12 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, "node_modules/@webassemblyjs/ast": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", @@ -2396,12 +2405,12 @@ } }, "node_modules/avl-tree-typed": { - "version": "1.37.2", - "resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.37.2.tgz", - "integrity": "sha512-nwQjVhtKeVnMA6J1ZQwgMo/cubZEIhOFXCZfwu/tzKCklr8WTXAdCyysOVuT52SwKhzkdNjjSeAevDhfH7m05g==", + "version": "1.37.9", + "resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.37.9.tgz", + "integrity": "sha512-FC7ezzT3Yw8H65oZgf/3RGYo9gnZRgORzlGGO4PyC19ZeIu0UZMHu1+kT0yEfbIE1qGBb4lnuwk4ia8CitcgLg==", "dev": true, "dependencies": { - "data-structure-typed": "^1.37.2" + "data-structure-typed": "^1.37.9" } }, "node_modules/babel-jest": { @@ -2586,12 +2595,12 @@ } }, "node_modules/binary-tree-typed": { - "version": "1.37.2", - "resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.37.2.tgz", - "integrity": "sha512-bCdPFOAm5eMiuDiJLfnj1g6dR2Ib2p4NLrhTvSzCWVjf/o/LLCjzpS0HfXHZ+sjhqfs7yxthgbW4SeHgDO5MPw==", + "version": "1.37.9", + "resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.37.9.tgz", + "integrity": "sha512-8nCjU4V6ViR8NQfxCBsLRFx5Z8D4jpUIx4NuvjliR1R8YIzL6wMmahemve+UbCUWhZJNG5Dv0kVnnCWIK+T0hw==", "dev": true, "dependencies": { - "data-structure-typed": "^1.37.2" + "data-structure-typed": "^1.37.9" } }, "node_modules/brace-expansion": { @@ -2670,12 +2679,12 @@ } }, "node_modules/bst-typed": { - "version": "1.37.2", - "resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.37.2.tgz", - "integrity": "sha512-6WBCmwIX5ibA5i8B/WyL3aXv4m0Pi2xU/6uPTIHfkQAfBSpdMUxrmwRJ5G6aBBJ6wwZ+KkRKezZj6DbklY2FRA==", + "version": "1.37.9", + "resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.37.9.tgz", + "integrity": "sha512-KUp29JhTbNVdA1ePP7gUdi7uaRpM8DVhve9LMHQSUzxTDtHGc8mFTA+njFY7LLU2Rqtu/vqBgTu7bJRVJbWrPA==", "dev": true, "dependencies": { - "data-structure-typed": "^1.37.2" + "data-structure-typed": "^1.37.9" } }, "node_modules/buffer-from": { @@ -2685,13 +2694,14 @@ "dev": true }, "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", "dev": true, "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -2716,9 +2726,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001549", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001549.tgz", - "integrity": "sha512-qRp48dPYSCYaP+KurZLhDYdVE+yEyht/3NlmcJgVQ2VMGt6JL36ndQ/7rgspdZsJuxDPFIo/OzBT2+GmIJ53BA==", + "version": "1.0.30001553", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001553.tgz", + "integrity": "sha512-N0ttd6TrFfuqKNi+pMgWJTb9qrdJu4JSpgPFLe/lrD19ugC6fZgF0pUewRowDwzdDnb9V41mFcdlYgl/PyKf4A==", "dev": true, "funding": [ { @@ -3027,10 +3037,12 @@ } }, "node_modules/data-structure-typed": { - "version": "1.37.2", - "resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.37.2.tgz", - "integrity": "sha512-eVU6Bd2G2xPkdO3SVqo8R+nUkWrdgDbOTR3OYtoldZbNH6Hp2lbv49goDrMYeFBxbsdJ9+k9bNI6WNTpC728uA==", - "dev": true + "version": "1.37.9", + "resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.37.9.tgz", + "integrity": "sha512-6CUX8ANDv2IsJTB8tbdUrXFgWV1AAPxWdcco1ZRUX8caCM0Ge6Snwfse1G1BF6M8kVEuGO2r4q6zkw1z2DxAtQ==", + "dependencies": { + "data-structure-typed": "^1.37.5" + } }, "node_modules/debug": { "version": "4.3.4", @@ -3110,9 +3122,9 @@ } }, "node_modules/dependency-cruiser": { - "version": "14.1.1", - "resolved": "https://registry.npmjs.org/dependency-cruiser/-/dependency-cruiser-14.1.1.tgz", - "integrity": "sha512-npNLWv11pMH9BW4GBLuA5p6KYOXA9UjVDKQ4DzorEhAac5BS1J23K5I2WpEfkJMpwl9PKMsF4T/GDLSq3pogTw==", + "version": "14.1.2", + "resolved": "https://registry.npmjs.org/dependency-cruiser/-/dependency-cruiser-14.1.2.tgz", + "integrity": "sha512-DlHeyF7LxK+pQdEBS+5AykHhUNOyzhek7QCElcmkWfj/dGxuXudT4SrIn6jVtzOnIhU9GAJ8whqm1MHdLDDCHg==", "dev": true, "dependencies": { "acorn": "8.10.0", @@ -3122,7 +3134,7 @@ "acorn-walk": "8.2.0", "ajv": "8.12.0", "chalk": "5.3.0", - "commander": "11.0.0", + "commander": "11.1.0", "enhanced-resolve": "5.15.0", "figures": "5.0.0", "ignore": "5.2.4", @@ -3155,9 +3167,9 @@ } }, "node_modules/dependency-cruiser/node_modules/commander": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-11.0.0.tgz", - "integrity": "sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", "dev": true, "engines": { "node": ">=16" @@ -3212,9 +3224,9 @@ "dev": true }, "node_modules/electron-to-chromium": { - "version": "1.4.554", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.554.tgz", - "integrity": "sha512-Q0umzPJjfBrrj8unkONTgbKQXzXRrH7sVV7D9ea2yBV3Oaogz991yhbpfvo2LMNkJItmruXTEzVpP9cp7vaIiQ==", + "version": "1.4.565", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.565.tgz", + "integrity": "sha512-XbMoT6yIvg2xzcbs5hCADi0dXBh4//En3oFXmtPX+jiyyiCTiM9DGFT2SLottjpEs9Z8Mh8SqahbR96MaHfuSg==", "dev": true }, "node_modules/emittery": { @@ -3270,26 +3282,26 @@ } }, "node_modules/es-abstract": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.2.tgz", - "integrity": "sha512-YoxfFcDmhjOgWPWsV13+2RNjq1F6UQnfs+8TftwNqtzlmFzEXvlUwdrNrYeaizfjQzRMxkZ6ElWMOJIFKdVqwA==", + "version": "1.22.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", + "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", "dev": true, "dependencies": { "array-buffer-byte-length": "^1.0.0", "arraybuffer.prototype.slice": "^1.0.2", "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", + "call-bind": "^1.0.5", "es-set-tostringtag": "^2.0.1", "es-to-primitive": "^1.2.1", "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.1", + "get-intrinsic": "^1.2.2", "get-symbol-description": "^1.0.0", "globalthis": "^1.0.3", "gopd": "^1.0.1", - "has": "^1.0.3", "has-property-descriptors": "^1.0.0", "has-proto": "^1.0.1", "has-symbols": "^1.0.3", + "hasown": "^2.0.0", "internal-slot": "^1.0.5", "is-array-buffer": "^3.0.2", "is-callable": "^1.2.7", @@ -3299,7 +3311,7 @@ "is-string": "^1.0.7", "is-typed-array": "^1.1.12", "is-weakref": "^1.0.2", - "object-inspect": "^1.12.3", + "object-inspect": "^1.13.1", "object-keys": "^1.1.1", "object.assign": "^4.1.4", "regexp.prototype.flags": "^1.5.1", @@ -3313,7 +3325,7 @@ "typed-array-byte-offset": "^1.0.0", "typed-array-length": "^1.0.4", "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.11" + "which-typed-array": "^1.1.13" }, "engines": { "node": ">= 0.4" @@ -3329,26 +3341,26 @@ "dev": true }, "node_modules/es-set-tostringtag": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", - "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", + "integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==", "dev": true, "dependencies": { - "get-intrinsic": "^1.1.3", - "has": "^1.0.3", - "has-tostringtag": "^1.0.0" + "get-intrinsic": "^1.2.2", + "has-tostringtag": "^1.0.0", + "hasown": "^2.0.0" }, "engines": { "node": ">= 0.4" } }, "node_modules/es-shim-unscopables": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", - "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", "dev": true, "dependencies": { - "has": "^1.0.3" + "hasown": "^2.0.0" } }, "node_modules/es-to-primitive": { @@ -3390,18 +3402,19 @@ } }, "node_modules/eslint": { - "version": "8.51.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.51.0.tgz", - "integrity": "sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA==", + "version": "8.52.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.52.0.tgz", + "integrity": "sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "8.51.0", - "@humanwhocodes/config-array": "^0.11.11", + "@eslint/js": "8.52.0", + "@humanwhocodes/config-array": "^0.11.13", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -3539,26 +3552,26 @@ } }, "node_modules/eslint-plugin-import": { - "version": "2.28.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.28.1.tgz", - "integrity": "sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A==", + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.0.tgz", + "integrity": "sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg==", "dev": true, "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.findlastindex": "^1.2.2", - "array.prototype.flat": "^1.3.1", - "array.prototype.flatmap": "^1.3.1", + "array-includes": "^3.1.7", + "array.prototype.findlastindex": "^1.2.3", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", "debug": "^3.2.7", "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.7", + "eslint-import-resolver-node": "^0.3.9", "eslint-module-utils": "^2.8.0", - "has": "^1.0.3", - "is-core-module": "^2.13.0", + "hasown": "^2.0.0", + "is-core-module": "^2.13.1", "is-glob": "^4.0.3", "minimatch": "^3.1.2", - "object.fromentries": "^2.0.6", - "object.groupby": "^1.0.0", - "object.values": "^1.1.6", + "object.fromentries": "^2.0.7", + "object.groupby": "^1.0.1", + "object.values": "^1.1.7", "semver": "^6.3.1", "tsconfig-paths": "^3.14.2" }, @@ -3968,6 +3981,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, "node_modules/flat-cache": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.1.tgz", @@ -4072,15 +4094,15 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", - "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", "dev": true, "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", + "function-bind": "^1.1.2", "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -4283,15 +4305,6 @@ "uglify-js": "^3.1.4" } }, - "node_modules/has": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", - "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", - "dev": true, - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/has-bigints": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", @@ -4311,12 +4324,12 @@ } }, "node_modules/has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", "dev": true, "dependencies": { - "get-intrinsic": "^1.1.1" + "get-intrinsic": "^1.2.2" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -4361,13 +4374,25 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/heap-typed": { - "version": "1.37.2", - "resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.37.2.tgz", - "integrity": "sha512-zQXBfpZdCNnWETGKkxQmd14l8hiIk2HZ1rfmzjCb/OgfLDW3GiKVg5SPcn6FacsTqxLx8Y/ClQzpPeXZCOXtAQ==", + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", "dev": true, "dependencies": { - "data-structure-typed": "^1.37.2" + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/heap-typed": { + "version": "1.37.9", + "resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.37.9.tgz", + "integrity": "sha512-oYkcappLoSb8Zs9gbMaUfIwsm2arykNoQ6gF28x1PQuKa0/a9zonEqqRN6dKlfOT28JIvqhnrSed039YDlZhrQ==", + "dev": true, + "dependencies": { + "data-structure-typed": "^1.37.9" } }, "node_modules/html-escaper": { @@ -4476,13 +4501,13 @@ } }, "node_modules/internal-slot": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", - "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz", + "integrity": "sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==", "dev": true, "dependencies": { - "get-intrinsic": "^1.2.0", - "has": "^1.0.3", + "get-intrinsic": "^1.2.2", + "hasown": "^2.0.0", "side-channel": "^1.0.4" }, "engines": { @@ -4559,12 +4584,12 @@ } }, "node_modules/is-core-module": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", - "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", "dev": true, "dependencies": { - "has": "^1.0.3" + "hasown": "^2.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -6520,9 +6545,9 @@ } }, "node_modules/object-inspect": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.0.tgz", - "integrity": "sha512-HQ4J+ic8hKrgIt3mqk6cVOVrW2ozL4KdvHlqpBv9vDYWx9ysAgENAdvy4FoGF+KFdhR7nQTNm5J0ctAeOwn+3g==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -7306,6 +7331,21 @@ "randombytes": "^2.1.0" } }, + "node_modules/set-function-length": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", + "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.1", + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/set-function-name": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", @@ -7630,9 +7670,9 @@ "dev": true }, "node_modules/terser": { - "version": "5.21.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.21.0.tgz", - "integrity": "sha512-WtnFKrxu9kaoXuiZFSGrcAvvBqAdmKx0SFNmVNYdJamMu9yyN3I/QF0FbH4QcqJQ+y1CJnzxGIKH0cSj+FGYRw==", + "version": "5.22.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.22.0.tgz", + "integrity": "sha512-hHZVLgRA2z4NWcN6aS5rQDc+7Dcy58HOf2zbYwmFcQ+ua3h6eEFf5lIDKTzbWwlazPyOZsFQO8V80/IjVNExEw==", "dev": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -8428,12 +8468,13 @@ } }, "node_modules/webpack-merge": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.9.0.tgz", - "integrity": "sha512-6NbRQw4+Sy50vYNTw7EyOn41OZItPiXB8GNv3INSoe3PSFaHJEz3SHTrYVaRm2LilNGnFUzh0FAwqPEmU/CwDg==", + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", "dev": true, "dependencies": { "clone-deep": "^4.0.1", + "flat": "^5.0.2", "wildcard": "^2.0.0" }, "engines": { @@ -8513,13 +8554,13 @@ } }, "node_modules/which-typed-array": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", - "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", + "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", "dev": true, "dependencies": { "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", + "call-bind": "^1.0.4", "for-each": "^0.3.3", "gopd": "^1.0.1", "has-tostringtag": "^1.0.0" diff --git a/package.json b/package.json index 2fb8b95..53428ea 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "data-structure-typed", - "version": "1.37.3", + "version": "1.37.9", "description": "Data Structures of Javascript & TypeScript. Binary Tree, BST, Graph, Heap, Priority Queue, Linked List, Queue, Deque, Stack, AVL Tree, Tree Multiset, Trie, Directed Graph, Undirected Graph, Singly Linked List, Doubly Linked List, Max Heap, Max Priority Queue, Min Heap, Min Priority Queue.", "main": "dist/index.js", "module": "lib/index.js", @@ -27,16 +27,16 @@ "fix:src": "npm run lint:src && npm run format:src", "fix:test": "npm run lint:test && npm run format:test", "fix": "npm run fix:src && npm run fix:test", - "update:individuals": "npm i avl-tree-typed binary-tree-typed bst-typed heap-typed --save-dev", - "install:all-individuals": "npm i avl-tree-typed binary-tree-typed bst-typed deque-typed directed-graph-typed doubly-linked-list-typed graph-typed heap-typed linked-list-typed max-heap-typed max-priority-queue-typed min-heap-typed min-priority-queue-typed priority-queue-typed singly-linked-list-typed stack-typed tree-multiset-typed trie-typed undirected-graph-typed queue-typed --save-dev", + "update:subs": "npm i avl-tree-typed binary-tree-typed bst-typed heap-typed --save-dev", + "install:all-subs": "npm i avl-tree-typed binary-tree-typed bst-typed deque-typed directed-graph-typed doubly-linked-list-typed graph-typed heap-typed linked-list-typed max-heap-typed max-priority-queue-typed min-heap-typed min-priority-queue-typed priority-queue-typed singly-linked-list-typed stack-typed tree-multiset-typed trie-typed undirected-graph-typed queue-typed --save-dev", "test": "jest", "check:deps": "dependency-cruiser src", "changelog": "auto-changelog", "coverage:badge": "istanbul-badges-readme", - "ci": "env && git fetch --tags && npm run lint && npm run build && npm run update:individuals && npm run test && npm run changelog", - "publish:individuals": "sh scripts/publish_all_subs.sh", + "ci": "env && git fetch --tags && npm run lint && npm run build && npm run update:subs && npm run test && npm run changelog", + "publish:subs": "sh scripts/publish_all_subs.sh", "publish:docs": "sh scripts/publish_docs.sh", - "publish:all": "npm run ci && npm publish && npm run publish:individuals && npm run publish:docs" + "publish:all": "npm run ci && npm publish && npm run publish:subs && npm run publish:docs" }, "repository": { "type": "git", @@ -58,17 +58,17 @@ "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", "auto-changelog": "^2.4.0", - "avl-tree-typed": "^1.37.2", + "avl-tree-typed": "^1.37.9", "benchmark": "^2.1.4", - "binary-tree-typed": "^1.37.2", - "bst-typed": "^1.37.2", + "binary-tree-typed": "^1.37.9", + "bst-typed": "^1.37.9", "dependency-cruiser": "^14.1.0", "eslint": "^8.50.0", "eslint-config-prettier": "^9.0.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.28.1", - "heap-typed": "^1.37.2", + "heap-typed": "^1.37.9", "istanbul-badges-readme": "^1.8.5", "jest": "^29.7.0", "prettier": "^3.0.3", @@ -225,5 +225,8 @@ "tarjan", "Tarjan", "Tarjan's" - ] + ], + "dependencies": { + "data-structure-typed": "^1.37.5" + } } diff --git a/scripts/config.json b/scripts/config.json new file mode 100644 index 0000000..06383c9 --- /dev/null +++ b/scripts/config.json @@ -0,0 +1,5 @@ +{ + "sourceDir": "/Users/revone/projects/data-structure-typed", + "individualsDir": "/Users/revone/projects/data-structure-typed-individuals", + "docsDir": "/Users/revone/projects/data-structure-typed-docs" +} diff --git a/scripts/publish_all_subs.sh b/scripts/publish_all_subs.sh index 8ea802d..7b7da2f 100755 --- a/scripts/publish_all_subs.sh +++ b/scripts/publish_all_subs.sh @@ -1,5 +1,10 @@ #!/bin/bash +# Read the version variable from config.json +source_dir_default=$(jq -r .sourceDir ./scripts/config.json) + +individuals_dir_default=$(jq -r .individualsDir ./scripts/config.json) + # Function to prompt for a directory path with a default value prompt_for_directory() { local message="$1" @@ -9,10 +14,12 @@ prompt_for_directory() { } # Prompt for the source directory path -source_dir=$(prompt_for_directory "Enter the source directory" "/Users/revone/projects/data-structure-typed") +#source_dir=$(prompt_for_directory "Enter the source directory" "$source_dir_default") +source_dir="$source_dir_default" # Prompt for the destination directory path -individuals_dir=$(prompt_for_directory "Enter the destination directory" "/Users/revone/projects/data-structure-typed-individuals") +#individuals_dir=$(prompt_for_directory "Enter the destination directory" "$individuals_dir_default") +individuals_dir="$individuals_dir_default" # Read the version variable from package.json diff --git a/scripts/publish_docs.sh b/scripts/publish_docs.sh index 414b02b..71b1853 100755 --- a/scripts/publish_docs.sh +++ b/scripts/publish_docs.sh @@ -1,5 +1,11 @@ #!/bin/bash + +# Read the version variable from config.json +source_dir_default=$(jq -r .sourceDir ./scripts/config.json) + +docs_dir_default=$(jq -r .docsDir ./scripts/config.json) + # Function to prompt for a directory path with a default value prompt_for_directory() { local message="$1" @@ -9,10 +15,12 @@ prompt_for_directory() { } # Prompt for the source directory path -source_dir=$(prompt_for_directory "Enter the source directory" "/Users/revone/projects/data-structure-typed") +#source_dir=$(prompt_for_directory "Enter the source directory" "$source_dir_default") +source_dir="$source_dir_default" -# Prompt for the destination directory path -docs_dir=$(prompt_for_directory "Enter the destination directory" "/Users/revone/projects/data-structure-typed-docs") +# Prompt for the docs directory path +#docs_dir=$(prompt_for_directory "Enter the docs directory" "$docs_dir_default") +docs_dir="$docs_dir_default" # Check if jq is installed and install it if needed if ! command -v jq &> /dev/null; then diff --git a/src/data-structures/binary-tree/binary-indexed-tree.ts b/src/data-structures/binary-tree/binary-indexed-tree.ts index b83b265..da9dae0 100644 --- a/src/data-structures/binary-tree/binary-indexed-tree.ts +++ b/src/data-structures/binary-tree/binary-indexed-tree.ts @@ -5,72 +5,294 @@ * @copyright Copyright (c) 2022 Tyler Zeng * @license MIT License */ +import {getMSB} from '../../utils'; + export class BinaryIndexedTree { + protected readonly _freq: number; + protected readonly _max: number; + /** - * The constructor initializes an array with a specified length and fills it with zeros. - * @param {number} n - The parameter `n` represents the size of the array that will be used to store the sum tree. The - * sum tree is a binary tree data structure used to efficiently calculate the sum of a range of elements in an array. - * The size of the sum tree array is `n + 1` because + * The constructor initializes the properties of an object, including default frequency, maximum + * value, a freqMap data structure, the most significant bit, and the count of negative frequencies. + * @param - - `frequency`: The default frequency value. It is optional and has a default + * value of 0. */ - constructor(n: number) { - this._sumTree = new Array(n + 1).fill(0); + constructor({frequency = 0, max}: {frequency?: number; max: number}) { + this._freq = frequency; + this._max = max; + this._freqMap = {0: 0}; + this._msb = getMSB(max); + this._negativeCount = frequency < 0 ? max : 0; } - private _sumTree: number[]; + protected _freqMap: Record; - get sumTree(): number[] { - return this._sumTree; + get freqMap(): Record { + return this._freqMap; } - static lowBit(x: number) { - return x & -x; + set freqMap(value: Record) { + this._freqMap = value; + } + + protected _msb: number; + + get msb(): number { + return this._msb; + } + + set msb(value: number) { + this._msb = value; + } + + protected _negativeCount: number; + + get negativeCount(): number { + return this._negativeCount; + } + + set negativeCount(value: number) { + this._negativeCount = value; + } + + get freq(): number { + return this._freq; + } + + get max(): number { + return this._max; } /** - * The update function updates the values in a binary indexed tree by adding a delta value to the specified index and - * its ancestors. - * @param {number} i - The parameter `i` represents the index of the element in the `_sumTree` array that needs to be - * updated. - * @param {number} delta - The "delta" parameter represents the change in value that needs to be added to the element - * at index "i" in the "_sumTree" array. + * The function "readSingle" reads a single number from a specified index. + * @param {number} index - The `index` parameter is a number that represents the index of an element in a + * collection or array. + * @returns a number. */ - update(i: number, delta: number) { - while (i < this._sumTree.length) { - this._sumTree[i] += delta; - i += BinaryIndexedTree.lowBit(i); + readSingle(index: number): number { + this._checkIndex(index); + return this._readSingle(index); + } + + /** + * The "update" function updates the value at a given index by adding a delta and triggers a callback + * to notify of the change. + * @param {number} position - The `index` parameter represents the index of the element that needs to be + * updated in the data structure. + * @param {number} change - The "delta" parameter represents the change in value that needs to be + * applied to the frequency at the specified index. + */ + update(position: number, change: number): void { + this._checkIndex(position); + const freqCur = this._readSingle(position); + + this._update(position, change); + this._updateNegativeCount(freqCur, freqCur + change); + } + + /** + * The function "writeSingle" checks the index and writes a single value with a given frequency. + * @param {number} index - The `index` parameter is a number that represents the index of an element. It + * is used to identify the specific element that needs to be written. + * @param {number} freq - The `freq` parameter represents the frequency value that needs to be + * written. + */ + writeSingle(index: number, freq: number): void { + this._checkIndex(index); + this._writeSingle(index, freq); + } + + /** + * The read function takes a count parameter, checks if it is an integer, and returns the result of + * calling the _read function with the count parameter clamped between 0 and the maximum value. + * @param {number} count - The `count` parameter is a number that represents the number of items to + * read. + * @returns a number. + */ + read(count: number): number { + if (!Number.isInteger(count)) { + throw new Error('Invalid count'); + } + return this._read(Math.max(Math.min(count, this.max), 0)); + } + + /** + * The function returns the lower bound of a non-descending sequence that sums up to a given number. + * @param {number} sum - The `sum` parameter is a number that represents the target sum that we want + * to find in the sequence. + * @returns The lowerBound function is returning a number. + */ + lowerBound(sum: number): number { + if (this.negativeCount > 0) { + throw new Error('Sequence is not non-descending'); + } + return this._binarySearch(sum, (x, y) => x < y); + } + + /** + * The upperBound function returns the index of the first element in a sequence that is greater than + * or equal to a given sum. + * @param {number} sum - The "sum" parameter is a number that represents the target sum that we want + * to find in the sequence. + * @returns The upperBound function is returning a number. + */ + upperBound(sum: number): number { + if (this.negativeCount > 0) { + throw new Error('Must not be descending'); + } + return this._binarySearch(sum, (x, y) => x <= y); + } + + /** + * The function returns the value of a specific index in a freqMap data structure, or a default value if + * the index is not found. + * @param {number} index - The `index` parameter is a number that represents the index of a node in a + * freqMap data structure. + * @returns a number. + */ + protected _getFrequency(index: number): number { + if (index in this.freqMap) { + return this.freqMap[index]; + } + + return this.freq * (index & -index); + } + + /** + * The function _updateFrequency adds a delta value to the element at the specified index in the freqMap array. + * @param {number} index - The index parameter is a number that represents the index of the freqMap + * element that needs to be updated. + * @param {number} delta - The `delta` parameter represents the change in value that needs to be + * added to the freqMap at the specified `index`. + */ + protected _updateFrequency(index: number, delta: number): void { + this.freqMap[index] = this._getFrequency(index) + delta; + } + + /** + * The function checks if the given index is valid and within the range. + * @param {number} index - The parameter "index" is of type number and represents the index value + * that needs to be checked. + */ + protected _checkIndex(index: number): void { + if (!Number.isInteger(index)) { + throw new Error('Invalid index: Index must be an integer.'); + } + if (index < 0 || index >= this.max) { + throw new Error('Index out of range: Index must be within the range [0, this.max).'); } } /** - * The function calculates the prefix sum of an array using a binary indexed tree. - * @param {number} i - The parameter "i" in the function "getPrefixSum" represents the index of the element in the - * array for which we want to calculate the prefix sum. - * @returns The function `getPrefixSum` returns the prefix sum of the elements in the binary indexed tree up to index - * `i`. + * The function calculates the sum of elements in an array up to a given index using a binary indexed + * freqMap. + * @param {number} index - The `index` parameter is a number that represents the index of an element in a + * data structure. + * @returns a number. */ - getPrefixSum(i: number) { - let sum = 0; - while (i > 0) { - sum += this._sumTree[i]; - i -= BinaryIndexedTree.lowBit(i); + protected _readSingle(index: number): number { + index = index + 1; + let sum = this._getFrequency(index); + const z = index - (index & -index); + + index--; + + while (index !== z) { + sum -= this._getFrequency(index); + index -= index & -index; } + return sum; } /** - * The function `getRangeSum` calculates the sum of a range of numbers in an array. - * @param {number} start - The start parameter is the starting index of the range for which we want to calculate the - * sum. - * @param {number} end - The "end" parameter represents the ending index of the range for which we want to calculate - * the sum. - * @returns the sum of the elements in the range specified by the start and end indices. + * The function `_updateNegativeCount` updates a counter based on changes in frequency values. + * @param {number} freqCur - The current frequency value. + * @param {number} freqNew - The freqNew parameter represents the new frequency value. */ - getRangeSum(start: number, end: number): number { - if (!(0 <= start && start <= end && end <= this._sumTree.length)) throw 'Index out of bounds'; - return this.getPrefixSum(end) - this.getPrefixSum(start); + protected _updateNegativeCount(freqCur: number, freqNew: number): void { + if (freqCur < 0 && freqNew >= 0) { + this.negativeCount--; + } else if (freqCur >= 0 && freqNew < 0) { + this.negativeCount++; + } } - protected _setSumTree(value: number[]) { - this._sumTree = value; + /** + * The `_update` function updates the values in a binary indexed freqMap starting from a given index and + * propagating the changes to its parent nodes. + * @param {number} index - The `index` parameter is a number that represents the index of the element in + * the data structure that needs to be updated. + * @param {number} delta - The `delta` parameter represents the change in value that needs to be + * applied to the elements in the data structure. + */ + protected _update(index: number, delta: number): void { + index = index + 1; + + while (index <= this.max) { + this._updateFrequency(index, delta); + index += index & -index; + } + } + + /** + * The `_writeSingle` function updates the frequency at a specific index and triggers a callback if + * the frequency has changed. + * @param {number} index - The `index` parameter is a number that represents the index of the element + * being modified or accessed. + * @param {number} freq - The `freq` parameter represents the new frequency value that needs to be + * written to the specified index `index`. + */ + protected _writeSingle(index: number, freq: number): void { + const freqCur = this._readSingle(index); + + this._update(index, freq - freqCur); + this._updateNegativeCount(freqCur, freq); + } + + /** + * The `_read` function calculates the sum of values in a binary freqMap up to a given count. + * @param {number} count - The `count` parameter is a number that represents the number of elements + * to read from the freqMap. + * @returns the sum of the values obtained from calling the `_getFrequency` method for each index in the + * range from `count` to 1. + */ + protected _read(count: number): number { + let index = count; + let sum = 0; + while (index) { + sum += this._getFrequency(index); + index -= index & -index; + } + + return sum; + } + + /** + * The function `_binarySearch` performs a binary search to find the largest number that satisfies a given + * condition. + * @param {number} sum - The sum parameter is a number that represents the target sum value. + * @param before - The `before` parameter is a function that takes two numbers `x` and `y` as + * arguments and returns a boolean value. It is used to determine if `x` is less than or equal to + * `y`. The purpose of this function is to compare two numbers and determine their order. + * @returns the value of the variable "left". + */ + protected _binarySearch(sum: number, before: (x: number, y: number) => boolean): number { + let left = 0; + let right = this.msb << 1; + let sumT = sum; + + while (right > left + 1) { + const middle = (left + right) >> 1; + const sumM = this._getFrequency(middle); + + if (middle <= this.max && before(sumM, sumT)) { + sumT -= sumM; + left = middle; + } else { + right = middle; + } + } + return left; } } diff --git a/src/data-structures/binary-tree/binary-tree.ts b/src/data-structures/binary-tree/binary-tree.ts index 7de5b1c..e654f31 100644 --- a/src/data-structures/binary-tree/binary-tree.ts +++ b/src/data-structures/binary-tree/binary-tree.ts @@ -134,7 +134,7 @@ export class BinaryTree = BinaryTreeNode> */ constructor(options?: BinaryTreeOptions) { if (options !== undefined) { - const { iterationType = IterationType.ITERATIVE } = options; + const {iterationType = IterationType.ITERATIVE} = options; this._loopType = iterationType; } } @@ -191,7 +191,7 @@ export class BinaryTree = BinaryTreeNode> * @returns {N} - The destination node after the swap. */ protected _swap(srcNode: N, destNode: N): N { - const { key, val } = destNode; + const {key, val} = destNode; const tempNode = this.createNode(key, val); if (tempNode) { @@ -322,7 +322,6 @@ export class BinaryTree = BinaryTreeNode> return keysOrNodes.length === this.addMany(keysOrNodes, data).length; } - /** * The `delete` function removes a node from a binary search tree and returns the deleted node along * with the parent node that needs to be balanced. diff --git a/src/data-structures/binary-tree/bst.ts b/src/data-structures/binary-tree/bst.ts index 82ff5df..f9bd32b 100644 --- a/src/data-structures/binary-tree/bst.ts +++ b/src/data-structures/binary-tree/bst.ts @@ -25,7 +25,6 @@ export class BSTNode = BSTNodeNested< } export class BST = BSTNode> extends BinaryTree implements IBinaryTree { - /** * The constructor function initializes a binary search tree object with an optional comparator * function. @@ -144,7 +143,12 @@ export class BST = BSTNode> extends BinaryTree * @returns The `addMany` function returns an array of `N`, `null`, or `undefined` values. */ - override addMany(keysOrNodes: (BinaryTreeNodeKey | null)[] | (N | null)[], data?: N['val'][], isBalanceAdd = true, iterationType = this.iterationType): (N | null | undefined)[] { + override addMany( + keysOrNodes: (BinaryTreeNodeKey | null)[] | (N | null)[], + data?: N['val'][], + isBalanceAdd = true, + iterationType = this.iterationType + ): (N | null | undefined)[] { // TODO this addMany function is inefficient, it should be optimized function hasNoNull(arr: (BinaryTreeNodeKey | null)[] | (N | null)[]): arr is BinaryTreeNodeKey[] | N[] { return arr.indexOf(null) === -1; @@ -230,7 +234,12 @@ export class BST = BSTNode> extends BinaryTree * @returns either the first node that matches the given nodeProperty and callback, or null if no * matching node is found. */ - override get(nodeProperty: BinaryTreeNodeKey | N, callback: MapCallback = this._defaultCallbackByKey,beginRoot = this.root, iterationType = this.iterationType): N | null { + override get( + nodeProperty: BinaryTreeNodeKey | N, + callback: MapCallback = this._defaultCallbackByKey, + beginRoot = this.root, + iterationType = this.iterationType + ): N | null { return this.getNodes(nodeProperty, callback, true, beginRoot, iterationType)[0] ?? null; } diff --git a/src/data-structures/heap/heap.ts b/src/data-structures/heap/heap.ts index 09cc63c..55bbbf1 100644 --- a/src/data-structures/heap/heap.ts +++ b/src/data-structures/heap/heap.ts @@ -5,8 +5,7 @@ * @license MIT License */ -import type {Comparator} from '../../types'; -import {DFSOrderPattern} from '../../types'; +import type {Comparator, DFSOrderPattern} from '../../types'; export class Heap { protected nodes: E[] = []; diff --git a/src/types/data-structures/avl-tree.ts b/src/types/data-structures/binary-tree/avl-tree.ts similarity index 94% rename from src/types/data-structures/avl-tree.ts rename to src/types/data-structures/binary-tree/avl-tree.ts index 16f86f7..611a467 100644 --- a/src/types/data-structures/avl-tree.ts +++ b/src/types/data-structures/binary-tree/avl-tree.ts @@ -1,4 +1,4 @@ -import {AVLTreeNode} from '../../data-structures'; +import {AVLTreeNode} from '../../../data-structures'; import {BSTOptions} from './bst'; export type AVLTreeNodeNested = AVLTreeNode>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> diff --git a/src/types/data-structures/doubly-linked-list.ts b/src/types/data-structures/binary-tree/binary-indexed-tree.ts similarity index 100% rename from src/types/data-structures/doubly-linked-list.ts rename to src/types/data-structures/binary-tree/binary-indexed-tree.ts diff --git a/src/types/data-structures/binary-tree.ts b/src/types/data-structures/binary-tree/binary-tree.ts similarity index 80% rename from src/types/data-structures/binary-tree.ts rename to src/types/data-structures/binary-tree/binary-tree.ts index e392a52..4d0e908 100644 --- a/src/types/data-structures/binary-tree.ts +++ b/src/types/data-structures/binary-tree/binary-tree.ts @@ -1,4 +1,4 @@ -import {BinaryTreeNode} from '../../data-structures/binary-tree'; +import {BinaryTreeNode} from '../../../data-structures'; /** * Enum representing different loop types. @@ -22,26 +22,14 @@ export enum FamilyPosition { MAL_NODE = 'MAL_NODE' } -export type BinaryTreeNodePropertyName = 'key' | 'val'; - -export type NodeOrPropertyName = 'node' | BinaryTreeNodePropertyName; - export type BinaryTreeNodeKey = number; export type BFSCallback = (node: N, level?: number) => any; export type BFSCallbackReturn = ReturnType>; -export type BinaryTreeNodeProperty> = - | N['val'] - | N - | number - | BinaryTreeNodeKey; export type BinaryTreeDeletedResult = { deleted: N | null | undefined; needBalanced: N | null }; -export type BinaryTreeNodeProperties> = - BinaryTreeNodeProperty[]; - export type BinaryTreeNodeNested = BinaryTreeNode>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> export type BinaryTreeOptions = { iterationType?: IterationType } diff --git a/src/types/data-structures/bst.ts b/src/types/data-structures/binary-tree/bst.ts similarity index 88% rename from src/types/data-structures/bst.ts rename to src/types/data-structures/binary-tree/bst.ts index 88bb72a..5d60225 100644 --- a/src/types/data-structures/bst.ts +++ b/src/types/data-structures/binary-tree/bst.ts @@ -1,4 +1,4 @@ -import {BSTNode} from '../../data-structures/binary-tree'; +import {BSTNode} from '../../../data-structures'; import type {BinaryTreeNodeKey, BinaryTreeOptions} from './binary-tree'; export type BSTComparator = (a: BinaryTreeNodeKey, b: BinaryTreeNodeKey) => number; @@ -9,5 +9,3 @@ export type BSTNodeNested = BSTNode = RBTreeNode>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -export type RBTreeOptions = BinaryTreeOptions & {} \ No newline at end of file +export type RBTreeOptions = BinaryTreeOptions & {} diff --git a/src/types/data-structures/segment-tree.ts b/src/types/data-structures/binary-tree/segment-tree.ts similarity index 100% rename from src/types/data-structures/segment-tree.ts rename to src/types/data-structures/binary-tree/segment-tree.ts diff --git a/src/types/data-structures/tree-multiset.ts b/src/types/data-structures/binary-tree/tree-multiset.ts similarity index 94% rename from src/types/data-structures/tree-multiset.ts rename to src/types/data-structures/binary-tree/tree-multiset.ts index 47c26a4..ad14629 100644 --- a/src/types/data-structures/tree-multiset.ts +++ b/src/types/data-structures/binary-tree/tree-multiset.ts @@ -1,4 +1,4 @@ -import {TreeMultisetNode} from '../../data-structures/binary-tree'; +import {TreeMultisetNode} from '../../../data-structures'; import {AVLTreeOptions} from './avl-tree'; export type TreeMultisetNodeNested = TreeMultisetNode>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> diff --git a/src/types/data-structures/abstract-graph.ts b/src/types/data-structures/graph/abstract-graph.ts similarity index 100% rename from src/types/data-structures/abstract-graph.ts rename to src/types/data-structures/graph/abstract-graph.ts diff --git a/src/types/data-structures/directed-graph.ts b/src/types/data-structures/graph/directed-graph.ts similarity index 100% rename from src/types/data-structures/directed-graph.ts rename to src/types/data-structures/graph/directed-graph.ts diff --git a/src/types/data-structures/graph/index.ts b/src/types/data-structures/graph/index.ts new file mode 100644 index 0000000..4ff9af0 --- /dev/null +++ b/src/types/data-structures/graph/index.ts @@ -0,0 +1,3 @@ +export * from './abstract-graph'; +export * from './map-graph'; +export * from './directed-graph'; diff --git a/src/types/data-structures/map-graph.ts b/src/types/data-structures/graph/map-graph.ts similarity index 100% rename from src/types/data-structures/map-graph.ts rename to src/types/data-structures/graph/map-graph.ts diff --git a/src/types/data-structures/heap.ts b/src/types/data-structures/graph/undirected-graph.ts similarity index 100% rename from src/types/data-structures/heap.ts rename to src/types/data-structures/graph/undirected-graph.ts diff --git a/src/types/data-structures/singly-linked-list.ts b/src/types/data-structures/hash/coordinate-map.ts similarity index 100% rename from src/types/data-structures/singly-linked-list.ts rename to src/types/data-structures/hash/coordinate-map.ts diff --git a/src/types/data-structures/hash/coordinate-set.ts b/src/types/data-structures/hash/coordinate-set.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/src/types/data-structures/hash/coordinate-set.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/types/data-structures/hash/hash-map.ts b/src/types/data-structures/hash/hash-map.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/src/types/data-structures/hash/hash-map.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/types/data-structures/hash/hash-table.ts b/src/types/data-structures/hash/hash-table.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/src/types/data-structures/hash/hash-table.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/types/data-structures/hash.ts b/src/types/data-structures/hash/index.ts similarity index 100% rename from src/types/data-structures/hash.ts rename to src/types/data-structures/hash/index.ts diff --git a/src/types/data-structures/hash/tree-map.ts b/src/types/data-structures/hash/tree-map.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/src/types/data-structures/hash/tree-map.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/types/data-structures/hash/tree-set.ts b/src/types/data-structures/hash/tree-set.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/src/types/data-structures/hash/tree-set.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/types/data-structures/heap/heap.ts b/src/types/data-structures/heap/heap.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/src/types/data-structures/heap/heap.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/types/data-structures/heap/index.ts b/src/types/data-structures/heap/index.ts new file mode 100644 index 0000000..0126870 --- /dev/null +++ b/src/types/data-structures/heap/index.ts @@ -0,0 +1 @@ +export * from './heap'; diff --git a/src/types/data-structures/heap/max-heap.ts b/src/types/data-structures/heap/max-heap.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/src/types/data-structures/heap/max-heap.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/types/data-structures/heap/min-heap.ts b/src/types/data-structures/heap/min-heap.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/src/types/data-structures/heap/min-heap.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/types/data-structures/index.ts b/src/types/data-structures/index.ts index 8ad00d7..4083893 100644 --- a/src/types/data-structures/index.ts +++ b/src/types/data-structures/index.ts @@ -1,17 +1,11 @@ export * from './binary-tree'; -export * from './bst'; -export * from './avl-tree'; -export * from './segment-tree'; -export * from './tree-multiset'; -export * from './abstract-graph'; -export * from './map-graph'; -export * from './rb-tree'; -export * from './directed-graph'; +export * from './graph'; +export * from './linked-list'; export * from './heap'; -export * from './singly-linked-list'; -export * from './doubly-linked-list'; -export * from './navigator'; +export * from './matrix'; export * from './hash'; - -export type MapCallback = (node: N) => any; -export type MapCallbackReturn = ReturnType>; +export * from './priority-queue'; +export * from './queue'; +export * from './stack'; +export * from './tree'; +export * from './trie'; diff --git a/src/types/data-structures/linked-list/doubly-linked-list.ts b/src/types/data-structures/linked-list/doubly-linked-list.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/src/types/data-structures/linked-list/doubly-linked-list.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/types/data-structures/linked-list/index.ts b/src/types/data-structures/linked-list/index.ts new file mode 100644 index 0000000..0bdd0b6 --- /dev/null +++ b/src/types/data-structures/linked-list/index.ts @@ -0,0 +1,2 @@ +export * from './singly-linked-list'; +export * from './doubly-linked-list'; diff --git a/src/types/data-structures/linked-list/singly-linked-list.ts b/src/types/data-structures/linked-list/singly-linked-list.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/src/types/data-structures/linked-list/singly-linked-list.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/types/data-structures/linked-list/skip-linked-list.ts b/src/types/data-structures/linked-list/skip-linked-list.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/src/types/data-structures/linked-list/skip-linked-list.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/types/data-structures/matrix/index.ts b/src/types/data-structures/matrix/index.ts new file mode 100644 index 0000000..8716d60 --- /dev/null +++ b/src/types/data-structures/matrix/index.ts @@ -0,0 +1 @@ +export * from './navigator'; diff --git a/src/types/data-structures/matrix/matrix.ts b/src/types/data-structures/matrix/matrix.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/src/types/data-structures/matrix/matrix.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/types/data-structures/matrix/matrix2d.ts b/src/types/data-structures/matrix/matrix2d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/src/types/data-structures/matrix/matrix2d.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/types/data-structures/navigator.ts b/src/types/data-structures/matrix/navigator.ts similarity index 100% rename from src/types/data-structures/navigator.ts rename to src/types/data-structures/matrix/navigator.ts diff --git a/src/types/data-structures/matrix/vector2d.ts b/src/types/data-structures/matrix/vector2d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/src/types/data-structures/matrix/vector2d.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/types/data-structures/priority-queue/index.ts b/src/types/data-structures/priority-queue/index.ts new file mode 100644 index 0000000..abfb1a8 --- /dev/null +++ b/src/types/data-structures/priority-queue/index.ts @@ -0,0 +1,3 @@ +export * from './priority-queue'; +export * from './min-priority-queue'; +export * from './max-priority-queue'; diff --git a/src/types/data-structures/priority-queue/max-priority-queue.ts b/src/types/data-structures/priority-queue/max-priority-queue.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/src/types/data-structures/priority-queue/max-priority-queue.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/types/data-structures/priority-queue/min-priority-queue.ts b/src/types/data-structures/priority-queue/min-priority-queue.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/src/types/data-structures/priority-queue/min-priority-queue.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/types/data-structures/priority-queue/priority-queue.ts b/src/types/data-structures/priority-queue/priority-queue.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/src/types/data-structures/priority-queue/priority-queue.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/types/data-structures/queue/deque.ts b/src/types/data-structures/queue/deque.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/src/types/data-structures/queue/deque.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/types/data-structures/queue/index.ts b/src/types/data-structures/queue/index.ts new file mode 100644 index 0000000..42a184f --- /dev/null +++ b/src/types/data-structures/queue/index.ts @@ -0,0 +1,2 @@ +export * from './queue'; +export * from './deque'; diff --git a/src/types/data-structures/queue/queue.ts b/src/types/data-structures/queue/queue.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/src/types/data-structures/queue/queue.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/types/data-structures/stack/index.ts b/src/types/data-structures/stack/index.ts new file mode 100644 index 0000000..d39a8e6 --- /dev/null +++ b/src/types/data-structures/stack/index.ts @@ -0,0 +1 @@ +export * from './stack'; diff --git a/src/types/data-structures/stack/stack.ts b/src/types/data-structures/stack/stack.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/src/types/data-structures/stack/stack.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/types/data-structures/tree/index.ts b/src/types/data-structures/tree/index.ts new file mode 100644 index 0000000..50842b5 --- /dev/null +++ b/src/types/data-structures/tree/index.ts @@ -0,0 +1 @@ +export * from './tree'; diff --git a/src/types/data-structures/tree/tree.ts b/src/types/data-structures/tree/tree.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/src/types/data-structures/tree/tree.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/types/data-structures/trie/index.ts b/src/types/data-structures/trie/index.ts new file mode 100644 index 0000000..8d6f206 --- /dev/null +++ b/src/types/data-structures/trie/index.ts @@ -0,0 +1 @@ +export * from './trie'; diff --git a/src/types/data-structures/trie/trie.ts b/src/types/data-structures/trie/trie.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/src/types/data-structures/trie/trie.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/types/helpers.ts b/src/types/helpers.ts index f1991de..35c570b 100644 --- a/src/types/helpers.ts +++ b/src/types/helpers.ts @@ -1,4 +1,9 @@ export type Comparator = (a: T, b: T) => number; -// export enum DFSOrderPattern {'pre' = 'pre', 'in' = 'in', 'post' = 'post'} export type DFSOrderPattern = 'pre' | 'in' | 'post'; + +export type MapCallback = (node: N) => any; + +export type MapCallbackReturn = ReturnType>; + +export enum CP {lt = 'lt', eq = 'eq', gt = 'gt'} diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 392d7e4..37fed27 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -77,3 +77,10 @@ export const trampolineAsync = (fn: TrlAsyncFn) => { {cont} ); }; + +export const getMSB = (value: number): number => { + if (value <= 0) { + return 0; + } + return 1 << (31 - Math.clz32(value)); +}; diff --git a/test/config.js b/test/config.js new file mode 100644 index 0000000..1b96349 --- /dev/null +++ b/test/config.js @@ -0,0 +1,4 @@ +'use strict'; +Object.defineProperty(exports, '__esModule', {value: true}); +exports.isDebugTest = void 0; +exports.isDebugTest = false; diff --git a/test/types/index.js b/test/types/index.js new file mode 100644 index 0000000..c040865 --- /dev/null +++ b/test/types/index.js @@ -0,0 +1,29 @@ +'use strict'; +var __createBinding = + (this && this.__createBinding) || + (Object.create + ? function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ('get' in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { + enumerable: true, + get: function () { + return m[k]; + } + }; + } + Object.defineProperty(o, k2, desc); + } + : function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; + }); +var __exportStar = + (this && this.__exportStar) || + function (m, exports) { + for (var p in m) + if (p !== 'default' && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); + }; +Object.defineProperty(exports, '__esModule', {value: true}); +__exportStar(require('./utils'), exports); diff --git a/test/types/utils/big-o.js b/test/types/utils/big-o.js new file mode 100644 index 0000000..38813da --- /dev/null +++ b/test/types/utils/big-o.js @@ -0,0 +1,2 @@ +'use strict'; +Object.defineProperty(exports, '__esModule', {value: true}); diff --git a/test/types/utils/index.js b/test/types/utils/index.js new file mode 100644 index 0000000..a48da0c --- /dev/null +++ b/test/types/utils/index.js @@ -0,0 +1,29 @@ +'use strict'; +var __createBinding = + (this && this.__createBinding) || + (Object.create + ? function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ('get' in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { + enumerable: true, + get: function () { + return m[k]; + } + }; + } + Object.defineProperty(o, k2, desc); + } + : function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; + }); +var __exportStar = + (this && this.__exportStar) || + function (m, exports) { + for (var p in m) + if (p !== 'default' && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); + }; +Object.defineProperty(exports, '__esModule', {value: true}); +__exportStar(require('./big-o'), exports); diff --git a/test/unit/data-structures/binary-tree/binary-index-tree.test.ts b/test/unit/data-structures/binary-tree/binary-index-tree.test.ts new file mode 100644 index 0000000..1e43598 --- /dev/null +++ b/test/unit/data-structures/binary-tree/binary-index-tree.test.ts @@ -0,0 +1,284 @@ +import {BinaryIndexedTree} from '../../../../src'; +import {isDebugTest} from '../../../config'; + +const isDebug = isDebugTest; + +describe('BinaryIndexedTree simple', () => { + let bit: BinaryIndexedTree; + + beforeEach(() => { + //Create a new BinaryIndexedTree instance before each test case + bit = new BinaryIndexedTree({frequency: 0, max: 10}); // Modify the value of max as needed + }); + + it('should initialize correctly', () => { + expect(bit.freq).toBe(0); + expect(bit.max).toBe(10); + expect(bit.freqMap).toEqual({0: 0}); // Modify the initialized record value according to the actual situation + // More initialization checks can be added + }); + + it('should read a single value correctly', () => { + // Test the function of reading a single value + bit.writeSingle(5, 5); //Write test data + expect(bit.readSingle(5)).toBe(5); // Read and verify + }); + + it('should update a value correctly', () => { + // Test the ability to update a single value + bit.writeSingle(5, 5); //Write test data + bit.update(5, 2); // update value + expect(bit.readSingle(5)).toBe(7); // Verify the updated value + }); + + it('should find lower bound correctly', () => { + //Test the function of finding the lower bound + bit.writeSingle(2, 10); + bit.writeSingle(5, 20); + bit.writeSingle(8, 30); + expect(bit.lowerBound(15)).toBe(5); // Find and verify the lower bound + }); + + it('should find upper bound correctly', () => { + //Test the function of finding the upper bound + bit.writeSingle(2, 10); + bit.writeSingle(5, 20); + bit.writeSingle(8, 30); + expect(bit.upperBound(25)).toBe(5); // Find and verify the upper bound + }); +}); + +describe('BinaryIndexedTree', () => { + const frequency = 999; + const max = 10; + let bit: BinaryIndexedTree; + + beforeEach(function () { + bit = new BinaryIndexedTree({frequency, max}); + }); + it('should validate the index', function () { + expect(() => bit.readSingle(-1)).toThrow('Index out of range'); + expect(() => bit.readSingle(10)).toThrow('Index out of range'); + }); + + it('should read a single frequency correctly', function () { + for (let i = 0; i < max; i++) { + expect(bit.readSingle(i)).toBe(frequency); + } + }); + it('should validate the index', function () { + expect(() => bit.update(-1, 100)).toThrow('Index out of range'); + expect(() => bit.update(10, 100)).toThrow('Index out of range'); + }); + it('should frequency and max', function () { + const frequency = 200; + const max = 1000; + const bit = new BinaryIndexedTree({frequency, max}); + + expect(bit.freq).toBe(frequency); + expect(bit.max).toBe(max); + }); + + it('should update the frequency with the given delta', function () { + for (let i = 0; i < max; i++) { + bit.update(i, i * 2); + } + for (let i = 0; i < max; i++) { + expect(bit.readSingle(i)).toBe(i * 2 + frequency); + } + }); + it('should validate the index', function () { + expect(() => bit.writeSingle(-1, 100)).toThrow('Index out of range'); + expect(() => bit.writeSingle(10, 100)).toThrow('Index out of range'); + }); + + it('should writeSingle to be correctly invoked', function () { + for (let i = 0; i < max; i++) { + bit.writeSingle(i, i * 2); + } + for (let i = 0; i < max; i++) { + expect(bit.readSingle(i)).toBe(i * 2); + } + }); + + it('should read the frequency', function () { + for (let c = 0; c <= max; c++) { + expect(bit.read(c)).toBe(c * frequency); + } + }); + + const values = [-5, 0, 5, 10, 95, 100, 1000]; + it('should find the upper-bound index', function () { + loopUpperBoundTests(bit, values); + }); + + it('should find the lower-bound index', function () { + loopLowerBoundTests(bit, values); + }); +}); + +describe('designated values', function () { + const array = [1, 8, 6, 10, 7, 9, 0, 2, 6, 3]; + const sumArray = (sum => array.map(value => (sum += value)))(0); + let bit: BinaryIndexedTree; + + beforeEach(function () { + bit = new BinaryIndexedTree({max: array.length}); + array.forEach((value, i) => bit.writeSingle(i, value)); + }); + + describe('readSingle', function () { + it('should read a single frequency correctly', function () { + array.forEach((value, i) => { + expect(bit.readSingle(i)).toBe(array[i]); + }); + }); + }); + + describe('update', function () { + it('should update the frequency with the given delta', function () { + array.forEach((value, i) => bit.update(i, value + i)); + array.forEach((value, i) => { + expect(bit.readSingle(i)).toBe(array[i] * 2 + i); + }); + }); + }); + + describe('writeSingle', function () { + it('should write a single frequency correctly', function () { + array.forEach((value, i) => bit.writeSingle(i, value + i)); + array.forEach((value, i) => { + expect(bit.readSingle(i)).toBe(array[i] + i); + }); + }); + }); + + describe('read', function () { + it('should read the cumulative frequency correctly', function () { + expect(bit.read(0)).toBe(0); + sumArray.forEach((sum, i) => { + expect(bit.read(i + 1)).toBe(sum); + }); + }); + }); + + const values = [-5, 0, 15, 25, 43, 53, 100]; + + describe('upperBound', function () { + it('should find the upper-bound index', function () { + loopUpperBoundTests(bit, values); + }); + }); + + describe('lowerBound', function () { + it('should find the lower-bound index', function () { + loopLowerBoundTests(bit, values); + }); + }); +}); + +describe('descending sequence', function () { + const array = [1, 8, -6, 10, 7, 9, 0, -2, 6, 3]; + let bit: BinaryIndexedTree; + + beforeEach(function () { + bit = new BinaryIndexedTree({max: array.length}); + array.forEach((value, i) => bit.writeSingle(i, value)); + }); + + it('should have a correct negativeCount property', function () { + expect(bit.negativeCount).toBe(2); + bit.update(2, 6); + expect(bit.negativeCount).toBe(1); + bit.update(7, 3); + expect(bit.negativeCount).toBe(0); + bit.update(8, -7); + expect(bit.negativeCount).toBe(1); + }); + + const values = [-5, 0, 15, 25, 43, 53, 100]; + + describe('upperBound', function () { + it('should validate the non-descending', function () { + expect(() => bit.upperBound(20)).toThrow('Must not be descending'); + bit.update(2, 12); + bit.update(7, 4); + loopUpperBoundTests(bit, values); + }); + }); + + describe('BinaryIndexedTree lowerBound', function () { + it('should validate the non-descending', function () { + expect(() => bit.lowerBound(20)).toThrow('Sequence is not non-descending'); + bit.update(2, 12); + bit.update(7, 4); + loopLowerBoundTests(bit, values); + }); + }); +}); + +describe('BinaryIndexedTree additional tests', () => { + it('should handle read method correctly', () => { + const bit = new BinaryIndexedTree({max: 10}); + bit.writeSingle(2, 10); + bit.writeSingle(5, 20); + bit.writeSingle(8, 30); + expect(bit.read(5)).toBe(10); // Ensure read method accumulates correctly + }); + + it('should handle consecutive operations', () => { + const bit = new BinaryIndexedTree({max: 10}); + bit.writeSingle(2, 10); + bit.update(2, 5); + expect(bit.readSingle(2)).toBe(15); + bit.writeSingle(5, 20); + expect(bit.readSingle(5)).toBe(20); + expect(bit.lowerBound(15)).toBe(2); + }); + + it('should handle frequent increment updates', () => { + const bit = new BinaryIndexedTree({max: 10}); + for (let i = 0; i < 10; i++) { + bit.update(2, 5); + } + expect(bit.readSingle(2)).toBe(50); + }); + + it('should handle edge cases', () => { + const bit = new BinaryIndexedTree({max: 10}); + bit.writeSingle(9, 100); + expect(bit.readSingle(9)).toBe(100); + expect(bit.lowerBound(200)).toBe(10); + }); +}); +function loopUpperBoundTests(bit: BinaryIndexedTree, values: number[]) { + for (const value of values) { + const index = bit.upperBound(value); + if (index > 0) { + expect(bit.read(index)).toBeLessThanOrEqual(value); + } else { + expect(index).toBe(0); + } + if (index < bit.max) { + expect(bit.read(index + 1)).toBeGreaterThan(value); + } else { + expect(index).toBe(bit.max); + } + } +} + +function loopLowerBoundTests(bit: BinaryIndexedTree, values: number[]) { + for (const value of values) { + const index = bit.lowerBound(value); + if (index > 0) { + expect(bit.read(index)).toBeLessThan(value); + } else { + expect(index).toBe(0); + } + if (index < bit.max) { + expect(bit.read(index + 1)).toBeGreaterThanOrEqual(value); + } else { + expect(index).toBe(bit.max); + } + } +} diff --git a/test/utils/big-o.js b/test/utils/big-o.js new file mode 100644 index 0000000..099b7ec --- /dev/null +++ b/test/utils/big-o.js @@ -0,0 +1,212 @@ +'use strict'; +Object.defineProperty(exports, '__esModule', {value: true}); +exports.logBigOMetrics = exports.logBigOMetricsWrap = exports.bigO = exports.magnitude = void 0; +var config_1 = require('../config'); + +var isDebug = config_1.isDebugTest; +var orderReducedBy = 2; // reduction of bigO's order compared to the baseline bigO +exports.magnitude = { + CONSTANT: Math.floor(Number.MAX_SAFE_INTEGER / Math.pow(10, orderReducedBy)), + LOG_N: Math.pow(10, 9 - orderReducedBy), + LINEAR: Math.pow(10, 6 - orderReducedBy), + N_LOG_N: Math.pow(10, 5 - orderReducedBy), + SQUARED: Math.pow(10, 4 - orderReducedBy), + CUBED: Math.pow(10, 3 - orderReducedBy), + FACTORIAL: 20 - orderReducedBy +}; +exports.bigO = { + CONSTANT: exports.magnitude.CONSTANT / 100000, + LOG_N: Math.log2(exports.magnitude.LOG_N) / 1000, + LINEAR: exports.magnitude.LINEAR / 1000, + N_LOG_N: (exports.magnitude.N_LOG_N * Math.log2(exports.magnitude.LOG_N)) / 1000, + SQUARED: Math.pow(exports.magnitude.SQUARED, 2) / 1000, + CUBED: Math.pow(exports.magnitude.SQUARED, 3) / 1000, + FACTORIAL: 10000 +}; +function findPotentialN(input) { + var longestArray = []; + var mostProperties = {}; + function recurse(obj) { + if (Array.isArray(obj)) { + if (obj.length > longestArray.length) { + longestArray = obj; + } + } else if (typeof obj === 'object' && obj !== null) { + var keys = Object.keys(obj); + if (keys.length > Object.keys(mostProperties).length) { + mostProperties = obj; + } + keys.forEach(function (key) { + recurse(obj[key]); + }); + } + } + if (Array.isArray(input)) { + input.forEach(function (item) { + recurse(item); + }); + } else { + recurse(input); + } + // return [longestArray, mostProperties] : [any[], { [key: string]: any }]; + return Math.max(longestArray.length, Object.keys(mostProperties).length); +} +function linearRegression(x, y) { + var n = x.length; + var sumX = x.reduce(function (acc, val) { + return acc + val; + }, 0); + var sumY = y.reduce(function (acc, val) { + return acc + val; + }, 0); + var sumXSquared = x.reduce(function (acc, val) { + return acc + Math.pow(val, 2); + }, 0); + var sumXY = x.reduce(function (acc, val, i) { + return acc + val * y[i]; + }, 0); + var slope = (n * sumXY - sumX * sumY) / (n * sumXSquared - Math.pow(sumX, 2)); + var intercept = (sumY - slope * sumX) / n; + var yHat = x.map(function (val) { + return slope * val + intercept; + }); + var totalVariation = y + .map(function (val, i) { + return Math.pow(val - yHat[i], 2); + }) + .reduce(function (acc, val) { + return acc + val; + }, 0); + var explainedVariation = y + .map(function (val) { + return Math.pow(val - sumY / n, 2); + }) + .reduce(function (acc, val) { + return acc + val; + }, 0); + var rSquared = 1 - totalVariation / explainedVariation; + return {slope: slope, intercept: intercept, rSquared: rSquared}; +} +function estimateBigO(runtimes, dataSizes) { + // Make sure the input runtimes and data sizes have the same length + if (runtimes.length !== dataSizes.length) { + return 'Lengths of input arrays do not match'; + } + // Create an array to store the computational complexity of each data point + var complexities = []; + // Traverse different possible complexities + var complexitiesToCheck = [ + 'O(1)', + 'O(log n)', + 'O(n)', + 'O(n log n)', + 'O(n^2)' // squared time complexity + ]; + var _loop_1 = function (complexity) { + // Calculate data points for fitting + var fittedData = dataSizes.map(function (size) { + if (complexity === 'O(1)') { + return 1; // constant time complexity + } else if (complexity === 'O(log n)') { + return Math.log(size); + } else if (complexity === 'O(n)') { + return size; + } else if (complexity === 'O(n log n)') { + return size * Math.log(size); + } else if (complexity === 'O(n^2)') { + return Math.pow(size, 2); + } else { + return Math.pow(size, 10); + } + }); + // Fit the data points using linear regression analysis + var regressionResult = linearRegression(fittedData, runtimes); + // Check the R-squared value of the fit. It is usually considered a valid fit if it is greater than 0.9. + if (regressionResult.rSquared >= 0.9) { + complexities.push(complexity); + } + }; + for (var _i = 0, complexitiesToCheck_1 = complexitiesToCheck; _i < complexitiesToCheck_1.length; _i++) { + var complexity = complexitiesToCheck_1[_i]; + _loop_1(complexity); + } + // If there is no valid fitting result, return "cannot estimate", otherwise return the estimated time complexity + if (complexities.length === 0) { + return 'Unable to estimate'; + } else { + return complexities.join(' or '); + } +} +var methodLogs = new Map(); +function logBigOMetricsWrap(fn, args, fnName) { + var startTime = performance.now(); + var result = fn(args); + var endTime = performance.now(); + var runTime = endTime - startTime; + var methodName = ''.concat(fnName); + if (!methodLogs.has(methodName)) { + methodLogs.set(methodName, []); + } + var methodLog = methodLogs.get(methodName); + var maxDataSize = args.length === 1 && typeof args[0] === 'number' ? args[0] : findPotentialN(args); + if (methodLog) { + methodLog.push([runTime, maxDataSize]); + if (methodLog.length >= 20) { + isDebug && console.log('triggered', methodName, methodLog); + var bigO_1 = estimateBigO( + methodLog.map(function (_a) { + var runTime = _a[0]; + return runTime; + }), + methodLog.map(function (_a) { + var runTime = _a[0]; + return runTime; + }) + ); + isDebug && console.log('Estimated Big O: '.concat(bigO_1)); + methodLogs.delete(methodName); + } + } + return result; +} +exports.logBigOMetricsWrap = logBigOMetricsWrap; +function logBigOMetrics(target, propertyKey, descriptor) { + var originalMethod = descriptor.value; + descriptor.value = function () { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + var startTime = performance.now(); + var result = originalMethod.apply(this, args); + var endTime = performance.now(); + var runTime = endTime - startTime; + var methodName = ''.concat(target.constructor.name, '.').concat(propertyKey); + if (!methodLogs.has(methodName)) { + methodLogs.set(methodName, []); + } + var methodLog = methodLogs.get(methodName); + var maxDataSize = args.length === 1 && typeof args[0] === 'number' ? args[0] : findPotentialN(args); + if (methodLog) { + methodLog.push([runTime, maxDataSize]); + if (methodLog.length >= 20) { + isDebug && console.log('triggered', methodName, methodLog); + var bigO_2 = estimateBigO( + methodLog.map(function (_a) { + var runTime = _a[0]; + return runTime; + }), + methodLog.map(function (_a) { + var runTime = _a[0]; + return runTime; + }) + ); + isDebug && console.log('Estimated Big O: '.concat(bigO_2)); + methodLogs.delete(methodName); + } + } + return result; + }; + return descriptor; +} +exports.logBigOMetrics = logBigOMetrics; diff --git a/test/utils/index.js b/test/utils/index.js new file mode 100644 index 0000000..9a9d3e3 --- /dev/null +++ b/test/utils/index.js @@ -0,0 +1,30 @@ +'use strict'; +var __createBinding = + (this && this.__createBinding) || + (Object.create + ? function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ('get' in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { + enumerable: true, + get: function () { + return m[k]; + } + }; + } + Object.defineProperty(o, k2, desc); + } + : function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; + }); +var __exportStar = + (this && this.__exportStar) || + function (m, exports) { + for (var p in m) + if (p !== 'default' && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); + }; +Object.defineProperty(exports, '__esModule', {value: true}); +__exportStar(require('./number'), exports); +__exportStar(require('./big-o'), exports); diff --git a/test/utils/number.js b/test/utils/number.js new file mode 100644 index 0000000..75aee0a --- /dev/null +++ b/test/utils/number.js @@ -0,0 +1,14 @@ +'use strict'; +Object.defineProperty(exports, '__esModule', {value: true}); +exports.getMSB = exports.getRandomInt = void 0; +function getRandomInt(min, max) { + return Math.floor(Math.random() * (max - min + 1)) + min; +} +exports.getRandomInt = getRandomInt; +var getMSB = function (value) { + if (value <= 0) { + return 0; + } + return 1 << (31 - Math.clz32(value)); +}; +exports.getMSB = getMSB; From 5978159d9e5f96f13bb39d1fe9ae3205bfa59deb Mon Sep 17 00:00:00 2001 From: Revone Date: Wed, 25 Oct 2023 10:40:39 +0800 Subject: [PATCH 17/46] [project] ready to publish all subs customized --- package.json | 3 ++- scripts/copy_to_all_subs.sh | 27 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 scripts/copy_to_all_subs.sh diff --git a/package.json b/package.json index 53428ea..55f3561 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,8 @@ "changelog": "auto-changelog", "coverage:badge": "istanbul-badges-readme", "ci": "env && git fetch --tags && npm run lint && npm run build && npm run update:subs && npm run test && npm run changelog", - "publish:subs": "sh scripts/publish_all_subs.sh", + "copy:to-subs": "sh scripts/copy_to_all_subs.sh", + "publish:subs": "npm run copy:to-subs && sh scripts/publish_all_subs.sh", "publish:docs": "sh scripts/publish_docs.sh", "publish:all": "npm run ci && npm publish && npm run publish:subs && npm run publish:docs" }, diff --git a/scripts/copy_to_all_subs.sh b/scripts/copy_to_all_subs.sh new file mode 100644 index 0000000..f8befe0 --- /dev/null +++ b/scripts/copy_to_all_subs.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +# Enable extended globbing +shopt -s extglob + +# target directory +individuals_dir_default=$(jq -r .individualsDir ./scripts/config.json) + +# Source directory +source_dir_default=$(jq -r .sourceDir ./scripts/config.json) + +# List of directories +directories=( + "avl-tree-typed" + +) + +# Loop through each directory +for dir in "${directories[@]}"; do + # Delete all files except index.ts + find "$individuals_dir_default"/"$dir"/src -type f ! -name 'index.ts' -delete + + # Copy the files to the target directory, excluding index.ts + cp -R "$source_dir_default"/src/!(index.ts) "$individuals_dir_default"/"$dir"/src +done + +echo "All packages copied." From 063b702236d812ace84af35bf29701f107f337f2 Mon Sep 17 00:00:00 2001 From: Revone Date: Wed, 25 Oct 2023 11:19:03 +0800 Subject: [PATCH 18/46] [project] Achieve a rational subpackage structure that enables individual subpackages to be independently exportable. --- package-lock.json | 62 ++- package.json | 10 +- scripts/copy_to_all_subs.sh | 20 +- scripts/publish_all_subs.sh | 4 +- src/data-structures/binary-tree/avl-tree.ts | 54 +-- .../binary-tree/binary-tree.ts | 110 +++--- src/data-structures/binary-tree/bst.ts | 4 + src/data-structures/binary-tree/rb-tree.ts | 4 +- .../binary-tree/tree-multiset.ts | 58 +-- src/data-structures/hash/hash-map.ts | 160 ++++---- src/data-structures/hash/hash-table.ts | 231 +++++------ src/data-structures/heap/heap.ts | 363 +++++++++--------- .../linked-list/doubly-linked-list.ts | 8 +- .../linked-list/skip-linked-list.ts | 93 ++--- src/data-structures/matrix/matrix2d.ts | 20 +- src/data-structures/trie/trie.ts | 18 +- src/types/helpers.ts | 6 +- .../binary-tree/binary-index-tree.test.ts | 2 +- 18 files changed, 629 insertions(+), 598 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3f14577..b57f885 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "data-structure-typed", - "version": "1.37.9", + "version": "1.38.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "data-structure-typed", - "version": "1.37.9", + "version": "1.38.1", "license": "MIT", "dependencies": { "data-structure-typed": "^1.37.5" @@ -18,17 +18,17 @@ "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", "auto-changelog": "^2.4.0", - "avl-tree-typed": "^1.37.9", + "avl-tree-typed": "^1.38.1", "benchmark": "^2.1.4", - "binary-tree-typed": "^1.37.9", - "bst-typed": "^1.37.9", + "binary-tree-typed": "^1.38.1", + "bst-typed": "^1.38.1", "dependency-cruiser": "^14.1.0", "eslint": "^8.50.0", "eslint-config-prettier": "^9.0.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.28.1", - "heap-typed": "^1.37.9", + "heap-typed": "^1.38.1", "istanbul-badges-readme": "^1.8.5", "jest": "^29.7.0", "prettier": "^3.0.3", @@ -2405,13 +2405,10 @@ } }, "node_modules/avl-tree-typed": { - "version": "1.37.9", - "resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.37.9.tgz", - "integrity": "sha512-FC7ezzT3Yw8H65oZgf/3RGYo9gnZRgORzlGGO4PyC19ZeIu0UZMHu1+kT0yEfbIE1qGBb4lnuwk4ia8CitcgLg==", - "dev": true, - "dependencies": { - "data-structure-typed": "^1.37.9" - } + "version": "1.38.1", + "resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.38.1.tgz", + "integrity": "sha512-owzl0/cOijCKDyL8RAR+8Q2ibtqA+datgKQEbs1qNpCvMgYBtaytIgwyR68jYD+u7QGTXWYdO288H6NiKI0eTA==", + "dev": true }, "node_modules/babel-jest": { "version": "29.7.0", @@ -2595,13 +2592,10 @@ } }, "node_modules/binary-tree-typed": { - "version": "1.37.9", - "resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.37.9.tgz", - "integrity": "sha512-8nCjU4V6ViR8NQfxCBsLRFx5Z8D4jpUIx4NuvjliR1R8YIzL6wMmahemve+UbCUWhZJNG5Dv0kVnnCWIK+T0hw==", - "dev": true, - "dependencies": { - "data-structure-typed": "^1.37.9" - } + "version": "1.38.1", + "resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.38.1.tgz", + "integrity": "sha512-h4dBfVSaqUPfpVRHI7ZWUv3BSFYF9VtzoRu5X2rIq4se89QX+1cQTirQ7bCG0mDLJ9A4GfmEVMvQvvmVhorBEQ==", + "dev": true }, "node_modules/brace-expansion": { "version": "1.1.11", @@ -2679,13 +2673,10 @@ } }, "node_modules/bst-typed": { - "version": "1.37.9", - "resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.37.9.tgz", - "integrity": "sha512-KUp29JhTbNVdA1ePP7gUdi7uaRpM8DVhve9LMHQSUzxTDtHGc8mFTA+njFY7LLU2Rqtu/vqBgTu7bJRVJbWrPA==", - "dev": true, - "dependencies": { - "data-structure-typed": "^1.37.9" - } + "version": "1.38.1", + "resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.38.1.tgz", + "integrity": "sha512-jNBmdOaSAApSx5iYo5ijunp3rtATcTmNOVnRiasCqKzSYTLfCJiGqIoXkDYMIFWK7hlgbAsVJkzTLciKf4RjcQ==", + "dev": true }, "node_modules/buffer-from": { "version": "1.1.2", @@ -3037,9 +3028,9 @@ } }, "node_modules/data-structure-typed": { - "version": "1.37.9", - "resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.37.9.tgz", - "integrity": "sha512-6CUX8ANDv2IsJTB8tbdUrXFgWV1AAPxWdcco1ZRUX8caCM0Ge6Snwfse1G1BF6M8kVEuGO2r4q6zkw1z2DxAtQ==", + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.38.0.tgz", + "integrity": "sha512-KXYXlyQm7k09Gp4hhsneMOL1bLEPse6Kv3qeE6CU78jidJEh8SY66K9auAUio1mpkjbKTCqjf7q3Ep4pXkhB2w==", "dependencies": { "data-structure-typed": "^1.37.5" } @@ -4387,13 +4378,10 @@ } }, "node_modules/heap-typed": { - "version": "1.37.9", - "resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.37.9.tgz", - "integrity": "sha512-oYkcappLoSb8Zs9gbMaUfIwsm2arykNoQ6gF28x1PQuKa0/a9zonEqqRN6dKlfOT28JIvqhnrSed039YDlZhrQ==", - "dev": true, - "dependencies": { - "data-structure-typed": "^1.37.9" - } + "version": "1.38.1", + "resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.38.1.tgz", + "integrity": "sha512-PvLlO5lSds9zOOX4GvVS2mgZfLk0f7Ev+++hYkGrlCqpcCGDsXVn+B0k/Jel0mkTXIK3zVkev2if7Cxsmk1pEQ==", + "dev": true }, "node_modules/html-escaper": { "version": "2.0.2", diff --git a/package.json b/package.json index 55f3561..f8753bb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "data-structure-typed", - "version": "1.37.9", + "version": "1.38.1", "description": "Data Structures of Javascript & TypeScript. Binary Tree, BST, Graph, Heap, Priority Queue, Linked List, Queue, Deque, Stack, AVL Tree, Tree Multiset, Trie, Directed Graph, Undirected Graph, Singly Linked List, Doubly Linked List, Max Heap, Max Priority Queue, Min Heap, Min Priority Queue.", "main": "dist/index.js", "module": "lib/index.js", @@ -59,17 +59,17 @@ "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", "auto-changelog": "^2.4.0", - "avl-tree-typed": "^1.37.9", + "avl-tree-typed": "^1.38.1", "benchmark": "^2.1.4", - "binary-tree-typed": "^1.37.9", - "bst-typed": "^1.37.9", + "binary-tree-typed": "^1.38.1", + "bst-typed": "^1.38.1", "dependency-cruiser": "^14.1.0", "eslint": "^8.50.0", "eslint-config-prettier": "^9.0.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.28.1", - "heap-typed": "^1.37.9", + "heap-typed": "^1.38.1", "istanbul-badges-readme": "^1.8.5", "jest": "^29.7.0", "prettier": "^3.0.3", diff --git a/scripts/copy_to_all_subs.sh b/scripts/copy_to_all_subs.sh index f8befe0..a12a000 100644 --- a/scripts/copy_to_all_subs.sh +++ b/scripts/copy_to_all_subs.sh @@ -12,7 +12,25 @@ source_dir_default=$(jq -r .sourceDir ./scripts/config.json) # List of directories directories=( "avl-tree-typed" - + "binary-tree-typed" + "bst-typed" + "deque-typed" + "directed-graph-typed" + "doubly-linked-list-typed" + "graph-typed" + "heap-typed" + "linked-list-typed" + "max-heap-typed" + "max-priority-queue-typed" + "min-heap-typed" + "min-priority-queue-typed" + "priority-queue-typed" + "singly-linked-list-typed" + "queue-typed" + "stack-typed" + "tree-multiset-typed" + "trie-typed" + "undirected-graph-typed" ) # Loop through each directory diff --git a/scripts/publish_all_subs.sh b/scripts/publish_all_subs.sh index 7b7da2f..6f52833 100755 --- a/scripts/publish_all_subs.sh +++ b/scripts/publish_all_subs.sh @@ -61,8 +61,8 @@ for dir in "${directories[@]}"; do # jq ".dependencies[\"data-structure-typed\"] = \"$version_prompted\"" package.json > temp.json # mv temp.json package.json - # Install data-structure-typed package and build - npm i data-structure-typed@"$version_prompted" +# # Install data-structure-typed package and build +# npm i data-structure-typed@"$version_prompted" npm run build:publish cd .. diff --git a/src/data-structures/binary-tree/avl-tree.ts b/src/data-structures/binary-tree/avl-tree.ts index a1f8fb0..1b1c88d 100644 --- a/src/data-structures/binary-tree/avl-tree.ts +++ b/src/data-structures/binary-tree/avl-tree.ts @@ -32,33 +32,6 @@ export class AVLTree = AVLTreeNode> extends B super(options); } - /** - * The function swaps the key, value, and height properties between two nodes in a binary tree. - * @param {N} srcNode - The `srcNode` parameter represents the source node that needs to be swapped - * with the `destNode`. - * @param {N} destNode - The `destNode` parameter represents the destination node where the values - * from the source node (`srcNode`) will be swapped to. - * @returns The method is returning the `destNode` after swapping its properties with the `srcNode`. - */ - protected override _swap(srcNode: N, destNode: N): N { - const {key, val, height} = destNode; - const tempNode = this.createNode(key, val); - - if (tempNode) { - tempNode.height = height; - - destNode.key = srcNode.key; - destNode.val = srcNode.val; - destNode.height = srcNode.height; - - srcNode.key = tempNode.key; - srcNode.val = tempNode.val; - srcNode.height = tempNode.height; - } - - return destNode; - } - /** * The function creates a new AVL tree node with the specified key and value. * @param {BinaryTreeNodeKey} key - The key parameter is the key value that will be associated with @@ -105,6 +78,33 @@ export class AVLTree = AVLTreeNode> extends B return deletedResults; } + /** + * The function swaps the key, value, and height properties between two nodes in a binary tree. + * @param {N} srcNode - The `srcNode` parameter represents the source node that needs to be swapped + * with the `destNode`. + * @param {N} destNode - The `destNode` parameter represents the destination node where the values + * from the source node (`srcNode`) will be swapped to. + * @returns The method is returning the `destNode` after swapping its properties with the `srcNode`. + */ + protected override _swap(srcNode: N, destNode: N): N { + const {key, val, height} = destNode; + const tempNode = this.createNode(key, val); + + if (tempNode) { + tempNode.height = height; + + destNode.key = srcNode.key; + destNode.val = srcNode.val; + destNode.height = srcNode.height; + + srcNode.key = tempNode.key; + srcNode.val = tempNode.val; + srcNode.height = tempNode.height; + } + + return destNode; + } + /** * The function calculates the balance factor of a node in a binary tree. * @param {N} node - The parameter "node" represents a node in a binary tree data structure. diff --git a/src/data-structures/binary-tree/binary-tree.ts b/src/data-structures/binary-tree/binary-tree.ts index e654f31..a82f8a3 100644 --- a/src/data-structures/binary-tree/binary-tree.ts +++ b/src/data-structures/binary-tree/binary-tree.ts @@ -26,16 +26,6 @@ import {Queue} from '../queue'; * @template FAMILY - The type of the family relationship in the binary tree. */ export class BinaryTreeNode = BinaryTreeNodeNested> { - /** - * Creates a new instance of BinaryTreeNode. - * @param {BinaryTreeNodeKey} key - The key associated with the node. - * @param {V} val - The value stored in the node. - */ - constructor(key: BinaryTreeNodeKey, val?: V) { - this.key = key; - this.val = val; - } - /** * The key associated with the node. */ @@ -46,6 +36,21 @@ export class BinaryTreeNode = */ val: V | undefined; + /** + * The parent node of the current node. + */ + parent: FAMILY | null | undefined; + + /** + * Creates a new instance of BinaryTreeNode. + * @param {BinaryTreeNodeKey} key - The key associated with the node. + * @param {V} val - The value stored in the node. + */ + constructor(key: BinaryTreeNodeKey, val?: V) { + this.key = key; + this.val = val; + } + private _left: FAMILY | null | undefined; /** @@ -86,11 +91,6 @@ export class BinaryTreeNode = this._right = v; } - /** - * The parent node of the current node. - */ - parent: FAMILY | null | undefined; - /** * Get the position of the node within its family. * @returns {FamilyPosition} - The family position of the node. @@ -128,6 +128,8 @@ export class BinaryTreeNode = * @template N - The type of the binary tree's nodes. */ export class BinaryTree = BinaryTreeNode> implements IBinaryTree { + private _loopType: IterationType = IterationType.ITERATIVE; + /** * Creates a new instance of BinaryTree. * @param {BinaryTreeOptions} [options] - The options for the binary tree. @@ -139,16 +141,6 @@ export class BinaryTree = BinaryTreeNode> } } - /** - * Creates a new instance of BinaryTreeNode with the given key and value. - * @param {BinaryTreeNodeKey} key - The key for the new node. - * @param {N['val']} val - The value for the new node. - * @returns {N} - The newly created BinaryTreeNode. - */ - createNode(key: BinaryTreeNodeKey, val?: N['val']): N { - return new BinaryTreeNode(key, val) as N; - } - private _root: N | null = null; /** @@ -167,8 +159,6 @@ export class BinaryTree = BinaryTreeNode> return this._size; } - private _loopType: IterationType = IterationType.ITERATIVE; - /** * Get the iteration type used in the binary tree. */ @@ -185,24 +175,13 @@ export class BinaryTree = BinaryTreeNode> } /** - * Swap the data of two nodes in the binary tree. - * @param {N} srcNode - The source node to swap. - * @param {N} destNode - The destination node to swap. - * @returns {N} - The destination node after the swap. + * Creates a new instance of BinaryTreeNode with the given key and value. + * @param {BinaryTreeNodeKey} key - The key for the new node. + * @param {N['val']} val - The value for the new node. + * @returns {N} - The newly created BinaryTreeNode. */ - protected _swap(srcNode: N, destNode: N): N { - const {key, val} = destNode; - const tempNode = this.createNode(key, val); - - if (tempNode) { - destNode.key = srcNode.key; - destNode.val = srcNode.val; - - srcNode.key = tempNode.key; - srcNode.val = tempNode.val; - } - - return destNode; + createNode(key: BinaryTreeNodeKey, val?: N['val']): N { + return new BinaryTreeNode(key, val) as N; } /** @@ -449,8 +428,6 @@ export class BinaryTree = BinaryTreeNode> } } - protected _defaultCallbackByKey: MapCallback = node => node.key; - /** * The `getMinHeight` function calculates the minimum height of a binary tree using either a * recursive or iterative approach. @@ -902,8 +879,6 @@ export class BinaryTree = BinaryTreeNode> return ans; } - // --- start additional methods --- - /** * The bfs function performs a breadth-first search traversal on a binary tree, executing a callback * function on each node. @@ -973,13 +948,7 @@ export class BinaryTree = BinaryTreeNode> } } - /** - * Time complexity is O(n) - * Space complexity of Iterative dfs equals to recursive dfs which is O(n) because of the stack - * The Morris algorithm only modifies the tree's structure during traversal; once the traversal is complete, - * the tree's structure should be restored to its original state to maintain the tree's integrity. - * This is because the purpose of the Morris algorithm is to save space rather than permanently alter the tree's shape. - */ + // --- start additional methods --- /** * The `morris` function performs a depth-first traversal of a binary tree using the Morris traversal @@ -1080,6 +1049,37 @@ export class BinaryTree = BinaryTreeNode> return ans; } + /** + * Swap the data of two nodes in the binary tree. + * @param {N} srcNode - The source node to swap. + * @param {N} destNode - The destination node to swap. + * @returns {N} - The destination node after the swap. + */ + protected _swap(srcNode: N, destNode: N): N { + const {key, val} = destNode; + const tempNode = this.createNode(key, val); + + if (tempNode) { + destNode.key = srcNode.key; + destNode.val = srcNode.val; + + srcNode.key = tempNode.key; + srcNode.val = tempNode.val; + } + + return destNode; + } + + /** + * Time complexity is O(n) + * Space complexity of Iterative dfs equals to recursive dfs which is O(n) because of the stack + * The Morris algorithm only modifies the tree's structure during traversal; once the traversal is complete, + * the tree's structure should be restored to its original state to maintain the tree's integrity. + * This is because the purpose of the Morris algorithm is to save space rather than permanently alter the tree's shape. + */ + + protected _defaultCallbackByKey: MapCallback = node => node.key; + /** * The function `_addTo` adds a new node to a binary tree if there is an available position. * @param {N | null} newNode - The `newNode` parameter represents the node that you want to add to diff --git a/src/data-structures/binary-tree/bst.ts b/src/data-structures/binary-tree/bst.ts index f9bd32b..b16ec02 100644 --- a/src/data-structures/binary-tree/bst.ts +++ b/src/data-structures/binary-tree/bst.ts @@ -153,22 +153,26 @@ export class BST = BSTNode> extends BinaryTree function hasNoNull(arr: (BinaryTreeNodeKey | null)[] | (N | null)[]): arr is BinaryTreeNodeKey[] | N[] { return arr.indexOf(null) === -1; } + if (!isBalanceAdd || !hasNoNull(keysOrNodes)) { return super.addMany(keysOrNodes, data); } const inserted: (N | null | undefined)[] = []; const combinedArr: [BinaryTreeNodeKey | N, N['val']][] = keysOrNodes.map((value, index) => [value, data?.[index]]); let sorted = []; + function isNodeOrNullTuple(arr: [BinaryTreeNodeKey | N, N['val']][]): arr is [N, N['val']][] { for (const [keyOrNode] of arr) if (keyOrNode instanceof BSTNode) return true; return false; } + function isBinaryTreeKeyOrNullTuple( arr: [BinaryTreeNodeKey | N, N['val']][] ): arr is [BinaryTreeNodeKey, N['val']][] { for (const [keyOrNode] of arr) if (typeof keyOrNode === 'number') return true; return false; } + let sortedKeysOrNodes: (number | N | null)[] = [], sortedData: (N['val'] | undefined)[] | undefined = []; diff --git a/src/data-structures/binary-tree/rb-tree.ts b/src/data-structures/binary-tree/rb-tree.ts index fafb4f1..d8d1685 100644 --- a/src/data-structures/binary-tree/rb-tree.ts +++ b/src/data-structures/binary-tree/rb-tree.ts @@ -6,13 +6,13 @@ export class RBTreeNode = RBTreeNo V, FAMILY > { - private _color: RBColor; - constructor(key: BinaryTreeNodeKey, val?: V) { super(key, val); this._color = RBColor.RED; } + private _color: RBColor; + get color(): RBColor { return this._color; } diff --git a/src/data-structures/binary-tree/tree-multiset.ts b/src/data-structures/binary-tree/tree-multiset.ts index 7dce900..a36826b 100644 --- a/src/data-structures/binary-tree/tree-multiset.ts +++ b/src/data-structures/binary-tree/tree-multiset.ts @@ -14,6 +14,8 @@ export class TreeMultisetNode< V = any, FAMILY extends TreeMultisetNode = TreeMultisetNodeNested > extends AVLTreeNode { + count: number; + /** * The constructor function initializes a BinaryTreeNode object with a key, value, and count. * @param {BinaryTreeNodeKey} key - The `key` parameter is of type `BinaryTreeNodeKey` and represents the unique identifier @@ -28,8 +30,6 @@ export class TreeMultisetNode< super(key, val); this.count = count; } - - count: number; } /** @@ -68,33 +68,6 @@ export class TreeMultiset = TreeMultiset return new TreeMultisetNode(key, val, count) as N; } - /** - * The function swaps the values of two nodes in a binary tree. - * @param {N} srcNode - The source node that needs to be swapped with the destination node. - * @param {N} destNode - The `destNode` parameter represents the destination node where the values - * from `srcNode` will be swapped into. - * @returns The method is returning the `destNode` after swapping its properties with the `srcNode`. - */ - protected override _swap(srcNode: N, destNode: N): N { - const {key, val, count, height} = destNode; - const tempNode = this.createNode(key, val, count); - if (tempNode) { - tempNode.height = height; - - destNode.key = srcNode.key; - destNode.val = srcNode.val; - destNode.count = srcNode.count; - destNode.height = srcNode.height; - - srcNode.key = tempNode.key; - srcNode.val = tempNode.val; - srcNode.count = tempNode.count; - srcNode.height = tempNode.height; - } - - return destNode; - } - /** * The `add` function adds a new node to a binary search tree, updating the count if the key already * exists, and balancing the tree if necessary. @@ -365,6 +338,33 @@ export class TreeMultiset = TreeMultiset this._setCount(0); } + /** + * The function swaps the values of two nodes in a binary tree. + * @param {N} srcNode - The source node that needs to be swapped with the destination node. + * @param {N} destNode - The `destNode` parameter represents the destination node where the values + * from `srcNode` will be swapped into. + * @returns The method is returning the `destNode` after swapping its properties with the `srcNode`. + */ + protected override _swap(srcNode: N, destNode: N): N { + const {key, val, count, height} = destNode; + const tempNode = this.createNode(key, val, count); + if (tempNode) { + tempNode.height = height; + + destNode.key = srcNode.key; + destNode.val = srcNode.val; + destNode.count = srcNode.count; + destNode.height = srcNode.height; + + srcNode.key = tempNode.key; + srcNode.val = tempNode.val; + srcNode.count = tempNode.count; + srcNode.height = tempNode.height; + } + + return destNode; + } + /** * The function sets the value of the "_count" property. * @param {number} v - number diff --git a/src/data-structures/hash/hash-map.ts b/src/data-structures/hash/hash-map.ts index 7661bf0..f3a5213 100644 --- a/src/data-structures/hash/hash-map.ts +++ b/src/data-structures/hash/hash-map.ts @@ -8,60 +8,6 @@ import {HashFunction} from '../../types'; * @license MIT License */ export class HashMap { - get hashFn(): HashFunction { - return this._hashFn; - } - - set hashFn(value: HashFunction) { - this._hashFn = value; - } - get table(): Array> { - return this._table; - } - - set table(value: Array>) { - this._table = value; - } - - get capacityMultiplier(): number { - return this._capacityMultiplier; - } - - set capacityMultiplier(value: number) { - this._capacityMultiplier = value; - } - - get loadFactor(): number { - return this._loadFactor; - } - - set loadFactor(value: number) { - this._loadFactor = value; - } - - get initialCapacity(): number { - return this._initialCapacity; - } - - set initialCapacity(value: number) { - this._initialCapacity = value; - } - - get size(): number { - return this._size; - } - - set size(value: number) { - this._size = value; - } - - private _initialCapacity: number; - private _loadFactor: number; - private _capacityMultiplier: number; - private _size: number; - private _table: Array>; - private _hashFn: HashFunction; - /** * The constructor initializes the properties of a hash table, including the initial capacity, load factor, capacity * multiplier, size, table array, and hash function. @@ -92,31 +38,64 @@ export class HashMap { }); } - private _hash(key: K): number { - return this._hashFn(key); + private _initialCapacity: number; + + get initialCapacity(): number { + return this._initialCapacity; } - /** - * The `resizeTable` function resizes the table used in a hash map by creating a new table with a specified capacity and - * rehashing the key-value pairs from the old table into the new table. - * @param {number} newCapacity - The newCapacity parameter is the desired capacity for the resized table. It represents - * the number of buckets that the new table should have. - */ - private resizeTable(newCapacity: number): void { - const newTable = new Array(newCapacity); - for (const bucket of this._table) { - // Note that this is this._table - if (bucket) { - for (const [key, value] of bucket) { - const newIndex = this._hash(key) % newCapacity; - if (!newTable[newIndex]) { - newTable[newIndex] = []; - } - newTable[newIndex].push([key, value]); - } - } - } - this._table = newTable; // Again, here is this._table + set initialCapacity(value: number) { + this._initialCapacity = value; + } + + private _loadFactor: number; + + get loadFactor(): number { + return this._loadFactor; + } + + set loadFactor(value: number) { + this._loadFactor = value; + } + + private _capacityMultiplier: number; + + get capacityMultiplier(): number { + return this._capacityMultiplier; + } + + set capacityMultiplier(value: number) { + this._capacityMultiplier = value; + } + + private _size: number; + + get size(): number { + return this._size; + } + + set size(value: number) { + this._size = value; + } + + private _table: Array>; + + get table(): Array> { + return this._table; + } + + set table(value: Array>) { + this._table = value; + } + + private _hashFn: HashFunction; + + get hashFn(): HashFunction { + return this._hashFn; + } + + set hashFn(value: HashFunction) { + this._hashFn = value; } set(key: K, value: V): void { @@ -200,4 +179,31 @@ export class HashMap { isEmpty(): boolean { return this.size === 0; } + + private _hash(key: K): number { + return this._hashFn(key); + } + + /** + * The `resizeTable` function resizes the table used in a hash map by creating a new table with a specified capacity and + * rehashing the key-value pairs from the old table into the new table. + * @param {number} newCapacity - The newCapacity parameter is the desired capacity for the resized table. It represents + * the number of buckets that the new table should have. + */ + private resizeTable(newCapacity: number): void { + const newTable = new Array(newCapacity); + for (const bucket of this._table) { + // Note that this is this._table + if (bucket) { + for (const [key, value] of bucket) { + const newIndex = this._hash(key) % newCapacity; + if (!newTable[newIndex]) { + newTable[newIndex] = []; + } + newTable[newIndex].push([key, value]); + } + } + } + this._table = newTable; // Again, here is this._table + } } diff --git a/src/data-structures/hash/hash-table.ts b/src/data-structures/hash/hash-table.ts index 00ac8da..bf0116e 100644 --- a/src/data-structures/hash/hash-table.ts +++ b/src/data-structures/hash/hash-table.ts @@ -21,21 +21,17 @@ export class HashTableNode { import {HashFunction} from '../../types'; export class HashTable { - get hashFn(): HashFunction { - return this._hashFn; + private static readonly DEFAULT_CAPACITY = 16; + private 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 | null>(this._capacity).fill(null); } - set hashFn(value: HashFunction) { - this._hashFn = value; - } - - get buckets(): Array | null> { - return this._buckets; - } - - set buckets(value: Array | null>) { - this._buckets = value; - } + private _capacity: number; get capacity(): number { return this._capacity; @@ -45,19 +41,118 @@ export class HashTable { this._capacity = value; } - private static readonly DEFAULT_CAPACITY = 16; - private static readonly LOAD_FACTOR = 0.75; - - private _capacity: number; private _size: number; + + get size(): number { + return this._size; + } + private _buckets: Array | null>; + + get buckets(): Array | null> { + return this._buckets; + } + + set buckets(value: Array | null>) { + this._buckets = value; + } + private _hashFn: HashFunction; - 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 | null>(this._capacity).fill(null); + get hashFn(): HashFunction { + return this._hashFn; + } + + set hashFn(value: HashFunction) { + this._hashFn = value; + } + + /** + * 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} val - The parameter `val` 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, val: V): void { + const index = this._hash(key); + const newNode = new HashTableNode(key, val); + + 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.val = val; + 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.val; + } + 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 | null = null; + + while (currentNode) { + if (currentNode.key === key) { + if (prevNode) { + prevNode.next = currentNode.next; + } else { + this._buckets[index] = currentNode.next; + } + this._size--; + currentNode.next = null; // Release memory + return; + } + prevNode = currentNode; + currentNode = currentNode.next; + } } /** @@ -152,94 +247,6 @@ export class HashTable { return this._stringHash(JSON.stringify(key)); } - /** - * 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} val - The parameter `val` 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, val: V): void { - const index = this._hash(key); - const newNode = new HashTableNode(key, val); - - 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.val = val; - 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.val; - } - 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 | null = null; - - while (currentNode) { - if (currentNode.key === key) { - if (prevNode) { - prevNode.next = currentNode.next; - } else { - this._buckets[index] = currentNode.next; - } - this._size--; - currentNode.next = null; // Release memory - return; - } - prevNode = currentNode; - currentNode = currentNode.next; - } - } - /** * 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. @@ -270,8 +277,4 @@ export class HashTable { this._buckets = newBuckets; this._capacity = newCapacity; } - - get size(): number { - return this._size; - } } diff --git a/src/data-structures/heap/heap.ts b/src/data-structures/heap/heap.ts index 55bbbf1..177b1e7 100644 --- a/src/data-structures/heap/heap.ts +++ b/src/data-structures/heap/heap.ts @@ -15,6 +15,34 @@ export class Heap { this.comparator = comparator; } + /** + * Get the size (number of elements) of the heap. + */ + get size(): number { + return this.nodes.length; + } + + /** + * Get the last element in the heap, which is not necessarily a leaf node. + * @returns The last element or undefined if the heap is empty. + */ + get leaf(): E | undefined { + return this.nodes[this.size - 1] ?? undefined; + } + + /** + * Static method that creates a binary heap from an array of nodes and a comparison function. + * @param nodes + * @param comparator - Comparison function. + * @returns A new Heap instance. + */ + static heapify(nodes: E[], comparator: Comparator): Heap { + const binaryHeap = new Heap(comparator); + binaryHeap.nodes = [...nodes]; + binaryHeap.fix(); // Fix heap properties + return binaryHeap; + } + /** * Insert an element into the heap and maintain the heap properties. * @param element - The element to be inserted. @@ -59,57 +87,6 @@ export class Heap { return this.poll(); } - /** - * Float operation to maintain heap properties after adding an element. - * @param index - The index of the newly added element. - */ - protected bubbleUp(index: number): void { - const element = this.nodes[index]; - while (index > 0) { - const parentIndex = Math.floor((index - 1) / 2); - const parent = this.nodes[parentIndex]; - if (this.comparator(element, parent) < 0) { - this.nodes[index] = parent; - this.nodes[parentIndex] = element; - index = parentIndex; - } else { - break; - } - } - } - - /** - * Sinking operation to maintain heap properties after removing the top element. - * @param index - The index from which to start sinking. - */ - protected sinkDown(index: number): void { - const leftChildIndex = 2 * index + 1; - const rightChildIndex = 2 * index + 2; - const length = this.nodes.length; - let targetIndex = index; - - if (leftChildIndex < length && this.comparator(this.nodes[leftChildIndex], this.nodes[targetIndex]) < 0) { - targetIndex = leftChildIndex; - } - if (rightChildIndex < length && this.comparator(this.nodes[rightChildIndex], this.nodes[targetIndex]) < 0) { - targetIndex = rightChildIndex; - } - - if (targetIndex !== index) { - const temp = this.nodes[index]; - this.nodes[index] = this.nodes[targetIndex]; - this.nodes[targetIndex] = temp; - this.sinkDown(targetIndex); - } - } - - /** - * Fix the entire heap to maintain heap properties. - */ - protected fix() { - for (let i = Math.floor(this.size / 2); i >= 0; i--) this.sinkDown(i); - } - /** * Peek at the top element of the heap without removing it. * @returns The top element or undefined if the heap is empty. @@ -121,21 +98,6 @@ export class Heap { return this.nodes[0]; } - /** - * Get the size (number of elements) of the heap. - */ - get size(): number { - return this.nodes.length; - } - - /** - * Get the last element in the heap, which is not necessarily a leaf node. - * @returns The last element or undefined if the heap is empty. - */ - get leaf(): E | undefined { - return this.nodes[this.size - 1] ?? undefined; - } - /** * Check if the heap is empty. * @returns True if the heap is empty, otherwise false. @@ -238,16 +200,54 @@ export class Heap { } /** - * Static method that creates a binary heap from an array of nodes and a comparison function. - * @param nodes - * @param comparator - Comparison function. - * @returns A new Heap instance. + * Float operation to maintain heap properties after adding an element. + * @param index - The index of the newly added element. */ - static heapify(nodes: E[], comparator: Comparator): Heap { - const binaryHeap = new Heap(comparator); - binaryHeap.nodes = [...nodes]; - binaryHeap.fix(); // Fix heap properties - return binaryHeap; + protected bubbleUp(index: number): void { + const element = this.nodes[index]; + while (index > 0) { + const parentIndex = Math.floor((index - 1) / 2); + const parent = this.nodes[parentIndex]; + if (this.comparator(element, parent) < 0) { + this.nodes[index] = parent; + this.nodes[parentIndex] = element; + index = parentIndex; + } else { + break; + } + } + } + + /** + * Sinking operation to maintain heap properties after removing the top element. + * @param index - The index from which to start sinking. + */ + protected sinkDown(index: number): void { + const leftChildIndex = 2 * index + 1; + const rightChildIndex = 2 * index + 2; + const length = this.nodes.length; + let targetIndex = index; + + if (leftChildIndex < length && this.comparator(this.nodes[leftChildIndex], this.nodes[targetIndex]) < 0) { + targetIndex = leftChildIndex; + } + if (rightChildIndex < length && this.comparator(this.nodes[rightChildIndex], this.nodes[targetIndex]) < 0) { + targetIndex = rightChildIndex; + } + + if (targetIndex !== index) { + const temp = this.nodes[index]; + this.nodes[index] = this.nodes[targetIndex]; + this.nodes[targetIndex] = temp; + this.sinkDown(targetIndex); + } + } + + /** + * Fix the entire heap to maintain heap properties. + */ + protected fix() { + for (let i = Math.floor(this.size / 2); i >= 0; i--) this.sinkDown(i); } } @@ -259,6 +259,7 @@ export class FibonacciHeapNode { child?: FibonacciHeapNode; parent?: FibonacciHeapNode; marked: boolean; + constructor(element: E, degree = 0) { this.element = element; this.degree = degree; @@ -268,8 +269,8 @@ export class FibonacciHeapNode { export class FibonacciHeap { root?: FibonacciHeapNode; - protected min?: FibonacciHeapNode; size: number = 0; + protected min?: FibonacciHeapNode; protected readonly comparator: Comparator; constructor(comparator?: Comparator) { @@ -281,18 +282,6 @@ export class FibonacciHeap { } } - /** - * Default comparator function used by the heap. - * @param {E} a - * @param {E} b - * @protected - */ - protected defaultComparator(a: E, b: E): number { - if (a < b) return -1; - if (a > b) return 1; - return 0; - } - /** * Get the size (number of elements) of the heap. * @returns {number} The size of the heap. Returns 0 if the heap is empty. Returns -1 if the heap is invalid. @@ -303,30 +292,6 @@ export class FibonacciHeap { this.size = 0; } - /** - * Create a new node. - * @param element - * @protected - */ - protected createNode(element: E): FibonacciHeapNode { - return new FibonacciHeapNode(element); - } - - /** - * Merge the given node with the root list. - * @param node - The node to be merged. - */ - protected mergeWithRoot(node: FibonacciHeapNode): void { - if (!this.root) { - this.root = node; - } else { - node.right = this.root.right; - node.left = this.root; - this.root.right!.left = node; - this.root.right = node; - } - } - /** * O(1) time operation. * Insert an element into the heap and maintain the heap properties. @@ -394,18 +359,6 @@ export class FibonacciHeap { return nodes; } - /** - * O(log n) time operation. - * Remove and return the top element (smallest or largest element) from the heap. - * @param node - The node to be removed. - * @protected - */ - protected removeFromRoot(node: FibonacciHeapNode): void { - if (this.root === node) this.root = node.right; - if (node.left) node.left.right = node.right; - if (node.right) node.right.left = node.left; - } - /** * O(log n) time operation. * Remove and return the top element (smallest or largest element) from the heap. @@ -423,63 +376,6 @@ export class FibonacciHeap { } } - /** - * O(log n) time operation. - * Remove and return the top element (smallest or largest element) from the heap. - * @param y - * @param x - * @protected - */ - protected link(y: FibonacciHeapNode, x: FibonacciHeapNode): void { - this.removeFromRoot(y); - y.left = y; - y.right = y; - this.mergeWithChild(x, y); - x.degree++; - y.parent = x; - } - - /** - * O(log n) time operation. - * Remove and return the top element (smallest or largest element) from the heap. - * @protected - */ - protected consolidate(): void { - const A: (FibonacciHeapNode | undefined)[] = new Array(this.size); - const nodes = this.consumeLinkedList(this.root); - let x: FibonacciHeapNode | undefined, - y: FibonacciHeapNode | undefined, - d: number, - t: FibonacciHeapNode | undefined; - - for (const node of nodes) { - x = node; - d = x.degree; - - while (A[d]) { - y = A[d] as FibonacciHeapNode; - - if (this.comparator(x.element, y.element) > 0) { - t = x; - x = y; - y = t; - } - - this.link(y, x); - A[d] = undefined; - d++; - } - - A[d] = x; - } - - for (let i = 0; i < this.size; i++) { - if (A[i] && this.comparator(A[i]!.element, this.min!.element) <= 0) { - this.min = A[i]!; - } - } - } - /** * O(log n) time operation. * Remove and return the top element (smallest or largest element) from the heap. @@ -557,4 +453,109 @@ export class FibonacciHeap { // Clear the heap that was merged heapToMerge.clear(); } + + /** + * Default comparator function used by the heap. + * @param {E} a + * @param {E} b + * @protected + */ + protected defaultComparator(a: E, b: E): number { + if (a < b) return -1; + if (a > b) return 1; + return 0; + } + + /** + * Create a new node. + * @param element + * @protected + */ + protected createNode(element: E): FibonacciHeapNode { + return new FibonacciHeapNode(element); + } + + /** + * Merge the given node with the root list. + * @param node - The node to be merged. + */ + protected mergeWithRoot(node: FibonacciHeapNode): void { + if (!this.root) { + this.root = node; + } else { + node.right = this.root.right; + node.left = this.root; + this.root.right!.left = node; + this.root.right = node; + } + } + + /** + * O(log n) time operation. + * Remove and return the top element (smallest or largest element) from the heap. + * @param node - The node to be removed. + * @protected + */ + protected removeFromRoot(node: FibonacciHeapNode): void { + if (this.root === node) this.root = node.right; + if (node.left) node.left.right = node.right; + if (node.right) node.right.left = node.left; + } + + /** + * O(log n) time operation. + * Remove and return the top element (smallest or largest element) from the heap. + * @param y + * @param x + * @protected + */ + protected link(y: FibonacciHeapNode, x: FibonacciHeapNode): void { + this.removeFromRoot(y); + y.left = y; + y.right = y; + this.mergeWithChild(x, y); + x.degree++; + y.parent = x; + } + + /** + * O(log n) time operation. + * Remove and return the top element (smallest or largest element) from the heap. + * @protected + */ + protected consolidate(): void { + const A: (FibonacciHeapNode | undefined)[] = new Array(this.size); + const nodes = this.consumeLinkedList(this.root); + let x: FibonacciHeapNode | undefined, + y: FibonacciHeapNode | undefined, + d: number, + t: FibonacciHeapNode | undefined; + + for (const node of nodes) { + x = node; + d = x.degree; + + while (A[d]) { + y = A[d] as FibonacciHeapNode; + + if (this.comparator(x.element, y.element) > 0) { + t = x; + x = y; + y = t; + } + + this.link(y, x); + A[d] = undefined; + d++; + } + + A[d] = x; + } + + for (let i = 0; i < this.size; i++) { + if (A[i] && this.comparator(A[i]!.element, this.min!.element) <= 0) { + this.min = A[i]!; + } + } + } } diff --git a/src/data-structures/linked-list/doubly-linked-list.ts b/src/data-structures/linked-list/doubly-linked-list.ts index 58e917d..cbd69d5 100644 --- a/src/data-structures/linked-list/doubly-linked-list.ts +++ b/src/data-structures/linked-list/doubly-linked-list.ts @@ -84,6 +84,10 @@ export class DoublyLinkedList { return this._length; } + get size(): number { + return this.length; + } + /** * The `fromArray` function creates a new instance of a DoublyLinkedList and populates it with the elements from the * given array. @@ -222,10 +226,6 @@ export class DoublyLinkedList { return this.tail?.val; } - get size(): number { - return this.length; - } - /** * The `getAt` function returns the value at a specified index in a linked list, or null if the index is out of bounds. * @param {number} index - The index parameter is a number that represents the position of the element we want to diff --git a/src/data-structures/linked-list/skip-linked-list.ts b/src/data-structures/linked-list/skip-linked-list.ts index 23778eb..59842ae 100644 --- a/src/data-structures/linked-list/skip-linked-list.ts +++ b/src/data-structures/linked-list/skip-linked-list.ts @@ -19,39 +19,6 @@ export class SkipListNode { } export class SkipList { - get probability(): number { - return this._probability; - } - - set probability(value: number) { - this._probability = value; - } - get maxLevel(): number { - return this._maxLevel; - } - - set maxLevel(value: number) { - this._maxLevel = value; - } - get level(): number { - return this._level; - } - - set level(value: number) { - this._level = value; - } - get head(): SkipListNode { - return this._head; - } - - set head(value: SkipListNode) { - this._head = value; - } - private _head: SkipListNode; - private _level: number; - private _maxLevel: number; - private _probability: number; - /** * 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 @@ -66,16 +33,44 @@ export class SkipList { this._probability = probability; } - /** - * The function "randomLevel" generates a random level based on a given probability and maximum level. - * @returns the level, which is a number. - */ - private randomLevel(): number { - let level = 1; - while (Math.random() < this.probability && level < this.maxLevel) { - level++; - } - return level; + private _head: SkipListNode; + + get head(): SkipListNode { + return this._head; + } + + set head(value: SkipListNode) { + this._head = value; + } + + private _level: number; + + get level(): number { + return this._level; + } + + set level(value: number) { + this._level = value; + } + + private _maxLevel: number; + + get maxLevel(): number { + return this._maxLevel; + } + + set maxLevel(value: number) { + this._maxLevel = value; + } + + private _probability: number; + + get probability(): number { + return this._probability; + } + + set probability(value: number) { + this._probability = value; } /** @@ -163,4 +158,16 @@ export class SkipList { return false; } + + /** + * The function "randomLevel" generates a random level based on a given probability and maximum level. + * @returns the level, which is a number. + */ + private randomLevel(): number { + let level = 1; + while (Math.random() < this.probability && level < this.maxLevel) { + level++; + } + return level; + } } diff --git a/src/data-structures/matrix/matrix2d.ts b/src/data-structures/matrix/matrix2d.ts index 0914d48..f6cfd72 100644 --- a/src/data-structures/matrix/matrix2d.ts +++ b/src/data-structures/matrix/matrix2d.ts @@ -58,16 +58,6 @@ export class Matrix2D { return this._matrix; } - /** - * The function "toVector" returns a new Vector2D object with the values from the first and second elements of the - * _matrix array. - * @returns A new instance of the Vector2D class is being returned. The values of the returned vector are taken from - * the first column of the matrix. - */ - toVector(): Vector2D { - return new Vector2D(this._matrix[0][0], this._matrix[1][0]); - } - /** * The function takes two 2D matrices as input and returns their sum as a new 2D matrix. * @param {Matrix2D} matrix1 - Matrix2D - The first matrix to be added. @@ -208,6 +198,16 @@ export class Matrix2D { [0, 0, vector.w] ]); } + + /** + * The function "toVector" returns a new Vector2D object with the values from the first and second elements of the + * _matrix array. + * @returns A new instance of the Vector2D class is being returned. The values of the returned vector are taken from + * the first column of the matrix. + */ + toVector(): Vector2D { + return new Vector2D(this._matrix[0][0], this._matrix[1][0]); + } } export default Matrix2D; diff --git a/src/data-structures/trie/trie.ts b/src/data-structures/trie/trie.ts index 83f71c7..d5ba4c8 100644 --- a/src/data-structures/trie/trie.ts +++ b/src/data-structures/trie/trie.ts @@ -52,6 +52,8 @@ export class TrieNode { * Trie represents a Trie data structure. It provides basic Trie operations and additional methods. */ export class Trie { + private readonly _caseSensitive: boolean; + constructor(words?: string[], caseSensitive = true) { this._root = new TrieNode(''); this._caseSensitive = caseSensitive; @@ -72,8 +74,6 @@ export class Trie { this._root = v; } - private readonly _caseSensitive: boolean; - /** * Add a word to the Trie structure. * @param {string} word - The word to add. @@ -110,13 +110,6 @@ export class Trie { return cur.isEnd; } - private _caseProcess(str: string) { - if (!this._caseSensitive) { - str = str.toLowerCase(); // Convert str to lowercase if case-insensitive - } - return str; - } - /** * Remove a word from the Trie structure. * @param{string} word - The word to delete. @@ -282,5 +275,12 @@ export class Trie { return words; } + private _caseProcess(str: string) { + if (!this._caseSensitive) { + str = str.toLowerCase(); // Convert str to lowercase if case-insensitive + } + return str; + } + // --- end additional methods --- } diff --git a/src/types/helpers.ts b/src/types/helpers.ts index 35c570b..ca84f77 100644 --- a/src/types/helpers.ts +++ b/src/types/helpers.ts @@ -6,4 +6,8 @@ export type MapCallback = (node: N) => any; export type MapCallbackReturn = ReturnType>; -export enum CP {lt = 'lt', eq = 'eq', gt = 'gt'} +export enum CP { + lt = 'lt', + eq = 'eq', + gt = 'gt' +} diff --git a/test/unit/data-structures/binary-tree/binary-index-tree.test.ts b/test/unit/data-structures/binary-tree/binary-index-tree.test.ts index 1e43598..a11a93e 100644 --- a/test/unit/data-structures/binary-tree/binary-index-tree.test.ts +++ b/test/unit/data-structures/binary-tree/binary-index-tree.test.ts @@ -1,7 +1,7 @@ import {BinaryIndexedTree} from '../../../../src'; import {isDebugTest} from '../../../config'; -const isDebug = isDebugTest; +// const isDebug = isDebugTest; describe('BinaryIndexedTree simple', () => { let bit: BinaryIndexedTree; From b7dd86dad2d6736b5b88236708390b32fd7a8046 Mon Sep 17 00:00:00 2001 From: Revone Date: Wed, 25 Oct 2023 11:26:30 +0800 Subject: [PATCH 19/46] [project] remove unnecessary self dependency --- package-lock.json | 17 +++-------------- package.json | 5 +---- 2 files changed, 4 insertions(+), 18 deletions(-) diff --git a/package-lock.json b/package-lock.json index b57f885..cce46cb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,9 +8,6 @@ "name": "data-structure-typed", "version": "1.38.1", "license": "MIT", - "dependencies": { - "data-structure-typed": "^1.37.5" - }, "devDependencies": { "@types/benchmark": "^2.1.3", "@types/jest": "^29.5.5", @@ -3027,14 +3024,6 @@ "node": ">= 8" } }, - "node_modules/data-structure-typed": { - "version": "1.38.0", - "resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.38.0.tgz", - "integrity": "sha512-KXYXlyQm7k09Gp4hhsneMOL1bLEPse6Kv3qeE6CU78jidJEh8SY66K9auAUio1mpkjbKTCqjf7q3Ep4pXkhB2w==", - "dependencies": { - "data-structure-typed": "^1.37.5" - } - }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -3215,9 +3204,9 @@ "dev": true }, "node_modules/electron-to-chromium": { - "version": "1.4.565", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.565.tgz", - "integrity": "sha512-XbMoT6yIvg2xzcbs5hCADi0dXBh4//En3oFXmtPX+jiyyiCTiM9DGFT2SLottjpEs9Z8Mh8SqahbR96MaHfuSg==", + "version": "1.4.566", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.566.tgz", + "integrity": "sha512-mv+fAy27uOmTVlUULy15U3DVJ+jg+8iyKH1bpwboCRhtDC69GKf1PPTZvEIhCyDr81RFqfxZJYrbgp933a1vtg==", "dev": true }, "node_modules/emittery": { diff --git a/package.json b/package.json index f8753bb..28fe003 100644 --- a/package.json +++ b/package.json @@ -226,8 +226,5 @@ "tarjan", "Tarjan", "Tarjan's" - ], - "dependencies": { - "data-structure-typed": "^1.37.5" - } + ] } From e45854d3f488045408ab7a934ff48ca983e0f001 Mon Sep 17 00:00:00 2001 From: Revone Date: Wed, 25 Oct 2023 15:51:50 +0800 Subject: [PATCH 20/46] [project] Optimize the build configuration to be compatible with both earlier and later versions of Node.js. Switch to using tsup for UMD module output. Format code using an IDE. --- package-lock.json | 1072 +++++++++++++---- package.json | 31 +- src/data-structures/binary-tree/avl-tree.ts | 2 +- .../binary-tree/binary-indexed-tree.ts | 2 +- .../binary-tree/binary-tree.ts | 4 +- .../binary-tree/tree-multiset.ts | 3 +- src/data-structures/graph/abstract-graph.ts | 21 +- src/data-structures/graph/directed-graph.ts | 3 +- src/data-structures/graph/undirected-graph.ts | 9 +- src/data-structures/hash/hash-map.ts | 2 +- src/data-structures/hash/tree-map.ts | 3 +- src/data-structures/hash/tree-set.ts | 3 +- .../linked-list/singly-linked-list.ts | 2 +- src/data-structures/matrix/matrix.ts | 2 +- src/data-structures/matrix/vector2d.ts | 3 +- src/data-structures/queue/deque.ts | 9 +- src/data-structures/queue/queue.ts | 2 +- src/types/data-structures/matrix/navigator.ts | 2 +- src/types/utils/utils.ts | 2 +- src/types/utils/validate-type.ts | 4 +- test/integration/bst.test.ts | 2 +- test/integration/index.html | 3 +- .../binary-tree/avl-tree.test.ts | 2 +- .../binary-tree/binary-index-tree.test.ts | 3 +- .../data-structures/binary-tree/bst.test.ts | 6 +- .../binary-tree/overall.test.ts | 2 +- .../binary-tree/tree-multiset.test.ts | 2 +- .../data-structures/hash/hash-table.test.ts | 2 +- test/unit/data-structures/heap/heap.test.ts | 4 +- .../linked-list/doubly-linked-list.test.ts | 2 +- .../linked-list/singly-linked-list.test.ts | 4 +- .../data-structures/matrix/navigator.test.ts | 2 +- .../priority-queue/max-priority-queue.test.ts | 4 +- test/unit/data-structures/queue/deque.test.ts | 2 +- test/unit/data-structures/queue/queue.test.ts | 2 +- test/utils/big-o.ts | 2 +- tsconfig-base.json | 27 + tsconfig-cjs.json | 9 + tsconfig.json | 33 +- tsconfig.prod.json | 26 - tsup.config.js | 11 + 41 files changed, 968 insertions(+), 363 deletions(-) create mode 100644 tsconfig-base.json create mode 100644 tsconfig-cjs.json delete mode 100644 tsconfig.prod.json create mode 100644 tsup.config.js diff --git a/package-lock.json b/package-lock.json index cce46cb..a705cb4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,10 +31,9 @@ "prettier": "^3.0.3", "ts-jest": "^29.1.1", "ts-loader": "^9.4.4", + "tsup": "^7.2.0", "typedoc": "^0.25.1", - "typescript": "^5.2.2", - "webpack": "^5.88.2", - "webpack-cli": "^5.1.4" + "typescript": "^5.2.2" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -678,13 +677,356 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, - "node_modules/@discoveryjs/json-ext": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", - "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "node_modules/@esbuild/android-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", + "cpu": [ + "arm" + ], "dev": true, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=10.0.0" + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" } }, "node_modules/@eslint-community/eslint-utils": { @@ -1466,6 +1808,7 @@ "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", "dev": true, + "peer": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.0", "@jridgewell/trace-mapping": "^0.3.9" @@ -1598,6 +1941,7 @@ "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.6.tgz", "integrity": "sha512-P6bY56TVmX8y9J87jHNgQh43h6VVU+6H7oN7hgvivV81K2XY8qJZ5vqPy/HdUoVIelii2kChYVzQanlswPWVFw==", "dev": true, + "peer": true, "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -1608,6 +1952,7 @@ "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.6.tgz", "integrity": "sha512-zfM4ipmxVKWdxtDaJ3MP3pBurDXOCoyjvlpE3u6Qzrmw4BPbfm4/ambIeTk/r/J0iq/+2/xp0Fmt+gFvXJY2PQ==", "dev": true, + "peer": true, "dependencies": { "@types/eslint": "*", "@types/estree": "*" @@ -1617,7 +1962,8 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.3.tgz", "integrity": "sha512-CS2rOaoQ/eAgAfcTfq6amKG7bsN+EMcgGY4FAFQdvSj2y1ixvOZTUA9mOtCai7E1SYu283XNw7urKK30nP3wkQ==", - "dev": true + "dev": true, + "peer": true }, "node_modules/@types/graceful-fs": { "version": "4.1.8", @@ -1910,6 +2256,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", "dev": true, + "peer": true, "dependencies": { "@webassemblyjs/helper-numbers": "1.11.6", "@webassemblyjs/helper-wasm-bytecode": "1.11.6" @@ -1919,25 +2266,29 @@ "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", - "dev": true + "dev": true, + "peer": true }, "node_modules/@webassemblyjs/helper-api-error": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", - "dev": true + "dev": true, + "peer": true }, "node_modules/@webassemblyjs/helper-buffer": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==", - "dev": true + "dev": true, + "peer": true }, "node_modules/@webassemblyjs/helper-numbers": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", "dev": true, + "peer": true, "dependencies": { "@webassemblyjs/floating-point-hex-parser": "1.11.6", "@webassemblyjs/helper-api-error": "1.11.6", @@ -1948,13 +2299,15 @@ "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", - "dev": true + "dev": true, + "peer": true }, "node_modules/@webassemblyjs/helper-wasm-section": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", "dev": true, + "peer": true, "dependencies": { "@webassemblyjs/ast": "1.11.6", "@webassemblyjs/helper-buffer": "1.11.6", @@ -1967,6 +2320,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", "dev": true, + "peer": true, "dependencies": { "@xtuc/ieee754": "^1.2.0" } @@ -1976,6 +2330,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", "dev": true, + "peer": true, "dependencies": { "@xtuc/long": "4.2.2" } @@ -1984,13 +2339,15 @@ "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", - "dev": true + "dev": true, + "peer": true }, "node_modules/@webassemblyjs/wasm-edit": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", "dev": true, + "peer": true, "dependencies": { "@webassemblyjs/ast": "1.11.6", "@webassemblyjs/helper-buffer": "1.11.6", @@ -2007,6 +2364,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", "dev": true, + "peer": true, "dependencies": { "@webassemblyjs/ast": "1.11.6", "@webassemblyjs/helper-wasm-bytecode": "1.11.6", @@ -2020,6 +2378,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", "dev": true, + "peer": true, "dependencies": { "@webassemblyjs/ast": "1.11.6", "@webassemblyjs/helper-buffer": "1.11.6", @@ -2032,6 +2391,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", "dev": true, + "peer": true, "dependencies": { "@webassemblyjs/ast": "1.11.6", "@webassemblyjs/helper-api-error": "1.11.6", @@ -2046,66 +2406,25 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", "dev": true, + "peer": true, "dependencies": { "@webassemblyjs/ast": "1.11.6", "@xtuc/long": "4.2.2" } }, - "node_modules/@webpack-cli/configtest": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", - "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", - "dev": true, - "engines": { - "node": ">=14.15.0" - }, - "peerDependencies": { - "webpack": "5.x.x", - "webpack-cli": "5.x.x" - } - }, - "node_modules/@webpack-cli/info": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", - "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", - "dev": true, - "engines": { - "node": ">=14.15.0" - }, - "peerDependencies": { - "webpack": "5.x.x", - "webpack-cli": "5.x.x" - } - }, - "node_modules/@webpack-cli/serve": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", - "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", - "dev": true, - "engines": { - "node": ">=14.15.0" - }, - "peerDependencies": { - "webpack": "5.x.x", - "webpack-cli": "5.x.x" - }, - "peerDependenciesMeta": { - "webpack-dev-server": { - "optional": true - } - } - }, "node_modules/@xtuc/ieee754": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true + "dev": true, + "peer": true }, "node_modules/@xtuc/long": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true + "dev": true, + "peer": true }, "node_modules/acorn": { "version": "8.10.0", @@ -2124,6 +2443,7 @@ "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", "dev": true, + "peer": true, "peerDependencies": { "acorn": "^8" } @@ -2234,6 +2554,12 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true + }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", @@ -2588,6 +2914,15 @@ "platform": "^1.3.3" } }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/binary-tree-typed": { "version": "1.38.1", "resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.38.1.tgz", @@ -2681,6 +3016,30 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, + "node_modules/bundle-require": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/bundle-require/-/bundle-require-4.0.2.tgz", + "integrity": "sha512-jwzPOChofl67PSTW2SGubV9HBQAhhR2i6nskiOThauo9dzwDUgOWQScFVaJkjEfYX+UXiD+LEx8EblQMc2wIag==", + "dev": true, + "dependencies": { + "load-tsconfig": "^0.2.3" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "peerDependencies": { + "esbuild": ">=0.17" + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/call-bind": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", @@ -2714,9 +3073,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001553", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001553.tgz", - "integrity": "sha512-N0ttd6TrFfuqKNi+pMgWJTb9qrdJu4JSpgPFLe/lrD19ugC6fZgF0pUewRowDwzdDnb9V41mFcdlYgl/PyKf4A==", + "version": "1.0.30001554", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001554.tgz", + "integrity": "sha512-A2E3U//MBwbJVzebddm1YfNp7Nud5Ip+IPn4BozBmn4KqVX7AvluoIDFWjsv5OkGnKUXQVmMSoMKLa3ScCblcQ==", "dev": true, "funding": [ { @@ -2754,11 +3113,51 @@ "node": ">=10" } }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/chrome-trace-event": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", "dev": true, + "peer": true, "engines": { "node": ">=6.0" } @@ -2868,20 +3267,6 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -2913,12 +3298,6 @@ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, - "node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true - }, "node_modules/commander": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", @@ -3240,18 +3619,6 @@ "node": ">=10.13.0" } }, - "node_modules/envinfo": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.10.0.tgz", - "integrity": "sha512-ZtUjZO6l5mwTHvc1L9+1q5p/R3wTopcfqMW8r5t8SJSKqeVI/LtajORwRFEKpEFuekjD0VBjwu1HMxL4UalIRw==", - "dev": true, - "bin": { - "envinfo": "dist/cli.js" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -3318,7 +3685,8 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.1.tgz", "integrity": "sha512-JUFAyicQV9mXc3YRxPnDlrfBKpqt6hUYzz9/boprUJHs4e4KVr3XwOF70doO6gwXUor6EWZJAyWAfKki84t20Q==", - "dev": true + "dev": true, + "peer": true }, "node_modules/es-set-tostringtag": { "version": "2.0.2", @@ -3360,6 +3728,43 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/esbuild": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" + } + }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -3768,6 +4173,7 @@ "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "dev": true, + "peer": true, "engines": { "node": ">=0.8.x" } @@ -3866,15 +4272,6 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, - "node_modules/fastest-levenshtein": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", - "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", - "dev": true, - "engines": { - "node": ">= 4.9.1" - } - }, "node_modules/fastq": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", @@ -3961,15 +4358,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "bin": { - "flat": "cli.js" - } - }, "node_modules/flat-cache": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.1.tgz", @@ -4173,7 +4561,8 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true + "dev": true, + "peer": true }, "node_modules/global-dirs": { "version": "3.0.1", @@ -4532,6 +4921,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/is-boolean-object": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", @@ -4687,18 +5088,6 @@ "node": ">=8" } }, - "node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -4820,15 +5209,6 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/istanbul-badges-readme": { "version": "1.8.5", "resolved": "https://registry.npmjs.org/istanbul-badges-readme/-/istanbul-badges-readme-1.8.5.tgz", @@ -6145,6 +6525,15 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/joycon": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", + "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -6226,15 +6615,6 @@ "json-buffer": "3.0.1" } }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/kleur": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", @@ -6266,17 +6646,36 @@ "node": ">= 0.8.0" } }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "dev": true }, + "node_modules/load-tsconfig": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/load-tsconfig/-/load-tsconfig-0.2.5.tgz", + "integrity": "sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, "node_modules/loader-runner": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", "dev": true, + "peer": true, "engines": { "node": ">=6.11.5" } @@ -6314,6 +6713,12 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "node_modules/lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==", + "dev": true + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -6404,6 +6809,7 @@ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "dev": true, + "peer": true, "engines": { "node": ">= 0.6" } @@ -6413,6 +6819,7 @@ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, + "peer": true, "dependencies": { "mime-db": "1.52.0" }, @@ -6456,6 +6863,17 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -6521,6 +6939,15 @@ "node": ">=8" } }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/object-inspect": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", @@ -6864,6 +7291,35 @@ "integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==", "dev": true }, + "node_modules/postcss-load-config": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.1.tgz", + "integrity": "sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==", + "dev": true, + "dependencies": { + "lilconfig": "^2.0.5", + "yaml": "^2.1.1" + }, + "engines": { + "node": ">= 14" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -6965,6 +7421,7 @@ "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "dev": true, + "peer": true, "dependencies": { "safe-buffer": "^5.1.0" } @@ -6975,6 +7432,18 @@ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "dev": true }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, "node_modules/rechoir": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", @@ -7121,6 +7590,22 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rollup": { + "version": "3.29.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", + "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", + "dev": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -7180,7 +7665,8 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "peer": true }, "node_modules/safe-regex": { "version": "2.1.1", @@ -7210,6 +7696,7 @@ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", "dev": true, + "peer": true, "dependencies": { "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", @@ -7228,6 +7715,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -7244,6 +7732,7 @@ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", "dev": true, + "peer": true, "peerDependencies": { "ajv": "^6.9.1" } @@ -7252,7 +7741,8 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "dev": true, + "peer": true }, "node_modules/semver": { "version": "7.5.4", @@ -7304,6 +7794,7 @@ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", "dev": true, + "peer": true, "dependencies": { "randombytes": "^2.1.0" } @@ -7337,18 +7828,6 @@ "node": ">= 0.4" } }, - "node_modules/shallow-clone": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -7607,6 +8086,57 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/sucrase": { + "version": "3.34.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.34.0.tgz", + "integrity": "sha512-70/LQEZ07TEcxiU2dz51FKaE6hCTWC6vr7FOk3Gr0U60C3shtAN+H+BFr9XlYe5xqf3RA8nrc+VIwzCfnxuXJw==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "7.1.6", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sucrase/node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/sucrase/node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -7651,6 +8181,7 @@ "resolved": "https://registry.npmjs.org/terser/-/terser-5.22.0.tgz", "integrity": "sha512-hHZVLgRA2z4NWcN6aS5rQDc+7Dcy58HOf2zbYwmFcQ+ua3h6eEFf5lIDKTzbWwlazPyOZsFQO8V80/IjVNExEw==", "dev": true, + "peer": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", @@ -7669,6 +8200,7 @@ "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz", "integrity": "sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==", "dev": true, + "peer": true, "dependencies": { "@jridgewell/trace-mapping": "^0.3.17", "jest-worker": "^27.4.5", @@ -7703,6 +8235,7 @@ "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", "dev": true, + "peer": true, "dependencies": { "@types/node": "*", "merge-stream": "^2.0.0", @@ -7717,6 +8250,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, + "peer": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -7731,13 +8265,15 @@ "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true + "dev": true, + "peer": true }, "node_modules/terser/node_modules/source-map-support": { "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dev": true, + "peer": true, "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -7763,6 +8299,27 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -7796,6 +8353,15 @@ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", "dev": true }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "bin": { + "tree-kill": "cli.js" + } + }, "node_modules/ts-api-utils": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", @@ -7808,6 +8374,12 @@ "typescript": ">=4.2.0" } }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true + }, "node_modules/ts-jest": { "version": "29.1.1", "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.1.tgz", @@ -8048,6 +8620,98 @@ "node": ">=4" } }, + "node_modules/tsup": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/tsup/-/tsup-7.2.0.tgz", + "integrity": "sha512-vDHlczXbgUvY3rWvqFEbSqmC1L7woozbzngMqTtL2PGBODTtWlRwGDDawhvWzr5c1QjKe4OAKqJGfE1xeXUvtQ==", + "dev": true, + "dependencies": { + "bundle-require": "^4.0.0", + "cac": "^6.7.12", + "chokidar": "^3.5.1", + "debug": "^4.3.1", + "esbuild": "^0.18.2", + "execa": "^5.0.0", + "globby": "^11.0.3", + "joycon": "^3.0.1", + "postcss-load-config": "^4.0.1", + "resolve-from": "^5.0.0", + "rollup": "^3.2.5", + "source-map": "0.8.0-beta.0", + "sucrase": "^3.20.3", + "tree-kill": "^1.2.2" + }, + "bin": { + "tsup": "dist/cli-default.js", + "tsup-node": "dist/cli-node.js" + }, + "engines": { + "node": ">=16.14" + }, + "peerDependencies": { + "@swc/core": "^1", + "postcss": "^8.4.12", + "typescript": ">=4.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "postcss": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/tsup/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/tsup/node_modules/source-map": { + "version": "0.8.0-beta.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", + "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", + "dev": true, + "dependencies": { + "whatwg-url": "^7.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tsup/node_modules/tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/tsup/node_modules/webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", + "dev": true + }, + "node_modules/tsup/node_modules/whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "dev": true, + "dependencies": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -8317,6 +8981,7 @@ "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", "dev": true, + "peer": true, "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" @@ -8348,6 +9013,7 @@ "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.89.0.tgz", "integrity": "sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw==", "dev": true, + "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.3", "@types/estree": "^1.0.0", @@ -8390,79 +9056,12 @@ } } }, - "node_modules/webpack-cli": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", - "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", - "dev": true, - "dependencies": { - "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^2.1.1", - "@webpack-cli/info": "^2.0.2", - "@webpack-cli/serve": "^2.0.5", - "colorette": "^2.0.14", - "commander": "^10.0.1", - "cross-spawn": "^7.0.3", - "envinfo": "^7.7.3", - "fastest-levenshtein": "^1.0.12", - "import-local": "^3.0.2", - "interpret": "^3.1.1", - "rechoir": "^0.8.0", - "webpack-merge": "^5.7.3" - }, - "bin": { - "webpack-cli": "bin/cli.js" - }, - "engines": { - "node": ">=14.15.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "5.x.x" - }, - "peerDependenciesMeta": { - "@webpack-cli/generators": { - "optional": true - }, - "webpack-bundle-analyzer": { - "optional": true - }, - "webpack-dev-server": { - "optional": true - } - } - }, - "node_modules/webpack-cli/node_modules/commander": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", - "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", - "dev": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/webpack-merge": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", - "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", - "dev": true, - "dependencies": { - "clone-deep": "^4.0.1", - "flat": "^5.0.2", - "wildcard": "^2.0.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, "node_modules/webpack-sources": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", "dev": true, + "peer": true, "engines": { "node": ">=10.13.0" } @@ -8472,6 +9071,7 @@ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, + "peer": true, "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" @@ -8485,6 +9085,7 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true, + "peer": true, "engines": { "node": ">=4.0" } @@ -8549,12 +9150,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/wildcard": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", - "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", - "dev": true - }, "node_modules/wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", @@ -8651,6 +9246,15 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true }, + "node_modules/yaml": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.3.tgz", + "integrity": "sha512-zw0VAJxgeZ6+++/su5AFoqBbZbrEakwu+X0M5HmcwUiBL7AzcuPKjj5we4xfQLp78LkEMpD0cOnUhmgOVy3KdQ==", + "dev": true, + "engines": { + "node": ">= 14" + } + }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", diff --git a/package.json b/package.json index 28fe003..3d07be4 100644 --- a/package.json +++ b/package.json @@ -1,21 +1,23 @@ { "name": "data-structure-typed", - "version": "1.38.1", + "version": "1.38.2", "description": "Data Structures of Javascript & TypeScript. Binary Tree, BST, Graph, Heap, Priority Queue, Linked List, Queue, Deque, Stack, AVL Tree, Tree Multiset, Trie, Directed Graph, Undirected Graph, Singly Linked List, Doubly Linked List, Max Heap, Max Priority Queue, Min Heap, Min Priority Queue.", - "main": "dist/index.js", - "module": "lib/index.js", - "types": "lib/index.d.ts", - "source": "src/index.ts", - "umd:main": "umd/bundle.min.js", + "main": "dist/cjs/index.js", + "module": "dist/mjs/index.js", + "types": "dist/mjs/index.d.ts", + "umd:main": "dist/umd/index.global.js", "exports": { - "import": "./lib/index.js", - "require": "./dist/index.js" + ".": { + "import": "./dist/mjs/index.js", + "require": "./dist/cjs/index.js", + "types": "./dist/mjs/index.d.ts" + } }, "scripts": { - "build": "npm run build:es6 && npm run build:commonjs && npm run build:umd && npm run build:docs", - "build:es6": "rm -rf lib && tsc", - "build:commonjs": "rm -rf dist && tsc --project tsconfig.prod.json", - "build:umd": "webpack", + "build": "npm run build:mjs && npm run build:cjs && npm run build:umd && npm run build:docs", + "build:mjs": "rm -rf dist/mjs && tsc -p tsconfig.json", + "build:cjs": "rm -rf dist/cjs && tsc -p tsconfig-cjs.json", + "build:umd": "tsup", "build:docs": "typedoc --out docs ./src", "check": "tsc --noEmit", "lint:src": "eslint --fix 'src/**/*.{js,ts}'", @@ -75,10 +77,9 @@ "prettier": "^3.0.3", "ts-jest": "^29.1.1", "ts-loader": "^9.4.4", + "tsup": "^7.2.0", "typedoc": "^0.25.1", - "typescript": "^5.2.2", - "webpack": "^5.88.2", - "webpack-cli": "^5.1.4" + "typescript": "^5.2.2" }, "keywords": [ "data", diff --git a/src/data-structures/binary-tree/avl-tree.ts b/src/data-structures/binary-tree/avl-tree.ts index 1b1c88d..704e907 100644 --- a/src/data-structures/binary-tree/avl-tree.ts +++ b/src/data-structures/binary-tree/avl-tree.ts @@ -152,7 +152,7 @@ export class AVLTree = AVLTreeNode> extends B // 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-indexed-tree.ts b/src/data-structures/binary-tree/binary-indexed-tree.ts index da9dae0..467e918 100644 --- a/src/data-structures/binary-tree/binary-indexed-tree.ts +++ b/src/data-structures/binary-tree/binary-indexed-tree.ts @@ -17,7 +17,7 @@ export class BinaryIndexedTree { * @param - - `frequency`: The default frequency value. It is optional and has a default * value of 0. */ - constructor({frequency = 0, max}: {frequency?: number; max: number}) { + constructor({frequency = 0, max}: { frequency?: number; max: number }) { this._freq = frequency; this._max = max; this._freqMap = {0: 0}; diff --git a/src/data-structures/binary-tree/binary-tree.ts b/src/data-structures/binary-tree/binary-tree.ts index a82f8a3..9a38bc1 100644 --- a/src/data-structures/binary-tree/binary-tree.ts +++ b/src/data-structures/binary-tree/binary-tree.ts @@ -407,7 +407,7 @@ export class BinaryTree = BinaryTreeNode> return -1; } - const stack: {node: N; depth: number}[] = [{node: beginRoot, depth: 0}]; + const stack: { node: N; depth: number }[] = [{node: beginRoot, depth: 0}]; let maxHeight = 0; while (stack.length > 0) { @@ -842,7 +842,7 @@ export class BinaryTree = BinaryTreeNode> _traverse(beginRoot); } else { // 0: visit, 1: print - const stack: {opt: 0 | 1; node: N | null | undefined}[] = [{opt: 0, node: beginRoot}]; + const stack: { opt: 0 | 1; node: N | null | undefined }[] = [{opt: 0, node: beginRoot}]; while (stack.length > 0) { const cur = stack.pop(); diff --git a/src/data-structures/binary-tree/tree-multiset.ts b/src/data-structures/binary-tree/tree-multiset.ts index a36826b..40b9ddc 100644 --- a/src/data-structures/binary-tree/tree-multiset.ts +++ b/src/data-structures/binary-tree/tree-multiset.ts @@ -37,8 +37,7 @@ export class TreeMultisetNode< */ export class TreeMultiset = TreeMultisetNode> extends AVLTree - implements IBinaryTree -{ + implements IBinaryTree { /** * The constructor function for a TreeMultiset class in TypeScript, which extends another class and sets an option to * merge duplicated values. diff --git a/src/data-structures/graph/abstract-graph.ts b/src/data-structures/graph/abstract-graph.ts index e820f6b..f93a731 100644 --- a/src/data-structures/graph/abstract-graph.ts +++ b/src/data-structures/graph/abstract-graph.ts @@ -105,8 +105,7 @@ export abstract class AbstractEdge { export abstract class AbstractGraph< V extends AbstractVertex = AbstractVertex, E extends AbstractEdge = AbstractEdge -> implements IGraph -{ +> implements IGraph { private _vertices: Map = new Map(); get vertices(): Map { @@ -554,14 +553,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); @@ -623,7 +622,7 @@ export abstract class AbstractGraph< if (vertexOrKey instanceof AbstractVertex) distMap.set(vertexOrKey, Infinity); } - const heap = new PriorityQueue<{key: number; val: V}>((a, b) => a.key - b.key); + const heap = new PriorityQueue<{ key: number; val: V }>((a, b) => a.key - b.key); heap.add({key: 0, val: srcVertex}); distMap.set(srcVertex, 0); @@ -852,7 +851,7 @@ export abstract class AbstractGraph< * `predecessor` property is a 2D array of vertices (or `null`) representing the predecessor vertices in the shortest * path between vertices in the */ - floyd(): {costs: number[][]; predecessor: (V | null)[][]} { + floyd(): { costs: number[][]; predecessor: (V | null)[][] } { const idAndVertices = [...this._vertices]; const n = idAndVertices.length; diff --git a/src/data-structures/graph/directed-graph.ts b/src/data-structures/graph/directed-graph.ts index 438ea75..f30a841 100644 --- a/src/data-structures/graph/directed-graph.ts +++ b/src/data-structures/graph/directed-graph.ts @@ -64,8 +64,7 @@ export class DirectedEdge extends AbstractEdge { export class DirectedGraph = DirectedVertex, E 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 b962047..a7a81ff 100644 --- a/src/data-structures/graph/undirected-graph.ts +++ b/src/data-structures/graph/undirected-graph.ts @@ -51,12 +51,11 @@ export class UndirectedEdge extends AbstractEdge { } export class UndirectedGraph< - V extends UndirectedVertex = UndirectedVertex, - E extends UndirectedEdge = UndirectedEdge - > + V extends UndirectedVertex = UndirectedVertex, + E extends UndirectedEdge = UndirectedEdge +> extends AbstractGraph - implements IGraph -{ + implements IGraph { /** * The constructor initializes a new Map object to store edges. */ diff --git a/src/data-structures/hash/hash-map.ts b/src/data-structures/hash/hash-map.ts index f3a5213..5231237 100644 --- a/src/data-structures/hash/hash-map.ts +++ b/src/data-structures/hash/hash-map.ts @@ -157,7 +157,7 @@ export class HashMap { } } - *entries(): IterableIterator<[K, V]> { + * entries(): IterableIterator<[K, V]> { for (const bucket of this.table) { if (bucket) { for (const [key, value] of bucket) { diff --git a/src/data-structures/hash/tree-map.ts b/src/data-structures/hash/tree-map.ts index fe86360..a6d743d 100644 --- a/src/data-structures/hash/tree-map.ts +++ b/src/data-structures/hash/tree-map.ts @@ -1 +1,2 @@ -export class TreeMap {} +export class TreeMap { +} diff --git a/src/data-structures/hash/tree-set.ts b/src/data-structures/hash/tree-set.ts index 591aeda..65f14db 100644 --- a/src/data-structures/hash/tree-set.ts +++ b/src/data-structures/hash/tree-set.ts @@ -1 +1,2 @@ -export class TreeSet {} +export class TreeSet { +} diff --git a/src/data-structures/linked-list/singly-linked-list.ts b/src/data-structures/linked-list/singly-linked-list.ts index 2eaca25..b39925f 100644 --- a/src/data-structures/linked-list/singly-linked-list.ts +++ b/src/data-structures/linked-list/singly-linked-list.ts @@ -490,7 +490,7 @@ export class SinglyLinkedList { return count; } - *[Symbol.iterator]() { + * [Symbol.iterator]() { let current = this.head; while (current) { diff --git a/src/data-structures/matrix/matrix.ts b/src/data-structures/matrix/matrix.ts index 8f27617..7e8ae4b 100644 --- a/src/data-structures/matrix/matrix.ts +++ b/src/data-structures/matrix/matrix.ts @@ -14,7 +14,7 @@ export class MatrixNTI2D { * given initial value or 0 if not provided. * @param options - An object containing the following properties: */ - constructor(options: {row: number; col: number; initialVal?: V}) { + constructor(options: { row: number; col: number; initialVal?: V }) { const {row, col, initialVal} = options; this._matrix = new Array(row).fill(undefined).map(() => new Array(col).fill(initialVal || 0)); } diff --git a/src/data-structures/matrix/vector2d.ts b/src/data-structures/matrix/vector2d.ts index 1b215ca..e8e4074 100644 --- a/src/data-structures/matrix/vector2d.ts +++ b/src/data-structures/matrix/vector2d.ts @@ -10,7 +10,8 @@ export class Vector2D { public x: number = 0, public y: number = 0, public w: number = 1 // needed for matrix multiplication - ) {} + ) { + } /** * The function checks if the x and y values of a point are both zero. diff --git a/src/data-structures/queue/deque.ts b/src/data-structures/queue/deque.ts index 3290ab1..9faabda 100644 --- a/src/data-structures/queue/deque.ts +++ b/src/data-structures/queue/deque.ts @@ -9,7 +9,8 @@ import {DoublyLinkedList} from '../linked-list'; // O(n) time complexity of obtaining the value // O(1) time complexity of adding at the beginning and the end -export class Deque extends DoublyLinkedList {} +export class Deque extends DoublyLinkedList { +} // O(1) time complexity of obtaining the value // O(n) time complexity of adding at the beginning and the end @@ -19,9 +20,9 @@ export class ObjectDeque { if (capacity !== undefined) this._capacity = capacity; } - private _nodes: {[key: number]: E} = {}; + private _nodes: { [key: number]: E } = {}; - get nodes(): {[p: number]: E} { + get nodes(): { [p: number]: E } { return this._nodes; } @@ -156,7 +157,7 @@ export class ObjectDeque { return this._size <= 0; } - protected _seNodes(value: {[p: number]: E}) { + protected _seNodes(value: { [p: number]: E }) { this._nodes = value; } diff --git a/src/data-structures/queue/queue.ts b/src/data-structures/queue/queue.ts index 4549b31..d11dd92 100644 --- a/src/data-structures/queue/queue.ts +++ b/src/data-structures/queue/queue.ts @@ -183,7 +183,7 @@ export class Queue { return new Queue(this.nodes.slice(this.offset)); } - *[Symbol.iterator]() { + * [Symbol.iterator]() { for (const item of this.nodes) { yield item; } diff --git a/src/types/data-structures/matrix/navigator.ts b/src/types/data-structures/matrix/navigator.ts index 9d8b9a9..34eddd9 100644 --- a/src/types/data-structures/matrix/navigator.ts +++ b/src/types/data-structures/matrix/navigator.ts @@ -1,6 +1,6 @@ export type Direction = 'up' | 'right' | 'down' | 'left'; -export type Turning = {[key in Direction]: Direction}; +export type Turning = { [key in Direction]: Direction }; export type NavigatorParams = { matrix: T[][]; diff --git a/src/types/utils/utils.ts b/src/types/utils/utils.ts index f4d26c4..1f3a505 100644 --- a/src/types/utils/utils.ts +++ b/src/types/utils/utils.ts @@ -1,5 +1,5 @@ export type ToThunkFn = () => ReturnType; -export type Thunk = () => ReturnType & {__THUNK__: symbol}; +export type Thunk = () => ReturnType & { __THUNK__: symbol }; export type TrlFn = (...args: any[]) => any; export type TrlAsyncFn = (...args: any[]) => any; diff --git a/src/types/utils/validate-type.ts b/src/types/utils/validate-type.ts index ac9ff28..3ebf451 100644 --- a/src/types/utils/validate-type.ts +++ b/src/types/utils/validate-type.ts @@ -1,6 +1,6 @@ -export type KeyValueObject = {[key: string]: any}; +export type KeyValueObject = { [key: string]: any }; -export type KeyValueObjectWithKey = {[key: string]: any; key: string | number | symbol}; +export type KeyValueObjectWithKey = { [key: string]: any; key: string | number | symbol }; export type NonNumberNonObjectButDefined = string | boolean | symbol | null; diff --git a/test/integration/bst.test.ts b/test/integration/bst.test.ts index a482a37..425af06 100644 --- a/test/integration/bst.test.ts +++ b/test/integration/bst.test.ts @@ -183,7 +183,7 @@ describe('Individual package BST operations test', () => { }); it('should perform various operations on a Binary Search Tree with object values', () => { - const objBST = new BST>(); + const objBST = new BST>(); expect(objBST).toBeInstanceOf(BST); objBST.add(11, {key: 11, keyA: 11}); objBST.add(3, {key: 3, keyA: 3}); diff --git a/test/integration/index.html b/test/integration/index.html index 5df808f..ab70fa2 100644 --- a/test/integration/index.html +++ b/test/integration/index.html @@ -40,8 +40,7 @@ console.log(performance.now() - startTime); - } - catch (e) { + } catch (e) { console.error(e); } diff --git a/test/unit/data-structures/binary-tree/avl-tree.test.ts b/test/unit/data-structures/binary-tree/avl-tree.test.ts index e606423..aa0ebee 100644 --- a/test/unit/data-structures/binary-tree/avl-tree.test.ts +++ b/test/unit/data-structures/binary-tree/avl-tree.test.ts @@ -1,4 +1,4 @@ -import {AVLTree, CP, AVLTreeNode} from '../../../../src'; +import {AVLTree, AVLTreeNode, CP} from '../../../../src'; describe('AVL Tree Test', () => { it('should perform various operations on a AVL Tree', () => { diff --git a/test/unit/data-structures/binary-tree/binary-index-tree.test.ts b/test/unit/data-structures/binary-tree/binary-index-tree.test.ts index a11a93e..dbbf71e 100644 --- a/test/unit/data-structures/binary-tree/binary-index-tree.test.ts +++ b/test/unit/data-structures/binary-tree/binary-index-tree.test.ts @@ -1,5 +1,5 @@ import {BinaryIndexedTree} from '../../../../src'; -import {isDebugTest} from '../../../config'; +// import {isDebugTest} from '../../../config'; // const isDebug = isDebugTest; @@ -251,6 +251,7 @@ describe('BinaryIndexedTree additional tests', () => { expect(bit.lowerBound(200)).toBe(10); }); }); + function loopUpperBoundTests(bit: BinaryIndexedTree, values: number[]) { for (const value of values) { const index = bit.upperBound(value); diff --git a/test/unit/data-structures/binary-tree/bst.test.ts b/test/unit/data-structures/binary-tree/bst.test.ts index 9683af9..6290d07 100644 --- a/test/unit/data-structures/binary-tree/bst.test.ts +++ b/test/unit/data-structures/binary-tree/bst.test.ts @@ -189,7 +189,7 @@ describe('BST operations test', () => { }); it('should perform various operations on a Binary Search Tree with object values', () => { - const objBST = new BST>(); + const objBST = new BST>(); expect(objBST).toBeInstanceOf(BST); objBST.add(11, {key: 11, keyA: 11}); objBST.add(3, {key: 3, keyA: 3}); @@ -260,7 +260,7 @@ describe('BST operations test', () => { objBST.perfectlyBalance(); expect(objBST.isPerfectlyBalanced()).toBe(true); - const bfsNodesAfterBalanced: BSTNode<{key: number; keyA: number}>[] = []; + const bfsNodesAfterBalanced: BSTNode<{ key: number; keyA: number }>[] = []; objBST.bfs(node => bfsNodesAfterBalanced.push(node)); expect(bfsNodesAfterBalanced[0].key).toBe(8); expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16); @@ -385,7 +385,7 @@ describe('BST operations test', () => { expect(bfsIDs[1]).toBe(12); expect(bfsIDs[2]).toBe(16); - const bfsNodes: BSTNode<{key: number; keyA: number}>[] = []; + const bfsNodes: BSTNode<{ key: number; keyA: number }>[] = []; objBST.bfs(node => bfsNodes.push(node)); expect(bfsNodes[0].key).toBe(2); expect(bfsNodes[1].key).toBe(12); diff --git a/test/unit/data-structures/binary-tree/overall.test.ts b/test/unit/data-structures/binary-tree/overall.test.ts index 5325180..d12b9ad 100644 --- a/test/unit/data-structures/binary-tree/overall.test.ts +++ b/test/unit/data-structures/binary-tree/overall.test.ts @@ -29,7 +29,7 @@ describe('Overall BinaryTree Test', () => { bfsIDs[0] === 11; // true expect(bfsIDs[0]).toBe(11); - const objBST = new BST>(); + const objBST = new BST>(); objBST.add(11, {key: 11, keyA: 11}); objBST.add(3, {key: 3, keyA: 3}); diff --git a/test/unit/data-structures/binary-tree/tree-multiset.test.ts b/test/unit/data-structures/binary-tree/tree-multiset.test.ts index 6812143..997c28d 100644 --- a/test/unit/data-structures/binary-tree/tree-multiset.test.ts +++ b/test/unit/data-structures/binary-tree/tree-multiset.test.ts @@ -206,7 +206,7 @@ describe('TreeMultiset operations test', () => { }); it('should perform various operations on a Binary Search Tree with object values', () => { - const objTreeMultiset = new TreeMultiset>(); + const objTreeMultiset = new TreeMultiset>(); expect(objTreeMultiset).toBeInstanceOf(TreeMultiset); objTreeMultiset.add(11, {key: 11, keyA: 11}); objTreeMultiset.add(3, {key: 3, keyA: 3}); diff --git a/test/unit/data-structures/hash/hash-table.test.ts b/test/unit/data-structures/hash/hash-table.test.ts index bf77d1a..b4ff78e 100644 --- a/test/unit/data-structures/hash/hash-table.test.ts +++ b/test/unit/data-structures/hash/hash-table.test.ts @@ -1,4 +1,4 @@ -import {HashTableNode, HashTable} from '../../../../src'; +import {HashTable, HashTableNode} from '../../../../src'; describe('HashNode', () => { it('should create a HashNode with key and value', () => { diff --git a/test/unit/data-structures/heap/heap.test.ts b/test/unit/data-structures/heap/heap.test.ts index 8745402..14c54cf 100644 --- a/test/unit/data-structures/heap/heap.test.ts +++ b/test/unit/data-structures/heap/heap.test.ts @@ -22,7 +22,7 @@ describe('Heap Operation Test', () => { }); it('should object heap work well', function () { - const minHeap = new MinHeap<{a: string; key: number}>((a, b) => a.key - b.key); + const minHeap = new MinHeap<{ a: string; key: number }>((a, b) => a.key - b.key); minHeap.add({key: 1, a: 'a1'}); minHeap.add({key: 6, a: 'a6'}); minHeap.add({key: 2, a: 'a2'}); @@ -37,7 +37,7 @@ describe('Heap Operation Test', () => { i++; } - const maxHeap = new MaxHeap<{key: number; a: string}>((a, b) => b.key - a.key); + const maxHeap = new MaxHeap<{ key: number; a: string }>((a, b) => b.key - a.key); maxHeap.add({key: 1, a: 'a1'}); maxHeap.add({key: 6, a: 'a6'}); maxHeap.add({key: 5, a: 'a5'}); diff --git a/test/unit/data-structures/linked-list/doubly-linked-list.test.ts b/test/unit/data-structures/linked-list/doubly-linked-list.test.ts index eab2ad5..0838337 100644 --- a/test/unit/data-structures/linked-list/doubly-linked-list.test.ts +++ b/test/unit/data-structures/linked-list/doubly-linked-list.test.ts @@ -3,7 +3,7 @@ import {bigO, magnitude} from '../../../utils'; describe('DoublyLinkedList Operation Test', () => { let list: DoublyLinkedList; - let objectList: DoublyLinkedList<{keyA: number}>; + let objectList: DoublyLinkedList<{ keyA: number }>; beforeEach(() => { list = new DoublyLinkedList(); diff --git a/test/unit/data-structures/linked-list/singly-linked-list.test.ts b/test/unit/data-structures/linked-list/singly-linked-list.test.ts index 74a3de8..092b2e6 100644 --- a/test/unit/data-structures/linked-list/singly-linked-list.test.ts +++ b/test/unit/data-structures/linked-list/singly-linked-list.test.ts @@ -3,10 +3,10 @@ import {bigO, magnitude} from '../../../utils'; describe('SinglyLinkedList Operation Test', () => { let list: SinglyLinkedList; - let objectList: SinglyLinkedList<{keyA: number}>; + let objectList: SinglyLinkedList<{ keyA: number }>; beforeEach(() => { list = new SinglyLinkedList(); - objectList = new SinglyLinkedList<{keyA: number}>(); + objectList = new SinglyLinkedList<{ keyA: number }>(); }); describe('push', () => { diff --git a/test/unit/data-structures/matrix/navigator.test.ts b/test/unit/data-structures/matrix/navigator.test.ts index 9d4595b..f8d3eda 100644 --- a/test/unit/data-structures/matrix/navigator.test.ts +++ b/test/unit/data-structures/matrix/navigator.test.ts @@ -1,4 +1,4 @@ -import {Character, NavigatorParams, Turning, Navigator} from '../../../../src'; +import {Character, Navigator, NavigatorParams, Turning} from '../../../../src'; const exampleMatrix: number[][] = [ [0, 0, 0, 0], diff --git a/test/unit/data-structures/priority-queue/max-priority-queue.test.ts b/test/unit/data-structures/priority-queue/max-priority-queue.test.ts index f8a63bc..f389309 100644 --- a/test/unit/data-structures/priority-queue/max-priority-queue.test.ts +++ b/test/unit/data-structures/priority-queue/max-priority-queue.test.ts @@ -17,7 +17,7 @@ describe('MaxPriorityQueue Operation Test', () => { }); it('should add elements and maintain heap property in a object MaxPriorityQueue', () => { - const priorityQueue = new MaxPriorityQueue<{keyA: number}>((a, b) => b.keyA - a.keyA); + const priorityQueue = new MaxPriorityQueue<{ keyA: number }>((a, b) => b.keyA - a.keyA); priorityQueue.refill([{keyA: 5}, {keyA: 3}, {keyA: 1}]); priorityQueue.add({keyA: 7}); @@ -64,7 +64,7 @@ describe('MaxPriorityQueue Operation Test', () => { it('should correctly heapify an object array', () => { const nodes = [{keyA: 5}, {keyA: 3}, {keyA: 7}, {keyA: 1}]; - const maxPQ = MaxPriorityQueue.heapify<{keyA: number}>(nodes, (a, b) => b.keyA - a.keyA); + const maxPQ = MaxPriorityQueue.heapify<{ keyA: number }>(nodes, (a, b) => b.keyA - a.keyA); expect(maxPQ.poll()?.keyA).toBe(7); expect(maxPQ.poll()?.keyA).toBe(5); diff --git a/test/unit/data-structures/queue/deque.test.ts b/test/unit/data-structures/queue/deque.test.ts index 9e4b275..ca41a61 100644 --- a/test/unit/data-structures/queue/deque.test.ts +++ b/test/unit/data-structures/queue/deque.test.ts @@ -1,4 +1,4 @@ -import {Deque, ArrayDeque, ObjectDeque} from '../../../../src'; +import {ArrayDeque, Deque, ObjectDeque} from '../../../../src'; import {bigO} from '../../../utils'; describe('Deque Tests', () => { diff --git a/test/unit/data-structures/queue/queue.test.ts b/test/unit/data-structures/queue/queue.test.ts index 7f35cab..93d15bc 100644 --- a/test/unit/data-structures/queue/queue.test.ts +++ b/test/unit/data-structures/queue/queue.test.ts @@ -1,4 +1,4 @@ -import {Queue, LinkedListQueue} from '../../../../src'; +import {LinkedListQueue, Queue} from '../../../../src'; import {bigO, magnitude} from '../../../utils'; describe('Queue Operation Test', () => { diff --git a/test/utils/big-o.ts b/test/utils/big-o.ts index 43d7eca..cc9fc86 100644 --- a/test/utils/big-o.ts +++ b/test/utils/big-o.ts @@ -26,7 +26,7 @@ export const bigO = { function findPotentialN(input: any): number { let longestArray: any[] = []; - let mostProperties: {[key: string]: any} = {}; + let mostProperties: { [key: string]: any } = {}; function recurse(obj: any) { if (Array.isArray(obj)) { diff --git a/tsconfig-base.json b/tsconfig-base.json new file mode 100644 index 0000000..a10109a --- /dev/null +++ b/tsconfig-base.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "allowJs": true, + "allowSyntheticDefaultImports": true, + "baseUrl": "src", + "declaration": true, + "esModuleInterop": true, + "inlineSourceMap": false, + "lib": ["esnext"], + "listEmittedFiles": false, + "listFiles": false, + "moduleResolution": "node", + "noFallthroughCasesInSwitch": true, + "pretty": true, + "resolveJsonModule": true, + "rootDir": "src", + "skipLibCheck": true, + "strict": true, + "traceResolution": false, + "types": ["node", "jest"] + }, + "compileOnSave": false, + "exclude": ["node_modules", "dist"], + "include": [ + "./src/**/*.ts", // Include your .ts files + ] +} diff --git a/tsconfig-cjs.json b/tsconfig-cjs.json new file mode 100644 index 0000000..9141737 --- /dev/null +++ b/tsconfig-cjs.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig-base.json", + "compilerOptions": { + "module": "CommonJS", + "outDir": "dist/cjs", + "target": "ES2015", + "sourceMap": true + } +} diff --git a/tsconfig.json b/tsconfig.json index c9eddd2..65bb75a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,30 +1,9 @@ { + "extends": "./tsconfig-base.json", "compilerOptions": { - "target": "ES6", - "module": "ES6", - "outDir": "./lib", - "declaration": true, - "lib": [ - "ESNext" - ], - "strict": true, - "esModuleInterop": true, - "moduleResolution": "node", - "skipLibCheck": true, - "downlevelIteration": true, - "removeComments": false, - "experimentalDecorators": true, - "typeRoots": [ - "node_modules/@types" - ] - }, - - "include": ["src/**/*.ts", "src/**/*.js"], - "exclude": [ - "node_modules", - "lib", - "dist", - "umd" - ] + "module": "NodeNext", + "moduleResolution": "NodeNext", + "outDir": "dist/mjs", + "target": "ESNext" + } } - diff --git a/tsconfig.prod.json b/tsconfig.prod.json deleted file mode 100644 index f71489b..0000000 --- a/tsconfig.prod.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "target": "ES6", - "module": "CommonJS", - "outDir": "./dist", - "declaration": true, - "lib": [ - "ESNext" - ], - "sourceMap": true, - "strict": true, - "downlevelIteration": true, - "removeComments": false, - "typeRoots": [ - "node_modules/@types" - ] - }, - "include": ["src/**/*.ts", "src/**/*.js"], - "exclude": [ - "node_modules", - "lib", - "dist", - "umd" - ] -} - diff --git a/tsup.config.js b/tsup.config.js new file mode 100644 index 0000000..dd1aa90 --- /dev/null +++ b/tsup.config.js @@ -0,0 +1,11 @@ +export default [{ + entry: ['src/index.ts'], + format: ["iife"], + clean: true, + sourcemap: true, + minify: true, + outDir: 'dist/umd', + globalName: 'dataStructureTyped', + platform: "browser", + bundle: true +}]; From 8df45c5c52ff9e2f9874e06c8a0edf956f06bed0 Mon Sep 17 00:00:00 2001 From: Revone Date: Wed, 25 Oct 2023 21:09:11 +0800 Subject: [PATCH 21/46] [binary-tree] Dynamically infer traversal method return values based on callback function results. --- package-lock.json | 36 ++++++++-------- package.json | 8 ++-- src/data-structures/binary-tree/avl-tree.ts | 2 +- .../binary-tree/binary-indexed-tree.ts | 2 +- .../binary-tree/binary-tree.ts | 42 +++++++++---------- src/data-structures/binary-tree/bst.ts | 14 +++---- .../binary-tree/tree-multiset.ts | 3 +- src/data-structures/graph/abstract-graph.ts | 21 +++++----- src/data-structures/graph/directed-graph.ts | 3 +- src/data-structures/graph/undirected-graph.ts | 9 ++-- src/data-structures/hash/hash-map.ts | 2 +- src/data-structures/hash/tree-map.ts | 3 +- src/data-structures/hash/tree-set.ts | 3 +- .../linked-list/singly-linked-list.ts | 2 +- src/data-structures/matrix/matrix.ts | 2 +- src/data-structures/matrix/vector2d.ts | 3 +- src/data-structures/queue/deque.ts | 9 ++-- src/data-structures/queue/queue.ts | 2 +- .../binary-tree/binary-tree.ts | 3 +- src/types/data-structures/matrix/navigator.ts | 2 +- src/types/helpers.ts | 2 +- src/types/utils/utils.ts | 2 +- src/types/utils/validate-type.ts | 4 +- test/integration/bst.test.ts | 2 +- .../binary-tree/avl-tree.test.ts | 25 +++++++++-- .../binary-tree/binary-tree.test.ts | 21 +++++++++- .../data-structures/binary-tree/bst.test.ts | 6 +-- .../binary-tree/overall.test.ts | 2 +- .../binary-tree/tree-multiset.test.ts | 2 +- test/unit/data-structures/heap/heap.test.ts | 4 +- .../linked-list/doubly-linked-list.test.ts | 2 +- .../linked-list/singly-linked-list.test.ts | 4 +- .../priority-queue/max-priority-queue.test.ts | 4 +- test/utils/big-o.ts | 2 +- 34 files changed, 145 insertions(+), 108 deletions(-) diff --git a/package-lock.json b/package-lock.json index a705cb4..c4f24c4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "data-structure-typed", - "version": "1.38.1", + "version": "1.38.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "data-structure-typed", - "version": "1.38.1", + "version": "1.38.2", "license": "MIT", "devDependencies": { "@types/benchmark": "^2.1.3", @@ -15,17 +15,17 @@ "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", "auto-changelog": "^2.4.0", - "avl-tree-typed": "^1.38.1", + "avl-tree-typed": "^1.38.2", "benchmark": "^2.1.4", - "binary-tree-typed": "^1.38.1", - "bst-typed": "^1.38.1", + "binary-tree-typed": "^1.38.2", + "bst-typed": "^1.38.2", "dependency-cruiser": "^14.1.0", "eslint": "^8.50.0", "eslint-config-prettier": "^9.0.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.28.1", - "heap-typed": "^1.38.1", + "heap-typed": "^1.38.2", "istanbul-badges-readme": "^1.8.5", "jest": "^29.7.0", "prettier": "^3.0.3", @@ -2728,9 +2728,9 @@ } }, "node_modules/avl-tree-typed": { - "version": "1.38.1", - "resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.38.1.tgz", - "integrity": "sha512-owzl0/cOijCKDyL8RAR+8Q2ibtqA+datgKQEbs1qNpCvMgYBtaytIgwyR68jYD+u7QGTXWYdO288H6NiKI0eTA==", + "version": "1.38.2", + "resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.38.2.tgz", + "integrity": "sha512-2P1DPzdnTuvENa6bGA7vqglC+Ae8GndRSX4H5JeB4V5ZVoiWFpSDL2lO4kRJJYbceL+hemx4Ge/MriGYKgXIfQ==", "dev": true }, "node_modules/babel-jest": { @@ -2924,9 +2924,9 @@ } }, "node_modules/binary-tree-typed": { - "version": "1.38.1", - "resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.38.1.tgz", - "integrity": "sha512-h4dBfVSaqUPfpVRHI7ZWUv3BSFYF9VtzoRu5X2rIq4se89QX+1cQTirQ7bCG0mDLJ9A4GfmEVMvQvvmVhorBEQ==", + "version": "1.38.2", + "resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.38.2.tgz", + "integrity": "sha512-odemWypyURZVq3qdegpaQDFydmt3sZA3uLHbcav3bBbnPj9WuMSIbOeOs21Nrj/yJHk1GrmlFRbPjYrrDXfdaw==", "dev": true }, "node_modules/brace-expansion": { @@ -3005,9 +3005,9 @@ } }, "node_modules/bst-typed": { - "version": "1.38.1", - "resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.38.1.tgz", - "integrity": "sha512-jNBmdOaSAApSx5iYo5ijunp3rtATcTmNOVnRiasCqKzSYTLfCJiGqIoXkDYMIFWK7hlgbAsVJkzTLciKf4RjcQ==", + "version": "1.38.2", + "resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.38.2.tgz", + "integrity": "sha512-BcTSvIbi8m5kEqzlS++YYlg2IgKhuqsX1mu200BLGq4d327vsQq9hY8TneuL54N4KAr4McR2GqpkDaHXQ3eTbw==", "dev": true }, "node_modules/buffer-from": { @@ -4756,9 +4756,9 @@ } }, "node_modules/heap-typed": { - "version": "1.38.1", - "resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.38.1.tgz", - "integrity": "sha512-PvLlO5lSds9zOOX4GvVS2mgZfLk0f7Ev+++hYkGrlCqpcCGDsXVn+B0k/Jel0mkTXIK3zVkev2if7Cxsmk1pEQ==", + "version": "1.38.2", + "resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.38.2.tgz", + "integrity": "sha512-GVNHQlbQkuuZMpMBj8fvekI8ClHst3s8W1qozLragMLD/ndb+acumWCXeypR9gwgjDTneqOW6fAgpUMDDKOn9Q==", "dev": true }, "node_modules/html-escaper": { diff --git a/package.json b/package.json index 3d07be4..93cf47e 100644 --- a/package.json +++ b/package.json @@ -61,17 +61,17 @@ "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", "auto-changelog": "^2.4.0", - "avl-tree-typed": "^1.38.1", + "avl-tree-typed": "^1.38.2", "benchmark": "^2.1.4", - "binary-tree-typed": "^1.38.1", - "bst-typed": "^1.38.1", + "binary-tree-typed": "^1.38.2", + "bst-typed": "^1.38.2", "dependency-cruiser": "^14.1.0", "eslint": "^8.50.0", "eslint-config-prettier": "^9.0.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.28.1", - "heap-typed": "^1.38.1", + "heap-typed": "^1.38.2", "istanbul-badges-readme": "^1.8.5", "jest": "^29.7.0", "prettier": "^3.0.3", diff --git a/src/data-structures/binary-tree/avl-tree.ts b/src/data-structures/binary-tree/avl-tree.ts index 704e907..1b1c88d 100644 --- a/src/data-structures/binary-tree/avl-tree.ts +++ b/src/data-structures/binary-tree/avl-tree.ts @@ -152,7 +152,7 @@ export class AVLTree = AVLTreeNode> extends B // 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-indexed-tree.ts b/src/data-structures/binary-tree/binary-indexed-tree.ts index 467e918..da9dae0 100644 --- a/src/data-structures/binary-tree/binary-indexed-tree.ts +++ b/src/data-structures/binary-tree/binary-indexed-tree.ts @@ -17,7 +17,7 @@ export class BinaryIndexedTree { * @param - - `frequency`: The default frequency value. It is optional and has a default * value of 0. */ - constructor({frequency = 0, max}: { frequency?: number; max: number }) { + constructor({frequency = 0, max}: {frequency?: number; max: number}) { this._freq = frequency; this._max = max; this._freqMap = {0: 0}; diff --git a/src/data-structures/binary-tree/binary-tree.ts b/src/data-structures/binary-tree/binary-tree.ts index 9a38bc1..7b2ea5e 100644 --- a/src/data-structures/binary-tree/binary-tree.ts +++ b/src/data-structures/binary-tree/binary-tree.ts @@ -407,7 +407,7 @@ export class BinaryTree = BinaryTreeNode> return -1; } - const stack: { node: N; depth: number }[] = [{node: beginRoot, depth: 0}]; + const stack: {node: N; depth: number}[] = [{node: beginRoot, depth: 0}]; let maxHeight = 0; while (stack.length > 0) { @@ -512,9 +512,9 @@ export class BinaryTree = BinaryTreeNode> * traverse the binary tree. It can have two possible values: * @returns The function `getNodes` returns an array of nodes (`N[]`). */ - getNodes( + getNodes = MapCallback>( nodeProperty: BinaryTreeNodeKey | N, - callback: MapCallback = this._defaultCallbackByKey, + callback: C = this._defaultCallbackByKey as C, onlyOne = false, beginRoot: N | null = this.root, iterationType = this.iterationType @@ -570,9 +570,9 @@ export class BinaryTree = BinaryTreeNode> * performed when searching for nodes in the binary tree. It can have one of the following values: * @returns a boolean value. */ - has( + has = MapCallback>( nodeProperty: BinaryTreeNodeKey | N, - callback: MapCallback = this._defaultCallbackByKey, + callback: C = this._defaultCallbackByKey as C, beginRoot = this.root, iterationType = this.iterationType ): boolean { @@ -595,9 +595,9 @@ export class BinaryTree = BinaryTreeNode> * performed when searching for a node in the binary tree. It can have one of the following values: * @returns either the found node (of type N) or null if no node is found. */ - get( + get = MapCallback>( nodeProperty: BinaryTreeNodeKey | N, - callback: MapCallback = this._defaultCallbackByKey, + callback: C = this._defaultCallbackByKey as C, beginRoot = this.root, iterationType = this.iterationType ): N | null { @@ -761,11 +761,11 @@ export class BinaryTree = BinaryTreeNode> * performed on the binary tree. It can have two possible values: * @returns The function `subTreeTraverse` returns an array of `MapCallbackReturn`. */ - subTreeTraverse( - callback: MapCallback = this._defaultCallbackByKey, + subTreeTraverse = MapCallback>( + callback: C = this._defaultCallbackByKey as C, beginRoot: N | BinaryTreeNodeKey | null = this.root, iterationType = this.iterationType - ): MapCallbackReturn[] { + ): ReturnType[] { if (typeof beginRoot === 'number') beginRoot = this.get(beginRoot); const ans: MapCallbackReturn[] = []; @@ -808,12 +808,12 @@ export class BinaryTree = BinaryTreeNode> * iteration used in the depth-first search algorithm. It can have two possible values: * @returns The function `dfs` returns an array of `MapCallbackReturn` values. */ - dfs( - callback: MapCallback = this._defaultCallbackByKey, + dfs = MapCallback>( + callback: C = this._defaultCallbackByKey as C, pattern: DFSOrderPattern = 'in', beginRoot: N | null = this.root, iterationType: IterationType = IterationType.ITERATIVE - ): MapCallbackReturn[] { + ): ReturnType[] { if (!beginRoot) return []; const ans: MapCallbackReturn[] = []; if (iterationType === IterationType.RECURSIVE) { @@ -842,7 +842,7 @@ export class BinaryTree = BinaryTreeNode> _traverse(beginRoot); } else { // 0: visit, 1: print - const stack: { opt: 0 | 1; node: N | null | undefined }[] = [{opt: 0, node: beginRoot}]; + const stack: {opt: 0 | 1; node: N | null | undefined}[] = [{opt: 0, node: beginRoot}]; while (stack.length > 0) { const cur = stack.pop(); @@ -896,12 +896,12 @@ export class BinaryTree = BinaryTreeNode> * in the breadth-first search (BFS) algorithm. It can have two possible values: * @returns The function `bfs` returns an array of `BFSCallbackReturn[]`. */ - bfs( - callback: BFSCallback = this._defaultCallbackByKey, + bfs = BFSCallback>( + callback: C = this._defaultCallbackByKey as C, withLevel: boolean = false, beginRoot: N | null = this.root, iterationType = this.iterationType - ): BFSCallbackReturn[] { + ): ReturnType[] { if (!beginRoot) return []; const ans: BFSCallbackReturn[] = []; @@ -964,11 +964,11 @@ export class BinaryTree = BinaryTreeNode> * `beginRoot` is `null`, an empty array will be returned. * @returns The `morris` function returns an array of `MapCallbackReturn` values. */ - morris( - callback: MapCallback = this._defaultCallbackByKey, + morris = MapCallback>( + callback: C = this._defaultCallbackByKey as C, pattern: DFSOrderPattern = 'in', beginRoot: N | null = this.root - ): MapCallbackReturn[] { + ): ReturnType[] { if (beginRoot === null) return []; const ans: MapCallbackReturn[] = []; @@ -1078,7 +1078,7 @@ export class BinaryTree = BinaryTreeNode> * This is because the purpose of the Morris algorithm is to save space rather than permanently alter the tree's shape. */ - protected _defaultCallbackByKey: MapCallback = node => node.key; + protected _defaultCallbackByKey: (node: N) => number = node => node.key; /** * The function `_addTo` adds a new node to a binary tree if there is an available position. diff --git a/src/data-structures/binary-tree/bst.ts b/src/data-structures/binary-tree/bst.ts index b16ec02..0237476 100644 --- a/src/data-structures/binary-tree/bst.ts +++ b/src/data-structures/binary-tree/bst.ts @@ -238,9 +238,9 @@ export class BST = BSTNode> extends BinaryTree * @returns either the first node that matches the given nodeProperty and callback, or null if no * matching node is found. */ - override get( + override get = MapCallback>( nodeProperty: BinaryTreeNodeKey | N, - callback: MapCallback = this._defaultCallbackByKey, + callback: C = this._defaultCallbackByKey as C, beginRoot = this.root, iterationType = this.iterationType ): N | null { @@ -289,9 +289,9 @@ export class BST = BSTNode> extends BinaryTree * traverse the binary tree. It can have one of the following values: * @returns an array of nodes (N[]). */ - override getNodes( + override getNodes = MapCallback>( nodeProperty: BinaryTreeNodeKey | N, - callback: MapCallback = this._defaultCallbackByKey, + callback: C = this._defaultCallbackByKey as C, onlyOne = false, beginRoot: N | null = this.root, iterationType = this.iterationType @@ -363,12 +363,12 @@ export class BST = BSTNode> extends BinaryTree * done recursively or iteratively. It can have two possible values: * @returns The function `lesserOrGreaterTraverse` returns an array of `MapCallbackReturn`. */ - lesserOrGreaterTraverse( - callback: MapCallback = this._defaultCallbackByKey, + lesserOrGreaterTraverse = MapCallback>( + callback: C = this._defaultCallbackByKey as C, lesserOrGreater: CP = CP.lt, targetNode: N | BinaryTreeNodeKey | null = this.root, iterationType = this.iterationType - ): MapCallbackReturn { + ): ReturnType[] { if (typeof targetNode === 'number') targetNode = this.get(targetNode); const ans: MapCallbackReturn[] = []; if (!targetNode) return ans; diff --git a/src/data-structures/binary-tree/tree-multiset.ts b/src/data-structures/binary-tree/tree-multiset.ts index 40b9ddc..a36826b 100644 --- a/src/data-structures/binary-tree/tree-multiset.ts +++ b/src/data-structures/binary-tree/tree-multiset.ts @@ -37,7 +37,8 @@ export class TreeMultisetNode< */ export class TreeMultiset = TreeMultisetNode> extends AVLTree - implements IBinaryTree { + implements IBinaryTree +{ /** * The constructor function for a TreeMultiset class in TypeScript, which extends another class and sets an option to * merge duplicated values. diff --git a/src/data-structures/graph/abstract-graph.ts b/src/data-structures/graph/abstract-graph.ts index f93a731..e820f6b 100644 --- a/src/data-structures/graph/abstract-graph.ts +++ b/src/data-structures/graph/abstract-graph.ts @@ -105,7 +105,8 @@ export abstract class AbstractEdge { export abstract class AbstractGraph< V extends AbstractVertex = AbstractVertex, E extends AbstractEdge = AbstractEdge -> implements IGraph { +> implements IGraph +{ private _vertices: Map = new Map(); get vertices(): Map { @@ -553,14 +554,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); @@ -622,7 +623,7 @@ export abstract class AbstractGraph< if (vertexOrKey instanceof AbstractVertex) distMap.set(vertexOrKey, Infinity); } - const heap = new PriorityQueue<{ key: number; val: V }>((a, b) => a.key - b.key); + const heap = new PriorityQueue<{key: number; val: V}>((a, b) => a.key - b.key); heap.add({key: 0, val: srcVertex}); distMap.set(srcVertex, 0); @@ -851,7 +852,7 @@ export abstract class AbstractGraph< * `predecessor` property is a 2D array of vertices (or `null`) representing the predecessor vertices in the shortest * path between vertices in the */ - floyd(): { costs: number[][]; predecessor: (V | null)[][] } { + floyd(): {costs: number[][]; predecessor: (V | null)[][]} { const idAndVertices = [...this._vertices]; const n = idAndVertices.length; diff --git a/src/data-structures/graph/directed-graph.ts b/src/data-structures/graph/directed-graph.ts index f30a841..438ea75 100644 --- a/src/data-structures/graph/directed-graph.ts +++ b/src/data-structures/graph/directed-graph.ts @@ -64,7 +64,8 @@ export class DirectedEdge extends AbstractEdge { export class DirectedGraph = DirectedVertex, E 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 a7a81ff..b962047 100644 --- a/src/data-structures/graph/undirected-graph.ts +++ b/src/data-structures/graph/undirected-graph.ts @@ -51,11 +51,12 @@ export class UndirectedEdge extends AbstractEdge { } export class UndirectedGraph< - V extends UndirectedVertex = UndirectedVertex, - E extends UndirectedEdge = UndirectedEdge -> + V extends UndirectedVertex = UndirectedVertex, + E extends UndirectedEdge = UndirectedEdge + > extends AbstractGraph - implements IGraph { + implements IGraph +{ /** * The constructor initializes a new Map object to store edges. */ diff --git a/src/data-structures/hash/hash-map.ts b/src/data-structures/hash/hash-map.ts index 5231237..f3a5213 100644 --- a/src/data-structures/hash/hash-map.ts +++ b/src/data-structures/hash/hash-map.ts @@ -157,7 +157,7 @@ export class HashMap { } } - * entries(): IterableIterator<[K, V]> { + *entries(): IterableIterator<[K, V]> { for (const bucket of this.table) { if (bucket) { for (const [key, value] of bucket) { diff --git a/src/data-structures/hash/tree-map.ts b/src/data-structures/hash/tree-map.ts index a6d743d..fe86360 100644 --- a/src/data-structures/hash/tree-map.ts +++ b/src/data-structures/hash/tree-map.ts @@ -1,2 +1 @@ -export class TreeMap { -} +export class TreeMap {} diff --git a/src/data-structures/hash/tree-set.ts b/src/data-structures/hash/tree-set.ts index 65f14db..591aeda 100644 --- a/src/data-structures/hash/tree-set.ts +++ b/src/data-structures/hash/tree-set.ts @@ -1,2 +1 @@ -export class TreeSet { -} +export class TreeSet {} diff --git a/src/data-structures/linked-list/singly-linked-list.ts b/src/data-structures/linked-list/singly-linked-list.ts index b39925f..2eaca25 100644 --- a/src/data-structures/linked-list/singly-linked-list.ts +++ b/src/data-structures/linked-list/singly-linked-list.ts @@ -490,7 +490,7 @@ export class SinglyLinkedList { return count; } - * [Symbol.iterator]() { + *[Symbol.iterator]() { let current = this.head; while (current) { diff --git a/src/data-structures/matrix/matrix.ts b/src/data-structures/matrix/matrix.ts index 7e8ae4b..8f27617 100644 --- a/src/data-structures/matrix/matrix.ts +++ b/src/data-structures/matrix/matrix.ts @@ -14,7 +14,7 @@ export class MatrixNTI2D { * given initial value or 0 if not provided. * @param options - An object containing the following properties: */ - constructor(options: { row: number; col: number; initialVal?: V }) { + constructor(options: {row: number; col: number; initialVal?: V}) { const {row, col, initialVal} = options; this._matrix = new Array(row).fill(undefined).map(() => new Array(col).fill(initialVal || 0)); } diff --git a/src/data-structures/matrix/vector2d.ts b/src/data-structures/matrix/vector2d.ts index e8e4074..1b215ca 100644 --- a/src/data-structures/matrix/vector2d.ts +++ b/src/data-structures/matrix/vector2d.ts @@ -10,8 +10,7 @@ export class Vector2D { public x: number = 0, public y: number = 0, public w: number = 1 // needed for matrix multiplication - ) { - } + ) {} /** * The function checks if the x and y values of a point are both zero. diff --git a/src/data-structures/queue/deque.ts b/src/data-structures/queue/deque.ts index 9faabda..3290ab1 100644 --- a/src/data-structures/queue/deque.ts +++ b/src/data-structures/queue/deque.ts @@ -9,8 +9,7 @@ import {DoublyLinkedList} from '../linked-list'; // O(n) time complexity of obtaining the value // O(1) time complexity of adding at the beginning and the end -export class Deque extends DoublyLinkedList { -} +export class Deque extends DoublyLinkedList {} // O(1) time complexity of obtaining the value // O(n) time complexity of adding at the beginning and the end @@ -20,9 +19,9 @@ export class ObjectDeque { if (capacity !== undefined) this._capacity = capacity; } - private _nodes: { [key: number]: E } = {}; + private _nodes: {[key: number]: E} = {}; - get nodes(): { [p: number]: E } { + get nodes(): {[p: number]: E} { return this._nodes; } @@ -157,7 +156,7 @@ export class ObjectDeque { return this._size <= 0; } - protected _seNodes(value: { [p: number]: E }) { + protected _seNodes(value: {[p: number]: E}) { this._nodes = value; } diff --git a/src/data-structures/queue/queue.ts b/src/data-structures/queue/queue.ts index d11dd92..4549b31 100644 --- a/src/data-structures/queue/queue.ts +++ b/src/data-structures/queue/queue.ts @@ -183,7 +183,7 @@ export class Queue { return new Queue(this.nodes.slice(this.offset)); } - * [Symbol.iterator]() { + *[Symbol.iterator]() { for (const item of this.nodes) { yield item; } diff --git a/src/types/data-structures/binary-tree/binary-tree.ts b/src/types/data-structures/binary-tree/binary-tree.ts index 4d0e908..80ce0a4 100644 --- a/src/types/data-structures/binary-tree/binary-tree.ts +++ b/src/types/data-structures/binary-tree/binary-tree.ts @@ -1,4 +1,5 @@ import {BinaryTreeNode} from '../../../data-structures'; +import PropertyKeysOf = jest.PropertyKeysOf; /** * Enum representing different loop types. @@ -24,7 +25,7 @@ export enum FamilyPosition { export type BinaryTreeNodeKey = number; -export type BFSCallback = (node: N, level?: number) => any; +export type BFSCallback = (node: N, level?: number) => D; export type BFSCallbackReturn = ReturnType>; diff --git a/src/types/data-structures/matrix/navigator.ts b/src/types/data-structures/matrix/navigator.ts index 34eddd9..9d8b9a9 100644 --- a/src/types/data-structures/matrix/navigator.ts +++ b/src/types/data-structures/matrix/navigator.ts @@ -1,6 +1,6 @@ export type Direction = 'up' | 'right' | 'down' | 'left'; -export type Turning = { [key in Direction]: Direction }; +export type Turning = {[key in Direction]: Direction}; export type NavigatorParams = { matrix: T[][]; diff --git a/src/types/helpers.ts b/src/types/helpers.ts index ca84f77..077114d 100644 --- a/src/types/helpers.ts +++ b/src/types/helpers.ts @@ -2,7 +2,7 @@ export type Comparator = (a: T, b: T) => number; export type DFSOrderPattern = 'pre' | 'in' | 'post'; -export type MapCallback = (node: N) => any; +export type MapCallback = (node: N) => D; export type MapCallbackReturn = ReturnType>; diff --git a/src/types/utils/utils.ts b/src/types/utils/utils.ts index 1f3a505..f4d26c4 100644 --- a/src/types/utils/utils.ts +++ b/src/types/utils/utils.ts @@ -1,5 +1,5 @@ export type ToThunkFn = () => ReturnType; -export type Thunk = () => ReturnType & { __THUNK__: symbol }; +export type Thunk = () => ReturnType & {__THUNK__: symbol}; export type TrlFn = (...args: any[]) => any; export type TrlAsyncFn = (...args: any[]) => any; diff --git a/src/types/utils/validate-type.ts b/src/types/utils/validate-type.ts index 3ebf451..ac9ff28 100644 --- a/src/types/utils/validate-type.ts +++ b/src/types/utils/validate-type.ts @@ -1,6 +1,6 @@ -export type KeyValueObject = { [key: string]: any }; +export type KeyValueObject = {[key: string]: any}; -export type KeyValueObjectWithKey = { [key: string]: any; key: string | number | symbol }; +export type KeyValueObjectWithKey = {[key: string]: any; key: string | number | symbol}; export type NonNumberNonObjectButDefined = string | boolean | symbol | null; diff --git a/test/integration/bst.test.ts b/test/integration/bst.test.ts index 425af06..a482a37 100644 --- a/test/integration/bst.test.ts +++ b/test/integration/bst.test.ts @@ -183,7 +183,7 @@ describe('Individual package BST operations test', () => { }); it('should perform various operations on a Binary Search Tree with object values', () => { - const objBST = new BST>(); + const objBST = new BST>(); expect(objBST).toBeInstanceOf(BST); objBST.add(11, {key: 11, keyA: 11}); objBST.add(3, {key: 3, keyA: 3}); diff --git a/test/unit/data-structures/binary-tree/avl-tree.test.ts b/test/unit/data-structures/binary-tree/avl-tree.test.ts index aa0ebee..e0e5e18 100644 --- a/test/unit/data-structures/binary-tree/avl-tree.test.ts +++ b/test/unit/data-structures/binary-tree/avl-tree.test.ts @@ -38,8 +38,7 @@ describe('AVL Tree Test', () => { expect(dfs[dfs.length - 1].key).toBe(16); tree.perfectlyBalance(); - const bfs: AVLTreeNode[] = []; - tree.bfs(node => bfs.push(node)); + const bfs = tree.bfs(node => node); expect(tree.isPerfectlyBalanced()).toBe(true); expect(bfs[0].key).toBe(8); expect(bfs[bfs.length - 1].key).toBe(16); @@ -98,8 +97,7 @@ describe('AVL Tree Test', () => { expect(tree.getHeight()).toBe(1); expect(tree.isAVLBalanced()).toBe(true); - const lastBFSIds = new Array(); - tree.bfs(node => lastBFSIds.push(node.key)); + const lastBFSIds = tree.bfs(); expect(lastBFSIds[0]).toBe(12); expect(lastBFSIds[1]).toBe(2); expect(lastBFSIds[2]).toBe(16); @@ -111,3 +109,22 @@ describe('AVL Tree Test', () => { expect(lastBFSNodes[2].key).toBe(16); }); }); + +describe('AVLTree APIs test', () => { + const avl = new AVLTree>(); + beforeEach(() => { + avl.clear(); + }); + + it('add', () => { + avl.add(1); + const node2 = new AVLTreeNode(2); + avl.add(node2); + const node3 = new AVLTreeNode(3, {id: 3, text: 'text3'}); + avl.add(node3); + avl.add(node3, {id: 3, text: 'text33'}); + + const bfsRes = avl.bfs(node => node.key, false); + expect(bfsRes[0]).toBe(2); + }); +}); diff --git a/test/unit/data-structures/binary-tree/binary-tree.test.ts b/test/unit/data-structures/binary-tree/binary-tree.test.ts index 21cbe99..fcb5f4e 100644 --- a/test/unit/data-structures/binary-tree/binary-tree.test.ts +++ b/test/unit/data-structures/binary-tree/binary-tree.test.ts @@ -1,4 +1,4 @@ -import {BinaryTree, BinaryTreeNode} from '../../../../src'; +import {AVLTree, AVLTreeNode, BinaryTree, BinaryTreeNode} from '../../../../src'; describe('BinaryTreeNode', () => { it('should create an instance of BinaryTreeNode', () => { @@ -194,3 +194,22 @@ describe('BinaryTree Morris Traversal', () => { expect(node1?.right).toBe(node3); }); }); + +describe('BinaryTree APIs test', () => { + const avl = new AVLTree>(); + beforeEach(() => { + avl.clear(); + }); + + it('add', () => { + avl.add(1); + const node2 = new AVLTreeNode(2); + avl.add(node2); + const node3 = new AVLTreeNode(3, {id: 3, text: 'text3'}); + avl.add(node3); + avl.add(node3, {id: 3, text: 'text33'}); + + const bfsRes = avl.bfs(node => node); + expect(bfsRes[0]?.key).toBe(2); + }); +}); diff --git a/test/unit/data-structures/binary-tree/bst.test.ts b/test/unit/data-structures/binary-tree/bst.test.ts index 6290d07..9683af9 100644 --- a/test/unit/data-structures/binary-tree/bst.test.ts +++ b/test/unit/data-structures/binary-tree/bst.test.ts @@ -189,7 +189,7 @@ describe('BST operations test', () => { }); it('should perform various operations on a Binary Search Tree with object values', () => { - const objBST = new BST>(); + const objBST = new BST>(); expect(objBST).toBeInstanceOf(BST); objBST.add(11, {key: 11, keyA: 11}); objBST.add(3, {key: 3, keyA: 3}); @@ -260,7 +260,7 @@ describe('BST operations test', () => { objBST.perfectlyBalance(); expect(objBST.isPerfectlyBalanced()).toBe(true); - const bfsNodesAfterBalanced: BSTNode<{ key: number; keyA: number }>[] = []; + const bfsNodesAfterBalanced: BSTNode<{key: number; keyA: number}>[] = []; objBST.bfs(node => bfsNodesAfterBalanced.push(node)); expect(bfsNodesAfterBalanced[0].key).toBe(8); expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16); @@ -385,7 +385,7 @@ describe('BST operations test', () => { expect(bfsIDs[1]).toBe(12); expect(bfsIDs[2]).toBe(16); - const bfsNodes: BSTNode<{ key: number; keyA: number }>[] = []; + const bfsNodes: BSTNode<{key: number; keyA: number}>[] = []; objBST.bfs(node => bfsNodes.push(node)); expect(bfsNodes[0].key).toBe(2); expect(bfsNodes[1].key).toBe(12); diff --git a/test/unit/data-structures/binary-tree/overall.test.ts b/test/unit/data-structures/binary-tree/overall.test.ts index d12b9ad..5325180 100644 --- a/test/unit/data-structures/binary-tree/overall.test.ts +++ b/test/unit/data-structures/binary-tree/overall.test.ts @@ -29,7 +29,7 @@ describe('Overall BinaryTree Test', () => { bfsIDs[0] === 11; // true expect(bfsIDs[0]).toBe(11); - const objBST = new BST>(); + const objBST = new BST>(); objBST.add(11, {key: 11, keyA: 11}); objBST.add(3, {key: 3, keyA: 3}); diff --git a/test/unit/data-structures/binary-tree/tree-multiset.test.ts b/test/unit/data-structures/binary-tree/tree-multiset.test.ts index 997c28d..6812143 100644 --- a/test/unit/data-structures/binary-tree/tree-multiset.test.ts +++ b/test/unit/data-structures/binary-tree/tree-multiset.test.ts @@ -206,7 +206,7 @@ describe('TreeMultiset operations test', () => { }); it('should perform various operations on a Binary Search Tree with object values', () => { - const objTreeMultiset = new TreeMultiset>(); + const objTreeMultiset = new TreeMultiset>(); expect(objTreeMultiset).toBeInstanceOf(TreeMultiset); objTreeMultiset.add(11, {key: 11, keyA: 11}); objTreeMultiset.add(3, {key: 3, keyA: 3}); diff --git a/test/unit/data-structures/heap/heap.test.ts b/test/unit/data-structures/heap/heap.test.ts index 14c54cf..8745402 100644 --- a/test/unit/data-structures/heap/heap.test.ts +++ b/test/unit/data-structures/heap/heap.test.ts @@ -22,7 +22,7 @@ describe('Heap Operation Test', () => { }); it('should object heap work well', function () { - const minHeap = new MinHeap<{ a: string; key: number }>((a, b) => a.key - b.key); + const minHeap = new MinHeap<{a: string; key: number}>((a, b) => a.key - b.key); minHeap.add({key: 1, a: 'a1'}); minHeap.add({key: 6, a: 'a6'}); minHeap.add({key: 2, a: 'a2'}); @@ -37,7 +37,7 @@ describe('Heap Operation Test', () => { i++; } - const maxHeap = new MaxHeap<{ key: number; a: string }>((a, b) => b.key - a.key); + const maxHeap = new MaxHeap<{key: number; a: string}>((a, b) => b.key - a.key); maxHeap.add({key: 1, a: 'a1'}); maxHeap.add({key: 6, a: 'a6'}); maxHeap.add({key: 5, a: 'a5'}); diff --git a/test/unit/data-structures/linked-list/doubly-linked-list.test.ts b/test/unit/data-structures/linked-list/doubly-linked-list.test.ts index 0838337..eab2ad5 100644 --- a/test/unit/data-structures/linked-list/doubly-linked-list.test.ts +++ b/test/unit/data-structures/linked-list/doubly-linked-list.test.ts @@ -3,7 +3,7 @@ import {bigO, magnitude} from '../../../utils'; describe('DoublyLinkedList Operation Test', () => { let list: DoublyLinkedList; - let objectList: DoublyLinkedList<{ keyA: number }>; + let objectList: DoublyLinkedList<{keyA: number}>; beforeEach(() => { list = new DoublyLinkedList(); diff --git a/test/unit/data-structures/linked-list/singly-linked-list.test.ts b/test/unit/data-structures/linked-list/singly-linked-list.test.ts index 092b2e6..74a3de8 100644 --- a/test/unit/data-structures/linked-list/singly-linked-list.test.ts +++ b/test/unit/data-structures/linked-list/singly-linked-list.test.ts @@ -3,10 +3,10 @@ import {bigO, magnitude} from '../../../utils'; describe('SinglyLinkedList Operation Test', () => { let list: SinglyLinkedList; - let objectList: SinglyLinkedList<{ keyA: number }>; + let objectList: SinglyLinkedList<{keyA: number}>; beforeEach(() => { list = new SinglyLinkedList(); - objectList = new SinglyLinkedList<{ keyA: number }>(); + objectList = new SinglyLinkedList<{keyA: number}>(); }); describe('push', () => { diff --git a/test/unit/data-structures/priority-queue/max-priority-queue.test.ts b/test/unit/data-structures/priority-queue/max-priority-queue.test.ts index f389309..f8a63bc 100644 --- a/test/unit/data-structures/priority-queue/max-priority-queue.test.ts +++ b/test/unit/data-structures/priority-queue/max-priority-queue.test.ts @@ -17,7 +17,7 @@ describe('MaxPriorityQueue Operation Test', () => { }); it('should add elements and maintain heap property in a object MaxPriorityQueue', () => { - const priorityQueue = new MaxPriorityQueue<{ keyA: number }>((a, b) => b.keyA - a.keyA); + const priorityQueue = new MaxPriorityQueue<{keyA: number}>((a, b) => b.keyA - a.keyA); priorityQueue.refill([{keyA: 5}, {keyA: 3}, {keyA: 1}]); priorityQueue.add({keyA: 7}); @@ -64,7 +64,7 @@ describe('MaxPriorityQueue Operation Test', () => { it('should correctly heapify an object array', () => { const nodes = [{keyA: 5}, {keyA: 3}, {keyA: 7}, {keyA: 1}]; - const maxPQ = MaxPriorityQueue.heapify<{ keyA: number }>(nodes, (a, b) => b.keyA - a.keyA); + const maxPQ = MaxPriorityQueue.heapify<{keyA: number}>(nodes, (a, b) => b.keyA - a.keyA); expect(maxPQ.poll()?.keyA).toBe(7); expect(maxPQ.poll()?.keyA).toBe(5); diff --git a/test/utils/big-o.ts b/test/utils/big-o.ts index cc9fc86..43d7eca 100644 --- a/test/utils/big-o.ts +++ b/test/utils/big-o.ts @@ -26,7 +26,7 @@ export const bigO = { function findPotentialN(input: any): number { let longestArray: any[] = []; - let mostProperties: { [key: string]: any } = {}; + let mostProperties: {[key: string]: any} = {}; function recurse(obj: any) { if (Array.isArray(obj)) { From 23cbdbabcafd2c046cb6cd841e839f0d65d34ee4 Mon Sep 17 00:00:00 2001 From: Revone Date: Wed, 25 Oct 2023 21:11:11 +0800 Subject: [PATCH 22/46] [binary-tree] bfs simplified --- test/unit/data-structures/binary-tree/avl-tree.test.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/unit/data-structures/binary-tree/avl-tree.test.ts b/test/unit/data-structures/binary-tree/avl-tree.test.ts index e0e5e18..1bd8174 100644 --- a/test/unit/data-structures/binary-tree/avl-tree.test.ts +++ b/test/unit/data-structures/binary-tree/avl-tree.test.ts @@ -102,8 +102,7 @@ describe('AVL Tree Test', () => { expect(lastBFSIds[1]).toBe(2); expect(lastBFSIds[2]).toBe(16); - const lastBFSNodes: AVLTreeNode[] = []; - tree.bfs(node => lastBFSNodes.push(node)); + const lastBFSNodes = tree.bfs(node => node); expect(lastBFSNodes[0].key).toBe(12); expect(lastBFSNodes[1].key).toBe(2); expect(lastBFSNodes[2].key).toBe(16); From 2d518151aeb0d72d204e51e3587a030c04aafa81 Mon Sep 17 00:00:00 2001 From: Revone Date: Wed, 25 Oct 2023 21:11:44 +0800 Subject: [PATCH 23/46] [pkg] v1.38.3 publish --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 93cf47e..b0a5357 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "data-structure-typed", - "version": "1.38.2", + "version": "1.38.3", "description": "Data Structures of Javascript & TypeScript. Binary Tree, BST, Graph, Heap, Priority Queue, Linked List, Queue, Deque, Stack, AVL Tree, Tree Multiset, Trie, Directed Graph, Undirected Graph, Singly Linked List, Doubly Linked List, Max Heap, Max Priority Queue, Min Heap, Min Priority Queue.", "main": "dist/cjs/index.js", "module": "dist/mjs/index.js", From 31c228668e56512c5116a49b7dac57f91917b002 Mon Sep 17 00:00:00 2001 From: Revone Date: Thu, 26 Oct 2023 16:45:08 +0800 Subject: [PATCH 24/46] [optimization] allow all list datatype delete methods to accept null as an input argument --- CHANGELOG.md | 2 +- README.md | 2 +- package-lock.json | 28 +++++++++---------- package.json | 10 +++---- scripts/publish_all_subs.sh | 4 +-- .../linked-list/doubly-linked-list.ts | 6 ++-- .../linked-list/singly-linked-list.ts | 9 ++---- .../binary-tree/binary-tree.ts | 1 - test/integration/index.html | 4 +-- 9 files changed, 29 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eb6646d..f1dd951 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.37.3](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) +## [v1.38.4](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) ### Changes diff --git a/README.md b/README.md index 169fefd..b6a6055 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ import { ```html - + ``` ```js diff --git a/package-lock.json b/package-lock.json index c4f24c4..01deb13 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "data-structure-typed", - "version": "1.38.2", + "version": "1.38.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "data-structure-typed", - "version": "1.38.2", + "version": "1.38.4", "license": "MIT", "devDependencies": { "@types/benchmark": "^2.1.3", @@ -15,10 +15,10 @@ "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", "auto-changelog": "^2.4.0", - "avl-tree-typed": "^1.38.2", + "avl-tree-typed": "^1.38.3", "benchmark": "^2.1.4", - "binary-tree-typed": "^1.38.2", - "bst-typed": "^1.38.2", + "binary-tree-typed": "^1.38.3", + "bst-typed": "^1.38.3", "dependency-cruiser": "^14.1.0", "eslint": "^8.50.0", "eslint-config-prettier": "^9.0.0", @@ -2728,9 +2728,9 @@ } }, "node_modules/avl-tree-typed": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.38.2.tgz", - "integrity": "sha512-2P1DPzdnTuvENa6bGA7vqglC+Ae8GndRSX4H5JeB4V5ZVoiWFpSDL2lO4kRJJYbceL+hemx4Ge/MriGYKgXIfQ==", + "version": "1.38.3", + "resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.38.3.tgz", + "integrity": "sha512-ecoSXprvLtWQlq3Cgp4HNeSeWQgruHyjePxZ8+2ldeUhNN0xgI4Bm8yv/GbN7wV6WGG3V85EidBnu9skZ7jDUA==", "dev": true }, "node_modules/babel-jest": { @@ -2924,9 +2924,9 @@ } }, "node_modules/binary-tree-typed": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.38.2.tgz", - "integrity": "sha512-odemWypyURZVq3qdegpaQDFydmt3sZA3uLHbcav3bBbnPj9WuMSIbOeOs21Nrj/yJHk1GrmlFRbPjYrrDXfdaw==", + "version": "1.38.3", + "resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.38.3.tgz", + "integrity": "sha512-fMnVgcByTNPM3D5sGJOQJ7/N3BUPqiMju4uTb7vDuGFC/sOcM1yN2MzbCEg/Ewwz7AQ7fydC2icuvqyY/AEUWA==", "dev": true }, "node_modules/brace-expansion": { @@ -3005,9 +3005,9 @@ } }, "node_modules/bst-typed": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.38.2.tgz", - "integrity": "sha512-BcTSvIbi8m5kEqzlS++YYlg2IgKhuqsX1mu200BLGq4d327vsQq9hY8TneuL54N4KAr4McR2GqpkDaHXQ3eTbw==", + "version": "1.38.3", + "resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.38.3.tgz", + "integrity": "sha512-T83xkJXfuTjh0wGLiabSqmje4Ky5VxAfYA0RcM4UcgM7lFsYvyGwuSaI9AEWYbr+8Tb2sKqQ8uNP45mF+rB9Lg==", "dev": true }, "node_modules/buffer-from": { diff --git a/package.json b/package.json index b0a5357..3616ea3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "data-structure-typed", - "version": "1.38.3", + "version": "1.38.4", "description": "Data Structures of Javascript & TypeScript. Binary Tree, BST, Graph, Heap, Priority Queue, Linked List, Queue, Deque, Stack, AVL Tree, Tree Multiset, Trie, Directed Graph, Undirected Graph, Singly Linked List, Doubly Linked List, Max Heap, Max Priority Queue, Min Heap, Min Priority Queue.", "main": "dist/cjs/index.js", "module": "dist/mjs/index.js", @@ -39,7 +39,7 @@ "copy:to-subs": "sh scripts/copy_to_all_subs.sh", "publish:subs": "npm run copy:to-subs && sh scripts/publish_all_subs.sh", "publish:docs": "sh scripts/publish_docs.sh", - "publish:all": "npm run ci && npm publish && npm run publish:subs && npm run publish:docs" + "publish:all": "npm run ci && npm publish && npm run publish:docs && npm run publish:subs" }, "repository": { "type": "git", @@ -61,10 +61,10 @@ "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", "auto-changelog": "^2.4.0", - "avl-tree-typed": "^1.38.2", + "avl-tree-typed": "^1.38.3", "benchmark": "^2.1.4", - "binary-tree-typed": "^1.38.2", - "bst-typed": "^1.38.2", + "binary-tree-typed": "^1.38.3", + "bst-typed": "^1.38.3", "dependency-cruiser": "^14.1.0", "eslint": "^8.50.0", "eslint-config-prettier": "^9.0.0", diff --git a/scripts/publish_all_subs.sh b/scripts/publish_all_subs.sh index 6f52833..7b7da2f 100755 --- a/scripts/publish_all_subs.sh +++ b/scripts/publish_all_subs.sh @@ -61,8 +61,8 @@ for dir in "${directories[@]}"; do # jq ".dependencies[\"data-structure-typed\"] = \"$version_prompted\"" package.json > temp.json # mv temp.json package.json -# # Install data-structure-typed package and build -# npm i data-structure-typed@"$version_prompted" + # Install data-structure-typed package and build + npm i data-structure-typed@"$version_prompted" npm run build:publish cd .. diff --git a/src/data-structures/linked-list/doubly-linked-list.ts b/src/data-structures/linked-list/doubly-linked-list.ts index cbd69d5..972f137 100644 --- a/src/data-structures/linked-list/doubly-linked-list.ts +++ b/src/data-structures/linked-list/doubly-linked-list.ts @@ -266,7 +266,7 @@ export class DoublyLinkedList { * @returns The function `findNodeByValue` returns a `DoublyLinkedListNode` if a node with the specified value `val` * is found in the linked list. If no such node is found, it returns `null`. */ - findNode(val: E): DoublyLinkedListNode | null { + findNode(val: E | null): DoublyLinkedListNode | null { let current = this.head; while (current) { @@ -341,7 +341,7 @@ export class DoublyLinkedList { * @returns The `delete` method returns a boolean value. It returns `true` if the value or node was successfully * deleted from the doubly linked list, and `false` if the value or node was not found in the list. */ - delete(valOrNode: E | DoublyLinkedListNode): boolean { + delete(valOrNode: E | DoublyLinkedListNode | null): boolean { let node: DoublyLinkedListNode | null; if (valOrNode instanceof DoublyLinkedListNode) { @@ -594,8 +594,6 @@ export class DoublyLinkedList { return false; } - insertBefore(existingValueOrNode: E, newValue: E): boolean; - insertBefore(existingValueOrNode: DoublyLinkedListNode, newValue: E): boolean; /** * The `insertBefore` function inserts a new value before an existing value or node in a doubly linked list. diff --git a/src/data-structures/linked-list/singly-linked-list.ts b/src/data-structures/linked-list/singly-linked-list.ts index 2eaca25..c4e1da9 100644 --- a/src/data-structures/linked-list/singly-linked-list.ts +++ b/src/data-structures/linked-list/singly-linked-list.ts @@ -214,9 +214,6 @@ export class SinglyLinkedList { return removedNode!.val; } - delete(valueOrNode: E): boolean; - delete(valueOrNode: SinglyLinkedListNode): boolean; - /** * The delete function removes a node with a specific value from a singly linked list. * @param {E | SinglyLinkedListNode} valueOrNode - The `valueOrNode` parameter can accept either a value of type `E` @@ -224,7 +221,8 @@ export class SinglyLinkedList { * @returns The `delete` method returns a boolean value. It returns `true` if the value or node is found and * successfully deleted from the linked list, and `false` if the value or node is not found in the linked list. */ - delete(valueOrNode: E | SinglyLinkedListNode): boolean { + delete(valueOrNode: E | SinglyLinkedListNode | null | undefined): boolean { + if (!valueOrNode) return false; let value: E; if (valueOrNode instanceof SinglyLinkedListNode) { value = valueOrNode.val; @@ -397,9 +395,6 @@ export class SinglyLinkedList { return null; } - insertBefore(existingValue: E, newValue: E): boolean; - insertBefore(existingValue: SinglyLinkedListNode, newValue: E): boolean; - /** * The `insertBefore` function inserts a new value before an existing value in a singly linked list. * @param {E | SinglyLinkedListNode} existingValueOrNode - The existing value or node that you want to insert the diff --git a/src/types/data-structures/binary-tree/binary-tree.ts b/src/types/data-structures/binary-tree/binary-tree.ts index 80ce0a4..61b63bb 100644 --- a/src/types/data-structures/binary-tree/binary-tree.ts +++ b/src/types/data-structures/binary-tree/binary-tree.ts @@ -1,5 +1,4 @@ import {BinaryTreeNode} from '../../../data-structures'; -import PropertyKeysOf = jest.PropertyKeysOf; /** * Enum representing different loop types. diff --git a/test/integration/index.html b/test/integration/index.html index ab70fa2..0fab945 100644 --- a/test/integration/index.html +++ b/test/integration/index.html @@ -3,7 +3,7 @@ CDN Test - +
@@ -23,7 +23,7 @@ $avlTreeSpan.innerText = 'AVLTree'; $avlTree.append($avlTreeSpan); avlTree.add(1, 1); - console.log(avlTree.BFS()); + console.log(avlTree.bfs()); $modules.append($avlTree); From f2d3be75744cc1ba21d2eeaa4b135c4da2b71134 Mon Sep 17 00:00:00 2001 From: Revone Date: Thu, 26 Oct 2023 20:26:06 +0800 Subject: [PATCH 25/46] [binary-tree] Translate the return value type inference for methods that take a callback function as a parameter. --- CHANGELOG.md | 2 +- package-lock.json | 62 ++++-- package.json | 10 +- src/data-structures/binary-tree/avl-tree.ts | 24 ++- .../binary-tree/binary-tree.ts | 195 +++++++++++------- src/data-structures/binary-tree/bst.ts | 34 +-- src/data-structures/binary-tree/rb-tree.ts | 4 +- .../binary-tree/tree-multiset.ts | 20 +- src/interfaces/binary-tree.ts | 2 +- src/types/helpers.ts | 4 + .../binary-tree/tree-multiset.test.ts | 28 +-- 11 files changed, 242 insertions(+), 143 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f1dd951..5e34f57 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.38.4](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) +## [v1.38.5](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) ### Changes diff --git a/package-lock.json b/package-lock.json index 01deb13..469cb06 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "data-structure-typed", - "version": "1.38.4", + "version": "1.38.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "data-structure-typed", - "version": "1.38.4", + "version": "1.38.5", "license": "MIT", "devDependencies": { "@types/benchmark": "^2.1.3", @@ -15,17 +15,17 @@ "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", "auto-changelog": "^2.4.0", - "avl-tree-typed": "^1.38.3", + "avl-tree-typed": "^1.38.4", "benchmark": "^2.1.4", - "binary-tree-typed": "^1.38.3", - "bst-typed": "^1.38.3", + "binary-tree-typed": "^1.38.4", + "bst-typed": "^1.38.4", "dependency-cruiser": "^14.1.0", "eslint": "^8.50.0", "eslint-config-prettier": "^9.0.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.28.1", - "heap-typed": "^1.38.2", + "heap-typed": "^1.38.4", "istanbul-badges-readme": "^1.8.5", "jest": "^29.7.0", "prettier": "^3.0.3", @@ -2728,10 +2728,13 @@ } }, "node_modules/avl-tree-typed": { - "version": "1.38.3", - "resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.38.3.tgz", - "integrity": "sha512-ecoSXprvLtWQlq3Cgp4HNeSeWQgruHyjePxZ8+2ldeUhNN0xgI4Bm8yv/GbN7wV6WGG3V85EidBnu9skZ7jDUA==", - "dev": true + "version": "1.38.4", + "resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.38.4.tgz", + "integrity": "sha512-m4+vC3t52CnPqMB5dxZI016OKMCxitk6vDsdqSadPHUeZd92E9LEQSHzgjdZ380FGcIZuz9q0IS7VTHR4F3+gg==", + "dev": true, + "dependencies": { + "data-structure-typed": "^1.38.4" + } }, "node_modules/babel-jest": { "version": "29.7.0", @@ -2924,10 +2927,13 @@ } }, "node_modules/binary-tree-typed": { - "version": "1.38.3", - "resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.38.3.tgz", - "integrity": "sha512-fMnVgcByTNPM3D5sGJOQJ7/N3BUPqiMju4uTb7vDuGFC/sOcM1yN2MzbCEg/Ewwz7AQ7fydC2icuvqyY/AEUWA==", - "dev": true + "version": "1.38.4", + "resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.38.4.tgz", + "integrity": "sha512-InWS3ggQsmEyqgvaO+Veme/uTphUxaFQ1C7/9Bz07zcr8lV0riDsj0En9qwGTI8R4L32CpBL1cxQXJbk9Do45g==", + "dev": true, + "dependencies": { + "data-structure-typed": "^1.38.4" + } }, "node_modules/brace-expansion": { "version": "1.1.11", @@ -3005,10 +3011,13 @@ } }, "node_modules/bst-typed": { - "version": "1.38.3", - "resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.38.3.tgz", - "integrity": "sha512-T83xkJXfuTjh0wGLiabSqmje4Ky5VxAfYA0RcM4UcgM7lFsYvyGwuSaI9AEWYbr+8Tb2sKqQ8uNP45mF+rB9Lg==", - "dev": true + "version": "1.38.4", + "resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.38.4.tgz", + "integrity": "sha512-OCY+VQBfj8m8KYZullDuKrwYD8vzRBiIQ92hYDL3GWzuDMlTeEFUyIcDni0SR91JxRuUPbL7CuxN0fQRjDMKRg==", + "dev": true, + "dependencies": { + "data-structure-typed": "^1.38.4" + } }, "node_modules/buffer-from": { "version": "1.1.2", @@ -3403,6 +3412,12 @@ "node": ">= 8" } }, + "node_modules/data-structure-typed": { + "version": "1.38.4", + "resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.38.4.tgz", + "integrity": "sha512-Yt9yjrx3Cm030z3o/6hr+AG0n+ZpWd+YpG2YiwxNwOT+hTZ6PYWt9MI+UVpiJSW/1Mrr0gchLlipU1r7l+UI/w==", + "dev": true + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -4756,10 +4771,13 @@ } }, "node_modules/heap-typed": { - "version": "1.38.2", - "resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.38.2.tgz", - "integrity": "sha512-GVNHQlbQkuuZMpMBj8fvekI8ClHst3s8W1qozLragMLD/ndb+acumWCXeypR9gwgjDTneqOW6fAgpUMDDKOn9Q==", - "dev": true + "version": "1.38.4", + "resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.38.4.tgz", + "integrity": "sha512-fI+xbxoC3jpkmwqKIFRoJ8BGojd7FitEeYhwrkGpKnNMs9zp5dxA2qmrk+Gof0lDMuRca5CplVyInvGgL7cjzw==", + "dev": true, + "dependencies": { + "data-structure-typed": "^1.38.4" + } }, "node_modules/html-escaper": { "version": "2.0.2", diff --git a/package.json b/package.json index 3616ea3..dfce9bd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "data-structure-typed", - "version": "1.38.4", + "version": "1.38.5", "description": "Data Structures of Javascript & TypeScript. Binary Tree, BST, Graph, Heap, Priority Queue, Linked List, Queue, Deque, Stack, AVL Tree, Tree Multiset, Trie, Directed Graph, Undirected Graph, Singly Linked List, Doubly Linked List, Max Heap, Max Priority Queue, Min Heap, Min Priority Queue.", "main": "dist/cjs/index.js", "module": "dist/mjs/index.js", @@ -61,17 +61,17 @@ "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", "auto-changelog": "^2.4.0", - "avl-tree-typed": "^1.38.3", + "avl-tree-typed": "^1.38.4", "benchmark": "^2.1.4", - "binary-tree-typed": "^1.38.3", - "bst-typed": "^1.38.3", + "binary-tree-typed": "^1.38.4", + "bst-typed": "^1.38.4", "dependency-cruiser": "^14.1.0", "eslint": "^8.50.0", "eslint-config-prettier": "^9.0.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.28.1", - "heap-typed": "^1.38.2", + "heap-typed": "^1.38.4", "istanbul-badges-readme": "^1.8.5", "jest": "^29.7.0", "prettier": "^3.0.3", diff --git a/src/data-structures/binary-tree/avl-tree.ts b/src/data-structures/binary-tree/avl-tree.ts index 1b1c88d..da4d2e6 100644 --- a/src/data-structures/binary-tree/avl-tree.ts +++ b/src/data-structures/binary-tree/avl-tree.ts @@ -6,8 +6,15 @@ * @license MIT License */ import {BST, BSTNode} from './bst'; -import type {AVLTreeNodeNested, AVLTreeOptions, BinaryTreeDeletedResult, BinaryTreeNodeKey} from '../../types'; +import type { + AVLTreeNodeNested, + AVLTreeOptions, + BinaryTreeDeletedResult, + BinaryTreeNodeKey, + DefaultMapCallback +} from '../../types'; import {IBinaryTree} from '../../interfaces'; +import {MapCallback} from "../../types"; export class AVLTreeNode = AVLTreeNodeNested> extends BSTNode< V, @@ -64,12 +71,19 @@ export class AVLTree = AVLTreeNode> extends B /** * The function overrides the delete method of a binary tree and balances the tree after deleting a * node if necessary. - * @param {N | BinaryTreeNodeKey} nodeOrKey - The `nodeOrKey` parameter can be either a node object - * (`N`) or a key value (`BinaryTreeNodeKey`). + * @param {ReturnType} identifier - The `identifier` parameter is either a + * `BinaryTreeNodeKey` or a generic type `N`. It represents the property of the node that we are + * searching for. It can be a specific key value or any other property of the node. + * @param callback - The `callback` parameter is a function that takes a node as input and returns a + * value. This value is compared with the `identifier` parameter to determine if the node should be + * included in the result. The `callback` parameter has a default value of + * `this._defaultCallbackByKey` * @returns The method is returning an array of `BinaryTreeDeletedResult` objects. */ - override delete(nodeOrKey: N | BinaryTreeNodeKey): BinaryTreeDeletedResult[] { - const deletedResults = super.delete(nodeOrKey); + override delete>( + identifier: ReturnType, + callback: C = this._defaultCallbackByKey as C): BinaryTreeDeletedResult[] { + const deletedResults = super.delete(identifier, callback); for (const {needBalanced} of deletedResults) { if (needBalanced) { this._balancePath(needBalanced); diff --git a/src/data-structures/binary-tree/binary-tree.ts b/src/data-structures/binary-tree/binary-tree.ts index 7b2ea5e..70aa5d5 100644 --- a/src/data-structures/binary-tree/binary-tree.ts +++ b/src/data-structures/binary-tree/binary-tree.ts @@ -15,7 +15,7 @@ import type { MapCallback, MapCallbackReturn } from '../../types'; -import {BinaryTreeDeletedResult, DFSOrderPattern, FamilyPosition, IterationType} from '../../types'; +import {BinaryTreeDeletedResult, DefaultMapCallback, DFSOrderPattern, FamilyPosition, IterationType} from '../../types'; import {IBinaryTree} from '../../interfaces'; import {trampoline} from '../../utils'; import {Queue} from '../queue'; @@ -97,29 +97,17 @@ export class BinaryTreeNode = */ get familyPosition(): FamilyPosition { const that = this as unknown as FAMILY; - if (that.parent) { - if (that.parent.left === that) { - if (that.left || that.right) { - return FamilyPosition.ROOT_LEFT; - } else { - return FamilyPosition.LEFT; - } - } else if (that.parent.right === that) { - if (that.left || that.right) { - return FamilyPosition.ROOT_RIGHT; - } else { - return FamilyPosition.RIGHT; - } - } else { - return FamilyPosition.MAL_NODE; - } - } else { - if (that.left || that.right) { - return FamilyPosition.ROOT; - } else { - return FamilyPosition.ISOLATED; - } + if (!this.parent) { + return this.left || this.right ? FamilyPosition.ROOT : FamilyPosition.ISOLATED; } + + if (this.parent.left === that) { + return this.left || this.right ? FamilyPosition.ROOT_LEFT : FamilyPosition.LEFT; + } else if (this.parent.right === that) { + return this.left || this.right ? FamilyPosition.ROOT_RIGHT : FamilyPosition.RIGHT; + } + + return FamilyPosition.MAL_NODE; } } @@ -234,7 +222,8 @@ export class BinaryTree = BinaryTreeNode> return; } - const existNode = keyOrNode ? this.get(keyOrNode, this._defaultCallbackByKey) : undefined; + const key = typeof keyOrNode === 'number' ? keyOrNode : keyOrNode ? keyOrNode.key: undefined; + const existNode = key !== undefined ? this.get(key, this._defaultCallbackByKey) : undefined; if (this.root) { if (existNode) { @@ -267,24 +256,18 @@ export class BinaryTree = BinaryTreeNode> */ addMany(keysOrNodes: (BinaryTreeNodeKey | null)[] | (N | null)[], values?: N['val'][]): (N | null | undefined)[] { // TODO not sure addMany not be run multi times - const inserted: (N | null | undefined)[] = []; - - for (let i = 0; i < keysOrNodes.length; i++) { - const keyOrNode = keysOrNodes[i]; + return keysOrNodes.map((keyOrNode, i) => { if (keyOrNode instanceof BinaryTreeNode) { - inserted.push(this.add(keyOrNode.key, keyOrNode.val)); - continue; + return this.add(keyOrNode.key, keyOrNode.val); } if (keyOrNode === null) { - inserted.push(this.add(null)); - continue; + return this.add(null); } const val = values?.[i]; - inserted.push(this.add(keyOrNode, val)); - } - return inserted; + return this.add(keyOrNode, val); + }); } /** @@ -301,19 +284,37 @@ export class BinaryTree = BinaryTreeNode> return keysOrNodes.length === this.addMany(keysOrNodes, data).length; } + delete>( + identifier: ReturnType | N + ): BinaryTreeDeletedResult[]; + + delete>( + identifier: ReturnType | N, + callback: C + ): BinaryTreeDeletedResult[]; + /** * The `delete` function removes a node from a binary search tree and returns the deleted node along * with the parent node that needs to be balanced. - * @param {N | BinaryTreeNodeKey} nodeOrKey - The `nodeOrKey` parameter can be either a node (`N`) or * a key (`BinaryTreeNodeKey`). If it is a key, the function will find the corresponding node in the * binary tree. * @returns an array of `BinaryTreeDeletedResult` objects. + * @param {ReturnType} identifier - The `identifier` parameter is either a + * `BinaryTreeNodeKey` or a generic type `N`. It represents the property of the node that we are + * searching for. It can be a specific key value or any other property of the node. + * @param callback - The `callback` parameter is a function that takes a node as input and returns a + * value. This value is compared with the `identifier` parameter to determine if the node should be + * included in the result. The `callback` parameter has a default value of + * `this._defaultCallbackByKey`, which */ - delete(nodeOrKey: N | BinaryTreeNodeKey): BinaryTreeDeletedResult[] { + delete>( + identifier: ReturnType | N, + callback: C = this._defaultCallbackByKey as C): BinaryTreeDeletedResult[] { const bstDeletedResult: BinaryTreeDeletedResult[] = []; if (!this.root) return bstDeletedResult; + if (identifier instanceof BinaryTreeNode) callback = (node => node) as C; - const curr: N | null = typeof nodeOrKey === 'number' ? this.get(nodeOrKey) : nodeOrKey; + const curr = this.get(identifier, callback); if (!curr) return bstDeletedResult; const parent: N | null = curr?.parent ? curr.parent : null; @@ -354,16 +355,16 @@ export class BinaryTree = BinaryTreeNode> /** * The function `getDepth` calculates the depth of a given node in a binary tree relative to a * specified root node. - * @param {N | BinaryTreeNodeKey | null} distNode - The `distNode` parameter represents the node + * @param {BinaryTreeNodeKey | N | null} distNode - The `distNode` parameter represents the node * whose depth we want to find in the binary tree. It can be either a node object (`N`), a key value * of the node (`BinaryTreeNodeKey`), or `null`. - * @param {N | BinaryTreeNodeKey | null} beginRoot - The `beginRoot` parameter represents the + * @param {BinaryTreeNodeKey | N | null} beginRoot - The `beginRoot` parameter represents the * starting node from which we want to calculate the depth. It can be either a node object or the key * of a node in the binary tree. If no value is provided for `beginRoot`, it defaults to the root * node of the binary tree. * @returns the depth of the `distNode` relative to the `beginRoot`. */ - getDepth(distNode: N | BinaryTreeNodeKey | null, beginRoot: N | BinaryTreeNodeKey | null = this.root): number { + getDepth(distNode: BinaryTreeNodeKey | N | null, beginRoot: BinaryTreeNodeKey | N | null = this.root): number { if (typeof distNode === 'number') distNode = this.get(distNode); if (typeof beginRoot === 'number') beginRoot = this.get(beginRoot); let depth = 0; @@ -380,7 +381,7 @@ export class BinaryTree = BinaryTreeNode> /** * The `getHeight` function calculates the maximum height of a binary tree using either recursive or * iterative approach. - * @param {N | BinaryTreeNodeKey | null} beginRoot - The `beginRoot` parameter represents the + * @param {BinaryTreeNodeKey | N | null} beginRoot - The `beginRoot` parameter represents the * starting node from which the height of the binary tree is calculated. It can be either a node * object (`N`), a key value of a node in the tree (`BinaryTreeNodeKey`), or `null` if no starting * node is specified. If ` @@ -389,7 +390,7 @@ export class BinaryTree = BinaryTreeNode> * possible values: * @returns the height of the binary tree. */ - getHeight(beginRoot: N | BinaryTreeNodeKey | null = this.root, iterationType = this.iterationType): number { + getHeight(beginRoot: BinaryTreeNodeKey | N | null = this.root, iterationType = this.iterationType): number { if (typeof beginRoot === 'number') beginRoot = this.get(beginRoot); if (!beginRoot) return -1; @@ -491,18 +492,55 @@ export class BinaryTree = BinaryTreeNode> return this.getMinHeight(beginRoot) + 1 >= this.getHeight(beginRoot); } + + getNodes>( + identifier: ReturnType | N + ): N[]; + + getNodes>( + identifier: ReturnType | N, + callback: C + ): N[]; + + getNodes>( + identifier: ReturnType | N, + onlyOne: boolean + ): N[]; + + getNodes>( + identifier: ReturnType | N, + callback: C, + onlyOne: boolean + ): N[]; + + getNodes>( + identifier: ReturnType | N, + callback: C, + onlyOne: boolean, + beginRoot: N | null + ): N[]; + + getNodes>( + identifier: ReturnType | N, + callback: C, + onlyOne: boolean, + beginRoot: N | null, + iterationType: IterationType + ): N[]; + + /** * The function `getNodes` returns an array of nodes that match a given node property, using either * recursive or iterative traversal. - * @param {BinaryTreeNodeKey | N} nodeProperty - The `nodeProperty` parameter is either a + * @param {ReturnType} identifier - The `identifier` parameter is either a * `BinaryTreeNodeKey` or a generic type `N`. It represents the property of the node that we are * searching for. It can be a specific key value or any other property of the node. * @param callback - The `callback` parameter is a function that takes a node as input and returns a - * value. This value is compared with the `nodeProperty` parameter to determine if the node should be + * value. This value is compared with the `identifier` parameter to determine if the node should be * included in the result. The `callback` parameter has a default value of * `this._defaultCallbackByKey`, which * @param [onlyOne=false] - A boolean value indicating whether to stop searching after finding the - * first node that matches the nodeProperty. If set to true, the function will return an array with + * first node that matches the identifier. If set to true, the function will return an array with * only one element (or an empty array if no matching node is found). If set to false (default), the * function will continue searching for all * @param {N | null} beginRoot - The `beginRoot` parameter is the starting node from which the @@ -512,20 +550,20 @@ export class BinaryTree = BinaryTreeNode> * traverse the binary tree. It can have two possible values: * @returns The function `getNodes` returns an array of nodes (`N[]`). */ - getNodes = MapCallback>( - nodeProperty: BinaryTreeNodeKey | N, + getNodes>( + identifier: ReturnType | N, callback: C = this._defaultCallbackByKey as C, onlyOne = false, beginRoot: N | null = this.root, iterationType = this.iterationType ): N[] { if (!beginRoot) return []; - + if (identifier instanceof BinaryTreeNode) callback = (node => node) as C; const ans: N[] = []; if (iterationType === IterationType.RECURSIVE) { const _traverse = (cur: N) => { - if (callback(cur) === nodeProperty) { + if (callback(cur) === identifier) { ans.push(cur); if (onlyOne) return; } @@ -540,7 +578,7 @@ export class BinaryTree = BinaryTreeNode> while (queue.size > 0) { const cur = queue.shift(); if (cur) { - if (callback(cur) === nodeProperty) { + if (callback(cur) === identifier) { ans.push(cur); if (onlyOne) return ans; } @@ -553,9 +591,17 @@ export class BinaryTree = BinaryTreeNode> return ans; } + has>(identifier: ReturnType | N): boolean; + + has>(identifier: ReturnType | N, callback: C): boolean; + + has>(identifier: ReturnType | N, beginRoot: N | null): boolean; + + has>(identifier: ReturnType | N, callback: C, beginRoot: N | null): boolean; + /** * The function checks if a binary tree has a node with a given property or key. - * @param {BinaryTreeNodeKey | N} nodeProperty - The `nodeProperty` parameter is the key or value of + * @param {BinaryTreeNodeKey | N} identifier - The `identifier` parameter is the key or value of * the node that you want to find in the binary tree. It can be either a `BinaryTreeNodeKey` or a * generic type `N`. * @param callback - The `callback` parameter is a function that is used to determine whether a node @@ -570,19 +616,30 @@ export class BinaryTree = BinaryTreeNode> * performed when searching for nodes in the binary tree. It can have one of the following values: * @returns a boolean value. */ - has = MapCallback>( - nodeProperty: BinaryTreeNodeKey | N, + has>( + identifier: ReturnType | N, callback: C = this._defaultCallbackByKey as C, beginRoot = this.root, iterationType = this.iterationType ): boolean { + if (identifier instanceof BinaryTreeNode) callback = (node => node) as C; // TODO may support finding node by value equal - return this.getNodes(nodeProperty, callback, true, beginRoot, iterationType).length > 0; + return this.getNodes(identifier, callback, true, beginRoot, iterationType).length > 0; } + get>(identifier: ReturnType | N): N | null; + + get>(identifier: ReturnType | N, callback: C): N | null; + + get>(identifier: ReturnType | N, beginRoot: N | null): N | null; + + get>(identifier: ReturnType | N, callback: C, beginRoot: N | null): N | null; + + get>(identifier: ReturnType | N, callback: C, beginRoot: N | null, iterationType: IterationType): N | null; + /** * The function `get` returns the first node in a binary tree that matches the given property or key. - * @param {BinaryTreeNodeKey | N} nodeProperty - The `nodeProperty` parameter is the key or value of + * @param {BinaryTreeNodeKey | N} identifier - The `identifier` parameter is the key or value of * the node that you want to find in the binary tree. It can be either a `BinaryTreeNodeKey` or `N` * type. * @param callback - The `callback` parameter is a function that is used to determine whether a node @@ -595,14 +652,15 @@ export class BinaryTree = BinaryTreeNode> * performed when searching for a node in the binary tree. It can have one of the following values: * @returns either the found node (of type N) or null if no node is found. */ - get = MapCallback>( - nodeProperty: BinaryTreeNodeKey | N, + get>( + identifier: ReturnType | N, callback: C = this._defaultCallbackByKey as C, beginRoot = this.root, iterationType = this.iterationType ): N | null { + if (identifier instanceof BinaryTreeNode) callback = (node => node) as C; // TODO may support finding node by value equal - return this.getNodes(nodeProperty, callback, true, beginRoot, iterationType)[0] ?? null; + return this.getNodes(identifier, callback, true, beginRoot, iterationType)[0] ?? null; } /** @@ -631,7 +689,7 @@ export class BinaryTree = BinaryTreeNode> /** * The function `getLeftMost` returns the leftmost node in a binary tree, either using recursive or * iterative traversal. - * @param {N | BinaryTreeNodeKey | null} beginRoot - The `beginRoot` parameter is the starting point + * @param {BinaryTreeNodeKey | N | null} beginRoot - The `beginRoot` parameter is the starting point * for finding the leftmost node in a binary tree. It can be either a node object (`N`), a key value * of a node (`BinaryTreeNodeKey`), or `null` if the tree is empty. * @param iterationType - The `iterationType` parameter is used to determine the type of iteration to @@ -639,7 +697,7 @@ export class BinaryTree = BinaryTreeNode> * @returns The function `getLeftMost` returns the leftmost node (`N`) in a binary tree. If there is * no leftmost node, it returns `null`. */ - getLeftMost(beginRoot: N | BinaryTreeNodeKey | null = this.root, iterationType = this.iterationType): N | null { + getLeftMost(beginRoot: BinaryTreeNodeKey | N | null = this.root, iterationType = this.iterationType): N | null { if (typeof beginRoot === 'number') beginRoot = this.get(beginRoot); if (!beginRoot) return beginRoot; @@ -754,16 +812,16 @@ export class BinaryTree = BinaryTreeNode> * subtree traversal. It takes a single argument, which is the current node being traversed, and * returns a value. The return values from each callback invocation will be collected and returned as * an array. - * @param {N | BinaryTreeNodeKey | null} beginRoot - The `beginRoot` parameter is the starting point + * @param {BinaryTreeNodeKey | N | null} beginRoot - The `beginRoot` parameter is the starting point * for traversing the subtree. It can be either a node object, a key value of a node, or `null` to * start from the root of the tree. * @param iterationType - The `iterationType` parameter determines the type of traversal to be * performed on the binary tree. It can have two possible values: * @returns The function `subTreeTraverse` returns an array of `MapCallbackReturn`. */ - subTreeTraverse = MapCallback>( + subTreeTraverse>( callback: C = this._defaultCallbackByKey as C, - beginRoot: N | BinaryTreeNodeKey | null = this.root, + beginRoot: BinaryTreeNodeKey | N | null = this.root, iterationType = this.iterationType ): ReturnType[] { if (typeof beginRoot === 'number') beginRoot = this.get(beginRoot); @@ -808,7 +866,7 @@ export class BinaryTree = BinaryTreeNode> * iteration used in the depth-first search algorithm. It can have two possible values: * @returns The function `dfs` returns an array of `MapCallbackReturn` values. */ - dfs = MapCallback>( + dfs>( callback: C = this._defaultCallbackByKey as C, pattern: DFSOrderPattern = 'in', beginRoot: N | null = this.root, @@ -886,7 +944,7 @@ export class BinaryTree = BinaryTreeNode> * breadth-first search. It takes a node of type `N` as its argument and returns a value of type * `BFSCallbackReturn`. The default value for this parameter is `this._defaultCallbackByKey * @param {boolean} [withLevel=false] - The `withLevel` parameter is a boolean flag that determines - * whether or not to include the level of each node in the callback function. If `withLevel` is set + * whether to include the level of each node in the callback function. If `withLevel` is set * to `true`, the level of each node will be passed as an argument to the callback function. If * `withLevel` is * @param {N | null} beginRoot - The `beginRoot` parameter is the starting node for the breadth-first @@ -964,7 +1022,7 @@ export class BinaryTree = BinaryTreeNode> * `beginRoot` is `null`, an empty array will be returned. * @returns The `morris` function returns an array of `MapCallbackReturn` values. */ - morris = MapCallback>( + morris>( callback: C = this._defaultCallbackByKey as C, pattern: DFSOrderPattern = 'in', beginRoot: N | null = this.root @@ -1077,8 +1135,7 @@ export class BinaryTree = BinaryTreeNode> * the tree's structure should be restored to its original state to maintain the tree's integrity. * This is because the purpose of the Morris algorithm is to save space rather than permanently alter the tree's shape. */ - - protected _defaultCallbackByKey: (node: N) => number = node => node.key; + protected _defaultCallbackByKey: DefaultMapCallback = node => node.key; /** * The function `_addTo` adds a new node to a binary tree if there is an available position. diff --git a/src/data-structures/binary-tree/bst.ts b/src/data-structures/binary-tree/bst.ts index 0237476..1e632aa 100644 --- a/src/data-structures/binary-tree/bst.ts +++ b/src/data-structures/binary-tree/bst.ts @@ -132,7 +132,7 @@ export class BST = BSTNode> extends BinaryTree /** * The `addMany` function is used to efficiently add multiple nodes to a binary search tree while * maintaining balance. - * @param {[BinaryTreeNodeKey | N, N['val']][]} arr - The `arr` parameter in the `addMany` function + * @param {[BinaryTreeNodeKey | N, N['val']][]} keysOrNodes - The `arr` parameter in the `addMany` function * represents an array of keys or nodes that need to be added to the binary search tree. It can be an * array of `BinaryTreeNodeKey` or `N` (which represents the node type in the binary search tree) or * `null @@ -223,7 +223,7 @@ export class BST = BSTNode> extends BinaryTree /** * The function returns the first node in the binary tree that matches the given node property and * callback. - * @param {BinaryTreeNodeKey | N} nodeProperty - The `nodeProperty` parameter is used to specify the + * @param {ReturnType | N} identifier - The `nodeProperty` parameter is used to specify the * property of the binary tree node that you want to search for. It can be either a specific key * value (`BinaryTreeNodeKey`) or a custom callback function (`MapCallback`) that determines * whether a node matches the desired property. @@ -238,13 +238,13 @@ export class BST = BSTNode> extends BinaryTree * @returns either the first node that matches the given nodeProperty and callback, or null if no * matching node is found. */ - override get = MapCallback>( - nodeProperty: BinaryTreeNodeKey | N, + override get>( + identifier: ReturnType | N, callback: C = this._defaultCallbackByKey as C, beginRoot = this.root, iterationType = this.iterationType ): N | null { - return this.getNodes(nodeProperty, callback, true, beginRoot, iterationType)[0] ?? null; + return this.getNodes(identifier, callback, true, beginRoot, iterationType)[0] ?? null; } /** @@ -271,7 +271,7 @@ export class BST = BSTNode> extends BinaryTree /** * The function `getNodes` retrieves nodes from a binary tree based on a given node property or key, * using either recursive or iterative traversal. - * @param {BinaryTreeNodeKey | N} nodeProperty - The `nodeProperty` parameter represents the property + * @param {ReturnType | N} identifier - The `nodeProperty` parameter represents the property * of the binary tree node that you want to search for. It can be either a `BinaryTreeNodeKey` or a * generic type `N`. * @param callback - The `callback` parameter is a function that takes a node as input and returns a @@ -289,8 +289,8 @@ export class BST = BSTNode> extends BinaryTree * traverse the binary tree. It can have one of the following values: * @returns an array of nodes (N[]). */ - override getNodes = MapCallback>( - nodeProperty: BinaryTreeNodeKey | N, + override getNodes>( + identifier: ReturnType | N, callback: C = this._defaultCallbackByKey as C, onlyOne = false, beginRoot: N | null = this.root, @@ -302,7 +302,7 @@ export class BST = BSTNode> extends BinaryTree if (iterationType === IterationType.RECURSIVE) { const _traverse = (cur: N) => { const callbackResult = callback(cur); - if (callbackResult === nodeProperty) { + if (callbackResult === identifier) { ans.push(cur); if (onlyOne) return; } @@ -310,8 +310,8 @@ export class BST = BSTNode> extends BinaryTree if (!cur.left && !cur.right) return; // TODO potential bug if (callback === this._defaultCallbackByKey) { - if (this._compare(cur.key, nodeProperty as number) === CP.gt) cur.left && _traverse(cur.left); - if (this._compare(cur.key, nodeProperty as number) === CP.lt) cur.right && _traverse(cur.right); + if (this._compare(cur.key, identifier as number) === CP.gt) cur.left && _traverse(cur.left); + if (this._compare(cur.key, identifier as number) === CP.lt) cur.right && _traverse(cur.right); } else { cur.left && _traverse(cur.left); cur.right && _traverse(cur.right); @@ -325,14 +325,14 @@ export class BST = BSTNode> extends BinaryTree const cur = queue.shift(); if (cur) { const callbackResult = callback(cur); - if (callbackResult === nodeProperty) { + if (callbackResult === identifier) { ans.push(cur); if (onlyOne) return ans; } // TODO potential bug if (callback === this._defaultCallbackByKey) { - if (this._compare(cur.key, nodeProperty as number) === CP.gt) cur.left && queue.push(cur.left); - if (this._compare(cur.key, nodeProperty as number) === CP.lt) cur.right && queue.push(cur.right); + if (this._compare(cur.key, identifier as number) === CP.gt) cur.left && queue.push(cur.left); + if (this._compare(cur.key, identifier as number) === CP.lt) cur.right && queue.push(cur.right); } else { cur.left && queue.push(cur.left); cur.right && queue.push(cur.right); @@ -355,7 +355,7 @@ export class BST = BSTNode> extends BinaryTree * @param {CP} lesserOrGreater - The `lesserOrGreater` parameter is used to determine whether to * traverse nodes that are lesser than, greater than, or equal to the `targetNode`. It can take one * of the following values: - * @param {N | BinaryTreeNodeKey | null} targetNode - The `targetNode` parameter in the + * @param {BinaryTreeNodeKey | N | null} targetNode - The `targetNode` parameter in the * `lesserOrGreaterTraverse` function is used to specify the node from which the traversal should * start. It can be either a reference to a specific node (`N`), the key of a node * (`BinaryTreeNodeKey`), or `null` to @@ -363,10 +363,10 @@ export class BST = BSTNode> extends BinaryTree * done recursively or iteratively. It can have two possible values: * @returns The function `lesserOrGreaterTraverse` returns an array of `MapCallbackReturn`. */ - lesserOrGreaterTraverse = MapCallback>( + lesserOrGreaterTraverse>( callback: C = this._defaultCallbackByKey as C, lesserOrGreater: CP = CP.lt, - targetNode: N | BinaryTreeNodeKey | null = this.root, + targetNode: BinaryTreeNodeKey | N | null = this.root, iterationType = this.iterationType ): ReturnType[] { if (typeof targetNode === 'number') targetNode = this.get(targetNode); diff --git a/src/data-structures/binary-tree/rb-tree.ts b/src/data-structures/binary-tree/rb-tree.ts index d8d1685..475f058 100644 --- a/src/data-structures/binary-tree/rb-tree.ts +++ b/src/data-structures/binary-tree/rb-tree.ts @@ -205,8 +205,8 @@ export class RBTree = RBTreeNode> extends BST< // node.right = null; // } // - // override delete(nodeOrKey: BinaryTreeNodeKey | N): BinaryTreeDeletedResult[] { - // const node = this.get(nodeOrKey); + // override delete(keyOrNode: BinaryTreeNodeKey | N): BinaryTreeDeletedResult[] { + // const node = this.get(keyOrNode); // const result: BinaryTreeDeletedResult[] = [{deleted: undefined, needBalanced: null}]; // if (!node) return result; // Node does not exist // diff --git a/src/data-structures/binary-tree/tree-multiset.ts b/src/data-structures/binary-tree/tree-multiset.ts index a36826b..464956b 100644 --- a/src/data-structures/binary-tree/tree-multiset.ts +++ b/src/data-structures/binary-tree/tree-multiset.ts @@ -5,8 +5,8 @@ * @copyright Copyright (c) 2022 Tyler Zeng * @license MIT License */ -import type {BinaryTreeNodeKey, TreeMultisetNodeNested, TreeMultisetOptions} from '../../types'; -import {BinaryTreeDeletedResult, CP, FamilyPosition, IterationType} from '../../types'; +import type {BinaryTreeNodeKey, DefaultMapCallback, TreeMultisetNodeNested, TreeMultisetOptions} from '../../types'; +import {BinaryTreeDeletedResult, CP, FamilyPosition, IterationType, MapCallback} from '../../types'; import {IBinaryTree} from '../../interfaces'; import {AVLTree, AVLTreeNode} from './avl-tree'; @@ -265,20 +265,26 @@ export class TreeMultiset = TreeMultiset /** * The `delete` function in a binary search tree deletes a node from the tree and returns the deleted * node along with the parent node that needs to be balanced. - * @param {N | BinaryTreeNodeKey} nodeOrKey - The `nodeOrKey` parameter can be either a node object - * (`N`) or a key value (`BinaryTreeNodeKey`). It represents the node or key that needs to be deleted - * from the binary tree. + * @param {ReturnType} identifier - The `identifier` parameter is either a + * `BinaryTreeNodeKey` or a generic type `N`. It represents the property of the node that we are + * searching for. It can be a specific key value or any other property of the node. + * @param callback - The `callback` parameter is a function that takes a node as input and returns a + * value. This value is compared with the `identifier` parameter to determine if the node should be + * included in the result. The `callback` parameter has a default value of + * `this._defaultCallbackByKey` * @param [ignoreCount=false] - A boolean flag indicating whether to ignore the count of the node * being deleted. If set to true, the count of the node will not be considered and the node will be * deleted regardless of its count. If set to false (default), the count of the node will be * decremented by 1 and * @returns The method `delete` returns an array of `BinaryTreeDeletedResult` objects. */ - override delete(nodeOrKey: N | BinaryTreeNodeKey, ignoreCount = false): BinaryTreeDeletedResult[] { + override delete>( + identifier: ReturnType, + callback: C = this._defaultCallbackByKey as C, ignoreCount = false): BinaryTreeDeletedResult[] { const bstDeletedResult: BinaryTreeDeletedResult[] = []; if (!this.root) return bstDeletedResult; - const curr: N | null = this.get(nodeOrKey); + const curr: N | null = this.get(identifier, callback); if (!curr) return bstDeletedResult; const parent: N | null = curr?.parent ? curr.parent : null; diff --git a/src/interfaces/binary-tree.ts b/src/interfaces/binary-tree.ts index 62a788b..ca63969 100644 --- a/src/interfaces/binary-tree.ts +++ b/src/interfaces/binary-tree.ts @@ -6,5 +6,5 @@ export interface IBinaryTree> { add(keyOrNode: BinaryTreeNodeKey | N | null, val?: N['val']): N | null | undefined; - delete(nodeOrKey: N | BinaryTreeNodeKey): BinaryTreeDeletedResult[]; + // delete(keyOrNode: BinaryTreeNodeKey | N): BinaryTreeDeletedResult[]; } diff --git a/src/types/helpers.ts b/src/types/helpers.ts index 077114d..93a5b64 100644 --- a/src/types/helpers.ts +++ b/src/types/helpers.ts @@ -1,9 +1,13 @@ +import {BinaryTreeNodeKey} from "./data-structures"; + export type Comparator = (a: T, b: T) => number; export type DFSOrderPattern = 'pre' | 'in' | 'post'; export type MapCallback = (node: N) => D; +export type DefaultMapCallback = (node: N) => D; + export type MapCallbackReturn = ReturnType>; export enum CP { diff --git a/test/unit/data-structures/binary-tree/tree-multiset.test.ts b/test/unit/data-structures/binary-tree/tree-multiset.test.ts index 6812143..e0f7125 100644 --- a/test/unit/data-structures/binary-tree/tree-multiset.test.ts +++ b/test/unit/data-structures/binary-tree/tree-multiset.test.ts @@ -73,7 +73,7 @@ describe('TreeMultiset operations test', () => { expect(bfsNodesAfterBalanced[0].key).toBe(8); expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16); - const removed11 = treeMultiset.delete(11, true); + const removed11 = treeMultiset.delete(11, undefined, true); expect(removed11 instanceof Array); expect(removed11[0]); expect(removed11[0].deleted); @@ -84,7 +84,7 @@ describe('TreeMultiset operations test', () => { expect(treeMultiset.getHeight(15)).toBe(1); - const removed1 = treeMultiset.delete(1, true); + const removed1 = treeMultiset.delete(1, undefined, true); expect(removed1 instanceof Array); expect(removed1[0]); expect(removed1[0].deleted); @@ -94,7 +94,7 @@ describe('TreeMultiset operations test', () => { expect(treeMultiset.getHeight()).toBe(4); - const removed4 = treeMultiset.delete(4, true); + const removed4 = treeMultiset.delete(4, undefined, true); expect(removed4 instanceof Array); expect(removed4[0]); expect(removed4[0].deleted); @@ -103,7 +103,7 @@ describe('TreeMultiset operations test', () => { expect(treeMultiset.isAVLBalanced()).toBe(true); expect(treeMultiset.getHeight()).toBe(4); - const removed10 = treeMultiset.delete(10, true); + const removed10 = treeMultiset.delete(10, undefined, true); expect(removed10 instanceof Array); expect(removed10[0]); expect(removed10[0].deleted); @@ -112,7 +112,7 @@ describe('TreeMultiset operations test', () => { expect(treeMultiset.getHeight()).toBe(3); - const removed15 = treeMultiset.delete(15, true); + const removed15 = treeMultiset.delete(15, undefined, true); expect(removed15 instanceof Array); expect(removed15[0]); expect(removed15[0].deleted); @@ -121,7 +121,7 @@ describe('TreeMultiset operations test', () => { expect(treeMultiset.isAVLBalanced()).toBe(true); expect(treeMultiset.getHeight()).toBe(3); - const removed5 = treeMultiset.delete(5, true); + const removed5 = treeMultiset.delete(5, undefined, true); expect(removed5 instanceof Array); expect(removed5[0]); expect(removed5[0].deleted); @@ -130,7 +130,7 @@ describe('TreeMultiset operations test', () => { expect(treeMultiset.isAVLBalanced()).toBe(true); expect(treeMultiset.getHeight()).toBe(3); - const removed13 = treeMultiset.delete(13, true); + const removed13 = treeMultiset.delete(13, undefined, true); expect(removed13 instanceof Array); expect(removed13[0]); expect(removed13[0].deleted); @@ -138,7 +138,7 @@ describe('TreeMultiset operations test', () => { expect(treeMultiset.isAVLBalanced()).toBe(true); expect(treeMultiset.getHeight()).toBe(3); - const removed3 = treeMultiset.delete(3, true); + const removed3 = treeMultiset.delete(3, undefined, true); expect(removed3 instanceof Array); expect(removed3[0]); expect(removed3[0].deleted); @@ -146,7 +146,7 @@ describe('TreeMultiset operations test', () => { expect(treeMultiset.isAVLBalanced()).toBe(true); expect(treeMultiset.getHeight()).toBe(3); - const removed8 = treeMultiset.delete(8, true); + const removed8 = treeMultiset.delete(8, undefined, true); expect(removed8 instanceof Array); expect(removed8[0]); expect(removed8[0].deleted); @@ -154,17 +154,17 @@ describe('TreeMultiset operations test', () => { expect(treeMultiset.isAVLBalanced()).toBe(true); expect(treeMultiset.getHeight()).toBe(3); - const removed6 = treeMultiset.delete(6, true); + const removed6 = treeMultiset.delete(6, undefined, true); expect(removed6 instanceof Array); expect(removed6[0]); expect(removed6[0].deleted); if (removed6[0].deleted) expect(removed6[0].deleted.key).toBe(6); - expect(treeMultiset.delete(6, true).length).toBe(0); + expect(treeMultiset.delete(6, undefined, true).length).toBe(0); expect(treeMultiset.isAVLBalanced()).toBe(true); expect(treeMultiset.getHeight()).toBe(2); - const removed7 = treeMultiset.delete(7, true); + const removed7 = treeMultiset.delete(7, undefined, true); expect(removed7 instanceof Array); expect(removed7[0]); expect(removed7[0].deleted); @@ -172,7 +172,7 @@ describe('TreeMultiset operations test', () => { expect(treeMultiset.isAVLBalanced()).toBe(true); expect(treeMultiset.getHeight()).toBe(2); - const removed9 = treeMultiset.delete(9, true); + const removed9 = treeMultiset.delete(9, undefined, true); expect(removed9 instanceof Array); expect(removed9[0]); expect(removed9[0].deleted); @@ -180,7 +180,7 @@ describe('TreeMultiset operations test', () => { expect(treeMultiset.isAVLBalanced()).toBe(true); expect(treeMultiset.getHeight()).toBe(2); - const removed14 = treeMultiset.delete(14, true); + const removed14 = treeMultiset.delete(14, undefined, true); expect(removed14 instanceof Array); expect(removed14[0]); expect(removed14[0].deleted); From af23af911ad3a987ce9ecbc10d5bd69eba7a0082 Mon Sep 17 00:00:00 2001 From: Revone Date: Fri, 27 Oct 2023 17:17:27 +0800 Subject: [PATCH 26/46] [binary-tree] renamed _loopType to _iterationType --- CHANGELOG.md | 2 +- package-lock.json | 36 ++++---- package.json | 10 +-- src/data-structures/binary-tree/avl-tree.ts | 21 ++--- .../binary-tree/binary-indexed-tree.ts | 2 +- .../binary-tree/binary-tree.ts | 83 ++++++++----------- .../binary-tree/tree-multiset.ts | 9 +- src/data-structures/graph/abstract-graph.ts | 21 +++-- src/data-structures/graph/directed-graph.ts | 3 +- src/data-structures/graph/undirected-graph.ts | 9 +- src/data-structures/hash/hash-map.ts | 2 +- src/data-structures/hash/tree-map.ts | 3 +- src/data-structures/hash/tree-set.ts | 3 +- .../linked-list/doubly-linked-list.ts | 1 - .../linked-list/singly-linked-list.ts | 2 +- src/data-structures/matrix/matrix.ts | 2 +- src/data-structures/matrix/vector2d.ts | 3 +- src/data-structures/queue/deque.ts | 9 +- src/data-structures/queue/queue.ts | 2 +- src/interfaces/binary-tree.ts | 4 +- src/types/data-structures/matrix/navigator.ts | 2 +- src/types/helpers.ts | 2 +- src/types/utils/utils.ts | 2 +- src/types/utils/validate-type.ts | 4 +- 24 files changed, 109 insertions(+), 128 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e34f57..182e92e 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.38.5](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) +## [v1.38.6](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) ### Changes diff --git a/package-lock.json b/package-lock.json index 469cb06..a984c7f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "data-structure-typed", - "version": "1.38.5", + "version": "1.38.6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "data-structure-typed", - "version": "1.38.5", + "version": "1.38.6", "license": "MIT", "devDependencies": { "@types/benchmark": "^2.1.3", @@ -15,17 +15,17 @@ "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", "auto-changelog": "^2.4.0", - "avl-tree-typed": "^1.38.4", + "avl-tree-typed": "^1.38.5", "benchmark": "^2.1.4", - "binary-tree-typed": "^1.38.4", - "bst-typed": "^1.38.4", + "binary-tree-typed": "^1.38.5", + "bst-typed": "^1.38.5", "dependency-cruiser": "^14.1.0", "eslint": "^8.50.0", "eslint-config-prettier": "^9.0.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.28.1", - "heap-typed": "^1.38.4", + "heap-typed": "^1.38.5", "istanbul-badges-readme": "^1.8.5", "jest": "^29.7.0", "prettier": "^3.0.3", @@ -2728,9 +2728,9 @@ } }, "node_modules/avl-tree-typed": { - "version": "1.38.4", - "resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.38.4.tgz", - "integrity": "sha512-m4+vC3t52CnPqMB5dxZI016OKMCxitk6vDsdqSadPHUeZd92E9LEQSHzgjdZ380FGcIZuz9q0IS7VTHR4F3+gg==", + "version": "1.38.5", + "resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.38.5.tgz", + "integrity": "sha512-rwVkzj8+N57YPCurFn+kmtxEd9xvE8QqYlOAkibRsEScN8E2z7cHkVlT0mxc26Q8HfLUvkqJjvEcwoLaHqYxzw==", "dev": true, "dependencies": { "data-structure-typed": "^1.38.4" @@ -2927,9 +2927,9 @@ } }, "node_modules/binary-tree-typed": { - "version": "1.38.4", - "resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.38.4.tgz", - "integrity": "sha512-InWS3ggQsmEyqgvaO+Veme/uTphUxaFQ1C7/9Bz07zcr8lV0riDsj0En9qwGTI8R4L32CpBL1cxQXJbk9Do45g==", + "version": "1.38.5", + "resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.38.5.tgz", + "integrity": "sha512-ksluya1YOjzQWMJzCNWnkjw/iinYvYMQhZYLwcdhwuiSy7nlDJpSxil3dh3sc3ffZDjCDi+FtTe2TOlOKBNzHQ==", "dev": true, "dependencies": { "data-structure-typed": "^1.38.4" @@ -3011,9 +3011,9 @@ } }, "node_modules/bst-typed": { - "version": "1.38.4", - "resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.38.4.tgz", - "integrity": "sha512-OCY+VQBfj8m8KYZullDuKrwYD8vzRBiIQ92hYDL3GWzuDMlTeEFUyIcDni0SR91JxRuUPbL7CuxN0fQRjDMKRg==", + "version": "1.38.5", + "resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.38.5.tgz", + "integrity": "sha512-JrfBhfqx9VFFQ/EMjG+CHCnEoJdrR3BZ0AGCpT2y6NbBWOdjuLghorVnvy85kiEpU06xSQewhqf3cWNz0pSrPA==", "dev": true, "dependencies": { "data-structure-typed": "^1.38.4" @@ -4771,9 +4771,9 @@ } }, "node_modules/heap-typed": { - "version": "1.38.4", - "resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.38.4.tgz", - "integrity": "sha512-fI+xbxoC3jpkmwqKIFRoJ8BGojd7FitEeYhwrkGpKnNMs9zp5dxA2qmrk+Gof0lDMuRca5CplVyInvGgL7cjzw==", + "version": "1.38.5", + "resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.38.5.tgz", + "integrity": "sha512-C9LQZScfnHGbhxL6wnUJEGwfg2oqdY10a0An3t/1pSVGEN91tmZzQS10BfYf5plQgF2fYNhZJbSkiuanUA0TgQ==", "dev": true, "dependencies": { "data-structure-typed": "^1.38.4" diff --git a/package.json b/package.json index dfce9bd..41e8e4f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "data-structure-typed", - "version": "1.38.5", + "version": "1.38.6", "description": "Data Structures of Javascript & TypeScript. Binary Tree, BST, Graph, Heap, Priority Queue, Linked List, Queue, Deque, Stack, AVL Tree, Tree Multiset, Trie, Directed Graph, Undirected Graph, Singly Linked List, Doubly Linked List, Max Heap, Max Priority Queue, Min Heap, Min Priority Queue.", "main": "dist/cjs/index.js", "module": "dist/mjs/index.js", @@ -61,17 +61,17 @@ "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", "auto-changelog": "^2.4.0", - "avl-tree-typed": "^1.38.4", + "avl-tree-typed": "^1.38.5", "benchmark": "^2.1.4", - "binary-tree-typed": "^1.38.4", - "bst-typed": "^1.38.4", + "binary-tree-typed": "^1.38.5", + "bst-typed": "^1.38.5", "dependency-cruiser": "^14.1.0", "eslint": "^8.50.0", "eslint-config-prettier": "^9.0.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.28.1", - "heap-typed": "^1.38.4", + "heap-typed": "^1.38.5", "istanbul-badges-readme": "^1.8.5", "jest": "^29.7.0", "prettier": "^3.0.3", diff --git a/src/data-structures/binary-tree/avl-tree.ts b/src/data-structures/binary-tree/avl-tree.ts index da4d2e6..e1c7bc7 100644 --- a/src/data-structures/binary-tree/avl-tree.ts +++ b/src/data-structures/binary-tree/avl-tree.ts @@ -6,20 +6,12 @@ * @license MIT License */ import {BST, BSTNode} from './bst'; -import type { - AVLTreeNodeNested, - AVLTreeOptions, - BinaryTreeDeletedResult, - BinaryTreeNodeKey, - DefaultMapCallback -} from '../../types'; +import type {AVLTreeNodeNested, AVLTreeOptions, BinaryTreeDeletedResult, BinaryTreeNodeKey} from '../../types'; +import {MapCallback} from '../../types'; import {IBinaryTree} from '../../interfaces'; -import {MapCallback} from "../../types"; -export class AVLTreeNode = AVLTreeNodeNested> extends BSTNode< - V, - FAMILY -> { +export class AVLTreeNode = AVLTreeNodeNested> extends + BSTNode { height: number; constructor(key: BinaryTreeNodeKey, val?: V) { @@ -82,7 +74,8 @@ export class AVLTree = AVLTreeNode> extends B */ override delete>( identifier: ReturnType, - callback: C = this._defaultCallbackByKey as C): BinaryTreeDeletedResult[] { + callback: C = this._defaultCallbackByKey as C + ): BinaryTreeDeletedResult[] { const deletedResults = super.delete(identifier, callback); for (const {needBalanced} of deletedResults) { if (needBalanced) { @@ -166,7 +159,7 @@ export class AVLTree = AVLTreeNode> extends B // 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-indexed-tree.ts b/src/data-structures/binary-tree/binary-indexed-tree.ts index da9dae0..467e918 100644 --- a/src/data-structures/binary-tree/binary-indexed-tree.ts +++ b/src/data-structures/binary-tree/binary-indexed-tree.ts @@ -17,7 +17,7 @@ export class BinaryIndexedTree { * @param - - `frequency`: The default frequency value. It is optional and has a default * value of 0. */ - constructor({frequency = 0, max}: {frequency?: number; max: number}) { + constructor({frequency = 0, max}: { frequency?: number; max: number }) { this._freq = frequency; this._max = max; this._freqMap = {0: 0}; diff --git a/src/data-structures/binary-tree/binary-tree.ts b/src/data-structures/binary-tree/binary-tree.ts index 70aa5d5..b18e848 100644 --- a/src/data-structures/binary-tree/binary-tree.ts +++ b/src/data-structures/binary-tree/binary-tree.ts @@ -116,8 +116,6 @@ export class BinaryTreeNode = * @template N - The type of the binary tree's nodes. */ export class BinaryTree = BinaryTreeNode> implements IBinaryTree { - private _loopType: IterationType = IterationType.ITERATIVE; - /** * Creates a new instance of BinaryTree. * @param {BinaryTreeOptions} [options] - The options for the binary tree. @@ -125,10 +123,27 @@ export class BinaryTree = BinaryTreeNode> constructor(options?: BinaryTreeOptions) { if (options !== undefined) { const {iterationType = IterationType.ITERATIVE} = options; - this._loopType = iterationType; + this._iterationType = iterationType; } } + private _iterationType: IterationType = IterationType.ITERATIVE; + + /** + * Get the iteration type used in the binary tree. + */ + get iterationType(): IterationType { + return this._iterationType; + } + + /** + * Set the iteration type for the binary tree. + * @param {IterationType} v - The new iteration type to set. + */ + set iterationType(v: IterationType) { + this._iterationType = v; + } + private _root: N | null = null; /** @@ -147,21 +162,6 @@ export class BinaryTree = BinaryTreeNode> return this._size; } - /** - * Get the iteration type used in the binary tree. - */ - get iterationType(): IterationType { - return this._loopType; - } - - /** - * Set the iteration type for the binary tree. - * @param {IterationType} v - The new iteration type to set. - */ - set iterationType(v: IterationType) { - this._loopType = v; - } - /** * Creates a new instance of BinaryTreeNode with the given key and value. * @param {BinaryTreeNodeKey} key - The key for the new node. @@ -222,7 +222,7 @@ export class BinaryTree = BinaryTreeNode> return; } - const key = typeof keyOrNode === 'number' ? keyOrNode : keyOrNode ? keyOrNode.key: undefined; + const key = typeof keyOrNode === 'number' ? keyOrNode : keyOrNode ? keyOrNode.key : undefined; const existNode = key !== undefined ? this.get(key, this._defaultCallbackByKey) : undefined; if (this.root) { @@ -284,14 +284,9 @@ export class BinaryTree = BinaryTreeNode> return keysOrNodes.length === this.addMany(keysOrNodes, data).length; } - delete>( - identifier: ReturnType | N - ): BinaryTreeDeletedResult[]; + delete>(identifier: ReturnType | N): BinaryTreeDeletedResult[]; - delete>( - identifier: ReturnType | N, - callback: C - ): BinaryTreeDeletedResult[]; + delete>(identifier: ReturnType | N, callback: C): BinaryTreeDeletedResult[]; /** * The `delete` function removes a node from a binary search tree and returns the deleted node along @@ -309,7 +304,8 @@ export class BinaryTree = BinaryTreeNode> */ delete>( identifier: ReturnType | N, - callback: C = this._defaultCallbackByKey as C): BinaryTreeDeletedResult[] { + callback: C = this._defaultCallbackByKey as C + ): BinaryTreeDeletedResult[] { const bstDeletedResult: BinaryTreeDeletedResult[] = []; if (!this.root) return bstDeletedResult; if (identifier instanceof BinaryTreeNode) callback = (node => node) as C; @@ -408,7 +404,7 @@ export class BinaryTree = BinaryTreeNode> return -1; } - const stack: {node: N; depth: number}[] = [{node: beginRoot, depth: 0}]; + const stack: { node: N; depth: number }[] = [{node: beginRoot, depth: 0}]; let maxHeight = 0; while (stack.length > 0) { @@ -492,26 +488,13 @@ export class BinaryTree = BinaryTreeNode> return this.getMinHeight(beginRoot) + 1 >= this.getHeight(beginRoot); } + getNodes>(identifier: ReturnType | N): N[]; - getNodes>( - identifier: ReturnType | N - ): N[]; + getNodes>(identifier: ReturnType | N, callback: C): N[]; - getNodes>( - identifier: ReturnType | N, - callback: C - ): N[]; + getNodes>(identifier: ReturnType | N, onlyOne: boolean): N[]; - getNodes>( - identifier: ReturnType | N, - onlyOne: boolean - ): N[]; - - getNodes>( - identifier: ReturnType | N, - callback: C, - onlyOne: boolean - ): N[]; + getNodes>(identifier: ReturnType | N, callback: C, onlyOne: boolean): N[]; getNodes>( identifier: ReturnType | N, @@ -528,7 +511,6 @@ export class BinaryTree = BinaryTreeNode> iterationType: IterationType ): N[]; - /** * The function `getNodes` returns an array of nodes that match a given node property, using either * recursive or iterative traversal. @@ -635,7 +617,12 @@ export class BinaryTree = BinaryTreeNode> get>(identifier: ReturnType | N, callback: C, beginRoot: N | null): N | null; - get>(identifier: ReturnType | N, callback: C, beginRoot: N | null, iterationType: IterationType): N | null; + get>( + identifier: ReturnType | N, + callback: C, + beginRoot: N | null, + iterationType: IterationType + ): N | null; /** * The function `get` returns the first node in a binary tree that matches the given property or key. @@ -900,7 +887,7 @@ export class BinaryTree = BinaryTreeNode> _traverse(beginRoot); } else { // 0: visit, 1: print - const stack: {opt: 0 | 1; node: N | null | undefined}[] = [{opt: 0, node: beginRoot}]; + const stack: { opt: 0 | 1; node: N | null | undefined }[] = [{opt: 0, node: beginRoot}]; while (stack.length > 0) { const cur = stack.pop(); diff --git a/src/data-structures/binary-tree/tree-multiset.ts b/src/data-structures/binary-tree/tree-multiset.ts index 464956b..9dbf025 100644 --- a/src/data-structures/binary-tree/tree-multiset.ts +++ b/src/data-structures/binary-tree/tree-multiset.ts @@ -5,7 +5,7 @@ * @copyright Copyright (c) 2022 Tyler Zeng * @license MIT License */ -import type {BinaryTreeNodeKey, DefaultMapCallback, TreeMultisetNodeNested, TreeMultisetOptions} from '../../types'; +import type {BinaryTreeNodeKey, TreeMultisetNodeNested, TreeMultisetOptions} from '../../types'; import {BinaryTreeDeletedResult, CP, FamilyPosition, IterationType, MapCallback} from '../../types'; import {IBinaryTree} from '../../interfaces'; import {AVLTree, AVLTreeNode} from './avl-tree'; @@ -37,8 +37,7 @@ export class TreeMultisetNode< */ export class TreeMultiset = TreeMultisetNode> extends AVLTree - implements IBinaryTree -{ + implements IBinaryTree { /** * The constructor function for a TreeMultiset class in TypeScript, which extends another class and sets an option to * merge duplicated values. @@ -280,7 +279,9 @@ export class TreeMultiset = TreeMultiset */ override delete>( identifier: ReturnType, - callback: C = this._defaultCallbackByKey as C, ignoreCount = false): BinaryTreeDeletedResult[] { + callback: C = this._defaultCallbackByKey as C, + ignoreCount = false + ): BinaryTreeDeletedResult[] { const bstDeletedResult: BinaryTreeDeletedResult[] = []; if (!this.root) return bstDeletedResult; diff --git a/src/data-structures/graph/abstract-graph.ts b/src/data-structures/graph/abstract-graph.ts index e820f6b..f93a731 100644 --- a/src/data-structures/graph/abstract-graph.ts +++ b/src/data-structures/graph/abstract-graph.ts @@ -105,8 +105,7 @@ export abstract class AbstractEdge { export abstract class AbstractGraph< V extends AbstractVertex = AbstractVertex, E extends AbstractEdge = AbstractEdge -> implements IGraph -{ +> implements IGraph { private _vertices: Map = new Map(); get vertices(): Map { @@ -554,14 +553,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); @@ -623,7 +622,7 @@ export abstract class AbstractGraph< if (vertexOrKey instanceof AbstractVertex) distMap.set(vertexOrKey, Infinity); } - const heap = new PriorityQueue<{key: number; val: V}>((a, b) => a.key - b.key); + const heap = new PriorityQueue<{ key: number; val: V }>((a, b) => a.key - b.key); heap.add({key: 0, val: srcVertex}); distMap.set(srcVertex, 0); @@ -852,7 +851,7 @@ export abstract class AbstractGraph< * `predecessor` property is a 2D array of vertices (or `null`) representing the predecessor vertices in the shortest * path between vertices in the */ - floyd(): {costs: number[][]; predecessor: (V | null)[][]} { + floyd(): { costs: number[][]; predecessor: (V | null)[][] } { const idAndVertices = [...this._vertices]; const n = idAndVertices.length; diff --git a/src/data-structures/graph/directed-graph.ts b/src/data-structures/graph/directed-graph.ts index 438ea75..f30a841 100644 --- a/src/data-structures/graph/directed-graph.ts +++ b/src/data-structures/graph/directed-graph.ts @@ -64,8 +64,7 @@ export class DirectedEdge extends AbstractEdge { export class DirectedGraph = DirectedVertex, E 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 b962047..a7a81ff 100644 --- a/src/data-structures/graph/undirected-graph.ts +++ b/src/data-structures/graph/undirected-graph.ts @@ -51,12 +51,11 @@ export class UndirectedEdge extends AbstractEdge { } export class UndirectedGraph< - V extends UndirectedVertex = UndirectedVertex, - E extends UndirectedEdge = UndirectedEdge - > + V extends UndirectedVertex = UndirectedVertex, + E extends UndirectedEdge = UndirectedEdge +> extends AbstractGraph - implements IGraph -{ + implements IGraph { /** * The constructor initializes a new Map object to store edges. */ diff --git a/src/data-structures/hash/hash-map.ts b/src/data-structures/hash/hash-map.ts index f3a5213..5231237 100644 --- a/src/data-structures/hash/hash-map.ts +++ b/src/data-structures/hash/hash-map.ts @@ -157,7 +157,7 @@ export class HashMap { } } - *entries(): IterableIterator<[K, V]> { + * entries(): IterableIterator<[K, V]> { for (const bucket of this.table) { if (bucket) { for (const [key, value] of bucket) { diff --git a/src/data-structures/hash/tree-map.ts b/src/data-structures/hash/tree-map.ts index fe86360..a6d743d 100644 --- a/src/data-structures/hash/tree-map.ts +++ b/src/data-structures/hash/tree-map.ts @@ -1 +1,2 @@ -export class TreeMap {} +export class TreeMap { +} diff --git a/src/data-structures/hash/tree-set.ts b/src/data-structures/hash/tree-set.ts index 591aeda..65f14db 100644 --- a/src/data-structures/hash/tree-set.ts +++ b/src/data-structures/hash/tree-set.ts @@ -1 +1,2 @@ -export class TreeSet {} +export class TreeSet { +} diff --git a/src/data-structures/linked-list/doubly-linked-list.ts b/src/data-structures/linked-list/doubly-linked-list.ts index 972f137..ab9ddc5 100644 --- a/src/data-structures/linked-list/doubly-linked-list.ts +++ b/src/data-structures/linked-list/doubly-linked-list.ts @@ -594,7 +594,6 @@ export class DoublyLinkedList { return false; } - /** * The `insertBefore` function inserts a new value before an existing value or node in a doubly linked list. * @param {E | DoublyLinkedListNode} existingValueOrNode - The existing value or node in the doubly linked list diff --git a/src/data-structures/linked-list/singly-linked-list.ts b/src/data-structures/linked-list/singly-linked-list.ts index c4e1da9..18233d8 100644 --- a/src/data-structures/linked-list/singly-linked-list.ts +++ b/src/data-structures/linked-list/singly-linked-list.ts @@ -485,7 +485,7 @@ export class SinglyLinkedList { return count; } - *[Symbol.iterator]() { + * [Symbol.iterator]() { let current = this.head; while (current) { diff --git a/src/data-structures/matrix/matrix.ts b/src/data-structures/matrix/matrix.ts index 8f27617..7e8ae4b 100644 --- a/src/data-structures/matrix/matrix.ts +++ b/src/data-structures/matrix/matrix.ts @@ -14,7 +14,7 @@ export class MatrixNTI2D { * given initial value or 0 if not provided. * @param options - An object containing the following properties: */ - constructor(options: {row: number; col: number; initialVal?: V}) { + constructor(options: { row: number; col: number; initialVal?: V }) { const {row, col, initialVal} = options; this._matrix = new Array(row).fill(undefined).map(() => new Array(col).fill(initialVal || 0)); } diff --git a/src/data-structures/matrix/vector2d.ts b/src/data-structures/matrix/vector2d.ts index 1b215ca..e8e4074 100644 --- a/src/data-structures/matrix/vector2d.ts +++ b/src/data-structures/matrix/vector2d.ts @@ -10,7 +10,8 @@ export class Vector2D { public x: number = 0, public y: number = 0, public w: number = 1 // needed for matrix multiplication - ) {} + ) { + } /** * The function checks if the x and y values of a point are both zero. diff --git a/src/data-structures/queue/deque.ts b/src/data-structures/queue/deque.ts index 3290ab1..9faabda 100644 --- a/src/data-structures/queue/deque.ts +++ b/src/data-structures/queue/deque.ts @@ -9,7 +9,8 @@ import {DoublyLinkedList} from '../linked-list'; // O(n) time complexity of obtaining the value // O(1) time complexity of adding at the beginning and the end -export class Deque extends DoublyLinkedList {} +export class Deque extends DoublyLinkedList { +} // O(1) time complexity of obtaining the value // O(n) time complexity of adding at the beginning and the end @@ -19,9 +20,9 @@ export class ObjectDeque { if (capacity !== undefined) this._capacity = capacity; } - private _nodes: {[key: number]: E} = {}; + private _nodes: { [key: number]: E } = {}; - get nodes(): {[p: number]: E} { + get nodes(): { [p: number]: E } { return this._nodes; } @@ -156,7 +157,7 @@ export class ObjectDeque { return this._size <= 0; } - protected _seNodes(value: {[p: number]: E}) { + protected _seNodes(value: { [p: number]: E }) { this._nodes = value; } diff --git a/src/data-structures/queue/queue.ts b/src/data-structures/queue/queue.ts index 4549b31..d11dd92 100644 --- a/src/data-structures/queue/queue.ts +++ b/src/data-structures/queue/queue.ts @@ -183,7 +183,7 @@ export class Queue { return new Queue(this.nodes.slice(this.offset)); } - *[Symbol.iterator]() { + * [Symbol.iterator]() { for (const item of this.nodes) { yield item; } diff --git a/src/interfaces/binary-tree.ts b/src/interfaces/binary-tree.ts index ca63969..a499659 100644 --- a/src/interfaces/binary-tree.ts +++ b/src/interfaces/binary-tree.ts @@ -1,10 +1,10 @@ import {BinaryTreeNode} from '../data-structures'; -import {BinaryTreeDeletedResult, BinaryTreeNodeKey} from '../types'; +import {BinaryTreeDeletedResult, BinaryTreeNodeKey, MapCallback} from '../types'; export interface IBinaryTree> { createNode(key: BinaryTreeNodeKey, val?: N['val']): N; add(keyOrNode: BinaryTreeNodeKey | N | null, val?: N['val']): N | null | undefined; - // delete(keyOrNode: BinaryTreeNodeKey | N): BinaryTreeDeletedResult[]; + delete>(identifier: ReturnType | N, callback: C): BinaryTreeDeletedResult[]; } diff --git a/src/types/data-structures/matrix/navigator.ts b/src/types/data-structures/matrix/navigator.ts index 9d8b9a9..34eddd9 100644 --- a/src/types/data-structures/matrix/navigator.ts +++ b/src/types/data-structures/matrix/navigator.ts @@ -1,6 +1,6 @@ export type Direction = 'up' | 'right' | 'down' | 'left'; -export type Turning = {[key in Direction]: Direction}; +export type Turning = { [key in Direction]: Direction }; export type NavigatorParams = { matrix: T[][]; diff --git a/src/types/helpers.ts b/src/types/helpers.ts index 93a5b64..0d80e9e 100644 --- a/src/types/helpers.ts +++ b/src/types/helpers.ts @@ -1,4 +1,4 @@ -import {BinaryTreeNodeKey} from "./data-structures"; +import {BinaryTreeNodeKey} from './data-structures'; export type Comparator = (a: T, b: T) => number; diff --git a/src/types/utils/utils.ts b/src/types/utils/utils.ts index f4d26c4..1f3a505 100644 --- a/src/types/utils/utils.ts +++ b/src/types/utils/utils.ts @@ -1,5 +1,5 @@ export type ToThunkFn = () => ReturnType; -export type Thunk = () => ReturnType & {__THUNK__: symbol}; +export type Thunk = () => ReturnType & { __THUNK__: symbol }; export type TrlFn = (...args: any[]) => any; export type TrlAsyncFn = (...args: any[]) => any; diff --git a/src/types/utils/validate-type.ts b/src/types/utils/validate-type.ts index ac9ff28..3ebf451 100644 --- a/src/types/utils/validate-type.ts +++ b/src/types/utils/validate-type.ts @@ -1,6 +1,6 @@ -export type KeyValueObject = {[key: string]: any}; +export type KeyValueObject = { [key: string]: any }; -export type KeyValueObjectWithKey = {[key: string]: any; key: string | number | symbol}; +export type KeyValueObjectWithKey = { [key: string]: any; key: string | number | symbol }; export type NonNumberNonObjectButDefined = string | boolean | symbol | null; From 06dc8bdc4dd8e95cb106275a2ed02cb48e1b3319 Mon Sep 17 00:00:00 2001 From: Revone Date: Fri, 27 Oct 2023 18:04:31 +0800 Subject: [PATCH 27/46] [binary-tree] Change the design so that when instantiating the BinaryTree data structure, there's no need to specify the node type; instead, use the second default generic parameter and its default value. --- package.json | 1 + src/data-structures/binary-tree/avl-tree.ts | 14 +++--- .../binary-tree/binary-tree.ts | 48 +++++++++---------- src/data-structures/binary-tree/bst.ts | 18 +++---- src/data-structures/binary-tree/rb-tree.ts | 10 ++-- .../binary-tree/tree-multiset.ts | 20 ++++---- src/interfaces/binary-tree.ts | 4 +- .../binary-tree/avl-tree.test.ts | 4 +- .../binary-tree/binary-tree.test.ts | 2 +- .../data-structures/binary-tree/bst.test.ts | 2 +- .../binary-tree/overall.test.ts | 2 +- .../binary-tree/tree-multiset.test.ts | 2 +- 12 files changed, 64 insertions(+), 63 deletions(-) diff --git a/package.json b/package.json index 41e8e4f..2d15880 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "lint:test": "eslint --fix 'test/**/*.{js,ts}'", "lint": "npm run lint:src && npm run lint:test", "format:src": "prettier --write 'src/**/*.{js,ts}'", + "format:specific": "prettier --write 'src/data-structures/binary-tree/bst.ts'", "format:test": "prettier --write 'test/**/*.{js,ts}'", "format": "npm run format:src && npm run format:test", "fix:src": "npm run lint:src && npm run format:src", diff --git a/src/data-structures/binary-tree/avl-tree.ts b/src/data-structures/binary-tree/avl-tree.ts index e1c7bc7..e232497 100644 --- a/src/data-structures/binary-tree/avl-tree.ts +++ b/src/data-structures/binary-tree/avl-tree.ts @@ -10,8 +10,8 @@ import type {AVLTreeNodeNested, AVLTreeOptions, BinaryTreeDeletedResult, BinaryT import {MapCallback} from '../../types'; import {IBinaryTree} from '../../interfaces'; -export class AVLTreeNode = AVLTreeNodeNested> extends - BSTNode { +export class AVLTreeNode = AVLTreeNodeNested> extends + BSTNode { height: number; constructor(key: BinaryTreeNodeKey, val?: V) { @@ -20,7 +20,7 @@ export class AVLTreeNode = AVLTre } } -export class AVLTree = AVLTreeNode> extends BST implements IBinaryTree { +export class AVLTree = AVLTreeNode> extends BST implements IBinaryTree{ /** * This is a constructor function for an AVL tree data structure in TypeScript. * @param {AVLTreeOptions} [options] - The `options` parameter is an optional object that can be passed to the @@ -36,12 +36,12 @@ export class AVLTree = AVLTreeNode> extends B * @param {BinaryTreeNodeKey} key - The key parameter is the key value that will be associated with * the new node. It is used to determine the position of the node in the binary search tree. * @param [val] - The parameter `val` is an optional value that can be assigned to the node. It is of - * type `N['val']`, which means it can be any value that is assignable to the `val` property of the + * type `V`, which means it can be any value that is assignable to the `val` property of the * node type `N`. * @returns a new AVLTreeNode object with the specified key and value. */ - override createNode(key: BinaryTreeNodeKey, val?: N['val']): N { - return new AVLTreeNode(key, val) as N; + override createNode(key: BinaryTreeNodeKey, val?: V): N { + return new AVLTreeNode(key, val) as N; } /** @@ -53,7 +53,7 @@ export class AVLTree = AVLTreeNode> extends B * are adding to the binary search tree. * @returns The method is returning the inserted node (`N`), `null`, or `undefined`. */ - override add(keyOrNode: BinaryTreeNodeKey | N | null, val?: N['val']): N | null | undefined { + override add(keyOrNode: BinaryTreeNodeKey | N | null, val?: V): N | null | undefined { // TODO support node as a param const inserted = super.add(keyOrNode, val); if (inserted) this._balancePath(inserted); diff --git a/src/data-structures/binary-tree/binary-tree.ts b/src/data-structures/binary-tree/binary-tree.ts index b18e848..5a30edf 100644 --- a/src/data-structures/binary-tree/binary-tree.ts +++ b/src/data-structures/binary-tree/binary-tree.ts @@ -23,9 +23,9 @@ import {Queue} from '../queue'; /** * Represents a node in a binary tree. * @template V - The type of data stored in the node. - * @template FAMILY - The type of the family relationship in the binary tree. + * @template N - The type of the family relationship in the binary tree. */ -export class BinaryTreeNode = BinaryTreeNodeNested> { +export class BinaryTreeNode = BinaryTreeNode>> { /** * The key associated with the node. */ @@ -39,7 +39,7 @@ export class BinaryTreeNode = /** * The parent node of the current node. */ - parent: FAMILY | null | undefined; + parent: N | null | undefined; /** * Creates a new instance of BinaryTreeNode. @@ -51,42 +51,42 @@ export class BinaryTreeNode = this.val = val; } - private _left: FAMILY | null | undefined; + private _left: N | null | undefined; /** * Get the left child node. */ - get left(): FAMILY | null | undefined { + get left(): N | null | undefined { return this._left; } /** * Set the left child node. - * @param {FAMILY | null | undefined} v - The left child node. + * @param {N | null | undefined} v - The left child node. */ - set left(v: FAMILY | null | undefined) { + set left(v: N | null | undefined) { if (v) { - v.parent = this as unknown as FAMILY; + v.parent = this as unknown as N; } this._left = v; } - private _right: FAMILY | null | undefined; + private _right: N | null | undefined; /** * Get the right child node. */ - get right(): FAMILY | null | undefined { + get right(): N | null | undefined { return this._right; } /** * Set the right child node. - * @param {FAMILY | null | undefined} v - The right child node. + * @param {N | null | undefined} v - The right child node. */ - set right(v: FAMILY | null | undefined) { + set right(v: N | null | undefined) { if (v) { - v.parent = this as unknown as FAMILY; + v.parent = this as unknown as N; } this._right = v; } @@ -96,7 +96,7 @@ export class BinaryTreeNode = * @returns {FamilyPosition} - The family position of the node. */ get familyPosition(): FamilyPosition { - const that = this as unknown as FAMILY; + const that = this as unknown as N; if (!this.parent) { return this.left || this.right ? FamilyPosition.ROOT : FamilyPosition.ISOLATED; } @@ -115,7 +115,7 @@ export class BinaryTreeNode = * Represents a binary tree data structure. * @template N - The type of the binary tree's nodes. */ -export class BinaryTree = BinaryTreeNode> implements IBinaryTree { +export class BinaryTree = BinaryTreeNode> implements IBinaryTree{ /** * Creates a new instance of BinaryTree. * @param {BinaryTreeOptions} [options] - The options for the binary tree. @@ -165,11 +165,11 @@ export class BinaryTree = BinaryTreeNode> /** * Creates a new instance of BinaryTreeNode with the given key and value. * @param {BinaryTreeNodeKey} key - The key for the new node. - * @param {N['val']} val - The value for the new node. + * @param {V} val - The value for the new node. * @returns {N} - The newly created BinaryTreeNode. */ - createNode(key: BinaryTreeNodeKey, val?: N['val']): N { - return new BinaryTreeNode(key, val) as N; + createNode(key: BinaryTreeNodeKey, val?: V): N { + return new BinaryTreeNode(key, val) as N; } /** @@ -191,10 +191,10 @@ export class BinaryTree = BinaryTreeNode> /** * Add a node with the given key and value to the binary tree. * @param {BinaryTreeNodeKey | N | null} keyOrNode - The key or node to add to the binary tree. - * @param {N['val']} val - The value for the new node (optional). + * @param {V} val - The value for the new node (optional). * @returns {N | null | undefined} - The inserted node, or null if nothing was inserted, or undefined if the operation failed. */ - add(keyOrNode: BinaryTreeNodeKey | N | null, val?: N['val']): N | null | undefined { + add(keyOrNode: BinaryTreeNodeKey | N | null, val?: V): N | null | undefined { const _bfs = (root: N, newNode: N | null): N | undefined | null => { const queue = new Queue([root]); while (queue.size > 0) { @@ -249,12 +249,12 @@ export class BinaryTree = BinaryTreeNode> * values, and adds them to the binary tree. * @param {(BinaryTreeNodeKey | null)[] | (N | null)[]} keysOrNodes - An array of BinaryTreeNodeKey or BinaryTreeNode * objects, or null values. - * @param {N['val'][]} [values] - The `values` parameter is an optional array of values (`N['val'][]`) that corresponds to + * @param {V[]} [values] - The `values` parameter is an optional array of values (`V[]`) that corresponds to * the nodes or node IDs being added. It is used to set the value of each node being added. If `values` is not provided, * the value of the nodes will be `undefined`. * @returns The function `addMany` returns an array of `N`, `null`, or `undefined` values. */ - addMany(keysOrNodes: (BinaryTreeNodeKey | null)[] | (N | null)[], values?: N['val'][]): (N | null | undefined)[] { + addMany(keysOrNodes: (BinaryTreeNodeKey | null)[] | (N | null)[], values?: V[]): (N | null | undefined)[] { // TODO not sure addMany not be run multi times return keysOrNodes.map((keyOrNode, i) => { if (keyOrNode instanceof BinaryTreeNode) { @@ -274,12 +274,12 @@ export class BinaryTree = BinaryTreeNode> * The `refill` function clears the binary tree and adds multiple nodes with the given IDs or nodes and optional data. * @param {(BinaryTreeNodeKey | N)[]} keysOrNodes - The `keysOrNodes` parameter is an array that can contain either * `BinaryTreeNodeKey` or `N` values. - * @param {N[] | Array} [data] - The `data` parameter is an optional array of values that will be assigned to + * @param {N[] | Array} [data] - The `data` parameter is an optional array of values that will be assigned to * the nodes being added. If provided, the length of the `data` array should be equal to the length of the `keysOrNodes` * array. Each value in the `data` array will be assigned to the * @returns The method is returning a boolean value. */ - refill(keysOrNodes: (BinaryTreeNodeKey | null)[] | (N | null)[], data?: N[] | Array): boolean { + refill(keysOrNodes: (BinaryTreeNodeKey | null)[] | (N | null)[], data?: Array): boolean { this.clear(); return keysOrNodes.length === this.addMany(keysOrNodes, data).length; } diff --git a/src/data-structures/binary-tree/bst.ts b/src/data-structures/binary-tree/bst.ts index 1e632aa..9c2a22d 100644 --- a/src/data-structures/binary-tree/bst.ts +++ b/src/data-structures/binary-tree/bst.ts @@ -18,13 +18,13 @@ import {BinaryTree, BinaryTreeNode} from './binary-tree'; import {IBinaryTree} from '../../interfaces'; import {Queue} from '../queue'; -export class BSTNode = BSTNodeNested> extends BinaryTreeNode { +export class BSTNode = BSTNodeNested> extends BinaryTreeNode { constructor(key: BinaryTreeNodeKey, val?: V) { super(key, val); } } -export class BST = BSTNode> extends BinaryTree implements IBinaryTree { +export class BST = BSTNode> extends BinaryTree implements IBinaryTree { /** * The constructor function initializes a binary search tree object with an optional comparator * function. @@ -49,8 +49,8 @@ export class BST = BSTNode> extends BinaryTree * represents the value associated with the node in a binary search tree. * @returns a new instance of the BSTNode class with the specified key and value. */ - override createNode(key: BinaryTreeNodeKey, val?: N['val']): N { - return new BSTNode(key, val) as N; + override createNode(key: BinaryTreeNodeKey, val?: V): N { + return new BSTNode(key, val) as N; } /** @@ -63,7 +63,7 @@ export class BST = BSTNode> extends BinaryTree * @returns the inserted node (N) if it was successfully added to the binary search tree. If the node * was not added or if the parameters were invalid, it returns null or undefined. */ - override add(keyOrNode: BinaryTreeNodeKey | N | null, val?: N['val']): N | null | undefined { + override add(keyOrNode: BinaryTreeNodeKey | N | null, val?: V): N | null | undefined { // TODO support node as a parameter let inserted: N | null = null; let newNode: N | null = null; @@ -136,7 +136,7 @@ export class BST = BSTNode> extends BinaryTree * represents an array of keys or nodes that need to be added to the binary search tree. It can be an * array of `BinaryTreeNodeKey` or `N` (which represents the node type in the binary search tree) or * `null - * @param {N['val'][]} data - The values of tree nodes + * @param {V[]} data - The values of tree nodes * @param {boolean} isBalanceAdd - If true the nodes will be balance inserted in binary search method. * @param iterationType - The `iterationType` parameter determines the type of iteration to be used. * It can have two possible values: @@ -145,7 +145,7 @@ export class BST = BSTNode> extends BinaryTree override addMany( keysOrNodes: (BinaryTreeNodeKey | null)[] | (N | null)[], - data?: N['val'][], + data?: V[], isBalanceAdd = true, iterationType = this.iterationType ): (N | null | undefined)[] { @@ -174,7 +174,7 @@ export class BST = BSTNode> extends BinaryTree } let sortedKeysOrNodes: (number | N | null)[] = [], - sortedData: (N['val'] | undefined)[] | undefined = []; + sortedData: (V | undefined)[] | undefined = []; if (isNodeOrNullTuple(combinedArr)) { sorted = combinedArr.sort((a, b) => a[0].key - b[0].key); @@ -185,7 +185,7 @@ export class BST = BSTNode> extends BinaryTree } sortedKeysOrNodes = sorted.map(([keyOrNode]) => keyOrNode); sortedData = sorted.map(([, val]) => val); - const recursive = (arr: (BinaryTreeNodeKey | null | N)[], data?: N['val'][]) => { + const recursive = (arr: (BinaryTreeNodeKey | null | N)[], data?: (V | undefined)[]) => { if (arr.length === 0) return; const mid = Math.floor((arr.length - 1) / 2); diff --git a/src/data-structures/binary-tree/rb-tree.ts b/src/data-structures/binary-tree/rb-tree.ts index 475f058..b8ef6db 100644 --- a/src/data-structures/binary-tree/rb-tree.ts +++ b/src/data-structures/binary-tree/rb-tree.ts @@ -2,9 +2,9 @@ import {BinaryTreeNodeKey, RBColor, RBTreeNodeNested, RBTreeOptions} from '../.. import {IBinaryTree} from '../../interfaces'; import {BST, BSTNode} from './bst'; -export class RBTreeNode = RBTreeNodeNested> extends BSTNode< +export class RBTreeNode = RBTreeNodeNested> extends BSTNode< V, - FAMILY + N > { constructor(key: BinaryTreeNodeKey, val?: V) { super(key, val); @@ -22,16 +22,16 @@ export class RBTreeNode = RBTreeNo } } -export class RBTree = RBTreeNode> extends BST implements IBinaryTree { +export class RBTree = RBTreeNode> extends BST implements IBinaryTree { constructor(options?: RBTreeOptions) { super(options); } - override createNode(key: BinaryTreeNodeKey, val?: N['val']): N { + override createNode(key: BinaryTreeNodeKey, val?: V): N { return new RBTreeNode(key, val) as N; } - // override add(keyOrNode: BinaryTreeNodeKey | N | null, val?: N['val']): N | null | undefined { + // override add(keyOrNode: BinaryTreeNodeKey | N | null, val?: V): N | null | undefined { // const inserted = super.add(keyOrNode, val); // if (inserted) this._fixInsertViolation(inserted); // return inserted; diff --git a/src/data-structures/binary-tree/tree-multiset.ts b/src/data-structures/binary-tree/tree-multiset.ts index 9dbf025..3cc76f4 100644 --- a/src/data-structures/binary-tree/tree-multiset.ts +++ b/src/data-structures/binary-tree/tree-multiset.ts @@ -12,8 +12,8 @@ import {AVLTree, AVLTreeNode} from './avl-tree'; export class TreeMultisetNode< V = any, - FAMILY extends TreeMultisetNode = TreeMultisetNodeNested -> extends AVLTreeNode { + N extends TreeMultisetNode = TreeMultisetNodeNested +> extends AVLTreeNode { count: number; /** @@ -35,9 +35,9 @@ export class TreeMultisetNode< /** * The only distinction between a TreeMultiset and a AVLTree lies in the ability of the former to store duplicate nodes through the utilization of counters. */ -export class TreeMultiset = TreeMultisetNode> - extends AVLTree - implements IBinaryTree { +export class TreeMultiset = TreeMultisetNode> + extends AVLTree + implements IBinaryTree { /** * The constructor function for a TreeMultiset class in TypeScript, which extends another class and sets an option to * merge duplicated values. @@ -63,7 +63,7 @@ export class TreeMultiset = TreeMultiset * occurrences of the value in the binary search tree node. If not provided, the count will default to 1. * @returns A new instance of the BSTNode class with the specified key, value, and count (if provided). */ - override createNode(key: BinaryTreeNodeKey, val?: N['val'], count?: number): N { + override createNode(key: BinaryTreeNodeKey, val?: V, count?: number): N { return new TreeMultisetNode(key, val, count) as N; } @@ -80,7 +80,7 @@ export class TreeMultiset = TreeMultiset * count is specified, the default count will be 1. * @returns The function `add` returns a value of type `N | null | undefined`. */ - override add(keyOrNode: BinaryTreeNodeKey | N | null, val?: N['val'], count = 1): N | null | undefined { + override add(keyOrNode: BinaryTreeNodeKey | N | null, val?: V, count = 1): N | null | undefined { let inserted: N | null | undefined = undefined, newNode: N | null; if (keyOrNode instanceof TreeMultisetNode) { @@ -186,14 +186,14 @@ export class TreeMultiset = TreeMultiset * inserted nodes. * @param {(BinaryTreeNodeKey | null)[] | (N | null)[]} keysOrNodes - An array of keys or nodes to be * added to the multiset. Each element can be either a BinaryTreeNodeKey or a TreeMultisetNode. - * @param {N['val'][]} [data] - The `data` parameter is an optional array of values that correspond + * @param {V[]} [data] - The `data` parameter is an optional array of values that correspond * to the keys or nodes being added to the multiset. It is used to associate additional data with * each key or node. * @returns The function `addMany` returns an array of `N`, `null`, or `undefined` values. */ override addMany( keysOrNodes: (BinaryTreeNodeKey | null)[] | (N | null)[], - data?: N['val'][] + data?: V[] ): (N | null | undefined)[] { const inserted: (N | null | undefined)[] = []; @@ -206,7 +206,7 @@ export class TreeMultiset = TreeMultiset } if (keyOrNode === null) { - inserted.push(this.add(NaN, null, 0)); + inserted.push(this.add(NaN, undefined, 0)); continue; } diff --git a/src/interfaces/binary-tree.ts b/src/interfaces/binary-tree.ts index a499659..61afbfd 100644 --- a/src/interfaces/binary-tree.ts +++ b/src/interfaces/binary-tree.ts @@ -1,7 +1,7 @@ import {BinaryTreeNode} from '../data-structures'; -import {BinaryTreeDeletedResult, BinaryTreeNodeKey, MapCallback} from '../types'; +import {BinaryTreeDeletedResult, BinaryTreeNodeKey, BinaryTreeNodeNested, MapCallback} from '../types'; -export interface IBinaryTree> { +export interface IBinaryTree = BinaryTreeNodeNested> { createNode(key: BinaryTreeNodeKey, val?: N['val']): N; add(keyOrNode: BinaryTreeNodeKey | N | null, val?: N['val']): N | null | undefined; diff --git a/test/unit/data-structures/binary-tree/avl-tree.test.ts b/test/unit/data-structures/binary-tree/avl-tree.test.ts index 1bd8174..01c0e16 100644 --- a/test/unit/data-structures/binary-tree/avl-tree.test.ts +++ b/test/unit/data-structures/binary-tree/avl-tree.test.ts @@ -3,7 +3,7 @@ import {AVLTree, AVLTreeNode, CP} from '../../../../src'; describe('AVL Tree Test', () => { it('should perform various operations on a AVL Tree', () => { const arr = [11, 3, 15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5]; - const tree = new AVLTree>(); + const tree = new AVLTree(); for (const i of arr) tree.add(i, i); @@ -110,7 +110,7 @@ describe('AVL Tree Test', () => { }); describe('AVLTree APIs test', () => { - const avl = new AVLTree>(); + const avl = new AVLTree<{id: number; text: string}>(); beforeEach(() => { avl.clear(); }); diff --git a/test/unit/data-structures/binary-tree/binary-tree.test.ts b/test/unit/data-structures/binary-tree/binary-tree.test.ts index fcb5f4e..49d87d8 100644 --- a/test/unit/data-structures/binary-tree/binary-tree.test.ts +++ b/test/unit/data-structures/binary-tree/binary-tree.test.ts @@ -196,7 +196,7 @@ describe('BinaryTree Morris Traversal', () => { }); describe('BinaryTree APIs test', () => { - const avl = new AVLTree>(); + const avl = new AVLTree<{id: number; text: string}>(); beforeEach(() => { avl.clear(); }); diff --git a/test/unit/data-structures/binary-tree/bst.test.ts b/test/unit/data-structures/binary-tree/bst.test.ts index 9683af9..872223f 100644 --- a/test/unit/data-structures/binary-tree/bst.test.ts +++ b/test/unit/data-structures/binary-tree/bst.test.ts @@ -189,7 +189,7 @@ describe('BST operations test', () => { }); it('should perform various operations on a Binary Search Tree with object values', () => { - const objBST = new BST>(); + const objBST = new BST<{key: number; keyA: number}>(); expect(objBST).toBeInstanceOf(BST); objBST.add(11, {key: 11, keyA: 11}); objBST.add(3, {key: 3, keyA: 3}); diff --git a/test/unit/data-structures/binary-tree/overall.test.ts b/test/unit/data-structures/binary-tree/overall.test.ts index 5325180..e4301b1 100644 --- a/test/unit/data-structures/binary-tree/overall.test.ts +++ b/test/unit/data-structures/binary-tree/overall.test.ts @@ -29,7 +29,7 @@ describe('Overall BinaryTree Test', () => { bfsIDs[0] === 11; // true expect(bfsIDs[0]).toBe(11); - const objBST = new BST>(); + const objBST = new BST<{key: number; keyA: number}>(); objBST.add(11, {key: 11, keyA: 11}); objBST.add(3, {key: 3, keyA: 3}); diff --git a/test/unit/data-structures/binary-tree/tree-multiset.test.ts b/test/unit/data-structures/binary-tree/tree-multiset.test.ts index e0f7125..795ce47 100644 --- a/test/unit/data-structures/binary-tree/tree-multiset.test.ts +++ b/test/unit/data-structures/binary-tree/tree-multiset.test.ts @@ -206,7 +206,7 @@ describe('TreeMultiset operations test', () => { }); it('should perform various operations on a Binary Search Tree with object values', () => { - const objTreeMultiset = new TreeMultiset>(); + const objTreeMultiset = new TreeMultiset<{key: number; keyA: number}>(); expect(objTreeMultiset).toBeInstanceOf(TreeMultiset); objTreeMultiset.add(11, {key: 11, keyA: 11}); objTreeMultiset.add(3, {key: 3, keyA: 3}); From edad774263feee4cf47670f36e43519a239fe8f2 Mon Sep 17 00:00:00 2001 From: Revone Date: Fri, 27 Oct 2023 18:07:40 +0800 Subject: [PATCH 28/46] [project] IDE formated --- src/data-structures/binary-tree/avl-tree.ts | 5 ++--- src/data-structures/binary-tree/binary-tree.ts | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/data-structures/binary-tree/avl-tree.ts b/src/data-structures/binary-tree/avl-tree.ts index e232497..b22c120 100644 --- a/src/data-structures/binary-tree/avl-tree.ts +++ b/src/data-structures/binary-tree/avl-tree.ts @@ -10,8 +10,7 @@ import type {AVLTreeNodeNested, AVLTreeOptions, BinaryTreeDeletedResult, BinaryT import {MapCallback} from '../../types'; import {IBinaryTree} from '../../interfaces'; -export class AVLTreeNode = AVLTreeNodeNested> extends - BSTNode { +export class AVLTreeNode = AVLTreeNodeNested> extends BSTNode { height: number; constructor(key: BinaryTreeNodeKey, val?: V) { @@ -20,7 +19,7 @@ export class AVLTreeNode = AVLTreeNodeNeste } } -export class AVLTree = AVLTreeNode> extends BST implements IBinaryTree{ +export class AVLTree = AVLTreeNode> extends BST implements IBinaryTree { /** * This is a constructor function for an AVL tree data structure in TypeScript. * @param {AVLTreeOptions} [options] - The `options` parameter is an optional object that can be passed to the diff --git a/src/data-structures/binary-tree/binary-tree.ts b/src/data-structures/binary-tree/binary-tree.ts index 5a30edf..0c897b3 100644 --- a/src/data-structures/binary-tree/binary-tree.ts +++ b/src/data-structures/binary-tree/binary-tree.ts @@ -115,7 +115,7 @@ export class BinaryTreeNode = BinaryTree * Represents a binary tree data structure. * @template N - The type of the binary tree's nodes. */ -export class BinaryTree = BinaryTreeNode> implements IBinaryTree{ +export class BinaryTree = BinaryTreeNode> implements IBinaryTree { /** * Creates a new instance of BinaryTree. * @param {BinaryTreeOptions} [options] - The options for the binary tree. From f90afe0b5745bc105c470b53c7ec0a40f47c9b89 Mon Sep 17 00:00:00 2001 From: Revone Date: Fri, 27 Oct 2023 22:30:52 +0800 Subject: [PATCH 29/46] [binary-tree] The binary tree's BFS and level-order traversal results should be the same. However, for convenience, we provide an additional method called listLevels to display traversal results in levels. --- .editorconfig | 23 +++--- CHANGELOG.md | 2 +- README.md | 2 +- package-lock.json | 50 ++++++------- package.json | 13 ++-- src/data-structures/binary-tree/avl-tree.ts | 4 +- .../binary-tree/binary-tree.ts | 73 ++++++++++++++++--- src/data-structures/binary-tree/bst.ts | 2 +- src/data-structures/binary-tree/rb-tree.ts | 7 +- .../binary-tree/tree-multiset.ts | 7 +- test/integration/bst.test.ts | 2 +- test/integration/index.html | 2 +- .../binary-tree/avl-tree.test.ts | 4 +- .../binary-tree/binary-tree.test.ts | 25 ++++++- .../data-structures/binary-tree/bst.test.ts | 14 +--- .../binary-tree/overall.test.ts | 40 +++++----- .../binary-tree/tree-multiset.test.ts | 4 +- test/unit/data-structures/heap/heap.test.ts | 4 +- .../linked-list/doubly-linked-list.test.ts | 2 +- .../linked-list/singly-linked-list.test.ts | 4 +- .../priority-queue/max-priority-queue.test.ts | 4 +- test/utils/big-o.ts | 2 +- tsup.config.js | 15 +++- 23 files changed, 190 insertions(+), 115 deletions(-) diff --git a/.editorconfig b/.editorconfig index f709510..7396604 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,15 +1,18 @@ # Editor configuration, see http://editorconfig.org -root = true -[*] -charset = utf-8 -end_of_line = lf -indent_style = space -indent_size = 2 -insert_final_newline = true -trim_trailing_whitespace = true -[*.md] + +root=true # represents the top-level EditorConfig configuration file + +[*] # means applicable to all files +charset = utf-8 #Set the file character set to utf-8 +indent_style = space #Indent style (tab | space) +indent_size = 2 # indent size +end_of_line = lf # Control line break type (lf | cr | crlf) +trim_trailing_whitespace = true # Remove any whitespace characters at the beginning of the line +insert_final_newline = true #Always insert a new line at the end of the file + +[*.md] # Indicates that only md files apply the following rules max_line_length = off trim_trailing_whitespace = false -[*.yml] + [*.{yml,yaml}] indent_size = 2 diff --git a/CHANGELOG.md b/CHANGELOG.md index 182e92e..eea0a8b 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.38.6](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) +## [v1.38.8](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) ### Changes diff --git a/README.md b/README.md index b6a6055..fe1284f 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ import { ```html - + ``` ```js diff --git a/package-lock.json b/package-lock.json index a984c7f..33961d3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "data-structure-typed", - "version": "1.38.6", + "version": "1.38.8", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "data-structure-typed", - "version": "1.38.6", + "version": "1.38.8", "license": "MIT", "devDependencies": { "@types/benchmark": "^2.1.3", @@ -15,17 +15,17 @@ "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", "auto-changelog": "^2.4.0", - "avl-tree-typed": "^1.38.5", + "avl-tree-typed": "^1.38.7", "benchmark": "^2.1.4", - "binary-tree-typed": "^1.38.5", - "bst-typed": "^1.38.5", + "binary-tree-typed": "^1.38.7", + "bst-typed": "^1.38.7", "dependency-cruiser": "^14.1.0", "eslint": "^8.50.0", "eslint-config-prettier": "^9.0.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.28.1", - "heap-typed": "^1.38.5", + "heap-typed": "^1.38.7", "istanbul-badges-readme": "^1.8.5", "jest": "^29.7.0", "prettier": "^3.0.3", @@ -2728,12 +2728,12 @@ } }, "node_modules/avl-tree-typed": { - "version": "1.38.5", - "resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.38.5.tgz", - "integrity": "sha512-rwVkzj8+N57YPCurFn+kmtxEd9xvE8QqYlOAkibRsEScN8E2z7cHkVlT0mxc26Q8HfLUvkqJjvEcwoLaHqYxzw==", + "version": "1.38.7", + "resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.38.7.tgz", + "integrity": "sha512-B5lOJoYI/8Y+WUI+atnN8FtKwjOZk6X91O55Qu8p6nauduOZlJvx0HtN3mmTKk0bYNqEHDNK5iyHD60Rwqx5Hw==", "dev": true, "dependencies": { - "data-structure-typed": "^1.38.4" + "data-structure-typed": "^1.38.7" } }, "node_modules/babel-jest": { @@ -2927,12 +2927,12 @@ } }, "node_modules/binary-tree-typed": { - "version": "1.38.5", - "resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.38.5.tgz", - "integrity": "sha512-ksluya1YOjzQWMJzCNWnkjw/iinYvYMQhZYLwcdhwuiSy7nlDJpSxil3dh3sc3ffZDjCDi+FtTe2TOlOKBNzHQ==", + "version": "1.38.7", + "resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.38.7.tgz", + "integrity": "sha512-Z/xh9iEg0r7WNUzRAPa/yPHJJpc3s0jgC8bioiKgoIU67wxV8Mbn5WbuF+m2oXXpYyaM4qhC+AGU43OkHss7rQ==", "dev": true, "dependencies": { - "data-structure-typed": "^1.38.4" + "data-structure-typed": "^1.38.7" } }, "node_modules/brace-expansion": { @@ -3011,12 +3011,12 @@ } }, "node_modules/bst-typed": { - "version": "1.38.5", - "resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.38.5.tgz", - "integrity": "sha512-JrfBhfqx9VFFQ/EMjG+CHCnEoJdrR3BZ0AGCpT2y6NbBWOdjuLghorVnvy85kiEpU06xSQewhqf3cWNz0pSrPA==", + "version": "1.38.7", + "resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.38.7.tgz", + "integrity": "sha512-jo8owKRnKPOAbdqR6SmvWjF2yceqN/3j736xujDum4Uh8devBLguV7m49HUv7pfkKAx8uwuuE+6b0dPQaxR4vA==", "dev": true, "dependencies": { - "data-structure-typed": "^1.38.4" + "data-structure-typed": "^1.38.7" } }, "node_modules/buffer-from": { @@ -3413,9 +3413,9 @@ } }, "node_modules/data-structure-typed": { - "version": "1.38.4", - "resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.38.4.tgz", - "integrity": "sha512-Yt9yjrx3Cm030z3o/6hr+AG0n+ZpWd+YpG2YiwxNwOT+hTZ6PYWt9MI+UVpiJSW/1Mrr0gchLlipU1r7l+UI/w==", + "version": "1.38.7", + "resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.38.7.tgz", + "integrity": "sha512-YPV3hlUFTAG93+LoW8eaMv+KS4s9PF5MfpvvUkZybuR7WxqLtamCXWE1o3TRKkYFa9MEguxcq5ZaniCdeLg8Mw==", "dev": true }, "node_modules/debug": { @@ -4771,12 +4771,12 @@ } }, "node_modules/heap-typed": { - "version": "1.38.5", - "resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.38.5.tgz", - "integrity": "sha512-C9LQZScfnHGbhxL6wnUJEGwfg2oqdY10a0An3t/1pSVGEN91tmZzQS10BfYf5plQgF2fYNhZJbSkiuanUA0TgQ==", + "version": "1.38.7", + "resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.38.7.tgz", + "integrity": "sha512-9ASCFfeKkN8iPFqgRUskah+a3RAxG4f+sbTVE8xRv4xwHpPLfwGo7gbJLkiJ5fkV+0PRN/ZXUkQPT5cI0XcbZQ==", "dev": true, "dependencies": { - "data-structure-typed": "^1.38.4" + "data-structure-typed": "^1.38.7" } }, "node_modules/html-escaper": { diff --git a/package.json b/package.json index 2d15880..de686d2 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,11 @@ { "name": "data-structure-typed", - "version": "1.38.6", + "version": "1.38.8", "description": "Data Structures of Javascript & TypeScript. Binary Tree, BST, Graph, Heap, Priority Queue, Linked List, Queue, Deque, Stack, AVL Tree, Tree Multiset, Trie, Directed Graph, Undirected Graph, Singly Linked List, Doubly Linked List, Max Heap, Max Priority Queue, Min Heap, Min Priority Queue.", "main": "dist/cjs/index.js", "module": "dist/mjs/index.js", "types": "dist/mjs/index.d.ts", - "umd:main": "dist/umd/index.global.js", + "umd:main": "dist/umd/data-structure-typed.min.js", "exports": { ".": { "import": "./dist/mjs/index.js", @@ -24,7 +24,6 @@ "lint:test": "eslint --fix 'test/**/*.{js,ts}'", "lint": "npm run lint:src && npm run lint:test", "format:src": "prettier --write 'src/**/*.{js,ts}'", - "format:specific": "prettier --write 'src/data-structures/binary-tree/bst.ts'", "format:test": "prettier --write 'test/**/*.{js,ts}'", "format": "npm run format:src && npm run format:test", "fix:src": "npm run lint:src && npm run format:src", @@ -62,17 +61,17 @@ "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", "auto-changelog": "^2.4.0", - "avl-tree-typed": "^1.38.5", + "avl-tree-typed": "^1.38.7", "benchmark": "^2.1.4", - "binary-tree-typed": "^1.38.5", - "bst-typed": "^1.38.5", + "binary-tree-typed": "^1.38.7", + "bst-typed": "^1.38.7", "dependency-cruiser": "^14.1.0", "eslint": "^8.50.0", "eslint-config-prettier": "^9.0.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.28.1", - "heap-typed": "^1.38.5", + "heap-typed": "^1.38.7", "istanbul-badges-readme": "^1.8.5", "jest": "^29.7.0", "prettier": "^3.0.3", diff --git a/src/data-structures/binary-tree/avl-tree.ts b/src/data-structures/binary-tree/avl-tree.ts index b22c120..f9bcdfd 100644 --- a/src/data-structures/binary-tree/avl-tree.ts +++ b/src/data-structures/binary-tree/avl-tree.ts @@ -19,7 +19,9 @@ export class AVLTreeNode = AVLTreeNodeNeste } } -export class AVLTree = AVLTreeNode> extends BST implements IBinaryTree { +export class AVLTree = AVLTreeNode>> + extends BST + implements IBinaryTree { /** * This is a constructor function for an AVL tree data structure in TypeScript. * @param {AVLTreeOptions} [options] - The `options` parameter is an optional object that can be passed to the diff --git a/src/data-structures/binary-tree/binary-tree.ts b/src/data-structures/binary-tree/binary-tree.ts index 0c897b3..fe72d9a 100644 --- a/src/data-structures/binary-tree/binary-tree.ts +++ b/src/data-structures/binary-tree/binary-tree.ts @@ -115,7 +115,7 @@ export class BinaryTreeNode = BinaryTree * Represents a binary tree data structure. * @template N - The type of the binary tree's nodes. */ -export class BinaryTree = BinaryTreeNode> implements IBinaryTree { +export class BinaryTree = BinaryTreeNode>> implements IBinaryTree { /** * Creates a new instance of BinaryTree. * @param {BinaryTreeOptions} [options] - The options for the binary tree. @@ -930,10 +930,6 @@ export class BinaryTree = BinaryTreeNode * @param callback - The `callback` parameter is a function that will be called for each node in the * breadth-first search. It takes a node of type `N` as its argument and returns a value of type * `BFSCallbackReturn`. The default value for this parameter is `this._defaultCallbackByKey - * @param {boolean} [withLevel=false] - The `withLevel` parameter is a boolean flag that determines - * whether to include the level of each node in the callback function. If `withLevel` is set - * to `true`, the level of each node will be passed as an argument to the callback function. If - * `withLevel` is * @param {N | null} beginRoot - The `beginRoot` parameter is the starting node for the breadth-first * search. It determines from which node the search will begin. If `beginRoot` is `null`, the search * will not be performed and an empty array will be returned. @@ -943,7 +939,6 @@ export class BinaryTree = BinaryTreeNode */ bfs = BFSCallback>( callback: C = this._defaultCallbackByKey as C, - withLevel: boolean = false, beginRoot: N | null = this.root, iterationType = this.iterationType ): ReturnType[] { @@ -951,9 +946,67 @@ export class BinaryTree = BinaryTreeNode const ans: BFSCallbackReturn[] = []; + if (iterationType === IterationType.RECURSIVE) { + const queue = new Queue([beginRoot]); + + function traverse(level: number) { + if (queue.size === 0) return; + + const current = queue.shift()!; + ans.push(callback(current)); + + if (current.left) queue.push(current.left); + if (current.right) queue.push(current.right); + + traverse(level + 1); + } + + traverse(0); + } else { + const queue = new Queue([beginRoot]); + while (queue.size > 0) { + const levelSize = queue.size; + + for (let i = 0; i < levelSize; i++) { + const current = queue.shift()!; + ans.push(callback(current)); + + if (current.left) queue.push(current.left); + if (current.right) queue.push(current.right); + } + + } + } + return ans; + } + + /** + * The `listLevels` function takes a binary tree node and a callback function, and returns an array + * of arrays representing the levels of the tree. + * @param {C} callback - The `callback` parameter is a function that will be called on each node in + * the tree. It takes a node as input and returns a value. The return type of the callback function + * is determined by the generic type `C`. + * @param {N | null} beginRoot - The `beginRoot` parameter represents the starting node of the binary tree + * traversal. It can be any node in the binary tree. If no node is provided, the traversal will start + * from the root node of the binary tree. + * @param iterationType - The `iterationType` parameter determines whether the tree traversal is done + * recursively or iteratively. It can have two possible values: + * @returns The function `listLevels` returns an array of arrays, where each inner array represents a + * level in a binary tree. Each inner array contains the return type of the provided callback + * function `C` applied to the nodes at that level. + */ + listLevels = BFSCallback>( + callback: C = this._defaultCallbackByKey as C, + beginRoot: N | null = this.root, + iterationType = this.iterationType + ): ReturnType[][] { + if (!beginRoot) return []; + const levelsNodes: ReturnType[][] = []; + if (iterationType === IterationType.RECURSIVE) { const _recursive = (node: N, level: number) => { - callback && ans.push(callback(node, withLevel ? level : undefined)); + if (!levelsNodes[level]) levelsNodes[level] = []; + levelsNodes[level].push(callback(node)); if (node.left) _recursive(node.left, level + 1); if (node.right) _recursive(node.right, level + 1); }; @@ -966,12 +1019,14 @@ export class BinaryTree = BinaryTreeNode const head = stack.pop()!; const [node, level] = head; - callback && ans.push(callback(node, withLevel ? level : undefined)); + if (!levelsNodes[level]) levelsNodes[level] = []; + levelsNodes[level].push(callback(node)); if (node.right) stack.push([node.right, level + 1]); if (node.left) stack.push([node.left, level + 1]); } } - return ans; + + return levelsNodes; } /** diff --git a/src/data-structures/binary-tree/bst.ts b/src/data-structures/binary-tree/bst.ts index 9c2a22d..446279c 100644 --- a/src/data-structures/binary-tree/bst.ts +++ b/src/data-structures/binary-tree/bst.ts @@ -24,7 +24,7 @@ export class BSTNode = BSTNodeNested> extend } } -export class BST = BSTNode> extends BinaryTree implements IBinaryTree { +export class BST = BSTNode>> extends BinaryTree implements IBinaryTree { /** * The constructor function initializes a binary search tree object with an optional comparator * function. diff --git a/src/data-structures/binary-tree/rb-tree.ts b/src/data-structures/binary-tree/rb-tree.ts index b8ef6db..16b9751 100644 --- a/src/data-structures/binary-tree/rb-tree.ts +++ b/src/data-structures/binary-tree/rb-tree.ts @@ -2,10 +2,7 @@ import {BinaryTreeNodeKey, RBColor, RBTreeNodeNested, RBTreeOptions} from '../.. import {IBinaryTree} from '../../interfaces'; import {BST, BSTNode} from './bst'; -export class RBTreeNode = RBTreeNodeNested> extends BSTNode< - V, - N -> { +export class RBTreeNode = RBTreeNodeNested> extends BSTNode { constructor(key: BinaryTreeNodeKey, val?: V) { super(key, val); this._color = RBColor.RED; @@ -22,7 +19,7 @@ export class RBTreeNode = RBTreeNodeNested = RBTreeNode> extends BST implements IBinaryTree { +export class RBTree = RBTreeNode>> extends BST implements IBinaryTree { constructor(options?: RBTreeOptions) { super(options); } diff --git a/src/data-structures/binary-tree/tree-multiset.ts b/src/data-structures/binary-tree/tree-multiset.ts index 3cc76f4..f07d298 100644 --- a/src/data-structures/binary-tree/tree-multiset.ts +++ b/src/data-structures/binary-tree/tree-multiset.ts @@ -35,7 +35,7 @@ export class TreeMultisetNode< /** * The only distinction between a TreeMultiset and a AVLTree lies in the ability of the former to store duplicate nodes through the utilization of counters. */ -export class TreeMultiset = TreeMultisetNode> +export class TreeMultiset = TreeMultisetNode>> extends AVLTree implements IBinaryTree { /** @@ -191,10 +191,7 @@ export class TreeMultiset = TreeMultis * each key or node. * @returns The function `addMany` returns an array of `N`, `null`, or `undefined` values. */ - override addMany( - keysOrNodes: (BinaryTreeNodeKey | null)[] | (N | null)[], - data?: V[] - ): (N | null | undefined)[] { + override addMany(keysOrNodes: (BinaryTreeNodeKey | null)[] | (N | null)[], data?: V[]): (N | null | undefined)[] { const inserted: (N | null | undefined)[] = []; for (let i = 0; i < keysOrNodes.length; i++) { diff --git a/test/integration/bst.test.ts b/test/integration/bst.test.ts index a482a37..35a6061 100644 --- a/test/integration/bst.test.ts +++ b/test/integration/bst.test.ts @@ -183,7 +183,7 @@ describe('Individual package BST operations test', () => { }); it('should perform various operations on a Binary Search Tree with object values', () => { - const objBST = new BST>(); + const objBST = new BST<{ key: number; keyA: number }>(); expect(objBST).toBeInstanceOf(BST); objBST.add(11, {key: 11, keyA: 11}); objBST.add(3, {key: 3, keyA: 3}); diff --git a/test/integration/index.html b/test/integration/index.html index 0fab945..8c85112 100644 --- a/test/integration/index.html +++ b/test/integration/index.html @@ -3,7 +3,7 @@ CDN Test - +
diff --git a/test/unit/data-structures/binary-tree/avl-tree.test.ts b/test/unit/data-structures/binary-tree/avl-tree.test.ts index 01c0e16..5c99c38 100644 --- a/test/unit/data-structures/binary-tree/avl-tree.test.ts +++ b/test/unit/data-structures/binary-tree/avl-tree.test.ts @@ -110,7 +110,7 @@ describe('AVL Tree Test', () => { }); describe('AVLTree APIs test', () => { - const avl = new AVLTree<{id: number; text: string}>(); + const avl = new AVLTree<{ id: number; text: string }>(); beforeEach(() => { avl.clear(); }); @@ -123,7 +123,7 @@ describe('AVLTree APIs test', () => { avl.add(node3); avl.add(node3, {id: 3, text: 'text33'}); - const bfsRes = avl.bfs(node => node.key, false); + const bfsRes = avl.bfs(node => node.key); expect(bfsRes[0]).toBe(2); }); }); diff --git a/test/unit/data-structures/binary-tree/binary-tree.test.ts b/test/unit/data-structures/binary-tree/binary-tree.test.ts index 49d87d8..0e9ce66 100644 --- a/test/unit/data-structures/binary-tree/binary-tree.test.ts +++ b/test/unit/data-structures/binary-tree/binary-tree.test.ts @@ -1,4 +1,8 @@ -import {AVLTree, AVLTreeNode, BinaryTree, BinaryTreeNode} from '../../../../src'; +import {AVLTree, AVLTreeNode, BinaryTree, BinaryTreeNode, IterationType} from '../../../../src'; +import {isDebugTest} from "../../../config"; + +const isDebug = isDebugTest; +// const isDebug = true; describe('BinaryTreeNode', () => { it('should create an instance of BinaryTreeNode', () => { @@ -196,7 +200,7 @@ describe('BinaryTree Morris Traversal', () => { }); describe('BinaryTree APIs test', () => { - const avl = new AVLTree<{id: number; text: string}>(); + const avl = new AVLTree<{ id: number; text: string }>(); beforeEach(() => { avl.clear(); }); @@ -213,3 +217,20 @@ describe('BinaryTree APIs test', () => { expect(bfsRes[0]?.key).toBe(2); }); }); + +describe('BinaryTree traversals', () => { + const tree = new BinaryTree(); + + const arr = [35, 20, 40, 15, 29, null, 50, null, 16, 28, 30, 45, 55]; + tree.refill(arr); + expect(tree.dfs(node => node.key, 'pre')).toEqual([35, 20, 15, 16, 29, 28, 30, 40, 50, 45, 55]); + expect(tree.dfs(node => node.key, 'in')).toEqual([15, 16, 20, 28, 29, 30, 35, 40, 45, 50, 55]); + expect(tree.dfs(node => node.key, 'post')).toEqual([16, 15, 28, 30, 29, 20, 45, 55, 50, 40, 35]); + expect(tree.bfs(node => node.key, tree.root, IterationType.RECURSIVE)).toEqual([35, 20, 40, 15, 29, 50, 16, 28, 30, 45, 55]); + expect(tree.bfs(node => node.key, tree.root, IterationType.ITERATIVE)).toEqual([35, 20, 40, 15, 29, 50, 16, 28, 30, 45, 55]); + + const levels = tree.listLevels(node => node.key); + expect(levels).toEqual([[35], [20, 40], [15, 29, 50], [16, 28, 30, 45, 55]]); + isDebug && console.log(levels); + +}) diff --git a/test/unit/data-structures/binary-tree/bst.test.ts b/test/unit/data-structures/binary-tree/bst.test.ts index 872223f..7b0441c 100644 --- a/test/unit/data-structures/binary-tree/bst.test.ts +++ b/test/unit/data-structures/binary-tree/bst.test.ts @@ -189,7 +189,7 @@ describe('BST operations test', () => { }); it('should perform various operations on a Binary Search Tree with object values', () => { - const objBST = new BST<{key: number; keyA: number}>(); + const objBST = new BST<{ key: number; keyA: number }>(); expect(objBST).toBeInstanceOf(BST); objBST.add(11, {key: 11, keyA: 11}); objBST.add(3, {key: 3, keyA: 3}); @@ -260,7 +260,7 @@ describe('BST operations test', () => { objBST.perfectlyBalance(); expect(objBST.isPerfectlyBalanced()).toBe(true); - const bfsNodesAfterBalanced: BSTNode<{key: number; keyA: number}>[] = []; + const bfsNodesAfterBalanced: BSTNode<{ key: number; keyA: number }>[] = []; objBST.bfs(node => bfsNodesAfterBalanced.push(node)); expect(bfsNodesAfterBalanced[0].key).toBe(8); expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16); @@ -385,7 +385,7 @@ describe('BST operations test', () => { expect(bfsIDs[1]).toBe(12); expect(bfsIDs[2]).toBe(16); - const bfsNodes: BSTNode<{key: number; keyA: number}>[] = []; + const bfsNodes: BSTNode<{ key: number; keyA: number }>[] = []; objBST.bfs(node => bfsNodes.push(node)); expect(bfsNodes[0].key).toBe(2); expect(bfsNodes[1].key).toBe(12); @@ -435,13 +435,7 @@ describe('BST Performance test', function () { bst.addMany(nodes); isDebug && console.log('---add', performance.now() - start); const startL = performance.now(); - const arr: number[][] = []; - bst.bfs((node, level) => { - if (level !== undefined) { - if (!arr[level]) arr[level] = []; - arr[level].push(node.key); - } - }, true); + const arr: number[][] = bst.listLevels((node) => node.key); isDebug && console.log('---listLevels', arr); isDebug && console.log('---listLevels', performance.now() - startL); }); diff --git a/test/unit/data-structures/binary-tree/overall.test.ts b/test/unit/data-structures/binary-tree/overall.test.ts index e4301b1..04dff37 100644 --- a/test/unit/data-structures/binary-tree/overall.test.ts +++ b/test/unit/data-structures/binary-tree/overall.test.ts @@ -1,4 +1,4 @@ -import {AVLTree, BST, BSTNode} from '../../../../src'; +import {AVLTree, BST} from '../../../../src'; describe('Overall BinaryTree Test', () => { it('should perform various operations on BinaryTree', () => { @@ -6,30 +6,30 @@ describe('Overall BinaryTree Test', () => { bst.add(11); bst.add(3); bst.addMany([15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5], undefined, false); - bst.size === 16; // true - expect(bst.size).toBe(16); // true - bst.has(6); // true - expect(bst.has(6)).toBe(true); // true - bst.getHeight(6) === 2; // true - bst.getHeight() === 5; // true - bst.getDepth(6) === 3; // true - expect(bst.getHeight(6)).toBe(2); // true - expect(bst.getHeight()).toBe(5); // true - expect(bst.getDepth(6)).toBe(3); // true + bst.size === 16; // true + expect(bst.size).toBe(16); // true + bst.has(6); // true + expect(bst.has(6)).toBe(true); // true + bst.getHeight(6) === 2; // true + bst.getHeight() === 5; // true + bst.getDepth(6) === 3; // true + expect(bst.getHeight(6)).toBe(2); // true + expect(bst.getHeight()).toBe(5); // true + expect(bst.getDepth(6)).toBe(3); // true const leftMost = bst.getLeftMost(); - leftMost?.key === 1; // true + leftMost?.key === 1; // true expect(leftMost?.key).toBe(1); bst.delete(6); - bst.get(6); // null + bst.get(6); // null expect(bst.get(6)).toBeNull(); - bst.isAVLBalanced(); // true or false + bst.isAVLBalanced(); // true or false expect(bst.isAVLBalanced()).toBe(true); const bfsIDs: number[] = []; bst.bfs(node => bfsIDs.push(node.key)); - bfsIDs[0] === 11; // true + bfsIDs[0] === 11; // true expect(bfsIDs[0]).toBe(11); - const objBST = new BST<{key: number; keyA: number}>(); + const objBST = new BST<{ key: number; keyA: number }>(); objBST.add(11, {key: 11, keyA: 11}); objBST.add(3, {key: 3, keyA: 3}); @@ -57,10 +57,10 @@ describe('Overall BinaryTree Test', () => { const avlTree = new AVLTree(); avlTree.addMany([11, 3, 15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5]); - avlTree.isAVLBalanced(); // true - expect(avlTree.isAVLBalanced()).toBe(true); // true + avlTree.isAVLBalanced(); // true + expect(avlTree.isAVLBalanced()).toBe(true); // true avlTree.delete(10); - avlTree.isAVLBalanced(); // true - expect(avlTree.isAVLBalanced()).toBe(true); // true + avlTree.isAVLBalanced(); // true + expect(avlTree.isAVLBalanced()).toBe(true); // true }); }); diff --git a/test/unit/data-structures/binary-tree/tree-multiset.test.ts b/test/unit/data-structures/binary-tree/tree-multiset.test.ts index 795ce47..5e25bde 100644 --- a/test/unit/data-structures/binary-tree/tree-multiset.test.ts +++ b/test/unit/data-structures/binary-tree/tree-multiset.test.ts @@ -206,7 +206,7 @@ describe('TreeMultiset operations test', () => { }); it('should perform various operations on a Binary Search Tree with object values', () => { - const objTreeMultiset = new TreeMultiset<{key: number; keyA: number}>(); + const objTreeMultiset = new TreeMultiset<{ key: number; keyA: number }>(); expect(objTreeMultiset).toBeInstanceOf(TreeMultiset); objTreeMultiset.add(11, {key: 11, keyA: 11}); objTreeMultiset.add(3, {key: 3, keyA: 3}); @@ -481,7 +481,7 @@ describe('TreeMultiset Performance test', function () { } isDebug && console.log('---add', performance.now() - start); const startL = performance.now(); - treeMS.lesserOrGreaterTraverse((node: TreeMultisetNode) => (node.count += 1), CP.lt, inputSize / 2); + treeMS.lesserOrGreaterTraverse((node) => (node.count += 1), CP.lt, inputSize / 2); isDebug && console.log('---lesserOrGreaterTraverse', performance.now() - startL); }); }); diff --git a/test/unit/data-structures/heap/heap.test.ts b/test/unit/data-structures/heap/heap.test.ts index 8745402..14c54cf 100644 --- a/test/unit/data-structures/heap/heap.test.ts +++ b/test/unit/data-structures/heap/heap.test.ts @@ -22,7 +22,7 @@ describe('Heap Operation Test', () => { }); it('should object heap work well', function () { - const minHeap = new MinHeap<{a: string; key: number}>((a, b) => a.key - b.key); + const minHeap = new MinHeap<{ a: string; key: number }>((a, b) => a.key - b.key); minHeap.add({key: 1, a: 'a1'}); minHeap.add({key: 6, a: 'a6'}); minHeap.add({key: 2, a: 'a2'}); @@ -37,7 +37,7 @@ describe('Heap Operation Test', () => { i++; } - const maxHeap = new MaxHeap<{key: number; a: string}>((a, b) => b.key - a.key); + const maxHeap = new MaxHeap<{ key: number; a: string }>((a, b) => b.key - a.key); maxHeap.add({key: 1, a: 'a1'}); maxHeap.add({key: 6, a: 'a6'}); maxHeap.add({key: 5, a: 'a5'}); diff --git a/test/unit/data-structures/linked-list/doubly-linked-list.test.ts b/test/unit/data-structures/linked-list/doubly-linked-list.test.ts index eab2ad5..0838337 100644 --- a/test/unit/data-structures/linked-list/doubly-linked-list.test.ts +++ b/test/unit/data-structures/linked-list/doubly-linked-list.test.ts @@ -3,7 +3,7 @@ import {bigO, magnitude} from '../../../utils'; describe('DoublyLinkedList Operation Test', () => { let list: DoublyLinkedList; - let objectList: DoublyLinkedList<{keyA: number}>; + let objectList: DoublyLinkedList<{ keyA: number }>; beforeEach(() => { list = new DoublyLinkedList(); diff --git a/test/unit/data-structures/linked-list/singly-linked-list.test.ts b/test/unit/data-structures/linked-list/singly-linked-list.test.ts index 74a3de8..092b2e6 100644 --- a/test/unit/data-structures/linked-list/singly-linked-list.test.ts +++ b/test/unit/data-structures/linked-list/singly-linked-list.test.ts @@ -3,10 +3,10 @@ import {bigO, magnitude} from '../../../utils'; describe('SinglyLinkedList Operation Test', () => { let list: SinglyLinkedList; - let objectList: SinglyLinkedList<{keyA: number}>; + let objectList: SinglyLinkedList<{ keyA: number }>; beforeEach(() => { list = new SinglyLinkedList(); - objectList = new SinglyLinkedList<{keyA: number}>(); + objectList = new SinglyLinkedList<{ keyA: number }>(); }); describe('push', () => { diff --git a/test/unit/data-structures/priority-queue/max-priority-queue.test.ts b/test/unit/data-structures/priority-queue/max-priority-queue.test.ts index f8a63bc..f389309 100644 --- a/test/unit/data-structures/priority-queue/max-priority-queue.test.ts +++ b/test/unit/data-structures/priority-queue/max-priority-queue.test.ts @@ -17,7 +17,7 @@ describe('MaxPriorityQueue Operation Test', () => { }); it('should add elements and maintain heap property in a object MaxPriorityQueue', () => { - const priorityQueue = new MaxPriorityQueue<{keyA: number}>((a, b) => b.keyA - a.keyA); + const priorityQueue = new MaxPriorityQueue<{ keyA: number }>((a, b) => b.keyA - a.keyA); priorityQueue.refill([{keyA: 5}, {keyA: 3}, {keyA: 1}]); priorityQueue.add({keyA: 7}); @@ -64,7 +64,7 @@ describe('MaxPriorityQueue Operation Test', () => { it('should correctly heapify an object array', () => { const nodes = [{keyA: 5}, {keyA: 3}, {keyA: 7}, {keyA: 1}]; - const maxPQ = MaxPriorityQueue.heapify<{keyA: number}>(nodes, (a, b) => b.keyA - a.keyA); + const maxPQ = MaxPriorityQueue.heapify<{ keyA: number }>(nodes, (a, b) => b.keyA - a.keyA); expect(maxPQ.poll()?.keyA).toBe(7); expect(maxPQ.poll()?.keyA).toBe(5); diff --git a/test/utils/big-o.ts b/test/utils/big-o.ts index 43d7eca..cc9fc86 100644 --- a/test/utils/big-o.ts +++ b/test/utils/big-o.ts @@ -26,7 +26,7 @@ export const bigO = { function findPotentialN(input: any): number { let longestArray: any[] = []; - let mostProperties: {[key: string]: any} = {}; + let mostProperties: { [key: string]: any } = {}; function recurse(obj: any) { if (Array.isArray(obj)) { diff --git a/tsup.config.js b/tsup.config.js index dd1aa90..fe37d02 100644 --- a/tsup.config.js +++ b/tsup.config.js @@ -1,11 +1,18 @@ export default [{ - entry: ['src/index.ts'], + entryPoints: { + "data-structure-typed": "src/index.ts" + }, format: ["iife"], clean: true, sourcemap: true, minify: true, - outDir: 'dist/umd', - globalName: 'dataStructureTyped', + outDir: "dist/umd", + globalName: "dataStructureTyped", platform: "browser", - bundle: true + bundle: true, + outExtension() { + return { + js: `.min.js`, + } + }, }]; From f8e0607b2514fdedb5206633469a8efc805123e5 Mon Sep 17 00:00:00 2001 From: Revone Date: Sat, 28 Oct 2023 15:50:42 +0800 Subject: [PATCH 30/46] [trie] The Trie's getWords method now offers an optional parameter to retrieve all words in case of an empty string input. --- .../binary-tree/binary-tree.ts | 4 +- src/data-structures/binary-tree/bst.ts | 4 +- src/data-structures/binary-tree/rb-tree.ts | 4 +- src/data-structures/trie/trie.ts | 6 ++- test/integration/bst.test.ts | 2 +- .../binary-tree/avl-tree.test.ts | 2 +- .../binary-tree/binary-tree.test.ts | 15 +++++--- .../data-structures/binary-tree/bst.test.ts | 8 ++-- .../binary-tree/overall.test.ts | 38 +++++++++---------- .../binary-tree/tree-multiset.test.ts | 4 +- test/unit/data-structures/heap/heap.test.ts | 4 +- .../linked-list/doubly-linked-list.test.ts | 2 +- .../linked-list/singly-linked-list.test.ts | 4 +- .../priority-queue/max-priority-queue.test.ts | 4 +- test/utils/big-o.ts | 2 +- 15 files changed, 56 insertions(+), 47 deletions(-) diff --git a/src/data-structures/binary-tree/binary-tree.ts b/src/data-structures/binary-tree/binary-tree.ts index fe72d9a..7dec2a4 100644 --- a/src/data-structures/binary-tree/binary-tree.ts +++ b/src/data-structures/binary-tree/binary-tree.ts @@ -115,7 +115,8 @@ export class BinaryTreeNode = BinaryTree * Represents a binary tree data structure. * @template N - The type of the binary tree's nodes. */ -export class BinaryTree = BinaryTreeNode>> implements IBinaryTree { +export class BinaryTree = BinaryTreeNode>> + implements IBinaryTree { /** * Creates a new instance of BinaryTree. * @param {BinaryTreeOptions} [options] - The options for the binary tree. @@ -974,7 +975,6 @@ export class BinaryTree = BinaryTreeNode if (current.left) queue.push(current.left); if (current.right) queue.push(current.right); } - } } return ans; diff --git a/src/data-structures/binary-tree/bst.ts b/src/data-structures/binary-tree/bst.ts index 446279c..9e73700 100644 --- a/src/data-structures/binary-tree/bst.ts +++ b/src/data-structures/binary-tree/bst.ts @@ -24,7 +24,9 @@ export class BSTNode = BSTNodeNested> extend } } -export class BST = BSTNode>> extends BinaryTree implements IBinaryTree { +export class BST = BSTNode>> + extends BinaryTree + implements IBinaryTree { /** * The constructor function initializes a binary search tree object with an optional comparator * function. diff --git a/src/data-structures/binary-tree/rb-tree.ts b/src/data-structures/binary-tree/rb-tree.ts index 16b9751..45c363b 100644 --- a/src/data-structures/binary-tree/rb-tree.ts +++ b/src/data-structures/binary-tree/rb-tree.ts @@ -19,7 +19,9 @@ export class RBTreeNode = RBTreeNodeNested = RBTreeNode>> extends BST implements IBinaryTree { +export class RBTree = RBTreeNode>> + extends BST + implements IBinaryTree { constructor(options?: RBTreeOptions) { super(options); } diff --git a/src/data-structures/trie/trie.ts b/src/data-structures/trie/trie.ts index d5ba4c8..780b562 100644 --- a/src/data-structures/trie/trie.ts +++ b/src/data-structures/trie/trie.ts @@ -241,9 +241,10 @@ export class Trie { * @param {string} prefix - The `prefix` parameter is a string that represents the prefix that we want to search for in the * trie. It is an optional parameter, so if no prefix is provided, it will default to an empty string. * @param {number} max - The max count of words will be found + * @param isAllWhenEmptyPrefix - If true, when the prefix provided as '', returns all the words in the trie. * @returns {string[]} an array of strings. */ - getWords(prefix = '', max = Number.MAX_SAFE_INTEGER): string[] { + getWords(prefix = '', max = Number.MAX_SAFE_INTEGER, isAllWhenEmptyPrefix = false): string[] { prefix = this._caseProcess(prefix); const words: string[] = []; let found = 0; @@ -270,7 +271,8 @@ export class Trie { if (nodeC) startNode = nodeC; } } - if (startNode !== this.root) dfs(startNode, prefix); + + if (isAllWhenEmptyPrefix || startNode !== this.root) dfs(startNode, prefix); return words; } diff --git a/test/integration/bst.test.ts b/test/integration/bst.test.ts index 35a6061..0a33db7 100644 --- a/test/integration/bst.test.ts +++ b/test/integration/bst.test.ts @@ -183,7 +183,7 @@ describe('Individual package BST operations test', () => { }); it('should perform various operations on a Binary Search Tree with object values', () => { - const objBST = new BST<{ key: number; keyA: number }>(); + const objBST = new BST<{key: number; keyA: number}>(); expect(objBST).toBeInstanceOf(BST); objBST.add(11, {key: 11, keyA: 11}); objBST.add(3, {key: 3, keyA: 3}); diff --git a/test/unit/data-structures/binary-tree/avl-tree.test.ts b/test/unit/data-structures/binary-tree/avl-tree.test.ts index 5c99c38..cfd74ea 100644 --- a/test/unit/data-structures/binary-tree/avl-tree.test.ts +++ b/test/unit/data-structures/binary-tree/avl-tree.test.ts @@ -110,7 +110,7 @@ describe('AVL Tree Test', () => { }); describe('AVLTree APIs test', () => { - const avl = new AVLTree<{ id: number; text: string }>(); + const avl = new AVLTree<{id: number; text: string}>(); beforeEach(() => { avl.clear(); }); diff --git a/test/unit/data-structures/binary-tree/binary-tree.test.ts b/test/unit/data-structures/binary-tree/binary-tree.test.ts index 0e9ce66..97e3482 100644 --- a/test/unit/data-structures/binary-tree/binary-tree.test.ts +++ b/test/unit/data-structures/binary-tree/binary-tree.test.ts @@ -1,5 +1,5 @@ import {AVLTree, AVLTreeNode, BinaryTree, BinaryTreeNode, IterationType} from '../../../../src'; -import {isDebugTest} from "../../../config"; +import {isDebugTest} from '../../../config'; const isDebug = isDebugTest; // const isDebug = true; @@ -200,7 +200,7 @@ describe('BinaryTree Morris Traversal', () => { }); describe('BinaryTree APIs test', () => { - const avl = new AVLTree<{ id: number; text: string }>(); + const avl = new AVLTree<{id: number; text: string}>(); beforeEach(() => { avl.clear(); }); @@ -226,11 +226,14 @@ describe('BinaryTree traversals', () => { expect(tree.dfs(node => node.key, 'pre')).toEqual([35, 20, 15, 16, 29, 28, 30, 40, 50, 45, 55]); expect(tree.dfs(node => node.key, 'in')).toEqual([15, 16, 20, 28, 29, 30, 35, 40, 45, 50, 55]); expect(tree.dfs(node => node.key, 'post')).toEqual([16, 15, 28, 30, 29, 20, 45, 55, 50, 40, 35]); - expect(tree.bfs(node => node.key, tree.root, IterationType.RECURSIVE)).toEqual([35, 20, 40, 15, 29, 50, 16, 28, 30, 45, 55]); - expect(tree.bfs(node => node.key, tree.root, IterationType.ITERATIVE)).toEqual([35, 20, 40, 15, 29, 50, 16, 28, 30, 45, 55]); + expect(tree.bfs(node => node.key, tree.root, IterationType.RECURSIVE)).toEqual([ + 35, 20, 40, 15, 29, 50, 16, 28, 30, 45, 55 + ]); + expect(tree.bfs(node => node.key, tree.root, IterationType.ITERATIVE)).toEqual([ + 35, 20, 40, 15, 29, 50, 16, 28, 30, 45, 55 + ]); const levels = tree.listLevels(node => node.key); expect(levels).toEqual([[35], [20, 40], [15, 29, 50], [16, 28, 30, 45, 55]]); isDebug && console.log(levels); - -}) +}); diff --git a/test/unit/data-structures/binary-tree/bst.test.ts b/test/unit/data-structures/binary-tree/bst.test.ts index 7b0441c..7f8e374 100644 --- a/test/unit/data-structures/binary-tree/bst.test.ts +++ b/test/unit/data-structures/binary-tree/bst.test.ts @@ -189,7 +189,7 @@ describe('BST operations test', () => { }); it('should perform various operations on a Binary Search Tree with object values', () => { - const objBST = new BST<{ key: number; keyA: number }>(); + const objBST = new BST<{key: number; keyA: number}>(); expect(objBST).toBeInstanceOf(BST); objBST.add(11, {key: 11, keyA: 11}); objBST.add(3, {key: 3, keyA: 3}); @@ -260,7 +260,7 @@ describe('BST operations test', () => { objBST.perfectlyBalance(); expect(objBST.isPerfectlyBalanced()).toBe(true); - const bfsNodesAfterBalanced: BSTNode<{ key: number; keyA: number }>[] = []; + const bfsNodesAfterBalanced: BSTNode<{key: number; keyA: number}>[] = []; objBST.bfs(node => bfsNodesAfterBalanced.push(node)); expect(bfsNodesAfterBalanced[0].key).toBe(8); expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16); @@ -385,7 +385,7 @@ describe('BST operations test', () => { expect(bfsIDs[1]).toBe(12); expect(bfsIDs[2]).toBe(16); - const bfsNodes: BSTNode<{ key: number; keyA: number }>[] = []; + const bfsNodes: BSTNode<{key: number; keyA: number}>[] = []; objBST.bfs(node => bfsNodes.push(node)); expect(bfsNodes[0].key).toBe(2); expect(bfsNodes[1].key).toBe(12); @@ -435,7 +435,7 @@ describe('BST Performance test', function () { bst.addMany(nodes); isDebug && console.log('---add', performance.now() - start); const startL = performance.now(); - const arr: number[][] = bst.listLevels((node) => node.key); + const arr: number[][] = bst.listLevels(node => node.key); isDebug && console.log('---listLevels', arr); isDebug && console.log('---listLevels', performance.now() - startL); }); diff --git a/test/unit/data-structures/binary-tree/overall.test.ts b/test/unit/data-structures/binary-tree/overall.test.ts index 04dff37..520c2bc 100644 --- a/test/unit/data-structures/binary-tree/overall.test.ts +++ b/test/unit/data-structures/binary-tree/overall.test.ts @@ -6,30 +6,30 @@ describe('Overall BinaryTree Test', () => { bst.add(11); bst.add(3); bst.addMany([15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5], undefined, false); - bst.size === 16; // true - expect(bst.size).toBe(16); // true - bst.has(6); // true - expect(bst.has(6)).toBe(true); // true - bst.getHeight(6) === 2; // true - bst.getHeight() === 5; // true - bst.getDepth(6) === 3; // true - expect(bst.getHeight(6)).toBe(2); // true - expect(bst.getHeight()).toBe(5); // true - expect(bst.getDepth(6)).toBe(3); // true + bst.size === 16; // true + expect(bst.size).toBe(16); // true + bst.has(6); // true + expect(bst.has(6)).toBe(true); // true + bst.getHeight(6) === 2; // true + bst.getHeight() === 5; // true + bst.getDepth(6) === 3; // true + expect(bst.getHeight(6)).toBe(2); // true + expect(bst.getHeight()).toBe(5); // true + expect(bst.getDepth(6)).toBe(3); // true const leftMost = bst.getLeftMost(); - leftMost?.key === 1; // true + leftMost?.key === 1; // true expect(leftMost?.key).toBe(1); bst.delete(6); - bst.get(6); // null + bst.get(6); // null expect(bst.get(6)).toBeNull(); - bst.isAVLBalanced(); // true or false + bst.isAVLBalanced(); // true or false expect(bst.isAVLBalanced()).toBe(true); const bfsIDs: number[] = []; bst.bfs(node => bfsIDs.push(node.key)); - bfsIDs[0] === 11; // true + bfsIDs[0] === 11; // true expect(bfsIDs[0]).toBe(11); - const objBST = new BST<{ key: number; keyA: number }>(); + const objBST = new BST<{key: number; keyA: number}>(); objBST.add(11, {key: 11, keyA: 11}); objBST.add(3, {key: 3, keyA: 3}); @@ -57,10 +57,10 @@ describe('Overall BinaryTree Test', () => { const avlTree = new AVLTree(); avlTree.addMany([11, 3, 15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5]); - avlTree.isAVLBalanced(); // true - expect(avlTree.isAVLBalanced()).toBe(true); // true + avlTree.isAVLBalanced(); // true + expect(avlTree.isAVLBalanced()).toBe(true); // true avlTree.delete(10); - avlTree.isAVLBalanced(); // true - expect(avlTree.isAVLBalanced()).toBe(true); // true + avlTree.isAVLBalanced(); // true + expect(avlTree.isAVLBalanced()).toBe(true); // true }); }); diff --git a/test/unit/data-structures/binary-tree/tree-multiset.test.ts b/test/unit/data-structures/binary-tree/tree-multiset.test.ts index 5e25bde..8de9ddd 100644 --- a/test/unit/data-structures/binary-tree/tree-multiset.test.ts +++ b/test/unit/data-structures/binary-tree/tree-multiset.test.ts @@ -206,7 +206,7 @@ describe('TreeMultiset operations test', () => { }); it('should perform various operations on a Binary Search Tree with object values', () => { - const objTreeMultiset = new TreeMultiset<{ key: number; keyA: number }>(); + const objTreeMultiset = new TreeMultiset<{key: number; keyA: number}>(); expect(objTreeMultiset).toBeInstanceOf(TreeMultiset); objTreeMultiset.add(11, {key: 11, keyA: 11}); objTreeMultiset.add(3, {key: 3, keyA: 3}); @@ -481,7 +481,7 @@ describe('TreeMultiset Performance test', function () { } isDebug && console.log('---add', performance.now() - start); const startL = performance.now(); - treeMS.lesserOrGreaterTraverse((node) => (node.count += 1), CP.lt, inputSize / 2); + treeMS.lesserOrGreaterTraverse(node => (node.count += 1), CP.lt, inputSize / 2); isDebug && console.log('---lesserOrGreaterTraverse', performance.now() - startL); }); }); diff --git a/test/unit/data-structures/heap/heap.test.ts b/test/unit/data-structures/heap/heap.test.ts index 14c54cf..8745402 100644 --- a/test/unit/data-structures/heap/heap.test.ts +++ b/test/unit/data-structures/heap/heap.test.ts @@ -22,7 +22,7 @@ describe('Heap Operation Test', () => { }); it('should object heap work well', function () { - const minHeap = new MinHeap<{ a: string; key: number }>((a, b) => a.key - b.key); + const minHeap = new MinHeap<{a: string; key: number}>((a, b) => a.key - b.key); minHeap.add({key: 1, a: 'a1'}); minHeap.add({key: 6, a: 'a6'}); minHeap.add({key: 2, a: 'a2'}); @@ -37,7 +37,7 @@ describe('Heap Operation Test', () => { i++; } - const maxHeap = new MaxHeap<{ key: number; a: string }>((a, b) => b.key - a.key); + const maxHeap = new MaxHeap<{key: number; a: string}>((a, b) => b.key - a.key); maxHeap.add({key: 1, a: 'a1'}); maxHeap.add({key: 6, a: 'a6'}); maxHeap.add({key: 5, a: 'a5'}); diff --git a/test/unit/data-structures/linked-list/doubly-linked-list.test.ts b/test/unit/data-structures/linked-list/doubly-linked-list.test.ts index 0838337..eab2ad5 100644 --- a/test/unit/data-structures/linked-list/doubly-linked-list.test.ts +++ b/test/unit/data-structures/linked-list/doubly-linked-list.test.ts @@ -3,7 +3,7 @@ import {bigO, magnitude} from '../../../utils'; describe('DoublyLinkedList Operation Test', () => { let list: DoublyLinkedList; - let objectList: DoublyLinkedList<{ keyA: number }>; + let objectList: DoublyLinkedList<{keyA: number}>; beforeEach(() => { list = new DoublyLinkedList(); diff --git a/test/unit/data-structures/linked-list/singly-linked-list.test.ts b/test/unit/data-structures/linked-list/singly-linked-list.test.ts index 092b2e6..74a3de8 100644 --- a/test/unit/data-structures/linked-list/singly-linked-list.test.ts +++ b/test/unit/data-structures/linked-list/singly-linked-list.test.ts @@ -3,10 +3,10 @@ import {bigO, magnitude} from '../../../utils'; describe('SinglyLinkedList Operation Test', () => { let list: SinglyLinkedList; - let objectList: SinglyLinkedList<{ keyA: number }>; + let objectList: SinglyLinkedList<{keyA: number}>; beforeEach(() => { list = new SinglyLinkedList(); - objectList = new SinglyLinkedList<{ keyA: number }>(); + objectList = new SinglyLinkedList<{keyA: number}>(); }); describe('push', () => { diff --git a/test/unit/data-structures/priority-queue/max-priority-queue.test.ts b/test/unit/data-structures/priority-queue/max-priority-queue.test.ts index f389309..f8a63bc 100644 --- a/test/unit/data-structures/priority-queue/max-priority-queue.test.ts +++ b/test/unit/data-structures/priority-queue/max-priority-queue.test.ts @@ -17,7 +17,7 @@ describe('MaxPriorityQueue Operation Test', () => { }); it('should add elements and maintain heap property in a object MaxPriorityQueue', () => { - const priorityQueue = new MaxPriorityQueue<{ keyA: number }>((a, b) => b.keyA - a.keyA); + const priorityQueue = new MaxPriorityQueue<{keyA: number}>((a, b) => b.keyA - a.keyA); priorityQueue.refill([{keyA: 5}, {keyA: 3}, {keyA: 1}]); priorityQueue.add({keyA: 7}); @@ -64,7 +64,7 @@ describe('MaxPriorityQueue Operation Test', () => { it('should correctly heapify an object array', () => { const nodes = [{keyA: 5}, {keyA: 3}, {keyA: 7}, {keyA: 1}]; - const maxPQ = MaxPriorityQueue.heapify<{ keyA: number }>(nodes, (a, b) => b.keyA - a.keyA); + const maxPQ = MaxPriorityQueue.heapify<{keyA: number}>(nodes, (a, b) => b.keyA - a.keyA); expect(maxPQ.poll()?.keyA).toBe(7); expect(maxPQ.poll()?.keyA).toBe(5); diff --git a/test/utils/big-o.ts b/test/utils/big-o.ts index cc9fc86..43d7eca 100644 --- a/test/utils/big-o.ts +++ b/test/utils/big-o.ts @@ -26,7 +26,7 @@ export const bigO = { function findPotentialN(input: any): number { let longestArray: any[] = []; - let mostProperties: { [key: string]: any } = {}; + let mostProperties: {[key: string]: any} = {}; function recurse(obj: any) { if (Array.isArray(obj)) { From c11cc4527b3f217523b28ba18dabca05ba384b23 Mon Sep 17 00:00:00 2001 From: Revone Date: Sat, 28 Oct 2023 15:58:48 +0800 Subject: [PATCH 31/46] [graph] The removal method in the graph data structure is standardized to 'delete' --- CHANGELOG.md | 2 +- README.md | 18 +++---- package-lock.json | 50 +++++++++---------- package.json | 10 ++-- src/data-structures/graph/abstract-graph.ts | 8 +-- src/data-structures/graph/directed-graph.ts | 12 ++--- src/data-structures/graph/undirected-graph.ts | 8 +-- .../graph/directed-graph.test.ts | 6 +-- .../data-structures/graph/overall.test.ts | 4 +- .../graph/undirected-graph.test.ts | 4 +- 10 files changed, 61 insertions(+), 61 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eea0a8b..faa6716 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.38.8](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) +## [v1.38.9](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) ### Changes diff --git a/README.md b/README.md index fe1284f..dc413a5 100644 --- a/README.md +++ b/README.md @@ -106,7 +106,7 @@ bst.getDepth(6) === 3; // true bst.getLeftMost()?.id === 1; // true -bst.remove(6); +bst.delete(6); bst.get(6); // null bst.isAVLBalanced(); // true bst.bfs()[0] === 11; // true @@ -121,7 +121,7 @@ objBST.addMany([{id: 15, keyA: 15}, {id: 1, keyA: 1}, {id: 8, keyA: 8}, {id: 14, keyA: 14}, {id: 4, keyA: 4}, {id: 7, keyA: 7}, {id: 10, keyA: 10}, {id: 5, keyA: 5}]); -objBST.remove(11); +objBST.delete(11); ``` #### JS @@ -142,7 +142,7 @@ bst.getDepth(6) === 3; // true const leftMost = bst.getLeftMost(); leftMost?.id === 1; // true expect(leftMost?.id).toBe(1); -bst.remove(6); +bst.delete(6); bst.get(6); // null bst.isAVLBalanced(); // true or false const bfsIDs = bst.bfs(); @@ -159,12 +159,12 @@ objBST.addMany([{id: 15, keyA: 15}, {id: 1, keyA: 1}, {id: 8, keyA: 8}, {id: 14, keyA: 14}, {id: 4, keyA: 4}, {id: 7, keyA: 7}, {id: 10, keyA: 10}, {id: 5, keyA: 5}]); -objBST.remove(11); +objBST.delete(11); const avlTree = new AVLTree(); avlTree.addMany([11, 3, 15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5]) avlTree.isAVLBalanced(); // true -avlTree.remove(10); +avlTree.delete(10); avlTree.isAVLBalanced(); // true ``` @@ -178,7 +178,7 @@ import {AVLTree} from 'data-structure-typed'; const avlTree = new AVLTree(); avlTree.addMany([11, 3, 15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5]) avlTree.isAVLBalanced(); // true -avlTree.remove(10); +avlTree.delete(10); avlTree.isAVLBalanced(); // true ``` @@ -190,7 +190,7 @@ const {AVLTree} = require('data-structure-typed'); const avlTree = new AVLTree(); avlTree.addMany([11, 3, 15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5]) avlTree.isAVLBalanced(); // true -avlTree.remove(10); +avlTree.delete(10); avlTree.isAVLBalanced(); // true ``` @@ -214,7 +214,7 @@ graph.addEdge('A', 'B'); graph.hasEdge('A', 'B'); // true graph.hasEdge('B', 'A'); // false -graph.removeEdgeSrcToDest('A', 'B'); +graph.deleteEdgeSrcToDest('A', 'B'); graph.hasEdge('A', 'B'); // false graph.addVertex('C'); @@ -237,7 +237,7 @@ graph.addVertex('A'); graph.addVertex('B'); graph.addVertex('C'); graph.addVertex('D'); -graph.removeVertex('C'); +graph.deleteVertex('C'); graph.addEdge('A', 'B'); graph.addEdge('B', 'D'); diff --git a/package-lock.json b/package-lock.json index 33961d3..fe7c2c2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "data-structure-typed", - "version": "1.38.8", + "version": "1.38.9", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "data-structure-typed", - "version": "1.38.8", + "version": "1.38.9", "license": "MIT", "devDependencies": { "@types/benchmark": "^2.1.3", @@ -15,17 +15,17 @@ "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", "auto-changelog": "^2.4.0", - "avl-tree-typed": "^1.38.7", + "avl-tree-typed": "^1.38.8", "benchmark": "^2.1.4", - "binary-tree-typed": "^1.38.7", - "bst-typed": "^1.38.7", + "binary-tree-typed": "^1.38.8", + "bst-typed": "^1.38.8", "dependency-cruiser": "^14.1.0", "eslint": "^8.50.0", "eslint-config-prettier": "^9.0.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.28.1", - "heap-typed": "^1.38.7", + "heap-typed": "^1.38.8", "istanbul-badges-readme": "^1.8.5", "jest": "^29.7.0", "prettier": "^3.0.3", @@ -2728,12 +2728,12 @@ } }, "node_modules/avl-tree-typed": { - "version": "1.38.7", - "resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.38.7.tgz", - "integrity": "sha512-B5lOJoYI/8Y+WUI+atnN8FtKwjOZk6X91O55Qu8p6nauduOZlJvx0HtN3mmTKk0bYNqEHDNK5iyHD60Rwqx5Hw==", + "version": "1.38.8", + "resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.38.8.tgz", + "integrity": "sha512-TMR5vZgH2fGUWDHqG7LNnGmWximwzg4tGthKNT3l9bL7zGnAg2C406j/6Hp/J29mvb5DV+j2NCCeBXmhu/B+AA==", "dev": true, "dependencies": { - "data-structure-typed": "^1.38.7" + "data-structure-typed": "^1.38.8" } }, "node_modules/babel-jest": { @@ -2927,12 +2927,12 @@ } }, "node_modules/binary-tree-typed": { - "version": "1.38.7", - "resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.38.7.tgz", - "integrity": "sha512-Z/xh9iEg0r7WNUzRAPa/yPHJJpc3s0jgC8bioiKgoIU67wxV8Mbn5WbuF+m2oXXpYyaM4qhC+AGU43OkHss7rQ==", + "version": "1.38.8", + "resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.38.8.tgz", + "integrity": "sha512-sS1Efx5XDFY8d1r+pLrt17sZH2bDQbhzJm27OFPO6p/Qkz7qSeJZhYTrpnbr2IFjk3eh0ljkIa3e9+s7AYfhow==", "dev": true, "dependencies": { - "data-structure-typed": "^1.38.7" + "data-structure-typed": "^1.38.8" } }, "node_modules/brace-expansion": { @@ -3011,12 +3011,12 @@ } }, "node_modules/bst-typed": { - "version": "1.38.7", - "resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.38.7.tgz", - "integrity": "sha512-jo8owKRnKPOAbdqR6SmvWjF2yceqN/3j736xujDum4Uh8devBLguV7m49HUv7pfkKAx8uwuuE+6b0dPQaxR4vA==", + "version": "1.38.8", + "resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.38.8.tgz", + "integrity": "sha512-gv3w5u3YIpnmQltcxWbLtpFqom3/z9b/NPdtc57m6rPaRAAWQy4pzyXAETgQX29p8RrCkVn/2cZLC6i6YfEjWw==", "dev": true, "dependencies": { - "data-structure-typed": "^1.38.7" + "data-structure-typed": "^1.38.8" } }, "node_modules/buffer-from": { @@ -3413,9 +3413,9 @@ } }, "node_modules/data-structure-typed": { - "version": "1.38.7", - "resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.38.7.tgz", - "integrity": "sha512-YPV3hlUFTAG93+LoW8eaMv+KS4s9PF5MfpvvUkZybuR7WxqLtamCXWE1o3TRKkYFa9MEguxcq5ZaniCdeLg8Mw==", + "version": "1.38.8", + "resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.38.8.tgz", + "integrity": "sha512-HU+9+HqDLN9f9ipANtibwkK3d65f0FzpvuKavrHSbBMiJvufwchZUxNkfmwGLqgdX8MUGw/Rrk15GpEloYhKNw==", "dev": true }, "node_modules/debug": { @@ -4771,12 +4771,12 @@ } }, "node_modules/heap-typed": { - "version": "1.38.7", - "resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.38.7.tgz", - "integrity": "sha512-9ASCFfeKkN8iPFqgRUskah+a3RAxG4f+sbTVE8xRv4xwHpPLfwGo7gbJLkiJ5fkV+0PRN/ZXUkQPT5cI0XcbZQ==", + "version": "1.38.8", + "resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.38.8.tgz", + "integrity": "sha512-jckb42KnKLidVpfbAChCkrYKFU1rVvTXiH/2G6ABsipzhOIvpM5ItIiR20hT2QP6wkUsEg/CG/K7h3HDQIsXXg==", "dev": true, "dependencies": { - "data-structure-typed": "^1.38.7" + "data-structure-typed": "^1.38.8" } }, "node_modules/html-escaper": { diff --git a/package.json b/package.json index de686d2..af9208a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "data-structure-typed", - "version": "1.38.8", + "version": "1.38.9", "description": "Data Structures of Javascript & TypeScript. Binary Tree, BST, Graph, Heap, Priority Queue, Linked List, Queue, Deque, Stack, AVL Tree, Tree Multiset, Trie, Directed Graph, Undirected Graph, Singly Linked List, Doubly Linked List, Max Heap, Max Priority Queue, Min Heap, Min Priority Queue.", "main": "dist/cjs/index.js", "module": "dist/mjs/index.js", @@ -61,17 +61,17 @@ "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", "auto-changelog": "^2.4.0", - "avl-tree-typed": "^1.38.7", + "avl-tree-typed": "^1.38.8", "benchmark": "^2.1.4", - "binary-tree-typed": "^1.38.7", - "bst-typed": "^1.38.7", + "binary-tree-typed": "^1.38.8", + "bst-typed": "^1.38.8", "dependency-cruiser": "^14.1.0", "eslint": "^8.50.0", "eslint-config-prettier": "^9.0.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.28.1", - "heap-typed": "^1.38.7", + "heap-typed": "^1.38.8", "istanbul-badges-readme": "^1.8.5", "jest": "^29.7.0", "prettier": "^3.0.3", diff --git a/src/data-structures/graph/abstract-graph.ts b/src/data-structures/graph/abstract-graph.ts index f93a731..49ecc28 100644 --- a/src/data-structures/graph/abstract-graph.ts +++ b/src/data-structures/graph/abstract-graph.ts @@ -130,7 +130,7 @@ export abstract class AbstractGraph< */ abstract createEdge(srcOrV1: VertexKey | string, destOrV2: VertexKey | string, weight?: number, val?: E): E; - abstract removeEdge(edge: E): E | null; + abstract deleteEdge(edge: E): E | null; abstract getEdge(srcOrKey: V | VertexKey, destOrKey: V | VertexKey): E | null; @@ -179,12 +179,12 @@ export abstract class AbstractGraph< } /** - * The `removeVertex` function removes a vertex from a graph by its ID or by the vertex object itself. + * The `deleteVertex` function removes a vertex from a graph by its ID or by the vertex object itself. * @param {V | VertexKey} vertexOrKey - The parameter `vertexOrKey` can be either a vertex object (`V`) or a vertex ID * (`VertexKey`). * @returns The method is returning a boolean value. */ - removeVertex(vertexOrKey: V | VertexKey): boolean { + deleteVertex(vertexOrKey: V | VertexKey): boolean { const vertexKey = this._getVertexKey(vertexOrKey); return this._vertices.delete(vertexKey); } @@ -199,7 +199,7 @@ export abstract class AbstractGraph< removeAllVertices(vertices: V[] | VertexKey[]): boolean { const removed: boolean[] = []; for (const v of vertices) { - removed.push(this.removeVertex(v)); + removed.push(this.deleteVertex(v)); } return removed.length > 0; } diff --git a/src/data-structures/graph/directed-graph.ts b/src/data-structures/graph/directed-graph.ts index f30a841..cc29bf3 100644 --- a/src/data-structures/graph/directed-graph.ts +++ b/src/data-structures/graph/directed-graph.ts @@ -153,7 +153,7 @@ export class DirectedGraph = DirectedVertex, E ext * @param {V | VertexKey} destOrKey - The `destOrKey` parameter represents the destination vertex or its ID. * @returns the removed edge (E) if it exists, or null if either the source or destination vertex does not exist. */ - removeEdgeSrcToDest(srcOrKey: V | VertexKey, destOrKey: V | VertexKey): E | null { + deleteEdgeSrcToDest(srcOrKey: V | VertexKey, destOrKey: V | VertexKey): E | null { const src: V | null = this._getVertex(srcOrKey); const dest: V | null = this._getVertex(destOrKey); let removed: E | null = null; @@ -177,9 +177,9 @@ export class DirectedGraph = DirectedVertex, E ext * The function removes an edge from a graph and returns the removed edge, or null if the edge was not found. * @param {E} edge - The `edge` parameter is an object that represents an edge in a graph. It has two properties: `src` * and `dest`, which represent the source and destination vertices of the edge, respectively. - * @returns The method `removeEdge` returns the removed edge (`E`) if it exists, or `null` if the edge does not exist. + * @returns The method `deleteEdge` returns the removed edge (`E`) if it exists, or `null` if the edge does not exist. */ - removeEdge(edge: E): E | null { + deleteEdge(edge: E): E | null { let removed: E | null = null; const src = this._getVertex(edge.src); const dest = this._getVertex(edge.dest); @@ -206,12 +206,12 @@ export class DirectedGraph = DirectedVertex, E ext * the second vertex in the edge that needs to be removed. * @returns an array of removed edges (E[]). */ - removeEdgesBetween(v1: VertexKey | V, v2: VertexKey | V): E[] { + deleteEdgesBetween(v1: VertexKey | V, v2: VertexKey | V): E[] { const removed: E[] = []; if (v1 && v2) { - const v1ToV2 = this.removeEdgeSrcToDest(v1, v2); - const v2ToV1 = this.removeEdgeSrcToDest(v2, v1); + const v1ToV2 = this.deleteEdgeSrcToDest(v1, v2); + const v2ToV1 = this.deleteEdgeSrcToDest(v2, v1); v1ToV2 && removed.push(v1ToV2); v2ToV1 && removed.push(v2ToV1); diff --git a/src/data-structures/graph/undirected-graph.ts b/src/data-structures/graph/undirected-graph.ts index a7a81ff..8bdf1c2 100644 --- a/src/data-structures/graph/undirected-graph.ts +++ b/src/data-structures/graph/undirected-graph.ts @@ -127,7 +127,7 @@ export class UndirectedGraph< * (VertexKey). It represents the second vertex of the edge that needs to be removed. * @returns the removed edge (E) if it exists, or null if either of the vertices (V) does not exist. */ - removeEdgeBetween(v1: V | VertexKey, v2: V | VertexKey): E | null { + deleteEdgeBetween(v1: V | VertexKey, v2: V | VertexKey): E | null { const vertex1: V | null = this._getVertex(v1); const vertex2: V | null = this._getVertex(v2); @@ -148,12 +148,12 @@ export class UndirectedGraph< } /** - * The removeEdge function removes an edge between two vertices in a graph. + * The deleteEdge function removes an edge between two vertices in a graph. * @param {E} edge - The parameter "edge" is of type E, which represents an edge in a graph. * @returns The method is returning either the removed edge (of type E) or null if the edge was not found. */ - removeEdge(edge: E): E | null { - return this.removeEdgeBetween(edge.vertices[0], edge.vertices[1]); + deleteEdge(edge: E): E | null { + return this.deleteEdgeBetween(edge.vertices[0], edge.vertices[1]); } /** diff --git a/test/unit/data-structures/graph/directed-graph.test.ts b/test/unit/data-structures/graph/directed-graph.test.ts index e942041..fcd8443 100644 --- a/test/unit/data-structures/graph/directed-graph.test.ts +++ b/test/unit/data-structures/graph/directed-graph.test.ts @@ -40,7 +40,7 @@ describe('DirectedGraph Operation Test', () => { graph.addVertex(vertex2); graph.addEdge(edge); - expect(graph.removeEdge(edge)).toBe(edge); + expect(graph.deleteEdge(edge)).toBe(edge); expect(graph.hasEdge('A', 'B')).toBe(false); }); @@ -164,7 +164,7 @@ describe('Inherit from DirectedGraph and perform operations', () => { myGraph.addVertex(2, 'data2'); myGraph.addEdge(1, 2, 10, 'edge-data1-2'); - const removedEdge = myGraph.removeEdgeSrcToDest(1, 2); + const removedEdge = myGraph.deleteEdgeSrcToDest(1, 2); const edgeAfterRemoval = myGraph.getEdge(1, 2); expect(removedEdge).toBeInstanceOf(MyEdge); @@ -233,7 +233,7 @@ describe('Inherit from DirectedGraph and perform operations test2.', () => { expect(myGraph.getEdge(2, 1)).toBeTruthy(); expect(myGraph.getEdge(1, '100')).toBeFalsy(); - myGraph.removeEdgeSrcToDest(1, 2); + myGraph.deleteEdgeSrcToDest(1, 2); expect(myGraph.getEdge(1, 2)).toBeFalsy(); myGraph.addEdge(3, 1, 3, 'edge-data-3-1'); diff --git a/test/unit/data-structures/graph/overall.test.ts b/test/unit/data-structures/graph/overall.test.ts index 883ff5d..fee3094 100644 --- a/test/unit/data-structures/graph/overall.test.ts +++ b/test/unit/data-structures/graph/overall.test.ts @@ -20,7 +20,7 @@ describe('Overall Graph Operation Test', () => { expect(graph.hasEdge('A', 'B')).toBe(true); // true expect(graph.hasEdge('B', 'A')).toBe(false); // false - graph.removeEdgeSrcToDest('A', 'B'); + graph.deleteEdgeSrcToDest('A', 'B'); graph.hasEdge('A', 'B'); // false expect(graph.hasEdge('A', 'B')).toBe(false); // false @@ -38,7 +38,7 @@ describe('Overall Graph Operation Test', () => { graph.addVertex('B'); graph.addVertex('C'); graph.addVertex('D'); - graph.removeVertex('C'); + graph.deleteVertex('C'); graph.addEdge('A', 'B'); graph.addEdge('B', 'D'); diff --git a/test/unit/data-structures/graph/undirected-graph.test.ts b/test/unit/data-structures/graph/undirected-graph.test.ts index 3d0eb6e..9d81ee1 100644 --- a/test/unit/data-structures/graph/undirected-graph.test.ts +++ b/test/unit/data-structures/graph/undirected-graph.test.ts @@ -40,7 +40,7 @@ describe('UndirectedGraph Operation Test', () => { graph.addVertex(vertex2); graph.addEdge(edge); - expect(graph.removeEdge(edge)).toBe(edge); + expect(graph.deleteEdge(edge)).toBe(edge); expect(graph.hasEdge('A', 'B')).toBe(false); }); @@ -49,7 +49,7 @@ describe('UndirectedGraph Operation Test', () => { graph.addVertex('B'); graph.addVertex('C'); graph.addVertex('D'); - graph.removeVertex('C'); + graph.deleteVertex('C'); graph.addEdge('A', 'B'); graph.addEdge('B', 'D'); From 6c45f53f72216609fa3b11cfde580ae9909d8c06 Mon Sep 17 00:00:00 2001 From: Revone Date: Sat, 28 Oct 2023 17:37:51 +0800 Subject: [PATCH 32/46] [heap, priority-queue, binary-indexed-tree] Heap and PriorityQueue constructors use a single object as a parameter for uniformity with the design of other data structures. Binary Indexed Tree includes the getPrefixSum method. --- CHANGELOG.md | 2 +- package-lock.json | 50 +++++++++---------- package.json | 10 ++-- .../binary-tree/binary-indexed-tree.ts | 20 ++++++++ src/data-structures/graph/abstract-graph.ts | 2 +- src/data-structures/heap/heap.ts | 24 ++++----- src/data-structures/heap/max-heap.ts | 14 +++--- src/data-structures/heap/min-heap.ts | 14 +++--- .../priority-queue/max-priority-queue.ts | 14 +++--- .../priority-queue/min-priority-queue.ts | 14 +++--- .../priority-queue/priority-queue.ts | 6 +-- test/integration/bst.test.ts | 2 +- .../binary-tree/avl-tree.test.ts | 2 +- .../binary-tree/binary-index-tree.test.ts | 35 +++++++++++++ .../binary-tree/binary-tree.test.ts | 2 +- .../data-structures/binary-tree/bst.test.ts | 6 +-- .../binary-tree/overall.test.ts | 2 +- .../binary-tree/tree-multiset.test.ts | 2 +- test/unit/data-structures/heap/heap.test.ts | 4 +- .../data-structures/heap/max-heap.test.ts | 2 +- .../data-structures/heap/min-heap.test.ts | 2 +- .../linked-list/doubly-linked-list.test.ts | 2 +- .../linked-list/singly-linked-list.test.ts | 4 +- .../priority-queue/max-priority-queue.test.ts | 6 +-- .../priority-queue/priority-queue.test.ts | 20 ++++---- test/utils/big-o.ts | 2 +- 26 files changed, 163 insertions(+), 100 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index faa6716..43c4c33 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.38.9](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) +## [v1.39.0](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) ### Changes diff --git a/package-lock.json b/package-lock.json index fe7c2c2..036d8c4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "data-structure-typed", - "version": "1.38.9", + "version": "1.39.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "data-structure-typed", - "version": "1.38.9", + "version": "1.39.0", "license": "MIT", "devDependencies": { "@types/benchmark": "^2.1.3", @@ -15,17 +15,17 @@ "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", "auto-changelog": "^2.4.0", - "avl-tree-typed": "^1.38.8", + "avl-tree-typed": "^1.38.9", "benchmark": "^2.1.4", - "binary-tree-typed": "^1.38.8", - "bst-typed": "^1.38.8", + "binary-tree-typed": "^1.38.9", + "bst-typed": "^1.38.9", "dependency-cruiser": "^14.1.0", "eslint": "^8.50.0", "eslint-config-prettier": "^9.0.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.28.1", - "heap-typed": "^1.38.8", + "heap-typed": "^1.38.9", "istanbul-badges-readme": "^1.8.5", "jest": "^29.7.0", "prettier": "^3.0.3", @@ -2728,12 +2728,12 @@ } }, "node_modules/avl-tree-typed": { - "version": "1.38.8", - "resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.38.8.tgz", - "integrity": "sha512-TMR5vZgH2fGUWDHqG7LNnGmWximwzg4tGthKNT3l9bL7zGnAg2C406j/6Hp/J29mvb5DV+j2NCCeBXmhu/B+AA==", + "version": "1.38.9", + "resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.38.9.tgz", + "integrity": "sha512-1Qy7d5G8JXa5Z2KKmlZI1WOmJkIyW6l2zRGHCxXItEfIg+BirZm6BK4IOb03OJjA2qg2N5AxgZDKuMDAzbRXNw==", "dev": true, "dependencies": { - "data-structure-typed": "^1.38.8" + "data-structure-typed": "^1.38.9" } }, "node_modules/babel-jest": { @@ -2927,12 +2927,12 @@ } }, "node_modules/binary-tree-typed": { - "version": "1.38.8", - "resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.38.8.tgz", - "integrity": "sha512-sS1Efx5XDFY8d1r+pLrt17sZH2bDQbhzJm27OFPO6p/Qkz7qSeJZhYTrpnbr2IFjk3eh0ljkIa3e9+s7AYfhow==", + "version": "1.38.9", + "resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.38.9.tgz", + "integrity": "sha512-XGp+ADfVMhhpEqLV+Bi27FkJcT1P6ExPpGuhzhKzyfoWmsnjp94tuuvrUDCqPjYoioGwzbG7yUnC2Fbi4CbsAA==", "dev": true, "dependencies": { - "data-structure-typed": "^1.38.8" + "data-structure-typed": "^1.38.9" } }, "node_modules/brace-expansion": { @@ -3011,12 +3011,12 @@ } }, "node_modules/bst-typed": { - "version": "1.38.8", - "resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.38.8.tgz", - "integrity": "sha512-gv3w5u3YIpnmQltcxWbLtpFqom3/z9b/NPdtc57m6rPaRAAWQy4pzyXAETgQX29p8RrCkVn/2cZLC6i6YfEjWw==", + "version": "1.38.9", + "resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.38.9.tgz", + "integrity": "sha512-jnHwqyTjRCDitmzXydhcP1YmRsCfBYxwhDXD8lm1pQPWOXkcAIU7HqTg7WCPrReo1GaWfQJeBhAIsguluEQ6Lw==", "dev": true, "dependencies": { - "data-structure-typed": "^1.38.8" + "data-structure-typed": "^1.38.9" } }, "node_modules/buffer-from": { @@ -3413,9 +3413,9 @@ } }, "node_modules/data-structure-typed": { - "version": "1.38.8", - "resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.38.8.tgz", - "integrity": "sha512-HU+9+HqDLN9f9ipANtibwkK3d65f0FzpvuKavrHSbBMiJvufwchZUxNkfmwGLqgdX8MUGw/Rrk15GpEloYhKNw==", + "version": "1.38.9", + "resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.38.9.tgz", + "integrity": "sha512-iHOVtsBY7ZVI28I0ikedDFmBeu3rGu1gSnmemg11PT/KIuflNe9zdwlNm+yZ4M56LbQp0aqY09YoNnNX43UvRw==", "dev": true }, "node_modules/debug": { @@ -4771,12 +4771,12 @@ } }, "node_modules/heap-typed": { - "version": "1.38.8", - "resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.38.8.tgz", - "integrity": "sha512-jckb42KnKLidVpfbAChCkrYKFU1rVvTXiH/2G6ABsipzhOIvpM5ItIiR20hT2QP6wkUsEg/CG/K7h3HDQIsXXg==", + "version": "1.38.9", + "resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.38.9.tgz", + "integrity": "sha512-50RxpJOqMDMbpGa3NZny3YO8NArmwVeIipNDHkOvHXH+P93BvbaFz06rOyuJ1cUxDwTPsv34VfJgrz576/BZtg==", "dev": true, "dependencies": { - "data-structure-typed": "^1.38.8" + "data-structure-typed": "^1.38.9" } }, "node_modules/html-escaper": { diff --git a/package.json b/package.json index af9208a..8ee3af3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "data-structure-typed", - "version": "1.38.9", + "version": "1.39.0", "description": "Data Structures of Javascript & TypeScript. Binary Tree, BST, Graph, Heap, Priority Queue, Linked List, Queue, Deque, Stack, AVL Tree, Tree Multiset, Trie, Directed Graph, Undirected Graph, Singly Linked List, Doubly Linked List, Max Heap, Max Priority Queue, Min Heap, Min Priority Queue.", "main": "dist/cjs/index.js", "module": "dist/mjs/index.js", @@ -61,17 +61,17 @@ "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", "auto-changelog": "^2.4.0", - "avl-tree-typed": "^1.38.8", + "avl-tree-typed": "^1.38.9", "benchmark": "^2.1.4", - "binary-tree-typed": "^1.38.8", - "bst-typed": "^1.38.8", + "binary-tree-typed": "^1.38.9", + "bst-typed": "^1.38.9", "dependency-cruiser": "^14.1.0", "eslint": "^8.50.0", "eslint-config-prettier": "^9.0.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.28.1", - "heap-typed": "^1.38.8", + "heap-typed": "^1.38.9", "istanbul-badges-readme": "^1.8.5", "jest": "^29.7.0", "prettier": "^3.0.3", diff --git a/src/data-structures/binary-tree/binary-indexed-tree.ts b/src/data-structures/binary-tree/binary-indexed-tree.ts index 467e918..4b4e8dd 100644 --- a/src/data-structures/binary-tree/binary-indexed-tree.ts +++ b/src/data-structures/binary-tree/binary-indexed-tree.ts @@ -143,6 +143,26 @@ export class BinaryIndexedTree { return this._binarySearch(sum, (x, y) => x <= y); } + /** + * The function calculates the prefix sum of an array using a binary indexed tree. + * @param {number} i - The parameter "i" in the function "getPrefixSum" represents the index of the element in the + * array for which we want to calculate the prefix sum. + * @returns The function `getPrefixSum` returns the prefix sum of the elements in the binary indexed tree up to index + * `i`. + */ + getPrefixSum(i: number): number { + this._checkIndex(i); + i++; // Convert to 1-based index + + let sum = 0; + while (i > 0) { + sum += this._getFrequency(i); + i -= i & -i; + } + + return sum; + } + /** * The function returns the value of a specific index in a freqMap data structure, or a default value if * the index is not found. diff --git a/src/data-structures/graph/abstract-graph.ts b/src/data-structures/graph/abstract-graph.ts index 49ecc28..adc52db 100644 --- a/src/data-structures/graph/abstract-graph.ts +++ b/src/data-structures/graph/abstract-graph.ts @@ -622,7 +622,7 @@ export abstract class AbstractGraph< if (vertexOrKey instanceof AbstractVertex) distMap.set(vertexOrKey, Infinity); } - const heap = new PriorityQueue<{ key: number; val: V }>((a, b) => a.key - b.key); + const heap = new PriorityQueue<{ key: number; val: V }>({comparator: (a, b) => a.key - b.key}); heap.add({key: 0, val: srcVertex}); distMap.set(srcVertex, 0); diff --git a/src/data-structures/heap/heap.ts b/src/data-structures/heap/heap.ts index 177b1e7..b4a197b 100644 --- a/src/data-structures/heap/heap.ts +++ b/src/data-structures/heap/heap.ts @@ -7,12 +7,16 @@ import type {Comparator, DFSOrderPattern} from '../../types'; -export class Heap { +export class Heap { protected nodes: E[] = []; protected readonly comparator: Comparator; - constructor(comparator: Comparator) { - this.comparator = comparator; + constructor(options: { comparator: Comparator; nodes?: E[] }) { + this.comparator = options.comparator; + if (options.nodes && options.nodes.length > 0) { + this.nodes = options.nodes; + this.fix(); + } } /** @@ -32,15 +36,11 @@ export class Heap { /** * Static method that creates a binary heap from an array of nodes and a comparison function. - * @param nodes - * @param comparator - Comparison function. * @returns A new Heap instance. + * @param options */ - static heapify(nodes: E[], comparator: Comparator): Heap { - const binaryHeap = new Heap(comparator); - binaryHeap.nodes = [...nodes]; - binaryHeap.fix(); // Fix heap properties - return binaryHeap; + static heapify(options: { nodes: E[]; comparator: Comparator }): Heap { + return new Heap(options); } /** @@ -180,7 +180,7 @@ export class Heap { * @returns A new Heap instance containing the same elements. */ clone(): Heap { - const clonedHeap = new Heap(this.comparator); + const clonedHeap = new Heap({comparator: this.comparator}); clonedHeap.nodes = [...this.nodes]; return clonedHeap; } @@ -269,7 +269,7 @@ export class FibonacciHeapNode { export class FibonacciHeap { root?: FibonacciHeapNode; - size: number = 0; + size = 0; protected min?: FibonacciHeapNode; protected readonly comparator: Comparator; diff --git a/src/data-structures/heap/max-heap.ts b/src/data-structures/heap/max-heap.ts index 55ace08..139ef64 100644 --- a/src/data-structures/heap/max-heap.ts +++ b/src/data-structures/heap/max-heap.ts @@ -11,14 +11,16 @@ import type {Comparator} from '../../types'; export class MaxHeap extends Heap { constructor( - comparator: 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 b - a; + options: { comparator: Comparator; nodes?: E[] } = { + 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 b - a; + } } } ) { - super(comparator); + super(options); } } diff --git a/src/data-structures/heap/min-heap.ts b/src/data-structures/heap/min-heap.ts index fcc809b..5057017 100644 --- a/src/data-structures/heap/min-heap.ts +++ b/src/data-structures/heap/min-heap.ts @@ -11,14 +11,16 @@ import type {Comparator} from '../../types'; export class MinHeap extends Heap { constructor( - comparator: 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; + options: { comparator: Comparator; nodes?: E[] } = { + 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; + } } } ) { - super(comparator); + super(options); } } diff --git a/src/data-structures/priority-queue/max-priority-queue.ts b/src/data-structures/priority-queue/max-priority-queue.ts index 49f016e..409c99f 100644 --- a/src/data-structures/priority-queue/max-priority-queue.ts +++ b/src/data-structures/priority-queue/max-priority-queue.ts @@ -10,14 +10,16 @@ import type {Comparator} from '../../types'; export class MaxPriorityQueue extends PriorityQueue { constructor( - compare: 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 b - a; + options: { comparator: Comparator; nodes?: E[] } = { + 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 b - a; + } } } ) { - super(compare); + super(options); } } diff --git a/src/data-structures/priority-queue/min-priority-queue.ts b/src/data-structures/priority-queue/min-priority-queue.ts index 0e1b3e8..da8ab64 100644 --- a/src/data-structures/priority-queue/min-priority-queue.ts +++ b/src/data-structures/priority-queue/min-priority-queue.ts @@ -10,14 +10,16 @@ import type {Comparator} from '../../types'; export class MinPriorityQueue extends PriorityQueue { constructor( - compare: 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; + options: { comparator: Comparator; nodes?: E[] } = { + 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; + } } } ) { - super(compare); + super(options); } } diff --git a/src/data-structures/priority-queue/priority-queue.ts b/src/data-structures/priority-queue/priority-queue.ts index 2bc2769..60deb98 100644 --- a/src/data-structures/priority-queue/priority-queue.ts +++ b/src/data-structures/priority-queue/priority-queue.ts @@ -9,8 +9,8 @@ import {Heap} from '../heap'; import {Comparator} from '../../types'; -export class PriorityQueue extends Heap { - constructor(comparator: Comparator) { - super(comparator); +export class PriorityQueue extends Heap { + constructor(options: { comparator: Comparator; nodes?: E[] }) { + super(options); } } diff --git a/test/integration/bst.test.ts b/test/integration/bst.test.ts index 0a33db7..35a6061 100644 --- a/test/integration/bst.test.ts +++ b/test/integration/bst.test.ts @@ -183,7 +183,7 @@ describe('Individual package BST operations test', () => { }); it('should perform various operations on a Binary Search Tree with object values', () => { - const objBST = new BST<{key: number; keyA: number}>(); + const objBST = new BST<{ key: number; keyA: number }>(); expect(objBST).toBeInstanceOf(BST); objBST.add(11, {key: 11, keyA: 11}); objBST.add(3, {key: 3, keyA: 3}); diff --git a/test/unit/data-structures/binary-tree/avl-tree.test.ts b/test/unit/data-structures/binary-tree/avl-tree.test.ts index cfd74ea..5c99c38 100644 --- a/test/unit/data-structures/binary-tree/avl-tree.test.ts +++ b/test/unit/data-structures/binary-tree/avl-tree.test.ts @@ -110,7 +110,7 @@ describe('AVL Tree Test', () => { }); describe('AVLTree APIs test', () => { - const avl = new AVLTree<{id: number; text: string}>(); + const avl = new AVLTree<{ id: number; text: string }>(); beforeEach(() => { avl.clear(); }); diff --git a/test/unit/data-structures/binary-tree/binary-index-tree.test.ts b/test/unit/data-structures/binary-tree/binary-index-tree.test.ts index dbbf71e..db4e912 100644 --- a/test/unit/data-structures/binary-tree/binary-index-tree.test.ts +++ b/test/unit/data-structures/binary-tree/binary-index-tree.test.ts @@ -283,3 +283,38 @@ function loopLowerBoundTests(bit: BinaryIndexedTree, values: number[]) { } } } + +describe('', () => { + class NumArrayDC { + private _tree: BinaryIndexedTree; + private readonly _nums: number[]; + + constructor(nums: number[]) { + this._nums = nums; + this._tree = new BinaryIndexedTree({max: nums.length + 1}); + for (let i = 0; i < nums.length; i++) { + this._tree.update(i + 1, nums[i]); + } + } + + update(index: number, val: number): void { + this._tree.update(index + 1, val - this._nums[index]); + this._nums[index] = val; + } + + sumRange(left: number, right: number): number { + return this._tree.getPrefixSum(right + 1) - this._tree.getPrefixSum(left); + } + } + + it('', () => { + const numArray = new NumArrayDC([1, 3, 5, 8, 2, 9, 4, 5, 8, 1, 3, 2]); + expect(numArray.sumRange(0, 8)).toBe(45); + expect(numArray.sumRange(0, 2)).toBe(9); + numArray.update(1, 2); + expect(numArray.sumRange(0, 2)).toBe(8); + expect(numArray.sumRange(3, 4)).toBe(10); + numArray.update(3, 2); + expect(numArray.sumRange(3, 4)).toBe(4); + }); +}); diff --git a/test/unit/data-structures/binary-tree/binary-tree.test.ts b/test/unit/data-structures/binary-tree/binary-tree.test.ts index 97e3482..3398166 100644 --- a/test/unit/data-structures/binary-tree/binary-tree.test.ts +++ b/test/unit/data-structures/binary-tree/binary-tree.test.ts @@ -200,7 +200,7 @@ describe('BinaryTree Morris Traversal', () => { }); describe('BinaryTree APIs test', () => { - const avl = new AVLTree<{id: number; text: string}>(); + const avl = new AVLTree<{ id: number; text: string }>(); beforeEach(() => { avl.clear(); }); diff --git a/test/unit/data-structures/binary-tree/bst.test.ts b/test/unit/data-structures/binary-tree/bst.test.ts index 7f8e374..1991ad0 100644 --- a/test/unit/data-structures/binary-tree/bst.test.ts +++ b/test/unit/data-structures/binary-tree/bst.test.ts @@ -189,7 +189,7 @@ describe('BST operations test', () => { }); it('should perform various operations on a Binary Search Tree with object values', () => { - const objBST = new BST<{key: number; keyA: number}>(); + const objBST = new BST<{ key: number; keyA: number }>(); expect(objBST).toBeInstanceOf(BST); objBST.add(11, {key: 11, keyA: 11}); objBST.add(3, {key: 3, keyA: 3}); @@ -260,7 +260,7 @@ describe('BST operations test', () => { objBST.perfectlyBalance(); expect(objBST.isPerfectlyBalanced()).toBe(true); - const bfsNodesAfterBalanced: BSTNode<{key: number; keyA: number}>[] = []; + const bfsNodesAfterBalanced: BSTNode<{ key: number; keyA: number }>[] = []; objBST.bfs(node => bfsNodesAfterBalanced.push(node)); expect(bfsNodesAfterBalanced[0].key).toBe(8); expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16); @@ -385,7 +385,7 @@ describe('BST operations test', () => { expect(bfsIDs[1]).toBe(12); expect(bfsIDs[2]).toBe(16); - const bfsNodes: BSTNode<{key: number; keyA: number}>[] = []; + const bfsNodes: BSTNode<{ key: number; keyA: number }>[] = []; objBST.bfs(node => bfsNodes.push(node)); expect(bfsNodes[0].key).toBe(2); expect(bfsNodes[1].key).toBe(12); diff --git a/test/unit/data-structures/binary-tree/overall.test.ts b/test/unit/data-structures/binary-tree/overall.test.ts index 520c2bc..8c1921c 100644 --- a/test/unit/data-structures/binary-tree/overall.test.ts +++ b/test/unit/data-structures/binary-tree/overall.test.ts @@ -29,7 +29,7 @@ describe('Overall BinaryTree Test', () => { bfsIDs[0] === 11; // true expect(bfsIDs[0]).toBe(11); - const objBST = new BST<{key: number; keyA: number}>(); + const objBST = new BST<{ key: number; keyA: number }>(); objBST.add(11, {key: 11, keyA: 11}); objBST.add(3, {key: 3, keyA: 3}); diff --git a/test/unit/data-structures/binary-tree/tree-multiset.test.ts b/test/unit/data-structures/binary-tree/tree-multiset.test.ts index 8de9ddd..361b90d 100644 --- a/test/unit/data-structures/binary-tree/tree-multiset.test.ts +++ b/test/unit/data-structures/binary-tree/tree-multiset.test.ts @@ -206,7 +206,7 @@ describe('TreeMultiset operations test', () => { }); it('should perform various operations on a Binary Search Tree with object values', () => { - const objTreeMultiset = new TreeMultiset<{key: number; keyA: number}>(); + const objTreeMultiset = new TreeMultiset<{ key: number; keyA: number }>(); expect(objTreeMultiset).toBeInstanceOf(TreeMultiset); objTreeMultiset.add(11, {key: 11, keyA: 11}); objTreeMultiset.add(3, {key: 3, keyA: 3}); diff --git a/test/unit/data-structures/heap/heap.test.ts b/test/unit/data-structures/heap/heap.test.ts index 8745402..d827b91 100644 --- a/test/unit/data-structures/heap/heap.test.ts +++ b/test/unit/data-structures/heap/heap.test.ts @@ -22,7 +22,7 @@ describe('Heap Operation Test', () => { }); it('should object heap work well', function () { - const minHeap = new MinHeap<{a: string; key: number}>((a, b) => a.key - b.key); + const minHeap = new MinHeap<{ a: string; key: number }>({comparator: (a, b) => a.key - b.key}); minHeap.add({key: 1, a: 'a1'}); minHeap.add({key: 6, a: 'a6'}); minHeap.add({key: 2, a: 'a2'}); @@ -37,7 +37,7 @@ describe('Heap Operation Test', () => { i++; } - const maxHeap = new MaxHeap<{key: number; a: string}>((a, b) => b.key - a.key); + const maxHeap = new MaxHeap<{ key: number; a: string }>({comparator: (a, b) => b.key - a.key}); maxHeap.add({key: 1, a: 'a1'}); maxHeap.add({key: 6, a: 'a6'}); maxHeap.add({key: 5, a: 'a5'}); diff --git a/test/unit/data-structures/heap/max-heap.test.ts b/test/unit/data-structures/heap/max-heap.test.ts index b6dd044..67ec6f8 100644 --- a/test/unit/data-structures/heap/max-heap.test.ts +++ b/test/unit/data-structures/heap/max-heap.test.ts @@ -5,7 +5,7 @@ describe('MaxHeap', () => { let maxHeap: MaxHeap; beforeEach(() => { - maxHeap = new MaxHeap(numberComparator); + maxHeap = new MaxHeap({comparator: numberComparator}); }); test('add and poll elements in descending order', () => { diff --git a/test/unit/data-structures/heap/min-heap.test.ts b/test/unit/data-structures/heap/min-heap.test.ts index be8d548..d462c9b 100644 --- a/test/unit/data-structures/heap/min-heap.test.ts +++ b/test/unit/data-structures/heap/min-heap.test.ts @@ -5,7 +5,7 @@ describe('MinHeap', () => { let minHeap: MinHeap; beforeEach(() => { - minHeap = new MinHeap(numberComparator); + minHeap = new MinHeap({comparator: numberComparator}); }); test('add and poll elements in ascending order', () => { diff --git a/test/unit/data-structures/linked-list/doubly-linked-list.test.ts b/test/unit/data-structures/linked-list/doubly-linked-list.test.ts index eab2ad5..0838337 100644 --- a/test/unit/data-structures/linked-list/doubly-linked-list.test.ts +++ b/test/unit/data-structures/linked-list/doubly-linked-list.test.ts @@ -3,7 +3,7 @@ import {bigO, magnitude} from '../../../utils'; describe('DoublyLinkedList Operation Test', () => { let list: DoublyLinkedList; - let objectList: DoublyLinkedList<{keyA: number}>; + let objectList: DoublyLinkedList<{ keyA: number }>; beforeEach(() => { list = new DoublyLinkedList(); diff --git a/test/unit/data-structures/linked-list/singly-linked-list.test.ts b/test/unit/data-structures/linked-list/singly-linked-list.test.ts index 74a3de8..092b2e6 100644 --- a/test/unit/data-structures/linked-list/singly-linked-list.test.ts +++ b/test/unit/data-structures/linked-list/singly-linked-list.test.ts @@ -3,10 +3,10 @@ import {bigO, magnitude} from '../../../utils'; describe('SinglyLinkedList Operation Test', () => { let list: SinglyLinkedList; - let objectList: SinglyLinkedList<{keyA: number}>; + let objectList: SinglyLinkedList<{ keyA: number }>; beforeEach(() => { list = new SinglyLinkedList(); - objectList = new SinglyLinkedList<{keyA: number}>(); + objectList = new SinglyLinkedList<{ keyA: number }>(); }); describe('push', () => { diff --git a/test/unit/data-structures/priority-queue/max-priority-queue.test.ts b/test/unit/data-structures/priority-queue/max-priority-queue.test.ts index f8a63bc..8b2f287 100644 --- a/test/unit/data-structures/priority-queue/max-priority-queue.test.ts +++ b/test/unit/data-structures/priority-queue/max-priority-queue.test.ts @@ -17,7 +17,7 @@ describe('MaxPriorityQueue Operation Test', () => { }); it('should add elements and maintain heap property in a object MaxPriorityQueue', () => { - const priorityQueue = new MaxPriorityQueue<{keyA: number}>((a, b) => b.keyA - a.keyA); + const priorityQueue = new MaxPriorityQueue<{ keyA: number }>({comparator: (a, b) => b.keyA - a.keyA}); priorityQueue.refill([{keyA: 5}, {keyA: 3}, {keyA: 1}]); priorityQueue.add({keyA: 7}); @@ -53,7 +53,7 @@ describe('MaxPriorityQueue Operation Test', () => { it('should correctly heapify an array', () => { const array = [5, 3, 7, 1]; - const heap = MaxPriorityQueue.heapify(array, (a, b) => b - a); + const heap = MaxPriorityQueue.heapify({nodes: array, comparator: (a, b) => b - a}); heap.refill(array); expect(heap.poll()).toBe(7); @@ -64,7 +64,7 @@ describe('MaxPriorityQueue Operation Test', () => { it('should correctly heapify an object array', () => { const nodes = [{keyA: 5}, {keyA: 3}, {keyA: 7}, {keyA: 1}]; - const maxPQ = MaxPriorityQueue.heapify<{keyA: number}>(nodes, (a, b) => b.keyA - a.keyA); + const maxPQ = MaxPriorityQueue.heapify<{ keyA: number }>({nodes: nodes, comparator: (a, b) => b.keyA - a.keyA}); expect(maxPQ.poll()?.keyA).toBe(7); expect(maxPQ.poll()?.keyA).toBe(5); diff --git a/test/unit/data-structures/priority-queue/priority-queue.test.ts b/test/unit/data-structures/priority-queue/priority-queue.test.ts index 29bcd87..dd4fba0 100644 --- a/test/unit/data-structures/priority-queue/priority-queue.test.ts +++ b/test/unit/data-structures/priority-queue/priority-queue.test.ts @@ -3,7 +3,7 @@ import {getRandomInt} from '../../../utils'; describe('PriorityQueue Operation Test', () => { it('should PriorityQueue poll, pee, heapify, toArray work well', function () { - const minPQ = new PriorityQueue((a, b) => a - b); + const minPQ = new PriorityQueue({comparator: (a, b) => a - b}); minPQ.refill([5, 2, 3, 4, 6, 1]); expect(minPQ.toArray()).toEqual([1, 2, 3, 4, 6, 5]); minPQ.poll(); @@ -11,13 +11,13 @@ describe('PriorityQueue Operation Test', () => { minPQ.poll(); expect(minPQ.toArray()).toEqual([4, 5, 6]); expect(minPQ.peek()).toBe(4); - expect(PriorityQueue.heapify([3, 2, 1, 5, 6, 7, 8, 9, 10], (a, b) => a - b).toArray()).toEqual([ - 1, 2, 3, 5, 6, 7, 8, 9, 10 - ]); + expect(PriorityQueue.heapify({nodes: [3, 2, 1, 5, 6, 7, 8, 9, 10], comparator: (a, b) => a - b}).toArray()).toEqual( + [1, 2, 3, 5, 6, 7, 8, 9, 10] + ); }); it('should Max PriorityQueue poll, peek, heapify, toArray work well', function () { - const maxPriorityQueue = new PriorityQueue((a, b) => b - a); + const maxPriorityQueue = new PriorityQueue({comparator: (a, b) => b - a}); maxPriorityQueue.refill([5, 2, 3, 4, 6, 1]); expect(maxPriorityQueue.toArray()).toEqual([6, 5, 3, 4, 2, 1]); maxPriorityQueue.poll(); @@ -25,13 +25,13 @@ describe('PriorityQueue Operation Test', () => { maxPriorityQueue.poll(); expect(maxPriorityQueue.toArray()).toEqual([3, 2, 1]); expect(maxPriorityQueue.peek()).toBe(3); - expect(PriorityQueue.heapify([3, 2, 1, 5, 6, 7, 8, 9, 10], (a, b) => a - b).toArray()).toEqual([ - 1, 2, 3, 5, 6, 7, 8, 9, 10 - ]); + expect(PriorityQueue.heapify({nodes: [3, 2, 1, 5, 6, 7, 8, 9, 10], comparator: (a, b) => a - b}).toArray()).toEqual( + [1, 2, 3, 5, 6, 7, 8, 9, 10] + ); }); it('should PriorityQueue clone, sort, getNodes, dfs work well', function () { - const minPQ1 = new PriorityQueue((a, b) => a - b); + const minPQ1 = new PriorityQueue({comparator: (a, b) => a - b}); minPQ1.refill([2, 5, 8, 3, 1, 6, 7, 4]); const clonedPriorityQueue = minPQ1.clone(); expect(clonedPriorityQueue.getNodes()).toEqual(minPQ1.getNodes()); @@ -45,7 +45,7 @@ describe('PriorityQueue Operation Test', () => { describe('Priority Queue Performance Test', () => { it('should numeric heap work well', function () { const values = Array.from(new Array(10000), () => getRandomInt(1, 10000000)); - const minPriorityQueue = new PriorityQueue((a, b) => a - b); + const minPriorityQueue = new PriorityQueue({comparator: (a, b) => a - b}); minPriorityQueue.refill(values); const sorted = minPriorityQueue.sort(); expect(sorted).toEqual(values.sort((a, b) => a - b)); diff --git a/test/utils/big-o.ts b/test/utils/big-o.ts index 43d7eca..cc9fc86 100644 --- a/test/utils/big-o.ts +++ b/test/utils/big-o.ts @@ -26,7 +26,7 @@ export const bigO = { function findPotentialN(input: any): number { let longestArray: any[] = []; - let mostProperties: {[key: string]: any} = {}; + let mostProperties: { [key: string]: any } = {}; function recurse(obj: any) { if (Array.isArray(obj)) { From bd1720973af406d0dd692651754411b489b508e4 Mon Sep 17 00:00:00 2001 From: Revone Date: Sat, 28 Oct 2023 23:54:27 +0800 Subject: [PATCH 33/46] [test] Increase the test coverage to 89.51. --- package.json | 2 +- src/data-structures/binary-tree/avl-tree.ts | 9 +- .../binary-tree/binary-indexed-tree.ts | 2 +- .../binary-tree/binary-tree.ts | 130 ++---- src/data-structures/binary-tree/bst.ts | 28 +- src/data-structures/binary-tree/rb-tree.ts | 3 +- .../binary-tree/tree-multiset.ts | 7 +- src/data-structures/graph/abstract-graph.ts | 23 +- src/data-structures/graph/directed-graph.ts | 3 +- src/data-structures/graph/map-graph.ts | 4 +- src/data-structures/graph/undirected-graph.ts | 9 +- src/data-structures/hash/hash-map.ts | 2 +- src/data-structures/hash/tree-map.ts | 3 +- src/data-structures/hash/tree-set.ts | 3 +- src/data-structures/heap/heap.ts | 4 +- src/data-structures/heap/max-heap.ts | 2 +- src/data-structures/heap/min-heap.ts | 2 +- .../linked-list/singly-linked-list.ts | 2 +- src/data-structures/matrix/matrix.ts | 2 +- src/data-structures/matrix/matrix2d.ts | 4 +- src/data-structures/matrix/vector2d.ts | 5 +- .../priority-queue/max-priority-queue.ts | 2 +- .../priority-queue/min-priority-queue.ts | 2 +- .../priority-queue/priority-queue.ts | 2 +- src/data-structures/queue/deque.ts | 9 +- src/data-structures/queue/queue.ts | 2 +- src/interfaces/binary-tree.ts | 4 +- .../binary-tree/binary-tree.ts | 4 - src/types/data-structures/matrix/navigator.ts | 2 +- src/types/helpers.ts | 8 +- src/types/utils/utils.ts | 2 +- src/types/utils/validate-type.ts | 4 +- test/integration/bst.test.ts | 2 +- .../binary-tree/avl-tree.test.ts | 144 +++++- .../binary-tree/binary-tree.test.ts | 316 +++++++++++-- .../data-structures/binary-tree/bst.test.ts | 398 +++++++++++++++- .../binary-tree/overall.test.ts | 2 +- .../binary-tree/rb-tree.test.ts | 80 +++- .../binary-tree/tree-multiset.test.ts | 429 ++++++++++-------- .../graph/directed-graph.test.ts | 38 +- .../data-structures/graph/map-graph.test.ts | 83 +++- .../graph/undirected-graph.test.ts | 82 ++++ test/unit/data-structures/heap/heap.test.ts | 4 +- .../linked-list/doubly-linked-list.test.ts | 2 +- .../linked-list/singly-linked-list.test.ts | 6 +- .../data-structures/matrix/matrix2d.test.ts | 207 +++++++++ .../data-structures/matrix/navigator.test.ts | 167 ++++++- .../data-structures/matrix/vector2d.test.ts | 171 +++++++ .../priority-queue/max-priority-queue.test.ts | 4 +- test/unit/data-structures/queue/deque.test.ts | 265 ++++++++++- test/unit/data-structures/queue/queue.test.ts | 4 +- test/utils/big-o.ts | 2 +- 52 files changed, 2248 insertions(+), 448 deletions(-) create mode 100644 test/unit/data-structures/matrix/vector2d.test.ts diff --git a/package.json b/package.json index 8ee3af3..680b283 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "data-structure-typed", - "version": "1.39.0", + "version": "1.39.1", "description": "Data Structures of Javascript & TypeScript. Binary Tree, BST, Graph, Heap, Priority Queue, Linked List, Queue, Deque, Stack, AVL Tree, Tree Multiset, Trie, Directed Graph, Undirected Graph, Singly Linked List, Doubly Linked List, Max Heap, Max Priority Queue, Min Heap, Min Priority Queue.", "main": "dist/cjs/index.js", "module": "dist/mjs/index.js", diff --git a/src/data-structures/binary-tree/avl-tree.ts b/src/data-structures/binary-tree/avl-tree.ts index f9bcdfd..47eb26f 100644 --- a/src/data-structures/binary-tree/avl-tree.ts +++ b/src/data-structures/binary-tree/avl-tree.ts @@ -7,7 +7,7 @@ */ import {BST, BSTNode} from './bst'; import type {AVLTreeNodeNested, AVLTreeOptions, BinaryTreeDeletedResult, BinaryTreeNodeKey} from '../../types'; -import {MapCallback} from '../../types'; +import {OneParamCallback} from '../../types'; import {IBinaryTree} from '../../interfaces'; export class AVLTreeNode = AVLTreeNodeNested> extends BSTNode { @@ -21,7 +21,8 @@ export class AVLTreeNode = AVLTreeNodeNeste export class AVLTree = AVLTreeNode>> extends BST - implements IBinaryTree { + implements IBinaryTree +{ /** * This is a constructor function for an AVL tree data structure in TypeScript. * @param {AVLTreeOptions} [options] - The `options` parameter is an optional object that can be passed to the @@ -73,7 +74,7 @@ export class AVLTree = AVLTreeNode` objects. */ - override delete>( + override delete>( identifier: ReturnType, callback: C = this._defaultCallbackByKey as C ): BinaryTreeDeletedResult[] { @@ -160,7 +161,7 @@ export class AVLTree = AVLTreeNode = BinaryTree * @template N - The type of the binary tree's nodes. */ export class BinaryTree = BinaryTreeNode>> - implements IBinaryTree { + implements IBinaryTree +{ /** * Creates a new instance of BinaryTree. * @param {BinaryTreeOptions} [options] - The options for the binary tree. @@ -285,10 +278,6 @@ export class BinaryTree = BinaryTreeNode return keysOrNodes.length === this.addMany(keysOrNodes, data).length; } - delete>(identifier: ReturnType | N): BinaryTreeDeletedResult[]; - - delete>(identifier: ReturnType | N, callback: C): BinaryTreeDeletedResult[]; - /** * The `delete` function removes a node from a binary search tree and returns the deleted node along * with the parent node that needs to be balanced. @@ -303,13 +292,13 @@ export class BinaryTree = BinaryTreeNode * included in the result. The `callback` parameter has a default value of * `this._defaultCallbackByKey`, which */ - delete>( - identifier: ReturnType | N, + delete>( + identifier: ReturnType | null, callback: C = this._defaultCallbackByKey as C ): BinaryTreeDeletedResult[] { const bstDeletedResult: BinaryTreeDeletedResult[] = []; if (!this.root) return bstDeletedResult; - if (identifier instanceof BinaryTreeNode) callback = (node => node) as C; + if ((identifier as any) instanceof BinaryTreeNode) callback = (node => node) as C; const curr = this.get(identifier, callback); if (!curr) return bstDeletedResult; @@ -320,7 +309,8 @@ export class BinaryTree = BinaryTreeNode if (!curr.left) { if (!parent) { - if (curr.right !== undefined) this._setRoot(curr.right); + // Handle the case when there's only one root node + this._setRoot(null); } else { const {familyPosition: fp} = curr; if (fp === FamilyPosition.LEFT || fp === FamilyPosition.ROOT_LEFT) { @@ -405,7 +395,7 @@ export class BinaryTree = BinaryTreeNode return -1; } - const stack: { node: N; depth: number }[] = [{node: beginRoot, depth: 0}]; + const stack: {node: N; depth: number}[] = [{node: beginRoot, depth: 0}]; let maxHeight = 0; while (stack.length > 0) { @@ -489,29 +479,6 @@ export class BinaryTree = BinaryTreeNode return this.getMinHeight(beginRoot) + 1 >= this.getHeight(beginRoot); } - getNodes>(identifier: ReturnType | N): N[]; - - getNodes>(identifier: ReturnType | N, callback: C): N[]; - - getNodes>(identifier: ReturnType | N, onlyOne: boolean): N[]; - - getNodes>(identifier: ReturnType | N, callback: C, onlyOne: boolean): N[]; - - getNodes>( - identifier: ReturnType | N, - callback: C, - onlyOne: boolean, - beginRoot: N | null - ): N[]; - - getNodes>( - identifier: ReturnType | N, - callback: C, - onlyOne: boolean, - beginRoot: N | null, - iterationType: IterationType - ): N[]; - /** * The function `getNodes` returns an array of nodes that match a given node property, using either * recursive or iterative traversal. @@ -533,15 +500,15 @@ export class BinaryTree = BinaryTreeNode * traverse the binary tree. It can have two possible values: * @returns The function `getNodes` returns an array of nodes (`N[]`). */ - getNodes>( - identifier: ReturnType | N, + getNodes>( + identifier: ReturnType | null, callback: C = this._defaultCallbackByKey as C, onlyOne = false, beginRoot: N | null = this.root, iterationType = this.iterationType ): N[] { if (!beginRoot) return []; - if (identifier instanceof BinaryTreeNode) callback = (node => node) as C; + if ((identifier as any) instanceof BinaryTreeNode) callback = (node => node) as C; const ans: N[] = []; if (iterationType === IterationType.RECURSIVE) { @@ -574,14 +541,6 @@ export class BinaryTree = BinaryTreeNode return ans; } - has>(identifier: ReturnType | N): boolean; - - has>(identifier: ReturnType | N, callback: C): boolean; - - has>(identifier: ReturnType | N, beginRoot: N | null): boolean; - - has>(identifier: ReturnType | N, callback: C, beginRoot: N | null): boolean; - /** * The function checks if a binary tree has a node with a given property or key. * @param {BinaryTreeNodeKey | N} identifier - The `identifier` parameter is the key or value of @@ -599,32 +558,17 @@ export class BinaryTree = BinaryTreeNode * performed when searching for nodes in the binary tree. It can have one of the following values: * @returns a boolean value. */ - has>( - identifier: ReturnType | N, + has>( + identifier: ReturnType | null, callback: C = this._defaultCallbackByKey as C, beginRoot = this.root, iterationType = this.iterationType ): boolean { - if (identifier instanceof BinaryTreeNode) callback = (node => node) as C; + if ((identifier as any) instanceof BinaryTreeNode) callback = (node => node) as C; // TODO may support finding node by value equal return this.getNodes(identifier, callback, true, beginRoot, iterationType).length > 0; } - get>(identifier: ReturnType | N): N | null; - - get>(identifier: ReturnType | N, callback: C): N | null; - - get>(identifier: ReturnType | N, beginRoot: N | null): N | null; - - get>(identifier: ReturnType | N, callback: C, beginRoot: N | null): N | null; - - get>( - identifier: ReturnType | N, - callback: C, - beginRoot: N | null, - iterationType: IterationType - ): N | null; - /** * The function `get` returns the first node in a binary tree that matches the given property or key. * @param {BinaryTreeNodeKey | N} identifier - The `identifier` parameter is the key or value of @@ -640,13 +584,13 @@ export class BinaryTree = BinaryTreeNode * performed when searching for a node in the binary tree. It can have one of the following values: * @returns either the found node (of type N) or null if no node is found. */ - get>( - identifier: ReturnType | N, + get>( + identifier: ReturnType | null, callback: C = this._defaultCallbackByKey as C, beginRoot = this.root, iterationType = this.iterationType ): N | null { - if (identifier instanceof BinaryTreeNode) callback = (node => node) as C; + if ((identifier as any) instanceof BinaryTreeNode) callback = (node => node) as C; // TODO may support finding node by value equal return this.getNodes(identifier, callback, true, beginRoot, iterationType)[0] ?? null; } @@ -750,7 +694,7 @@ export class BinaryTree = BinaryTreeNode * possible values: * @returns The function `isSubtreeBST` returns a boolean value. */ - isSubtreeBST(beginRoot: N, iterationType = this.iterationType): boolean { + isSubtreeBST(beginRoot: N | null, iterationType = this.iterationType): boolean { // TODO there is a bug if (!beginRoot) return true; @@ -805,16 +749,16 @@ export class BinaryTree = BinaryTreeNode * start from the root of the tree. * @param iterationType - The `iterationType` parameter determines the type of traversal to be * performed on the binary tree. It can have two possible values: - * @returns The function `subTreeTraverse` returns an array of `MapCallbackReturn`. + * @returns The function `subTreeTraverse` returns an array of `ReturnType>`. */ - subTreeTraverse>( + subTreeTraverse>( callback: C = this._defaultCallbackByKey as C, beginRoot: BinaryTreeNodeKey | N | null = this.root, iterationType = this.iterationType ): ReturnType[] { if (typeof beginRoot === 'number') beginRoot = this.get(beginRoot); - const ans: MapCallbackReturn[] = []; + const ans: ReturnType>[] = []; if (!beginRoot) return ans; if (iterationType === IterationType.RECURSIVE) { @@ -852,16 +796,16 @@ export class BinaryTree = BinaryTreeNode * is `null`, an empty array will be returned. * @param {IterationType} iterationType - The `iterationType` parameter determines the type of * iteration used in the depth-first search algorithm. It can have two possible values: - * @returns The function `dfs` returns an array of `MapCallbackReturn` values. + * @returns The function `dfs` returns an array of `ReturnType>` values. */ - dfs>( + dfs>( callback: C = this._defaultCallbackByKey as C, pattern: DFSOrderPattern = 'in', beginRoot: N | null = this.root, iterationType: IterationType = IterationType.ITERATIVE ): ReturnType[] { if (!beginRoot) return []; - const ans: MapCallbackReturn[] = []; + const ans: ReturnType>[] = []; if (iterationType === IterationType.RECURSIVE) { const _traverse = (node: N) => { switch (pattern) { @@ -888,7 +832,7 @@ export class BinaryTree = BinaryTreeNode _traverse(beginRoot); } else { // 0: visit, 1: print - const stack: { opt: 0 | 1; node: N | null | undefined }[] = [{opt: 0, node: beginRoot}]; + const stack: {opt: 0 | 1; node: N | null | undefined}[] = [{opt: 0, node: beginRoot}]; while (stack.length > 0) { const cur = stack.pop(); @@ -930,22 +874,22 @@ export class BinaryTree = BinaryTreeNode * function on each node. * @param callback - The `callback` parameter is a function that will be called for each node in the * breadth-first search. It takes a node of type `N` as its argument and returns a value of type - * `BFSCallbackReturn`. The default value for this parameter is `this._defaultCallbackByKey + * `ReturnType>`. The default value for this parameter is `this._defaultCallbackByKey * @param {N | null} beginRoot - The `beginRoot` parameter is the starting node for the breadth-first * search. It determines from which node the search will begin. If `beginRoot` is `null`, the search * will not be performed and an empty array will be returned. * @param iterationType - The `iterationType` parameter determines the type of iteration to be used * in the breadth-first search (BFS) algorithm. It can have two possible values: - * @returns The function `bfs` returns an array of `BFSCallbackReturn[]`. + * @returns The function `bfs` returns an array of `ReturnType>[]`. */ - bfs = BFSCallback>( + bfs>( callback: C = this._defaultCallbackByKey as C, beginRoot: N | null = this.root, iterationType = this.iterationType ): ReturnType[] { if (!beginRoot) return []; - const ans: BFSCallbackReturn[] = []; + const ans: ReturnType>[] = []; if (iterationType === IterationType.RECURSIVE) { const queue = new Queue([beginRoot]); @@ -995,7 +939,7 @@ export class BinaryTree = BinaryTreeNode * level in a binary tree. Each inner array contains the return type of the provided callback * function `C` applied to the nodes at that level. */ - listLevels = BFSCallback>( + listLevels>( callback: C = this._defaultCallbackByKey as C, beginRoot: N | null = this.root, iterationType = this.iterationType @@ -1054,7 +998,7 @@ export class BinaryTree = BinaryTreeNode * The `morris` function performs a depth-first traversal of a binary tree using the Morris traversal * algorithm and returns an array of values obtained by applying a callback function to each node. * @param callback - The `callback` parameter is a function that will be called on each node in the - * tree. It takes a node of type `N` as input and returns a value of type `MapCallbackReturn`. The + * tree. It takes a node of type `N` as input and returns a value of type `ReturnType>`. The * default value for this parameter is `this._defaultCallbackByKey`. * @param {DFSOrderPattern} [pattern=in] - The `pattern` parameter in the `morris` function * determines the order in which the nodes of a binary tree are traversed. It can have one of the @@ -1062,15 +1006,15 @@ export class BinaryTree = BinaryTreeNode * @param {N | null} beginRoot - The `beginRoot` parameter is the starting node for the Morris * traversal. It specifies the root node of the tree from which the traversal should begin. If * `beginRoot` is `null`, an empty array will be returned. - * @returns The `morris` function returns an array of `MapCallbackReturn` values. + * @returns The `morris` function returns an array of `ReturnType>` values. */ - morris>( + morris>( callback: C = this._defaultCallbackByKey as C, pattern: DFSOrderPattern = 'in', beginRoot: N | null = this.root ): ReturnType[] { if (beginRoot === null) return []; - const ans: MapCallbackReturn[] = []; + const ans: ReturnType>[] = []; let cur: N | null | undefined = beginRoot; const _reverseEdge = (node: N | null | undefined) => { @@ -1177,7 +1121,7 @@ export class BinaryTree = BinaryTreeNode * the tree's structure should be restored to its original state to maintain the tree's integrity. * This is because the purpose of the Morris algorithm is to save space rather than permanently alter the tree's shape. */ - protected _defaultCallbackByKey: DefaultMapCallback = node => node.key; + protected _defaultCallbackByKey: OneParamCallback = node => node.key; /** * The function `_addTo` adds a new node to a binary tree if there is an available position. diff --git a/src/data-structures/binary-tree/bst.ts b/src/data-structures/binary-tree/bst.ts index 9e73700..8b74002 100644 --- a/src/data-structures/binary-tree/bst.ts +++ b/src/data-structures/binary-tree/bst.ts @@ -5,14 +5,7 @@ * @copyright Copyright (c) 2022 Tyler Zeng * @license MIT License */ -import type { - BinaryTreeNodeKey, - BSTComparator, - BSTNodeNested, - BSTOptions, - MapCallback, - MapCallbackReturn -} from '../../types'; +import type {BinaryTreeNodeKey, BSTComparator, BSTNodeNested, BSTOptions, OneParamCallback} from '../../types'; import {CP, IterationType} from '../../types'; import {BinaryTree, BinaryTreeNode} from './binary-tree'; import {IBinaryTree} from '../../interfaces'; @@ -26,7 +19,8 @@ export class BSTNode = BSTNodeNested> extend export class BST = BSTNode>> extends BinaryTree - implements IBinaryTree { + implements IBinaryTree +{ /** * The constructor function initializes a binary search tree object with an optional comparator * function. @@ -227,7 +221,7 @@ export class BST = BSTNode> * callback. * @param {ReturnType | N} identifier - The `nodeProperty` parameter is used to specify the * property of the binary tree node that you want to search for. It can be either a specific key - * value (`BinaryTreeNodeKey`) or a custom callback function (`MapCallback`) that determines + * value (`BinaryTreeNodeKey`) or a custom callback function (`OneParamCallback`) that determines * whether a node matches the desired property. * @param callback - The `callback` parameter is a function that is used to determine whether a node * matches the desired property. It takes a node as input and returns a boolean value indicating @@ -240,8 +234,8 @@ export class BST = BSTNode> * @returns either the first node that matches the given nodeProperty and callback, or null if no * matching node is found. */ - override get>( - identifier: ReturnType | N, + override get>( + identifier: ReturnType | null, callback: C = this._defaultCallbackByKey as C, beginRoot = this.root, iterationType = this.iterationType @@ -291,8 +285,8 @@ export class BST = BSTNode> * traverse the binary tree. It can have one of the following values: * @returns an array of nodes (N[]). */ - override getNodes>( - identifier: ReturnType | N, + override getNodes>( + identifier: ReturnType | null, callback: C = this._defaultCallbackByKey as C, onlyOne = false, beginRoot: N | null = this.root, @@ -363,16 +357,16 @@ export class BST = BSTNode> * (`BinaryTreeNodeKey`), or `null` to * @param iterationType - The `iterationType` parameter determines whether the traversal should be * done recursively or iteratively. It can have two possible values: - * @returns The function `lesserOrGreaterTraverse` returns an array of `MapCallbackReturn`. + * @returns The function `lesserOrGreaterTraverse` returns an array of `ReturnType>`. */ - lesserOrGreaterTraverse>( + lesserOrGreaterTraverse>( callback: C = this._defaultCallbackByKey as C, lesserOrGreater: CP = CP.lt, targetNode: BinaryTreeNodeKey | N | null = this.root, iterationType = this.iterationType ): ReturnType[] { if (typeof targetNode === 'number') targetNode = this.get(targetNode); - const ans: MapCallbackReturn[] = []; + const ans: ReturnType>[] = []; if (!targetNode) return ans; const targetKey = targetNode.key; if (!this.root) return ans; diff --git a/src/data-structures/binary-tree/rb-tree.ts b/src/data-structures/binary-tree/rb-tree.ts index 45c363b..c4ad717 100644 --- a/src/data-structures/binary-tree/rb-tree.ts +++ b/src/data-structures/binary-tree/rb-tree.ts @@ -21,7 +21,8 @@ export class RBTreeNode = RBTreeNodeNested = RBTreeNode>> extends BST - implements IBinaryTree { + implements IBinaryTree +{ constructor(options?: RBTreeOptions) { super(options); } diff --git a/src/data-structures/binary-tree/tree-multiset.ts b/src/data-structures/binary-tree/tree-multiset.ts index f07d298..0dab37e 100644 --- a/src/data-structures/binary-tree/tree-multiset.ts +++ b/src/data-structures/binary-tree/tree-multiset.ts @@ -6,7 +6,7 @@ * @license MIT License */ import type {BinaryTreeNodeKey, TreeMultisetNodeNested, TreeMultisetOptions} from '../../types'; -import {BinaryTreeDeletedResult, CP, FamilyPosition, IterationType, MapCallback} from '../../types'; +import {BinaryTreeDeletedResult, CP, FamilyPosition, IterationType, OneParamCallback} from '../../types'; import {IBinaryTree} from '../../interfaces'; import {AVLTree, AVLTreeNode} from './avl-tree'; @@ -37,7 +37,8 @@ export class TreeMultisetNode< */ export class TreeMultiset = TreeMultisetNode>> extends AVLTree - implements IBinaryTree { + implements IBinaryTree +{ /** * The constructor function for a TreeMultiset class in TypeScript, which extends another class and sets an option to * merge duplicated values. @@ -274,7 +275,7 @@ export class TreeMultiset = TreeMultis * decremented by 1 and * @returns The method `delete` returns an array of `BinaryTreeDeletedResult` objects. */ - override delete>( + override delete>( identifier: ReturnType, callback: C = this._defaultCallbackByKey as C, ignoreCount = false diff --git a/src/data-structures/graph/abstract-graph.ts b/src/data-structures/graph/abstract-graph.ts index adc52db..d7d5b08 100644 --- a/src/data-structures/graph/abstract-graph.ts +++ b/src/data-structures/graph/abstract-graph.ts @@ -105,7 +105,8 @@ export abstract class AbstractEdge { export abstract class AbstractGraph< V extends AbstractVertex = AbstractVertex, E extends AbstractEdge = AbstractEdge -> implements IGraph { +> implements IGraph +{ private _vertices: Map = new Map(); get vertices(): Map { @@ -196,7 +197,7 @@ export abstract class AbstractGraph< * @returns a boolean value. It returns true if at least one vertex was successfully removed, and false if no vertices * were removed. */ - removeAllVertices(vertices: V[] | VertexKey[]): boolean { + removeManyVertices(vertices: V[] | VertexKey[]): boolean { const removed: boolean[] = []; for (const v of vertices) { removed.push(this.deleteVertex(v)); @@ -553,14 +554,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); @@ -622,7 +623,7 @@ export abstract class AbstractGraph< if (vertexOrKey instanceof AbstractVertex) distMap.set(vertexOrKey, Infinity); } - const heap = new PriorityQueue<{ key: number; val: V }>({comparator: (a, b) => a.key - b.key}); + const heap = new PriorityQueue<{key: number; val: V}>({comparator: (a, b) => a.key - b.key}); heap.add({key: 0, val: srcVertex}); distMap.set(srcVertex, 0); @@ -851,7 +852,7 @@ export abstract class AbstractGraph< * `predecessor` property is a 2D array of vertices (or `null`) representing the predecessor vertices in the shortest * path between vertices in the */ - floyd(): { costs: number[][]; predecessor: (V | null)[][] } { + floyd(): {costs: number[][]; predecessor: (V | null)[][]} { const idAndVertices = [...this._vertices]; const n = idAndVertices.length; diff --git a/src/data-structures/graph/directed-graph.ts b/src/data-structures/graph/directed-graph.ts index cc29bf3..175e6bc 100644 --- a/src/data-structures/graph/directed-graph.ts +++ b/src/data-structures/graph/directed-graph.ts @@ -64,7 +64,8 @@ export class DirectedEdge extends AbstractEdge { export class DirectedGraph = DirectedVertex, E 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/map-graph.ts b/src/data-structures/graph/map-graph.ts index acfa6fa..8d7d71e 100644 --- a/src/data-structures/graph/map-graph.ts +++ b/src/data-structures/graph/map-graph.ts @@ -109,9 +109,9 @@ export class MapGraph = MapVertex, E extends MapEd */ override createVertex( key: VertexKey, - val?: V['val'], lat: number = this.origin[0], - long: number = this.origin[1] + long: number = this.origin[1], + val?: V['val'] ): V { return new MapVertex(key, lat, long, val) as V; } diff --git a/src/data-structures/graph/undirected-graph.ts b/src/data-structures/graph/undirected-graph.ts index 8bdf1c2..1380542 100644 --- a/src/data-structures/graph/undirected-graph.ts +++ b/src/data-structures/graph/undirected-graph.ts @@ -51,11 +51,12 @@ export class UndirectedEdge extends AbstractEdge { } export class UndirectedGraph< - V extends UndirectedVertex = UndirectedVertex, - E extends UndirectedEdge = UndirectedEdge -> + V extends UndirectedVertex = UndirectedVertex, + E extends UndirectedEdge = UndirectedEdge + > extends AbstractGraph - implements IGraph { + implements IGraph +{ /** * The constructor initializes a new Map object to store edges. */ diff --git a/src/data-structures/hash/hash-map.ts b/src/data-structures/hash/hash-map.ts index 5231237..f3a5213 100644 --- a/src/data-structures/hash/hash-map.ts +++ b/src/data-structures/hash/hash-map.ts @@ -157,7 +157,7 @@ export class HashMap { } } - * entries(): IterableIterator<[K, V]> { + *entries(): IterableIterator<[K, V]> { for (const bucket of this.table) { if (bucket) { for (const [key, value] of bucket) { diff --git a/src/data-structures/hash/tree-map.ts b/src/data-structures/hash/tree-map.ts index a6d743d..fe86360 100644 --- a/src/data-structures/hash/tree-map.ts +++ b/src/data-structures/hash/tree-map.ts @@ -1,2 +1 @@ -export class TreeMap { -} +export class TreeMap {} diff --git a/src/data-structures/hash/tree-set.ts b/src/data-structures/hash/tree-set.ts index 65f14db..591aeda 100644 --- a/src/data-structures/hash/tree-set.ts +++ b/src/data-structures/hash/tree-set.ts @@ -1,2 +1 @@ -export class TreeSet { -} +export class TreeSet {} diff --git a/src/data-structures/heap/heap.ts b/src/data-structures/heap/heap.ts index b4a197b..4f3fbe6 100644 --- a/src/data-structures/heap/heap.ts +++ b/src/data-structures/heap/heap.ts @@ -11,7 +11,7 @@ export class Heap { protected nodes: E[] = []; protected readonly comparator: Comparator; - constructor(options: { comparator: Comparator; nodes?: E[] }) { + constructor(options: {comparator: Comparator; nodes?: E[]}) { this.comparator = options.comparator; if (options.nodes && options.nodes.length > 0) { this.nodes = options.nodes; @@ -39,7 +39,7 @@ export class Heap { * @returns A new Heap instance. * @param options */ - static heapify(options: { nodes: E[]; comparator: Comparator }): Heap { + static heapify(options: {nodes: E[]; comparator: Comparator}): Heap { return new Heap(options); } diff --git a/src/data-structures/heap/max-heap.ts b/src/data-structures/heap/max-heap.ts index 139ef64..be2c9b1 100644 --- a/src/data-structures/heap/max-heap.ts +++ b/src/data-structures/heap/max-heap.ts @@ -11,7 +11,7 @@ import type {Comparator} from '../../types'; export class MaxHeap extends Heap { constructor( - options: { comparator: Comparator; nodes?: E[] } = { + options: {comparator: Comparator; nodes?: E[]} = { 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'); diff --git a/src/data-structures/heap/min-heap.ts b/src/data-structures/heap/min-heap.ts index 5057017..dc86f87 100644 --- a/src/data-structures/heap/min-heap.ts +++ b/src/data-structures/heap/min-heap.ts @@ -11,7 +11,7 @@ import type {Comparator} from '../../types'; export class MinHeap extends Heap { constructor( - options: { comparator: Comparator; nodes?: E[] } = { + options: {comparator: Comparator; nodes?: E[]} = { 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'); diff --git a/src/data-structures/linked-list/singly-linked-list.ts b/src/data-structures/linked-list/singly-linked-list.ts index 18233d8..c4e1da9 100644 --- a/src/data-structures/linked-list/singly-linked-list.ts +++ b/src/data-structures/linked-list/singly-linked-list.ts @@ -485,7 +485,7 @@ export class SinglyLinkedList { return count; } - * [Symbol.iterator]() { + *[Symbol.iterator]() { let current = this.head; while (current) { diff --git a/src/data-structures/matrix/matrix.ts b/src/data-structures/matrix/matrix.ts index 7e8ae4b..8f27617 100644 --- a/src/data-structures/matrix/matrix.ts +++ b/src/data-structures/matrix/matrix.ts @@ -14,7 +14,7 @@ export class MatrixNTI2D { * given initial value or 0 if not provided. * @param options - An object containing the following properties: */ - constructor(options: { row: number; col: number; initialVal?: V }) { + constructor(options: {row: number; col: number; initialVal?: V}) { const {row, col, initialVal} = options; this._matrix = new Array(row).fill(undefined).map(() => new Array(col).fill(initialVal || 0)); } diff --git a/src/data-structures/matrix/matrix2d.ts b/src/data-structures/matrix/matrix2d.ts index f6cfd72..ab9bfef 100644 --- a/src/data-structures/matrix/matrix2d.ts +++ b/src/data-structures/matrix/matrix2d.ts @@ -5,7 +5,7 @@ * @copyright Copyright (c) 2022 Tyler Zeng * @license MIT License */ -import Vector2D from './vector2d'; +import {Vector2D} from './vector2d'; export class Matrix2D { private readonly _matrix: number[][]; @@ -209,5 +209,3 @@ export class Matrix2D { return new Vector2D(this._matrix[0][0], this._matrix[1][0]); } } - -export default Matrix2D; diff --git a/src/data-structures/matrix/vector2d.ts b/src/data-structures/matrix/vector2d.ts index e8e4074..1b2ff44 100644 --- a/src/data-structures/matrix/vector2d.ts +++ b/src/data-structures/matrix/vector2d.ts @@ -10,8 +10,7 @@ export class Vector2D { public x: number = 0, public y: number = 0, public w: number = 1 // needed for matrix multiplication - ) { - } + ) {} /** * The function checks if the x and y values of a point are both zero. @@ -313,5 +312,3 @@ export class Vector2D { this.y = 0; } } - -export default Vector2D; diff --git a/src/data-structures/priority-queue/max-priority-queue.ts b/src/data-structures/priority-queue/max-priority-queue.ts index 409c99f..dbb0793 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 type {Comparator} from '../../types'; export class MaxPriorityQueue extends PriorityQueue { constructor( - options: { comparator: Comparator; nodes?: E[] } = { + options: {comparator: Comparator; nodes?: E[]} = { 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'); diff --git a/src/data-structures/priority-queue/min-priority-queue.ts b/src/data-structures/priority-queue/min-priority-queue.ts index da8ab64..8b8386f 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 type {Comparator} from '../../types'; export class MinPriorityQueue extends PriorityQueue { constructor( - options: { comparator: Comparator; nodes?: E[] } = { + options: {comparator: Comparator; nodes?: E[]} = { 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'); diff --git a/src/data-structures/priority-queue/priority-queue.ts b/src/data-structures/priority-queue/priority-queue.ts index 60deb98..edfbaf2 100644 --- a/src/data-structures/priority-queue/priority-queue.ts +++ b/src/data-structures/priority-queue/priority-queue.ts @@ -10,7 +10,7 @@ import {Heap} from '../heap'; import {Comparator} from '../../types'; export class PriorityQueue extends Heap { - constructor(options: { comparator: Comparator; nodes?: E[] }) { + constructor(options: {comparator: Comparator; nodes?: E[]}) { super(options); } } diff --git a/src/data-structures/queue/deque.ts b/src/data-structures/queue/deque.ts index 9faabda..3290ab1 100644 --- a/src/data-structures/queue/deque.ts +++ b/src/data-structures/queue/deque.ts @@ -9,8 +9,7 @@ import {DoublyLinkedList} from '../linked-list'; // O(n) time complexity of obtaining the value // O(1) time complexity of adding at the beginning and the end -export class Deque extends DoublyLinkedList { -} +export class Deque extends DoublyLinkedList {} // O(1) time complexity of obtaining the value // O(n) time complexity of adding at the beginning and the end @@ -20,9 +19,9 @@ export class ObjectDeque { if (capacity !== undefined) this._capacity = capacity; } - private _nodes: { [key: number]: E } = {}; + private _nodes: {[key: number]: E} = {}; - get nodes(): { [p: number]: E } { + get nodes(): {[p: number]: E} { return this._nodes; } @@ -157,7 +156,7 @@ export class ObjectDeque { return this._size <= 0; } - protected _seNodes(value: { [p: number]: E }) { + protected _seNodes(value: {[p: number]: E}) { this._nodes = value; } diff --git a/src/data-structures/queue/queue.ts b/src/data-structures/queue/queue.ts index d11dd92..4549b31 100644 --- a/src/data-structures/queue/queue.ts +++ b/src/data-structures/queue/queue.ts @@ -183,7 +183,7 @@ export class Queue { return new Queue(this.nodes.slice(this.offset)); } - * [Symbol.iterator]() { + *[Symbol.iterator]() { for (const item of this.nodes) { yield item; } diff --git a/src/interfaces/binary-tree.ts b/src/interfaces/binary-tree.ts index 61afbfd..1ff1f53 100644 --- a/src/interfaces/binary-tree.ts +++ b/src/interfaces/binary-tree.ts @@ -1,10 +1,10 @@ import {BinaryTreeNode} from '../data-structures'; -import {BinaryTreeDeletedResult, BinaryTreeNodeKey, BinaryTreeNodeNested, MapCallback} from '../types'; +import {BinaryTreeDeletedResult, BinaryTreeNodeKey, BinaryTreeNodeNested, OneParamCallback} from '../types'; export interface IBinaryTree = BinaryTreeNodeNested> { createNode(key: BinaryTreeNodeKey, val?: N['val']): N; add(keyOrNode: BinaryTreeNodeKey | N | null, val?: N['val']): N | null | undefined; - delete>(identifier: ReturnType | N, callback: C): BinaryTreeDeletedResult[]; + delete>(identifier: ReturnType | null, callback: C): BinaryTreeDeletedResult[]; } diff --git a/src/types/data-structures/binary-tree/binary-tree.ts b/src/types/data-structures/binary-tree/binary-tree.ts index 61b63bb..e037ede 100644 --- a/src/types/data-structures/binary-tree/binary-tree.ts +++ b/src/types/data-structures/binary-tree/binary-tree.ts @@ -24,10 +24,6 @@ export enum FamilyPosition { export type BinaryTreeNodeKey = number; -export type BFSCallback = (node: N, level?: number) => D; - -export type BFSCallbackReturn = ReturnType>; - export type BinaryTreeDeletedResult = { deleted: N | null | undefined; needBalanced: N | null }; export type BinaryTreeNodeNested = BinaryTreeNode>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> diff --git a/src/types/data-structures/matrix/navigator.ts b/src/types/data-structures/matrix/navigator.ts index 34eddd9..9d8b9a9 100644 --- a/src/types/data-structures/matrix/navigator.ts +++ b/src/types/data-structures/matrix/navigator.ts @@ -1,6 +1,6 @@ export type Direction = 'up' | 'right' | 'down' | 'left'; -export type Turning = { [key in Direction]: Direction }; +export type Turning = {[key in Direction]: Direction}; export type NavigatorParams = { matrix: T[][]; diff --git a/src/types/helpers.ts b/src/types/helpers.ts index 0d80e9e..acd9a20 100644 --- a/src/types/helpers.ts +++ b/src/types/helpers.ts @@ -1,14 +1,8 @@ -import {BinaryTreeNodeKey} from './data-structures'; - export type Comparator = (a: T, b: T) => number; export type DFSOrderPattern = 'pre' | 'in' | 'post'; -export type MapCallback = (node: N) => D; - -export type DefaultMapCallback = (node: N) => D; - -export type MapCallbackReturn = ReturnType>; +export type OneParamCallback = (node: N) => D; export enum CP { lt = 'lt', diff --git a/src/types/utils/utils.ts b/src/types/utils/utils.ts index 1f3a505..f4d26c4 100644 --- a/src/types/utils/utils.ts +++ b/src/types/utils/utils.ts @@ -1,5 +1,5 @@ export type ToThunkFn = () => ReturnType; -export type Thunk = () => ReturnType & { __THUNK__: symbol }; +export type Thunk = () => ReturnType & {__THUNK__: symbol}; export type TrlFn = (...args: any[]) => any; export type TrlAsyncFn = (...args: any[]) => any; diff --git a/src/types/utils/validate-type.ts b/src/types/utils/validate-type.ts index 3ebf451..ac9ff28 100644 --- a/src/types/utils/validate-type.ts +++ b/src/types/utils/validate-type.ts @@ -1,6 +1,6 @@ -export type KeyValueObject = { [key: string]: any }; +export type KeyValueObject = {[key: string]: any}; -export type KeyValueObjectWithKey = { [key: string]: any; key: string | number | symbol }; +export type KeyValueObjectWithKey = {[key: string]: any; key: string | number | symbol}; export type NonNumberNonObjectButDefined = string | boolean | symbol | null; diff --git a/test/integration/bst.test.ts b/test/integration/bst.test.ts index 35a6061..0a33db7 100644 --- a/test/integration/bst.test.ts +++ b/test/integration/bst.test.ts @@ -183,7 +183,7 @@ describe('Individual package BST operations test', () => { }); it('should perform various operations on a Binary Search Tree with object values', () => { - const objBST = new BST<{ key: number; keyA: number }>(); + const objBST = new BST<{key: number; keyA: number}>(); expect(objBST).toBeInstanceOf(BST); objBST.add(11, {key: 11, keyA: 11}); objBST.add(3, {key: 3, keyA: 3}); diff --git a/test/unit/data-structures/binary-tree/avl-tree.test.ts b/test/unit/data-structures/binary-tree/avl-tree.test.ts index 5c99c38..e7e7d00 100644 --- a/test/unit/data-structures/binary-tree/avl-tree.test.ts +++ b/test/unit/data-structures/binary-tree/avl-tree.test.ts @@ -1,4 +1,4 @@ -import {AVLTree, AVLTreeNode, CP} from '../../../../src'; +import {AVLTree, AVLTreeNode, CP, IterationType} from '../../../../src'; describe('AVL Tree Test', () => { it('should perform various operations on a AVL Tree', () => { @@ -109,8 +109,117 @@ describe('AVL Tree Test', () => { }); }); +describe('AVL Tree Test recursively', () => { + it('should perform various operations on a AVL Tree', () => { + const arr = [11, 3, 15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5]; + const tree = new AVLTree({iterationType: IterationType.RECURSIVE}); + + for (const i of arr) tree.add(i, i); + + const node6 = tree.get(6); + + expect(node6 && tree.getHeight(node6)).toBe(3); + expect(node6 && tree.getDepth(node6)).toBe(1); + + const getNodeById = tree.get(10); + expect(getNodeById?.key).toBe(10); + + const getMinNodeByRoot = tree.getLeftMost(); + expect(getMinNodeByRoot?.key).toBe(1); + + const node15 = tree.get(15); + const getMinNodeBySpecificNode = node15 && tree.getLeftMost(node15); + expect(getMinNodeBySpecificNode?.key).toBe(12); + + let subTreeSum = 0; + node15 && tree.subTreeTraverse(node => (subTreeSum += node.key), node15); + expect(subTreeSum).toBe(70); + + let lesserSum = 0; + tree.lesserOrGreaterTraverse(node => (lesserSum += node.key), CP.lt, 10); + expect(lesserSum).toBe(45); + + // node15 has type problem. After the uniform design, the generics of containers (DirectedGraph, BST) are based on the type of value. However, this design has a drawback: when I attempt to inherit from the Vertex or BSTNode classes, the types of the results obtained by all methods are those of the parent class. + expect(node15?.val).toBe(15); + + const dfs = tree.dfs(node => node, 'in'); + expect(dfs[0].key).toBe(1); + expect(dfs[dfs.length - 1].key).toBe(16); + + tree.perfectlyBalance(); + const bfs = tree.bfs(node => node); + expect(tree.isPerfectlyBalanced()).toBe(true); + expect(bfs[0].key).toBe(8); + expect(bfs[bfs.length - 1].key).toBe(16); + + expect(tree.delete(11)[0].deleted?.key).toBe(11); + expect(tree.isAVLBalanced()).toBe(true); + expect(node15 && tree.getHeight(node15)).toBe(2); + + expect(tree.delete(1)[0].deleted?.key).toBe(1); + expect(tree.isAVLBalanced()).toBe(true); + expect(tree.getHeight()).toBe(4); + + expect(tree.delete(4)[0].deleted?.key).toBe(4); + expect(tree.isAVLBalanced()).toBe(true); + expect(tree.getHeight()).toBe(4); + + expect(tree.delete(10)[0].deleted?.key).toBe(10); + expect(tree.isAVLBalanced()).toBe(true); + expect(tree.getHeight()).toBe(3); + + expect(tree.delete(15)[0].deleted?.key).toBe(15); + expect(tree.isAVLBalanced()).toBe(true); + + expect(tree.getHeight()).toBe(3); + + expect(tree.delete(5)[0].deleted?.key).toBe(5); + expect(tree.isAVLBalanced()).toBe(true); + expect(tree.getHeight()).toBe(3); + + expect(tree.delete(13)[0].deleted?.key).toBe(13); + expect(tree.isAVLBalanced()).toBe(true); + expect(tree.getHeight()).toBe(3); + + expect(tree.delete(3)[0].deleted?.key).toBe(3); + expect(tree.isAVLBalanced()).toBe(true); + expect(tree.getHeight()).toBe(3); + + expect(tree.delete(8)[0].deleted?.key).toBe(8); + expect(tree.isAVLBalanced()).toBe(true); + expect(tree.getHeight()).toBe(3); + + expect(tree.delete(6)[0].deleted?.key).toBe(6); + expect(tree.delete(6).length).toBe(0); + expect(tree.isAVLBalanced()).toBe(true); + expect(tree.getHeight()).toBe(2); + + expect(tree.delete(7)[0].deleted?.key).toBe(7); + expect(tree.isAVLBalanced()).toBe(true); + expect(tree.getHeight()).toBe(2); + + expect(tree.delete(9)[0].deleted?.key).toBe(9); + expect(tree.isAVLBalanced()).toBe(true); + expect(tree.getHeight()).toBe(2); + expect(tree.delete(14)[0].deleted?.key).toBe(14); + expect(tree.isAVLBalanced()).toBe(true); + expect(tree.getHeight()).toBe(1); + + expect(tree.isAVLBalanced()).toBe(true); + const lastBFSIds = tree.bfs(); + expect(lastBFSIds[0]).toBe(12); + expect(lastBFSIds[1]).toBe(2); + expect(lastBFSIds[2]).toBe(16); + + const lastBFSNodes = tree.bfs(node => node); + expect(lastBFSNodes[0].key).toBe(12); + expect(lastBFSNodes[1].key).toBe(2); + expect(lastBFSNodes[2].key).toBe(16); + }); +}); + describe('AVLTree APIs test', () => { - const avl = new AVLTree<{ id: number; text: string }>(); + const avl = new AVLTree<{id: number; text: string}>(); beforeEach(() => { avl.clear(); }); @@ -127,3 +236,34 @@ describe('AVLTree APIs test', () => { expect(bfsRes[0]).toBe(2); }); }); + +describe('AVLTree', () => { + it('should balance the tree using _balanceLR when nodes are added', () => { + const avlTree = new AVLTree(); + avlTree.add(10, 'A'); + avlTree.add(5, 'B'); + avlTree.add(15, 'C'); + avlTree.add(3, 'D'); + avlTree.add(7, 'E'); + + // Adding nodes to trigger _balanceLR + avlTree.add(12, 'F'); + + // You can add more specific assertions to check the tree's balance and structure. + }); + + it('should balance the tree using _balanceLR when nodes are deleted', () => { + const avlTree = new AVLTree(); + avlTree.add(10, 'A'); + avlTree.add(5, 'B'); + avlTree.add(15, 'C'); + avlTree.add(3, 'D'); + avlTree.add(7, 'E'); + avlTree.add(12, 'F'); + + // Deleting nodes to trigger _balanceLR + avlTree.delete(3); + + // You can add more specific assertions to check the tree's balance and structure. + }); +}); diff --git a/test/unit/data-structures/binary-tree/binary-tree.test.ts b/test/unit/data-structures/binary-tree/binary-tree.test.ts index 3398166..e15a7ed 100644 --- a/test/unit/data-structures/binary-tree/binary-tree.test.ts +++ b/test/unit/data-structures/binary-tree/binary-tree.test.ts @@ -71,81 +71,112 @@ describe('BinaryTreeNode', () => { }); describe('BinaryTree', () => { - let binaryTree: BinaryTree; + let tree: BinaryTree; beforeEach(() => { - binaryTree = new BinaryTree(); + tree = new BinaryTree(); }); afterEach(() => { - binaryTree.clear(); + tree.clear(); }); - test('should add a node', () => { - const node = binaryTree.add(1); + it('should add a node', () => { + const node = tree.add(1); expect(node).not.toBeNull(); - expect(binaryTree.size).toBe(1); + expect(tree.size).toBe(1); }); - test('should delete a node', () => { - const node = binaryTree.add(1); - expect(binaryTree.size).toBe(1); + it('should delete a node', () => { + const node = tree.add(1); + expect(tree.size).toBe(1); if (node) { - const result = binaryTree.delete(node); + const result = tree.delete(node, node => node); expect(result).toHaveLength(1); - expect(binaryTree.size).toBe(0); + expect(tree.size).toBe(0); } }); - test('should add and find nodes', () => { - binaryTree.add(1); - binaryTree.add(2); - binaryTree.add(3); + it('should add and find nodes', () => { + tree.add(1); + tree.add(2); + tree.add(3); - expect(binaryTree.has(1)).toBe(true); - expect(binaryTree.has(2)).toBe(true); - expect(binaryTree.has(3)).toBe(true); - expect(binaryTree.has(4)).toBe(false); + expect(tree.has(1)).toBe(true); + expect(tree.has(2)).toBe(true); + expect(tree.has(3)).toBe(true); + expect(tree.has(4)).toBe(false); + const node4 = tree.get(4); + expect(tree.has(node4, node => node)).toBe(false); }); - test('should getDepth return correct depth', () => { - binaryTree.add(1); - expect(binaryTree.getDepth(1)).toBe(0); - binaryTree.add(2); - expect(binaryTree.getDepth(2)).toBe(1); - binaryTree.add(3); - expect(binaryTree.getDepth(3, 1)).toBe(1); - binaryTree.add(4); - expect(binaryTree.getDepth(4, 1)).toBe(2); - expect(binaryTree.getDepth(4)).toBe(2); - expect(binaryTree.getDepth(4, 2)).toBe(1); + it('should getDepth return correct depth', () => { + tree.add(1); + expect(tree.getDepth(1)).toBe(0); + tree.add(2); + expect(tree.getDepth(2)).toBe(1); + tree.add(3); + expect(tree.getDepth(3, 1)).toBe(1); + tree.add(4); + expect(tree.getDepth(4, 1)).toBe(2); + expect(tree.getDepth(4)).toBe(2); + expect(tree.getDepth(4, 2)).toBe(1); }); - test('should traverse in-order', () => { - binaryTree.add(4); - binaryTree.add(2); - binaryTree.add(6); - binaryTree.add(1); - binaryTree.add(3); - binaryTree.add(5); - binaryTree.add(7); + it('should traverse in-order', () => { + tree.add(4); + tree.add(2); + tree.add(6); + tree.add(1); + tree.add(3); + tree.add(5); + tree.add(7); - const inOrder = binaryTree.dfs(node => node.key); + const inOrder = tree.dfs(node => node.key); expect(inOrder).toEqual([1, 2, 3, 4, 5, 6, 7]); }); - test('should clear the tree', () => { - binaryTree.add(1); - binaryTree.add(2); + it('should getLeftMost', () => { + tree.addMany([4, 2, 6, 1, 3, 5, 7]); - expect(binaryTree.size).toBe(2); + const leftMost = tree.getLeftMost(tree.root, IterationType.RECURSIVE); + expect(leftMost?.key).toEqual(1); + const rightMost = tree.getRightMost(tree.root, IterationType.RECURSIVE); + expect(rightMost?.key).toEqual(7); + }); - binaryTree.clear(); + it('should isSubtreeBST', () => { + tree.addMany([ + new BinaryTreeNode(4, 4), + new BinaryTreeNode(2, 2), + new BinaryTreeNode(6, 6), + new BinaryTreeNode(1, 1), + new BinaryTreeNode(3, 3), + new BinaryTreeNode(5, 5), + new BinaryTreeNode(7, 7), + new BinaryTreeNode(4, 4) + ]); - expect(binaryTree.size).toBe(0); - expect(binaryTree.root).toBeNull(); + expect(tree.isSubtreeBST(tree.get(4), IterationType.RECURSIVE)).toBe(true); + }); + + it('should subTreeTraverse', () => { + tree.addMany([4, 2, 6, 1, 3, 5, 7]); + expect(tree.subTreeTraverse(node => node.key, tree.get(6), IterationType.RECURSIVE)).toEqual([6, 5, 7]); + }); + + it('should clear the tree', () => { + tree.add(1); + tree.add(2); + + expect(tree.size).toBe(2); + + tree.clear(); + + expect(tree.size).toBe(0); + expect(tree.root).toBeNull(); }); }); @@ -200,7 +231,7 @@ describe('BinaryTree Morris Traversal', () => { }); describe('BinaryTree APIs test', () => { - const avl = new AVLTree<{ id: number; text: string }>(); + const avl = new AVLTree<{id: number; text: string}>(); beforeEach(() => { avl.clear(); }); @@ -236,4 +267,195 @@ describe('BinaryTree traversals', () => { const levels = tree.listLevels(node => node.key); expect(levels).toEqual([[35], [20, 40], [15, 29, 50], [16, 28, 30, 45, 55]]); isDebug && console.log(levels); + + expect(tree.listLevels(node => node.key, tree.root, IterationType.RECURSIVE)).toEqual([ + [35], + [20, 40], + [15, 29, 50], + [16, 28, 30, 45, 55] + ]); + isDebug && console.log(levels); +}); + +describe('BinaryTree', () => { + let tree: BinaryTree; + + beforeEach(() => { + tree = new BinaryTree(); + }); + + afterEach(() => { + tree.clear(); + }); + + it('should create an empty BinaryTree', () => { + expect(tree.size).toBe(0); + expect(tree.isEmpty()).toBe(true); + expect(tree.root).toBe(null); + }); + + it('should add nodes to the tree', () => { + tree.add(5, 'A'); + tree.add(3, 'B'); + tree.add(7, 'C'); + + expect(tree.size).toBe(3); + expect(tree.isEmpty()).toBe(false); + expect(tree.root?.key).toBe(5); + }); + + it('should clear the BinaryTree', () => { + tree.add(5, 'A'); + tree.add(3, 'B'); + tree.add(7, 'C'); + + tree.clear(); + + expect(tree.size).toBe(0); + expect(tree.isEmpty()).toBe(true); + expect(tree.root).toBe(null); + }); + + it('should get nodes by key', () => { + tree.add(5, 'A'); + tree.add(3, 'B'); + tree.add(7, 'C'); + + const nodeA = tree.get(5); + const nodeB = tree.get(3); + + expect(nodeA?.key).toBe(5); + expect(nodeA?.val).toBe('A'); + expect(nodeB?.key).toBe(3); + expect(nodeB?.val).toBe('B'); + }); + + it('should return null when getting a non-existent node', () => { + tree.add(5, 'A'); + + const node = tree.get(3); + + expect(node).toBe(null); + }); + + it('should get the depth of a node', () => { + tree.add(5, 'A'); + tree.add(3, 'B'); + tree.add(7, 'C'); + + expect(tree.getDepth(7)).toBe(1); + expect(tree.getDepth(3)).toBe(1); + }); + + it('should get the height of the tree', () => { + tree.add(5, 'A'); + tree.add(3, 'B'); + tree.add(7, 'C'); + + expect(tree.getHeight()).toBe(1); + expect(tree.getHeight(undefined, IterationType.RECURSIVE)).toBe(1); + expect(tree.getMinHeight(undefined, IterationType.RECURSIVE)).toBe(1); + }); + + it('should check if the tree is a binary search tree', () => { + tree.add(5, 'A'); + tree.add(3, 'B'); + tree.add(7, 'C'); + + expect(tree.isBST()).toBe(true); + }); + + it('should perform a depth-first traversal', () => { + tree.add(5, 'A'); + tree.add(3, 'B'); + tree.add(7, 'C'); + + const result = tree.dfs(); + expect(result).toEqual([3, 5, 7]); + // Add assertions for the result of depth-first traversal + }); + + it('should perform a breadth-first traversal', () => { + tree.add(5, 'A'); + tree.add(3, 'B'); + tree.add(7, 'C'); + + const result = tree.bfs(node => node.key); + expect(result).toEqual([5, 3, 7]); + // Add assertions for the result of breadth-first traversal + }); + + it('should list levels of the tree', () => { + tree.add(5, 'A'); + tree.add(3, 'B'); + tree.add(7, 'C'); + + const levels = tree.listLevels(); + expect(levels).toEqual([[5], [3, 7]]); + // Add assertions for the levels of the tree + }); + + it('should delete nodes from the tree', () => { + tree.add(5, 'A'); + tree.add(3, 'B'); + tree.add(7, 'C'); + + tree.delete(3); + + expect(tree.size).toBe(2); + expect(tree.get(3)).toBe(null); + }); + + it('should check if the tree is perfectly balanced', () => { + tree.add(5, 'A'); + tree.add(3, 'B'); + tree.add(7, 'C'); + + expect(tree.isPerfectlyBalanced()).toBe(true); + }); + + it('should get nodes by a custom callback', () => { + tree.add(5, 'A'); + tree.add(3, 'B'); + tree.add(7, 'C'); + + const nodes = tree.getNodes('B', (node: BinaryTreeNode) => node.val); + + expect(nodes.length).toBe(1); + expect(nodes[0].key).toBe(3); + + const nodesRec = tree.getNodes( + 'B', + (node: BinaryTreeNode) => node.val, + false, + tree.root, + IterationType.RECURSIVE + ); + + expect(nodesRec.length).toBe(1); + expect(nodesRec[0].key).toBe(3); + }); + + it('should perform Morris traversal', () => { + tree.add(5, 'A'); + tree.add(3, 'B'); + tree.add(7, 'C'); + + const result = tree.morris(); + expect(result).toEqual([3, 5, 7]); + // Add assertions for the result of Morris traversal + }); + + it('should perform delete all', () => { + tree.add(5, 'A'); + tree.add(3, 'B'); + tree.add(7, 'C'); + + tree.delete(5); + tree.delete(7); + tree.delete(3); + + expect(tree.root).toBe(null); + expect(tree.getHeight()).toBe(-1); + }); }); diff --git a/test/unit/data-structures/binary-tree/bst.test.ts b/test/unit/data-structures/binary-tree/bst.test.ts index 1991ad0..b4d4a44 100644 --- a/test/unit/data-structures/binary-tree/bst.test.ts +++ b/test/unit/data-structures/binary-tree/bst.test.ts @@ -1,4 +1,4 @@ -import {BST, BSTNode, CP} from '../../../../src'; +import {BST, BSTNode, CP, IterationType} from '../../../../src'; import {isDebugTest} from '../../../config'; const isDebug = isDebugTest; @@ -189,7 +189,7 @@ describe('BST operations test', () => { }); it('should perform various operations on a Binary Search Tree with object values', () => { - const objBST = new BST<{ key: number; keyA: number }>(); + const objBST = new BST<{key: number; keyA: number}>(); expect(objBST).toBeInstanceOf(BST); objBST.add(11, {key: 11, keyA: 11}); objBST.add(3, {key: 3, keyA: 3}); @@ -260,7 +260,7 @@ describe('BST operations test', () => { objBST.perfectlyBalance(); expect(objBST.isPerfectlyBalanced()).toBe(true); - const bfsNodesAfterBalanced: BSTNode<{ key: number; keyA: number }>[] = []; + const bfsNodesAfterBalanced: BSTNode<{key: number; keyA: number}>[] = []; objBST.bfs(node => bfsNodesAfterBalanced.push(node)); expect(bfsNodesAfterBalanced[0].key).toBe(8); expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16); @@ -385,7 +385,397 @@ describe('BST operations test', () => { expect(bfsIDs[1]).toBe(12); expect(bfsIDs[2]).toBe(16); - const bfsNodes: BSTNode<{ key: number; keyA: number }>[] = []; + const bfsNodes: BSTNode<{key: number; keyA: number}>[] = []; + objBST.bfs(node => bfsNodes.push(node)); + expect(bfsNodes[0].key).toBe(2); + expect(bfsNodes[1].key).toBe(12); + expect(bfsNodes[2].key).toBe(16); + }); +}); + +describe('BST operations test recursively', () => { + it('should perform various operations on a Binary Search Tree with numeric values', () => { + const bst = new BST({iterationType: IterationType.RECURSIVE}); + expect(bst).toBeInstanceOf(BST); + bst.add(11, 11); + bst.add(3, 3); + const idsAndValues = [15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5]; + bst.addMany(idsAndValues, idsAndValues, false); + expect(bst.root).toBeInstanceOf(BSTNode); + + if (bst.root) expect(bst.root.key).toBe(11); + + expect(bst.size).toBe(16); + + expect(bst.has(6)).toBe(true); + + const node6 = bst.get(6); + expect(node6 && bst.getHeight(6)).toBe(2); + expect(node6 && bst.getDepth(6)).toBe(3); + + const nodeId10 = bst.get(10); + expect(nodeId10?.key).toBe(10); + + const nodeVal9 = bst.get(9, node => node.val); + expect(nodeVal9?.key).toBe(9); + + const leftMost = bst.getLeftMost(); + expect(leftMost?.key).toBe(1); + + const node15 = bst.get(15); + const minNodeBySpecificNode = node15 && bst.getLeftMost(node15); + expect(minNodeBySpecificNode?.key).toBe(12); + + let subTreeSum = 0; + node15 && bst.subTreeTraverse(node => (subTreeSum += node.key), 15); + expect(subTreeSum).toBe(70); + + let lesserSum = 0; + bst.lesserOrGreaterTraverse(node => (lesserSum += node.key), CP.lt, 10); + expect(lesserSum).toBe(45); + + expect(node15).toBeInstanceOf(BSTNode); + + const node11 = bst.get(11); + expect(node11).toBeInstanceOf(BSTNode); + + const dfsInorderNodes = bst.dfs(node => node, 'in'); + expect(dfsInorderNodes[0].key).toBe(1); + expect(dfsInorderNodes[dfsInorderNodes.length - 1].key).toBe(16); + + bst.perfectlyBalance(); + expect(bst.isPerfectlyBalanced()).toBe(true); + + const bfsNodesAfterBalanced: BSTNode[] = []; + bst.bfs(node => bfsNodesAfterBalanced.push(node)); + expect(bfsNodesAfterBalanced[0].key).toBe(8); + expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16); + + const removed11 = bst.delete(11); + expect(removed11).toBeInstanceOf(Array); + expect(removed11[0]).toBeDefined(); + expect(removed11[0].deleted).toBeDefined(); + + if (removed11[0].deleted) expect(removed11[0].deleted.key).toBe(11); + + expect(bst.isAVLBalanced()).toBe(true); + + expect(bst.getHeight(15)).toBe(1); + + const removed1 = bst.delete(1); + expect(removed1).toBeInstanceOf(Array); + expect(removed1[0]).toBeDefined(); + expect(removed1[0].deleted).toBeDefined(); + if (removed1[0].deleted) expect(removed1[0].deleted.key).toBe(1); + + expect(bst.isAVLBalanced()).toBe(true); + + expect(bst.getHeight()).toBe(4); + + const removed4 = bst.delete(4); + expect(removed4).toBeInstanceOf(Array); + expect(removed4[0]).toBeDefined(); + expect(removed4[0].deleted).toBeDefined(); + if (removed4[0].deleted) expect(removed4[0].deleted.key).toBe(4); + expect(bst.isAVLBalanced()).toBe(true); + expect(bst.getHeight()).toBe(4); + + const removed10 = bst.delete(10); + expect(removed10).toBeInstanceOf(Array); + expect(removed10[0]).toBeDefined(); + expect(removed10[0].deleted).toBeDefined(); + if (removed10[0].deleted) expect(removed10[0].deleted.key).toBe(10); + expect(bst.isAVLBalanced()).toBe(false); + expect(bst.getHeight()).toBe(4); + + const removed15 = bst.delete(15); + expect(removed15).toBeInstanceOf(Array); + expect(removed15[0]).toBeDefined(); + expect(removed15[0].deleted).toBeDefined(); + if (removed15[0].deleted) expect(removed15[0].deleted.key).toBe(15); + + expect(bst.isAVLBalanced()).toBe(true); + expect(bst.getHeight()).toBe(3); + + const removed5 = bst.delete(5); + expect(removed5).toBeInstanceOf(Array); + expect(removed5[0]).toBeDefined(); + expect(removed5[0].deleted).toBeDefined(); + if (removed5[0].deleted) expect(removed5[0].deleted.key).toBe(5); + + expect(bst.isAVLBalanced()).toBe(true); + expect(bst.getHeight()).toBe(3); + + const removed13 = bst.delete(13); + expect(removed13).toBeInstanceOf(Array); + expect(removed13[0]).toBeDefined(); + expect(removed13[0].deleted).toBeDefined(); + if (removed13[0].deleted) expect(removed13[0].deleted.key).toBe(13); + expect(bst.isAVLBalanced()).toBe(true); + expect(bst.getHeight()).toBe(3); + + const removed3 = bst.delete(3); + expect(removed3).toBeInstanceOf(Array); + expect(removed3[0]).toBeDefined(); + expect(removed3[0].deleted).toBeDefined(); + if (removed3[0].deleted) expect(removed3[0].deleted.key).toBe(3); + expect(bst.isAVLBalanced()).toBe(false); + expect(bst.getHeight()).toBe(3); + + const removed8 = bst.delete(8); + expect(removed8).toBeInstanceOf(Array); + expect(removed8[0]).toBeDefined(); + expect(removed8[0].deleted).toBeDefined(); + if (removed8[0].deleted) expect(removed8[0].deleted.key).toBe(8); + expect(bst.isAVLBalanced()).toBe(true); + expect(bst.getHeight()).toBe(3); + + const removed6 = bst.delete(6); + expect(removed6).toBeInstanceOf(Array); + expect(removed6[0]).toBeDefined(); + expect(removed6[0].deleted).toBeDefined(); + if (removed6[0].deleted) expect(removed6[0].deleted.key).toBe(6); + expect(bst.delete(6).length).toBe(0); + expect(bst.isAVLBalanced()).toBe(false); + expect(bst.getHeight()).toBe(3); + + const removed7 = bst.delete(7); + expect(removed7).toBeInstanceOf(Array); + expect(removed7[0]).toBeDefined(); + expect(removed7[0].deleted).toBeDefined(); + if (removed7[0].deleted) expect(removed7[0].deleted.key).toBe(7); + expect(bst.isAVLBalanced()).toBe(false); + expect(bst.getHeight()).toBe(3); + + const removed9 = bst.delete(9); + expect(removed9).toBeInstanceOf(Array); + expect(removed9[0]).toBeDefined(); + expect(removed9[0].deleted).toBeDefined(); + if (removed9[0].deleted) expect(removed9[0].deleted.key).toBe(9); + expect(bst.isAVLBalanced()).toBe(false); + expect(bst.getHeight()).toBe(3); + + const removed14 = bst.delete(14); + expect(removed14).toBeInstanceOf(Array); + expect(removed14[0]).toBeDefined(); + expect(removed14[0].deleted).toBeDefined(); + if (removed14[0].deleted) expect(removed14[0].deleted.key).toBe(14); + expect(bst.isAVLBalanced()).toBe(false); + expect(bst.getHeight()).toBe(2); + + expect(bst.isAVLBalanced()).toBe(false); + + const bfsIDs: number[] = []; + bst.bfs(node => bfsIDs.push(node.key)); + expect(bfsIDs[0]).toBe(2); + expect(bfsIDs[1]).toBe(12); + expect(bfsIDs[2]).toBe(16); + + const bfsNodes: BSTNode[] = []; + bst.bfs(node => bfsNodes.push(node)); + expect(bfsNodes[0].key).toBe(2); + expect(bfsNodes[1].key).toBe(12); + expect(bfsNodes[2].key).toBe(16); + }); + + it('should perform various operations on a Binary Search Tree with object values', () => { + const objBST = new BST<{key: number; keyA: number}>(); + expect(objBST).toBeInstanceOf(BST); + objBST.add(11, {key: 11, keyA: 11}); + objBST.add(3, {key: 3, keyA: 3}); + const values = [ + {key: 15, keyA: 15}, + {key: 1, keyA: 1}, + {key: 8, keyA: 8}, + {key: 13, keyA: 13}, + {key: 16, keyA: 16}, + {key: 2, keyA: 2}, + {key: 6, keyA: 6}, + {key: 9, keyA: 9}, + {key: 12, keyA: 12}, + {key: 14, keyA: 14}, + {key: 4, keyA: 4}, + {key: 7, keyA: 7}, + {key: 10, keyA: 10}, + {key: 5, keyA: 5} + ]; + + objBST.addMany( + values.map(item => item.key), + values, + false + ); + + expect(objBST.root).toBeInstanceOf(BSTNode); + + if (objBST.root) expect(objBST.root.key).toBe(11); + + expect(objBST.has(6)).toBe(true); + + const node6 = objBST.get(6); + expect(node6 && objBST.getHeight(node6)).toBe(2); + expect(node6 && objBST.getDepth(node6)).toBe(3); + + const nodeId10 = objBST.get(10); + expect(nodeId10?.key).toBe(10); + + const nodeVal9 = objBST.get(9); + expect(nodeVal9?.key).toBe(9); + + const leftMost = objBST.getLeftMost(); + expect(leftMost?.key).toBe(1); + + const node15 = objBST.get(15); + expect(node15?.val).toEqual({key: 15, keyA: 15}); + const minNodeBySpecificNode = node15 && objBST.getLeftMost(node15); + expect(minNodeBySpecificNode?.key).toBe(12); + + let subTreeSum = 0; + node15 && objBST.subTreeTraverse(node => (subTreeSum += node.key), node15); + expect(subTreeSum).toBe(70); + + let lesserSum = 0; + objBST.lesserOrGreaterTraverse(node => (lesserSum += node.key), CP.lt, 10); + expect(lesserSum).toBe(45); + + expect(node15).toBeInstanceOf(BSTNode); + + const node11 = objBST.get(11); + expect(node11).toBeInstanceOf(BSTNode); + + const dfsInorderNodes = objBST.dfs(node => node, 'in'); + expect(dfsInorderNodes[0].key).toBe(1); + expect(dfsInorderNodes[dfsInorderNodes.length - 1].key).toBe(16); + + objBST.perfectlyBalance(); + expect(objBST.isPerfectlyBalanced()).toBe(true); + + const bfsNodesAfterBalanced: BSTNode<{key: number; keyA: number}>[] = []; + objBST.bfs(node => bfsNodesAfterBalanced.push(node)); + expect(bfsNodesAfterBalanced[0].key).toBe(8); + expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16); + + const removed11 = objBST.delete(11); + expect(removed11).toBeInstanceOf(Array); + expect(removed11[0]).toBeDefined(); + expect(removed11[0].deleted).toBeDefined(); + + if (removed11[0].deleted) expect(removed11[0].deleted.key).toBe(11); + + expect(objBST.isAVLBalanced()).toBe(true); + + expect(node15 && objBST.getHeight(node15)).toBe(2); + + const removed1 = objBST.delete(1); + expect(removed1).toBeInstanceOf(Array); + expect(removed1[0]).toBeDefined(); + expect(removed1[0].deleted).toBeDefined(); + if (removed1[0].deleted) expect(removed1[0].deleted.key).toBe(1); + + expect(objBST.isAVLBalanced()).toBe(true); + + expect(objBST.getHeight()).toBe(4); + + const removed4 = objBST.delete(4); + expect(removed4).toBeInstanceOf(Array); + expect(removed4[0]).toBeDefined(); + expect(removed4[0].deleted).toBeDefined(); + if (removed4[0].deleted) expect(removed4[0].deleted.key).toBe(4); + expect(objBST.isAVLBalanced()).toBe(true); + expect(objBST.getHeight()).toBe(4); + + const removed10 = objBST.delete(10); + expect(removed10).toBeInstanceOf(Array); + expect(removed10[0]).toBeDefined(); + expect(removed10[0].deleted).toBeDefined(); + if (removed10[0].deleted) expect(removed10[0].deleted.key).toBe(10); + expect(objBST.isAVLBalanced()).toBe(false); + expect(objBST.getHeight()).toBe(4); + + const removed15 = objBST.delete(15); + expect(removed15).toBeInstanceOf(Array); + expect(removed15[0]).toBeDefined(); + expect(removed15[0].deleted).toBeDefined(); + if (removed15[0].deleted) expect(removed15[0].deleted.key).toBe(15); + + expect(objBST.isAVLBalanced()).toBe(true); + expect(objBST.getHeight()).toBe(3); + + const removed5 = objBST.delete(5); + expect(removed5).toBeInstanceOf(Array); + expect(removed5[0]).toBeDefined(); + expect(removed5[0].deleted).toBeDefined(); + if (removed5[0].deleted) expect(removed5[0].deleted.key).toBe(5); + + expect(objBST.isAVLBalanced()).toBe(true); + expect(objBST.getHeight()).toBe(3); + + const removed13 = objBST.delete(13); + expect(removed13).toBeInstanceOf(Array); + expect(removed13[0]).toBeDefined(); + expect(removed13[0].deleted).toBeDefined(); + if (removed13[0].deleted) expect(removed13[0].deleted.key).toBe(13); + expect(objBST.isAVLBalanced()).toBe(true); + expect(objBST.getHeight()).toBe(3); + + const removed3 = objBST.delete(3); + expect(removed3).toBeInstanceOf(Array); + expect(removed3[0]).toBeDefined(); + expect(removed3[0].deleted).toBeDefined(); + if (removed3[0].deleted) expect(removed3[0].deleted.key).toBe(3); + expect(objBST.isAVLBalanced()).toBe(false); + expect(objBST.getHeight()).toBe(3); + + const removed8 = objBST.delete(8); + expect(removed8).toBeInstanceOf(Array); + expect(removed8[0]).toBeDefined(); + expect(removed8[0].deleted).toBeDefined(); + if (removed8[0].deleted) expect(removed8[0].deleted.key).toBe(8); + expect(objBST.isAVLBalanced()).toBe(true); + expect(objBST.getHeight()).toBe(3); + + const removed6 = objBST.delete(6); + expect(removed6).toBeInstanceOf(Array); + expect(removed6[0]).toBeDefined(); + expect(removed6[0].deleted).toBeDefined(); + if (removed6[0].deleted) expect(removed6[0].deleted.key).toBe(6); + expect(objBST.delete(6).length).toBe(0); + expect(objBST.isAVLBalanced()).toBe(false); + expect(objBST.getHeight()).toBe(3); + + const removed7 = objBST.delete(7); + expect(removed7).toBeInstanceOf(Array); + expect(removed7[0]).toBeDefined(); + expect(removed7[0].deleted).toBeDefined(); + if (removed7[0].deleted) expect(removed7[0].deleted.key).toBe(7); + expect(objBST.isAVLBalanced()).toBe(false); + expect(objBST.getHeight()).toBe(3); + + const removed9 = objBST.delete(9); + expect(removed9).toBeInstanceOf(Array); + expect(removed9[0]).toBeDefined(); + expect(removed9[0].deleted).toBeDefined(); + if (removed9[0].deleted) expect(removed9[0].deleted.key).toBe(9); + expect(objBST.isAVLBalanced()).toBe(false); + expect(objBST.getHeight()).toBe(3); + + const removed14 = objBST.delete(14); + expect(removed14).toBeInstanceOf(Array); + expect(removed14[0]).toBeDefined(); + expect(removed14[0].deleted).toBeDefined(); + if (removed14[0].deleted) expect(removed14[0].deleted.key).toBe(14); + expect(objBST.isAVLBalanced()).toBe(false); + expect(objBST.getHeight()).toBe(2); + + expect(objBST.isAVLBalanced()).toBe(false); + + const bfsIDs: number[] = []; + objBST.bfs(node => bfsIDs.push(node.key)); + expect(bfsIDs[0]).toBe(2); + expect(bfsIDs[1]).toBe(12); + expect(bfsIDs[2]).toBe(16); + + const bfsNodes: BSTNode<{key: number; keyA: number}>[] = []; objBST.bfs(node => bfsNodes.push(node)); expect(bfsNodes[0].key).toBe(2); expect(bfsNodes[1].key).toBe(12); diff --git a/test/unit/data-structures/binary-tree/overall.test.ts b/test/unit/data-structures/binary-tree/overall.test.ts index 8c1921c..520c2bc 100644 --- a/test/unit/data-structures/binary-tree/overall.test.ts +++ b/test/unit/data-structures/binary-tree/overall.test.ts @@ -29,7 +29,7 @@ describe('Overall BinaryTree Test', () => { bfsIDs[0] === 11; // true expect(bfsIDs[0]).toBe(11); - const objBST = new BST<{ key: number; keyA: number }>(); + const objBST = new BST<{key: number; keyA: number}>(); objBST.add(11, {key: 11, keyA: 11}); objBST.add(3, {key: 3, keyA: 3}); diff --git a/test/unit/data-structures/binary-tree/rb-tree.test.ts b/test/unit/data-structures/binary-tree/rb-tree.test.ts index 884e126..afd016b 100644 --- a/test/unit/data-structures/binary-tree/rb-tree.test.ts +++ b/test/unit/data-structures/binary-tree/rb-tree.test.ts @@ -1,14 +1,80 @@ -// import {RBTree, RBTreeNode} from '../../../../src'; +import {RBTree, RBTreeNode} from '../../../../src'; + +describe('RBTreeNode', () => { + it('should create an instance of RBTreeNode', () => { + const node = new RBTreeNode(1); + expect(node).toBeInstanceOf(RBTreeNode); + }); + + it('should set and get the ID correctly', () => { + const node = new RBTreeNode(1); + expect(node.key).toBe(1); + + node.key = 2; + expect(node.key).toBe(2); + }); + + it('should set and get the value correctly', () => { + const node: RBTreeNode = new RBTreeNode(1, 42); + expect(node.val).toBe(42); + + node.val = 55; + expect(node.val).toBe(55); + }); + + it('should set and get the left child correctly', () => { + const node1 = new RBTreeNode(1); + const node2 = new RBTreeNode(2); + + node1.left = node2; + + expect(node1.left).toBe(node2); + expect(node2.parent).toBe(node1); + }); + + it('should set and get the right child correctly', () => { + const node1 = new RBTreeNode(1); + const node2 = new RBTreeNode(2); + + node1.right = node2; + + expect(node1.right).toBe(node2); + expect(node2.parent).toBe(node1); + }); + + it('should set and get the parent correctly', () => { + const node1 = new RBTreeNode(1); + const node2 = new RBTreeNode(2); + + node1.left = node2; + + expect(node2.parent).toBe(node1); + expect(node1.left).toBe(node2); + }); + + it('should determine family position correctly', () => { + const root = new RBTreeNode(1); + const leftChild = new RBTreeNode(2); + const rightChild = new RBTreeNode(3); + + root.left = leftChild; + root.right = rightChild; + + expect(leftChild.familyPosition).toBe('LEFT'); + expect(rightChild.familyPosition).toBe('RIGHT'); + expect(root.familyPosition).toBe('ROOT'); + }); +}); describe('Red-Black Tree Tests', () => { - // let tree: RBTree>; - // - // beforeEach(() => { - // tree = new RBTree>(); - // }); + let tree: RBTree>; + + beforeEach(() => { + tree = new RBTree>(); + }); test('Insertion and In-order Traverse', () => { - // tree.add(5); + tree.add(5); // tree.add(3); // tree.add(7); // tree.add(2); diff --git a/test/unit/data-structures/binary-tree/tree-multiset.test.ts b/test/unit/data-structures/binary-tree/tree-multiset.test.ts index 361b90d..ab90ae2 100644 --- a/test/unit/data-structures/binary-tree/tree-multiset.test.ts +++ b/test/unit/data-structures/binary-tree/tree-multiset.test.ts @@ -1,7 +1,8 @@ -import {CP, TreeMultiset, TreeMultisetNode} from '../../../../src'; +import {CP, IterationType, TreeMultiset, TreeMultisetNode} from '../../../../src'; import {isDebugTest} from '../../../config'; const isDebug = isDebugTest; + describe('TreeMultiset operations test', () => { it('should perform various operations on a Binary Search Tree with numeric values', () => { const treeMultiset = new TreeMultiset(); @@ -206,7 +207,7 @@ describe('TreeMultiset operations test', () => { }); it('should perform various operations on a Binary Search Tree with object values', () => { - const objTreeMultiset = new TreeMultiset<{ key: number; keyA: number }>(); + const objTreeMultiset = new TreeMultiset<{key: number; keyA: number}>(); expect(objTreeMultiset).toBeInstanceOf(TreeMultiset); objTreeMultiset.add(11, {key: 11, keyA: 11}); objTreeMultiset.add(3, {key: 3, keyA: 3}); @@ -239,196 +240,250 @@ describe('TreeMultiset operations test', () => { expect(objTreeMultiset.count).toBe(16); expect(objTreeMultiset.has(6)).toBe(true); + }); +}); - // const node6 = objTreeMultiset.get(6); - // expect(node6 && objTreeMultiset.getHeight(node6)).toBe(2); - // expect(node6 && objTreeMultiset.getDepth(node6)).toBe(3); - // - // const nodeId10 = objTreeMultiset.get(10, 'key'); - // expect(nodeId10?.key).toBe(10); - // - // const nodeVal9 = objTreeMultiset.get(9, 'key'); - // expect(nodeVal9?.key).toBe(9); - // - // const nodesByCount1 = objTreeMultiset.getNodesByCount(1); - // expect(nodesByCount1.length).toBe(16); - // - // const leftMost = objTreeMultiset.getLeftMost(); - // expect(leftMost?.key).toBe(1); - // - // const node15 = objTreeMultiset.get(15); - // expect(node15?.val).toEqual({key: 15, keyA: 15}); - // const minNodeBySpecificNode = node15 && objTreeMultiset.getLeftMost(node15); - // expect(minNodeBySpecificNode?.key).toBe(12); - // - // const subTreeSum = node15 && objTreeMultiset.subTreeSum(node15); - // expect(subTreeSum).toBe(70); - // - // const lesserSum = objTreeMultiset.lesserSum(10); - // expect(lesserSum).toBe(45); - // - // expect(node15).toBeInstanceOf(TreeMultisetNode); - // if (node15 instanceof TreeMultisetNode) { - // const subTreeAdd = objTreeMultiset.subTreeAddCount(node15, 1); - // expect(subTreeAdd).toBeDefined(); - // } - // - // const node11 = objTreeMultiset.get(11); - // expect(node11).toBeInstanceOf(TreeMultisetNode); - // if (node11 instanceof TreeMultisetNode) { - // const allGreaterNodesAdded = objTreeMultiset.allGreaterNodesAddCount(node11, 2); - // expect(allGreaterNodesAdded).toBeDefined(); - // } - // - // const dfsInorderNodes = objTreeMultiset.dfs(node => node, 'in'); - // expect(dfsInorderNodes[0].key).toBe(1); - // expect(dfsInorderNodes[dfsInorderNodes.length - 1].key).toBe(16); - // - // objTreeMultiset.perfectlyBalance(); - // expect(objTreeMultiset.isPerfectlyBalanced()).toBe(true); - // - // const bfsNodesAfterBalanced = objTreeMultiset.bfs('node'); - // expect(bfsNodesAfterBalanced[0].key).toBe(8); - // expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16); - // - // const removed11 = objTreeMultiset.delete(11, true); - // expect(removed11).toBeInstanceOf(Array); - // expect(removed11[0]).toBeDefined(); - // expect(removed11[0].deleted).toBeDefined(); - // - // if (removed11[0].deleted) expect(removed11[0].deleted.key).toBe(11); - // - // expect(objTreeMultiset.isAVLBalanced()).toBe(true); - // - // expect(node15 && objTreeMultiset.getHeight(node15)).toBe(2); - // - // const removed1 = objTreeMultiset.delete(1, true); - // expect(removed1).toBeInstanceOf(Array); - // expect(removed1[0]).toBeDefined(); - // expect(removed1[0].deleted).toBeDefined(); - // if (removed1[0].deleted) expect(removed1[0].deleted.key).toBe(1); - // - // expect(objTreeMultiset.isAVLBalanced()).toBe(true); - // - // expect(objTreeMultiset.getHeight()).toBe(4); - // - // const removed4 = objTreeMultiset.delete(4, true); - // expect(removed4).toBeInstanceOf(Array); - // expect(removed4[0]).toBeDefined(); - // expect(removed4[0].deleted).toBeDefined(); - // if (removed4[0].deleted) expect(removed4[0].deleted.key).toBe(4); - // expect(objTreeMultiset.isAVLBalanced()).toBe(true); - // expect(objTreeMultiset.getHeight()).toBe(4); - // - // const removed10 = objTreeMultiset.delete(10, true); - // expect(removed10).toBeInstanceOf(Array); - // expect(removed10[0]).toBeDefined(); - // expect(removed10[0].deleted).toBeDefined(); - // if (removed10[0].deleted) expect(removed10[0].deleted.key).toBe(10); - // expect(objTreeMultiset.isAVLBalanced()).toBe(false); - // expect(objTreeMultiset.getHeight()).toBe(4); - // - // const removed15 = objTreeMultiset.delete(15, true); - // expect(removed15).toBeInstanceOf(Array); - // expect(removed15[0]).toBeDefined(); - // expect(removed15[0].deleted).toBeDefined(); - // if (removed15[0].deleted) expect(removed15[0].deleted.key).toBe(15); - // - // expect(objTreeMultiset.isAVLBalanced()).toBe(true); - // expect(objTreeMultiset.getHeight()).toBe(3); - // - // const removed5 = objTreeMultiset.delete(5, true); - // expect(removed5).toBeInstanceOf(Array); - // expect(removed5[0]).toBeDefined(); - // expect(removed5[0].deleted).toBeDefined(); - // if (removed5[0].deleted) expect(removed5[0].deleted.key).toBe(5); - // - // expect(objTreeMultiset.isAVLBalanced()).toBe(true); - // expect(objTreeMultiset.getHeight()).toBe(3); - // - // const removed13 = objTreeMultiset.delete(13, true); - // expect(removed13).toBeInstanceOf(Array); - // expect(removed13[0]).toBeDefined(); - // expect(removed13[0].deleted).toBeDefined(); - // if (removed13[0].deleted) expect(removed13[0].deleted.key).toBe(13); - // expect(objTreeMultiset.isAVLBalanced()).toBe(true); - // expect(objTreeMultiset.getHeight()).toBe(3); - // - // const removed3 = objTreeMultiset.delete(3, true); - // expect(removed3).toBeInstanceOf(Array); - // expect(removed3[0]).toBeDefined(); - // expect(removed3[0].deleted).toBeDefined(); - // if (removed3[0].deleted) expect(removed3[0].deleted.key).toBe(3); - // expect(objTreeMultiset.isAVLBalanced()).toBe(false); - // expect(objTreeMultiset.getHeight()).toBe(3); - // - // const removed8 = objTreeMultiset.delete(8, true); - // expect(removed8).toBeInstanceOf(Array); - // expect(removed8[0]).toBeDefined(); - // expect(removed8[0].deleted).toBeDefined(); - // if (removed8[0].deleted) expect(removed8[0].deleted.key).toBe(8); - // expect(objTreeMultiset.isAVLBalanced()).toBe(true); - // expect(objTreeMultiset.getHeight()).toBe(3); - // - // const removed6 = objTreeMultiset.delete(6, true); - // expect(removed6).toBeInstanceOf(Array); - // expect(removed6[0]).toBeDefined(); - // expect(removed6[0].deleted).toBeDefined(); - // if (removed6[0].deleted) expect(removed6[0].deleted.key).toBe(6); - // expect(objTreeMultiset.delete(6, true).length).toBe(0); - // expect(objTreeMultiset.isAVLBalanced()).toBe(false); - // expect(objTreeMultiset.getHeight()).toBe(3); - // - // const removed7 = objTreeMultiset.delete(7, true); - // expect(removed7).toBeInstanceOf(Array); - // expect(removed7[0]).toBeDefined(); - // expect(removed7[0].deleted).toBeDefined(); - // if (removed7[0].deleted) expect(removed7[0].deleted.key).toBe(7); - // expect(objTreeMultiset.isAVLBalanced()).toBe(false); - // expect(objTreeMultiset.getHeight()).toBe(3); - // - // const removed9 = objTreeMultiset.delete(9, true); - // expect(removed9).toBeInstanceOf(Array); - // expect(removed9[0]).toBeDefined(); - // expect(removed9[0].deleted).toBeDefined(); - // if (removed9[0].deleted) expect(removed9[0].deleted.key).toBe(9); - // expect(objTreeMultiset.isAVLBalanced()).toBe(false); - // expect(objTreeMultiset.getHeight()).toBe(3); - // - // const removed14 = objTreeMultiset.delete(14, true); - // expect(removed14).toBeInstanceOf(Array); - // expect(removed14[0]).toBeDefined(); - // expect(removed14[0].deleted).toBeDefined(); - // if (removed14[0].deleted) expect(removed14[0].deleted.key).toBe(14); - // expect(objTreeMultiset.isAVLBalanced()).toBe(false); - // expect(objTreeMultiset.getHeight()).toBe(2); - // - // - // expect(objTreeMultiset.isAVLBalanced()).toBe(false); - // - // const bfsIDs = objTreeMultiset.bfs(); - // expect(bfsIDs[0]).toBe(2); - // expect(bfsIDs[1]).toBe(12); - // expect(bfsIDs[2]).toBe(16); - // - // const bfsNodes = objTreeMultiset.bfs('node'); - // expect(bfsNodes[0].key).toBe(2); - // expect(bfsNodes[1].key).toBe(12); - // expect(bfsNodes[2].key).toBe(16); - // - // expect(objTreeMultiset.count).toBe(5); +describe('TreeMultiset operations test recursively', () => { + it('should perform various operations on a Binary Search Tree with numeric values', () => { + const treeMultiset = new TreeMultiset({iterationType: IterationType.RECURSIVE}); + + expect(treeMultiset instanceof TreeMultiset); + treeMultiset.add(11, 11); + treeMultiset.add(3, 3); + const idAndValues = [11, 3, 15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5]; + treeMultiset.addMany(idAndValues, idAndValues); + expect(treeMultiset.root instanceof TreeMultisetNode); + + if (treeMultiset.root) expect(treeMultiset.root.key == 11); + + expect(treeMultiset.size).toBe(16); + expect(treeMultiset.count).toBe(18); + + expect(treeMultiset.has(6)); + + expect(treeMultiset.getHeight(6)).toBe(3); + expect(treeMultiset.getDepth(6)).toBe(1); + const nodeId10 = treeMultiset.get(10); + expect(nodeId10?.key).toBe(10); + + const nodeVal9 = treeMultiset.get(9, node => node.val); + expect(nodeVal9?.key).toBe(9); + + const nodesByCount1 = treeMultiset.getNodes(1, node => node.count); + expect(nodesByCount1.length).toBe(14); + + const nodesByCount2 = treeMultiset.getNodes(2, node => node.count); + expect(nodesByCount2.length).toBe(2); + const leftMost = treeMultiset.getLeftMost(); + expect(leftMost?.key).toBe(1); + + const node15 = treeMultiset.get(15); + const minNodeBySpecificNode = node15 && treeMultiset.getLeftMost(node15); + expect(minNodeBySpecificNode?.key).toBe(12); + + let subTreeSum = 0; + node15 && treeMultiset.subTreeTraverse((node: TreeMultisetNode) => (subTreeSum += node.key), 15); + expect(subTreeSum).toBe(70); + let lesserSum = 0; + treeMultiset.lesserOrGreaterTraverse((node: TreeMultisetNode) => (lesserSum += node.key), CP.lt, 10); + expect(lesserSum).toBe(45); + + expect(node15 instanceof TreeMultisetNode); + if (node15 instanceof TreeMultisetNode) { + const subTreeAdd = treeMultiset.subTreeTraverse((node: TreeMultisetNode) => (node.count += 1), 15); + expect(subTreeAdd); + } + const node11 = treeMultiset.get(11); + expect(node11 instanceof TreeMultisetNode); + if (node11 instanceof TreeMultisetNode) { + const allGreaterNodesAdded = treeMultiset.lesserOrGreaterTraverse(node => (node.count += 2), CP.gt, 11); + expect(allGreaterNodesAdded); + } + + const dfsInorderNodes = treeMultiset.dfs(node => node, 'in'); + expect(dfsInorderNodes[0].key).toBe(1); + expect(dfsInorderNodes[dfsInorderNodes.length - 1].key).toBe(16); + expect(treeMultiset.isPerfectlyBalanced()).toBe(false); + + treeMultiset.perfectlyBalance(); + + expect(treeMultiset.isPerfectlyBalanced()).toBe(true); + expect(treeMultiset.isAVLBalanced()).toBe(true); + + const bfsNodesAfterBalanced = treeMultiset.bfs(node => node); + expect(bfsNodesAfterBalanced[0].key).toBe(8); + expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16); + + const removed11 = treeMultiset.delete(11, undefined, true); + expect(removed11 instanceof Array); + expect(removed11[0]); + expect(removed11[0].deleted); + + if (removed11[0].deleted) expect(removed11[0].deleted.key).toBe(11); + + expect(treeMultiset.isAVLBalanced()).toBe(true); + + expect(treeMultiset.getHeight(15)).toBe(1); + + const removed1 = treeMultiset.delete(1, undefined, true); + expect(removed1 instanceof Array); + expect(removed1[0]); + expect(removed1[0].deleted); + if (removed1[0].deleted) expect(removed1[0].deleted.key).toBe(1); + + expect(treeMultiset.isAVLBalanced()).toBe(true); + + expect(treeMultiset.getHeight()).toBe(4); + + const removed4 = treeMultiset.delete(4, undefined, true); + expect(removed4 instanceof Array); + expect(removed4[0]); + expect(removed4[0].deleted); + if (removed4[0].deleted) expect(removed4[0].deleted.key).toBe(4); + + expect(treeMultiset.isAVLBalanced()).toBe(true); + expect(treeMultiset.getHeight()).toBe(4); + + const removed10 = treeMultiset.delete(10, undefined, true); + expect(removed10 instanceof Array); + expect(removed10[0]); + expect(removed10[0].deleted); + if (removed10[0].deleted) expect(removed10[0].deleted.key).toBe(10); + expect(treeMultiset.isAVLBalanced()).toBe(true); + + expect(treeMultiset.getHeight()).toBe(3); + + const removed15 = treeMultiset.delete(15, undefined, true); + expect(removed15 instanceof Array); + expect(removed15[0]); + expect(removed15[0].deleted); + if (removed15[0].deleted) expect(removed15[0].deleted.key).toBe(15); + + expect(treeMultiset.isAVLBalanced()).toBe(true); + expect(treeMultiset.getHeight()).toBe(3); + + const removed5 = treeMultiset.delete(5, undefined, true); + expect(removed5 instanceof Array); + expect(removed5[0]); + expect(removed5[0].deleted); + if (removed5[0].deleted) expect(removed5[0].deleted.key).toBe(5); + + expect(treeMultiset.isAVLBalanced()).toBe(true); + expect(treeMultiset.getHeight()).toBe(3); + + const removed13 = treeMultiset.delete(13, undefined, true); + expect(removed13 instanceof Array); + expect(removed13[0]); + expect(removed13[0].deleted); + if (removed13[0].deleted) expect(removed13[0].deleted.key).toBe(13); + expect(treeMultiset.isAVLBalanced()).toBe(true); + expect(treeMultiset.getHeight()).toBe(3); + + const removed3 = treeMultiset.delete(3, undefined, true); + expect(removed3 instanceof Array); + expect(removed3[0]); + expect(removed3[0].deleted); + if (removed3[0].deleted) expect(removed3[0].deleted.key).toBe(3); + expect(treeMultiset.isAVLBalanced()).toBe(true); + expect(treeMultiset.getHeight()).toBe(3); + + const removed8 = treeMultiset.delete(8, undefined, true); + expect(removed8 instanceof Array); + expect(removed8[0]); + expect(removed8[0].deleted); + if (removed8[0].deleted) expect(removed8[0].deleted.key).toBe(8); + expect(treeMultiset.isAVLBalanced()).toBe(true); + expect(treeMultiset.getHeight()).toBe(3); + + const removed6 = treeMultiset.delete(6, undefined, true); + expect(removed6 instanceof Array); + expect(removed6[0]); + expect(removed6[0].deleted); + if (removed6[0].deleted) expect(removed6[0].deleted.key).toBe(6); + expect(treeMultiset.delete(6, undefined, true).length).toBe(0); + expect(treeMultiset.isAVLBalanced()).toBe(true); + + expect(treeMultiset.getHeight()).toBe(2); + + const removed7 = treeMultiset.delete(7, undefined, true); + expect(removed7 instanceof Array); + expect(removed7[0]); + expect(removed7[0].deleted); + if (removed7[0].deleted) expect(removed7[0].deleted.key).toBe(7); + expect(treeMultiset.isAVLBalanced()).toBe(true); + expect(treeMultiset.getHeight()).toBe(2); + + const removed9 = treeMultiset.delete(9, undefined, true); + expect(removed9 instanceof Array); + expect(removed9[0]); + expect(removed9[0].deleted); + if (removed9[0].deleted) expect(removed9[0].deleted.key).toBe(9); + expect(treeMultiset.isAVLBalanced()).toBe(true); + expect(treeMultiset.getHeight()).toBe(2); + + const removed14 = treeMultiset.delete(14, undefined, true); + expect(removed14 instanceof Array); + expect(removed14[0]); + expect(removed14[0].deleted); + if (removed14[0].deleted) expect(removed14[0].deleted.key).toBe(14); + expect(treeMultiset.isAVLBalanced()).toBe(true); + expect(treeMultiset.getHeight()).toBe(1); + + expect(treeMultiset.isAVLBalanced()).toBe(true); + + const bfsIDs = treeMultiset.bfs(node => node.key); + + expect(bfsIDs[0]).toBe(12); + expect(bfsIDs[1]).toBe(2); + expect(bfsIDs[2]).toBe(16); + + const bfsNodes = treeMultiset.bfs(node => node); + + expect(bfsNodes[0].key).toBe(12); + expect(bfsNodes[1].key).toBe(2); + expect(bfsNodes[2].key).toBe(16); + + expect(treeMultiset.count).toBe(9); + }); + + it('should perform various operations on a Binary Search Tree with object values', () => { + const objTreeMultiset = new TreeMultiset<{key: number; keyA: number}>(); + expect(objTreeMultiset).toBeInstanceOf(TreeMultiset); + objTreeMultiset.add(11, {key: 11, keyA: 11}); + objTreeMultiset.add(3, {key: 3, keyA: 3}); + const values = [ + {key: 15, keyA: 15}, + {key: 1, keyA: 1}, + {key: 8, keyA: 8}, + {key: 13, keyA: 13}, + {key: 16, keyA: 16}, + {key: 2, keyA: 2}, + {key: 6, keyA: 6}, + {key: 9, keyA: 9}, + {key: 12, keyA: 12}, + {key: 14, keyA: 14}, + {key: 4, keyA: 4}, + {key: 7, keyA: 7}, + {key: 10, keyA: 10}, + {key: 5, keyA: 5} + ]; + + objTreeMultiset.addMany( + values.map(item => item.key), + values + ); + + expect(objTreeMultiset.root).toBeInstanceOf(TreeMultisetNode); + + if (objTreeMultiset.root) expect(objTreeMultiset.root.key).toBe(11); + + expect(objTreeMultiset.count).toBe(16); + + expect(objTreeMultiset.has(6)).toBe(true); }); }); describe('TreeMultiset Performance test', function () { - // const treeMS = new TreeMultiset>(); - // const inputSize = [100]; // Adjust input sizes as needed - // - // // Define a function to calculate the expected O(n log n) time - // function expectedTime(n: number): number { - // return n * Math.log(n); - // } - const treeMS = new TreeMultiset>(); const inputSize = 100000; // Adjust input sizes as needed diff --git a/test/unit/data-structures/graph/directed-graph.test.ts b/test/unit/data-structures/graph/directed-graph.test.ts index fcd8443..91cb054 100644 --- a/test/unit/data-structures/graph/directed-graph.test.ts +++ b/test/unit/data-structures/graph/directed-graph.test.ts @@ -22,22 +22,27 @@ describe('DirectedGraph Operation Test', () => { const vertex1 = new DirectedVertex('A'); const vertex2 = new DirectedVertex('B'); const edge = new DirectedEdge('A', 'B'); + edge.src = edge.src; + edge.dest = edge.dest; graph.addVertex(vertex1); graph.addVertex(vertex2); graph.addEdge(edge); + expect(graph.outEdgeMap.size).toBe(1); + expect(graph.inEdgeMap.size).toBe(1); expect(graph.hasEdge('A', 'B')).toBe(true); expect(graph.hasEdge('B', 'A')).toBe(false); }); it('should delete edges', () => { const vertex1 = new DirectedVertex('A'); - const vertex2 = new DirectedVertex('B'); + // const vertex2 = new DirectedVertex('B'); + graph.createVertex('B'); const edge = new DirectedEdge('A', 'B'); graph.addVertex(vertex1); - graph.addVertex(vertex2); + graph.addVertex('B'); graph.addEdge(edge); expect(graph.deleteEdge(edge)).toBe(edge); @@ -49,16 +54,41 @@ describe('DirectedGraph Operation Test', () => { const vertexB = new DirectedVertex('B'); const vertexC = new DirectedVertex('C'); const edgeAB = new DirectedEdge('A', 'B'); - const edgeBC = new DirectedEdge('B', 'C'); + graph.createEdge('B', 'C'); graph.addVertex(vertexA); graph.addVertex(vertexB); graph.addVertex(vertexC); graph.addEdge(edgeAB); - graph.addEdge(edgeBC); + graph.addEdge('B', 'C'); + + expect(graph.getEdgeSrc(edgeAB)).toBe(vertexA); const topologicalOrder = graph.topologicalSort(); if (topologicalOrder) expect(topologicalOrder).toEqual(['A', 'B', 'C']); + + graph.deleteEdgesBetween('A', 'B'); + + const topologicalOrder1 = graph.topologicalSort(); + if (topologicalOrder1) expect(topologicalOrder1).toEqual(['B', 'C', 'A']); + + expect(graph.incomingEdgesOf(vertexC)?.length).toBe(1); + expect(graph.degreeOf(vertexA)).toBe(0); + expect(graph.inDegreeOf(vertexC)).toBe(1); + expect(graph.outDegreeOf(vertexC)).toBe(0); + expect(graph.edgesOf(vertexC)?.length).toBe(1); + + expect(graph.tarjan(true, true, true, true)?.dfnMap.size).toBe(3); + expect(graph.bellmanFord(vertexC, true, true, true)?.paths.length).toBe(3); + expect(graph.getMinPathBetween('B', 'C', true)?.length).toBe(2); + expect(graph.setEdgeWeight('B', 'C', 100)).toBe(true); + expect(graph.getMinCostBetween('B', 'C', true)).toBe(100); + expect(graph.getMinCostBetween('B', 'C')).toBe(1); + expect(graph.getAllPathsBetween('B', 'C')?.length).toBe(1); + expect(graph.deleteVertex(vertexB)).toBe(true); + expect(graph.getAllPathsBetween('B', 'C')?.length).toBe(0); + + expect(graph.removeManyVertices([vertexB, vertexC])).toBe(true); }); }); diff --git a/test/unit/data-structures/graph/map-graph.test.ts b/test/unit/data-structures/graph/map-graph.test.ts index 078a1fc..0c88ddd 100644 --- a/test/unit/data-structures/graph/map-graph.test.ts +++ b/test/unit/data-structures/graph/map-graph.test.ts @@ -1,4 +1,4 @@ -import {MapGraph, MapVertex} from '../../../../src'; +import {MapEdge, MapGraph, MapVertex} from '../../../../src'; describe('MapGraph Operation Test', () => { it('dijkstra shortest path', () => { @@ -43,3 +43,84 @@ describe('MapGraph Operation Test', () => { expect(surinToSaanenGoatFarmViaDij?.minDist).toBe(25.2); }); }); + +describe('MapGraph', () => { + let mapGraph: MapGraph; + + beforeEach(() => { + // Create a new MapGraph instance before each test + mapGraph = new MapGraph([0, 0], [100, 100]); + }); + + // Test adding vertices to the graph + it('should add vertices to the graph', () => { + const locationA = new MapVertex('A', 10, 20, 'Location A'); + const locationB = new MapVertex('B', 30, 40, 'Location B'); + + mapGraph.addVertex(locationA); + mapGraph.addVertex(locationB); + + expect(mapGraph.hasVertex('A')).toBe(true); + expect(mapGraph.hasVertex('B')).toBe(true); + }); + + // Test adding edges to the graph + it('should add edges to the graph', () => { + const locationA = new MapVertex('A', 10, 20, 'Location A'); + const locationB = new MapVertex('B', 30, 40, 'Location B'); + const edgeAB = new MapEdge('A', 'B', 50, 'Edge from A to B'); + + mapGraph.addVertex(locationA); + mapGraph.addVertex(locationB); + mapGraph.addEdge(edgeAB); + + expect(mapGraph.hasEdge('A', 'B')).toBe(true); + }); + + // Test getting neighbors of a vertex + it('should return the neighbors of a vertex', () => { + const locationA = new MapVertex('A', 10, 20, 'Location A'); + locationA.lat = locationA.lat; + locationA.long = locationA.long; + const locationB = mapGraph.createVertex('B', 30, 40, 'Location B'); + + const locationC = new MapVertex('C', 50, 60, 'Location C'); + const edgeAB = new MapEdge('A', 'B', 50, 'Edge from A to B'); + const edgeBC = new MapEdge('B', 'C', 60, 'Edge from B to C'); + + mapGraph.origin = mapGraph.origin; + mapGraph.bottomRight = mapGraph.bottomRight; + + mapGraph.addVertex(locationA); + mapGraph.addVertex(locationB); + mapGraph.addVertex(locationC); + mapGraph.addEdge(edgeAB); + mapGraph.addEdge(edgeBC); + + const neighborsOfA = mapGraph.getNeighbors('A'); + const neighborsOfB = mapGraph.getNeighbors('B'); + + expect(neighborsOfA).toEqual([locationB]); + expect(neighborsOfB).toEqual([locationC]); + }); + + // Test finding the shortest path between locations + it('should find the shortest path between two locations', () => { + const locationA = new MapVertex('A', 10, 20, 'Location A'); + const locationB = new MapVertex('B', 30, 40, 'Location B'); + const locationC = new MapVertex('C', 50, 60, 'Location C'); + const edgeAB = new MapEdge('A', 'B', 50, 'Edge from A to B'); + const edgeBC = new MapEdge('B', 'C', 60, 'Edge from B to C'); + + mapGraph.addVertex(locationA); + mapGraph.addVertex(locationB); + mapGraph.addVertex(locationC); + mapGraph.addEdge(edgeAB); + mapGraph.addEdge(edgeBC); + + const shortestPath = mapGraph.dijkstra('A', 'C'); + + expect(shortestPath?.minPath.length).toEqual(0); + expect(shortestPath?.distMap.size).toBe(3); + }); +}); diff --git a/test/unit/data-structures/graph/undirected-graph.test.ts b/test/unit/data-structures/graph/undirected-graph.test.ts index 9d81ee1..c331fd6 100644 --- a/test/unit/data-structures/graph/undirected-graph.test.ts +++ b/test/unit/data-structures/graph/undirected-graph.test.ts @@ -57,3 +57,85 @@ describe('UndirectedGraph Operation Test', () => { expect(Array.from(dijkstraResult?.seen ?? []).map(vertex => vertex.key)).toEqual(['A', 'B', 'D']); }); }); + +describe('UndirectedGraph', () => { + let undirectedGraph: UndirectedGraph, UndirectedEdge>; + + beforeEach(() => { + // Create a new UndirectedGraph instance before each test + undirectedGraph = new UndirectedGraph, UndirectedEdge>(); + }); + + // Test adding vertices to the graph + it('should add vertices to the graph', () => { + const vertexA = new UndirectedVertex('A', 'Location A'); + const vertexB = new UndirectedVertex('B', 'Location B'); + + undirectedGraph.addVertex(vertexA); + undirectedGraph.addVertex(vertexB); + + expect(undirectedGraph.hasVertex('A')).toBe(true); + expect(undirectedGraph.hasVertex('B')).toBe(true); + }); + + // Test adding edges to the graph + it('should add edges to the graph', () => { + const vertexA = new UndirectedVertex('A', 'Location A'); + const vertexB = new UndirectedVertex('B', 'Location B'); + const edgeAB = new UndirectedEdge('A', 'B', 1, 'Edge between A and B'); + + undirectedGraph.addVertex(vertexA); + undirectedGraph.addVertex(vertexB); + undirectedGraph.addEdge(edgeAB); + + expect(undirectedGraph.hasEdge('A', 'B')).toBe(true); + }); + + // Test getting neighbors of a vertex + it('should return the neighbors of a vertex', () => { + const vertexA = new UndirectedVertex('A', 'Location A'); + const vertexB = new UndirectedVertex('B', 'Location B'); + const vertexC = new UndirectedVertex('C', 'Location C'); + const edgeAB = new UndirectedEdge('A', 'B', 1, 'Edge between A and B'); + const edgeBC = new UndirectedEdge('B', 'C', 2, 'Edge between B and C'); + + undirectedGraph.addVertex(vertexA); + undirectedGraph.addVertex(vertexB); + undirectedGraph.addVertex(vertexC); + undirectedGraph.addEdge(edgeAB); + undirectedGraph.addEdge(edgeBC); + + const neighborsOfA = undirectedGraph.getNeighbors('A'); + const neighborsOfB = undirectedGraph.getNeighbors('B'); + + expect(neighborsOfA).toEqual([vertexB]); + expect(neighborsOfB).toEqual([vertexA, vertexC]); + }); + + // Test degree of a vertex + it('should return the degree of a vertex', () => { + const vertexA = new UndirectedVertex('A', 'Location A'); + const vertexB = new UndirectedVertex('B', 'Location B'); + const vertexC = new UndirectedVertex('C', 'Location C'); + const edgeAB = new UndirectedEdge('A', 'B', 3, 'Edge between A and B'); + const edgeBC = new UndirectedEdge('B', 'C', 4, 'Edge between B and C'); + + edgeAB.vertices = edgeAB.vertices; + expect(undirectedGraph.edges.size).toBe(0); + undirectedGraph.addVertex(vertexA); + undirectedGraph.addVertex(vertexB); + undirectedGraph.addVertex(vertexC); + undirectedGraph.addEdge(edgeAB); + undirectedGraph.addEdge(edgeBC); + + const degreeOfA = undirectedGraph.degreeOf('A'); + const degreeOfB = undirectedGraph.degreeOf('B'); + const degreeOfC = undirectedGraph.degreeOf('C'); + expect(undirectedGraph.edgeSet().length).toBe(2); + expect(undirectedGraph.getEndsOfEdge(edgeBC)?.length).toBe(2); + + expect(degreeOfA).toBe(1); + expect(degreeOfB).toBe(2); + expect(degreeOfC).toBe(1); + }); +}); diff --git a/test/unit/data-structures/heap/heap.test.ts b/test/unit/data-structures/heap/heap.test.ts index d827b91..19ed4dc 100644 --- a/test/unit/data-structures/heap/heap.test.ts +++ b/test/unit/data-structures/heap/heap.test.ts @@ -22,7 +22,7 @@ describe('Heap Operation Test', () => { }); it('should object heap work well', function () { - const minHeap = new MinHeap<{ a: string; key: number }>({comparator: (a, b) => a.key - b.key}); + const minHeap = new MinHeap<{a: string; key: number}>({comparator: (a, b) => a.key - b.key}); minHeap.add({key: 1, a: 'a1'}); minHeap.add({key: 6, a: 'a6'}); minHeap.add({key: 2, a: 'a2'}); @@ -37,7 +37,7 @@ describe('Heap Operation Test', () => { i++; } - const maxHeap = new MaxHeap<{ key: number; a: string }>({comparator: (a, b) => b.key - a.key}); + const maxHeap = new MaxHeap<{key: number; a: string}>({comparator: (a, b) => b.key - a.key}); maxHeap.add({key: 1, a: 'a1'}); maxHeap.add({key: 6, a: 'a6'}); maxHeap.add({key: 5, a: 'a5'}); diff --git a/test/unit/data-structures/linked-list/doubly-linked-list.test.ts b/test/unit/data-structures/linked-list/doubly-linked-list.test.ts index 0838337..eab2ad5 100644 --- a/test/unit/data-structures/linked-list/doubly-linked-list.test.ts +++ b/test/unit/data-structures/linked-list/doubly-linked-list.test.ts @@ -3,7 +3,7 @@ import {bigO, magnitude} from '../../../utils'; describe('DoublyLinkedList Operation Test', () => { let list: DoublyLinkedList; - let objectList: DoublyLinkedList<{ keyA: number }>; + let objectList: DoublyLinkedList<{keyA: number}>; beforeEach(() => { list = new DoublyLinkedList(); diff --git a/test/unit/data-structures/linked-list/singly-linked-list.test.ts b/test/unit/data-structures/linked-list/singly-linked-list.test.ts index 092b2e6..108f9ec 100644 --- a/test/unit/data-structures/linked-list/singly-linked-list.test.ts +++ b/test/unit/data-structures/linked-list/singly-linked-list.test.ts @@ -3,10 +3,10 @@ import {bigO, magnitude} from '../../../utils'; describe('SinglyLinkedList Operation Test', () => { let list: SinglyLinkedList; - let objectList: SinglyLinkedList<{ keyA: number }>; + let objectList: SinglyLinkedList<{keyA: number}>; beforeEach(() => { list = new SinglyLinkedList(); - objectList = new SinglyLinkedList<{ keyA: number }>(); + objectList = new SinglyLinkedList<{keyA: number}>(); }); describe('push', () => { @@ -393,7 +393,7 @@ describe('SinglyLinkedList Performance Test', () => { } // expect(performance.now() - startPopTime).toBeLessThan(bigO.LINEAR); - expect(performance.now() - startPopTime).toBeLessThan(bigO.LINEAR * 300); + expect(performance.now() - startPopTime).toBeLessThan(bigO.LINEAR * 400); }); }); describe('SinglyLinkedList', () => { diff --git a/test/unit/data-structures/matrix/matrix2d.test.ts b/test/unit/data-structures/matrix/matrix2d.test.ts index 2657f9f..a6213ea 100644 --- a/test/unit/data-structures/matrix/matrix2d.test.ts +++ b/test/unit/data-structures/matrix/matrix2d.test.ts @@ -1,5 +1,7 @@ import {Matrix2D, Vector2D} from '../../../../src'; +import {isDebugTest} from '../../../config'; +const isDebug = isDebugTest; describe('Matrix2D', () => { it('should initialize with default identity matrix', () => { const matrix = new Matrix2D(); @@ -136,3 +138,208 @@ describe('Matrix2D', () => { expect(result.m).toEqual(expectedMatrix); }); }); + +describe('Vector2D', () => { + it('should create a vector with default values', () => { + const vector = new Vector2D(); + expect(vector.x).toBe(0); + expect(vector.y).toBe(0); + expect(vector.w).toBe(1); + }); + + it('should correctly calculate vector length', () => { + const vector = new Vector2D(3, 4); + expect(vector.length).toBe(5); + }); + + it('should correctly add two vectors', () => { + const vector1 = new Vector2D(2, 3); + const vector2 = new Vector2D(1, 2); + const result = Vector2D.add(vector1, vector2); + expect(result.x).toBe(3); + expect(result.y).toBe(5); + }); + + // Add more test cases for Vector2D methods +}); + +describe('Matrix2D', () => { + it('should create an identity matrix by default', () => { + const matrix = new Matrix2D(); + expect(matrix.m).toEqual(Matrix2D.identity); + }); + + it('should correctly add two matrices', () => { + const matrix1 = new Matrix2D([ + [1, 2, 3], + [4, 5, 6], + [7, 8, 9] + ]); + const matrix2 = new Matrix2D([ + [9, 8, 7], + [6, 5, 4], + [3, 2, 1] + ]); + const result = Matrix2D.add(matrix1, matrix2); + expect(result.m).toEqual([ + [10, 10, 10], + [10, 10, 10], + [10, 10, 10] + ]); + }); + + // Add more test cases for Matrix2D methods +}); + +describe('Matrix2D', () => { + it('should create a matrix with default identity values', () => { + const matrix = new Matrix2D(); + expect(matrix.m).toEqual(Matrix2D.identity); + }); + + it('should create a matrix from a Vector2D', () => { + const vector = new Vector2D(2, 3); + const matrix = new Matrix2D(vector); + expect(matrix.m).toEqual([ + [2, 0, 0], + [3, 1, 0], + [1, 0, 1] + ]); + }); + + it('should correctly add two matrices', () => { + const matrix1 = new Matrix2D([ + [1, 2, 3], + [4, 5, 6], + [7, 8, 9] + ]); + const matrix2 = new Matrix2D([ + [9, 8, 7], + [6, 5, 4], + [3, 2, 1] + ]); + const result = Matrix2D.add(matrix1, matrix2); + expect(result.m).toEqual([ + [10, 10, 10], + [10, 10, 10], + [10, 10, 10] + ]); + }); + + it('should correctly subtract two matrices', () => { + const matrix1 = new Matrix2D([ + [5, 4, 3], + [2, 1, 0], + [0, 1, 2] + ]); + const matrix2 = new Matrix2D([ + [4, 3, 2], + [1, 0, 1], + [2, 1, 0] + ]); + const result = Matrix2D.subtract(matrix1, matrix2); + expect(result.m).toEqual([ + [1, 1, 1], + [1, 1, -1], + [-2, 0, 2] + ]); + }); + + it('should correctly multiply two matrices', () => { + const matrix1 = new Matrix2D([ + [1, 2, 3], + [4, 5, 6], + [7, 8, 9] + ]); + const matrix2 = new Matrix2D([ + [9, 8, 7], + [6, 5, 4], + [3, 2, 1] + ]); + const result = Matrix2D.multiply(matrix1, matrix2); + expect(result.m).toEqual([ + [30, 24, 18], + [84, 69, 54], + [138, 114, 90] + ]); + }); + + it('should correctly multiply a matrix by a value', () => { + const matrix = new Matrix2D([ + [2, 3, 4], + [5, 6, 7], + [8, 9, 10] + ]); + const value = 2; + const result = Matrix2D.multiplyByValue(matrix, value); + expect(result.m).toEqual([ + [4, 6, 8], + [10, 12, 14], + [16, 18, 20] + ]); + }); + + it('should correctly multiply a matrix by a vector', () => { + const matrix = new Matrix2D([ + [2, 3, 4], + [5, 6, 7], + [8, 9, 10] + ]); + const vector = new Vector2D(2, 3); + const result = Matrix2D.multiplyByVector(matrix, vector); + isDebug && console.log(JSON.stringify(result)); + expect(result).toEqual({x: 17, y: 35, w: 1}); + }); + + it('should correctly create a view matrix', () => { + const width = 800; + const height = 600; + const viewMatrix = Matrix2D.view(width, height); + expect(viewMatrix.m).toEqual([ + [1, 0, 400], + [0, -1, 300], + [0, 0, 1] + ]); + }); + + it('should correctly scale a matrix', () => { + const factor = 3; + const scaledMatrix = Matrix2D.scale(factor); + expect(scaledMatrix.m).toEqual([ + [3, 0, 0], + [0, 3, 0], + [0, 0, 3] + ]); + }); + + it('should correctly rotate a matrix', () => { + const radians = Math.PI / 4; // 45 degrees + const rotationMatrix = Matrix2D.rotate(radians); + console.log(JSON.stringify(rotationMatrix.m)); + expect(rotationMatrix.m).toEqual([ + [0.7071067811865476, -0.7071067811865475, 0], + [0.7071067811865475, 0.7071067811865476, 0], + [0, 0, 1] + ]); + }); + + it('should correctly translate a matrix', () => { + const translationVector = new Vector2D(2, 3); + const translationMatrix = Matrix2D.translate(translationVector); + expect(translationMatrix.m).toEqual([ + [1, 0, 2], + [0, 1, 3], + [0, 0, 1] + ]); + }); + + it('should correctly convert a matrix to a vector', () => { + const matrix = new Matrix2D([ + [2, 3, 4], + [5, 6, 7], + [8, 9, 10] + ]); + const vector = matrix.toVector(); + expect(vector).toEqual(new Vector2D(2, 5)); + }); +}); diff --git a/test/unit/data-structures/matrix/navigator.test.ts b/test/unit/data-structures/matrix/navigator.test.ts index f8d3eda..69029a0 100644 --- a/test/unit/data-structures/matrix/navigator.test.ts +++ b/test/unit/data-structures/matrix/navigator.test.ts @@ -1,5 +1,7 @@ import {Character, Navigator, NavigatorParams, Turning} from '../../../../src'; +import {isDebugTest} from '../../../config'; +const isDebug = isDebugTest; const exampleMatrix: number[][] = [ [0, 0, 0, 0], [0, 1, 1, 0], @@ -17,7 +19,7 @@ const exampleTurning: Turning = { // Create a sample move callback function const exampleOnMove = () => { expect(true).toBeTruthy(); - // console.log(`Moved to position (${cur[0]}, ${cur[1]})`); + // isDebug && console.log(`Moved to position (${cur[0]}, ${cur[1]})`); }; // Create an initial parameter object for the example @@ -77,3 +79,166 @@ describe('Navigator class', () => { expect(navigator.check('left')).toBe(false); // Open path }); }); + +describe('Navigator', () => { + it('should correctly navigate the grid', () => { + // Define a sample grid and initial parameters + const matrix: number[][] = [ + [0, 0, 1], + [0, 1, 0], + [0, 0, 0] + ]; + + const turning: Turning = { + up: 'right', + right: 'down', + down: 'left', + left: 'up' + }; + + const init: NavigatorParams['init'] = { + cur: [0, 0], // Initial position + charDir: 'right', // Initial character direction + VISITED: 2 // Value to mark visited cells + }; + + // Initialize the navigator + const navigator = new Navigator({ + matrix, + turning, + init, + onMove: cur => cur + }); + + // Define a function to track visited cells + const visitedCells: number[][] = []; + const onMove = (cur: number[]) => { + visitedCells.push([...cur]); + }; + + // Attach the onMove function + navigator.onMove = onMove; + + // Start the navigation + navigator.start(); + + // The character should have navigated the grid correctly + expect(visitedCells).toEqual([ + [0, 1], + [0, 2], + [1, 2], + [2, 2], + [2, 1], + [2, 0], + [1, 0], + [1, 1] + ]); + }); + + it('should not move if there are no valid moves', () => { + // Define a sample grid with no valid moves + const matrix: number[][] = [ + [1, 1], + [1, 1] + ]; + + const turning: Turning = { + up: 'right', + right: 'down', + down: 'left', + left: 'up' + }; + + const init: NavigatorParams['init'] = { + cur: [0, 0], // Initial position + charDir: 'right', // Initial character direction + VISITED: 2 // Value to mark visited cells + }; + + // Initialize the navigator + const navigator = new Navigator({ + matrix, + turning, + init, + onMove: cur => cur + }); + + // Define a function to track visited cells + const visitedCells: number[][] = []; + const onMove = (cur: number[]) => { + visitedCells.push([...cur]); + }; + + // Attach the onMove function + navigator.onMove = onMove; + + // Start the navigation + navigator.start(); + + // The character should not move + isDebug && console.log(visitedCells); + expect(visitedCells).toEqual([ + [0, 1], + [1, 1], + [1, 0] + ]); + }); + + it('should handle edge cases and turns correctly', () => { + // Define a sample grid with turns and edge cases + const matrix: number[][] = [ + [1, 0, 0, 0], + [1, 0, 1, 0], + [0, 0, 1, 1] + ]; + + const turning: Turning = { + up: 'right', + right: 'down', + down: 'left', + left: 'up' + }; + + const init: NavigatorParams['init'] = { + cur: [0, 0], // Initial position + charDir: 'right', // Initial character direction + VISITED: 2 // Value to mark visited cells + }; + + // Initialize the navigator + const navigator = new Navigator({ + matrix, + turning, + init, + onMove: cur => cur + }); + + // Define a function to track visited cells + const visitedCells: number[][] = []; + const onMove = (cur: number[]) => { + visitedCells.push([...cur]); + }; + + // Attach the onMove function + navigator.onMove = onMove; + + // Start the navigation + navigator.start(); + + // The character should have navigated the grid, handled turns, and edge cases + isDebug && console.log(visitedCells); + expect(visitedCells).toEqual([ + [0, 1], + [0, 2], + [0, 3], + [1, 3], + [2, 3], + [2, 2], + [2, 1], + [2, 0], + [1, 0], + [1, 1], + [1, 2] + ]); + }); +}); diff --git a/test/unit/data-structures/matrix/vector2d.test.ts b/test/unit/data-structures/matrix/vector2d.test.ts new file mode 100644 index 0000000..93d1f8d --- /dev/null +++ b/test/unit/data-structures/matrix/vector2d.test.ts @@ -0,0 +1,171 @@ +import {Vector2D} from '../../../../src'; + +describe('Vector2D', () => { + it('should create a vector with default values', () => { + const vector = new Vector2D(); + expect(vector.x).toBe(0); + expect(vector.y).toBe(0); + expect(vector.w).toBe(1); + }); + + it('should correctly check if a vector is zero', () => { + const nonZeroVector = new Vector2D(3, 4); + const zeroVector = new Vector2D(0, 0); + expect(nonZeroVector.isZero).toBe(false); + expect(zeroVector.isZero).toBe(true); + }); + + it('should correctly calculate vector length', () => { + const vector = new Vector2D(3, 4); + expect(vector.length).toBe(5); + }); + + it('should correctly calculate squared vector length', () => { + const vector = new Vector2D(3, 4); + expect(vector.lengthSq).toBe(25); + }); + + it('should correctly round vector components', () => { + const vector = new Vector2D(3.6, 4.3); + const roundedVector = vector.rounded; + expect(roundedVector.x).toBe(4); + expect(roundedVector.y).toBe(4); + }); + + it('should correctly add two vectors', () => { + const vector1 = new Vector2D(2, 3); + const vector2 = new Vector2D(1, 2); + const result = Vector2D.add(vector1, vector2); + expect(result.x).toBe(3); + expect(result.y).toBe(5); + }); + + it('should correctly subtract two vectors', () => { + const vector1 = new Vector2D(4, 5); + const vector2 = new Vector2D(1, 2); + const result = Vector2D.subtract(vector1, vector2); + expect(result.x).toBe(3); + expect(result.y).toBe(3); + }); + + it('should correctly subtract value from a vector', () => { + const vector = new Vector2D(5, 7); + const result = Vector2D.subtractValue(vector, 3); + expect(result.x).toBe(2); + expect(result.y).toBe(4); + }); + + it('should correctly multiply a vector by a value', () => { + const vector = new Vector2D(2, 3); + const result = Vector2D.multiply(vector, 4); + expect(result.x).toBe(8); + expect(result.y).toBe(12); + }); + + it('should correctly divide a vector by a value', () => { + const vector = new Vector2D(6, 8); + const result = Vector2D.divide(vector, 2); + expect(result.x).toBe(3); + expect(result.y).toBe(4); + }); + + it('should correctly check if two vectors are equal', () => { + const vector1 = new Vector2D(3, 4); + const vector2 = new Vector2D(3, 4); + const vector3 = new Vector2D(4, 5); + expect(Vector2D.equals(vector1, vector2)).toBe(true); + expect(Vector2D.equals(vector1, vector3)).toBe(false); + }); + + it('should correctly check if two vectors are equal within a rounding factor', () => { + const vector1 = new Vector2D(3, 4); + const vector2 = new Vector2D(2.9, 3.9); + const vector3 = new Vector2D(4, 5); + expect(Vector2D.equalsRounded(vector1, vector2, 0.2)).toBe(true); + expect(Vector2D.equalsRounded(vector1, vector3, 0.2)).toBe(false); + }); + + it('should correctly normalize a vector', () => { + const vector = new Vector2D(3, 4); + const normalized = Vector2D.normalize(vector); + expect(normalized.x).toBeCloseTo(0.6); + expect(normalized.y).toBeCloseTo(0.8); + }); + + it('should correctly truncate a vector', () => { + const vector = new Vector2D(3, 4); + const truncated = Vector2D.truncate(vector, 4); + expect(truncated.length).toBeLessThanOrEqual(4); + }); + + it('should correctly get the perpendicular vector', () => { + const vector = new Vector2D(3, 4); + const perpendicular = Vector2D.perp(vector); + expect(Vector2D.dot(vector, perpendicular)).toBe(0); + }); + + it('should correctly reverse the vector', () => { + const vector = new Vector2D(3, 4); + const reversed = Vector2D.reverse(vector); + expect(reversed.x).toBe(-3); + expect(reversed.y).toBe(-4); + }); + + it('should correctly get the absolute vector', () => { + const vector = new Vector2D(-3, 4); + const absVector = Vector2D.abs(vector); + expect(absVector.x).toBe(3); + expect(absVector.y).toBe(4); + }); + + it('should correctly calculate the dot product of two vectors', () => { + const vector1 = new Vector2D(2, 3); + const vector2 = new Vector2D(4, 5); + const dotProduct = Vector2D.dot(vector1, vector2); + expect(dotProduct).toBe(23); + }); + + it('should correctly calculate the distance between two vectors', () => { + const vector1 = new Vector2D(1, 1); + const vector2 = new Vector2D(4, 5); + const distance = Vector2D.distance(vector1, vector2); + expect(distance).toBeCloseTo(5); + }); + + it('should correctly calculate the squared distance between two vectors', () => { + const vector1 = new Vector2D(1, 1); + const vector2 = new Vector2D(4, 5); + const distanceSq = Vector2D.distanceSq(vector1, vector2); + expect(distanceSq).toBe(25); + }); + + it('should correctly determine the sign of the cross product of two vectors', () => { + const vector1 = new Vector2D(2, 3); + const vector2 = new Vector2D(4, 5); + const sign = Vector2D.sign(vector1, vector2); + expect(sign).toBe(-1); // Assuming specific vector values, the result may vary + }); + + it('should correctly calculate the angle between a vector and the negative y-axis', () => { + const vector = new Vector2D(3, 4); + const angle = Vector2D.angle(vector); + expect(angle).toBeCloseTo(2.498091544796509, 3); + }); + + it('should create a random vector within the specified range', () => { + const maxX = 10; + const maxY = 10; + const randomVector = Vector2D.random(maxX, maxY); + expect(randomVector.x).toBeGreaterThanOrEqual(-maxX / 2); + expect(randomVector.x).toBeLessThanOrEqual(maxX / 2); + expect(randomVector.y).toBeGreaterThanOrEqual(-maxY / 2); + expect(randomVector.y).toBeLessThanOrEqual(maxY / 2); + }); + + it('should zero the vector components', () => { + const vector = new Vector2D(3, 4); + vector.zero(); + expect(vector.x).toBe(0); + expect(vector.y).toBe(0); + }); +}); diff --git a/test/unit/data-structures/priority-queue/max-priority-queue.test.ts b/test/unit/data-structures/priority-queue/max-priority-queue.test.ts index 8b2f287..26fd837 100644 --- a/test/unit/data-structures/priority-queue/max-priority-queue.test.ts +++ b/test/unit/data-structures/priority-queue/max-priority-queue.test.ts @@ -17,7 +17,7 @@ describe('MaxPriorityQueue Operation Test', () => { }); it('should add elements and maintain heap property in a object MaxPriorityQueue', () => { - const priorityQueue = new MaxPriorityQueue<{ keyA: number }>({comparator: (a, b) => b.keyA - a.keyA}); + const priorityQueue = new MaxPriorityQueue<{keyA: number}>({comparator: (a, b) => b.keyA - a.keyA}); priorityQueue.refill([{keyA: 5}, {keyA: 3}, {keyA: 1}]); priorityQueue.add({keyA: 7}); @@ -64,7 +64,7 @@ describe('MaxPriorityQueue Operation Test', () => { it('should correctly heapify an object array', () => { const nodes = [{keyA: 5}, {keyA: 3}, {keyA: 7}, {keyA: 1}]; - const maxPQ = MaxPriorityQueue.heapify<{ keyA: number }>({nodes: nodes, comparator: (a, b) => b.keyA - a.keyA}); + const maxPQ = MaxPriorityQueue.heapify<{keyA: number}>({nodes: nodes, comparator: (a, b) => b.keyA - a.keyA}); expect(maxPQ.poll()?.keyA).toBe(7); expect(maxPQ.poll()?.keyA).toBe(5); diff --git a/test/unit/data-structures/queue/deque.test.ts b/test/unit/data-structures/queue/deque.test.ts index ca41a61..bc89ebf 100644 --- a/test/unit/data-structures/queue/deque.test.ts +++ b/test/unit/data-structures/queue/deque.test.ts @@ -1,6 +1,8 @@ import {ArrayDeque, Deque, ObjectDeque} from '../../../../src'; import {bigO} from '../../../utils'; +import {isDebugTest} from '../../../config'; +const isDebug = isDebugTest; describe('Deque Tests', () => { // Test cases for the Deque class (DoublyLinkedList-based) describe('Deque (DoublyLinkedList-based)', () => { @@ -141,7 +143,268 @@ describe('Deque Performance Test', () => { for (let i = 0; i < dataSize; i++) { queue.pop(); } - console.log(`Queue Deque Test: ${performance.now() - startTime} ms`); + isDebug && console.log(`Queue Deque Test: ${performance.now() - startTime} ms`); expect(performance.now() - startTime).toBeLessThan(bigO.LINEAR * 100); }); }); + +describe('Deque', () => { + let deque: Deque; + + beforeEach(() => { + deque = new Deque(); + }); + + test('should initialize an empty deque', () => { + expect(deque.size).toBe(0); + expect(deque.isEmpty()).toBe(true); + }); + + test('should add elements to the front and back', () => { + deque.addFirst(1); + deque.addLast(2); + + expect(deque.size).toBe(2); + expect(deque.peekFirst()).toBe(1); + expect(deque.peekLast()).toBe(2); + }); + + test('should remove elements from the front and back', () => { + deque.addFirst(1); + deque.addLast(2); + + const firstElement = deque.pollFirst(); + const lastElement = deque.pollLast(); + + expect(deque.size).toBe(0); + expect(firstElement).toBe(1); + expect(lastElement).toBe(2); + }); + + test('should get elements by index', () => { + deque.addLast(1); + deque.addLast(2); + deque.addLast(3); + + expect(deque.getAt(0)).toBe(1); + expect(deque.getAt(1)).toBe(2); + expect(deque.getAt(2)).toBe(3); + }); + + test('should return null for out-of-bounds index', () => { + expect(deque.getAt(0)).toBe(undefined); + expect(deque.getAt(1)).toBe(undefined); + expect(deque.getAt(-1)).toBe(undefined); + }); + + test('should check if the deque is empty', () => { + expect(deque.isEmpty()).toBe(true); + + deque.addLast(1); + expect(deque.isEmpty()).toBe(false); + + deque.pollFirst(); + expect(deque.isEmpty()).toBe(true); + }); +}); + +describe('ArrayDeque', () => { + let deque: ArrayDeque; + + beforeEach(() => { + deque = new ArrayDeque(); + }); + + test('should initialize an empty deque', () => { + expect(deque.size).toBe(0); + expect(deque.isEmpty()).toBe(true); + }); + + test('should add elements to the front and back', () => { + deque.addFirst(1); + deque.addLast(2); + + expect(deque.size).toBe(2); + expect(deque.peekFirst()).toBe(1); + expect(deque.peekLast()).toBe(2); + }); + + test('should remove elements from the front and back', () => { + deque.addFirst(1); + deque.addLast(2); + + const firstElement = deque.pollFirst(); + const lastElement = deque.pollLast(); + + expect(deque.size).toBe(0); + expect(firstElement).toBe(1); + expect(lastElement).toBe(2); + }); + + test('should get elements by index', () => { + deque.addLast(1); + deque.addLast(2); + deque.addLast(3); + + expect(deque.get(0)).toBe(1); + expect(deque.get(1)).toBe(2); + expect(deque.get(2)).toBe(3); + }); + + test('should return null for out-of-bounds index', () => { + expect(deque.get(0)).toBe(null); + expect(deque.get(1)).toBe(null); + expect(deque.get(-1)).toBe(null); + }); + + test('should check if the deque is empty', () => { + expect(deque.isEmpty()).toBe(true); + + deque.addLast(1); + expect(deque.isEmpty()).toBe(false); + + deque.pollFirst(); + expect(deque.isEmpty()).toBe(true); + }); + + test('should set elements at a specific index', () => { + deque.addLast(1); + deque.addLast(2); + deque.addLast(3); + + deque.set(1, 4); + + expect(deque.get(0)).toBe(1); + expect(deque.get(1)).toBe(4); + expect(deque.get(2)).toBe(3); + }); + + test('should insert elements at a specific index', () => { + deque.addLast(1); + deque.addLast(2); + deque.addLast(3); + + deque.insert(1, 4); + + expect(deque.size).toBe(4); + expect(deque.get(0)).toBe(1); + expect(deque.get(1)).toBe(4); + expect(deque.get(2)).toBe(2); + expect(deque.get(3)).toBe(3); + }); + + test('should delete elements at a specific index', () => { + deque.addLast(1); + deque.addLast(2); + deque.addLast(3); + + const deletedElement = deque.delete(1); + + expect(deque.size).toBe(2); + expect(deletedElement[0]).toBe(2); + expect(deque.get(0)).toBe(1); + expect(deque.get(1)).toBe(3); + }); +}); + +describe('ObjectDeque', () => { + let deque: ObjectDeque; + + beforeEach(() => { + deque = new ObjectDeque(); + }); + + test('should add elements to the front of the deque', () => { + deque.addFirst(1); + deque.addFirst(2); + + expect(deque.size).toBe(2); + expect(deque.peekFirst()).toBe(2); + expect(deque.peekLast()).toBe(1); + }); + + test('should add elements to the end of the deque', () => { + deque.addLast(1); + deque.addLast(2); + + expect(deque.size).toBe(2); + expect(deque.peekFirst()).toBe(1); + expect(deque.peekLast()).toBe(2); + }); + + test('should remove elements from the front of the deque', () => { + deque.addLast(1); + deque.addLast(2); + + const removedElement = deque.pollFirst(); + + expect(deque.size).toBe(1); + expect(removedElement).toBe(1); + expect(deque.peekFirst()).toBe(2); + }); + + test('should remove elements from the end of the deque', () => { + deque.addLast(1); + deque.addLast(2); + + const removedElement = deque.pollFirst(); + + expect(deque.size).toBe(1); + expect(removedElement).toBe(1); + expect(deque.peekLast()).toBe(2); + }); + + test('should return the element at the front of the deque without removing it', () => { + deque.addFirst(1); + deque.addFirst(2); + + expect(deque.peekFirst()).toBe(2); + expect(deque.size).toBe(2); + }); + + test('should return the element at the end of the deque without removing it', () => { + deque.addLast(1); + deque.addLast(2); + + expect(deque.peekLast()).toBe(2); + expect(deque.size).toBe(2); + }); + + test('should return the correct size of the deque', () => { + deque.addFirst(1); + deque.addLast(2); + deque.addLast(3); + + expect(deque.size).toBe(3); + }); + + test('should check if the deque is empty', () => { + expect(deque.isEmpty()).toBe(true); + + deque.addFirst(1); + + expect(deque.isEmpty()).toBe(false); + }); + + test('should set elements at a specific index', () => { + deque.addFirst(1); + deque.addLast(2); + deque.addLast(3); + + expect(deque.peekFirst()).toBe(1); + expect(deque.get(1)).toBe(2); + expect(deque.peekLast()).toBe(3); + }); + + test('should insert elements at a specific index', () => { + deque.addFirst(1); + deque.addLast(2); + deque.addLast(3); + + expect(deque.size).toBe(3); + expect(deque.peekFirst()).toBe(1); + expect(deque.get(1)).toBe(2); + expect(deque.get(2)).toBe(3); + expect(deque.peekLast()).toBe(3); + }); +}); diff --git a/test/unit/data-structures/queue/queue.test.ts b/test/unit/data-structures/queue/queue.test.ts index 93d15bc..a32e811 100644 --- a/test/unit/data-structures/queue/queue.test.ts +++ b/test/unit/data-structures/queue/queue.test.ts @@ -1,6 +1,8 @@ import {LinkedListQueue, Queue} from '../../../../src'; import {bigO, magnitude} from '../../../utils'; +import {isDebugTest} from '../../../config'; +const isDebug = isDebugTest; describe('Queue Operation Test', () => { it('should validate a queue', () => { const queue = new Queue(); @@ -209,7 +211,7 @@ describe('Queue Performance Test', () => { for (let i = 0; i < dataSize; i++) { queue.dequeue(); } - console.log(`Queue Performance Test: ${performance.now() - startTime} ms`); + isDebug && console.log(`Queue Performance Test: ${performance.now() - startTime} ms`); expect(performance.now() - startTime).toBeLessThan(bigO.LINEAR * 100); }); diff --git a/test/utils/big-o.ts b/test/utils/big-o.ts index cc9fc86..43d7eca 100644 --- a/test/utils/big-o.ts +++ b/test/utils/big-o.ts @@ -26,7 +26,7 @@ export const bigO = { function findPotentialN(input: any): number { let longestArray: any[] = []; - let mostProperties: { [key: string]: any } = {}; + let mostProperties: {[key: string]: any} = {}; function recurse(obj: any) { if (Array.isArray(obj)) { From c492af046126b6c0abb06c400f61c751dff120df Mon Sep 17 00:00:00 2001 From: Revone Date: Sun, 29 Oct 2023 16:43:19 +0800 Subject: [PATCH 34/46] [linked-list] Standardize the method names of DoublyLinkedList and SinglyLinkedList. --- CHANGELOG.md | 2 +- package-lock.json | 50 +++---- package.json | 8 +- .../linked-list/doubly-linked-list.ts | 119 ++++++++-------- .../linked-list/singly-linked-list.ts | 130 ++++++++++++++++-- src/data-structures/queue/deque.ts | 44 +++--- src/data-structures/queue/queue.ts | 6 +- .../linked-list/doubly-linked-list.test.ts | 10 +- .../linked-list/linked-list.test.ts | 4 +- .../linked-list/singly-linked-list.test.ts | 4 +- test/unit/data-structures/queue/deque.test.ts | 86 ++++++------ test/unit/data-structures/queue/queue.test.ts | 14 +- 12 files changed, 291 insertions(+), 186 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 43c4c33..51e66a0 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.39.0](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) +## [v1.39.1](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) ### Changes diff --git a/package-lock.json b/package-lock.json index 036d8c4..79cc7ab 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "data-structure-typed", - "version": "1.39.0", + "version": "1.39.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "data-structure-typed", - "version": "1.39.0", + "version": "1.39.1", "license": "MIT", "devDependencies": { "@types/benchmark": "^2.1.3", @@ -15,17 +15,17 @@ "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", "auto-changelog": "^2.4.0", - "avl-tree-typed": "^1.38.9", + "avl-tree-typed": "^1.39.0", "benchmark": "^2.1.4", - "binary-tree-typed": "^1.38.9", - "bst-typed": "^1.38.9", + "binary-tree-typed": "^1.39.0", + "bst-typed": "^1.39.0", "dependency-cruiser": "^14.1.0", "eslint": "^8.50.0", "eslint-config-prettier": "^9.0.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.28.1", - "heap-typed": "^1.38.9", + "heap-typed": "^1.39.0", "istanbul-badges-readme": "^1.8.5", "jest": "^29.7.0", "prettier": "^3.0.3", @@ -2728,12 +2728,12 @@ } }, "node_modules/avl-tree-typed": { - "version": "1.38.9", - "resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.38.9.tgz", - "integrity": "sha512-1Qy7d5G8JXa5Z2KKmlZI1WOmJkIyW6l2zRGHCxXItEfIg+BirZm6BK4IOb03OJjA2qg2N5AxgZDKuMDAzbRXNw==", + "version": "1.39.0", + "resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.39.0.tgz", + "integrity": "sha512-YpYfpO0slt8R5lcy4wrz7inKFAG1NKUZk2FnJ2FEYIdBJaBIUvW0cflx6Cuuy1iRiXbazpTqGQgKC0nERWUiow==", "dev": true, "dependencies": { - "data-structure-typed": "^1.38.9" + "data-structure-typed": "^1.39.0" } }, "node_modules/babel-jest": { @@ -2927,12 +2927,12 @@ } }, "node_modules/binary-tree-typed": { - "version": "1.38.9", - "resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.38.9.tgz", - "integrity": "sha512-XGp+ADfVMhhpEqLV+Bi27FkJcT1P6ExPpGuhzhKzyfoWmsnjp94tuuvrUDCqPjYoioGwzbG7yUnC2Fbi4CbsAA==", + "version": "1.39.0", + "resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.39.0.tgz", + "integrity": "sha512-oJzCbrs+l4qacscxFvVB/ielr22KiO8z/bWSx/tJmafpinWmkAuQIBRGqo+frfFi8MKstNerHPEF+4yT8AakUA==", "dev": true, "dependencies": { - "data-structure-typed": "^1.38.9" + "data-structure-typed": "^1.39.0" } }, "node_modules/brace-expansion": { @@ -3011,12 +3011,12 @@ } }, "node_modules/bst-typed": { - "version": "1.38.9", - "resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.38.9.tgz", - "integrity": "sha512-jnHwqyTjRCDitmzXydhcP1YmRsCfBYxwhDXD8lm1pQPWOXkcAIU7HqTg7WCPrReo1GaWfQJeBhAIsguluEQ6Lw==", + "version": "1.39.0", + "resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.39.0.tgz", + "integrity": "sha512-AvitIe0j8jPrXyZkQI5zhTYIc4eS5rxvW59/0YHymg54BeMs+zm1WzouPhsh7qp9D+IcTpQmqDY0kjc07Tic3w==", "dev": true, "dependencies": { - "data-structure-typed": "^1.38.9" + "data-structure-typed": "^1.39.0" } }, "node_modules/buffer-from": { @@ -3413,9 +3413,9 @@ } }, "node_modules/data-structure-typed": { - "version": "1.38.9", - "resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.38.9.tgz", - "integrity": "sha512-iHOVtsBY7ZVI28I0ikedDFmBeu3rGu1gSnmemg11PT/KIuflNe9zdwlNm+yZ4M56LbQp0aqY09YoNnNX43UvRw==", + "version": "1.39.0", + "resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.39.0.tgz", + "integrity": "sha512-HESmI/a+uE3ELRDVKIBSmfgSMep4ETJco8jeZD2By5lNhMW9HDZE+SGNqlSeBJd3PdJyact9dWlXWwg7S3+ztQ==", "dev": true }, "node_modules/debug": { @@ -4771,12 +4771,12 @@ } }, "node_modules/heap-typed": { - "version": "1.38.9", - "resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.38.9.tgz", - "integrity": "sha512-50RxpJOqMDMbpGa3NZny3YO8NArmwVeIipNDHkOvHXH+P93BvbaFz06rOyuJ1cUxDwTPsv34VfJgrz576/BZtg==", + "version": "1.39.0", + "resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.39.0.tgz", + "integrity": "sha512-n9Qa+Ph6nnqRN6lz52R62CHrpgWixU/39P22WT9Epf+4dj+pDYPKEGekCCidjjxQXgoR56d6XjnZWFgiQYYN4Q==", "dev": true, "dependencies": { - "data-structure-typed": "^1.38.9" + "data-structure-typed": "^1.39.0" } }, "node_modules/html-escaper": { diff --git a/package.json b/package.json index 680b283..2fd7f9f 100644 --- a/package.json +++ b/package.json @@ -61,17 +61,17 @@ "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", "auto-changelog": "^2.4.0", - "avl-tree-typed": "^1.38.9", + "avl-tree-typed": "^1.39.0", "benchmark": "^2.1.4", - "binary-tree-typed": "^1.38.9", - "bst-typed": "^1.38.9", + "binary-tree-typed": "^1.39.0", + "bst-typed": "^1.39.0", "dependency-cruiser": "^14.1.0", "eslint": "^8.50.0", "eslint-config-prettier": "^9.0.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.28.1", - "heap-typed": "^1.38.9", + "heap-typed": "^1.39.0", "istanbul-badges-readme": "^1.8.5", "jest": "^29.7.0", "prettier": "^3.0.3", diff --git a/src/data-structures/linked-list/doubly-linked-list.ts b/src/data-structures/linked-list/doubly-linked-list.ts index ab9ddc5..ceacdb2 100644 --- a/src/data-structures/linked-list/doubly-linked-list.ts +++ b/src/data-structures/linked-list/doubly-linked-list.ts @@ -147,11 +147,11 @@ export class DoublyLinkedList { } /** - * The `pollLast()` function removes and returns the value of the last node in a doubly linked list. + * The `popLast()` function removes and returns the value of the last node in a doubly linked list. * @returns The method is returning the value of the removed node (removedNode.val) if the list is not empty. If the * list is empty, it returns null. */ - pollLast(): E | undefined { + popLast(): E | undefined { return this.pop(); } @@ -175,11 +175,11 @@ export class DoublyLinkedList { } /** - * The `pollFirst()` function removes and returns the value of the first node in a doubly linked list. + * The `popFirst()` function removes and returns the value of the first node in a doubly linked list. * @returns The method `shift()` returns the value of the node that is removed from the beginning of the doubly linked * list. */ - pollFirst(): E | undefined { + popFirst(): E | undefined { return this.shift(); } @@ -211,18 +211,18 @@ export class DoublyLinkedList { } /** - * The `peekFirst` function returns the first node in a doubly linked list, or null if the list is empty. - * @returns The method `peekFirst()` returns the first node of the doubly linked list, or `null` if the list is empty. + * The `getFirst` function returns the first node in a doubly linked list, or null if the list is empty. + * @returns The method `getFirst()` returns the first node of the doubly linked list, or `null` if the list is empty. */ - peekFirst(): E | undefined { + getFirst(): E | undefined { return this.head?.val; } /** - * The `peekLast` function returns the last node in a doubly linked list, or null if the list is empty. - * @returns The method `peekLast()` returns the last node of the doubly linked list, or `null` if the list is empty. + * The `getLast` function returns the last node in a doubly linked list, or null if the list is empty. + * @returns The method `getLast()` returns the last node of the doubly linked list, or `null` if the list is empty. */ - peekLast(): E | undefined { + getLast(): E | undefined { return this.tail?.val; } @@ -266,7 +266,7 @@ export class DoublyLinkedList { * @returns The function `findNodeByValue` returns a `DoublyLinkedListNode` if a node with the specified value `val` * is found in the linked list. If no such node is found, it returns `null`. */ - findNode(val: E | null): DoublyLinkedListNode | null { + getNode(val: E | null): DoublyLinkedListNode | null { let current = this.head; while (current) { @@ -310,6 +310,43 @@ export class DoublyLinkedList { return true; } + /** + * The `insertBefore` function inserts a new value before an existing value or node in a doubly linked list. + * @param {E | DoublyLinkedListNode} existingValueOrNode - The existing value or node in the doubly linked list + * before which the new value will be inserted. It can be either the value of the existing node or the existing node + * itself. + * @param {E} newValue - The `newValue` parameter represents the value that you want to insert into the doubly linked + * list. + * @returns The method returns a boolean value. It returns `true` if the insertion is successful, and `false` if the + * insertion fails. + */ + insertBefore(existingValueOrNode: E | DoublyLinkedListNode, newValue: E): boolean { + let existingNode; + + if (existingValueOrNode instanceof DoublyLinkedListNode) { + existingNode = existingValueOrNode; + } else { + existingNode = this.getNode(existingValueOrNode); + } + + if (existingNode) { + const newNode = new DoublyLinkedListNode(newValue); + newNode.prev = existingNode.prev; + if (existingNode.prev) { + existingNode.prev.next = newNode; + } + newNode.next = existingNode; + existingNode.prev = newNode; + if (existingNode === this.head) { + this.head = newNode; + } + this._length++; + return true; + } + + return false; + } + /** * The `deleteAt` function removes an element at a specified index from a linked list and returns the removed element. * @param {number} index - The index parameter represents the position of the element that needs to be deleted in the @@ -331,9 +368,6 @@ export class DoublyLinkedList { return removedNode!.val; } - delete(valOrNode: E): boolean; - delete(valOrNode: DoublyLinkedListNode): boolean; - /** * The `delete` function removes a node from a doubly linked list based on either the node itself or its value. * @param {E | DoublyLinkedListNode} valOrNode - The `valOrNode` parameter can accept either a value of type `E` or @@ -347,7 +381,7 @@ export class DoublyLinkedList { if (valOrNode instanceof DoublyLinkedListNode) { node = valOrNode; } else { - node = this.findNode(valOrNode); + node = this.getNode(valOrNode); } if (node) { @@ -437,14 +471,14 @@ export class DoublyLinkedList { } /** - * The `findLast` function iterates through a linked list from the last node to the first node and returns the last + * The `findBackward` function iterates through a linked list from the last node to the first node and returns the last * value that satisfies the given callback function, or null if no value satisfies the callback. * @param callback - A function that takes a value of type E as its parameter and returns a boolean value. This * function is used to determine whether a given value satisfies a certain condition. - * @returns The method `findLast` returns the last value in the linked list that satisfies the condition specified by + * @returns The method `findBackward` returns the last value in the linked list that satisfies the condition specified by * the callback function. If no value satisfies the condition, it returns `null`. */ - findLast(callback: (val: E) => boolean): E | null { + findBackward(callback: (val: E) => boolean): E | null { let current = this.tail; while (current) { if (callback(current.val)) { @@ -456,10 +490,10 @@ export class DoublyLinkedList { } /** - * The `toArrayReverse` function converts a doubly linked list into an array in reverse order. - * @returns The `toArrayReverse()` function returns an array of type `E[]`. + * The `toArrayBackward` function converts a doubly linked list into an array in reverse order. + * @returns The `toArrayBackward()` function returns an array of type `E[]`. */ - toArrayReverse(): E[] { + toArrayBackward(): E[] { const array: E[] = []; let current = this.tail; while (current) { @@ -555,9 +589,6 @@ export class DoublyLinkedList { return accumulator; } - insertAfter(existingValueOrNode: E, newValue: E): boolean; - insertAfter(existingValueOrNode: DoublyLinkedListNode, newValue: E): boolean; - /** * The `insertAfter` function inserts a new node with a given value after an existing node in a doubly linked list. * @param {E | DoublyLinkedListNode} existingValueOrNode - The existing value or node in the doubly linked list @@ -573,7 +604,7 @@ export class DoublyLinkedList { if (existingValueOrNode instanceof DoublyLinkedListNode) { existingNode = existingValueOrNode; } else { - existingNode = this.findNode(existingValueOrNode); + existingNode = this.getNode(existingValueOrNode); } if (existingNode) { @@ -594,40 +625,12 @@ export class DoublyLinkedList { return false; } - /** - * The `insertBefore` function inserts a new value before an existing value or node in a doubly linked list. - * @param {E | DoublyLinkedListNode} existingValueOrNode - The existing value or node in the doubly linked list - * before which the new value will be inserted. It can be either the value of the existing node or the existing node - * itself. - * @param {E} newValue - The `newValue` parameter represents the value that you want to insert into the doubly linked - * list. - * @returns The method returns a boolean value. It returns `true` if the insertion is successful, and `false` if the - * insertion fails. - */ - insertBefore(existingValueOrNode: E | DoublyLinkedListNode, newValue: E): boolean { - let existingNode; + * [Symbol.iterator]() { + let current = this.head; - if (existingValueOrNode instanceof DoublyLinkedListNode) { - existingNode = existingValueOrNode; - } else { - existingNode = this.findNode(existingValueOrNode); + while (current) { + yield current.val; + current = current.next; } - - if (existingNode) { - const newNode = new DoublyLinkedListNode(newValue); - newNode.prev = existingNode.prev; - if (existingNode.prev) { - existingNode.prev.next = newNode; - } - newNode.next = existingNode; - existingNode.prev = newNode; - if (existingNode === this.head) { - this.head = newNode; - } - this._length++; - return true; - } - - return false; } } diff --git a/src/data-structures/linked-list/singly-linked-list.ts b/src/data-structures/linked-list/singly-linked-list.ts index c4e1da9..48e41c4 100644 --- a/src/data-structures/linked-list/singly-linked-list.ts +++ b/src/data-structures/linked-list/singly-linked-list.ts @@ -87,17 +87,13 @@ export class SinglyLinkedList { return singlyLinkedList; } - getLength(): number { - return this._length; - } - /** - * The `push` function adds a new node with the given data to the end of a singly linked list. - * @param {E} data - The "data" parameter represents the value that you want to add to the linked list. It can be of + * The `push` function adds a new node with the given val to the end of a singly linked list. + * @param {E} val - The "val" parameter represents the value that you want to add to the linked list. It can be of * any type (E) as specified in the generic type declaration of the class or function. */ - push(data: E): void { - const newNode = new SinglyLinkedListNode(data); + push(val: E): void { + const newNode = new SinglyLinkedListNode(val); if (!this.head) { this.head = newNode; this.tail = newNode; @@ -108,6 +104,15 @@ export class SinglyLinkedList { this._length++; } + /** + * The `push` function adds a new node with the given val to the end of a singly linked list. + * @param {E} val - The "val" parameter represents the value that you want to add to the linked list. It can be of + * any type (E) as specified in the generic type declaration of the class or function. + */ + addLast(val: E): void { + this.push(val); + } + /** * The `pop()` function removes and returns the value of the last element in a linked list, updating the head and tail * pointers accordingly. @@ -135,6 +140,16 @@ export class SinglyLinkedList { return val; } + /** + * The `popLast()` function removes and returns the value of the last element in a linked list, updating the head and tail + * pointers accordingly. + * @returns The method `pop()` returns the value of the node that is being removed from the end of the linked list. If + * the linked list is empty, it returns `null`. + */ + popLast(): E | undefined { + return this.pop(); + } + /** * The `shift()` function removes and returns the value of the first node in a linked list. * @returns The value of the node that is being removed from the beginning of the linked list. @@ -147,6 +162,14 @@ export class SinglyLinkedList { return removedNode.val; } + /** + * The `popFirst()` function removes and returns the value of the first node in a linked list. + * @returns The value of the node that is being removed from the beginning of the linked list. + */ + popFirst(): E | undefined { + return this.shift(); + } + /** * The unshift function adds a new node with the given value to the beginning of a singly linked list. * @param {E} val - The parameter "val" represents the value of the new node that will be added to the beginning of the @@ -164,6 +187,15 @@ export class SinglyLinkedList { this._length++; } + /** + * The addFirst function adds a new node with the given value to the beginning of a singly linked list. + * @param {E} val - The parameter "val" represents the value of the new node that will be added to the beginning of the + * linked list. + */ + addFirst(val: E): void { + this.unshift(val); + } + /** * The function `getAt` returns the value at a specified index in a linked list, or null if the index is out of range. * @param {number} index - The index parameter is a number that represents the position of the element we want to @@ -382,7 +414,7 @@ export class SinglyLinkedList { * @returns a `SinglyLinkedListNode` if a node with the specified value is found in the linked list. If no node with * the specified value is found, the function returns `null`. */ - findNode(value: E): SinglyLinkedListNode | null { + getNode(value: E): SinglyLinkedListNode | null { let current = this.head; while (current) { @@ -432,9 +464,6 @@ export class SinglyLinkedList { return false; } - insertAfter(existingValueOrNode: E, newValue: E): boolean; - insertAfter(existingValueOrNode: SinglyLinkedListNode, newValue: E): boolean; - /** * The `insertAfter` function inserts a new node with a given value after an existing node in a singly linked list. * @param {E | SinglyLinkedListNode} existingValueOrNode - The existing value or node in the linked list after which @@ -449,7 +478,7 @@ export class SinglyLinkedList { if (existingValueOrNode instanceof SinglyLinkedListNode) { existingNode = existingValueOrNode; } else { - existingNode = this.findNode(existingValueOrNode); + existingNode = this.getNode(existingValueOrNode); } if (existingNode) { @@ -485,7 +514,80 @@ export class SinglyLinkedList { return count; } - *[Symbol.iterator]() { + /** + * The `forEach` function iterates over each element in a linked list and applies a callback function to each element. + * @param callback - The callback parameter is a function that takes two arguments: val and index. The val argument + * represents the value of the current node in the linked list, and the index argument represents the index of the + * current node in the linked list. + */ + forEach(callback: (val: E, index: number) => void): void { + let current = this.head; + let index = 0; + while (current) { + callback(current.val, index); + current = current.next; + index++; + } + } + + /** + * The `map` function takes a callback function and applies it to each element in the SinglyLinkedList, returning a new + * SinglyLinkedList with the transformed values. + * @param callback - The callback parameter is a function that takes a value of type E (the type of values stored in + * the original SinglyLinkedList) and returns a value of type U (the type of values that will be stored in the mapped + * SinglyLinkedList). + * @returns The `map` function is returning a new instance of `SinglyLinkedList` that contains the mapped values. + */ + map(callback: (val: E) => U): SinglyLinkedList { + const mappedList = new SinglyLinkedList(); + let current = this.head; + while (current) { + mappedList.push(callback(current.val)); + current = current.next; + } + return mappedList; + } + + /** + * The `filter` function iterates through a SinglyLinkedList and returns a new SinglyLinkedList containing only the + * elements that satisfy the given callback function. + * @param callback - The `callback` parameter is a function that takes a value of type `E` and returns a boolean value. + * It is used to determine whether a value should be included in the filtered list or not. + * @returns The filtered list, which is an instance of the SinglyLinkedList class. + */ + filter(callback: (val: E) => boolean): SinglyLinkedList { + const filteredList = new SinglyLinkedList(); + let current = this.head; + while (current) { + if (callback(current.val)) { + filteredList.push(current.val); + } + current = current.next; + } + return filteredList; + } + + /** + * The `reduce` function iterates over a linked list and applies a callback function to each element, accumulating a + * single value. + * @param callback - The `callback` parameter is a function that takes two arguments: `accumulator` and `val`. It is + * used to perform a specific operation on each element of the linked list. + * @param {U} initialValue - The `initialValue` parameter is the initial value of the accumulator. It is the starting + * point for the reduction operation. + * @returns The `reduce` method is returning the final value of the accumulator after iterating through all the + * elements in the linked list. + */ + reduce(callback: (accumulator: U, val: E) => U, initialValue: U): U { + let accumulator = initialValue; + let current = this.head; + while (current) { + accumulator = callback(accumulator, current.val); + current = current.next; + } + return accumulator; + } + + * [Symbol.iterator]() { let current = this.head; while (current) { diff --git a/src/data-structures/queue/deque.ts b/src/data-structures/queue/deque.ts index 3290ab1..8d6490a 100644 --- a/src/data-structures/queue/deque.ts +++ b/src/data-structures/queue/deque.ts @@ -95,12 +95,12 @@ export class ObjectDeque { } /** - * The function `pollFirst()` removes and returns the first element in a data structure. + * The function `popFirst()` removes and returns the first element in a data structure. * @returns The value of the first element in the data structure. */ - pollFirst() { + popFirst() { if (!this._size) return; - const value = this.peekFirst(); + const value = this.getFirst(); delete this._nodes[this._first]; this._first++; this._size--; @@ -108,20 +108,20 @@ export class ObjectDeque { } /** - * The `peekFirst` function returns the first element in an array-like data structure if it exists. + * The `getFirst` function returns the first element in an array-like data structure if it exists. * @returns The element at the first position of the `_nodes` array. */ - peekFirst() { + getFirst() { if (this._size) return this._nodes[this._first]; } /** - * The `pollLast()` function removes and returns the last element in a data structure. + * The `popLast()` function removes and returns the last element in a data structure. * @returns The value that was removed from the data structure. */ - pollLast() { + popLast() { if (!this._size) return; - const value = this.peekLast(); + const value = this.getLast(); delete this._nodes[this._last]; this._last--; this._size--; @@ -130,10 +130,10 @@ export class ObjectDeque { } /** - * The `peekLast()` function returns the last element in an array-like data structure. + * The `getLast()` function returns the last element in an array-like data structure. * @returns The last element in the array "_nodes" is being returned. */ - peekLast() { + getLast() { if (this._size) return this._nodes[this._last]; } @@ -188,19 +188,19 @@ export class ArrayDeque { } /** - * The function "pollLast" returns and removes the last element from an array, or returns null if the array is empty. - * @returns The method `pollLast()` returns the last element of the `_nodes` array, or `null` if the array is empty. + * The function "popLast" returns and removes the last element from an array, or returns null if the array is empty. + * @returns The method `popLast()` returns the last element of the `_nodes` array, or `null` if the array is empty. */ - pollLast(): E | null { + popLast(): E | null { return this._nodes.pop() ?? null; } /** - * The `pollFirst` function removes and returns the first element from an array, or returns null if the array is empty. - * @returns The `pollFirst()` function returns the first element of the `_nodes` array, or `null` if the array is + * The `popFirst` function removes and returns the first element from an array, or returns null if the array is empty. + * @returns The `popFirst()` function returns the first element of the `_nodes` array, or `null` if the array is * empty. */ - pollFirst(): E | null { + popFirst(): E | null { return this._nodes.shift() ?? null; } @@ -219,19 +219,19 @@ export class ArrayDeque { } /** - * The `peekFirst` function returns the first element of an array or null if the array is empty. - * @returns The function `peekFirst()` is returning the first element (`E`) of the `_nodes` array. If the array is + * The `getFirst` function returns the first element of an array or null if the array is empty. + * @returns The function `getFirst()` is returning the first element (`E`) of the `_nodes` array. If the array is * empty, it will return `null`. */ - peekFirst(): E | null { + getFirst(): E | null { return this._nodes[0] ?? null; } /** - * The `peekLast` function returns the last element of an array or null if the array is empty. - * @returns The method `peekLast()` returns the last element of the `_nodes` array, or `null` if the array is empty. + * The `getLast` function returns the last element of an array or null if the array is empty. + * @returns The method `getLast()` returns the last element of the `_nodes` array, or `null` if the array is empty. */ - peekLast(): E | null { + getLast(): E | null { return this._nodes[this._nodes.length - 1] ?? null; } diff --git a/src/data-structures/queue/queue.ts b/src/data-structures/queue/queue.ts index 4549b31..0f9e1a2 100644 --- a/src/data-structures/queue/queue.ts +++ b/src/data-structures/queue/queue.ts @@ -123,11 +123,11 @@ export class Queue { } /** - * The `peekLast` function returns the last element in an array-like data structure, or null 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 + * The `getLast` function returns the last element in an array-like data structure, or null if the structure is empty. + * @returns The method `getLast()` returns the last element of the `_nodes` array if the array is not empty. If the * array is empty, it returns `null`. */ - peekLast(): E | undefined { + getLast(): E | undefined { return this.size > 0 ? this.nodes[this.nodes.length - 1] : undefined; } diff --git a/test/unit/data-structures/linked-list/doubly-linked-list.test.ts b/test/unit/data-structures/linked-list/doubly-linked-list.test.ts index eab2ad5..c20880a 100644 --- a/test/unit/data-structures/linked-list/doubly-linked-list.test.ts +++ b/test/unit/data-structures/linked-list/doubly-linked-list.test.ts @@ -109,7 +109,7 @@ describe('DoublyLinkedList Operation Test', () => { list.reverse(); expect(list.toArray()).toEqual([3, 2, 1]); - expect(list.toArrayReverse()).toEqual([1, 2, 3]); + expect(list.toArrayBackward()).toEqual([1, 2, 3]); }); it('should map elements using a callback function', () => { @@ -189,7 +189,7 @@ describe('DoublyLinkedList Operation Test', () => { list.push(3); list.push(4); - const lastEven = list.findLast(val => val % 2 === 0); + const lastEven = list.findBackward(val => val % 2 === 0); expect(lastEven).toBe(4); }); @@ -211,7 +211,7 @@ describe('DoublyLinkedList Operation Test', () => { list.push(2); list.push(3); - const reversedArray = list.toArrayReverse(); + const reversedArray = list.toArrayBackward(); expect(reversedArray).toEqual([3, 2, 1]); }); @@ -327,8 +327,8 @@ describe('DoublyLinkedList Operation Test', () => { const insertSuccess = objectList.insertBefore(obj2, newObj); expect(insertSuccess).toBe(true); - const findNode = objectList.findNode(newObj); // Use newObj instead of obj2 - expect(findNode?.val).toEqual(newObj); + const getNode = objectList.getNode(newObj); // Use newObj instead of obj2 + expect(getNode?.val).toEqual(newObj); const deleted = objectList.delete(newObj); // Use newObj instead of obj2 expect(deleted).toBe(true); diff --git a/test/unit/data-structures/linked-list/linked-list.test.ts b/test/unit/data-structures/linked-list/linked-list.test.ts index d7178f1..91b27fc 100644 --- a/test/unit/data-structures/linked-list/linked-list.test.ts +++ b/test/unit/data-structures/linked-list/linked-list.test.ts @@ -11,7 +11,7 @@ describe('LinkedList Performance Test', () => { for (let i = 0; i < magnitude.SQUARED; i++) { doublyList.push(i); if (i === midIndex) { - midNode = doublyList.findNode(i); + midNode = doublyList.getNode(i); } else if (i > midIndex && midNode) { doublyList.insertBefore(midNode, i); } @@ -24,7 +24,7 @@ describe('LinkedList Performance Test', () => { for (let i = 0; i < magnitude.SQUARED; i++) { singlyList.push(i); if (i === midIndex) { - midSinglyNode = singlyList.findNode(i); + midSinglyNode = singlyList.getNode(i); } else if (i > midIndex && midSinglyNode) { singlyList.insertBefore(midSinglyNode.val, i); } diff --git a/test/unit/data-structures/linked-list/singly-linked-list.test.ts b/test/unit/data-structures/linked-list/singly-linked-list.test.ts index 108f9ec..2c4cbe3 100644 --- a/test/unit/data-structures/linked-list/singly-linked-list.test.ts +++ b/test/unit/data-structures/linked-list/singly-linked-list.test.ts @@ -362,8 +362,8 @@ describe('SinglyLinkedList Operation Test', () => { const insertSuccess = objectList.insertBefore(obj2, newObj); expect(insertSuccess).toBe(true); - const findNode = objectList.findNode(newObj); // Use newObj instead of obj2 - expect(findNode?.val).toEqual(newObj); + const getNode = objectList.getNode(newObj); // Use newObj instead of obj2 + expect(getNode?.val).toEqual(newObj); const deleted = objectList.delete(newObj); // Use newObj instead of obj2 expect(deleted).toBe(true); diff --git a/test/unit/data-structures/queue/deque.test.ts b/test/unit/data-structures/queue/deque.test.ts index bc89ebf..e8cd139 100644 --- a/test/unit/data-structures/queue/deque.test.ts +++ b/test/unit/data-structures/queue/deque.test.ts @@ -15,20 +15,20 @@ describe('Deque Tests', () => { it('should add elements at the beginning and end', () => { deque.addFirst(1); deque.addLast(2); - expect(deque.peekFirst()).toBe(1); - expect(deque.peekLast()).toBe(2); + expect(deque.getFirst()).toBe(1); + expect(deque.getLast()).toBe(2); }); it('should delete elements from the beginning and end', () => { deque.addFirst(1); deque.addLast(2); - deque.pollFirst(); - deque.pollLast(); + deque.popFirst(); + deque.popLast(); expect(deque.isEmpty()).toBe(true); }); it('should handle edge case when removing from an empty deque', () => { - const result = deque.pollFirst(); + const result = deque.popFirst(); expect(result).toBeUndefined(); }); @@ -40,18 +40,18 @@ describe('Deque Tests', () => { it('should handle adding and removing elements alternately', () => { deque.addFirst(1); - expect(deque.pollFirst()).toBe(1); + expect(deque.popFirst()).toBe(1); deque.addLast(2); - expect(deque.pollLast()).toBe(2); + expect(deque.popLast()).toBe(2); expect(deque.isEmpty()).toBe(true); }); it('should handle adding and removing elements in a cyclic manner', () => { deque.addFirst(1); deque.addLast(2); - expect(deque.pollFirst()).toBe(1); + expect(deque.popFirst()).toBe(1); deque.addFirst(3); - expect(deque.pollLast()).toBe(2); + expect(deque.popLast()).toBe(2); expect(deque.size).toBe(1); }); // Add more test cases as needed @@ -68,20 +68,20 @@ describe('Deque Tests', () => { it('should add elements at the beginning and end', () => { objectDeque.addFirst('one'); objectDeque.addLast('two'); - expect(objectDeque.peekFirst()).toBe('one'); - expect(objectDeque.peekLast()).toBe('two'); + expect(objectDeque.getFirst()).toBe('one'); + expect(objectDeque.getLast()).toBe('two'); }); it('should delete elements from the beginning and end', () => { objectDeque.addFirst('one'); objectDeque.addLast('two'); - objectDeque.pollFirst(); - objectDeque.pollLast(); + objectDeque.popFirst(); + objectDeque.popLast(); expect(objectDeque.isEmpty()).toBe(true); }); it('should handle edge case when removing from an empty deque', () => { - const result = objectDeque.pollFirst(); + const result = objectDeque.popFirst(); expect(result).toBeUndefined(); }); @@ -105,20 +105,20 @@ describe('Deque Tests', () => { it('should add elements at the beginning and end', () => { arrayDeque.addFirst(1); arrayDeque.addLast(2); - expect(arrayDeque.peekFirst()).toBe(1); - expect(arrayDeque.peekLast()).toBe(2); + expect(arrayDeque.getFirst()).toBe(1); + expect(arrayDeque.getLast()).toBe(2); }); it('should delete elements from the beginning and end', () => { arrayDeque.addFirst(1); arrayDeque.addLast(2); - arrayDeque.pollFirst(); - arrayDeque.pollLast(); + arrayDeque.popFirst(); + arrayDeque.popLast(); expect(arrayDeque.isEmpty()).toBe(true); }); it('should handle edge case when removing from an empty deque', () => { - const result = arrayDeque.pollFirst(); + const result = arrayDeque.popFirst(); expect(result).toBeNull(); }); @@ -165,16 +165,16 @@ describe('Deque', () => { deque.addLast(2); expect(deque.size).toBe(2); - expect(deque.peekFirst()).toBe(1); - expect(deque.peekLast()).toBe(2); + expect(deque.getFirst()).toBe(1); + expect(deque.getLast()).toBe(2); }); test('should remove elements from the front and back', () => { deque.addFirst(1); deque.addLast(2); - const firstElement = deque.pollFirst(); - const lastElement = deque.pollLast(); + const firstElement = deque.popFirst(); + const lastElement = deque.popLast(); expect(deque.size).toBe(0); expect(firstElement).toBe(1); @@ -203,7 +203,7 @@ describe('Deque', () => { deque.addLast(1); expect(deque.isEmpty()).toBe(false); - deque.pollFirst(); + deque.popFirst(); expect(deque.isEmpty()).toBe(true); }); }); @@ -225,16 +225,16 @@ describe('ArrayDeque', () => { deque.addLast(2); expect(deque.size).toBe(2); - expect(deque.peekFirst()).toBe(1); - expect(deque.peekLast()).toBe(2); + expect(deque.getFirst()).toBe(1); + expect(deque.getLast()).toBe(2); }); test('should remove elements from the front and back', () => { deque.addFirst(1); deque.addLast(2); - const firstElement = deque.pollFirst(); - const lastElement = deque.pollLast(); + const firstElement = deque.popFirst(); + const lastElement = deque.popLast(); expect(deque.size).toBe(0); expect(firstElement).toBe(1); @@ -263,7 +263,7 @@ describe('ArrayDeque', () => { deque.addLast(1); expect(deque.isEmpty()).toBe(false); - deque.pollFirst(); + deque.popFirst(); expect(deque.isEmpty()).toBe(true); }); @@ -319,8 +319,8 @@ describe('ObjectDeque', () => { deque.addFirst(2); expect(deque.size).toBe(2); - expect(deque.peekFirst()).toBe(2); - expect(deque.peekLast()).toBe(1); + expect(deque.getFirst()).toBe(2); + expect(deque.getLast()).toBe(1); }); test('should add elements to the end of the deque', () => { @@ -328,37 +328,37 @@ describe('ObjectDeque', () => { deque.addLast(2); expect(deque.size).toBe(2); - expect(deque.peekFirst()).toBe(1); - expect(deque.peekLast()).toBe(2); + expect(deque.getFirst()).toBe(1); + expect(deque.getLast()).toBe(2); }); test('should remove elements from the front of the deque', () => { deque.addLast(1); deque.addLast(2); - const removedElement = deque.pollFirst(); + const removedElement = deque.popFirst(); expect(deque.size).toBe(1); expect(removedElement).toBe(1); - expect(deque.peekFirst()).toBe(2); + expect(deque.getFirst()).toBe(2); }); test('should remove elements from the end of the deque', () => { deque.addLast(1); deque.addLast(2); - const removedElement = deque.pollFirst(); + const removedElement = deque.popFirst(); expect(deque.size).toBe(1); expect(removedElement).toBe(1); - expect(deque.peekLast()).toBe(2); + expect(deque.getLast()).toBe(2); }); test('should return the element at the front of the deque without removing it', () => { deque.addFirst(1); deque.addFirst(2); - expect(deque.peekFirst()).toBe(2); + expect(deque.getFirst()).toBe(2); expect(deque.size).toBe(2); }); @@ -366,7 +366,7 @@ describe('ObjectDeque', () => { deque.addLast(1); deque.addLast(2); - expect(deque.peekLast()).toBe(2); + expect(deque.getLast()).toBe(2); expect(deque.size).toBe(2); }); @@ -391,9 +391,9 @@ describe('ObjectDeque', () => { deque.addLast(2); deque.addLast(3); - expect(deque.peekFirst()).toBe(1); + expect(deque.getFirst()).toBe(1); expect(deque.get(1)).toBe(2); - expect(deque.peekLast()).toBe(3); + expect(deque.getLast()).toBe(3); }); test('should insert elements at a specific index', () => { @@ -402,9 +402,9 @@ describe('ObjectDeque', () => { deque.addLast(3); expect(deque.size).toBe(3); - expect(deque.peekFirst()).toBe(1); + expect(deque.getFirst()).toBe(1); expect(deque.get(1)).toBe(2); expect(deque.get(2)).toBe(3); - expect(deque.peekLast()).toBe(3); + expect(deque.getLast()).toBe(3); }); }); diff --git a/test/unit/data-structures/queue/queue.test.ts b/test/unit/data-structures/queue/queue.test.ts index a32e811..9e2a263 100644 --- a/test/unit/data-structures/queue/queue.test.ts +++ b/test/unit/data-structures/queue/queue.test.ts @@ -86,7 +86,7 @@ describe('Queue', () => { queue.push(2); expect(queue.size).toBe(2); expect(queue.peek()).toBe(1); - expect(queue.peekLast()).toBe(2); + expect(queue.getLast()).toBe(2); }); it('should shift elements from the front of the queue', () => { @@ -96,7 +96,7 @@ describe('Queue', () => { expect(shifted).toBe(1); expect(queue.size).toBe(1); expect(queue.peek()).toBe(2); - expect(queue.peekLast()).toBe(2); + expect(queue.getLast()).toBe(2); }); it('should handle shifting when queue reaches half size', () => { @@ -117,7 +117,7 @@ describe('Queue', () => { queue.push(1); queue.push(2); expect(queue.peek()).toBe(1); - expect(queue.peekLast()).toBe(2); + expect(queue.getLast()).toBe(2); }); it('should handle shifting when the queue is empty', () => { @@ -129,7 +129,7 @@ describe('Queue', () => { it('should handle peeking when the queue is empty', () => { expect(queue.peek()).toBeUndefined(); - expect(queue.peekLast()).toBeUndefined(); + expect(queue.getLast()).toBeUndefined(); }); it('should handle clearing the queue', () => { @@ -139,7 +139,7 @@ describe('Queue', () => { queue.clear(); expect(queue.size).toBe(0); expect(queue.peek()).toBeUndefined(); - expect(queue.peekLast()).toBeUndefined(); + expect(queue.getLast()).toBeUndefined(); }); it('should clone the queue', () => { @@ -149,7 +149,7 @@ describe('Queue', () => { const clonedQueue = queue.clone(); expect(clonedQueue.size).toBe(3); expect(clonedQueue.peek()).toBe(1); - expect(clonedQueue.peekLast()).toBe(3); + expect(clonedQueue.getLast()).toBe(3); }); it('should handle creating a queue from an array', () => { @@ -157,7 +157,7 @@ describe('Queue', () => { const newQueue = Queue.fromArray(elements); expect(newQueue.size).toBe(5); expect(newQueue.peek()).toBe(1); - expect(newQueue.peekLast()).toBe(5); + expect(newQueue.getLast()).toBe(5); }); it('should iterate through the queue', () => { From f87e682f26b5895d8d2e2bd7b0e4eb2a724e8752 Mon Sep 17 00:00:00 2001 From: Revone Date: Sun, 29 Oct 2023 21:52:27 +0800 Subject: [PATCH 35/46] [test] test coverage enriched to 90.37% --- .dependency-cruiser.js | 5 -- .gitignore | 1 + .npmignore | 2 +- package-lock.json | 62 ++++++++--------- package.json | 2 +- src/data-structures/binary-tree/avl-tree.ts | 5 +- .../binary-tree/binary-indexed-tree.ts | 2 +- .../binary-tree/binary-tree.ts | 52 ++++++++++++-- src/data-structures/binary-tree/bst.ts | 3 +- src/data-structures/binary-tree/rb-tree.ts | 3 +- .../binary-tree/tree-multiset.ts | 3 +- src/data-structures/graph/abstract-graph.ts | 21 +++--- src/data-structures/graph/directed-graph.ts | 3 +- src/data-structures/graph/undirected-graph.ts | 9 ++- src/data-structures/hash/hash-map.ts | 2 +- src/data-structures/hash/tree-map.ts | 3 +- src/data-structures/hash/tree-set.ts | 3 +- src/data-structures/heap/heap.ts | 4 +- src/data-structures/heap/max-heap.ts | 2 +- src/data-structures/heap/min-heap.ts | 2 +- .../linked-list/doubly-linked-list.ts | 3 + .../linked-list/singly-linked-list.ts | 3 + src/data-structures/matrix/matrix.ts | 2 +- src/data-structures/matrix/vector2d.ts | 3 +- .../priority-queue/max-priority-queue.ts | 2 +- .../priority-queue/min-priority-queue.ts | 2 +- .../priority-queue/priority-queue.ts | 2 +- src/data-structures/queue/deque.ts | 9 +-- src/data-structures/queue/queue.ts | 2 +- src/types/data-structures/matrix/navigator.ts | 2 +- src/types/utils/utils.ts | 2 +- src/types/utils/validate-type.ts | 4 +- test/integration/bst.test.ts | 2 +- .../binary-tree/avl-tree.test.ts | 2 +- .../binary-tree/binary-tree.test.ts | 26 ++++++- .../data-structures/binary-tree/bst.test.ts | 12 ++-- .../binary-tree/overall.test.ts | 2 +- .../binary-tree/tree-multiset.test.ts | 4 +- .../hash/coordinate-map.test.ts | 20 ++++++ .../hash/coordinate-set.test.ts | 25 +++++++ .../data-structures/hash/hash-table.test.ts | 4 +- test/unit/data-structures/heap/heap.test.ts | 4 +- .../linked-list/doubly-linked-list.test.ts | 67 +++++++++++++++++- .../linked-list/singly-linked-list.test.ts | 69 ++++++++++++++++--- .../priority-queue/max-priority-queue.test.ts | 4 +- test/utils/big-o.ts | 2 +- webpack.config.js | 28 -------- 47 files changed, 343 insertions(+), 153 deletions(-) delete mode 100644 webpack.config.js diff --git a/.dependency-cruiser.js b/.dependency-cruiser.js index 21b641c..78e5afc 100644 --- a/.dependency-cruiser.js +++ b/.dependency-cruiser.js @@ -273,11 +273,6 @@ module.exports = { your webpack config is a function and takes them (see webpack documentation for details) */ - // webpackConfig: { - // fileName: './webpack.config.js', - // env: {}, - // arguments: {}, - // }, /* Babel config ('.babelrc', '.babelrc.json', '.babelrc.json5', ...) to use for compilation (and whatever other naughty things babel plugins do to diff --git a/.gitignore b/.gitignore index d114687..a794ac0 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ npm-debug.* *.orig.* .DS_Store .idea +.vscode /notes /backup diff --git a/.npmignore b/.npmignore index 59bab7d..5c0a61c 100644 --- a/.npmignore +++ b/.npmignore @@ -1,4 +1,5 @@ .idea +.vscode .auto-changelog .auto-changelog-template.hbs .dependency-cruiser.js @@ -9,7 +10,6 @@ /notes /backup -/webpack.config.js /scripts /tsconfig.prod.json diff --git a/package-lock.json b/package-lock.json index 79cc7ab..e691959 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1045,9 +1045,9 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.9.1.tgz", - "integrity": "sha512-Y27x+MBLjXa+0JWDhykM3+JE+il3kHKAEqabfEWq3SDhZjLYb6/BHL/JKFnH3fe207JaXkyDo685Oc2Glt6ifA==", + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" @@ -2021,12 +2021,12 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.8.8", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.8.tgz", - "integrity": "sha512-YRsdVxq6OaLfmR9Hy816IMp33xOBjfyOgUd77ehqg96CFywxAPbDbXvAsuN2KVg2HOT8Eh6uAfU+l4WffwPVrQ==", + "version": "20.8.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.9.tgz", + "integrity": "sha512-UzykFsT3FhHb1h7yD4CA4YhBHq545JC0YnEz41xkipN88eKQtL6rSgocL5tbAP6Ola9Izm/Aw4Ora8He4x0BHg==", "dev": true, "dependencies": { - "undici-types": "~5.25.1" + "undici-types": "~5.26.4" } }, "node_modules/@types/semver": { @@ -2728,9 +2728,9 @@ } }, "node_modules/avl-tree-typed": { - "version": "1.39.0", - "resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.39.0.tgz", - "integrity": "sha512-YpYfpO0slt8R5lcy4wrz7inKFAG1NKUZk2FnJ2FEYIdBJaBIUvW0cflx6Cuuy1iRiXbazpTqGQgKC0nERWUiow==", + "version": "1.39.1", + "resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.39.1.tgz", + "integrity": "sha512-V4H5cBue8qzsUYzDIngPR6FJELuuMtwYSk34BdpgwPHpo79ZL0LqJmEiIY9FCmkoYPQFvZAz/Z7+RH9MJXgZPA==", "dev": true, "dependencies": { "data-structure-typed": "^1.39.0" @@ -2927,9 +2927,9 @@ } }, "node_modules/binary-tree-typed": { - "version": "1.39.0", - "resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.39.0.tgz", - "integrity": "sha512-oJzCbrs+l4qacscxFvVB/ielr22KiO8z/bWSx/tJmafpinWmkAuQIBRGqo+frfFi8MKstNerHPEF+4yT8AakUA==", + "version": "1.39.1", + "resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.39.1.tgz", + "integrity": "sha512-fbPwGQXmy9GKw/23yRm9c+9wDNgXbhvGUP6za0NQuo3kvJ522SAEzvgwPXEqO92RIKT/OpP0+aO5dpTJaOiodQ==", "dev": true, "dependencies": { "data-structure-typed": "^1.39.0" @@ -3011,9 +3011,9 @@ } }, "node_modules/bst-typed": { - "version": "1.39.0", - "resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.39.0.tgz", - "integrity": "sha512-AvitIe0j8jPrXyZkQI5zhTYIc4eS5rxvW59/0YHymg54BeMs+zm1WzouPhsh7qp9D+IcTpQmqDY0kjc07Tic3w==", + "version": "1.39.1", + "resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.39.1.tgz", + "integrity": "sha512-Oo86lN3GJIODrGHZSpNJZ7X1N1adgEpY8kd7jOvZd+zF2BHEJVpW8uTk3PtSgbCLGnEkSzE2lXWaaOZh5F9x1A==", "dev": true, "dependencies": { "data-structure-typed": "^1.39.0" @@ -3082,9 +3082,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001554", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001554.tgz", - "integrity": "sha512-A2E3U//MBwbJVzebddm1YfNp7Nud5Ip+IPn4BozBmn4KqVX7AvluoIDFWjsv5OkGnKUXQVmMSoMKLa3ScCblcQ==", + "version": "1.0.30001557", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001557.tgz", + "integrity": "sha512-91oR7hLNUP3gG6MLU+n96em322a8Xzes8wWdBKhLgUoiJsAF5irZnxSUCbc+qUZXNnPCfUwLOi9ZCZpkvjQajw==", "dev": true, "funding": [ { @@ -3413,9 +3413,9 @@ } }, "node_modules/data-structure-typed": { - "version": "1.39.0", - "resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.39.0.tgz", - "integrity": "sha512-HESmI/a+uE3ELRDVKIBSmfgSMep4ETJco8jeZD2By5lNhMW9HDZE+SGNqlSeBJd3PdJyact9dWlXWwg7S3+ztQ==", + "version": "1.39.1", + "resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.39.1.tgz", + "integrity": "sha512-zAotqpGJoWKG12b4pybA05oih3RAy50RlD++ye8M58AjcM5Aw8lZjWlsNmi+ICiAdq8P0xdJM6Z7/etysctJZg==", "dev": true }, "node_modules/debug": { @@ -3598,9 +3598,9 @@ "dev": true }, "node_modules/electron-to-chromium": { - "version": "1.4.566", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.566.tgz", - "integrity": "sha512-mv+fAy27uOmTVlUULy15U3DVJ+jg+8iyKH1bpwboCRhtDC69GKf1PPTZvEIhCyDr81RFqfxZJYrbgp933a1vtg==", + "version": "1.4.569", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.569.tgz", + "integrity": "sha512-LsrJjZ0IbVy12ApW3gpYpcmHS3iRxH4bkKOW98y1/D+3cvDUWGcbzbsFinfUS8knpcZk/PG/2p/RnkMCYN7PVg==", "dev": true }, "node_modules/emittery": { @@ -4771,9 +4771,9 @@ } }, "node_modules/heap-typed": { - "version": "1.39.0", - "resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.39.0.tgz", - "integrity": "sha512-n9Qa+Ph6nnqRN6lz52R62CHrpgWixU/39P22WT9Epf+4dj+pDYPKEGekCCidjjxQXgoR56d6XjnZWFgiQYYN4Q==", + "version": "1.39.1", + "resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.39.1.tgz", + "integrity": "sha512-+fKr3EKYNGLK9ZVLeZZFP58eKvGv/zWGYbBOZYIXkQZeBXtdL0b4rHL0LsoIpuyPMbhXDFNOhaasG4D1NbCu2Q==", "dev": true, "dependencies": { "data-structure-typed": "^1.39.0" @@ -8915,9 +8915,9 @@ } }, "node_modules/undici-types": { - "version": "5.25.3", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.25.3.tgz", - "integrity": "sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA==", + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "dev": true }, "node_modules/update-browserslist-db": { diff --git a/package.json b/package.json index 2fd7f9f..beca064 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "data-structure-typed", - "version": "1.39.1", + "version": "1.39.2", "description": "Data Structures of Javascript & TypeScript. Binary Tree, BST, Graph, Heap, Priority Queue, Linked List, Queue, Deque, Stack, AVL Tree, Tree Multiset, Trie, Directed Graph, Undirected Graph, Singly Linked List, Doubly Linked List, Max Heap, Max Priority Queue, Min Heap, Min Priority Queue.", "main": "dist/cjs/index.js", "module": "dist/mjs/index.js", diff --git a/src/data-structures/binary-tree/avl-tree.ts b/src/data-structures/binary-tree/avl-tree.ts index 47eb26f..2db0487 100644 --- a/src/data-structures/binary-tree/avl-tree.ts +++ b/src/data-structures/binary-tree/avl-tree.ts @@ -21,8 +21,7 @@ export class AVLTreeNode = AVLTreeNodeNeste export class AVLTree = AVLTreeNode>> extends BST - implements IBinaryTree -{ + implements IBinaryTree { /** * This is a constructor function for an AVL tree data structure in TypeScript. * @param {AVLTreeOptions} [options] - The `options` parameter is an optional object that can be passed to the @@ -161,7 +160,7 @@ export class AVLTree = AVLTreeNode = BinaryTree * @template N - The type of the binary tree's nodes. */ export class BinaryTree = BinaryTreeNode>> - implements IBinaryTree -{ + implements IBinaryTree { /** * Creates a new instance of BinaryTree. * @param {BinaryTreeOptions} [options] - The options for the binary tree. @@ -395,7 +394,7 @@ export class BinaryTree = BinaryTreeNode return -1; } - const stack: {node: N; depth: number}[] = [{node: beginRoot, depth: 0}]; + const stack: { node: N; depth: number }[] = [{node: beginRoot, depth: 0}]; let maxHeight = 0; while (stack.length > 0) { @@ -832,7 +831,7 @@ export class BinaryTree = BinaryTreeNode _traverse(beginRoot); } else { // 0: visit, 1: print - const stack: {opt: 0 | 1; node: N | null | undefined}[] = [{opt: 0, node: beginRoot}]; + const stack: { opt: 0 | 1; node: N | null | undefined }[] = [{opt: 0, node: beginRoot}]; while (stack.length > 0) { const cur = stack.pop(); @@ -1093,6 +1092,49 @@ export class BinaryTree = BinaryTreeNode return ans; } + /** + * The above function is an iterator for a binary tree that can be used to traverse the tree in + * either an iterative or recursive manner. + * @param node - The `node` parameter represents the current node in the binary tree from which the + * iteration starts. It is an optional parameter with a default value of `this.root`, which means + * that if no node is provided, the iteration will start from the root of the binary tree. + * @returns The `*[Symbol.iterator]` method returns a generator object that yields the keys of the + * binary tree nodes in a specific order. + */ + * [Symbol.iterator](node = this.root): Generator { + if (!node) { + return; + } + + if (this.iterationType === IterationType.ITERATIVE) { + const stack: (N | null | undefined)[] = []; + let current: N | null | undefined = node; + + while (current || stack.length > 0) { + while (current) { + stack.push(current); + current = current.left; + } + + current = stack.pop(); + + if (current) yield current.key; + if (current) current = current.right; + } + } else { + + if (node.left) { + yield* this[Symbol.iterator](node.left); + } + yield node.key; + if (node.right) { + yield* this[Symbol.iterator](node.right); + } + } + + } + + /** * Swap the data of two nodes in the binary tree. * @param {N} srcNode - The source node to swap. diff --git a/src/data-structures/binary-tree/bst.ts b/src/data-structures/binary-tree/bst.ts index 8b74002..ce4751d 100644 --- a/src/data-structures/binary-tree/bst.ts +++ b/src/data-structures/binary-tree/bst.ts @@ -19,8 +19,7 @@ export class BSTNode = BSTNodeNested> extend export class BST = BSTNode>> extends BinaryTree - implements IBinaryTree -{ + implements IBinaryTree { /** * The constructor function initializes a binary search tree object with an optional comparator * function. diff --git a/src/data-structures/binary-tree/rb-tree.ts b/src/data-structures/binary-tree/rb-tree.ts index c4ad717..45c363b 100644 --- a/src/data-structures/binary-tree/rb-tree.ts +++ b/src/data-structures/binary-tree/rb-tree.ts @@ -21,8 +21,7 @@ export class RBTreeNode = RBTreeNodeNested = RBTreeNode>> extends BST - implements IBinaryTree -{ + implements IBinaryTree { constructor(options?: RBTreeOptions) { super(options); } diff --git a/src/data-structures/binary-tree/tree-multiset.ts b/src/data-structures/binary-tree/tree-multiset.ts index 0dab37e..1cd5e49 100644 --- a/src/data-structures/binary-tree/tree-multiset.ts +++ b/src/data-structures/binary-tree/tree-multiset.ts @@ -37,8 +37,7 @@ export class TreeMultisetNode< */ export class TreeMultiset = TreeMultisetNode>> extends AVLTree - implements IBinaryTree -{ + implements IBinaryTree { /** * The constructor function for a TreeMultiset class in TypeScript, which extends another class and sets an option to * merge duplicated values. diff --git a/src/data-structures/graph/abstract-graph.ts b/src/data-structures/graph/abstract-graph.ts index d7d5b08..60a1819 100644 --- a/src/data-structures/graph/abstract-graph.ts +++ b/src/data-structures/graph/abstract-graph.ts @@ -105,8 +105,7 @@ export abstract class AbstractEdge { export abstract class AbstractGraph< V extends AbstractVertex = AbstractVertex, E extends AbstractEdge = AbstractEdge -> implements IGraph -{ +> implements IGraph { private _vertices: Map = new Map(); get vertices(): Map { @@ -554,14 +553,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); @@ -623,7 +622,7 @@ export abstract class AbstractGraph< if (vertexOrKey instanceof AbstractVertex) distMap.set(vertexOrKey, Infinity); } - const heap = new PriorityQueue<{key: number; val: V}>({comparator: (a, b) => a.key - b.key}); + const heap = new PriorityQueue<{ key: number; val: V }>({comparator: (a, b) => a.key - b.key}); heap.add({key: 0, val: srcVertex}); distMap.set(srcVertex, 0); @@ -852,7 +851,7 @@ export abstract class AbstractGraph< * `predecessor` property is a 2D array of vertices (or `null`) representing the predecessor vertices in the shortest * path between vertices in the */ - floyd(): {costs: number[][]; predecessor: (V | null)[][]} { + floyd(): { costs: number[][]; predecessor: (V | null)[][] } { const idAndVertices = [...this._vertices]; const n = idAndVertices.length; diff --git a/src/data-structures/graph/directed-graph.ts b/src/data-structures/graph/directed-graph.ts index 175e6bc..cc29bf3 100644 --- a/src/data-structures/graph/directed-graph.ts +++ b/src/data-structures/graph/directed-graph.ts @@ -64,8 +64,7 @@ export class DirectedEdge extends AbstractEdge { export class DirectedGraph = DirectedVertex, E 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 1380542..8bdf1c2 100644 --- a/src/data-structures/graph/undirected-graph.ts +++ b/src/data-structures/graph/undirected-graph.ts @@ -51,12 +51,11 @@ export class UndirectedEdge extends AbstractEdge { } export class UndirectedGraph< - V extends UndirectedVertex = UndirectedVertex, - E extends UndirectedEdge = UndirectedEdge - > + V extends UndirectedVertex = UndirectedVertex, + E extends UndirectedEdge = UndirectedEdge +> extends AbstractGraph - implements IGraph -{ + implements IGraph { /** * The constructor initializes a new Map object to store edges. */ diff --git a/src/data-structures/hash/hash-map.ts b/src/data-structures/hash/hash-map.ts index f3a5213..5231237 100644 --- a/src/data-structures/hash/hash-map.ts +++ b/src/data-structures/hash/hash-map.ts @@ -157,7 +157,7 @@ export class HashMap { } } - *entries(): IterableIterator<[K, V]> { + * entries(): IterableIterator<[K, V]> { for (const bucket of this.table) { if (bucket) { for (const [key, value] of bucket) { diff --git a/src/data-structures/hash/tree-map.ts b/src/data-structures/hash/tree-map.ts index fe86360..a6d743d 100644 --- a/src/data-structures/hash/tree-map.ts +++ b/src/data-structures/hash/tree-map.ts @@ -1 +1,2 @@ -export class TreeMap {} +export class TreeMap { +} diff --git a/src/data-structures/hash/tree-set.ts b/src/data-structures/hash/tree-set.ts index 591aeda..65f14db 100644 --- a/src/data-structures/hash/tree-set.ts +++ b/src/data-structures/hash/tree-set.ts @@ -1 +1,2 @@ -export class TreeSet {} +export class TreeSet { +} diff --git a/src/data-structures/heap/heap.ts b/src/data-structures/heap/heap.ts index 4f3fbe6..b4a197b 100644 --- a/src/data-structures/heap/heap.ts +++ b/src/data-structures/heap/heap.ts @@ -11,7 +11,7 @@ export class Heap { protected nodes: E[] = []; protected readonly comparator: Comparator; - constructor(options: {comparator: Comparator; nodes?: E[]}) { + constructor(options: { comparator: Comparator; nodes?: E[] }) { this.comparator = options.comparator; if (options.nodes && options.nodes.length > 0) { this.nodes = options.nodes; @@ -39,7 +39,7 @@ export class Heap { * @returns A new Heap instance. * @param options */ - static heapify(options: {nodes: E[]; comparator: Comparator}): Heap { + static heapify(options: { nodes: E[]; comparator: Comparator }): Heap { return new Heap(options); } diff --git a/src/data-structures/heap/max-heap.ts b/src/data-structures/heap/max-heap.ts index be2c9b1..139ef64 100644 --- a/src/data-structures/heap/max-heap.ts +++ b/src/data-structures/heap/max-heap.ts @@ -11,7 +11,7 @@ import type {Comparator} from '../../types'; export class MaxHeap extends Heap { constructor( - options: {comparator: Comparator; nodes?: E[]} = { + options: { comparator: Comparator; nodes?: E[] } = { 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'); diff --git a/src/data-structures/heap/min-heap.ts b/src/data-structures/heap/min-heap.ts index dc86f87..5057017 100644 --- a/src/data-structures/heap/min-heap.ts +++ b/src/data-structures/heap/min-heap.ts @@ -11,7 +11,7 @@ import type {Comparator} from '../../types'; export class MinHeap extends Heap { constructor( - options: {comparator: Comparator; nodes?: E[]} = { + options: { comparator: Comparator; nodes?: E[] } = { 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'); diff --git a/src/data-structures/linked-list/doubly-linked-list.ts b/src/data-structures/linked-list/doubly-linked-list.ts index ceacdb2..8e09f6f 100644 --- a/src/data-structures/linked-list/doubly-linked-list.ts +++ b/src/data-structures/linked-list/doubly-linked-list.ts @@ -625,6 +625,9 @@ export class DoublyLinkedList { return false; } + /** + * The function returns an iterator that iterates over the values of a linked list. + */ * [Symbol.iterator]() { let current = this.head; diff --git a/src/data-structures/linked-list/singly-linked-list.ts b/src/data-structures/linked-list/singly-linked-list.ts index 48e41c4..519747f 100644 --- a/src/data-structures/linked-list/singly-linked-list.ts +++ b/src/data-structures/linked-list/singly-linked-list.ts @@ -587,6 +587,9 @@ export class SinglyLinkedList { return accumulator; } + /** + * The function returns an iterator that iterates over the values of a linked list. + */ * [Symbol.iterator]() { let current = this.head; diff --git a/src/data-structures/matrix/matrix.ts b/src/data-structures/matrix/matrix.ts index 8f27617..7e8ae4b 100644 --- a/src/data-structures/matrix/matrix.ts +++ b/src/data-structures/matrix/matrix.ts @@ -14,7 +14,7 @@ export class MatrixNTI2D { * given initial value or 0 if not provided. * @param options - An object containing the following properties: */ - constructor(options: {row: number; col: number; initialVal?: V}) { + constructor(options: { row: number; col: number; initialVal?: V }) { const {row, col, initialVal} = options; this._matrix = new Array(row).fill(undefined).map(() => new Array(col).fill(initialVal || 0)); } diff --git a/src/data-structures/matrix/vector2d.ts b/src/data-structures/matrix/vector2d.ts index 1b2ff44..2f62f4e 100644 --- a/src/data-structures/matrix/vector2d.ts +++ b/src/data-structures/matrix/vector2d.ts @@ -10,7 +10,8 @@ export class Vector2D { public x: number = 0, public y: number = 0, public w: number = 1 // needed for matrix multiplication - ) {} + ) { + } /** * The function checks if the x and y values of a point are both zero. diff --git a/src/data-structures/priority-queue/max-priority-queue.ts b/src/data-structures/priority-queue/max-priority-queue.ts index dbb0793..409c99f 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 type {Comparator} from '../../types'; export class MaxPriorityQueue extends PriorityQueue { constructor( - options: {comparator: Comparator; nodes?: E[]} = { + options: { comparator: Comparator; nodes?: E[] } = { 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'); diff --git a/src/data-structures/priority-queue/min-priority-queue.ts b/src/data-structures/priority-queue/min-priority-queue.ts index 8b8386f..da8ab64 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 type {Comparator} from '../../types'; export class MinPriorityQueue extends PriorityQueue { constructor( - options: {comparator: Comparator; nodes?: E[]} = { + options: { comparator: Comparator; nodes?: E[] } = { 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'); diff --git a/src/data-structures/priority-queue/priority-queue.ts b/src/data-structures/priority-queue/priority-queue.ts index edfbaf2..60deb98 100644 --- a/src/data-structures/priority-queue/priority-queue.ts +++ b/src/data-structures/priority-queue/priority-queue.ts @@ -10,7 +10,7 @@ import {Heap} from '../heap'; import {Comparator} from '../../types'; export class PriorityQueue extends Heap { - constructor(options: {comparator: Comparator; nodes?: E[]}) { + constructor(options: { comparator: Comparator; nodes?: E[] }) { super(options); } } diff --git a/src/data-structures/queue/deque.ts b/src/data-structures/queue/deque.ts index 8d6490a..dfd6169 100644 --- a/src/data-structures/queue/deque.ts +++ b/src/data-structures/queue/deque.ts @@ -9,7 +9,8 @@ import {DoublyLinkedList} from '../linked-list'; // O(n) time complexity of obtaining the value // O(1) time complexity of adding at the beginning and the end -export class Deque extends DoublyLinkedList {} +export class Deque extends DoublyLinkedList { +} // O(1) time complexity of obtaining the value // O(n) time complexity of adding at the beginning and the end @@ -19,9 +20,9 @@ export class ObjectDeque { if (capacity !== undefined) this._capacity = capacity; } - private _nodes: {[key: number]: E} = {}; + private _nodes: { [key: number]: E } = {}; - get nodes(): {[p: number]: E} { + get nodes(): { [p: number]: E } { return this._nodes; } @@ -156,7 +157,7 @@ export class ObjectDeque { return this._size <= 0; } - protected _seNodes(value: {[p: number]: E}) { + protected _seNodes(value: { [p: number]: E }) { this._nodes = value; } diff --git a/src/data-structures/queue/queue.ts b/src/data-structures/queue/queue.ts index 0f9e1a2..8b97743 100644 --- a/src/data-structures/queue/queue.ts +++ b/src/data-structures/queue/queue.ts @@ -183,7 +183,7 @@ export class Queue { return new Queue(this.nodes.slice(this.offset)); } - *[Symbol.iterator]() { + * [Symbol.iterator]() { for (const item of this.nodes) { yield item; } diff --git a/src/types/data-structures/matrix/navigator.ts b/src/types/data-structures/matrix/navigator.ts index 9d8b9a9..34eddd9 100644 --- a/src/types/data-structures/matrix/navigator.ts +++ b/src/types/data-structures/matrix/navigator.ts @@ -1,6 +1,6 @@ export type Direction = 'up' | 'right' | 'down' | 'left'; -export type Turning = {[key in Direction]: Direction}; +export type Turning = { [key in Direction]: Direction }; export type NavigatorParams = { matrix: T[][]; diff --git a/src/types/utils/utils.ts b/src/types/utils/utils.ts index f4d26c4..1f3a505 100644 --- a/src/types/utils/utils.ts +++ b/src/types/utils/utils.ts @@ -1,5 +1,5 @@ export type ToThunkFn = () => ReturnType; -export type Thunk = () => ReturnType & {__THUNK__: symbol}; +export type Thunk = () => ReturnType & { __THUNK__: symbol }; export type TrlFn = (...args: any[]) => any; export type TrlAsyncFn = (...args: any[]) => any; diff --git a/src/types/utils/validate-type.ts b/src/types/utils/validate-type.ts index ac9ff28..3ebf451 100644 --- a/src/types/utils/validate-type.ts +++ b/src/types/utils/validate-type.ts @@ -1,6 +1,6 @@ -export type KeyValueObject = {[key: string]: any}; +export type KeyValueObject = { [key: string]: any }; -export type KeyValueObjectWithKey = {[key: string]: any; key: string | number | symbol}; +export type KeyValueObjectWithKey = { [key: string]: any; key: string | number | symbol }; export type NonNumberNonObjectButDefined = string | boolean | symbol | null; diff --git a/test/integration/bst.test.ts b/test/integration/bst.test.ts index 0a33db7..35a6061 100644 --- a/test/integration/bst.test.ts +++ b/test/integration/bst.test.ts @@ -183,7 +183,7 @@ describe('Individual package BST operations test', () => { }); it('should perform various operations on a Binary Search Tree with object values', () => { - const objBST = new BST<{key: number; keyA: number}>(); + const objBST = new BST<{ key: number; keyA: number }>(); expect(objBST).toBeInstanceOf(BST); objBST.add(11, {key: 11, keyA: 11}); objBST.add(3, {key: 3, keyA: 3}); diff --git a/test/unit/data-structures/binary-tree/avl-tree.test.ts b/test/unit/data-structures/binary-tree/avl-tree.test.ts index e7e7d00..8a7bec9 100644 --- a/test/unit/data-structures/binary-tree/avl-tree.test.ts +++ b/test/unit/data-structures/binary-tree/avl-tree.test.ts @@ -219,7 +219,7 @@ describe('AVL Tree Test recursively', () => { }); describe('AVLTree APIs test', () => { - const avl = new AVLTree<{id: number; text: string}>(); + const avl = new AVLTree<{ id: number; text: string }>(); beforeEach(() => { avl.clear(); }); diff --git a/test/unit/data-structures/binary-tree/binary-tree.test.ts b/test/unit/data-structures/binary-tree/binary-tree.test.ts index e15a7ed..64ac3f6 100644 --- a/test/unit/data-structures/binary-tree/binary-tree.test.ts +++ b/test/unit/data-structures/binary-tree/binary-tree.test.ts @@ -125,11 +125,19 @@ describe('BinaryTree', () => { }); it('should traverse in-order', () => { + tree.add(null); + tree.delete(1); + expect(tree.getHeight()).toBe(-1); tree.add(4); tree.add(2); + expect(tree.getHeight()).toBe(1); + tree.iterationType = IterationType.RECURSIVE; + expect(tree.getHeight()).toBe(1); + tree.iterationType = IterationType.ITERATIVE; + tree.add(6); tree.add(1); - tree.add(3); + tree.add(new BinaryTreeNode(3)); tree.add(5); tree.add(7); @@ -160,6 +168,7 @@ describe('BinaryTree', () => { ]); expect(tree.isSubtreeBST(tree.get(4), IterationType.RECURSIVE)).toBe(true); + expect(tree.isSubtreeBST(tree.get(4), IterationType.ITERATIVE)).toBe(true); }); it('should subTreeTraverse', () => { @@ -197,6 +206,7 @@ describe('BinaryTree Morris Traversal', () => { expect(result).toEqual(expected); expect(tree.dfs(node => node.key, 'in')).toEqual(expected); + expect(tree.dfs(node => node.key, 'in', tree.root, IterationType.RECURSIVE)).toEqual(expected); }); it('should perform pre-order Morris traversal correctly as dfs traversal', () => { @@ -231,7 +241,7 @@ describe('BinaryTree Morris Traversal', () => { }); describe('BinaryTree APIs test', () => { - const avl = new AVLTree<{id: number; text: string}>(); + const avl = new AVLTree<{ id: number; text: string }>(); beforeEach(() => { avl.clear(); }); @@ -255,8 +265,10 @@ describe('BinaryTree traversals', () => { const arr = [35, 20, 40, 15, 29, null, 50, null, 16, 28, 30, 45, 55]; tree.refill(arr); expect(tree.dfs(node => node.key, 'pre')).toEqual([35, 20, 15, 16, 29, 28, 30, 40, 50, 45, 55]); + expect(tree.dfs(node => node.key, 'pre', tree.root, IterationType.RECURSIVE)).toEqual([35, 20, 15, 16, 29, 28, 30, 40, 50, 45, 55]); expect(tree.dfs(node => node.key, 'in')).toEqual([15, 16, 20, 28, 29, 30, 35, 40, 45, 50, 55]); expect(tree.dfs(node => node.key, 'post')).toEqual([16, 15, 28, 30, 29, 20, 45, 55, 50, 40, 35]); + expect(tree.dfs(node => node.key, 'post', tree.root, IterationType.RECURSIVE)).toEqual([16, 15, 28, 30, 29, 20, 45, 55, 50, 40, 35]); expect(tree.bfs(node => node.key, tree.root, IterationType.RECURSIVE)).toEqual([ 35, 20, 40, 15, 29, 50, 16, 28, 30, 45, 55 ]); @@ -281,7 +293,7 @@ describe('BinaryTree', () => { let tree: BinaryTree; beforeEach(() => { - tree = new BinaryTree(); + tree = new BinaryTree({iterationType: IterationType.RECURSIVE}); }); afterEach(() => { @@ -441,6 +453,14 @@ describe('BinaryTree', () => { tree.add(3, 'B'); tree.add(7, 'C'); + tree.iterationType = IterationType.ITERATIVE; + // @ts-ignore + expect([...tree]).toEqual([3, 5, 7]); + tree.iterationType = IterationType.RECURSIVE; + // @ts-ignore + expect([...tree]).toEqual([3, 5, 7]); + tree.iterationType = IterationType.ITERATIVE; + const result = tree.morris(); expect(result).toEqual([3, 5, 7]); // Add assertions for the result of Morris traversal diff --git a/test/unit/data-structures/binary-tree/bst.test.ts b/test/unit/data-structures/binary-tree/bst.test.ts index b4d4a44..a4a59fa 100644 --- a/test/unit/data-structures/binary-tree/bst.test.ts +++ b/test/unit/data-structures/binary-tree/bst.test.ts @@ -189,7 +189,7 @@ describe('BST operations test', () => { }); it('should perform various operations on a Binary Search Tree with object values', () => { - const objBST = new BST<{key: number; keyA: number}>(); + const objBST = new BST<{ key: number; keyA: number }>(); expect(objBST).toBeInstanceOf(BST); objBST.add(11, {key: 11, keyA: 11}); objBST.add(3, {key: 3, keyA: 3}); @@ -260,7 +260,7 @@ describe('BST operations test', () => { objBST.perfectlyBalance(); expect(objBST.isPerfectlyBalanced()).toBe(true); - const bfsNodesAfterBalanced: BSTNode<{key: number; keyA: number}>[] = []; + const bfsNodesAfterBalanced: BSTNode<{ key: number; keyA: number }>[] = []; objBST.bfs(node => bfsNodesAfterBalanced.push(node)); expect(bfsNodesAfterBalanced[0].key).toBe(8); expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16); @@ -385,7 +385,7 @@ describe('BST operations test', () => { expect(bfsIDs[1]).toBe(12); expect(bfsIDs[2]).toBe(16); - const bfsNodes: BSTNode<{key: number; keyA: number}>[] = []; + const bfsNodes: BSTNode<{ key: number; keyA: number }>[] = []; objBST.bfs(node => bfsNodes.push(node)); expect(bfsNodes[0].key).toBe(2); expect(bfsNodes[1].key).toBe(12); @@ -579,7 +579,7 @@ describe('BST operations test recursively', () => { }); it('should perform various operations on a Binary Search Tree with object values', () => { - const objBST = new BST<{key: number; keyA: number}>(); + const objBST = new BST<{ key: number; keyA: number }>(); expect(objBST).toBeInstanceOf(BST); objBST.add(11, {key: 11, keyA: 11}); objBST.add(3, {key: 3, keyA: 3}); @@ -650,7 +650,7 @@ describe('BST operations test recursively', () => { objBST.perfectlyBalance(); expect(objBST.isPerfectlyBalanced()).toBe(true); - const bfsNodesAfterBalanced: BSTNode<{key: number; keyA: number}>[] = []; + const bfsNodesAfterBalanced: BSTNode<{ key: number; keyA: number }>[] = []; objBST.bfs(node => bfsNodesAfterBalanced.push(node)); expect(bfsNodesAfterBalanced[0].key).toBe(8); expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16); @@ -775,7 +775,7 @@ describe('BST operations test recursively', () => { expect(bfsIDs[1]).toBe(12); expect(bfsIDs[2]).toBe(16); - const bfsNodes: BSTNode<{key: number; keyA: number}>[] = []; + const bfsNodes: BSTNode<{ key: number; keyA: number }>[] = []; objBST.bfs(node => bfsNodes.push(node)); expect(bfsNodes[0].key).toBe(2); expect(bfsNodes[1].key).toBe(12); diff --git a/test/unit/data-structures/binary-tree/overall.test.ts b/test/unit/data-structures/binary-tree/overall.test.ts index 520c2bc..8c1921c 100644 --- a/test/unit/data-structures/binary-tree/overall.test.ts +++ b/test/unit/data-structures/binary-tree/overall.test.ts @@ -29,7 +29,7 @@ describe('Overall BinaryTree Test', () => { bfsIDs[0] === 11; // true expect(bfsIDs[0]).toBe(11); - const objBST = new BST<{key: number; keyA: number}>(); + const objBST = new BST<{ key: number; keyA: number }>(); objBST.add(11, {key: 11, keyA: 11}); objBST.add(3, {key: 3, keyA: 3}); diff --git a/test/unit/data-structures/binary-tree/tree-multiset.test.ts b/test/unit/data-structures/binary-tree/tree-multiset.test.ts index ab90ae2..4cfe46f 100644 --- a/test/unit/data-structures/binary-tree/tree-multiset.test.ts +++ b/test/unit/data-structures/binary-tree/tree-multiset.test.ts @@ -207,7 +207,7 @@ describe('TreeMultiset operations test', () => { }); it('should perform various operations on a Binary Search Tree with object values', () => { - const objTreeMultiset = new TreeMultiset<{key: number; keyA: number}>(); + const objTreeMultiset = new TreeMultiset<{ key: number; keyA: number }>(); expect(objTreeMultiset).toBeInstanceOf(TreeMultiset); objTreeMultiset.add(11, {key: 11, keyA: 11}); objTreeMultiset.add(3, {key: 3, keyA: 3}); @@ -447,7 +447,7 @@ describe('TreeMultiset operations test recursively', () => { }); it('should perform various operations on a Binary Search Tree with object values', () => { - const objTreeMultiset = new TreeMultiset<{key: number; keyA: number}>(); + const objTreeMultiset = new TreeMultiset<{ key: number; keyA: number }>(); expect(objTreeMultiset).toBeInstanceOf(TreeMultiset); objTreeMultiset.add(11, {key: 11, keyA: 11}); objTreeMultiset.add(3, {key: 3, keyA: 3}); diff --git a/test/unit/data-structures/hash/coordinate-map.test.ts b/test/unit/data-structures/hash/coordinate-map.test.ts index 8f5ec34..81fb68e 100644 --- a/test/unit/data-structures/hash/coordinate-map.test.ts +++ b/test/unit/data-structures/hash/coordinate-map.test.ts @@ -52,3 +52,23 @@ describe('CoordinateMap', () => { expect(retrievedValue).toBe(value); }); }); + +describe('CoordinateMap', () => { + class MyCoordinateMap extends CoordinateMap { + constructor(joint?: string) { + super(joint); + this._setJoint(joint += '-') + } + } + + const cMap = new MyCoordinateMap('*'); + + beforeEach(() => { + cMap.set([0, 0], 0); + cMap.set([0, 1], 1); + cMap.set([1, 1], 11); + }) + it('should joint to be *-', () => { + expect(cMap.joint).toBe('*-'); + }); +}); diff --git a/test/unit/data-structures/hash/coordinate-set.test.ts b/test/unit/data-structures/hash/coordinate-set.test.ts index 3fadc01..f9cce6c 100644 --- a/test/unit/data-structures/hash/coordinate-set.test.ts +++ b/test/unit/data-structures/hash/coordinate-set.test.ts @@ -39,3 +39,28 @@ describe('CoordinateSet', () => { expect(hasValue).toBe(true); }); }); + +describe('MyCoordinateSet', () => { + class MyCoordinateSet extends CoordinateSet { + constructor(joint?: string) { + super(joint); + this._setJoint(joint += '-') + } + } + + const mySet = new MyCoordinateSet('*'); + + beforeEach(() => { + mySet.add([0, 0]); + mySet.add([0, 1]); + mySet.add([1, 1]); + }) + it('should joint to be *-', () => { + expect(mySet.joint).toBe('*-'); + }); + + it('should has, delete', () => { + mySet.delete([0, 1]); + expect(mySet.has([0, 1])).toBe(false); + }); +}); diff --git a/test/unit/data-structures/hash/hash-table.test.ts b/test/unit/data-structures/hash/hash-table.test.ts index b4ff78e..363afd0 100644 --- a/test/unit/data-structures/hash/hash-table.test.ts +++ b/test/unit/data-structures/hash/hash-table.test.ts @@ -15,7 +15,9 @@ describe('HashNode', () => { describe('HashTable', () => { it('should initialize with default capacity', () => { const hashTable = new HashTable(); - + hashTable.capacity = hashTable.capacity; + hashTable.buckets = hashTable.buckets; + hashTable.hashFn = hashTable.hashFn; expect(hashTable.capacity).toBe(16); expect(hashTable.size).toBe(0); expect(hashTable.buckets.length).toBe(16); diff --git a/test/unit/data-structures/heap/heap.test.ts b/test/unit/data-structures/heap/heap.test.ts index 19ed4dc..d827b91 100644 --- a/test/unit/data-structures/heap/heap.test.ts +++ b/test/unit/data-structures/heap/heap.test.ts @@ -22,7 +22,7 @@ describe('Heap Operation Test', () => { }); it('should object heap work well', function () { - const minHeap = new MinHeap<{a: string; key: number}>({comparator: (a, b) => a.key - b.key}); + const minHeap = new MinHeap<{ a: string; key: number }>({comparator: (a, b) => a.key - b.key}); minHeap.add({key: 1, a: 'a1'}); minHeap.add({key: 6, a: 'a6'}); minHeap.add({key: 2, a: 'a2'}); @@ -37,7 +37,7 @@ describe('Heap Operation Test', () => { i++; } - const maxHeap = new MaxHeap<{key: number; a: string}>({comparator: (a, b) => b.key - a.key}); + const maxHeap = new MaxHeap<{ key: number; a: string }>({comparator: (a, b) => b.key - a.key}); maxHeap.add({key: 1, a: 'a1'}); maxHeap.add({key: 6, a: 'a6'}); maxHeap.add({key: 5, a: 'a5'}); diff --git a/test/unit/data-structures/linked-list/doubly-linked-list.test.ts b/test/unit/data-structures/linked-list/doubly-linked-list.test.ts index c20880a..a2a19f3 100644 --- a/test/unit/data-structures/linked-list/doubly-linked-list.test.ts +++ b/test/unit/data-structures/linked-list/doubly-linked-list.test.ts @@ -1,9 +1,72 @@ -import {DoublyLinkedList} from '../../../../src'; +import {DoublyLinkedList, DoublyLinkedListNode} from '../../../../src'; import {bigO, magnitude} from '../../../utils'; +describe('DoublyLinkedListNode', () => { + it('should DoublyLinkedListNode', () => { + const node1 = new DoublyLinkedListNode(2); + expect(node1.val).toBe(2); + node1.val = 1; + expect(node1.val).toBe(1); + }) +}); + describe('DoublyLinkedList Operation Test', () => { let list: DoublyLinkedList; - let objectList: DoublyLinkedList<{keyA: number}>; + + beforeEach(() => { + list = DoublyLinkedList.fromArray([1, 2, 3, 4, 5]); + }); + + it('should out of bound index', () => { + expect(list.getNodeAt(-1)).toBe(null); + expect(list.getNodeAt(5)).toBe(null); + expect(list.insertAt(5, 6)).toBe(true); + }); + + it('should insertBefore', () => { + expect(list.insertBefore(1, 0)).toBe(true); + }); + + it('should deleteAt', () => { + expect(list.deleteAt(1)).toBeTruthy(); + }); + + it('should delete tail', () => { + expect(list.delete(list.tail)).toBe(true); + expect(list.tail?.val).toBe(4); + expect(list.delete(6)).toBe(false); + expect(list.tail?.val).toBe(4); + }); + + + it('should find null', () => { + expect(list.find(val => val === 6)).toBe(null); + + }); + + it('should indexOf -1', () => { + expect(list.indexOf(6)).toBe(-1); + }); + + it('should findBackward null', () => { + expect(list.findBackward(val => val === 0)).toBe(null); + }); + + it('should insertAfter tail', () => { + expect(list.insertAfter(list.tail!, 6)).toBe(true); + }); + + it('should insertAfter tail', () => { + // @ts-ignore + expect([...list]).toEqual([1, 2, 3, 4, 5]); + }); + + +}); + +describe('DoublyLinkedList Operation Test', () => { + let list: DoublyLinkedList; + let objectList: DoublyLinkedList<{ keyA: number }>; beforeEach(() => { list = new DoublyLinkedList(); diff --git a/test/unit/data-structures/linked-list/singly-linked-list.test.ts b/test/unit/data-structures/linked-list/singly-linked-list.test.ts index 2c4cbe3..8a4ada6 100644 --- a/test/unit/data-structures/linked-list/singly-linked-list.test.ts +++ b/test/unit/data-structures/linked-list/singly-linked-list.test.ts @@ -1,12 +1,21 @@ -import {SinglyLinkedList} from '../../../../src'; +import {SinglyLinkedList, SinglyLinkedListNode} from '../../../../src'; import {bigO, magnitude} from '../../../utils'; +describe('SinglyLinkedListNode', () => { + it('should SinglyLinkedList', () => { + const node1 = new SinglyLinkedListNode(2); + expect(node1.val).toBe(2); + node1.val = 1; + expect(node1.val).toBe(1); + }) +}); + describe('SinglyLinkedList Operation Test', () => { let list: SinglyLinkedList; - let objectList: SinglyLinkedList<{keyA: number}>; + let objectList: SinglyLinkedList<{ keyA: number }>; beforeEach(() => { list = new SinglyLinkedList(); - objectList = new SinglyLinkedList<{keyA: number}>(); + objectList = new SinglyLinkedList<{ keyA: number }>(); }); describe('push', () => { @@ -21,8 +30,10 @@ describe('SinglyLinkedList Operation Test', () => { it('should delete and return the last element of the list', () => { list.push(1); list.push(2); + list.push(3); const popped = list.pop(); - expect(popped).toBe(2); + expect(popped).toBe(3); + expect(list.popLast()).toBe(2); expect(list.toArray()).toEqual([1]); }); @@ -36,9 +47,11 @@ describe('SinglyLinkedList Operation Test', () => { it('should delete and return the first element of the list', () => { list.push(1); list.push(2); + list.push(3); const shifted = list.shift(); expect(shifted).toBe(1); - expect(list.toArray()).toEqual([2]); + expect(list.popFirst()).toBe(2); + expect(list.toArray()).toEqual([3]); }); it('should return undefined if the list is empty', () => { @@ -50,7 +63,7 @@ describe('SinglyLinkedList Operation Test', () => { describe('unshift', () => { it('should add elements to the beginning of the list', () => { list.unshift(1); - list.unshift(2); + list.addFirst(2); expect(list.toArray()).toEqual([2, 1]); }); }); @@ -62,6 +75,7 @@ describe('SinglyLinkedList Operation Test', () => { list.push(3); const element = list.getAt(1); expect(element).toBe(2); + expect(list.getNodeAt(2)?.val).toBe(3); }); it('should return undefined for an out-of-bounds index', () => { @@ -113,9 +127,14 @@ describe('SinglyLinkedList Operation Test', () => { list.push(1); list.push(2); list.push(3); - const removed = list.delete(2); - expect(removed).toBe(true); - expect(list.toArray()).toEqual([1, 3]); + list.push(4); + list.push(5); + expect(list.delete(2)).toBe(true); + expect(list.toArray()).toEqual([1, 3, 4, 5]); + expect(list.delete(1)).toBe(true); + expect(list.toArray()).toEqual([3, 4, 5]); + expect(list.delete(5)).toBe(true); + expect(list.toArray()).toEqual([3, 4]); }); it('should return false if the value is not found', () => { @@ -427,7 +446,6 @@ describe('SinglyLinkedList', () => { expect(list.length).toBe(1); }); - // Add more test cases for other methods like shift, unshift, getAt, deleteAt, and more. it('should reverse the list', () => { list.push(1); @@ -439,7 +457,6 @@ describe('SinglyLinkedList', () => { // Add more assertions for reversed order. }); - // Add more test cases for other methods like find, indexOf, and more. it('should convert the list to an array', () => { list.push(1); @@ -447,5 +464,35 @@ describe('SinglyLinkedList', () => { list.push(3); const array = list.toArray(); expect(array).toEqual([1, 2, 3]); + // @ts-ignore + expect([...list]).toEqual([1, 2, 3]); + }); + + it('should filter the list', () => { + list.push(1); + list.push(2); + list.push(3); + expect(list.filter(val => val !== 2).toArray()).toEqual([1, 3]); + }); + + + it('should forEach the list', () => { + list.push(1); + list.push(2); + list.push(3); + list.forEach(val => val++); + expect(list.toArray()).toEqual([1, 2, 3]) + }); + + it('should map the list', () => { + list.addLast(1); + list.push(2); + list.push(3); + expect(list.map(val => val * 2).toArray()).toEqual([2, 4, 6]); + }); + + it('should reduce the list', () => { + const list1 = SinglyLinkedList.fromArray([1, 2, 3]); + expect(list1.reduce((acc, val) => acc + val, 0)).toEqual(6); }); }); diff --git a/test/unit/data-structures/priority-queue/max-priority-queue.test.ts b/test/unit/data-structures/priority-queue/max-priority-queue.test.ts index 26fd837..8b2f287 100644 --- a/test/unit/data-structures/priority-queue/max-priority-queue.test.ts +++ b/test/unit/data-structures/priority-queue/max-priority-queue.test.ts @@ -17,7 +17,7 @@ describe('MaxPriorityQueue Operation Test', () => { }); it('should add elements and maintain heap property in a object MaxPriorityQueue', () => { - const priorityQueue = new MaxPriorityQueue<{keyA: number}>({comparator: (a, b) => b.keyA - a.keyA}); + const priorityQueue = new MaxPriorityQueue<{ keyA: number }>({comparator: (a, b) => b.keyA - a.keyA}); priorityQueue.refill([{keyA: 5}, {keyA: 3}, {keyA: 1}]); priorityQueue.add({keyA: 7}); @@ -64,7 +64,7 @@ describe('MaxPriorityQueue Operation Test', () => { it('should correctly heapify an object array', () => { const nodes = [{keyA: 5}, {keyA: 3}, {keyA: 7}, {keyA: 1}]; - const maxPQ = MaxPriorityQueue.heapify<{keyA: number}>({nodes: nodes, comparator: (a, b) => b.keyA - a.keyA}); + const maxPQ = MaxPriorityQueue.heapify<{ keyA: number }>({nodes: nodes, comparator: (a, b) => b.keyA - a.keyA}); expect(maxPQ.poll()?.keyA).toBe(7); expect(maxPQ.poll()?.keyA).toBe(5); diff --git a/test/utils/big-o.ts b/test/utils/big-o.ts index 43d7eca..cc9fc86 100644 --- a/test/utils/big-o.ts +++ b/test/utils/big-o.ts @@ -26,7 +26,7 @@ export const bigO = { function findPotentialN(input: any): number { let longestArray: any[] = []; - let mostProperties: {[key: string]: any} = {}; + let mostProperties: { [key: string]: any } = {}; function recurse(obj: any) { if (Array.isArray(obj)) { diff --git a/webpack.config.js b/webpack.config.js deleted file mode 100644 index bf57ba7..0000000 --- a/webpack.config.js +++ /dev/null @@ -1,28 +0,0 @@ -const path = require('path'); - -module.exports = [ - { - mode:'production', - entry: './src/index.ts', - target: 'web', - output: { - filename: 'bundle.min.js', - path: path.resolve(__dirname, 'umd'), - library: 'dataStructureTyped', - libraryTarget: 'umd', - }, - resolve: { - extensions: ['.ts', '.js'], - }, - module: { - rules: [ - { - test: /\.ts$/, - use: 'ts-loader', - exclude: /node_modules/, - } - ], - }, - devtool: 'source-map', - }, -]; From bf5b865e2ce68e75086655ae2d2bf3b492649333 Mon Sep 17 00:00:00 2001 From: Revone Date: Mon, 30 Oct 2023 11:14:41 +0800 Subject: [PATCH 36/46] [binary-tree] bug fix#27 --- .prettierrc.js | 2 +- CHANGELOG.md | 2 +- package-lock.json | 12 +- package.json | 10 +- src/data-structures/binary-tree/avl-tree.ts | 25 +-- .../binary-tree/binary-indexed-tree.ts | 2 +- .../binary-tree/binary-tree.ts | 190 ++++++++++++------ src/data-structures/binary-tree/bst.ts | 63 +++--- src/data-structures/binary-tree/rb-tree.ts | 13 +- .../binary-tree/tree-multiset.ts | 31 +-- src/data-structures/graph/abstract-graph.ts | 21 +- src/data-structures/graph/directed-graph.ts | 3 +- src/data-structures/graph/undirected-graph.ts | 9 +- src/data-structures/hash/hash-map.ts | 2 +- src/data-structures/hash/tree-map.ts | 3 +- src/data-structures/hash/tree-set.ts | 3 +- src/data-structures/heap/heap.ts | 4 +- src/data-structures/heap/max-heap.ts | 2 +- src/data-structures/heap/min-heap.ts | 2 +- .../linked-list/doubly-linked-list.ts | 2 +- .../linked-list/singly-linked-list.ts | 2 +- src/data-structures/matrix/matrix.ts | 2 +- src/data-structures/matrix/vector2d.ts | 3 +- .../priority-queue/max-priority-queue.ts | 2 +- .../priority-queue/min-priority-queue.ts | 2 +- .../priority-queue/priority-queue.ts | 2 +- src/data-structures/queue/deque.ts | 9 +- src/data-structures/queue/queue.ts | 2 +- src/interfaces/binary-tree.ts | 8 +- .../binary-tree/binary-tree.ts | 2 +- src/types/data-structures/binary-tree/bst.ts | 4 +- src/types/data-structures/matrix/navigator.ts | 2 +- src/types/helpers.ts | 2 +- src/types/utils/utils.ts | 2 +- src/types/utils/validate-type.ts | 4 +- test/integration/bst.test.ts | 2 +- .../binary-tree/avl-tree.test.ts | 2 +- .../binary-tree/binary-tree.test.ts | 22 +- .../data-structures/binary-tree/bst.test.ts | 12 +- .../binary-tree/overall.test.ts | 2 +- .../binary-tree/tree-multiset.test.ts | 4 +- .../hash/coordinate-map.test.ts | 4 +- .../hash/coordinate-set.test.ts | 4 +- test/unit/data-structures/heap/heap.test.ts | 4 +- .../linked-list/doubly-linked-list.test.ts | 8 +- .../linked-list/singly-linked-list.test.ts | 11 +- .../priority-queue/max-priority-queue.test.ts | 4 +- test/utils/big-o.ts | 2 +- 48 files changed, 300 insertions(+), 230 deletions(-) diff --git a/.prettierrc.js b/.prettierrc.js index 2458204..124f598 100644 --- a/.prettierrc.js +++ b/.prettierrc.js @@ -3,7 +3,7 @@ module.exports = { "bracketSpacing": false, "htmlWhitespaceSensitivity": "css", "insertPragma": false, - "bracketSameLine": false, + "bracketSameLine": true, "jsxSingleQuote": true, "printWidth": 120, "proseWrap": "preserve", diff --git a/CHANGELOG.md b/CHANGELOG.md index 51e66a0..4fb300d 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.39.1](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) +## [v1.39.2](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) ### Changes diff --git a/package-lock.json b/package-lock.json index e691959..608505b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "data-structure-typed", - "version": "1.39.1", + "version": "1.39.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "data-structure-typed", - "version": "1.39.1", + "version": "1.39.2", "license": "MIT", "devDependencies": { "@types/benchmark": "^2.1.3", @@ -15,17 +15,17 @@ "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", "auto-changelog": "^2.4.0", - "avl-tree-typed": "^1.39.0", + "avl-tree-typed": "^1.39.1", "benchmark": "^2.1.4", - "binary-tree-typed": "^1.39.0", - "bst-typed": "^1.39.0", + "binary-tree-typed": "^1.39.1", + "bst-typed": "^1.39.1", "dependency-cruiser": "^14.1.0", "eslint": "^8.50.0", "eslint-config-prettier": "^9.0.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.28.1", - "heap-typed": "^1.39.0", + "heap-typed": "^1.39.1", "istanbul-badges-readme": "^1.8.5", "jest": "^29.7.0", "prettier": "^3.0.3", diff --git a/package.json b/package.json index beca064..33a2080 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "data-structure-typed", - "version": "1.39.2", + "version": "1.39.3", "description": "Data Structures of Javascript & TypeScript. Binary Tree, BST, Graph, Heap, Priority Queue, Linked List, Queue, Deque, Stack, AVL Tree, Tree Multiset, Trie, Directed Graph, Undirected Graph, Singly Linked List, Doubly Linked List, Max Heap, Max Priority Queue, Min Heap, Min Priority Queue.", "main": "dist/cjs/index.js", "module": "dist/mjs/index.js", @@ -61,17 +61,17 @@ "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", "auto-changelog": "^2.4.0", - "avl-tree-typed": "^1.39.0", + "avl-tree-typed": "^1.39.1", "benchmark": "^2.1.4", - "binary-tree-typed": "^1.39.0", - "bst-typed": "^1.39.0", + "binary-tree-typed": "^1.39.1", + "bst-typed": "^1.39.1", "dependency-cruiser": "^14.1.0", "eslint": "^8.50.0", "eslint-config-prettier": "^9.0.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.28.1", - "heap-typed": "^1.39.0", + "heap-typed": "^1.39.1", "istanbul-badges-readme": "^1.8.5", "jest": "^29.7.0", "prettier": "^3.0.3", diff --git a/src/data-structures/binary-tree/avl-tree.ts b/src/data-structures/binary-tree/avl-tree.ts index 2db0487..db9dd2a 100644 --- a/src/data-structures/binary-tree/avl-tree.ts +++ b/src/data-structures/binary-tree/avl-tree.ts @@ -6,14 +6,14 @@ * @license MIT License */ import {BST, BSTNode} from './bst'; -import type {AVLTreeNodeNested, AVLTreeOptions, BinaryTreeDeletedResult, BinaryTreeNodeKey} from '../../types'; -import {OneParamCallback} from '../../types'; +import type {AVLTreeNodeNested, AVLTreeOptions, BinaryTreeDeletedResult, BTNKey} from '../../types'; +import {BTNCallback} from '../../types'; import {IBinaryTree} from '../../interfaces'; export class AVLTreeNode = AVLTreeNodeNested> extends BSTNode { height: number; - constructor(key: BinaryTreeNodeKey, val?: V) { + constructor(key: BTNKey, val?: V) { super(key, val); this.height = 0; } @@ -21,7 +21,8 @@ export class AVLTreeNode = AVLTreeNodeNeste export class AVLTree = AVLTreeNode>> extends BST - implements IBinaryTree { + implements IBinaryTree +{ /** * This is a constructor function for an AVL tree data structure in TypeScript. * @param {AVLTreeOptions} [options] - The `options` parameter is an optional object that can be passed to the @@ -34,27 +35,27 @@ export class AVLTree = AVLTreeNode(key, val) as N; } /** * The function overrides the add method of a binary tree node and balances the tree after inserting * a new node. - * @param {BinaryTreeNodeKey | N | null} keyOrNode - The `keyOrNode` parameter can accept either a - * `BinaryTreeNodeKey` or a `N` (which represents a node in the binary tree) or `null`. + * @param {BTNKey | N | null} keyOrNode - The `keyOrNode` parameter can accept either a + * `BTNKey` or a `N` (which represents a node in the binary tree) or `null`. * @param [val] - The `val` parameter is the value that you want to assign to the new node that you * are adding to the binary search tree. * @returns The method is returning the inserted node (`N`), `null`, or `undefined`. */ - override add(keyOrNode: BinaryTreeNodeKey | N | null, val?: V): N | null | undefined { + override add(keyOrNode: BTNKey | N | null, val?: V): N | null | undefined { // TODO support node as a param const inserted = super.add(keyOrNode, val); if (inserted) this._balancePath(inserted); @@ -65,7 +66,7 @@ export class AVLTree = AVLTreeNode} identifier - The `identifier` parameter is either a - * `BinaryTreeNodeKey` or a generic type `N`. It represents the property of the node that we are + * `BTNKey` or a generic type `N`. It represents the property of the node that we are * searching for. It can be a specific key value or any other property of the node. * @param callback - The `callback` parameter is a function that takes a node as input and returns a * value. This value is compared with the `identifier` parameter to determine if the node should be @@ -73,7 +74,7 @@ export class AVLTree = AVLTreeNode` objects. */ - override delete>( + override delete>( identifier: ReturnType, callback: C = this._defaultCallbackByKey as C ): BinaryTreeDeletedResult[] { @@ -160,7 +161,7 @@ export class AVLTree = AVLTreeNode = BinaryTree /** * The key associated with the node. */ - key: BinaryTreeNodeKey; + key: BTNKey; /** * The value stored in the node. @@ -35,10 +35,10 @@ export class BinaryTreeNode = BinaryTree /** * Creates a new instance of BinaryTreeNode. - * @param {BinaryTreeNodeKey} key - The key associated with the node. + * @param {BTNKey} key - The key associated with the node. * @param {V} val - The value stored in the node. */ - constructor(key: BinaryTreeNodeKey, val?: V) { + constructor(key: BTNKey, val?: V) { this.key = key; this.val = val; } @@ -108,7 +108,8 @@ export class BinaryTreeNode = BinaryTree * @template N - The type of the binary tree's nodes. */ export class BinaryTree = BinaryTreeNode>> - implements IBinaryTree { + implements IBinaryTree +{ /** * Creates a new instance of BinaryTree. * @param {BinaryTreeOptions} [options] - The options for the binary tree. @@ -157,11 +158,11 @@ export class BinaryTree = BinaryTreeNode /** * Creates a new instance of BinaryTreeNode with the given key and value. - * @param {BinaryTreeNodeKey} key - The key for the new node. + * @param {BTNKey} key - The key for the new node. * @param {V} val - The value for the new node. * @returns {N} - The newly created BinaryTreeNode. */ - createNode(key: BinaryTreeNodeKey, val?: V): N { + createNode(key: BTNKey, val?: V): N { return new BinaryTreeNode(key, val) as N; } @@ -183,11 +184,11 @@ export class BinaryTree = BinaryTreeNode /** * Add a node with the given key and value to the binary tree. - * @param {BinaryTreeNodeKey | N | null} keyOrNode - The key or node to add to the binary tree. + * @param {BTNKey | N | null} keyOrNode - The key or node to add to the binary tree. * @param {V} val - The value for the new node (optional). * @returns {N | null | undefined} - The inserted node, or null if nothing was inserted, or undefined if the operation failed. */ - add(keyOrNode: BinaryTreeNodeKey | N | null, val?: V): N | null | undefined { + add(keyOrNode: BTNKey | N | null, val?: V): N | null | undefined { const _bfs = (root: N, newNode: N | null): N | undefined | null => { const queue = new Queue([root]); while (queue.size > 0) { @@ -240,14 +241,14 @@ export class BinaryTree = BinaryTreeNode /** * The `addMany` function takes an array of binary tree node IDs or nodes, and optionally an array of corresponding data * values, and adds them to the binary tree. - * @param {(BinaryTreeNodeKey | null)[] | (N | null)[]} keysOrNodes - An array of BinaryTreeNodeKey or BinaryTreeNode + * @param {(BTNKey | null)[] | (N | null)[]} keysOrNodes - An array of BTNKey or BinaryTreeNode * objects, or null values. * @param {V[]} [values] - The `values` parameter is an optional array of values (`V[]`) that corresponds to * the nodes or node IDs being added. It is used to set the value of each node being added. If `values` is not provided, * the value of the nodes will be `undefined`. * @returns The function `addMany` returns an array of `N`, `null`, or `undefined` values. */ - addMany(keysOrNodes: (BinaryTreeNodeKey | null)[] | (N | null)[], values?: V[]): (N | null | undefined)[] { + addMany(keysOrNodes: (BTNKey | null)[] | (N | null)[], values?: V[]): (N | null | undefined)[] { // TODO not sure addMany not be run multi times return keysOrNodes.map((keyOrNode, i) => { if (keyOrNode instanceof BinaryTreeNode) { @@ -265,33 +266,39 @@ export class BinaryTree = BinaryTreeNode /** * The `refill` function clears the binary tree and adds multiple nodes with the given IDs or nodes and optional data. - * @param {(BinaryTreeNodeKey | N)[]} keysOrNodes - The `keysOrNodes` parameter is an array that can contain either - * `BinaryTreeNodeKey` or `N` values. + * @param {(BTNKey | N)[]} keysOrNodes - The `keysOrNodes` parameter is an array that can contain either + * `BTNKey` or `N` values. * @param {N[] | Array} [data] - The `data` parameter is an optional array of values that will be assigned to * the nodes being added. If provided, the length of the `data` array should be equal to the length of the `keysOrNodes` * array. Each value in the `data` array will be assigned to the * @returns The method is returning a boolean value. */ - refill(keysOrNodes: (BinaryTreeNodeKey | null)[] | (N | null)[], data?: Array): boolean { + refill(keysOrNodes: (BTNKey | null)[] | (N | null)[], data?: Array): boolean { this.clear(); return keysOrNodes.length === this.addMany(keysOrNodes, data).length; } + delete>(identifier: BTNKey, callback?: C): BinaryTreeDeletedResult[]; + + delete>(identifier: N | null, callback?: C): BinaryTreeDeletedResult[]; + + delete>(identifier: ReturnType, callback: C): BinaryTreeDeletedResult[]; + /** * The `delete` function removes a node from a binary search tree and returns the deleted node along * with the parent node that needs to be balanced. - * a key (`BinaryTreeNodeKey`). If it is a key, the function will find the corresponding node in the + * a key (`BTNKey`). If it is a key, the function will find the corresponding node in the * binary tree. * @returns an array of `BinaryTreeDeletedResult` objects. * @param {ReturnType} identifier - The `identifier` parameter is either a - * `BinaryTreeNodeKey` or a generic type `N`. It represents the property of the node that we are + * `BTNKey` or a generic type `N`. It represents the property of the node that we are * searching for. It can be a specific key value or any other property of the node. * @param callback - The `callback` parameter is a function that takes a node as input and returns a * value. This value is compared with the `identifier` parameter to determine if the node should be * included in the result. The `callback` parameter has a default value of * `this._defaultCallbackByKey`, which */ - delete>( + delete>( identifier: ReturnType | null, callback: C = this._defaultCallbackByKey as C ): BinaryTreeDeletedResult[] { @@ -341,16 +348,16 @@ export class BinaryTree = BinaryTreeNode /** * The function `getDepth` calculates the depth of a given node in a binary tree relative to a * specified root node. - * @param {BinaryTreeNodeKey | N | null} distNode - The `distNode` parameter represents the node + * @param {BTNKey | N | null} distNode - The `distNode` parameter represents the node * whose depth we want to find in the binary tree. It can be either a node object (`N`), a key value - * of the node (`BinaryTreeNodeKey`), or `null`. - * @param {BinaryTreeNodeKey | N | null} beginRoot - The `beginRoot` parameter represents the + * of the node (`BTNKey`), or `null`. + * @param {BTNKey | N | null} beginRoot - The `beginRoot` parameter represents the * starting node from which we want to calculate the depth. It can be either a node object or the key * of a node in the binary tree. If no value is provided for `beginRoot`, it defaults to the root * node of the binary tree. * @returns the depth of the `distNode` relative to the `beginRoot`. */ - getDepth(distNode: BinaryTreeNodeKey | N | null, beginRoot: BinaryTreeNodeKey | N | null = this.root): number { + getDepth(distNode: BTNKey | N | null, beginRoot: BTNKey | N | null = this.root): number { if (typeof distNode === 'number') distNode = this.get(distNode); if (typeof beginRoot === 'number') beginRoot = this.get(beginRoot); let depth = 0; @@ -367,16 +374,16 @@ export class BinaryTree = BinaryTreeNode /** * The `getHeight` function calculates the maximum height of a binary tree using either recursive or * iterative approach. - * @param {BinaryTreeNodeKey | N | null} beginRoot - The `beginRoot` parameter represents the + * @param {BTNKey | N | null} beginRoot - The `beginRoot` parameter represents the * starting node from which the height of the binary tree is calculated. It can be either a node - * object (`N`), a key value of a node in the tree (`BinaryTreeNodeKey`), or `null` if no starting + * object (`N`), a key value of a node in the tree (`BTNKey`), or `null` if no starting * node is specified. If ` * @param iterationType - The `iterationType` parameter is used to determine whether to calculate the * height of the binary tree using a recursive approach or an iterative approach. It can have two * possible values: * @returns the height of the binary tree. */ - getHeight(beginRoot: BinaryTreeNodeKey | N | null = this.root, iterationType = this.iterationType): number { + getHeight(beginRoot: BTNKey | N | null = this.root, iterationType = this.iterationType): number { if (typeof beginRoot === 'number') beginRoot = this.get(beginRoot); if (!beginRoot) return -1; @@ -394,7 +401,7 @@ export class BinaryTree = BinaryTreeNode return -1; } - const stack: { node: N; depth: number }[] = [{node: beginRoot, depth: 0}]; + const stack: {node: N; depth: number}[] = [{node: beginRoot, depth: 0}]; let maxHeight = 0; while (stack.length > 0) { @@ -478,11 +485,35 @@ export class BinaryTree = BinaryTreeNode return this.getMinHeight(beginRoot) + 1 >= this.getHeight(beginRoot); } + getNodes>( + identifier: BTNKey, + callback: C, + onlyOne?: boolean, + beginRoot?: N | null, + iterationType?: IterationType + ): N[]; + + getNodes>( + identifier: N | null, + callback: C, + onlyOne?: boolean, + beginRoot?: N | null, + iterationType?: IterationType + ): N[]; + + getNodes>( + identifier: ReturnType, + callback: C, + onlyOne?: boolean, + beginRoot?: N | null, + iterationType?: IterationType + ): N[]; + /** * The function `getNodes` returns an array of nodes that match a given node property, using either * recursive or iterative traversal. * @param {ReturnType} identifier - The `identifier` parameter is either a - * `BinaryTreeNodeKey` or a generic type `N`. It represents the property of the node that we are + * `BTNKey` or a generic type `N`. It represents the property of the node that we are * searching for. It can be a specific key value or any other property of the node. * @param callback - The `callback` parameter is a function that takes a node as input and returns a * value. This value is compared with the `identifier` parameter to determine if the node should be @@ -499,7 +530,7 @@ export class BinaryTree = BinaryTreeNode * traverse the binary tree. It can have two possible values: * @returns The function `getNodes` returns an array of nodes (`N[]`). */ - getNodes>( + getNodes>( identifier: ReturnType | null, callback: C = this._defaultCallbackByKey as C, onlyOne = false, @@ -540,10 +571,31 @@ export class BinaryTree = BinaryTreeNode return ans; } + has>( + identifier: BTNKey, + callback?: C, + beginRoot?: N, + iterationType?: IterationType + ): boolean; + + has>( + identifier: N | null, + callback?: C, + beginRoot?: N, + iterationType?: IterationType + ): boolean; + + has>( + identifier: ReturnType | null, + callback: C, + beginRoot?: N, + iterationType?: IterationType + ): boolean; + /** * The function checks if a binary tree has a node with a given property or key. - * @param {BinaryTreeNodeKey | N} identifier - The `identifier` parameter is the key or value of - * the node that you want to find in the binary tree. It can be either a `BinaryTreeNodeKey` or a + * @param {BTNKey | N} identifier - The `identifier` parameter is the key or value of + * the node that you want to find in the binary tree. It can be either a `BTNKey` or a * generic type `N`. * @param callback - The `callback` parameter is a function that is used to determine whether a node * matches the desired criteria. It takes a node as input and returns a boolean value indicating @@ -557,7 +609,7 @@ export class BinaryTree = BinaryTreeNode * performed when searching for nodes in the binary tree. It can have one of the following values: * @returns a boolean value. */ - has>( + has>( identifier: ReturnType | null, callback: C = this._defaultCallbackByKey as C, beginRoot = this.root, @@ -568,10 +620,31 @@ export class BinaryTree = BinaryTreeNode return this.getNodes(identifier, callback, true, beginRoot, iterationType).length > 0; } + get>( + identifier: BTNKey, + callback?: C, + beginRoot?: N, + iterationType?: IterationType + ): N | null; + + get>( + identifier: N | null, + callback?: C, + beginRoot?: N, + iterationType?: IterationType + ): N | null; + + get>( + identifier: ReturnType, + callback: C, + beginRoot?: N, + iterationType?: IterationType + ): N | null; + /** * The function `get` returns the first node in a binary tree that matches the given property or key. - * @param {BinaryTreeNodeKey | N} identifier - The `identifier` parameter is the key or value of - * the node that you want to find in the binary tree. It can be either a `BinaryTreeNodeKey` or `N` + * @param {BTNKey | N} identifier - The `identifier` parameter is the key or value of + * the node that you want to find in the binary tree. It can be either a `BTNKey` or `N` * type. * @param callback - The `callback` parameter is a function that is used to determine whether a node * matches the desired criteria. It takes a node as input and returns a boolean value indicating @@ -583,7 +656,7 @@ export class BinaryTree = BinaryTreeNode * performed when searching for a node in the binary tree. It can have one of the following values: * @returns either the found node (of type N) or null if no node is found. */ - get>( + get>( identifier: ReturnType | null, callback: C = this._defaultCallbackByKey as C, beginRoot = this.root, @@ -620,15 +693,15 @@ export class BinaryTree = BinaryTreeNode /** * The function `getLeftMost` returns the leftmost node in a binary tree, either using recursive or * iterative traversal. - * @param {BinaryTreeNodeKey | N | null} beginRoot - The `beginRoot` parameter is the starting point + * @param {BTNKey | N | null} beginRoot - The `beginRoot` parameter is the starting point * for finding the leftmost node in a binary tree. It can be either a node object (`N`), a key value - * of a node (`BinaryTreeNodeKey`), or `null` if the tree is empty. + * of a node (`BTNKey`), or `null` if the tree is empty. * @param iterationType - The `iterationType` parameter is used to determine the type of iteration to * be performed when finding the leftmost node in a binary tree. It can have two possible values: * @returns The function `getLeftMost` returns the leftmost node (`N`) in a binary tree. If there is * no leftmost node, it returns `null`. */ - getLeftMost(beginRoot: BinaryTreeNodeKey | N | null = this.root, iterationType = this.iterationType): N | null { + getLeftMost(beginRoot: BTNKey | N | null = this.root, iterationType = this.iterationType): N | null { if (typeof beginRoot === 'number') beginRoot = this.get(beginRoot); if (!beginRoot) return beginRoot; @@ -698,7 +771,7 @@ export class BinaryTree = BinaryTreeNode if (!beginRoot) return true; if (iterationType === IterationType.RECURSIVE) { - const dfs = (cur: N | null | undefined, min: BinaryTreeNodeKey, max: BinaryTreeNodeKey): boolean => { + const dfs = (cur: N | null | undefined, min: BTNKey, max: BTNKey): boolean => { if (!cur) return true; if (cur.key <= min || cur.key >= max) return false; return dfs(cur.left, min, cur.key) && dfs(cur.right, cur.key, max); @@ -743,21 +816,21 @@ export class BinaryTree = BinaryTreeNode * subtree traversal. It takes a single argument, which is the current node being traversed, and * returns a value. The return values from each callback invocation will be collected and returned as * an array. - * @param {BinaryTreeNodeKey | N | null} beginRoot - The `beginRoot` parameter is the starting point + * @param {BTNKey | N | null} beginRoot - The `beginRoot` parameter is the starting point * for traversing the subtree. It can be either a node object, a key value of a node, or `null` to * start from the root of the tree. * @param iterationType - The `iterationType` parameter determines the type of traversal to be * performed on the binary tree. It can have two possible values: - * @returns The function `subTreeTraverse` returns an array of `ReturnType>`. + * @returns The function `subTreeTraverse` returns an array of `ReturnType>`. */ - subTreeTraverse>( + subTreeTraverse>( callback: C = this._defaultCallbackByKey as C, - beginRoot: BinaryTreeNodeKey | N | null = this.root, + beginRoot: BTNKey | N | null = this.root, iterationType = this.iterationType ): ReturnType[] { if (typeof beginRoot === 'number') beginRoot = this.get(beginRoot); - const ans: ReturnType>[] = []; + const ans: ReturnType>[] = []; if (!beginRoot) return ans; if (iterationType === IterationType.RECURSIVE) { @@ -795,16 +868,16 @@ export class BinaryTree = BinaryTreeNode * is `null`, an empty array will be returned. * @param {IterationType} iterationType - The `iterationType` parameter determines the type of * iteration used in the depth-first search algorithm. It can have two possible values: - * @returns The function `dfs` returns an array of `ReturnType>` values. + * @returns The function `dfs` returns an array of `ReturnType>` values. */ - dfs>( + dfs>( callback: C = this._defaultCallbackByKey as C, pattern: DFSOrderPattern = 'in', beginRoot: N | null = this.root, iterationType: IterationType = IterationType.ITERATIVE ): ReturnType[] { if (!beginRoot) return []; - const ans: ReturnType>[] = []; + const ans: ReturnType>[] = []; if (iterationType === IterationType.RECURSIVE) { const _traverse = (node: N) => { switch (pattern) { @@ -831,7 +904,7 @@ export class BinaryTree = BinaryTreeNode _traverse(beginRoot); } else { // 0: visit, 1: print - const stack: { opt: 0 | 1; node: N | null | undefined }[] = [{opt: 0, node: beginRoot}]; + const stack: {opt: 0 | 1; node: N | null | undefined}[] = [{opt: 0, node: beginRoot}]; while (stack.length > 0) { const cur = stack.pop(); @@ -873,22 +946,22 @@ export class BinaryTree = BinaryTreeNode * function on each node. * @param callback - The `callback` parameter is a function that will be called for each node in the * breadth-first search. It takes a node of type `N` as its argument and returns a value of type - * `ReturnType>`. The default value for this parameter is `this._defaultCallbackByKey + * `ReturnType>`. The default value for this parameter is `this._defaultCallbackByKey * @param {N | null} beginRoot - The `beginRoot` parameter is the starting node for the breadth-first * search. It determines from which node the search will begin. If `beginRoot` is `null`, the search * will not be performed and an empty array will be returned. * @param iterationType - The `iterationType` parameter determines the type of iteration to be used * in the breadth-first search (BFS) algorithm. It can have two possible values: - * @returns The function `bfs` returns an array of `ReturnType>[]`. + * @returns The function `bfs` returns an array of `ReturnType>[]`. */ - bfs>( + bfs>( callback: C = this._defaultCallbackByKey as C, beginRoot: N | null = this.root, iterationType = this.iterationType ): ReturnType[] { if (!beginRoot) return []; - const ans: ReturnType>[] = []; + const ans: ReturnType>[] = []; if (iterationType === IterationType.RECURSIVE) { const queue = new Queue([beginRoot]); @@ -938,7 +1011,7 @@ export class BinaryTree = BinaryTreeNode * level in a binary tree. Each inner array contains the return type of the provided callback * function `C` applied to the nodes at that level. */ - listLevels>( + listLevels>( callback: C = this._defaultCallbackByKey as C, beginRoot: N | null = this.root, iterationType = this.iterationType @@ -997,7 +1070,7 @@ export class BinaryTree = BinaryTreeNode * The `morris` function performs a depth-first traversal of a binary tree using the Morris traversal * algorithm and returns an array of values obtained by applying a callback function to each node. * @param callback - The `callback` parameter is a function that will be called on each node in the - * tree. It takes a node of type `N` as input and returns a value of type `ReturnType>`. The + * tree. It takes a node of type `N` as input and returns a value of type `ReturnType>`. The * default value for this parameter is `this._defaultCallbackByKey`. * @param {DFSOrderPattern} [pattern=in] - The `pattern` parameter in the `morris` function * determines the order in which the nodes of a binary tree are traversed. It can have one of the @@ -1005,15 +1078,15 @@ export class BinaryTree = BinaryTreeNode * @param {N | null} beginRoot - The `beginRoot` parameter is the starting node for the Morris * traversal. It specifies the root node of the tree from which the traversal should begin. If * `beginRoot` is `null`, an empty array will be returned. - * @returns The `morris` function returns an array of `ReturnType>` values. + * @returns The `morris` function returns an array of `ReturnType>` values. */ - morris>( + morris>( callback: C = this._defaultCallbackByKey as C, pattern: DFSOrderPattern = 'in', beginRoot: N | null = this.root ): ReturnType[] { if (beginRoot === null) return []; - const ans: ReturnType>[] = []; + const ans: ReturnType>[] = []; let cur: N | null | undefined = beginRoot; const _reverseEdge = (node: N | null | undefined) => { @@ -1101,7 +1174,7 @@ export class BinaryTree = BinaryTreeNode * @returns The `*[Symbol.iterator]` method returns a generator object that yields the keys of the * binary tree nodes in a specific order. */ - * [Symbol.iterator](node = this.root): Generator { + *[Symbol.iterator](node = this.root): Generator { if (!node) { return; } @@ -1122,7 +1195,6 @@ export class BinaryTree = BinaryTreeNode if (current) current = current.right; } } else { - if (node.left) { yield* this[Symbol.iterator](node.left); } @@ -1131,10 +1203,8 @@ export class BinaryTree = BinaryTreeNode yield* this[Symbol.iterator](node.right); } } - } - /** * Swap the data of two nodes in the binary tree. * @param {N} srcNode - The source node to swap. @@ -1163,7 +1233,7 @@ export class BinaryTree = BinaryTreeNode * the tree's structure should be restored to its original state to maintain the tree's integrity. * This is because the purpose of the Morris algorithm is to save space rather than permanently alter the tree's shape. */ - protected _defaultCallbackByKey: OneParamCallback = node => node.key; + protected _defaultCallbackByKey: BTNCallback = node => node.key; /** * The function `_addTo` adds a new node to a binary tree if there is an available position. diff --git a/src/data-structures/binary-tree/bst.ts b/src/data-structures/binary-tree/bst.ts index ce4751d..84a6944 100644 --- a/src/data-structures/binary-tree/bst.ts +++ b/src/data-structures/binary-tree/bst.ts @@ -5,21 +5,22 @@ * @copyright Copyright (c) 2022 Tyler Zeng * @license MIT License */ -import type {BinaryTreeNodeKey, BSTComparator, BSTNodeNested, BSTOptions, OneParamCallback} from '../../types'; +import type {BTNKey, BSTComparator, BSTNodeNested, BSTOptions, BTNCallback} from '../../types'; import {CP, IterationType} from '../../types'; import {BinaryTree, BinaryTreeNode} from './binary-tree'; import {IBinaryTree} from '../../interfaces'; import {Queue} from '../queue'; export class BSTNode = BSTNodeNested> extends BinaryTreeNode { - constructor(key: BinaryTreeNodeKey, val?: V) { + constructor(key: BTNKey, val?: V) { super(key, val); } } export class BST = BSTNode>> extends BinaryTree - implements IBinaryTree { + implements IBinaryTree +{ /** * The constructor function initializes a binary search tree object with an optional comparator * function. @@ -38,27 +39,27 @@ export class BST = BSTNode> /** * The function creates a new binary search tree node with the given key and value. - * @param {BinaryTreeNodeKey} key - The key parameter is the key value that will be associated with + * @param {BTNKey} key - The key parameter is the key value that will be associated with * the new node. It is used to determine the position of the node in the binary search tree. * @param [val] - The parameter `val` is an optional value that can be assigned to the node. It * represents the value associated with the node in a binary search tree. * @returns a new instance of the BSTNode class with the specified key and value. */ - override createNode(key: BinaryTreeNodeKey, val?: V): N { + override createNode(key: BTNKey, val?: V): N { return new BSTNode(key, val) as N; } /** * The `add` function in a binary search tree class inserts a new node with a given key and value * into the tree. - * @param {BinaryTreeNodeKey | N | null} keyOrNode - The `keyOrNode` parameter can be either a - * `BinaryTreeNodeKey` (which can be a number or a string), a `BSTNode` object, or `null`. + * @param {BTNKey | N | null} keyOrNode - The `keyOrNode` parameter can be either a + * `BTNKey` (which can be a number or a string), a `BSTNode` object, or `null`. * @param [val] - The `val` parameter is the value to be assigned to the new node being added to the * binary search tree. * @returns the inserted node (N) if it was successfully added to the binary search tree. If the node * was not added or if the parameters were invalid, it returns null or undefined. */ - override add(keyOrNode: BinaryTreeNodeKey | N | null, val?: V): N | null | undefined { + override add(keyOrNode: BTNKey | N | null, val?: V): N | null | undefined { // TODO support node as a parameter let inserted: N | null = null; let newNode: N | null = null; @@ -127,9 +128,9 @@ export class BST = BSTNode> /** * The `addMany` function is used to efficiently add multiple nodes to a binary search tree while * maintaining balance. - * @param {[BinaryTreeNodeKey | N, N['val']][]} keysOrNodes - The `arr` parameter in the `addMany` function + * @param {[BTNKey | N, N['val']][]} keysOrNodes - The `arr` parameter in the `addMany` function * represents an array of keys or nodes that need to be added to the binary search tree. It can be an - * array of `BinaryTreeNodeKey` or `N` (which represents the node type in the binary search tree) or + * array of `BTNKey` or `N` (which represents the node type in the binary search tree) or * `null * @param {V[]} data - The values of tree nodes * @param {boolean} isBalanceAdd - If true the nodes will be balance inserted in binary search method. @@ -139,13 +140,13 @@ export class BST = BSTNode> */ override addMany( - keysOrNodes: (BinaryTreeNodeKey | null)[] | (N | null)[], + keysOrNodes: (BTNKey | null)[] | (N | null)[], data?: V[], isBalanceAdd = true, iterationType = this.iterationType ): (N | null | undefined)[] { // TODO this addMany function is inefficient, it should be optimized - function hasNoNull(arr: (BinaryTreeNodeKey | null)[] | (N | null)[]): arr is BinaryTreeNodeKey[] | N[] { + function hasNoNull(arr: (BTNKey | null)[] | (N | null)[]): arr is BTNKey[] | N[] { return arr.indexOf(null) === -1; } @@ -153,17 +154,15 @@ export class BST = BSTNode> return super.addMany(keysOrNodes, data); } const inserted: (N | null | undefined)[] = []; - const combinedArr: [BinaryTreeNodeKey | N, N['val']][] = keysOrNodes.map((value, index) => [value, data?.[index]]); + const combinedArr: [BTNKey | N, N['val']][] = keysOrNodes.map((value, index) => [value, data?.[index]]); let sorted = []; - function isNodeOrNullTuple(arr: [BinaryTreeNodeKey | N, N['val']][]): arr is [N, N['val']][] { + function isNodeOrNullTuple(arr: [BTNKey | N, N['val']][]): arr is [N, N['val']][] { for (const [keyOrNode] of arr) if (keyOrNode instanceof BSTNode) return true; return false; } - function isBinaryTreeKeyOrNullTuple( - arr: [BinaryTreeNodeKey | N, N['val']][] - ): arr is [BinaryTreeNodeKey, N['val']][] { + function isBinaryTreeKeyOrNullTuple(arr: [BTNKey | N, N['val']][]): arr is [BTNKey, N['val']][] { for (const [keyOrNode] of arr) if (typeof keyOrNode === 'number') return true; return false; } @@ -180,7 +179,7 @@ export class BST = BSTNode> } sortedKeysOrNodes = sorted.map(([keyOrNode]) => keyOrNode); sortedData = sorted.map(([, val]) => val); - const recursive = (arr: (BinaryTreeNodeKey | null | N)[], data?: (V | undefined)[]) => { + const recursive = (arr: (BTNKey | null | N)[], data?: (V | undefined)[]) => { if (arr.length === 0) return; const mid = Math.floor((arr.length - 1) / 2); @@ -220,7 +219,7 @@ export class BST = BSTNode> * callback. * @param {ReturnType | N} identifier - The `nodeProperty` parameter is used to specify the * property of the binary tree node that you want to search for. It can be either a specific key - * value (`BinaryTreeNodeKey`) or a custom callback function (`OneParamCallback`) that determines + * value (`BTNKey`) or a custom callback function (`BTNCallback`) that determines * whether a node matches the desired property. * @param callback - The `callback` parameter is a function that is used to determine whether a node * matches the desired property. It takes a node as input and returns a boolean value indicating @@ -233,7 +232,7 @@ export class BST = BSTNode> * @returns either the first node that matches the given nodeProperty and callback, or null if no * matching node is found. */ - override get>( + override get>( identifier: ReturnType | null, callback: C = this._defaultCallbackByKey as C, beginRoot = this.root, @@ -257,7 +256,7 @@ export class BST = BSTNode> * the key of the leftmost node if the comparison result is greater than, and the key of the * rightmost node otherwise. If no node is found, it returns 0. */ - lastKey(beginRoot: N | null = this.root, iterationType = this.iterationType): BinaryTreeNodeKey { + lastKey(beginRoot: N | null = this.root, iterationType = this.iterationType): BTNKey { if (this._compare(0, 1) === CP.lt) return this.getRightMost(beginRoot, iterationType)?.key ?? 0; else if (this._compare(0, 1) === CP.gt) return this.getLeftMost(beginRoot, iterationType)?.key ?? 0; else return this.getRightMost(beginRoot, iterationType)?.key ?? 0; @@ -267,7 +266,7 @@ export class BST = BSTNode> * The function `getNodes` retrieves nodes from a binary tree based on a given node property or key, * using either recursive or iterative traversal. * @param {ReturnType | N} identifier - The `nodeProperty` parameter represents the property - * of the binary tree node that you want to search for. It can be either a `BinaryTreeNodeKey` or a + * of the binary tree node that you want to search for. It can be either a `BTNKey` or a * generic type `N`. * @param callback - The `callback` parameter is a function that takes a node as input and returns a * value. This value is compared with the `nodeProperty` parameter to determine if the node should be @@ -284,7 +283,7 @@ export class BST = BSTNode> * traverse the binary tree. It can have one of the following values: * @returns an array of nodes (N[]). */ - override getNodes>( + override getNodes>( identifier: ReturnType | null, callback: C = this._defaultCallbackByKey as C, onlyOne = false, @@ -350,22 +349,22 @@ export class BST = BSTNode> * @param {CP} lesserOrGreater - The `lesserOrGreater` parameter is used to determine whether to * traverse nodes that are lesser than, greater than, or equal to the `targetNode`. It can take one * of the following values: - * @param {BinaryTreeNodeKey | N | null} targetNode - The `targetNode` parameter in the + * @param {BTNKey | N | null} targetNode - The `targetNode` parameter in the * `lesserOrGreaterTraverse` function is used to specify the node from which the traversal should * start. It can be either a reference to a specific node (`N`), the key of a node - * (`BinaryTreeNodeKey`), or `null` to + * (`BTNKey`), or `null` to * @param iterationType - The `iterationType` parameter determines whether the traversal should be * done recursively or iteratively. It can have two possible values: - * @returns The function `lesserOrGreaterTraverse` returns an array of `ReturnType>`. + * @returns The function `lesserOrGreaterTraverse` returns an array of `ReturnType>`. */ - lesserOrGreaterTraverse>( + lesserOrGreaterTraverse>( callback: C = this._defaultCallbackByKey as C, lesserOrGreater: CP = CP.lt, - targetNode: BinaryTreeNodeKey | N | null = this.root, + targetNode: BTNKey | N | null = this.root, iterationType = this.iterationType ): ReturnType[] { if (typeof targetNode === 'number') targetNode = this.get(targetNode); - const ans: ReturnType>[] = []; + const ans: ReturnType>[] = []; if (!targetNode) return ans; const targetKey = targetNode.key; if (!this.root) return ans; @@ -508,12 +507,12 @@ export class BST = BSTNode> /** * The function compares two values using a comparator function and returns whether the first value * is greater than, less than, or equal to the second value. - * @param {BinaryTreeNodeKey} a - The parameter "a" is of type BinaryTreeNodeKey. - * @param {BinaryTreeNodeKey} b - The parameter "b" in the above code represents a BinaryTreeNodeKey. + * @param {BTNKey} a - The parameter "a" is of type BTNKey. + * @param {BTNKey} b - The parameter "b" in the above code represents a BTNKey. * @returns a value of type CP (ComparisonResult). The possible return values are CP.gt (greater * than), CP.lt (less than), or CP.eq (equal). */ - protected _compare(a: BinaryTreeNodeKey, b: BinaryTreeNodeKey): CP { + protected _compare(a: BTNKey, b: BTNKey): CP { const compared = this._comparator(a, b); if (compared > 0) return CP.gt; else if (compared < 0) return CP.lt; diff --git a/src/data-structures/binary-tree/rb-tree.ts b/src/data-structures/binary-tree/rb-tree.ts index 45c363b..56121f7 100644 --- a/src/data-structures/binary-tree/rb-tree.ts +++ b/src/data-structures/binary-tree/rb-tree.ts @@ -1,9 +1,9 @@ -import {BinaryTreeNodeKey, RBColor, RBTreeNodeNested, RBTreeOptions} from '../../types'; +import {BTNKey, RBColor, RBTreeNodeNested, RBTreeOptions} from '../../types'; import {IBinaryTree} from '../../interfaces'; import {BST, BSTNode} from './bst'; export class RBTreeNode = RBTreeNodeNested> extends BSTNode { - constructor(key: BinaryTreeNodeKey, val?: V) { + constructor(key: BTNKey, val?: V) { super(key, val); this._color = RBColor.RED; } @@ -21,16 +21,17 @@ export class RBTreeNode = RBTreeNodeNested = RBTreeNode>> extends BST - implements IBinaryTree { + implements IBinaryTree +{ constructor(options?: RBTreeOptions) { super(options); } - override createNode(key: BinaryTreeNodeKey, val?: V): N { + override createNode(key: BTNKey, val?: V): N { return new RBTreeNode(key, val) as N; } - // override add(keyOrNode: BinaryTreeNodeKey | N | null, val?: V): N | null | undefined { + // override add(keyOrNode: BTNKey | N | null, val?: V): N | null | undefined { // const inserted = super.add(keyOrNode, val); // if (inserted) this._fixInsertViolation(inserted); // return inserted; @@ -204,7 +205,7 @@ export class RBTree = RBTreeNode[] { + // override delete(keyOrNode: BTNKey | N): BinaryTreeDeletedResult[] { // const node = this.get(keyOrNode); // const result: BinaryTreeDeletedResult[] = [{deleted: undefined, needBalanced: null}]; // if (!node) return result; // Node does not exist diff --git a/src/data-structures/binary-tree/tree-multiset.ts b/src/data-structures/binary-tree/tree-multiset.ts index 1cd5e49..15b9a81 100644 --- a/src/data-structures/binary-tree/tree-multiset.ts +++ b/src/data-structures/binary-tree/tree-multiset.ts @@ -5,8 +5,8 @@ * @copyright Copyright (c) 2022 Tyler Zeng * @license MIT License */ -import type {BinaryTreeNodeKey, TreeMultisetNodeNested, TreeMultisetOptions} from '../../types'; -import {BinaryTreeDeletedResult, CP, FamilyPosition, IterationType, OneParamCallback} from '../../types'; +import type {BTNKey, TreeMultisetNodeNested, TreeMultisetOptions} from '../../types'; +import {BinaryTreeDeletedResult, CP, FamilyPosition, IterationType, BTNCallback} from '../../types'; import {IBinaryTree} from '../../interfaces'; import {AVLTree, AVLTreeNode} from './avl-tree'; @@ -18,7 +18,7 @@ export class TreeMultisetNode< /** * The constructor function initializes a BinaryTreeNode object with a key, value, and count. - * @param {BinaryTreeNodeKey} key - The `key` parameter is of type `BinaryTreeNodeKey` and represents the unique identifier + * @param {BTNKey} key - The `key` parameter is of type `BTNKey` and represents the unique identifier * of the binary tree node. * @param {V} [val] - The `val` parameter is an optional parameter of type `V`. It represents the value of the binary * tree node. If no value is provided, it will be `undefined`. @@ -26,7 +26,7 @@ export class TreeMultisetNode< * occurs in a binary tree node. It has a default value of 1, which means that if no value is provided for the `count` * parameter when creating a new instance of the `BinaryTreeNode` class. */ - constructor(key: BinaryTreeNodeKey, val?: V, count = 1) { + constructor(key: BTNKey, val?: V, count = 1) { super(key, val); this.count = count; } @@ -37,7 +37,8 @@ export class TreeMultisetNode< */ export class TreeMultiset = TreeMultisetNode>> extends AVLTree - implements IBinaryTree { + implements IBinaryTree +{ /** * The constructor function for a TreeMultiset class in TypeScript, which extends another class and sets an option to * merge duplicated values. @@ -56,22 +57,22 @@ export class TreeMultiset = TreeMultis /** * The function creates a new BSTNode with the given key, value, and count. - * @param {BinaryTreeNodeKey} key - The key parameter is the unique identifier for the binary tree node. It is used to + * @param {BTNKey} key - The key parameter is the unique identifier for the binary tree node. It is used to * distinguish one node from another in the tree. * @param {N} val - The `val` parameter represents the value that will be stored in the binary search tree node. * @param {number} [count] - The "count" parameter is an optional parameter of type number. It represents the number of * occurrences of the value in the binary search tree node. If not provided, the count will default to 1. * @returns A new instance of the BSTNode class with the specified key, value, and count (if provided). */ - override createNode(key: BinaryTreeNodeKey, val?: V, count?: number): N { + override createNode(key: BTNKey, val?: V, count?: number): N { return new TreeMultisetNode(key, val, count) as N; } /** * The `add` function adds a new node to a binary search tree, updating the count if the key already * exists, and balancing the tree if necessary. - * @param {BinaryTreeNodeKey | N | null} keyOrNode - The `keyOrNode` parameter can be either a - * `BinaryTreeNodeKey` (which represents the key of the node to be added), a `N` (which represents a + * @param {BTNKey | N | null} keyOrNode - The `keyOrNode` parameter can be either a + * `BTNKey` (which represents the key of the node to be added), a `N` (which represents a * node to be added), or `null` (which represents a null node). * @param [val] - The `val` parameter represents the value associated with the key that is being * added to the binary tree. @@ -80,7 +81,7 @@ export class TreeMultiset = TreeMultis * count is specified, the default count will be 1. * @returns The function `add` returns a value of type `N | null | undefined`. */ - override add(keyOrNode: BinaryTreeNodeKey | N | null, val?: V, count = 1): N | null | undefined { + override add(keyOrNode: BTNKey | N | null, val?: V, count = 1): N | null | undefined { let inserted: N | null | undefined = undefined, newNode: N | null; if (keyOrNode instanceof TreeMultisetNode) { @@ -184,14 +185,14 @@ export class TreeMultiset = TreeMultis /** * The `addMany` function adds multiple keys or nodes to a TreeMultiset and returns an array of the * inserted nodes. - * @param {(BinaryTreeNodeKey | null)[] | (N | null)[]} keysOrNodes - An array of keys or nodes to be - * added to the multiset. Each element can be either a BinaryTreeNodeKey or a TreeMultisetNode. + * @param {(BTNKey | null)[] | (N | null)[]} keysOrNodes - An array of keys or nodes to be + * added to the multiset. Each element can be either a BTNKey or a TreeMultisetNode. * @param {V[]} [data] - The `data` parameter is an optional array of values that correspond * to the keys or nodes being added to the multiset. It is used to associate additional data with * each key or node. * @returns The function `addMany` returns an array of `N`, `null`, or `undefined` values. */ - override addMany(keysOrNodes: (BinaryTreeNodeKey | null)[] | (N | null)[], data?: V[]): (N | null | undefined)[] { + override addMany(keysOrNodes: (BTNKey | null)[] | (N | null)[], data?: V[]): (N | null | undefined)[] { const inserted: (N | null | undefined)[] = []; for (let i = 0; i < keysOrNodes.length; i++) { @@ -262,7 +263,7 @@ export class TreeMultiset = TreeMultis * The `delete` function in a binary search tree deletes a node from the tree and returns the deleted * node along with the parent node that needs to be balanced. * @param {ReturnType} identifier - The `identifier` parameter is either a - * `BinaryTreeNodeKey` or a generic type `N`. It represents the property of the node that we are + * `BTNKey` or a generic type `N`. It represents the property of the node that we are * searching for. It can be a specific key value or any other property of the node. * @param callback - The `callback` parameter is a function that takes a node as input and returns a * value. This value is compared with the `identifier` parameter to determine if the node should be @@ -274,7 +275,7 @@ export class TreeMultiset = TreeMultis * decremented by 1 and * @returns The method `delete` returns an array of `BinaryTreeDeletedResult` objects. */ - override delete>( + override delete>( identifier: ReturnType, callback: C = this._defaultCallbackByKey as C, ignoreCount = false diff --git a/src/data-structures/graph/abstract-graph.ts b/src/data-structures/graph/abstract-graph.ts index 60a1819..d7d5b08 100644 --- a/src/data-structures/graph/abstract-graph.ts +++ b/src/data-structures/graph/abstract-graph.ts @@ -105,7 +105,8 @@ export abstract class AbstractEdge { export abstract class AbstractGraph< V extends AbstractVertex = AbstractVertex, E extends AbstractEdge = AbstractEdge -> implements IGraph { +> implements IGraph +{ private _vertices: Map = new Map(); get vertices(): Map { @@ -553,14 +554,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); @@ -622,7 +623,7 @@ export abstract class AbstractGraph< if (vertexOrKey instanceof AbstractVertex) distMap.set(vertexOrKey, Infinity); } - const heap = new PriorityQueue<{ key: number; val: V }>({comparator: (a, b) => a.key - b.key}); + const heap = new PriorityQueue<{key: number; val: V}>({comparator: (a, b) => a.key - b.key}); heap.add({key: 0, val: srcVertex}); distMap.set(srcVertex, 0); @@ -851,7 +852,7 @@ export abstract class AbstractGraph< * `predecessor` property is a 2D array of vertices (or `null`) representing the predecessor vertices in the shortest * path between vertices in the */ - floyd(): { costs: number[][]; predecessor: (V | null)[][] } { + floyd(): {costs: number[][]; predecessor: (V | null)[][]} { const idAndVertices = [...this._vertices]; const n = idAndVertices.length; diff --git a/src/data-structures/graph/directed-graph.ts b/src/data-structures/graph/directed-graph.ts index cc29bf3..175e6bc 100644 --- a/src/data-structures/graph/directed-graph.ts +++ b/src/data-structures/graph/directed-graph.ts @@ -64,7 +64,8 @@ export class DirectedEdge extends AbstractEdge { export class DirectedGraph = DirectedVertex, E 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 8bdf1c2..1380542 100644 --- a/src/data-structures/graph/undirected-graph.ts +++ b/src/data-structures/graph/undirected-graph.ts @@ -51,11 +51,12 @@ export class UndirectedEdge extends AbstractEdge { } export class UndirectedGraph< - V extends UndirectedVertex = UndirectedVertex, - E extends UndirectedEdge = UndirectedEdge -> + V extends UndirectedVertex = UndirectedVertex, + E extends UndirectedEdge = UndirectedEdge + > extends AbstractGraph - implements IGraph { + implements IGraph +{ /** * The constructor initializes a new Map object to store edges. */ diff --git a/src/data-structures/hash/hash-map.ts b/src/data-structures/hash/hash-map.ts index 5231237..f3a5213 100644 --- a/src/data-structures/hash/hash-map.ts +++ b/src/data-structures/hash/hash-map.ts @@ -157,7 +157,7 @@ export class HashMap { } } - * entries(): IterableIterator<[K, V]> { + *entries(): IterableIterator<[K, V]> { for (const bucket of this.table) { if (bucket) { for (const [key, value] of bucket) { diff --git a/src/data-structures/hash/tree-map.ts b/src/data-structures/hash/tree-map.ts index a6d743d..fe86360 100644 --- a/src/data-structures/hash/tree-map.ts +++ b/src/data-structures/hash/tree-map.ts @@ -1,2 +1 @@ -export class TreeMap { -} +export class TreeMap {} diff --git a/src/data-structures/hash/tree-set.ts b/src/data-structures/hash/tree-set.ts index 65f14db..591aeda 100644 --- a/src/data-structures/hash/tree-set.ts +++ b/src/data-structures/hash/tree-set.ts @@ -1,2 +1 @@ -export class TreeSet { -} +export class TreeSet {} diff --git a/src/data-structures/heap/heap.ts b/src/data-structures/heap/heap.ts index b4a197b..4f3fbe6 100644 --- a/src/data-structures/heap/heap.ts +++ b/src/data-structures/heap/heap.ts @@ -11,7 +11,7 @@ export class Heap { protected nodes: E[] = []; protected readonly comparator: Comparator; - constructor(options: { comparator: Comparator; nodes?: E[] }) { + constructor(options: {comparator: Comparator; nodes?: E[]}) { this.comparator = options.comparator; if (options.nodes && options.nodes.length > 0) { this.nodes = options.nodes; @@ -39,7 +39,7 @@ export class Heap { * @returns A new Heap instance. * @param options */ - static heapify(options: { nodes: E[]; comparator: Comparator }): Heap { + static heapify(options: {nodes: E[]; comparator: Comparator}): Heap { return new Heap(options); } diff --git a/src/data-structures/heap/max-heap.ts b/src/data-structures/heap/max-heap.ts index 139ef64..be2c9b1 100644 --- a/src/data-structures/heap/max-heap.ts +++ b/src/data-structures/heap/max-heap.ts @@ -11,7 +11,7 @@ import type {Comparator} from '../../types'; export class MaxHeap extends Heap { constructor( - options: { comparator: Comparator; nodes?: E[] } = { + options: {comparator: Comparator; nodes?: E[]} = { 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'); diff --git a/src/data-structures/heap/min-heap.ts b/src/data-structures/heap/min-heap.ts index 5057017..dc86f87 100644 --- a/src/data-structures/heap/min-heap.ts +++ b/src/data-structures/heap/min-heap.ts @@ -11,7 +11,7 @@ import type {Comparator} from '../../types'; export class MinHeap extends Heap { constructor( - options: { comparator: Comparator; nodes?: E[] } = { + options: {comparator: Comparator; nodes?: E[]} = { 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'); diff --git a/src/data-structures/linked-list/doubly-linked-list.ts b/src/data-structures/linked-list/doubly-linked-list.ts index 8e09f6f..b39a3ee 100644 --- a/src/data-structures/linked-list/doubly-linked-list.ts +++ b/src/data-structures/linked-list/doubly-linked-list.ts @@ -628,7 +628,7 @@ export class DoublyLinkedList { /** * The function returns an iterator that iterates over the values of a linked list. */ - * [Symbol.iterator]() { + *[Symbol.iterator]() { 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 519747f..fa443cc 100644 --- a/src/data-structures/linked-list/singly-linked-list.ts +++ b/src/data-structures/linked-list/singly-linked-list.ts @@ -590,7 +590,7 @@ export class SinglyLinkedList { /** * The function returns an iterator that iterates over the values of a linked list. */ - * [Symbol.iterator]() { + *[Symbol.iterator]() { let current = this.head; while (current) { diff --git a/src/data-structures/matrix/matrix.ts b/src/data-structures/matrix/matrix.ts index 7e8ae4b..8f27617 100644 --- a/src/data-structures/matrix/matrix.ts +++ b/src/data-structures/matrix/matrix.ts @@ -14,7 +14,7 @@ export class MatrixNTI2D { * given initial value or 0 if not provided. * @param options - An object containing the following properties: */ - constructor(options: { row: number; col: number; initialVal?: V }) { + constructor(options: {row: number; col: number; initialVal?: V}) { const {row, col, initialVal} = options; this._matrix = new Array(row).fill(undefined).map(() => new Array(col).fill(initialVal || 0)); } diff --git a/src/data-structures/matrix/vector2d.ts b/src/data-structures/matrix/vector2d.ts index 2f62f4e..1b2ff44 100644 --- a/src/data-structures/matrix/vector2d.ts +++ b/src/data-structures/matrix/vector2d.ts @@ -10,8 +10,7 @@ export class Vector2D { public x: number = 0, public y: number = 0, public w: number = 1 // needed for matrix multiplication - ) { - } + ) {} /** * The function checks if the x and y values of a point are both zero. diff --git a/src/data-structures/priority-queue/max-priority-queue.ts b/src/data-structures/priority-queue/max-priority-queue.ts index 409c99f..dbb0793 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 type {Comparator} from '../../types'; export class MaxPriorityQueue extends PriorityQueue { constructor( - options: { comparator: Comparator; nodes?: E[] } = { + options: {comparator: Comparator; nodes?: E[]} = { 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'); diff --git a/src/data-structures/priority-queue/min-priority-queue.ts b/src/data-structures/priority-queue/min-priority-queue.ts index da8ab64..8b8386f 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 type {Comparator} from '../../types'; export class MinPriorityQueue extends PriorityQueue { constructor( - options: { comparator: Comparator; nodes?: E[] } = { + options: {comparator: Comparator; nodes?: E[]} = { 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'); diff --git a/src/data-structures/priority-queue/priority-queue.ts b/src/data-structures/priority-queue/priority-queue.ts index 60deb98..edfbaf2 100644 --- a/src/data-structures/priority-queue/priority-queue.ts +++ b/src/data-structures/priority-queue/priority-queue.ts @@ -10,7 +10,7 @@ import {Heap} from '../heap'; import {Comparator} from '../../types'; export class PriorityQueue extends Heap { - constructor(options: { comparator: Comparator; nodes?: E[] }) { + constructor(options: {comparator: Comparator; nodes?: E[]}) { super(options); } } diff --git a/src/data-structures/queue/deque.ts b/src/data-structures/queue/deque.ts index dfd6169..8d6490a 100644 --- a/src/data-structures/queue/deque.ts +++ b/src/data-structures/queue/deque.ts @@ -9,8 +9,7 @@ import {DoublyLinkedList} from '../linked-list'; // O(n) time complexity of obtaining the value // O(1) time complexity of adding at the beginning and the end -export class Deque extends DoublyLinkedList { -} +export class Deque extends DoublyLinkedList {} // O(1) time complexity of obtaining the value // O(n) time complexity of adding at the beginning and the end @@ -20,9 +19,9 @@ export class ObjectDeque { if (capacity !== undefined) this._capacity = capacity; } - private _nodes: { [key: number]: E } = {}; + private _nodes: {[key: number]: E} = {}; - get nodes(): { [p: number]: E } { + get nodes(): {[p: number]: E} { return this._nodes; } @@ -157,7 +156,7 @@ export class ObjectDeque { return this._size <= 0; } - protected _seNodes(value: { [p: number]: E }) { + protected _seNodes(value: {[p: number]: E}) { this._nodes = value; } diff --git a/src/data-structures/queue/queue.ts b/src/data-structures/queue/queue.ts index 8b97743..0f9e1a2 100644 --- a/src/data-structures/queue/queue.ts +++ b/src/data-structures/queue/queue.ts @@ -183,7 +183,7 @@ export class Queue { return new Queue(this.nodes.slice(this.offset)); } - * [Symbol.iterator]() { + *[Symbol.iterator]() { for (const item of this.nodes) { yield item; } diff --git a/src/interfaces/binary-tree.ts b/src/interfaces/binary-tree.ts index 1ff1f53..1437d6c 100644 --- a/src/interfaces/binary-tree.ts +++ b/src/interfaces/binary-tree.ts @@ -1,10 +1,10 @@ import {BinaryTreeNode} from '../data-structures'; -import {BinaryTreeDeletedResult, BinaryTreeNodeKey, BinaryTreeNodeNested, OneParamCallback} from '../types'; +import {BinaryTreeDeletedResult, BTNKey, BinaryTreeNodeNested, BTNCallback} from '../types'; export interface IBinaryTree = BinaryTreeNodeNested> { - createNode(key: BinaryTreeNodeKey, val?: N['val']): N; + createNode(key: BTNKey, val?: N['val']): N; - add(keyOrNode: BinaryTreeNodeKey | N | null, val?: N['val']): N | null | undefined; + add(keyOrNode: BTNKey | N | null, val?: N['val']): N | null | undefined; - delete>(identifier: ReturnType | null, callback: C): BinaryTreeDeletedResult[]; + delete>(identifier: ReturnType | null, callback: C): BinaryTreeDeletedResult[]; } diff --git a/src/types/data-structures/binary-tree/binary-tree.ts b/src/types/data-structures/binary-tree/binary-tree.ts index e037ede..c9da335 100644 --- a/src/types/data-structures/binary-tree/binary-tree.ts +++ b/src/types/data-structures/binary-tree/binary-tree.ts @@ -22,7 +22,7 @@ export enum FamilyPosition { MAL_NODE = 'MAL_NODE' } -export type BinaryTreeNodeKey = number; +export type BTNKey = number; export type BinaryTreeDeletedResult = { deleted: N | null | undefined; needBalanced: N | null }; diff --git a/src/types/data-structures/binary-tree/bst.ts b/src/types/data-structures/binary-tree/bst.ts index 5d60225..6efe2d2 100644 --- a/src/types/data-structures/binary-tree/bst.ts +++ b/src/types/data-structures/binary-tree/bst.ts @@ -1,7 +1,7 @@ import {BSTNode} from '../../../data-structures'; -import type {BinaryTreeNodeKey, BinaryTreeOptions} from './binary-tree'; +import type {BTNKey, BinaryTreeOptions} from './binary-tree'; -export type BSTComparator = (a: BinaryTreeNodeKey, b: BinaryTreeNodeKey) => number; +export type BSTComparator = (a: BTNKey, b: BTNKey) => number; // prettier-ignore export type BSTNodeNested = BSTNode>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> diff --git a/src/types/data-structures/matrix/navigator.ts b/src/types/data-structures/matrix/navigator.ts index 34eddd9..9d8b9a9 100644 --- a/src/types/data-structures/matrix/navigator.ts +++ b/src/types/data-structures/matrix/navigator.ts @@ -1,6 +1,6 @@ export type Direction = 'up' | 'right' | 'down' | 'left'; -export type Turning = { [key in Direction]: Direction }; +export type Turning = {[key in Direction]: Direction}; export type NavigatorParams = { matrix: T[][]; diff --git a/src/types/helpers.ts b/src/types/helpers.ts index acd9a20..47ee910 100644 --- a/src/types/helpers.ts +++ b/src/types/helpers.ts @@ -2,7 +2,7 @@ export type Comparator = (a: T, b: T) => number; export type DFSOrderPattern = 'pre' | 'in' | 'post'; -export type OneParamCallback = (node: N) => D; +export type BTNCallback = (node: N) => D; export enum CP { lt = 'lt', diff --git a/src/types/utils/utils.ts b/src/types/utils/utils.ts index 1f3a505..f4d26c4 100644 --- a/src/types/utils/utils.ts +++ b/src/types/utils/utils.ts @@ -1,5 +1,5 @@ export type ToThunkFn = () => ReturnType; -export type Thunk = () => ReturnType & { __THUNK__: symbol }; +export type Thunk = () => ReturnType & {__THUNK__: symbol}; export type TrlFn = (...args: any[]) => any; export type TrlAsyncFn = (...args: any[]) => any; diff --git a/src/types/utils/validate-type.ts b/src/types/utils/validate-type.ts index 3ebf451..ac9ff28 100644 --- a/src/types/utils/validate-type.ts +++ b/src/types/utils/validate-type.ts @@ -1,6 +1,6 @@ -export type KeyValueObject = { [key: string]: any }; +export type KeyValueObject = {[key: string]: any}; -export type KeyValueObjectWithKey = { [key: string]: any; key: string | number | symbol }; +export type KeyValueObjectWithKey = {[key: string]: any; key: string | number | symbol}; export type NonNumberNonObjectButDefined = string | boolean | symbol | null; diff --git a/test/integration/bst.test.ts b/test/integration/bst.test.ts index 35a6061..0a33db7 100644 --- a/test/integration/bst.test.ts +++ b/test/integration/bst.test.ts @@ -183,7 +183,7 @@ describe('Individual package BST operations test', () => { }); it('should perform various operations on a Binary Search Tree with object values', () => { - const objBST = new BST<{ key: number; keyA: number }>(); + const objBST = new BST<{key: number; keyA: number}>(); expect(objBST).toBeInstanceOf(BST); objBST.add(11, {key: 11, keyA: 11}); objBST.add(3, {key: 3, keyA: 3}); diff --git a/test/unit/data-structures/binary-tree/avl-tree.test.ts b/test/unit/data-structures/binary-tree/avl-tree.test.ts index 8a7bec9..e7e7d00 100644 --- a/test/unit/data-structures/binary-tree/avl-tree.test.ts +++ b/test/unit/data-structures/binary-tree/avl-tree.test.ts @@ -219,7 +219,7 @@ describe('AVL Tree Test recursively', () => { }); describe('AVLTree APIs test', () => { - const avl = new AVLTree<{ id: number; text: string }>(); + const avl = new AVLTree<{id: number; text: string}>(); beforeEach(() => { avl.clear(); }); diff --git a/test/unit/data-structures/binary-tree/binary-tree.test.ts b/test/unit/data-structures/binary-tree/binary-tree.test.ts index 64ac3f6..3759552 100644 --- a/test/unit/data-structures/binary-tree/binary-tree.test.ts +++ b/test/unit/data-structures/binary-tree/binary-tree.test.ts @@ -71,10 +71,10 @@ describe('BinaryTreeNode', () => { }); describe('BinaryTree', () => { - let tree: BinaryTree; + let tree: BinaryTree; beforeEach(() => { - tree = new BinaryTree(); + tree = new BinaryTree(); }); afterEach(() => { @@ -99,16 +99,18 @@ describe('BinaryTree', () => { }); it('should add and find nodes', () => { - tree.add(1); - tree.add(2); - tree.add(3); + tree.add(1, 1); + tree.add(2, 2); + tree.add(3, 3); expect(tree.has(1)).toBe(true); expect(tree.has(2)).toBe(true); expect(tree.has(3)).toBe(true); expect(tree.has(4)).toBe(false); const node4 = tree.get(4); + expect(tree.has(node4)).toBe(false); expect(tree.has(node4, node => node)).toBe(false); + expect(tree.has('3', node => node.val?.toString())).toBe(true); }); it('should getDepth return correct depth', () => { @@ -241,7 +243,7 @@ describe('BinaryTree Morris Traversal', () => { }); describe('BinaryTree APIs test', () => { - const avl = new AVLTree<{ id: number; text: string }>(); + const avl = new AVLTree<{id: number; text: string}>(); beforeEach(() => { avl.clear(); }); @@ -265,10 +267,14 @@ describe('BinaryTree traversals', () => { const arr = [35, 20, 40, 15, 29, null, 50, null, 16, 28, 30, 45, 55]; tree.refill(arr); expect(tree.dfs(node => node.key, 'pre')).toEqual([35, 20, 15, 16, 29, 28, 30, 40, 50, 45, 55]); - expect(tree.dfs(node => node.key, 'pre', tree.root, IterationType.RECURSIVE)).toEqual([35, 20, 15, 16, 29, 28, 30, 40, 50, 45, 55]); + expect(tree.dfs(node => node.key, 'pre', tree.root, IterationType.RECURSIVE)).toEqual([ + 35, 20, 15, 16, 29, 28, 30, 40, 50, 45, 55 + ]); expect(tree.dfs(node => node.key, 'in')).toEqual([15, 16, 20, 28, 29, 30, 35, 40, 45, 50, 55]); expect(tree.dfs(node => node.key, 'post')).toEqual([16, 15, 28, 30, 29, 20, 45, 55, 50, 40, 35]); - expect(tree.dfs(node => node.key, 'post', tree.root, IterationType.RECURSIVE)).toEqual([16, 15, 28, 30, 29, 20, 45, 55, 50, 40, 35]); + expect(tree.dfs(node => node.key, 'post', tree.root, IterationType.RECURSIVE)).toEqual([ + 16, 15, 28, 30, 29, 20, 45, 55, 50, 40, 35 + ]); expect(tree.bfs(node => node.key, tree.root, IterationType.RECURSIVE)).toEqual([ 35, 20, 40, 15, 29, 50, 16, 28, 30, 45, 55 ]); diff --git a/test/unit/data-structures/binary-tree/bst.test.ts b/test/unit/data-structures/binary-tree/bst.test.ts index a4a59fa..b4d4a44 100644 --- a/test/unit/data-structures/binary-tree/bst.test.ts +++ b/test/unit/data-structures/binary-tree/bst.test.ts @@ -189,7 +189,7 @@ describe('BST operations test', () => { }); it('should perform various operations on a Binary Search Tree with object values', () => { - const objBST = new BST<{ key: number; keyA: number }>(); + const objBST = new BST<{key: number; keyA: number}>(); expect(objBST).toBeInstanceOf(BST); objBST.add(11, {key: 11, keyA: 11}); objBST.add(3, {key: 3, keyA: 3}); @@ -260,7 +260,7 @@ describe('BST operations test', () => { objBST.perfectlyBalance(); expect(objBST.isPerfectlyBalanced()).toBe(true); - const bfsNodesAfterBalanced: BSTNode<{ key: number; keyA: number }>[] = []; + const bfsNodesAfterBalanced: BSTNode<{key: number; keyA: number}>[] = []; objBST.bfs(node => bfsNodesAfterBalanced.push(node)); expect(bfsNodesAfterBalanced[0].key).toBe(8); expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16); @@ -385,7 +385,7 @@ describe('BST operations test', () => { expect(bfsIDs[1]).toBe(12); expect(bfsIDs[2]).toBe(16); - const bfsNodes: BSTNode<{ key: number; keyA: number }>[] = []; + const bfsNodes: BSTNode<{key: number; keyA: number}>[] = []; objBST.bfs(node => bfsNodes.push(node)); expect(bfsNodes[0].key).toBe(2); expect(bfsNodes[1].key).toBe(12); @@ -579,7 +579,7 @@ describe('BST operations test recursively', () => { }); it('should perform various operations on a Binary Search Tree with object values', () => { - const objBST = new BST<{ key: number; keyA: number }>(); + const objBST = new BST<{key: number; keyA: number}>(); expect(objBST).toBeInstanceOf(BST); objBST.add(11, {key: 11, keyA: 11}); objBST.add(3, {key: 3, keyA: 3}); @@ -650,7 +650,7 @@ describe('BST operations test recursively', () => { objBST.perfectlyBalance(); expect(objBST.isPerfectlyBalanced()).toBe(true); - const bfsNodesAfterBalanced: BSTNode<{ key: number; keyA: number }>[] = []; + const bfsNodesAfterBalanced: BSTNode<{key: number; keyA: number}>[] = []; objBST.bfs(node => bfsNodesAfterBalanced.push(node)); expect(bfsNodesAfterBalanced[0].key).toBe(8); expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16); @@ -775,7 +775,7 @@ describe('BST operations test recursively', () => { expect(bfsIDs[1]).toBe(12); expect(bfsIDs[2]).toBe(16); - const bfsNodes: BSTNode<{ key: number; keyA: number }>[] = []; + const bfsNodes: BSTNode<{key: number; keyA: number}>[] = []; objBST.bfs(node => bfsNodes.push(node)); expect(bfsNodes[0].key).toBe(2); expect(bfsNodes[1].key).toBe(12); diff --git a/test/unit/data-structures/binary-tree/overall.test.ts b/test/unit/data-structures/binary-tree/overall.test.ts index 8c1921c..520c2bc 100644 --- a/test/unit/data-structures/binary-tree/overall.test.ts +++ b/test/unit/data-structures/binary-tree/overall.test.ts @@ -29,7 +29,7 @@ describe('Overall BinaryTree Test', () => { bfsIDs[0] === 11; // true expect(bfsIDs[0]).toBe(11); - const objBST = new BST<{ key: number; keyA: number }>(); + const objBST = new BST<{key: number; keyA: number}>(); objBST.add(11, {key: 11, keyA: 11}); objBST.add(3, {key: 3, keyA: 3}); diff --git a/test/unit/data-structures/binary-tree/tree-multiset.test.ts b/test/unit/data-structures/binary-tree/tree-multiset.test.ts index 4cfe46f..ab90ae2 100644 --- a/test/unit/data-structures/binary-tree/tree-multiset.test.ts +++ b/test/unit/data-structures/binary-tree/tree-multiset.test.ts @@ -207,7 +207,7 @@ describe('TreeMultiset operations test', () => { }); it('should perform various operations on a Binary Search Tree with object values', () => { - const objTreeMultiset = new TreeMultiset<{ key: number; keyA: number }>(); + const objTreeMultiset = new TreeMultiset<{key: number; keyA: number}>(); expect(objTreeMultiset).toBeInstanceOf(TreeMultiset); objTreeMultiset.add(11, {key: 11, keyA: 11}); objTreeMultiset.add(3, {key: 3, keyA: 3}); @@ -447,7 +447,7 @@ describe('TreeMultiset operations test recursively', () => { }); it('should perform various operations on a Binary Search Tree with object values', () => { - const objTreeMultiset = new TreeMultiset<{ key: number; keyA: number }>(); + const objTreeMultiset = new TreeMultiset<{key: number; keyA: number}>(); expect(objTreeMultiset).toBeInstanceOf(TreeMultiset); objTreeMultiset.add(11, {key: 11, keyA: 11}); objTreeMultiset.add(3, {key: 3, keyA: 3}); diff --git a/test/unit/data-structures/hash/coordinate-map.test.ts b/test/unit/data-structures/hash/coordinate-map.test.ts index 81fb68e..672b2b7 100644 --- a/test/unit/data-structures/hash/coordinate-map.test.ts +++ b/test/unit/data-structures/hash/coordinate-map.test.ts @@ -57,7 +57,7 @@ describe('CoordinateMap', () => { class MyCoordinateMap extends CoordinateMap { constructor(joint?: string) { super(joint); - this._setJoint(joint += '-') + this._setJoint((joint += '-')); } } @@ -67,7 +67,7 @@ describe('CoordinateMap', () => { cMap.set([0, 0], 0); cMap.set([0, 1], 1); cMap.set([1, 1], 11); - }) + }); it('should joint to be *-', () => { expect(cMap.joint).toBe('*-'); }); diff --git a/test/unit/data-structures/hash/coordinate-set.test.ts b/test/unit/data-structures/hash/coordinate-set.test.ts index f9cce6c..a05ec04 100644 --- a/test/unit/data-structures/hash/coordinate-set.test.ts +++ b/test/unit/data-structures/hash/coordinate-set.test.ts @@ -44,7 +44,7 @@ describe('MyCoordinateSet', () => { class MyCoordinateSet extends CoordinateSet { constructor(joint?: string) { super(joint); - this._setJoint(joint += '-') + this._setJoint((joint += '-')); } } @@ -54,7 +54,7 @@ describe('MyCoordinateSet', () => { mySet.add([0, 0]); mySet.add([0, 1]); mySet.add([1, 1]); - }) + }); it('should joint to be *-', () => { expect(mySet.joint).toBe('*-'); }); diff --git a/test/unit/data-structures/heap/heap.test.ts b/test/unit/data-structures/heap/heap.test.ts index d827b91..19ed4dc 100644 --- a/test/unit/data-structures/heap/heap.test.ts +++ b/test/unit/data-structures/heap/heap.test.ts @@ -22,7 +22,7 @@ describe('Heap Operation Test', () => { }); it('should object heap work well', function () { - const minHeap = new MinHeap<{ a: string; key: number }>({comparator: (a, b) => a.key - b.key}); + const minHeap = new MinHeap<{a: string; key: number}>({comparator: (a, b) => a.key - b.key}); minHeap.add({key: 1, a: 'a1'}); minHeap.add({key: 6, a: 'a6'}); minHeap.add({key: 2, a: 'a2'}); @@ -37,7 +37,7 @@ describe('Heap Operation Test', () => { i++; } - const maxHeap = new MaxHeap<{ key: number; a: string }>({comparator: (a, b) => b.key - a.key}); + const maxHeap = new MaxHeap<{key: number; a: string}>({comparator: (a, b) => b.key - a.key}); maxHeap.add({key: 1, a: 'a1'}); maxHeap.add({key: 6, a: 'a6'}); maxHeap.add({key: 5, a: 'a5'}); diff --git a/test/unit/data-structures/linked-list/doubly-linked-list.test.ts b/test/unit/data-structures/linked-list/doubly-linked-list.test.ts index a2a19f3..7174969 100644 --- a/test/unit/data-structures/linked-list/doubly-linked-list.test.ts +++ b/test/unit/data-structures/linked-list/doubly-linked-list.test.ts @@ -7,7 +7,7 @@ describe('DoublyLinkedListNode', () => { expect(node1.val).toBe(2); node1.val = 1; expect(node1.val).toBe(1); - }) + }); }); describe('DoublyLinkedList Operation Test', () => { @@ -38,10 +38,8 @@ describe('DoublyLinkedList Operation Test', () => { expect(list.tail?.val).toBe(4); }); - it('should find null', () => { expect(list.find(val => val === 6)).toBe(null); - }); it('should indexOf -1', () => { @@ -60,13 +58,11 @@ describe('DoublyLinkedList Operation Test', () => { // @ts-ignore expect([...list]).toEqual([1, 2, 3, 4, 5]); }); - - }); describe('DoublyLinkedList Operation Test', () => { let list: DoublyLinkedList; - let objectList: DoublyLinkedList<{ keyA: number }>; + let objectList: DoublyLinkedList<{keyA: number}>; beforeEach(() => { list = new DoublyLinkedList(); diff --git a/test/unit/data-structures/linked-list/singly-linked-list.test.ts b/test/unit/data-structures/linked-list/singly-linked-list.test.ts index 8a4ada6..a3175d1 100644 --- a/test/unit/data-structures/linked-list/singly-linked-list.test.ts +++ b/test/unit/data-structures/linked-list/singly-linked-list.test.ts @@ -7,15 +7,15 @@ describe('SinglyLinkedListNode', () => { expect(node1.val).toBe(2); node1.val = 1; expect(node1.val).toBe(1); - }) + }); }); describe('SinglyLinkedList Operation Test', () => { let list: SinglyLinkedList; - let objectList: SinglyLinkedList<{ keyA: number }>; + let objectList: SinglyLinkedList<{keyA: number}>; beforeEach(() => { list = new SinglyLinkedList(); - objectList = new SinglyLinkedList<{ keyA: number }>(); + objectList = new SinglyLinkedList<{keyA: number}>(); }); describe('push', () => { @@ -446,7 +446,6 @@ describe('SinglyLinkedList', () => { expect(list.length).toBe(1); }); - it('should reverse the list', () => { list.push(1); list.push(2); @@ -457,7 +456,6 @@ describe('SinglyLinkedList', () => { // Add more assertions for reversed order. }); - it('should convert the list to an array', () => { list.push(1); list.push(2); @@ -475,13 +473,12 @@ describe('SinglyLinkedList', () => { expect(list.filter(val => val !== 2).toArray()).toEqual([1, 3]); }); - it('should forEach the list', () => { list.push(1); list.push(2); list.push(3); list.forEach(val => val++); - expect(list.toArray()).toEqual([1, 2, 3]) + expect(list.toArray()).toEqual([1, 2, 3]); }); it('should map the list', () => { diff --git a/test/unit/data-structures/priority-queue/max-priority-queue.test.ts b/test/unit/data-structures/priority-queue/max-priority-queue.test.ts index 8b2f287..26fd837 100644 --- a/test/unit/data-structures/priority-queue/max-priority-queue.test.ts +++ b/test/unit/data-structures/priority-queue/max-priority-queue.test.ts @@ -17,7 +17,7 @@ describe('MaxPriorityQueue Operation Test', () => { }); it('should add elements and maintain heap property in a object MaxPriorityQueue', () => { - const priorityQueue = new MaxPriorityQueue<{ keyA: number }>({comparator: (a, b) => b.keyA - a.keyA}); + const priorityQueue = new MaxPriorityQueue<{keyA: number}>({comparator: (a, b) => b.keyA - a.keyA}); priorityQueue.refill([{keyA: 5}, {keyA: 3}, {keyA: 1}]); priorityQueue.add({keyA: 7}); @@ -64,7 +64,7 @@ describe('MaxPriorityQueue Operation Test', () => { it('should correctly heapify an object array', () => { const nodes = [{keyA: 5}, {keyA: 3}, {keyA: 7}, {keyA: 1}]; - const maxPQ = MaxPriorityQueue.heapify<{ keyA: number }>({nodes: nodes, comparator: (a, b) => b.keyA - a.keyA}); + const maxPQ = MaxPriorityQueue.heapify<{keyA: number}>({nodes: nodes, comparator: (a, b) => b.keyA - a.keyA}); expect(maxPQ.poll()?.keyA).toBe(7); expect(maxPQ.poll()?.keyA).toBe(5); diff --git a/test/utils/big-o.ts b/test/utils/big-o.ts index cc9fc86..43d7eca 100644 --- a/test/utils/big-o.ts +++ b/test/utils/big-o.ts @@ -26,7 +26,7 @@ export const bigO = { function findPotentialN(input: any): number { let longestArray: any[] = []; - let mostProperties: { [key: string]: any } = {}; + let mostProperties: {[key: string]: any} = {}; function recurse(obj: any) { if (Array.isArray(obj)) { From c001251cfcc3e2dcd4d7f13018ba8523bb16d829 Mon Sep 17 00:00:00 2001 From: Revone Date: Mon, 30 Oct 2023 11:40:03 +0800 Subject: [PATCH 37/46] [binary-tree] this._defaultCallbackByKey deprecated --- CHANGELOG.md | 2 +- package-lock.json | 50 +++++++++---------- package.json | 10 ++-- src/data-structures/binary-tree/avl-tree.ts | 5 +- .../binary-tree/binary-tree.ts | 47 +++++++---------- src/data-structures/binary-tree/bst.ts | 12 ++--- .../binary-tree/tree-multiset.ts | 4 +- .../binary-tree/binary-tree.test.ts | 1 - 8 files changed, 61 insertions(+), 70 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4fb300d..5c67d7e 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.39.2](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) +## [v1.39.4](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) ### Changes diff --git a/package-lock.json b/package-lock.json index 608505b..6678db2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "data-structure-typed", - "version": "1.39.2", + "version": "1.39.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "data-structure-typed", - "version": "1.39.2", + "version": "1.39.4", "license": "MIT", "devDependencies": { "@types/benchmark": "^2.1.3", @@ -15,17 +15,17 @@ "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", "auto-changelog": "^2.4.0", - "avl-tree-typed": "^1.39.1", + "avl-tree-typed": "^1.39.3", "benchmark": "^2.1.4", - "binary-tree-typed": "^1.39.1", - "bst-typed": "^1.39.1", + "binary-tree-typed": "^1.39.3", + "bst-typed": "^1.39.3", "dependency-cruiser": "^14.1.0", "eslint": "^8.50.0", "eslint-config-prettier": "^9.0.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.28.1", - "heap-typed": "^1.39.1", + "heap-typed": "^1.39.3", "istanbul-badges-readme": "^1.8.5", "jest": "^29.7.0", "prettier": "^3.0.3", @@ -2728,12 +2728,12 @@ } }, "node_modules/avl-tree-typed": { - "version": "1.39.1", - "resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.39.1.tgz", - "integrity": "sha512-V4H5cBue8qzsUYzDIngPR6FJELuuMtwYSk34BdpgwPHpo79ZL0LqJmEiIY9FCmkoYPQFvZAz/Z7+RH9MJXgZPA==", + "version": "1.39.3", + "resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.39.3.tgz", + "integrity": "sha512-5tgPsLtuPkgLH6CDuz9OXGR+4AxXXdu6sOtQNrQeqvMkPlgkduxjOd5aMqAvCjkRKHZ3TjFi43sNEYRxzoQ6AQ==", "dev": true, "dependencies": { - "data-structure-typed": "^1.39.0" + "data-structure-typed": "^1.39.2" } }, "node_modules/babel-jest": { @@ -2927,12 +2927,12 @@ } }, "node_modules/binary-tree-typed": { - "version": "1.39.1", - "resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.39.1.tgz", - "integrity": "sha512-fbPwGQXmy9GKw/23yRm9c+9wDNgXbhvGUP6za0NQuo3kvJ522SAEzvgwPXEqO92RIKT/OpP0+aO5dpTJaOiodQ==", + "version": "1.39.3", + "resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.39.3.tgz", + "integrity": "sha512-bzNlbU5DVx0tK798O0loGfgFqFCTR/lHXptCEvU8YvQQ6E+/rv9zj926HHqQClU0vhtMdBQdQIoxJubGlYnwQQ==", "dev": true, "dependencies": { - "data-structure-typed": "^1.39.0" + "data-structure-typed": "^1.39.2" } }, "node_modules/brace-expansion": { @@ -3011,12 +3011,12 @@ } }, "node_modules/bst-typed": { - "version": "1.39.1", - "resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.39.1.tgz", - "integrity": "sha512-Oo86lN3GJIODrGHZSpNJZ7X1N1adgEpY8kd7jOvZd+zF2BHEJVpW8uTk3PtSgbCLGnEkSzE2lXWaaOZh5F9x1A==", + "version": "1.39.3", + "resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.39.3.tgz", + "integrity": "sha512-cb0ZMMBfITnStTek9oGxIQBK1ycqZsDzxwmgmNICRNVnrjA7RHa9jck3RIg0MTN/+W4DLTbZJDyqeUZwmWb+xQ==", "dev": true, "dependencies": { - "data-structure-typed": "^1.39.0" + "data-structure-typed": "^1.39.2" } }, "node_modules/buffer-from": { @@ -3413,9 +3413,9 @@ } }, "node_modules/data-structure-typed": { - "version": "1.39.1", - "resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.39.1.tgz", - "integrity": "sha512-zAotqpGJoWKG12b4pybA05oih3RAy50RlD++ye8M58AjcM5Aw8lZjWlsNmi+ICiAdq8P0xdJM6Z7/etysctJZg==", + "version": "1.39.2", + "resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.39.2.tgz", + "integrity": "sha512-KGr12Nntd4z8y9vQ+3q7t2vJ6rqjxKP0p/+arH2ZtuPn6HoQ9xZat2yRaHulQKeyiSIzYIpAlj5ZmFgaYRttrg==", "dev": true }, "node_modules/debug": { @@ -4771,12 +4771,12 @@ } }, "node_modules/heap-typed": { - "version": "1.39.1", - "resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.39.1.tgz", - "integrity": "sha512-+fKr3EKYNGLK9ZVLeZZFP58eKvGv/zWGYbBOZYIXkQZeBXtdL0b4rHL0LsoIpuyPMbhXDFNOhaasG4D1NbCu2Q==", + "version": "1.39.3", + "resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.39.3.tgz", + "integrity": "sha512-wq1d+5KwpCoY19Mls6e+ughQljwDNo3Z2TcPdmw0AYdXbEhajgaemggHbujxKpOB/r0iNaX4rdoGAm4HVJ3R3Q==", "dev": true, "dependencies": { - "data-structure-typed": "^1.39.0" + "data-structure-typed": "^1.39.2" } }, "node_modules/html-escaper": { diff --git a/package.json b/package.json index 33a2080..f14225c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "data-structure-typed", - "version": "1.39.3", + "version": "1.39.4", "description": "Data Structures of Javascript & TypeScript. Binary Tree, BST, Graph, Heap, Priority Queue, Linked List, Queue, Deque, Stack, AVL Tree, Tree Multiset, Trie, Directed Graph, Undirected Graph, Singly Linked List, Doubly Linked List, Max Heap, Max Priority Queue, Min Heap, Min Priority Queue.", "main": "dist/cjs/index.js", "module": "dist/mjs/index.js", @@ -61,17 +61,17 @@ "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", "auto-changelog": "^2.4.0", - "avl-tree-typed": "^1.39.1", + "avl-tree-typed": "^1.39.3", "benchmark": "^2.1.4", - "binary-tree-typed": "^1.39.1", - "bst-typed": "^1.39.1", + "binary-tree-typed": "^1.39.3", + "bst-typed": "^1.39.3", "dependency-cruiser": "^14.1.0", "eslint": "^8.50.0", "eslint-config-prettier": "^9.0.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.28.1", - "heap-typed": "^1.39.1", + "heap-typed": "^1.39.3", "istanbul-badges-readme": "^1.8.5", "jest": "^29.7.0", "prettier": "^3.0.3", diff --git a/src/data-structures/binary-tree/avl-tree.ts b/src/data-structures/binary-tree/avl-tree.ts index db9dd2a..4fc9324 100644 --- a/src/data-structures/binary-tree/avl-tree.ts +++ b/src/data-structures/binary-tree/avl-tree.ts @@ -71,13 +71,14 @@ export class AVLTree = AVLTreeNode node.key)` * @returns The method is returning an array of `BinaryTreeDeletedResult` objects. */ override delete>( identifier: ReturnType, - callback: C = this._defaultCallbackByKey as C + callback: C = ((node: N) => node.key) as C ): BinaryTreeDeletedResult[] { + if ((identifier as any) instanceof AVLTreeNode) callback = (node => node) as C; const deletedResults = super.delete(identifier, callback); for (const {needBalanced} of deletedResults) { if (needBalanced) { diff --git a/src/data-structures/binary-tree/binary-tree.ts b/src/data-structures/binary-tree/binary-tree.ts index 072e730..da5c9b3 100644 --- a/src/data-structures/binary-tree/binary-tree.ts +++ b/src/data-structures/binary-tree/binary-tree.ts @@ -217,7 +217,7 @@ export class BinaryTree = BinaryTreeNode } const key = typeof keyOrNode === 'number' ? keyOrNode : keyOrNode ? keyOrNode.key : undefined; - const existNode = key !== undefined ? this.get(key, this._defaultCallbackByKey) : undefined; + const existNode = key !== undefined ? this.get(key, (node: N) => node.key) : undefined; if (this.root) { if (existNode) { @@ -296,11 +296,11 @@ export class BinaryTree = BinaryTreeNode * @param callback - The `callback` parameter is a function that takes a node as input and returns a * value. This value is compared with the `identifier` parameter to determine if the node should be * included in the result. The `callback` parameter has a default value of - * `this._defaultCallbackByKey`, which + * `((node: N) => node.key)`, which */ delete>( identifier: ReturnType | null, - callback: C = this._defaultCallbackByKey as C + callback: C = ((node: N) => node.key) as C ): BinaryTreeDeletedResult[] { const bstDeletedResult: BinaryTreeDeletedResult[] = []; if (!this.root) return bstDeletedResult; @@ -487,7 +487,7 @@ export class BinaryTree = BinaryTreeNode getNodes>( identifier: BTNKey, - callback: C, + callback?: C, onlyOne?: boolean, beginRoot?: N | null, iterationType?: IterationType @@ -495,7 +495,7 @@ export class BinaryTree = BinaryTreeNode getNodes>( identifier: N | null, - callback: C, + callback?: C, onlyOne?: boolean, beginRoot?: N | null, iterationType?: IterationType @@ -518,7 +518,7 @@ export class BinaryTree = BinaryTreeNode * @param callback - The `callback` parameter is a function that takes a node as input and returns a * value. This value is compared with the `identifier` parameter to determine if the node should be * included in the result. The `callback` parameter has a default value of - * `this._defaultCallbackByKey`, which + * `((node: N) => node.key)`, which * @param [onlyOne=false] - A boolean value indicating whether to stop searching after finding the * first node that matches the identifier. If set to true, the function will return an array with * only one element (or an empty array if no matching node is found). If set to false (default), the @@ -532,7 +532,7 @@ export class BinaryTree = BinaryTreeNode */ getNodes>( identifier: ReturnType | null, - callback: C = this._defaultCallbackByKey as C, + callback: C = ((node: N) => node.key) as C, onlyOne = false, beginRoot: N | null = this.root, iterationType = this.iterationType @@ -600,7 +600,7 @@ export class BinaryTree = BinaryTreeNode * @param callback - The `callback` parameter is a function that is used to determine whether a node * matches the desired criteria. It takes a node as input and returns a boolean value indicating * whether the node matches the criteria or not. The default callback function - * `this._defaultCallbackByKey` is used if no callback function is + * `((node: N) => node.key)` is used if no callback function is * @param beginRoot - The `beginRoot` parameter is the starting point for the search. It specifies * the node from which the search should begin. By default, it is set to `this.root`, which means the * search will start from the root node of the binary tree. However, you can provide a different node @@ -611,7 +611,7 @@ export class BinaryTree = BinaryTreeNode */ has>( identifier: ReturnType | null, - callback: C = this._defaultCallbackByKey as C, + callback: C = ((node: N) => node.key) as C, beginRoot = this.root, iterationType = this.iterationType ): boolean { @@ -649,7 +649,7 @@ export class BinaryTree = BinaryTreeNode * @param callback - The `callback` parameter is a function that is used to determine whether a node * matches the desired criteria. It takes a node as input and returns a boolean value indicating * whether the node matches the criteria or not. The default callback function - * (`this._defaultCallbackByKey`) is used if no callback function is + * (`((node: N) => node.key)`) is used if no callback function is * @param beginRoot - The `beginRoot` parameter is the starting point for the search. It specifies * the root node from which the search should begin. * @param iterationType - The `iterationType` parameter specifies the type of iteration to be @@ -658,7 +658,7 @@ export class BinaryTree = BinaryTreeNode */ get>( identifier: ReturnType | null, - callback: C = this._defaultCallbackByKey as C, + callback: C = ((node: N) => node.key) as C, beginRoot = this.root, iterationType = this.iterationType ): N | null { @@ -824,7 +824,7 @@ export class BinaryTree = BinaryTreeNode * @returns The function `subTreeTraverse` returns an array of `ReturnType>`. */ subTreeTraverse>( - callback: C = this._defaultCallbackByKey as C, + callback: C = ((node: N) => node.key) as C, beginRoot: BTNKey | N | null = this.root, iterationType = this.iterationType ): ReturnType[] { @@ -860,7 +860,7 @@ export class BinaryTree = BinaryTreeNode * function on each node according to a specified order pattern. * @param callback - The `callback` parameter is a function that will be called on each node during * the depth-first search traversal. It takes a node as input and returns a value. The default value - * is `this._defaultCallbackByKey`, which is a callback function defined elsewhere in the code. + * is `((node: N) => node.key)`, which is a callback function defined elsewhere in the code. * @param {DFSOrderPattern} [pattern=in] - The `pattern` parameter determines the order in which the * nodes are visited during the depth-first search. There are three possible values for `pattern`: * @param {N | null} beginRoot - The `beginRoot` parameter is the starting node for the depth-first @@ -871,7 +871,7 @@ export class BinaryTree = BinaryTreeNode * @returns The function `dfs` returns an array of `ReturnType>` values. */ dfs>( - callback: C = this._defaultCallbackByKey as C, + callback: C = ((node: N) => node.key) as C, pattern: DFSOrderPattern = 'in', beginRoot: N | null = this.root, iterationType: IterationType = IterationType.ITERATIVE @@ -946,7 +946,7 @@ export class BinaryTree = BinaryTreeNode * function on each node. * @param callback - The `callback` parameter is a function that will be called for each node in the * breadth-first search. It takes a node of type `N` as its argument and returns a value of type - * `ReturnType>`. The default value for this parameter is `this._defaultCallbackByKey + * `ReturnType>`. The default value for this parameter is `((node: N) => node.key) * @param {N | null} beginRoot - The `beginRoot` parameter is the starting node for the breadth-first * search. It determines from which node the search will begin. If `beginRoot` is `null`, the search * will not be performed and an empty array will be returned. @@ -955,7 +955,7 @@ export class BinaryTree = BinaryTreeNode * @returns The function `bfs` returns an array of `ReturnType>[]`. */ bfs>( - callback: C = this._defaultCallbackByKey as C, + callback: C = ((node: N) => node.key) as C, beginRoot: N | null = this.root, iterationType = this.iterationType ): ReturnType[] { @@ -1012,7 +1012,7 @@ export class BinaryTree = BinaryTreeNode * function `C` applied to the nodes at that level. */ listLevels>( - callback: C = this._defaultCallbackByKey as C, + callback: C = ((node: N) => node.key) as C, beginRoot: N | null = this.root, iterationType = this.iterationType ): ReturnType[][] { @@ -1071,7 +1071,7 @@ export class BinaryTree = BinaryTreeNode * algorithm and returns an array of values obtained by applying a callback function to each node. * @param callback - The `callback` parameter is a function that will be called on each node in the * tree. It takes a node of type `N` as input and returns a value of type `ReturnType>`. The - * default value for this parameter is `this._defaultCallbackByKey`. + * default value for this parameter is `((node: N) => node.key)`. * @param {DFSOrderPattern} [pattern=in] - The `pattern` parameter in the `morris` function * determines the order in which the nodes of a binary tree are traversed. It can have one of the * following values: @@ -1081,7 +1081,7 @@ export class BinaryTree = BinaryTreeNode * @returns The `morris` function returns an array of `ReturnType>` values. */ morris>( - callback: C = this._defaultCallbackByKey as C, + callback: C = ((node: N) => node.key) as C, pattern: DFSOrderPattern = 'in', beginRoot: N | null = this.root ): ReturnType[] { @@ -1226,15 +1226,6 @@ export class BinaryTree = BinaryTreeNode return destNode; } - /** - * Time complexity is O(n) - * Space complexity of Iterative dfs equals to recursive dfs which is O(n) because of the stack - * The Morris algorithm only modifies the tree's structure during traversal; once the traversal is complete, - * the tree's structure should be restored to its original state to maintain the tree's integrity. - * This is because the purpose of the Morris algorithm is to save space rather than permanently alter the tree's shape. - */ - protected _defaultCallbackByKey: BTNCallback = node => node.key; - /** * The function `_addTo` adds a new node to a binary tree if there is an available position. * @param {N | null} newNode - The `newNode` parameter represents the node that you want to add to diff --git a/src/data-structures/binary-tree/bst.ts b/src/data-structures/binary-tree/bst.ts index 84a6944..4868953 100644 --- a/src/data-structures/binary-tree/bst.ts +++ b/src/data-structures/binary-tree/bst.ts @@ -234,7 +234,7 @@ export class BST = BSTNode> */ override get>( identifier: ReturnType | null, - callback: C = this._defaultCallbackByKey as C, + callback: C = ((node: N) => node.key) as C, beginRoot = this.root, iterationType = this.iterationType ): N | null { @@ -270,7 +270,7 @@ export class BST = BSTNode> * generic type `N`. * @param callback - The `callback` parameter is a function that takes a node as input and returns a * value. This value is compared with the `nodeProperty` parameter to determine if the node should be - * included in the result. The default value for `callback` is `this._defaultCallbackByKey`, which is + * included in the result. The default value for `callback` is `((node: N) => node.key)`, which is * a * @param [onlyOne=false] - A boolean value indicating whether to stop the traversal after finding * the first node that matches the nodeProperty. If set to true, the function will return an array @@ -285,7 +285,7 @@ export class BST = BSTNode> */ override getNodes>( identifier: ReturnType | null, - callback: C = this._defaultCallbackByKey as C, + callback: C = ((node: N) => node.key) as C, onlyOne = false, beginRoot: N | null = this.root, iterationType = this.iterationType @@ -303,7 +303,7 @@ export class BST = BSTNode> if (!cur.left && !cur.right) return; // TODO potential bug - if (callback === this._defaultCallbackByKey) { + if (callback === ((node: N) => node.key)) { if (this._compare(cur.key, identifier as number) === CP.gt) cur.left && _traverse(cur.left); if (this._compare(cur.key, identifier as number) === CP.lt) cur.right && _traverse(cur.right); } else { @@ -324,7 +324,7 @@ export class BST = BSTNode> if (onlyOne) return ans; } // TODO potential bug - if (callback === this._defaultCallbackByKey) { + if (callback === ((node: N) => node.key)) { if (this._compare(cur.key, identifier as number) === CP.gt) cur.left && queue.push(cur.left); if (this._compare(cur.key, identifier as number) === CP.lt) cur.right && queue.push(cur.right); } else { @@ -358,7 +358,7 @@ export class BST = BSTNode> * @returns The function `lesserOrGreaterTraverse` returns an array of `ReturnType>`. */ lesserOrGreaterTraverse>( - callback: C = this._defaultCallbackByKey as C, + callback: C = ((node: N) => node.key) as C, lesserOrGreater: CP = CP.lt, targetNode: BTNKey | N | null = this.root, iterationType = this.iterationType diff --git a/src/data-structures/binary-tree/tree-multiset.ts b/src/data-structures/binary-tree/tree-multiset.ts index 15b9a81..e196af7 100644 --- a/src/data-structures/binary-tree/tree-multiset.ts +++ b/src/data-structures/binary-tree/tree-multiset.ts @@ -268,7 +268,7 @@ export class TreeMultiset = TreeMultis * @param callback - The `callback` parameter is a function that takes a node as input and returns a * value. This value is compared with the `identifier` parameter to determine if the node should be * included in the result. The `callback` parameter has a default value of - * `this._defaultCallbackByKey` + * `((node: N) => node.key)` * @param [ignoreCount=false] - A boolean flag indicating whether to ignore the count of the node * being deleted. If set to true, the count of the node will not be considered and the node will be * deleted regardless of its count. If set to false (default), the count of the node will be @@ -277,7 +277,7 @@ export class TreeMultiset = TreeMultis */ override delete>( identifier: ReturnType, - callback: C = this._defaultCallbackByKey as C, + callback: C = ((node: N) => node.key) as C, ignoreCount = false ): BinaryTreeDeletedResult[] { const bstDeletedResult: BinaryTreeDeletedResult[] = []; diff --git a/test/unit/data-structures/binary-tree/binary-tree.test.ts b/test/unit/data-structures/binary-tree/binary-tree.test.ts index 3759552..2bd6647 100644 --- a/test/unit/data-structures/binary-tree/binary-tree.test.ts +++ b/test/unit/data-structures/binary-tree/binary-tree.test.ts @@ -480,7 +480,6 @@ describe('BinaryTree', () => { tree.delete(5); tree.delete(7); tree.delete(3); - expect(tree.root).toBe(null); expect(tree.getHeight()).toBe(-1); }); From d44788bea910ef2d057cc885bc6857c0b8075112 Mon Sep 17 00:00:00 2001 From: Revone Date: Mon, 30 Oct 2023 18:27:58 +0800 Subject: [PATCH 38/46] [graph] Modify the data structure design of the graph to change the generics of Vertex and Edge to defaults, where it is possible to only pass the value types of Vertex and Edge for increased usability. --- src/data-structures/graph/abstract-graph.ts | 268 +++++++++--------- src/data-structures/graph/directed-graph.ts | 179 ++++++------ src/data-structures/graph/map-graph.ts | 37 ++- src/data-structures/graph/undirected-graph.ts | 110 +++---- src/data-structures/queue/queue.ts | 2 +- src/interfaces/graph.ts | 6 +- .../graph/directed-graph.test.ts | 35 ++- .../data-structures/graph/map-graph.test.ts | 46 +-- .../graph/undirected-graph.test.ts | 4 +- test/unit/data-structures/queue/queue.test.ts | 16 +- 10 files changed, 357 insertions(+), 346 deletions(-) diff --git a/src/data-structures/graph/abstract-graph.ts b/src/data-structures/graph/abstract-graph.ts index d7d5b08..5b0aa79 100644 --- a/src/data-structures/graph/abstract-graph.ts +++ b/src/data-structures/graph/abstract-graph.ts @@ -45,29 +45,29 @@ export abstract class AbstractVertex { } } -export abstract class AbstractEdge { +export abstract class AbstractEdge { /** * The above function is a protected constructor that initializes the weight, value, and hash code properties of an * object. * @param {number} [weight] - The `weight` parameter is an optional number that represents the weight of the object. If * a value is provided, it will be assigned to the `_weight` property. If no value is provided, the default value of 1 * will be assigned. - * @param {V} [val] - The `val` parameter is of type `V`, which means it can be any type. It is an optional parameter, + * @param {VO} [val] - The `val` parameter is of type `VO`, which means it can be any type. It is an optional parameter, * meaning it can be omitted when creating an instance of the class. */ - protected constructor(weight?: number, val?: V) { + protected constructor(weight?: number, val?: VO) { this._weight = weight !== undefined ? weight : 1; this._val = val; this._hashCode = uuidV4(); } - private _val: V | undefined; + private _val: VO | undefined; - get val(): V | undefined { + get val(): VO | undefined { return this._val; } - set val(value: V | undefined) { + set val(value: VO | undefined) { this._val = value; } @@ -103,13 +103,15 @@ export abstract class AbstractEdge { } export abstract class AbstractGraph< - V extends AbstractVertex = AbstractVertex, - E extends AbstractEdge = AbstractEdge -> implements IGraph + V = any, + E = any, + VO extends AbstractVertex = AbstractVertex, + EO extends AbstractEdge = AbstractEdge +> implements IGraph { - private _vertices: Map = new Map(); + private _vertices: Map = new Map(); - get vertices(): Map { + get vertices(): Map { return this._vertices; } @@ -119,7 +121,7 @@ export abstract class AbstractGraph< * @param key * @param val */ - abstract createVertex(key: VertexKey, val?: V): V; + abstract createVertex(key: VertexKey, val?: V): VO; /** * In TypeScript, a subclass inherits the interface implementation of its parent class, without needing to implement the same interface again in the subclass. This behavior differs from Java's approach. In Java, if a parent class implements an interface, the subclass needs to explicitly implement the same interface, even if the parent class has already implemented it. @@ -129,21 +131,21 @@ export abstract class AbstractGraph< * @param weight * @param val */ - abstract createEdge(srcOrV1: VertexKey | string, destOrV2: VertexKey | string, weight?: number, val?: E): E; + abstract createEdge(srcOrV1: VertexKey | string, destOrV2: VertexKey | string, weight?: number, val?: E): EO; - abstract deleteEdge(edge: E): E | null; + abstract deleteEdge(edge: EO): EO | null; - abstract getEdge(srcOrKey: V | VertexKey, destOrKey: V | VertexKey): E | null; + abstract getEdge(srcOrKey: VO | VertexKey, destOrKey: VO | VertexKey): EO | null; - abstract degreeOf(vertexOrKey: V | VertexKey): number; + abstract degreeOf(vertexOrKey: VO | VertexKey): number; - abstract edgeSet(): E[]; + abstract edgeSet(): EO[]; - abstract edgesOf(vertexOrKey: V | VertexKey): E[]; + abstract edgesOf(vertexOrKey: VO | VertexKey): EO[]; - abstract getNeighbors(vertexOrKey: V | VertexKey): V[]; + abstract getNeighbors(vertexOrKey: VO | VertexKey): VO[]; - abstract getEndsOfEdge(edge: E): [V, V] | null; + abstract getEndsOfEdge(edge: EO): [VO, VO] | null; /** * The function "getVertex" returns the vertex with the specified ID or null if it doesn't exist. @@ -152,25 +154,25 @@ export abstract class AbstractGraph< * @returns The method `getVertex` returns the vertex with the specified `vertexKey` if it exists in the `_vertices` * map. If the vertex does not exist, it returns `null`. */ - getVertex(vertexKey: VertexKey): V | null { + getVertex(vertexKey: VertexKey): VO | null { return this._vertices.get(vertexKey) || null; } /** * The function checks if a vertex exists in a graph. - * @param {V | VertexKey} vertexOrKey - The parameter `vertexOrKey` can be either a vertex object (`V`) or a vertex ID + * @param {VO | VertexKey} vertexOrKey - The parameter `vertexOrKey` can be either a vertex object (`VO`) or a vertex ID * (`VertexKey`). * @returns a boolean value. */ - hasVertex(vertexOrKey: V | VertexKey): boolean { + hasVertex(vertexOrKey: VO | VertexKey): boolean { return this._vertices.has(this._getVertexKey(vertexOrKey)); } - addVertex(vertex: V): boolean; + addVertex(vertex: VO): boolean; - addVertex(key: VertexKey, val?: V['val']): boolean; + addVertex(key: VertexKey, val?: V): boolean; - addVertex(keyOrVertex: VertexKey | V, val?: V['val']): boolean { + addVertex(keyOrVertex: VertexKey | VO, val?: V): boolean { if (keyOrVertex instanceof AbstractVertex) { return this._addVertexOnly(keyOrVertex); } else { @@ -181,23 +183,23 @@ export abstract class AbstractGraph< /** * The `deleteVertex` function removes a vertex from a graph by its ID or by the vertex object itself. - * @param {V | VertexKey} vertexOrKey - The parameter `vertexOrKey` can be either a vertex object (`V`) or a vertex ID + * @param {VO | VertexKey} vertexOrKey - The parameter `vertexOrKey` can be either a vertex object (`VO`) or a vertex ID * (`VertexKey`). * @returns The method is returning a boolean value. */ - deleteVertex(vertexOrKey: V | VertexKey): boolean { + deleteVertex(vertexOrKey: VO | VertexKey): boolean { const vertexKey = this._getVertexKey(vertexOrKey); return this._vertices.delete(vertexKey); } /** * The function removes all vertices from a graph and returns a boolean indicating if any vertices were removed. - * @param {V[] | VertexKey[]} vertices - The `vertices` parameter can be either an array of vertices (`V[]`) or an array + * @param {VO[] | VertexKey[]} vertices - The `vertices` parameter can be either an array of vertices (`VO[]`) or an array * of vertex IDs (`VertexKey[]`). * @returns a boolean value. It returns true if at least one vertex was successfully removed, and false if no vertices * were removed. */ - removeManyVertices(vertices: V[] | VertexKey[]): boolean { + removeManyVertices(vertices: VO[] | VertexKey[]): boolean { const removed: boolean[] = []; for (const v of vertices) { removed.push(this.deleteVertex(v)); @@ -207,22 +209,22 @@ export abstract class AbstractGraph< /** * The function checks if there is an edge between two vertices and returns a boolean value indicating the result. - * @param {VertexKey | V} v1 - The parameter v1 can be either a VertexKey or a V. A VertexKey represents the unique - * identifier of a vertex in a graph, while V represents the type of the vertex object itself. - * @param {VertexKey | V} v2 - The parameter `v2` represents the second vertex in the edge. It can be either a - * `VertexKey` or a `V` type, which represents the type of the vertex. + * @param {VertexKey | VO} v1 - The parameter v1 can be either a VertexKey or a VO. A VertexKey represents the unique + * identifier of a vertex in a graph, while VO represents the type of the vertex object itself. + * @param {VertexKey | VO} v2 - The parameter `v2` represents the second vertex in the edge. It can be either a + * `VertexKey` or a `VO` type, which represents the type of the vertex. * @returns A boolean value is being returned. */ - hasEdge(v1: VertexKey | V, v2: VertexKey | V): boolean { + hasEdge(v1: VertexKey | VO, v2: VertexKey | VO): boolean { const edge = this.getEdge(v1, v2); return !!edge; } - addEdge(edge: E): boolean; + addEdge(edge: EO): boolean; - addEdge(src: V | VertexKey, dest: V | VertexKey, weight?: number, val?: E['val']): boolean; + addEdge(src: VO | VertexKey, dest: VO | VertexKey, weight?: number, val?: E): boolean; - addEdge(srcOrEdge: V | VertexKey | E, dest?: V | VertexKey, weight?: number, val?: E['val']): boolean { + addEdge(srcOrEdge: VO | VertexKey | EO, dest?: VO | VertexKey, weight?: number, val?: E): boolean { if (srcOrEdge instanceof AbstractEdge) { return this._addEdgeOnly(srcOrEdge); } else { @@ -240,16 +242,16 @@ export abstract class AbstractGraph< /** * The function sets the weight of an edge between two vertices in a graph. - * @param {VertexKey | V} srcOrKey - The `srcOrKey` parameter can be either a `VertexKey` or a `V` object. It represents + * @param {VertexKey | VO} srcOrKey - The `srcOrKey` parameter can be either a `VertexKey` or a `VO` object. It represents * the source vertex of the edge. - * @param {VertexKey | V} destOrKey - The `destOrKey` parameter represents the destination vertex of the edge. It can be - * either a `VertexKey` or a vertex object `V`. + * @param {VertexKey | VO} destOrKey - The `destOrKey` parameter represents the destination vertex of the edge. It can be + * either a `VertexKey` or a vertex object `VO`. * @param {number} weight - The weight parameter represents the weight of the edge between the source vertex (srcOrKey) * and the destination vertex (destOrKey). * @returns a boolean value. If the edge exists between the source and destination vertices, the function will update * the weight of the edge and return true. If the edge does not exist, the function will return false. */ - setEdgeWeight(srcOrKey: VertexKey | V, destOrKey: VertexKey | V, weight: number): boolean { + setEdgeWeight(srcOrKey: VertexKey | VO, destOrKey: VertexKey | VO, weight: number): boolean { const edge = this.getEdge(srcOrKey, destOrKey); if (edge) { edge.weight = weight; @@ -261,20 +263,20 @@ export abstract class AbstractGraph< /** * The function `getAllPathsBetween` finds all paths between two vertices in a graph using depth-first search. - * @param {V | VertexKey} v1 - The parameter `v1` represents either a vertex object (`V`) or a vertex ID (`VertexKey`). + * @param {VO | VertexKey} v1 - The parameter `v1` represents either a vertex object (`VO`) or a vertex ID (`VertexKey`). * It is the starting vertex for finding paths. - * @param {V | VertexKey} v2 - The parameter `v2` represents either a vertex object (`V`) or a vertex ID (`VertexKey`). - * @returns The function `getAllPathsBetween` returns an array of arrays of vertices (`V[][]`). + * @param {VO | VertexKey} v2 - The parameter `v2` represents either a vertex object (`VO`) or a vertex ID (`VertexKey`). + * @returns The function `getAllPathsBetween` returns an array of arrays of vertices (`VO[][]`). */ - getAllPathsBetween(v1: V | VertexKey, v2: V | VertexKey): V[][] { - const paths: V[][] = []; + getAllPathsBetween(v1: VO | VertexKey, v2: VO | VertexKey): VO[][] { + const paths: VO[][] = []; const vertex1 = this._getVertex(v1); const vertex2 = this._getVertex(v2); if (!(vertex1 && vertex2)) { return []; } - const dfs = (cur: V, dest: V, visiting: Map, path: V[]) => { + const dfs = (cur: VO, dest: VO, visiting: Map, path: VO[]) => { visiting.set(cur, true); if (cur === dest) { @@ -286,23 +288,23 @@ export abstract class AbstractGraph< if (!visiting.get(neighbor)) { path.push(neighbor); dfs(neighbor, dest, visiting, path); - arrayRemove(path, (vertex: V) => vertex === neighbor); + arrayRemove(path, (vertex: VO) => vertex === neighbor); } } visiting.set(cur, false); }; - dfs(vertex1, vertex2, new Map(), []); + dfs(vertex1, vertex2, new Map(), []); return paths; } /** * The function calculates the sum of weights along a given path. - * @param {V[]} path - An array of vertices (V) representing a path in a graph. + * @param {VO[]} path - An array of vertices (VO) representing a path in a graph. * @returns The function `getPathSumWeight` returns the sum of the weights of the edges in the given path. */ - getPathSumWeight(path: V[]): number { + getPathSumWeight(path: VO[]): number { let sum = 0; for (let i = 0; i < path.length; i++) { sum += this.getEdge(path[i], path[i + 1])?.weight || 0; @@ -313,8 +315,8 @@ export abstract class AbstractGraph< /** * The function `getMinCostBetween` calculates the minimum cost between two vertices in a graph, either based on edge * weights or using a breadth-first search algorithm. - * @param {V | VertexKey} v1 - The parameter `v1` represents the starting vertex or its ID. - * @param {V | VertexKey} v2 - The parameter `v2` represents the destination vertex or its ID. It is the vertex to which + * @param {VO | VertexKey} v1 - The parameter `v1` represents the starting vertex or its ID. + * @param {VO | VertexKey} v2 - The parameter `v2` represents the destination vertex or its ID. It is the vertex to which * you want to find the minimum cost or weight from the source vertex `v1`. * @param {boolean} [isWeight] - isWeight is an optional parameter that indicates whether the graph edges have weights. * If isWeight is set to true, the function will calculate the minimum cost between v1 and v2 based on the weights of @@ -324,7 +326,7 @@ export abstract class AbstractGraph< * vertices. If `isWeight` is `false` or not provided, it uses a breadth-first search (BFS) algorithm to calculate the * minimum number of */ - getMinCostBetween(v1: V | VertexKey, v2: V | VertexKey, isWeight?: boolean): number | null { + getMinCostBetween(v1: VO | VertexKey, v2: VO | VertexKey, isWeight?: boolean): number | null { if (isWeight === undefined) isWeight = false; if (isWeight) { @@ -342,8 +344,8 @@ export abstract class AbstractGraph< return null; } - const visited: Map = new Map(); - const queue = new Queue([vertex1]); + const visited: Map = new Map(); + const queue = new Queue([vertex1]); visited.set(vertex1, true); let cost = 0; while (queue.size > 0) { @@ -372,17 +374,17 @@ export abstract class AbstractGraph< /** * The function `getMinPathBetween` returns the minimum path between two vertices in a graph, either based on weight or * using a breadth-first search algorithm. - * @param {V | VertexKey} v1 - The parameter `v1` represents the starting vertex of the path. It can be either a vertex - * object (`V`) or a vertex ID (`VertexKey`). - * @param {V | VertexKey} v2 - V | VertexKey - The second vertex or vertex ID between which we want to find the minimum + * @param {VO | VertexKey} v1 - The parameter `v1` represents the starting vertex of the path. It can be either a vertex + * object (`VO`) or a vertex ID (`VertexKey`). + * @param {VO | VertexKey} v2 - VO | VertexKey - The second vertex or vertex ID between which we want to find the minimum * path. * @param {boolean} [isWeight] - A boolean flag indicating whether to consider the weight of edges in finding the * minimum path. If set to true, the function will use Dijkstra's algorithm to find the minimum weighted path. If set * to false, the function will use breadth-first search (BFS) to find the minimum path. - * @returns The function `getMinPathBetween` returns an array of vertices (`V[]`) representing the minimum path between + * @returns The function `getMinPathBetween` returns an array of vertices (`VO[]`) representing the minimum path between * two vertices (`v1` and `v2`). If there is no path between the vertices, it returns `null`. */ - getMinPathBetween(v1: V | VertexKey, v2: V | VertexKey, isWeight?: boolean): V[] | null { + getMinPathBetween(v1: VO | VertexKey, v2: VO | VertexKey, isWeight?: boolean): VO[] | null { if (isWeight === undefined) isWeight = false; if (isWeight) { @@ -401,14 +403,14 @@ export abstract class AbstractGraph< return allPaths[minIndex] || null; } else { // BFS - let minPath: V[] = []; + let minPath: VO[] = []; const vertex1 = this._getVertex(v1); const vertex2 = this._getVertex(v2); if (!(vertex1 && vertex2)) { return []; } - const dfs = (cur: V, dest: V, visiting: Map, path: V[]) => { + const dfs = (cur: VO, dest: VO, visiting: Map, path: VO[]) => { visiting.set(cur, true); if (cur === dest) { @@ -421,29 +423,29 @@ export abstract class AbstractGraph< if (!visiting.get(neighbor)) { path.push(neighbor); dfs(neighbor, dest, visiting, path); - arrayRemove(path, (vertex: V) => vertex === neighbor); + arrayRemove(path, (vertex: VO) => vertex === neighbor); } } visiting.set(cur, false); }; - dfs(vertex1, vertex2, new Map(), []); + dfs(vertex1, vertex2, new Map(), []); return minPath; } } /** - * Dijkstra algorithm time: O(VE) space: O(V + E) + * Dijkstra algorithm time: O(VE) space: O(VO + EO) * / /** - * Dijkstra algorithm time: O(VE) space: O(V + E) + * Dijkstra algorithm time: O(VE) space: O(VO + EO) * The function `dijkstraWithoutHeap` implements Dijkstra's algorithm to find the shortest path between two vertices in * a graph without using a heap data structure. - * @param {V | VertexKey} src - The source vertex from which to start the Dijkstra's algorithm. It can be either a + * @param {VO | VertexKey} src - The source vertex from which to start the Dijkstra's algorithm. It can be either a * vertex object or a vertex ID. - * @param {V | VertexKey | null} [dest] - The `dest` parameter in the `dijkstraWithoutHeap` function is an optional + * @param {VO | VertexKey | null} [dest] - The `dest` parameter in the `dijkstraWithoutHeap` function is an optional * parameter that specifies the destination vertex for the Dijkstra algorithm. It can be either a vertex object or its * identifier. If no destination is provided, the value is set to `null`. * @param {boolean} [getMinDist] - The `getMinDist` parameter is a boolean flag that determines whether the minimum @@ -452,27 +454,27 @@ export abstract class AbstractGraph< * @param {boolean} [genPaths] - The `genPaths` parameter is a boolean flag that determines whether or not to generate * paths in the Dijkstra algorithm. If `genPaths` is set to `true`, the algorithm will calculate and return the * shortest paths from the source vertex to all other vertices in the graph. If `genPaths - * @returns The function `dijkstraWithoutHeap` returns an object of type `DijkstraResult`. + * @returns The function `dijkstraWithoutHeap` returns an object of type `DijkstraResult`. */ dijkstraWithoutHeap( - src: V | VertexKey, - dest?: V | VertexKey | null, + src: VO | VertexKey, + dest?: VO | VertexKey | null, getMinDist?: boolean, genPaths?: boolean - ): DijkstraResult { + ): DijkstraResult { if (getMinDist === undefined) getMinDist = false; if (genPaths === undefined) genPaths = false; if (dest === undefined) dest = null; let minDist = Infinity; - let minDest: V | null = null; - let minPath: V[] = []; - const paths: V[][] = []; + let minDest: VO | null = null; + let minPath: VO[] = []; + const paths: VO[][] = []; const vertices = this._vertices; - const distMap: Map = new Map(); - const seen: Set = new Set(); - const preMap: Map = new Map(); // predecessor + const distMap: Map = new Map(); + const seen: Set = new Set(); + const preMap: Map = new Map(); // predecessor const srcVertex = this._getVertex(src); const destVertex = dest ? this._getVertex(dest) : null; @@ -490,7 +492,7 @@ export abstract class AbstractGraph< const getMinOfNoSeen = () => { let min = Infinity; - let minV: V | null = null; + let minV: VO | null = null; for (const [key, val] of distMap) { if (!seen.has(key)) { if (val < min) { @@ -502,12 +504,12 @@ export abstract class AbstractGraph< return minV; }; - const getPaths = (minV: V | null) => { + const getPaths = (minV: VO | null) => { for (const vertex of vertices) { const vertexOrKey = vertex[1]; if (vertexOrKey instanceof AbstractVertex) { - const path: V[] = [vertexOrKey]; + const path: VO[] = [vertexOrKey]; let parent = preMap.get(vertexOrKey); while (parent) { path.push(parent); @@ -569,11 +571,11 @@ export abstract class AbstractGraph< } /** - * Dijkstra algorithm time: O(logVE) space: O(V + E) + * Dijkstra algorithm time: O(logVE) space: O(VO + EO) * * Dijkstra's algorithm only solves the single-source shortest path problem, while the Bellman-Ford algorithm and Floyd-Warshall algorithm can address shortest paths between all pairs of nodes. * Dijkstra's algorithm is suitable for graphs with non-negative edge weights, whereas the Bellman-Ford algorithm and Floyd-Warshall algorithm can handle negative-weight edges. - * The time complexity of Dijkstra's algorithm and the Bellman-Ford algorithm depends on the size of the graph, while the time complexity of the Floyd-Warshall algorithm is O(V^3), where V is the number of nodes. For dense graphs, Floyd-Warshall might become slower. + * The time complexity of Dijkstra's algorithm and the Bellman-Ford algorithm depends on the size of the graph, while the time complexity of the Floyd-Warshall algorithm is O(VO^3), where VO is the number of nodes. For dense graphs, Floyd-Warshall might become slower. * * / @@ -581,9 +583,9 @@ export abstract class AbstractGraph< * Dijkstra's algorithm is used to find the shortest paths from a source node to all other nodes in a graph. Its basic idea is to repeatedly choose the node closest to the source node and update the distances of other nodes using this node as an intermediary. Dijkstra's algorithm requires that the edge weights in the graph are non-negative. * The `dijkstra` function implements Dijkstra's algorithm to find the shortest path between a source vertex and an * optional destination vertex, and optionally returns the minimum distance, the paths, and other information. - * @param {V | VertexKey} src - The `src` parameter represents the source vertex from which the Dijkstra algorithm will + * @param {VO | VertexKey} src - The `src` parameter represents the source vertex from which the Dijkstra algorithm will * start. It can be either a vertex object or a vertex ID. - * @param {V | VertexKey | null} [dest] - The `dest` parameter is the destination vertex or vertex ID. It specifies the + * @param {VO | VertexKey | null} [dest] - The `dest` parameter is the destination vertex or vertex ID. It specifies the * vertex to which the shortest path is calculated from the source vertex. If no destination is provided, the algorithm * will calculate the shortest paths to all other vertices from the source vertex. * @param {boolean} [getMinDist] - The `getMinDist` parameter is a boolean flag that determines whether the minimum @@ -592,26 +594,26 @@ export abstract class AbstractGraph< * @param {boolean} [genPaths] - The `genPaths` parameter is a boolean flag that determines whether or not to generate * paths in the Dijkstra algorithm. If `genPaths` is set to `true`, the algorithm will calculate and return the * shortest paths from the source vertex to all other vertices in the graph. If `genPaths - * @returns The function `dijkstra` returns an object of type `DijkstraResult`. + * @returns The function `dijkstra` returns an object of type `DijkstraResult`. */ dijkstra( - src: V | VertexKey, - dest?: V | VertexKey | null, + src: VO | VertexKey, + dest?: VO | VertexKey | null, getMinDist?: boolean, genPaths?: boolean - ): DijkstraResult { + ): DijkstraResult { if (getMinDist === undefined) getMinDist = false; if (genPaths === undefined) genPaths = false; if (dest === undefined) dest = null; let minDist = Infinity; - let minDest: V | null = null; - let minPath: V[] = []; - const paths: V[][] = []; + let minDest: VO | null = null; + let minPath: VO[] = []; + const paths: VO[][] = []; const vertices = this._vertices; - const distMap: Map = new Map(); - const seen: Set = new Set(); - const preMap: Map = new Map(); // predecessor + const distMap: Map = new Map(); + const seen: Set = new Set(); + const preMap: Map = new Map(); // predecessor const srcVertex = this._getVertex(src); const destVertex = dest ? this._getVertex(dest) : null; @@ -623,7 +625,7 @@ export abstract class AbstractGraph< if (vertexOrKey instanceof AbstractVertex) distMap.set(vertexOrKey, Infinity); } - const heap = new PriorityQueue<{key: number; val: V}>({comparator: (a, b) => a.key - b.key}); + const heap = new PriorityQueue<{key: number; val: VO}>({comparator: (a, b) => a.key - b.key}); heap.add({key: 0, val: srcVertex}); distMap.set(srcVertex, 0); @@ -631,14 +633,14 @@ export abstract class AbstractGraph< /** * The function `getPaths` retrieves all paths from vertices to a specified minimum vertex. - * @param {V | null} minV - The parameter `minV` is of type `V | null`. It represents the minimum vertex value or + * @param {VO | null} minV - The parameter `minV` is of type `VO | null`. It represents the minimum vertex value or * null. */ - const getPaths = (minV: V | null) => { + const getPaths = (minV: VO | null) => { for (const vertex of vertices) { const vertexOrKey = vertex[1]; if (vertexOrKey instanceof AbstractVertex) { - const path: V[] = [vertexOrKey]; + const path: VO[] = [vertexOrKey]; let parent = preMap.get(vertexOrKey); while (parent) { path.push(parent); @@ -706,17 +708,17 @@ export abstract class AbstractGraph< } /** - * BellmanFord time:O(VE) space:O(V) + * BellmanFord time:O(VE) space:O(VO) * one to rest pairs * / /** - * BellmanFord time:O(VE) space:O(V) + * BellmanFord time:O(VE) space:O(VO) * one to rest pairs * The Bellman-Ford algorithm is also used to find the shortest paths from a source node to all other nodes in a graph. Unlike Dijkstra's algorithm, it can handle edge weights that are negative. Its basic idea involves iterative relaxation of all edges for several rounds to gradually approximate the shortest paths. Due to its ability to handle negative-weight edges, the Bellman-Ford algorithm is more flexible in some scenarios. * The `bellmanFord` function implements the Bellman-Ford algorithm to find the shortest path from a source vertex to * all other vertices in a graph, and optionally detects negative cycles and generates the minimum path. - * @param {V | VertexKey} src - The `src` parameter is the source vertex from which the Bellman-Ford algorithm will + * @param {VO | VertexKey} src - The `src` parameter is the source vertex from which the Bellman-Ford algorithm will * start calculating the shortest paths. It can be either a vertex object or a vertex ID. * @param {boolean} [scanNegativeCycle] - A boolean flag indicating whether to scan for negative cycles in the graph. * @param {boolean} [getMin] - The `getMin` parameter is a boolean flag that determines whether the algorithm should @@ -726,16 +728,16 @@ export abstract class AbstractGraph< * vertex. * @returns The function `bellmanFord` returns an object with the following properties: */ - bellmanFord(src: V | VertexKey, scanNegativeCycle?: boolean, getMin?: boolean, genPath?: boolean) { + bellmanFord(src: VO | VertexKey, scanNegativeCycle?: boolean, getMin?: boolean, genPath?: boolean) { if (getMin === undefined) getMin = false; if (genPath === undefined) genPath = false; const srcVertex = this._getVertex(src); - const paths: V[][] = []; - const distMap: Map = new Map(); - const preMap: Map = new Map(); // predecessor + const paths: VO[][] = []; + const distMap: Map = new Map(); + const preMap: Map = new Map(); // predecessor let min = Infinity; - let minPath: V[] = []; + let minPath: VO[] = []; // TODO let hasNegativeCycle: boolean | undefined; if (scanNegativeCycle) hasNegativeCycle = false; @@ -770,7 +772,7 @@ export abstract class AbstractGraph< } } - let minDest: V | null = null; + let minDest: VO | null = null; if (getMin) { distMap.forEach((d, v) => { if (v !== srcVertex) { @@ -786,7 +788,7 @@ export abstract class AbstractGraph< for (const vertex of vertices) { const vertexOrKey = vertex[1]; if (vertexOrKey instanceof AbstractVertex) { - const path: V[] = [vertexOrKey]; + const path: VO[] = [vertexOrKey]; let parent = preMap.get(vertexOrKey); while (parent !== undefined) { path.push(parent); @@ -815,34 +817,34 @@ export abstract class AbstractGraph< } /** - * Dijkstra algorithm time: O(logVE) space: O(V + E) + * Dijkstra algorithm time: O(logVE) space: O(VO + EO) * / /** - * Dijkstra algorithm time: O(logVE) space: O(V + E) + * Dijkstra algorithm time: O(logVE) space: O(VO + EO) * Dijkstra's algorithm is used to find the shortest paths from a source node to all other nodes in a graph. Its basic idea is to repeatedly choose the node closest to the source node and update the distances of other nodes using this node as an intermediary. Dijkstra's algorithm requires that the edge weights in the graph are non-negative. */ /** - * BellmanFord time:O(VE) space:O(V) + * BellmanFord time:O(VE) space:O(VO) * one to rest pairs * The Bellman-Ford algorithm is also used to find the shortest paths from a source node to all other nodes in a graph. Unlike Dijkstra's algorithm, it can handle edge weights that are negative. Its basic idea involves iterative relaxation of all edges for several rounds to gradually approximate the shortest paths. Due to its ability to handle negative-weight edges, the Bellman-Ford algorithm is more flexible in some scenarios. * The `bellmanFord` function implements the Bellman-Ford algorithm to find the shortest path from a source vertex to */ /** - * Floyd algorithm time: O(V^3) space: O(V^2), not support graph with negative weight cycle + * Floyd algorithm time: O(VO^3) space: O(VO^2), not support graph with negative weight cycle * all pairs * The Floyd-Warshall algorithm is used to find the shortest paths between all pairs of nodes in a graph. It employs dynamic programming to compute the shortest paths from any node to any other node. The Floyd-Warshall algorithm's advantage lies in its ability to handle graphs with negative-weight edges, and it can simultaneously compute shortest paths between any two nodes. */ /** - * Floyd algorithm time: O(V^3) space: O(V^2), not support graph with negative weight cycle + * Floyd algorithm time: O(VO^3) space: O(VO^2), not support graph with negative weight cycle * all pairs * / /** - * Floyd algorithm time: O(V^3) space: O(V^2), not support graph with negative weight cycle + * Floyd algorithm time: O(VO^3) space: O(VO^2), not support graph with negative weight cycle * all pairs * The Floyd-Warshall algorithm is used to find the shortest paths between all pairs of nodes in a graph. It employs dynamic programming to compute the shortest paths from any node to any other node. The Floyd-Warshall algorithm's advantage lies in its ability to handle graphs with negative-weight edges, and it can simultaneously compute shortest paths between any two nodes. * The function implements the Floyd-Warshall algorithm to find the shortest path between all pairs of vertices in a @@ -852,12 +854,12 @@ export abstract class AbstractGraph< * `predecessor` property is a 2D array of vertices (or `null`) representing the predecessor vertices in the shortest * path between vertices in the */ - floyd(): {costs: number[][]; predecessor: (V | null)[][]} { + floyd(): {costs: number[][]; predecessor: (VO | null)[][]} { const idAndVertices = [...this._vertices]; const n = idAndVertices.length; const costs: number[][] = []; - const predecessor: (V | null)[][] = []; + const predecessor: (VO | null)[][] = []; // successors for (let i = 0; i < n; i++) { @@ -927,8 +929,8 @@ export abstract class AbstractGraph< if (needSCCs === undefined) needSCCs = defaultConfig; if (needCycles === undefined) needCycles = defaultConfig; - const dfnMap: Map = new Map(); - const lowMap: Map = new Map(); + const dfnMap: Map = new Map(); + const lowMap: Map = new Map(); const vertices = this._vertices; vertices.forEach(v => { dfnMap.set(v, -1); @@ -937,10 +939,10 @@ export abstract class AbstractGraph< const [root] = vertices.values(); - const articulationPoints: V[] = []; - const bridges: E[] = []; + const articulationPoints: VO[] = []; + const bridges: EO[] = []; let dfn = 0; - const dfs = (cur: V, parent: V | null) => { + const dfs = (cur: VO, parent: VO | null) => { dfn++; dfnMap.set(cur, dfn); lowMap.set(cur, dfn); @@ -983,10 +985,10 @@ export abstract class AbstractGraph< dfs(root, null); - let SCCs: Map = new Map(); + let SCCs: Map = new Map(); const getSCCs = () => { - const SCCs: Map = new Map(); + const SCCs: Map = new Map(); lowMap.forEach((low, vertex) => { if (!SCCs.has(low)) { SCCs.set(low, [vertex]); @@ -1001,9 +1003,9 @@ export abstract class AbstractGraph< SCCs = getSCCs(); } - const cycles: Map = new Map(); + const cycles: Map = new Map(); if (needCycles) { - let SCCs: Map = new Map(); + let SCCs: Map = new Map(); if (SCCs.size < 1) { SCCs = getSCCs(); } @@ -1018,9 +1020,9 @@ export abstract class AbstractGraph< return {dfnMap, lowMap, bridges, articulationPoints, SCCs, cycles}; } - protected abstract _addEdgeOnly(edge: E): boolean; + protected abstract _addEdgeOnly(edge: EO): boolean; - protected _addVertexOnly(newVertex: V): boolean { + protected _addVertexOnly(newVertex: VO): boolean { if (this.hasVertex(newVertex)) { return false; // throw (new Error('Duplicated vertex key is not allowed')); @@ -1029,16 +1031,16 @@ export abstract class AbstractGraph< return true; } - protected _getVertex(vertexOrKey: VertexKey | V): V | null { + protected _getVertex(vertexOrKey: VertexKey | VO): VO | null { const vertexKey = this._getVertexKey(vertexOrKey); return this._vertices.get(vertexKey) || null; } - protected _getVertexKey(vertexOrKey: V | VertexKey): VertexKey { + protected _getVertexKey(vertexOrKey: VO | VertexKey): VertexKey { return vertexOrKey instanceof AbstractVertex ? vertexOrKey.key : vertexOrKey; } - protected _setVertices(value: Map) { + protected _setVertices(value: Map) { this._vertices = value; } } diff --git a/src/data-structures/graph/directed-graph.ts b/src/data-structures/graph/directed-graph.ts index 175e6bc..32e522d 100644 --- a/src/data-structures/graph/directed-graph.ts +++ b/src/data-structures/graph/directed-graph.ts @@ -23,7 +23,7 @@ export class DirectedVertex extends AbstractVertex { } } -export class DirectedEdge extends AbstractEdge { +export class DirectedEdge extends AbstractEdge { /** * The constructor function initializes the source and destination vertices of an edge, along with an optional weight * and value. @@ -32,10 +32,10 @@ export class DirectedEdge extends AbstractEdge { * @param {VertexKey} dest - The `dest` parameter represents the destination vertex of an edge. It is of type * `VertexKey`, which is likely a unique identifier for a vertex in a graph. * @param {number} [weight] - The weight parameter is an optional number that represents the weight of the edge. - * @param {V} [val] - The `val` parameter is an optional parameter of type `V`. It represents the value associated with + * @param {E} [val] - The `val` parameter is an optional parameter of type `E`. It represents the value associated with * the edge. */ - constructor(src: VertexKey, dest: VertexKey, weight?: number, val?: V) { + constructor(src: VertexKey, dest: VertexKey, weight?: number, val?: E) { super(weight, val); this._src = src; this._dest = dest; @@ -62,9 +62,14 @@ export class DirectedEdge extends AbstractEdge { } } -export class DirectedGraph = DirectedVertex, E extends DirectedEdge = DirectedEdge> - extends AbstractGraph - implements IGraph +export class DirectedGraph< + V = any, + E = any, + VO extends DirectedVertex = DirectedVertex, + EO extends DirectedEdge = DirectedEdge + > + extends AbstractGraph + implements IGraph { /** * The constructor function initializes an instance of a class. @@ -73,15 +78,15 @@ export class DirectedGraph = DirectedVertex, E ext super(); } - private _outEdgeMap: Map = new Map(); + private _outEdgeMap: Map = new Map(); - get outEdgeMap(): Map { + get outEdgeMap(): Map { return this._outEdgeMap; } - private _inEdgeMap: Map = new Map(); + private _inEdgeMap: Map = new Map(); - get inEdgeMap(): Map { + get inEdgeMap(): Map { return this._inEdgeMap; } @@ -97,10 +102,10 @@ export class DirectedGraph = DirectedVertex, E ext * @param [val] - The 'val' parameter is an optional value that can be assigned to the vertex. If a value is provided, * it will be assigned to the 'val' property of the vertex. If no value is provided, the 'val' property will be * assigned the same value as the 'key' parameter - * @returns a new instance of a DirectedVertex object, casted as type V. + * @returns a new instance of a DirectedVertex object, casted as type VO. */ - createVertex(key: VertexKey, val?: V['val']): V { - return new DirectedVertex(key, val ?? key) as V; + createVertex(key: VertexKey, val?: V): VO { + return new DirectedVertex(key, val ?? key) as VO; } /** @@ -116,26 +121,26 @@ export class DirectedGraph = DirectedVertex, E ext * weight is provided, it defaults to 1. * @param [val] - The 'val' parameter is an optional value that can be assigned to the edge. It can be of any type and * is used to store additional information or data associated with the edge. - * @returns a new instance of a DirectedEdge object, casted as type E. + * @returns a new instance of a DirectedEdge object, casted as type EO. */ - createEdge(src: VertexKey, dest: VertexKey, weight?: number, val?: E['val']): E { - return new DirectedEdge(src, dest, weight ?? 1, val) as E; + createEdge(src: VertexKey, dest: VertexKey, weight?: number, val?: E): EO { + return new DirectedEdge(src, dest, weight ?? 1, val) as EO; } /** * The `getEdge` function retrieves an edge between two vertices based on their source and destination IDs. - * @param {V | null | VertexKey} srcOrKey - The source vertex or its ID. It can be either a vertex object or a vertex ID. - * @param {V | null | VertexKey} destOrKey - The `destOrKey` parameter in the `getEdge` function represents the - * destination vertex of the edge. It can be either a vertex object (`V`), a vertex ID (`VertexKey`), or `null` if the + * @param {VO | null | VertexKey} srcOrKey - The source vertex or its ID. It can be either a vertex object or a vertex ID. + * @param {VO | null | VertexKey} destOrKey - The `destOrKey` parameter in the `getEdge` function represents the + * destination vertex of the edge. It can be either a vertex object (`VO`), a vertex ID (`VertexKey`), or `null` if the * destination is not specified. * @returns the first edge found between the source and destination vertices, or null if no such edge is found. */ - getEdge(srcOrKey: V | null | VertexKey, destOrKey: V | null | VertexKey): E | null { - let edges: E[] = []; + getEdge(srcOrKey: VO | null | VertexKey, destOrKey: VO | null | VertexKey): EO | null { + let edges: EO[] = []; if (srcOrKey !== null && destOrKey !== null) { - const src: V | null = this._getVertex(srcOrKey); - const dest: V | null = this._getVertex(destOrKey); + const src: VO | null = this._getVertex(srcOrKey); + const dest: VO | null = this._getVertex(destOrKey); if (src && dest) { const srcOutEdges = this._outEdgeMap.get(src); @@ -150,49 +155,49 @@ export class DirectedGraph = DirectedVertex, E ext /** * The function removes an edge between two vertices in a graph and returns the removed edge. - * @param {V | VertexKey} srcOrKey - The source vertex or its ID. - * @param {V | VertexKey} destOrKey - The `destOrKey` parameter represents the destination vertex or its ID. - * @returns the removed edge (E) if it exists, or null if either the source or destination vertex does not exist. + * @param {VO | VertexKey} srcOrKey - The source vertex or its ID. + * @param {VO | VertexKey} destOrKey - The `destOrKey` parameter represents the destination vertex or its ID. + * @returns the removed edge (EO) if it exists, or null if either the source or destination vertex does not exist. */ - deleteEdgeSrcToDest(srcOrKey: V | VertexKey, destOrKey: V | VertexKey): E | null { - const src: V | null = this._getVertex(srcOrKey); - const dest: V | null = this._getVertex(destOrKey); - let removed: E | null = null; + deleteEdgeSrcToDest(srcOrKey: VO | VertexKey, destOrKey: VO | VertexKey): EO | null { + const src: VO | null = this._getVertex(srcOrKey); + const dest: VO | null = this._getVertex(destOrKey); + let removed: EO | null = null; if (!src || !dest) { return null; } const srcOutEdges = this._outEdgeMap.get(src); if (srcOutEdges) { - arrayRemove(srcOutEdges, (edge: E) => edge.dest === dest.key); + arrayRemove(srcOutEdges, (edge: EO) => edge.dest === dest.key); } const destInEdges = this._inEdgeMap.get(dest); if (destInEdges) { - removed = arrayRemove(destInEdges, (edge: E) => edge.src === src.key)[0] || null; + removed = arrayRemove(destInEdges, (edge: EO) => edge.src === src.key)[0] || null; } return removed; } /** * The function removes an edge from a graph and returns the removed edge, or null if the edge was not found. - * @param {E} edge - The `edge` parameter is an object that represents an edge in a graph. It has two properties: `src` + * @param {EO} edge - The `edge` parameter is an object that represents an edge in a graph. It has two properties: `src` * and `dest`, which represent the source and destination vertices of the edge, respectively. - * @returns The method `deleteEdge` returns the removed edge (`E`) if it exists, or `null` if the edge does not exist. + * @returns The method `deleteEdge` returns the removed edge (`EO`) if it exists, or `null` if the edge does not exist. */ - deleteEdge(edge: E): E | null { - let removed: E | null = null; + deleteEdge(edge: EO): EO | null { + let removed: EO | null = null; const src = this._getVertex(edge.src); const dest = this._getVertex(edge.dest); if (src && dest) { const srcOutEdges = this._outEdgeMap.get(src); if (srcOutEdges && srcOutEdges.length > 0) { - arrayRemove(srcOutEdges, (edge: E) => edge.src === src.key); + arrayRemove(srcOutEdges, (edge: EO) => edge.src === src.key); } const destInEdges = this._inEdgeMap.get(dest); if (destInEdges && destInEdges.length > 0) { - removed = arrayRemove(destInEdges, (edge: E) => edge.dest === dest.key)[0]; + removed = arrayRemove(destInEdges, (edge: EO) => edge.dest === dest.key)[0]; } } @@ -201,14 +206,14 @@ export class DirectedGraph = DirectedVertex, E ext /** * The function removes edges between two vertices and returns the removed edges. - * @param {VertexKey | V} v1 - The parameter `v1` can be either a `VertexKey` or a `V`. A `VertexKey` represents the - * unique identifier of a vertex in a graph, while `V` represents the actual vertex object. - * @param {VertexKey | V} v2 - The parameter `v2` represents either a `VertexKey` or a `V` object. It is used to specify + * @param {VertexKey | VO} v1 - The parameter `v1` can be either a `VertexKey` or a `VO`. A `VertexKey` represents the + * unique identifier of a vertex in a graph, while `VO` represents the actual vertex object. + * @param {VertexKey | VO} v2 - The parameter `v2` represents either a `VertexKey` or a `VO` object. It is used to specify * the second vertex in the edge that needs to be removed. - * @returns an array of removed edges (E[]). + * @returns an array of removed edges (EO[]). */ - deleteEdgesBetween(v1: VertexKey | V, v2: VertexKey | V): E[] { - const removed: E[] = []; + deleteEdgesBetween(v1: VertexKey | VO, v2: VertexKey | VO): EO[] { + const removed: EO[] = []; if (v1 && v2) { const v1ToV2 = this.deleteEdgeSrcToDest(v1, v2); @@ -223,11 +228,11 @@ export class DirectedGraph = DirectedVertex, E ext /** * The function `incomingEdgesOf` returns an array of incoming edges for a given vertex or vertex ID. - * @param {V | VertexKey} vertexOrKey - The parameter `vertexOrKey` can be either a vertex object (`V`) or a vertex ID + * @param {VO | VertexKey} vertexOrKey - The parameter `vertexOrKey` can be either a vertex object (`VO`) or a vertex ID * (`VertexKey`). - * @returns The method `incomingEdgesOf` returns an array of edges (`E[]`). + * @returns The method `incomingEdgesOf` returns an array of edges (`EO[]`). */ - incomingEdgesOf(vertexOrKey: V | VertexKey): E[] { + incomingEdgesOf(vertexOrKey: VO | VertexKey): EO[] { const target = this._getVertex(vertexOrKey); if (target) { return this.inEdgeMap.get(target) || []; @@ -237,11 +242,11 @@ export class DirectedGraph = DirectedVertex, E ext /** * The function `outgoingEdgesOf` returns an array of outgoing edges from a given vertex or vertex ID. - * @param {V | VertexKey} vertexOrKey - The parameter `vertexOrKey` can accept either a vertex object (`V`) or a vertex ID + * @param {VO | VertexKey} vertexOrKey - The parameter `vertexOrKey` can accept either a vertex object (`VO`) or a vertex ID * (`VertexKey`). - * @returns The method `outgoingEdgesOf` returns an array of edges (`E[]`). + * @returns The method `outgoingEdgesOf` returns an array of edges (`EO[]`). */ - outgoingEdgesOf(vertexOrKey: V | VertexKey): E[] { + outgoingEdgesOf(vertexOrKey: VO | VertexKey): EO[] { const target = this._getVertex(vertexOrKey); if (target) { return this._outEdgeMap.get(target) || []; @@ -251,69 +256,69 @@ export class DirectedGraph = DirectedVertex, E ext /** * The function "degreeOf" returns the total degree of a vertex, which is the sum of its out-degree and in-degree. - * @param {VertexKey | V} vertexOrKey - The parameter `vertexOrKey` can be either a `VertexKey` or a `V`. + * @param {VertexKey | VO} vertexOrKey - The parameter `vertexOrKey` can be either a `VertexKey` or a `VO`. * @returns The sum of the out-degree and in-degree of the specified vertex or vertex ID. */ - degreeOf(vertexOrKey: VertexKey | V): number { + degreeOf(vertexOrKey: VertexKey | VO): number { return this.outDegreeOf(vertexOrKey) + this.inDegreeOf(vertexOrKey); } /** * The function "inDegreeOf" returns the number of incoming edges for a given vertex. - * @param {VertexKey | V} vertexOrKey - The parameter `vertexOrKey` can be either a `VertexKey` or a `V`. + * @param {VertexKey | VO} vertexOrKey - The parameter `vertexOrKey` can be either a `VertexKey` or a `VO`. * @returns The number of incoming edges of the specified vertex or vertex ID. */ - inDegreeOf(vertexOrKey: VertexKey | V): number { + inDegreeOf(vertexOrKey: VertexKey | VO): number { return this.incomingEdgesOf(vertexOrKey).length; } /** * The function `outDegreeOf` returns the number of outgoing edges from a given vertex. - * @param {VertexKey | V} vertexOrKey - The parameter `vertexOrKey` can be either a `VertexKey` or a `V`. + * @param {VertexKey | VO} vertexOrKey - The parameter `vertexOrKey` can be either a `VertexKey` or a `VO`. * @returns The number of outgoing edges from the specified vertex or vertex ID. */ - outDegreeOf(vertexOrKey: VertexKey | V): number { + outDegreeOf(vertexOrKey: VertexKey | VO): number { return this.outgoingEdgesOf(vertexOrKey).length; } /** * The function "edgesOf" returns an array of both outgoing and incoming edges of a given vertex or vertex ID. - * @param {VertexKey | V} vertexOrKey - The parameter `vertexOrKey` can be either a `VertexKey` or a `V`. + * @param {VertexKey | VO} vertexOrKey - The parameter `vertexOrKey` can be either a `VertexKey` or a `VO`. * @returns The function `edgesOf` returns an array of edges. */ - edgesOf(vertexOrKey: VertexKey | V): E[] { + edgesOf(vertexOrKey: VertexKey | VO): EO[] { return [...this.outgoingEdgesOf(vertexOrKey), ...this.incomingEdgesOf(vertexOrKey)]; } /** * The function "getEdgeSrc" returns the source vertex of an edge, or null if the edge does not exist. - * @param {E} e - The parameter "e" is of type E, which represents an edge in a graph. - * @returns either a vertex object (V) or null. + * @param {EO} e - The parameter "e" is of type EO, which represents an edge in a graph. + * @returns either a vertex object (VO) or null. */ - getEdgeSrc(e: E): V | null { + getEdgeSrc(e: EO): VO | null { return this._getVertex(e.src); } /** * The function "getEdgeDest" returns the destination vertex of an edge. - * @param {E} e - The parameter "e" is of type "E", which represents an edge in a graph. - * @returns either a vertex object of type V or null. + * @param {EO} e - The parameter "e" is of type "EO", which represents an edge in a graph. + * @returns either a vertex object of type VO or null. */ - getEdgeDest(e: E): V | null { + getEdgeDest(e: EO): VO | null { return this._getVertex(e.dest); } /** * The function `getDestinations` returns an array of destination vertices connected to a given vertex. - * @param {V | VertexKey | null} vertex - The `vertex` parameter represents the starting vertex from which we want to - * find the destinations. It can be either a `V` object, a `VertexKey` value, or `null`. - * @returns an array of vertices (V[]). + * @param {VO | VertexKey | null} vertex - The `vertex` parameter represents the starting vertex from which we want to + * find the destinations. It can be either a `VO` object, a `VertexKey` value, or `null`. + * @returns an array of vertices (VO[]). */ - getDestinations(vertex: V | VertexKey | null): V[] { + getDestinations(vertex: VO | VertexKey | null): VO[] { if (vertex === null) { return []; } - const destinations: V[] = []; + const destinations: VO[] = []; const outgoingEdges = this.outgoingEdgesOf(vertex); for (const outEdge of outgoingEdges) { const child = this.getEdgeDest(outEdge); @@ -332,18 +337,18 @@ export class DirectedGraph = DirectedVertex, E ext * specified, the vertices themselves will be used for sorting. If 'key' is specified, the ids of * @returns an array of vertices or vertex IDs in topological order. If there is a cycle in the graph, it returns null. */ - topologicalSort(propertyName?: 'vertex' | 'key'): Array | null { + topologicalSort(propertyName?: 'vertex' | 'key'): Array | null { propertyName = propertyName ?? 'key'; // When judging whether there is a cycle in the undirected graph, all nodes with degree of **<= 1** are enqueued // When judging whether there is a cycle in the directed graph, all nodes with **in degree = 0** are enqueued - const statusMap: Map = new Map(); + const statusMap: Map = new Map(); for (const entry of this.vertices) { statusMap.set(entry[1], 0); } - let sorted: (V | VertexKey)[] = []; + let sorted: (VO | VertexKey)[] = []; let hasCycle = false; - const dfs = (cur: V | VertexKey) => { + const dfs = (cur: VO | VertexKey) => { statusMap.set(cur, 1); const children = this.getDestinations(cur); for (const child of children) { @@ -372,10 +377,10 @@ export class DirectedGraph = DirectedVertex, E ext /** * The `edgeSet` function returns an array of all the edges in the graph. - * @returns The `edgeSet()` method returns an array of edges (`E[]`). + * @returns The `edgeSet()` method returns an array of edges (`EO[]`). */ - edgeSet(): E[] { - let edges: E[] = []; + edgeSet(): EO[] { + let edges: EO[] = []; this._outEdgeMap.forEach(outEdges => { edges = [...edges, ...outEdges]; }); @@ -384,12 +389,12 @@ export class DirectedGraph = DirectedVertex, E ext /** * The function `getNeighbors` returns an array of neighboring vertices of a given vertex or vertex ID in a graph. - * @param {V | VertexKey} vertexOrKey - The parameter `vertexOrKey` can be either a vertex object (`V`) or a vertex ID + * @param {VO | VertexKey} vertexOrKey - The parameter `vertexOrKey` can be either a vertex object (`VO`) or a vertex ID * (`VertexKey`). - * @returns an array of vertices (V[]). + * @returns an array of vertices (VO[]). */ - getNeighbors(vertexOrKey: V | VertexKey): V[] { - const neighbors: V[] = []; + getNeighbors(vertexOrKey: VO | VertexKey): VO[] { + const neighbors: VO[] = []; const vertex = this._getVertex(vertexOrKey); if (vertex) { const outEdges = this.outgoingEdgesOf(vertex); @@ -407,11 +412,11 @@ export class DirectedGraph = DirectedVertex, E ext /** * The function "getEndsOfEdge" returns the source and destination vertices of an edge if it exists in the graph, * otherwise it returns null. - * @param {E} edge - The parameter `edge` is of type `E`, which represents an edge in a graph. - * @returns The function `getEndsOfEdge` returns an array containing two vertices `[V, V]` if the edge exists in the + * @param {EO} edge - The parameter `edge` is of type `EO`, which represents an edge in a graph. + * @returns The function `getEndsOfEdge` returns an array containing two vertices `[VO, VO]` if the edge exists in the * graph. If the edge does not exist, it returns `null`. */ - getEndsOfEdge(edge: E): [V, V] | null { + getEndsOfEdge(edge: EO): [VO, VO] | null { if (!this.hasEdge(edge.src, edge.dest)) { return null; } @@ -426,12 +431,12 @@ export class DirectedGraph = DirectedVertex, E ext /** * The function `_addEdgeOnly` adds an edge to a graph if the source and destination vertices exist. - * @param {E} edge - The parameter `edge` is of type `E`, which represents an edge in a graph. It is the edge that + * @param {EO} edge - The parameter `edge` is of type `EO`, which represents an edge in a graph. It is the edge that * needs to be added to the graph. * @returns a boolean value. It returns true if the edge was successfully added to the graph, and false if either the * source or destination vertex does not exist in the graph. */ - protected _addEdgeOnly(edge: E): boolean { + protected _addEdgeOnly(edge: EO): boolean { if (!(this.hasVertex(edge.src) && this.hasVertex(edge.dest))) { return false; } @@ -460,11 +465,11 @@ export class DirectedGraph = DirectedVertex, E ext } } - protected _setOutEdgeMap(value: Map) { + protected _setOutEdgeMap(value: Map) { this._outEdgeMap = value; } - protected _setInEdgeMap(value: Map) { + protected _setInEdgeMap(value: Map) { this._inEdgeMap = value; } } diff --git a/src/data-structures/graph/map-graph.ts b/src/data-structures/graph/map-graph.ts index 8d7d71e..6be80f6 100644 --- a/src/data-structures/graph/map-graph.ts +++ b/src/data-structures/graph/map-graph.ts @@ -14,7 +14,7 @@ export class MapVertex extends DirectedVertex { * @param {V} [val] - The "val" parameter is an optional value of type V. It is not required to be provided when * creating an instance of the class. */ - constructor(key: VertexKey, lat: number, long: number, val?: V) { + constructor(key: VertexKey, val: V, lat: number, long: number) { super(key, val); this._lat = lat; this._long = long; @@ -41,7 +41,7 @@ export class MapVertex extends DirectedVertex { } } -export class MapEdge extends DirectedEdge { +export class MapEdge extends DirectedEdge { /** * The constructor function initializes a new instance of a class with the given source, destination, weight, and * value. @@ -49,18 +49,20 @@ export class MapEdge extends DirectedEdge { * a graph. * @param {VertexKey} dest - The `dest` parameter is the identifier of the destination vertex for an edge. * @param {number} [weight] - The weight parameter is an optional number that represents the weight of the edge. - * @param {V} [val] - The "val" parameter is an optional parameter of type V. It is used to store additional + * @param {E} [val] - The "val" parameter is an optional parameter of type E. It is used to store additional * information or data associated with the edge. */ - constructor(src: VertexKey, dest: VertexKey, weight?: number, val?: V) { + constructor(src: VertexKey, dest: VertexKey, weight?: number, val?: E) { super(src, dest, weight, val); } } -export class MapGraph = MapVertex, E extends MapEdge = MapEdge> extends DirectedGraph< - V, - E -> { +export class MapGraph< + V = any, + E = any, + VO extends MapVertex = MapVertex, + EO extends MapEdge = MapEdge +> extends DirectedGraph { /** * The constructor function initializes the origin and bottomRight properties of a MapGraphCoordinate object. * @param {MapGraphCoordinate} origin - The `origin` parameter is a `MapGraphCoordinate` object that represents the @@ -101,19 +103,14 @@ export class MapGraph = MapVertex, E extends MapEd * @param {VertexKey} key - The key parameter is the unique identifier for the vertex. It is of type VertexKey, which could * be a string or a number depending on how you define it in your code. * @param [val] - The `val` parameter is an optional value that can be assigned to the `val` property of the vertex. It - * is of type `V['val']`, which means it should be of the same type as the `val` property of the vertex class `V`. + * is of type `V`, which means it should be of the same type as the `val` property of the vertex class `VO`. * @param {number} lat - The `lat` parameter represents the latitude of the vertex. It is a number that specifies the * position of the vertex on the Earth's surface in the north-south direction. * @param {number} long - The `long` parameter represents the longitude coordinate of the vertex. - * @returns The method is returning a new instance of the `MapVertex` class, casted as type `V`. + * @returns The method is returning a new instance of the `MapVertex` class, casted as type `VO`. */ - override createVertex( - key: VertexKey, - lat: number = this.origin[0], - long: number = this.origin[1], - val?: V['val'] - ): V { - return new MapVertex(key, lat, long, val) as V; + override createVertex(key: VertexKey, val?: V, lat: number = this.origin[0], long: number = this.origin[1]): VO { + return new MapVertex(key, val, lat, long) as VO; } /** @@ -126,9 +123,9 @@ export class MapGraph = MapVertex, E extends MapEd * If the weight is not provided, it can be set to a default value or left undefined. * @param [val] - The `val` parameter is an optional value that can be assigned to the edge. It can be of any type, * depending on the specific implementation of the `MapEdge` class. - * @returns a new instance of the `MapEdge` class, cast as type `E`. + * @returns a new instance of the `MapEdge` class, cast as type `EO`. */ - override createEdge(src: VertexKey, dest: VertexKey, weight?: number, val?: E['val']): E { - return new MapEdge(src, dest, weight, val) as E; + override createEdge(src: VertexKey, dest: VertexKey, weight?: number, val?: E): EO { + return new MapEdge(src, dest, weight, val) as EO; } } diff --git a/src/data-structures/graph/undirected-graph.ts b/src/data-structures/graph/undirected-graph.ts index 1380542..7adeb28 100644 --- a/src/data-structures/graph/undirected-graph.ts +++ b/src/data-structures/graph/undirected-graph.ts @@ -23,7 +23,7 @@ export class UndirectedVertex extends AbstractVertex { } } -export class UndirectedEdge extends AbstractEdge { +export class UndirectedEdge extends AbstractEdge { /** * The constructor function creates an instance of a class with two vertex IDs, an optional weight, and an optional * value. @@ -31,10 +31,10 @@ export class UndirectedEdge extends AbstractEdge { * @param {VertexKey} v2 - The parameter `v2` is a `VertexKey`, which represents the identifier of the second vertex in a * graph edge. * @param {number} [weight] - The weight parameter is an optional number that represents the weight of the edge. - * @param {V} [val] - The "val" parameter is an optional parameter of type V. It is used to store a value associated + * @param {E} [val] - The "val" parameter is an optional parameter of type E. It is used to store a value associated * with the edge. */ - constructor(v1: VertexKey, v2: VertexKey, weight?: number, val?: V) { + constructor(v1: VertexKey, v2: VertexKey, weight?: number, val?: E) { super(weight, val); this._vertices = [v1, v2]; } @@ -51,23 +51,25 @@ export class UndirectedEdge extends AbstractEdge { } export class UndirectedGraph< - V extends UndirectedVertex = UndirectedVertex, - E extends UndirectedEdge = UndirectedEdge + V = any, + E = any, + VO extends UndirectedVertex = UndirectedVertex, + EO extends UndirectedEdge = UndirectedEdge > - extends AbstractGraph - implements IGraph + extends AbstractGraph + implements IGraph { /** * The constructor initializes a new Map object to store edges. */ constructor() { super(); - this._edges = new Map(); + this._edges = new Map(); } - protected _edges: Map; + protected _edges: Map; - get edges(): Map { + get edges(): Map { return this._edges; } @@ -78,10 +80,10 @@ export class UndirectedGraph< * @param [val] - The `val` parameter is an optional value that can be assigned to the vertex. If a value is provided, * it will be used as the value of the vertex. If no value is provided, the `key` parameter will be used as the value of * the vertex. - * @returns The method is returning a new instance of the `UndirectedVertex` class, casted as type `V`. + * @returns The method is returning a new instance of the `UndirectedVertex` class, casted as type `VO`. */ - override createVertex(key: VertexKey, val?: V['val']): V { - return new UndirectedVertex(key, val ?? key) as V; + override createVertex(key: VertexKey, val?: VO['val']): VO { + return new UndirectedVertex(key, val ?? key) as VO; } /** @@ -92,26 +94,26 @@ export class UndirectedGraph< * no weight is provided, it defaults to 1. * @param [val] - The `val` parameter is an optional value that can be assigned to the edge. It can be of any type and * is used to store additional information or data associated with the edge. - * @returns a new instance of the `UndirectedEdge` class, which is casted as type `E`. + * @returns a new instance of the `UndirectedEdge` class, which is casted as type `EO`. */ - override createEdge(v1: VertexKey, v2: VertexKey, weight?: number, val?: E['val']): E { - return new UndirectedEdge(v1, v2, weight ?? 1, val) as E; + override createEdge(v1: VertexKey, v2: VertexKey, weight?: number, val?: EO['val']): EO { + return new UndirectedEdge(v1, v2, weight ?? 1, val) as EO; } /** * The function `getEdge` returns the first edge that connects two vertices, or null if no such edge exists. - * @param {V | null | VertexKey} v1 - The parameter `v1` represents a vertex or vertex ID. It can be of type `V` (vertex + * @param {VO | null | VertexKey} v1 - The parameter `v1` represents a vertex or vertex ID. It can be of type `VO` (vertex * object), `null`, or `VertexKey` (a string or number representing the ID of a vertex). - * @param {V | null | VertexKey} v2 - The parameter `v2` represents a vertex or vertex ID. It can be of type `V` (vertex + * @param {VO | null | VertexKey} v2 - The parameter `v2` represents a vertex or vertex ID. It can be of type `VO` (vertex * object), `null`, or `VertexKey` (vertex ID). - * @returns an edge (E) or null. + * @returns an edge (EO) or null. */ - getEdge(v1: V | null | VertexKey, v2: V | null | VertexKey): E | null { - let edges: E[] | undefined = []; + getEdge(v1: VO | null | VertexKey, v2: VO | null | VertexKey): EO | null { + let edges: EO[] | undefined = []; if (v1 !== null && v2 !== null) { - const vertex1: V | null = this._getVertex(v1); - const vertex2: V | null = this._getVertex(v2); + const vertex1: VO | null = this._getVertex(v1); + const vertex2: VO | null = this._getVertex(v2); if (vertex1 && vertex2) { edges = this._edges.get(vertex1)?.filter(e => e.vertices.includes(vertex2.key)); @@ -123,48 +125,48 @@ export class UndirectedGraph< /** * The function removes an edge between two vertices in a graph and returns the removed edge. - * @param {V | VertexKey} v1 - The parameter `v1` represents either a vertex object (`V`) or a vertex ID (`VertexKey`). - * @param {V | VertexKey} v2 - V | VertexKey - This parameter can be either a vertex object (V) or a vertex ID + * @param {VO | VertexKey} v1 - The parameter `v1` represents either a vertex object (`VO`) or a vertex ID (`VertexKey`). + * @param {VO | VertexKey} v2 - VO | VertexKey - This parameter can be either a vertex object (VO) or a vertex ID * (VertexKey). It represents the second vertex of the edge that needs to be removed. - * @returns the removed edge (E) if it exists, or null if either of the vertices (V) does not exist. + * @returns the removed edge (EO) if it exists, or null if either of the vertices (VO) does not exist. */ - deleteEdgeBetween(v1: V | VertexKey, v2: V | VertexKey): E | null { - const vertex1: V | null = this._getVertex(v1); - const vertex2: V | null = this._getVertex(v2); + deleteEdgeBetween(v1: VO | VertexKey, v2: VO | VertexKey): EO | null { + const vertex1: VO | null = this._getVertex(v1); + const vertex2: VO | null = this._getVertex(v2); if (!vertex1 || !vertex2) { return null; } const v1Edges = this._edges.get(vertex1); - let removed: E | null = null; + let removed: EO | null = null; if (v1Edges) { - removed = arrayRemove(v1Edges, (e: E) => e.vertices.includes(vertex2.key))[0] || null; + removed = arrayRemove(v1Edges, (e: EO) => e.vertices.includes(vertex2.key))[0] || null; } const v2Edges = this._edges.get(vertex2); if (v2Edges) { - arrayRemove(v2Edges, (e: E) => e.vertices.includes(vertex1.key)); + arrayRemove(v2Edges, (e: EO) => e.vertices.includes(vertex1.key)); } return removed; } /** * The deleteEdge function removes an edge between two vertices in a graph. - * @param {E} edge - The parameter "edge" is of type E, which represents an edge in a graph. - * @returns The method is returning either the removed edge (of type E) or null if the edge was not found. + * @param {EO} edge - The parameter "edge" is of type EO, which represents an edge in a graph. + * @returns The method is returning either the removed edge (of type EO) or null if the edge was not found. */ - deleteEdge(edge: E): E | null { + deleteEdge(edge: EO): EO | null { return this.deleteEdgeBetween(edge.vertices[0], edge.vertices[1]); } /** * The function `degreeOf` returns the degree of a vertex in a graph, which is the number of edges connected to that * vertex. - * @param {VertexKey | V} vertexOrKey - The parameter `vertexOrKey` can be either a `VertexKey` or a `V`. + * @param {VertexKey | VO} vertexOrKey - The parameter `vertexOrKey` can be either a `VertexKey` or a `VO`. * @returns The function `degreeOf` returns the degree of a vertex in a graph. The degree of a vertex is the number of * edges connected to that vertex. */ - degreeOf(vertexOrKey: VertexKey | V): number { + degreeOf(vertexOrKey: VertexKey | VO): number { const vertex = this._getVertex(vertexOrKey); if (vertex) { return this._edges.get(vertex)?.length || 0; @@ -175,11 +177,11 @@ export class UndirectedGraph< /** * The function returns the edges of a given vertex or vertex ID. - * @param {VertexKey | V} vertexOrKey - The parameter `vertexOrKey` can be either a `VertexKey` or a `V`. A `VertexKey` is a - * unique identifier for a vertex in a graph, while `V` represents the type of the vertex. + * @param {VertexKey | VO} vertexOrKey - The parameter `vertexOrKey` can be either a `VertexKey` or a `VO`. A `VertexKey` is a + * unique identifier for a vertex in a graph, while `VO` represents the type of the vertex. * @returns an array of edges. */ - edgesOf(vertexOrKey: VertexKey | V): E[] { + edgesOf(vertexOrKey: VertexKey | VO): EO[] { const vertex = this._getVertex(vertexOrKey); if (vertex) { return this._edges.get(vertex) || []; @@ -190,10 +192,10 @@ export class UndirectedGraph< /** * The function "edgeSet" returns an array of unique edges from a set of edges. - * @returns The method `edgeSet()` returns an array of type `E[]`. + * @returns The method `edgeSet()` returns an array of type `EO[]`. */ - edgeSet(): E[] { - const edgeSet: Set = new Set(); + edgeSet(): EO[] { + const edgeSet: Set = new Set(); this._edges.forEach(edges => { edges.forEach(edge => { edgeSet.add(edge); @@ -204,12 +206,12 @@ export class UndirectedGraph< /** * The function "getNeighbors" returns an array of neighboring vertices for a given vertex or vertex ID. - * @param {V | VertexKey} vertexOrKey - The parameter `vertexOrKey` can be either a vertex object (`V`) or a vertex ID + * @param {VO | VertexKey} vertexOrKey - The parameter `vertexOrKey` can be either a vertex object (`VO`) or a vertex ID * (`VertexKey`). - * @returns an array of vertices (V[]). + * @returns an array of vertices (VO[]). */ - getNeighbors(vertexOrKey: V | VertexKey): V[] { - const neighbors: V[] = []; + getNeighbors(vertexOrKey: VO | VertexKey): VO[] { + const neighbors: VO[] = []; const vertex = this._getVertex(vertexOrKey); if (vertex) { const neighborEdges = this.edgesOf(vertex); @@ -226,11 +228,11 @@ export class UndirectedGraph< /** * The function "getEndsOfEdge" returns the vertices at the ends of an edge if the edge exists in the graph, otherwise * it returns null. - * @param {E} edge - The parameter "edge" is of type E, which represents an edge in a graph. - * @returns The function `getEndsOfEdge` returns an array containing two vertices `[V, V]` if the edge exists in the + * @param {EO} edge - The parameter "edge" is of type EO, which represents an edge in a graph. + * @returns The function `getEndsOfEdge` returns an array containing two vertices `[VO, VO]` if the edge exists in the * graph. If the edge does not exist, it returns `null`. */ - getEndsOfEdge(edge: E): [V, V] | null { + getEndsOfEdge(edge: EO): [VO, VO] | null { if (!this.hasEdge(edge.vertices[0], edge.vertices[1])) { return null; } @@ -245,10 +247,10 @@ export class UndirectedGraph< /** * The function adds an edge to the graph by updating the adjacency list with the vertices of the edge. - * @param {E} edge - The parameter "edge" is of type E, which represents an edge in a graph. + * @param {EO} edge - The parameter "edge" is of type EO, which represents an edge in a graph. * @returns a boolean value. */ - protected _addEdgeOnly(edge: E): boolean { + protected _addEdgeOnly(edge: EO): boolean { for (const end of edge.vertices) { const endVertex = this._getVertex(end); if (endVertex === null) return false; @@ -266,9 +268,9 @@ export class UndirectedGraph< /** * The function sets the edges of a graph. - * @param v - A map where the keys are of type V and the values are arrays of type E. + * @param v - A map where the keys are of type VO and the values are arrays of type EO. */ - protected _setEdges(v: Map) { + protected _setEdges(v: Map) { this._edges = v; } } diff --git a/src/data-structures/queue/queue.ts b/src/data-structures/queue/queue.ts index 0f9e1a2..abc7ad1 100644 --- a/src/data-structures/queue/queue.ts +++ b/src/data-structures/queue/queue.ts @@ -5,7 +5,7 @@ */ import {SinglyLinkedList} from '../linked-list'; -export class LinkedListQueue extends SinglyLinkedList { +export class SkipQueue extends SinglyLinkedList { /** * The enqueue function adds a value to the end of an array. * @param {E} value - The value parameter represents the value that you want to add to the queue. diff --git a/src/interfaces/graph.ts b/src/interfaces/graph.ts index dd65e90..eae6ae9 100644 --- a/src/interfaces/graph.ts +++ b/src/interfaces/graph.ts @@ -1,7 +1,7 @@ import {VertexKey} from '../types'; -export interface IGraph { - createVertex(key: VertexKey, val?: V): V; +export interface IGraph { + createVertex(key: VertexKey, val?: V): VO; - createEdge(srcOrV1: VertexKey | string, destOrV2: VertexKey | string, weight?: number, val?: E): E; + createEdge(srcOrV1: VertexKey | string, destOrV2: VertexKey | string, weight?: number, val?: E): EO; } diff --git a/test/unit/data-structures/graph/directed-graph.test.ts b/test/unit/data-structures/graph/directed-graph.test.ts index 91cb054..fdb90f2 100644 --- a/test/unit/data-structures/graph/directed-graph.test.ts +++ b/test/unit/data-structures/graph/directed-graph.test.ts @@ -92,52 +92,57 @@ describe('DirectedGraph Operation Test', () => { }); }); -class MyVertex extends DirectedVertex { +class MyVertex extends DirectedVertex { constructor(key: VertexKey, val?: V) { super(key, val); this._data = val; } - private _data: string | undefined; + private _data: V | undefined; - get data(): string | undefined { + get data(): V | undefined { return this._data; } - set data(value: string | undefined) { + set data(value: V | undefined) { this._data = value; } } -class MyEdge extends DirectedEdge { +class MyEdge extends DirectedEdge { constructor(v1: VertexKey, v2: VertexKey, weight?: number, val?: E) { super(v1, v2, weight, val); this._data = val; } - private _data: string | undefined; + private _data: E | undefined; - get data(): string | undefined { + get data(): E | undefined { return this._data; } - set data(value: string | undefined) { + set data(value: E | undefined) { this._data = value; } } -class MyDirectedGraph, E extends MyEdge> extends DirectedGraph { - createVertex(key: VertexKey, val: V['val']): V { - return new MyVertex(key, val) as V; +class MyDirectedGraph< + V = any, + E = any, + VO extends MyVertex = MyVertex, + EO extends MyEdge = MyEdge +> extends DirectedGraph { + createVertex(key: VertexKey, val: V): VO { + return new MyVertex(key, val) as VO; } - createEdge(src: VertexKey, dest: VertexKey, weight?: number, val?: E['val']): E { - return new MyEdge(src, dest, weight ?? 1, val) as E; + createEdge(src: VertexKey, dest: VertexKey, weight?: number, val?: E): EO { + return new MyEdge(src, dest, weight ?? 1, val) as EO; } } describe('Inherit from DirectedGraph and perform operations', () => { - let myGraph = new MyDirectedGraph, MyEdge>(); + let myGraph = new MyDirectedGraph(); beforeEach(() => { myGraph = new MyDirectedGraph(); }); @@ -234,7 +239,7 @@ describe('Inherit from DirectedGraph and perform operations', () => { }); describe('Inherit from DirectedGraph and perform operations test2.', () => { - const myGraph = new MyDirectedGraph, MyEdge>(); + const myGraph = new MyDirectedGraph(); it('should test graph operations', () => { const vertex1 = new MyVertex(1, 'data1'); diff --git a/test/unit/data-structures/graph/map-graph.test.ts b/test/unit/data-structures/graph/map-graph.test.ts index 0c88ddd..94555c7 100644 --- a/test/unit/data-structures/graph/map-graph.test.ts +++ b/test/unit/data-structures/graph/map-graph.test.ts @@ -4,17 +4,17 @@ describe('MapGraph Operation Test', () => { it('dijkstra shortest path', () => { const mapGraph = new MapGraph([5.500338, 100.173665]); - mapGraph.addVertex(new MapVertex('Surin', 5.466724, 100.274805)); - mapGraph.addVertex(new MapVertex('Batu Feringgi Beach', 5.475141, 100.27667)); - mapGraph.addVertex(new MapVertex('Lotus', 5.459044, 100.308767)); - mapGraph.addVertex(new MapVertex('The Breeza', 5.454197, 100.307859)); - mapGraph.addVertex(new MapVertex('Hard Rock Hotel', 5.46785, 100.241876)); - mapGraph.addVertex(new MapVertex('Mira', 5.456749, 100.28665)); - mapGraph.addVertex(new MapVertex('Penang Bible Church', 5.428683, 100.314825)); - mapGraph.addVertex(new MapVertex('Queensbay', 5.33276, 100.306651)); - mapGraph.addVertex(new MapVertex('Saanen Goat Farm', 5.405738, 100.207699)); - mapGraph.addVertex(new MapVertex('Trinity Auto', 5.401126, 100.303739)); - mapGraph.addVertex(new MapVertex('Penang Airport', 5.293185, 100.265772)); + mapGraph.addVertex(new MapVertex('Surin', '', 5.466724, 100.274805)); + mapGraph.addVertex(new MapVertex('Batu Feringgi Beach', '', 5.475141, 100.27667)); + mapGraph.addVertex(new MapVertex('Lotus', '', 5.459044, 100.308767)); + mapGraph.addVertex(new MapVertex('The Breeza', '', 5.454197, 100.307859)); + mapGraph.addVertex(new MapVertex('Hard Rock Hotel', '', 5.46785, 100.241876)); + mapGraph.addVertex(new MapVertex('Mira', '', 5.456749, 100.28665)); + mapGraph.addVertex(new MapVertex('Penang Bible Church', '', 5.428683, 100.314825)); + mapGraph.addVertex(new MapVertex('Queensbay', '', 5.33276, 100.306651)); + mapGraph.addVertex(new MapVertex('Saanen Goat Farm', '', 5.405738, 100.207699)); + mapGraph.addVertex(new MapVertex('Trinity Auto', '', 5.401126, 100.303739)); + mapGraph.addVertex(new MapVertex('Penang Airport', '', 5.293185, 100.265772)); mapGraph.addEdge('Surin', 'Lotus', 4.7); mapGraph.addEdge('Lotus', 'The Breeza', 1); mapGraph.addEdge('Batu Feringgi Beach', 'Hard Rock Hotel', 5.2); @@ -45,17 +45,17 @@ describe('MapGraph Operation Test', () => { }); describe('MapGraph', () => { - let mapGraph: MapGraph; + let mapGraph: MapGraph; beforeEach(() => { // Create a new MapGraph instance before each test - mapGraph = new MapGraph([0, 0], [100, 100]); + mapGraph = new MapGraph([0, 0], [100, 100]); }); // Test adding vertices to the graph it('should add vertices to the graph', () => { - const locationA = new MapVertex('A', 10, 20, 'Location A'); - const locationB = new MapVertex('B', 30, 40, 'Location B'); + const locationA = new MapVertex('A', 'Location A', 10, 20); + const locationB = new MapVertex('B', 'Location B', 30, 40); mapGraph.addVertex(locationA); mapGraph.addVertex(locationB); @@ -66,8 +66,8 @@ describe('MapGraph', () => { // Test adding edges to the graph it('should add edges to the graph', () => { - const locationA = new MapVertex('A', 10, 20, 'Location A'); - const locationB = new MapVertex('B', 30, 40, 'Location B'); + const locationA = new MapVertex('A', 'Location A', 10, 20); + const locationB = new MapVertex('B', 'Location B', 30, 40); const edgeAB = new MapEdge('A', 'B', 50, 'Edge from A to B'); mapGraph.addVertex(locationA); @@ -79,12 +79,12 @@ describe('MapGraph', () => { // Test getting neighbors of a vertex it('should return the neighbors of a vertex', () => { - const locationA = new MapVertex('A', 10, 20, 'Location A'); + const locationA = new MapVertex('A', 'Location A', 10, 20); locationA.lat = locationA.lat; locationA.long = locationA.long; - const locationB = mapGraph.createVertex('B', 30, 40, 'Location B'); + const locationB = mapGraph.createVertex('B', 'Location B', 30, 40); - const locationC = new MapVertex('C', 50, 60, 'Location C'); + const locationC = new MapVertex('C', 'Location C', 50, 60); const edgeAB = new MapEdge('A', 'B', 50, 'Edge from A to B'); const edgeBC = new MapEdge('B', 'C', 60, 'Edge from B to C'); @@ -106,9 +106,9 @@ describe('MapGraph', () => { // Test finding the shortest path between locations it('should find the shortest path between two locations', () => { - const locationA = new MapVertex('A', 10, 20, 'Location A'); - const locationB = new MapVertex('B', 30, 40, 'Location B'); - const locationC = new MapVertex('C', 50, 60, 'Location C'); + const locationA = new MapVertex('A', 'Location A', 10, 20); + const locationB = new MapVertex('B', 'Location B', 30, 40); + const locationC = new MapVertex('C', 'Location C', 50, 60); const edgeAB = new MapEdge('A', 'B', 50, 'Edge from A to B'); const edgeBC = new MapEdge('B', 'C', 60, 'Edge from B to C'); diff --git a/test/unit/data-structures/graph/undirected-graph.test.ts b/test/unit/data-structures/graph/undirected-graph.test.ts index c331fd6..622f29f 100644 --- a/test/unit/data-structures/graph/undirected-graph.test.ts +++ b/test/unit/data-structures/graph/undirected-graph.test.ts @@ -59,11 +59,11 @@ describe('UndirectedGraph Operation Test', () => { }); describe('UndirectedGraph', () => { - let undirectedGraph: UndirectedGraph, UndirectedEdge>; + let undirectedGraph: UndirectedGraph; beforeEach(() => { // Create a new UndirectedGraph instance before each test - undirectedGraph = new UndirectedGraph, UndirectedEdge>(); + undirectedGraph = new UndirectedGraph(); }); // Test adding vertices to the graph diff --git a/test/unit/data-structures/queue/queue.test.ts b/test/unit/data-structures/queue/queue.test.ts index 9e2a263..eb062f6 100644 --- a/test/unit/data-structures/queue/queue.test.ts +++ b/test/unit/data-structures/queue/queue.test.ts @@ -1,4 +1,4 @@ -import {LinkedListQueue, Queue} from '../../../../src'; +import {SkipQueue, Queue} from '../../../../src'; import {bigO, magnitude} from '../../../utils'; import {isDebugTest} from '../../../config'; @@ -168,11 +168,11 @@ describe('Queue', () => { expect(values).toEqual([1, 2, 3]); }); }); -describe('LinkedListQueue', () => { - let queue: LinkedListQueue; +describe('SkipQueue', () => { + let queue: SkipQueue; beforeEach(() => { - queue = new LinkedListQueue(); + queue = new SkipQueue(); }); it('should enqueue elements to the end of the queue', () => { @@ -197,7 +197,7 @@ describe('LinkedListQueue', () => { expect(queue.peek()).toBe('A'); }); - // Add more test cases for other methods of LinkedListQueue. + // Add more test cases for other methods of SkipQueue. }); describe('Queue Performance Test', () => { @@ -228,16 +228,16 @@ describe('Queue Performance Test', () => { expect(performance.now() - startTime2).toBeLessThan(bigO.CUBED * 100); }); - it('should numeric LinkedListQueue be efficient', function () { + it('should numeric SkipQueue be efficient', function () { const startTime = performance.now(); - const queue = new LinkedListQueue(); + const queue = new SkipQueue(); for (let i = 0; i < dataSize; i++) { queue.enqueue(i); } for (let i = 0; i < dataSize; i++) { queue.dequeue(); } - console.log(`LinkedListQueue Performance Test: ${performance.now() - startTime} ms`); + console.log(`SkipQueue Performance Test: ${performance.now() - startTime} ms`); expect(performance.now() - startTime).toBeLessThan(bigO.LINEAR * 100); }); }); From 3aea9fc046176feaa9a457cc2c8a0b7d7d52bbf5 Mon Sep 17 00:00:00 2001 From: Revone Date: Mon, 30 Oct 2023 18:53:14 +0800 Subject: [PATCH 39/46] v1.39.5 published --- CHANGELOG.md | 3 ++- package-lock.json | 50 +++++++++++++++++++++++------------------------ package.json | 10 +++++----- 3 files changed, 32 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c67d7e..7dadcdc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,10 +8,11 @@ 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.39.4](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) +## [v1.39.5](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) ### Changes +- [graph] Modify the data structure design of the graph to change the g… [`#29`](https://github.com/zrwusa/data-structure-typed/pull/29) - Optimization [`#23`](https://github.com/zrwusa/data-structure-typed/pull/23) - Optimization [`#20`](https://github.com/zrwusa/data-structure-typed/pull/20) - [binary-tree, graph] Replace all code that uses Arrays as makeshift Q… [`#18`](https://github.com/zrwusa/data-structure-typed/pull/18) diff --git a/package-lock.json b/package-lock.json index 6678db2..9d349dd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "data-structure-typed", - "version": "1.39.4", + "version": "1.39.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "data-structure-typed", - "version": "1.39.4", + "version": "1.39.5", "license": "MIT", "devDependencies": { "@types/benchmark": "^2.1.3", @@ -15,17 +15,17 @@ "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", "auto-changelog": "^2.4.0", - "avl-tree-typed": "^1.39.3", + "avl-tree-typed": "^1.39.4", "benchmark": "^2.1.4", - "binary-tree-typed": "^1.39.3", - "bst-typed": "^1.39.3", + "binary-tree-typed": "^1.39.4", + "bst-typed": "^1.39.4", "dependency-cruiser": "^14.1.0", "eslint": "^8.50.0", "eslint-config-prettier": "^9.0.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.28.1", - "heap-typed": "^1.39.3", + "heap-typed": "^1.39.4", "istanbul-badges-readme": "^1.8.5", "jest": "^29.7.0", "prettier": "^3.0.3", @@ -2728,12 +2728,12 @@ } }, "node_modules/avl-tree-typed": { - "version": "1.39.3", - "resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.39.3.tgz", - "integrity": "sha512-5tgPsLtuPkgLH6CDuz9OXGR+4AxXXdu6sOtQNrQeqvMkPlgkduxjOd5aMqAvCjkRKHZ3TjFi43sNEYRxzoQ6AQ==", + "version": "1.39.4", + "resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.39.4.tgz", + "integrity": "sha512-hgX97KNfwuIu9byrhFF22WBqA1OgMk97bSDB8mKdhZ/5E9OecAglnh8vjeLqxAt0DUFUpghXJ+AenXoVlBYWmw==", "dev": true, "dependencies": { - "data-structure-typed": "^1.39.2" + "data-structure-typed": "^1.39.4" } }, "node_modules/babel-jest": { @@ -2927,12 +2927,12 @@ } }, "node_modules/binary-tree-typed": { - "version": "1.39.3", - "resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.39.3.tgz", - "integrity": "sha512-bzNlbU5DVx0tK798O0loGfgFqFCTR/lHXptCEvU8YvQQ6E+/rv9zj926HHqQClU0vhtMdBQdQIoxJubGlYnwQQ==", + "version": "1.39.4", + "resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.39.4.tgz", + "integrity": "sha512-HC3ue5u5Db4mW0EkE8rd6Bq5wQB5DSQHm4R6DhUnd95TRV/diiqD8MUheVNddEm3vg+vgCwTKCvwsO3joBakQw==", "dev": true, "dependencies": { - "data-structure-typed": "^1.39.2" + "data-structure-typed": "^1.39.4" } }, "node_modules/brace-expansion": { @@ -3011,12 +3011,12 @@ } }, "node_modules/bst-typed": { - "version": "1.39.3", - "resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.39.3.tgz", - "integrity": "sha512-cb0ZMMBfITnStTek9oGxIQBK1ycqZsDzxwmgmNICRNVnrjA7RHa9jck3RIg0MTN/+W4DLTbZJDyqeUZwmWb+xQ==", + "version": "1.39.4", + "resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.39.4.tgz", + "integrity": "sha512-efEtQyABOUehz7b+zpnL5QUg8IsK/vnoaB+ws+NN9LHAYlcJ4DvhvdAJT4J7YfnthNOhVgV6b+XmIOnaviWKHw==", "dev": true, "dependencies": { - "data-structure-typed": "^1.39.2" + "data-structure-typed": "^1.39.4" } }, "node_modules/buffer-from": { @@ -3413,9 +3413,9 @@ } }, "node_modules/data-structure-typed": { - "version": "1.39.2", - "resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.39.2.tgz", - "integrity": "sha512-KGr12Nntd4z8y9vQ+3q7t2vJ6rqjxKP0p/+arH2ZtuPn6HoQ9xZat2yRaHulQKeyiSIzYIpAlj5ZmFgaYRttrg==", + "version": "1.39.4", + "resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.39.4.tgz", + "integrity": "sha512-i2GtZluNIvGrQ6147oe7v0g2RV9KPDBT8bMbRDM+7cIHrQ3zr3w70W6yZx5scSKCvtg18kJ5lyXXPbEiY7zHsg==", "dev": true }, "node_modules/debug": { @@ -4771,12 +4771,12 @@ } }, "node_modules/heap-typed": { - "version": "1.39.3", - "resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.39.3.tgz", - "integrity": "sha512-wq1d+5KwpCoY19Mls6e+ughQljwDNo3Z2TcPdmw0AYdXbEhajgaemggHbujxKpOB/r0iNaX4rdoGAm4HVJ3R3Q==", + "version": "1.39.4", + "resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.39.4.tgz", + "integrity": "sha512-5qF7vdcFV9ZgIXZ3YyDZOHDZV9Ik+3Mv6Us2gStyyYGmMpgbENgAUxZmh8MDKJAH/Hf1DWK7TTGi0AQWPWKFWg==", "dev": true, "dependencies": { - "data-structure-typed": "^1.39.2" + "data-structure-typed": "^1.39.4" } }, "node_modules/html-escaper": { diff --git a/package.json b/package.json index f14225c..de2f4c4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "data-structure-typed", - "version": "1.39.4", + "version": "1.39.5", "description": "Data Structures of Javascript & TypeScript. Binary Tree, BST, Graph, Heap, Priority Queue, Linked List, Queue, Deque, Stack, AVL Tree, Tree Multiset, Trie, Directed Graph, Undirected Graph, Singly Linked List, Doubly Linked List, Max Heap, Max Priority Queue, Min Heap, Min Priority Queue.", "main": "dist/cjs/index.js", "module": "dist/mjs/index.js", @@ -61,17 +61,17 @@ "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", "auto-changelog": "^2.4.0", - "avl-tree-typed": "^1.39.3", + "avl-tree-typed": "^1.39.4", "benchmark": "^2.1.4", - "binary-tree-typed": "^1.39.3", - "bst-typed": "^1.39.3", + "binary-tree-typed": "^1.39.4", + "bst-typed": "^1.39.4", "dependency-cruiser": "^14.1.0", "eslint": "^8.50.0", "eslint-config-prettier": "^9.0.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.28.1", - "heap-typed": "^1.39.3", + "heap-typed": "^1.39.4", "istanbul-badges-readme": "^1.8.5", "jest": "^29.7.0", "prettier": "^3.0.3", From fcec29f32cce6f674571f36004cd586a65a5be10 Mon Sep 17 00:00:00 2001 From: Revone Date: Mon, 30 Oct 2023 20:08:25 +0800 Subject: [PATCH 40/46] [graph test] edge cases enriched --- src/data-structures/graph/abstract-graph.ts | 12 +-- src/data-structures/graph/directed-graph.ts | 6 +- src/data-structures/graph/undirected-graph.ts | 6 +- src/interfaces/graph.ts | 2 +- .../graph/abstract-graph.test.ts | 101 +++++++++++++++++- .../graph/directed-graph.test.ts | 10 ++ .../graph/undirected-graph.test.ts | 8 ++ 7 files changed, 130 insertions(+), 15 deletions(-) diff --git a/src/data-structures/graph/abstract-graph.ts b/src/data-structures/graph/abstract-graph.ts index 5b0aa79..6005bcc 100644 --- a/src/data-structures/graph/abstract-graph.ts +++ b/src/data-structures/graph/abstract-graph.ts @@ -45,7 +45,7 @@ export abstract class AbstractVertex { } } -export abstract class AbstractEdge { +export abstract class AbstractEdge { /** * The above function is a protected constructor that initializes the weight, value, and hash code properties of an * object. @@ -55,19 +55,19 @@ export abstract class AbstractEdge { * @param {VO} [val] - The `val` parameter is of type `VO`, which means it can be any type. It is an optional parameter, * meaning it can be omitted when creating an instance of the class. */ - protected constructor(weight?: number, val?: VO) { + protected constructor(weight?: number, val?: E) { this._weight = weight !== undefined ? weight : 1; this._val = val; this._hashCode = uuidV4(); } - private _val: VO | undefined; + private _val: E | undefined; - get val(): VO | undefined { + get val(): E | undefined { return this._val; } - set val(value: VO | undefined) { + set val(value: E | undefined) { this._val = value; } @@ -131,7 +131,7 @@ export abstract class AbstractGraph< * @param weight * @param val */ - abstract createEdge(srcOrV1: VertexKey | string, destOrV2: VertexKey | string, weight?: number, val?: E): EO; + abstract createEdge(srcOrV1: VertexKey, destOrV2: VertexKey, weight?: number, val?: E): EO; abstract deleteEdge(edge: EO): EO | null; diff --git a/src/data-structures/graph/directed-graph.ts b/src/data-structures/graph/directed-graph.ts index 32e522d..b3072a7 100644 --- a/src/data-structures/graph/directed-graph.ts +++ b/src/data-structures/graph/directed-graph.ts @@ -129,13 +129,13 @@ export class DirectedGraph< /** * The `getEdge` function retrieves an edge between two vertices based on their source and destination IDs. - * @param {VO | null | VertexKey} srcOrKey - The source vertex or its ID. It can be either a vertex object or a vertex ID. - * @param {VO | null | VertexKey} destOrKey - The `destOrKey` parameter in the `getEdge` function represents the + * @param {VO | VertexKey | null} srcOrKey - The source vertex or its ID. It can be either a vertex object or a vertex ID. + * @param {VO | VertexKey | null} destOrKey - The `destOrKey` parameter in the `getEdge` function represents the * destination vertex of the edge. It can be either a vertex object (`VO`), a vertex ID (`VertexKey`), or `null` if the * destination is not specified. * @returns the first edge found between the source and destination vertices, or null if no such edge is found. */ - getEdge(srcOrKey: VO | null | VertexKey, destOrKey: VO | null | VertexKey): EO | null { + getEdge(srcOrKey: VO | VertexKey | null, destOrKey: VO | VertexKey | null): EO | null { let edges: EO[] = []; if (srcOrKey !== null && destOrKey !== null) { diff --git a/src/data-structures/graph/undirected-graph.ts b/src/data-structures/graph/undirected-graph.ts index 7adeb28..85a7e0b 100644 --- a/src/data-structures/graph/undirected-graph.ts +++ b/src/data-structures/graph/undirected-graph.ts @@ -102,13 +102,13 @@ export class UndirectedGraph< /** * The function `getEdge` returns the first edge that connects two vertices, or null if no such edge exists. - * @param {VO | null | VertexKey} v1 - The parameter `v1` represents a vertex or vertex ID. It can be of type `VO` (vertex + * @param {VO | VertexKey | null} v1 - The parameter `v1` represents a vertex or vertex ID. It can be of type `VO` (vertex * object), `null`, or `VertexKey` (a string or number representing the ID of a vertex). - * @param {VO | null | VertexKey} v2 - The parameter `v2` represents a vertex or vertex ID. It can be of type `VO` (vertex + * @param {VO | VertexKey | null} v2 - The parameter `v2` represents a vertex or vertex ID. It can be of type `VO` (vertex * object), `null`, or `VertexKey` (vertex ID). * @returns an edge (EO) or null. */ - getEdge(v1: VO | null | VertexKey, v2: VO | null | VertexKey): EO | null { + getEdge(v1: VO | VertexKey | null, v2: VO | VertexKey | null): EO | null { let edges: EO[] | undefined = []; if (v1 !== null && v2 !== null) { diff --git a/src/interfaces/graph.ts b/src/interfaces/graph.ts index eae6ae9..7b968ae 100644 --- a/src/interfaces/graph.ts +++ b/src/interfaces/graph.ts @@ -3,5 +3,5 @@ import {VertexKey} from '../types'; export interface IGraph { createVertex(key: VertexKey, val?: V): VO; - createEdge(srcOrV1: VertexKey | string, destOrV2: VertexKey | string, weight?: number, val?: E): EO; + createEdge(srcOrV1: VertexKey, destOrV2: VertexKey, weight?: number, val?: E): EO; } diff --git a/test/unit/data-structures/graph/abstract-graph.test.ts b/test/unit/data-structures/graph/abstract-graph.test.ts index 8b2fb42..efd2250 100644 --- a/test/unit/data-structures/graph/abstract-graph.test.ts +++ b/test/unit/data-structures/graph/abstract-graph.test.ts @@ -1,5 +1,102 @@ +import {AbstractEdge, AbstractGraph, AbstractVertex, VertexKey} from '../../../../src'; + +class MyVertex extends AbstractVertex { + data?: V; + + constructor(key: VertexKey, val?: V) { + super(key, val); + this.data = val; + } +} + +class MyEdge extends AbstractEdge { + data?: E; + src: VertexKey; + dest: VertexKey; + + constructor(srcOrV1: VertexKey, destOrV2: VertexKey, weight?: number, val?: E) { + super(weight, val); + this.src = srcOrV1; + this.dest = destOrV2; + this.data = val; + this._setHashCode(''); + } +} + +class MyGraph< + V = any, + E = any, + VO extends MyVertex = MyVertex, + EO extends MyEdge = MyEdge +> extends AbstractGraph { + createVertex(key: VertexKey, val?: V): VO { + return new MyVertex(key, val) as VO; + } + + createEdge(srcOrV1: VertexKey, destOrV2: VertexKey, weight?: number, val?: E): EO { + return new MyEdge(srcOrV1, destOrV2, weight, val) as EO; + } + + deleteEdge(edge: EO): EO | null { + return edge; + } + + getEdge(srcOrKey: VertexKey, destOrKey: VertexKey): EO | null { + return new MyEdge(srcOrKey, destOrKey) as EO; + } + + degreeOf(vertexOrKey: VO | VertexKey): number { + return 1 ?? Number(vertexOrKey); + } + + edgeSet(): EO[] { + return [new MyEdge('a', 'b') as EO]; + } + + edgesOf(vertexOrKey: VO | VertexKey): EO[] { + const a = typeof vertexOrKey === "string" ? vertexOrKey : "a"; + return [new MyEdge(a, 'b') as EO]; + } + + getNeighbors(vertexOrKey: VO | VertexKey): VO[] { + const a = typeof vertexOrKey === "string" ? vertexOrKey : "a"; + return [new MyVertex(a, 'b') as VO]; + } + + getEndsOfEdge(edge: EO): [VO, VO] | null { + return edge ? null : null; + } + + protected _addEdgeOnly(edge: EO): boolean { + return edge ? true : true; + } +} + describe('AbstractGraph Operation Test', () => { - it('should xxx', function () { - expect(true).toBe(true); + const myGraph: MyGraph = new MyGraph(); + + beforeEach(() => { + }); + it('should edge cases', function () { + myGraph.addVertex('A', 1); + myGraph.addVertex('B', 2); + myGraph.addVertex('C', 3); + myGraph.addVertex('D', 4); + + const vA = myGraph.getVertex('A'); + // const vB = myGraph.getVertex('B'); + // const vC = myGraph.getVertex('C'); + // const vD = myGraph.getVertex('D'); + + const eAB = new MyEdge('A', 'B'); + // const eBC = new MyEdge('B', 'C'); + // const eCD = new MyEdge('C', 'D'); + vA!.key = vA?.key || 1; + vA!.val = vA?.val ?? 2; + + eAB!.val = eAB.val; + const hs = eAB.hashCode; + + expect(hs).toBe(''); }); }); diff --git a/test/unit/data-structures/graph/directed-graph.test.ts b/test/unit/data-structures/graph/directed-graph.test.ts index fdb90f2..9b2c2a4 100644 --- a/test/unit/data-structures/graph/directed-graph.test.ts +++ b/test/unit/data-structures/graph/directed-graph.test.ts @@ -139,6 +139,14 @@ class MyDirectedGraph< createEdge(src: VertexKey, dest: VertexKey, weight?: number, val?: E): EO { return new MyEdge(src, dest, weight ?? 1, val) as EO; } + + setInEdgeMap(value: Map) { + super._setInEdgeMap(value); + } + + setOutEdgeMap(value: Map) { + super._setOutEdgeMap(value); + } } describe('Inherit from DirectedGraph and perform operations', () => { @@ -164,6 +172,8 @@ describe('Inherit from DirectedGraph and perform operations', () => { myGraph.addVertex(2, 'data2'); myGraph.addEdge(1, 2, 10, 'edge-data1-2'); myGraph.addEdge(new MyEdge(2, 1, 20, 'edge-data2-1')); + myGraph.setInEdgeMap(myGraph.inEdgeMap); + myGraph.setOutEdgeMap(myGraph.outEdgeMap); expect(myGraph.edgeSet().length).toBe(2); // TODO diff --git a/test/unit/data-structures/graph/undirected-graph.test.ts b/test/unit/data-structures/graph/undirected-graph.test.ts index 622f29f..e8129cb 100644 --- a/test/unit/data-structures/graph/undirected-graph.test.ts +++ b/test/unit/data-structures/graph/undirected-graph.test.ts @@ -7,6 +7,14 @@ describe('UndirectedGraph Operation Test', () => { graph = new UndirectedGraph(); }); + it('should edge cases', () => { + expect(graph.deleteEdge(new UndirectedEdge('c', 'd'))).toBe(null); + expect(graph.deleteEdgeBetween('c', 'd')).toBe(null); + expect(graph.degreeOf('c')).toBe(0); + expect(graph.edgesOf('c').length).toBe(0); + expect(graph.getEndsOfEdge(new UndirectedEdge('c', 'd'))).toBe(null); + }); + it('should add vertices', () => { const vertex1 = new UndirectedVertex('A'); const vertex2 = new UndirectedVertex('B'); From 121516f303a60ee89d1b555392c3fec5afb24af8 Mon Sep 17 00:00:00 2001 From: Revone Date: Mon, 30 Oct 2023 20:27:08 +0800 Subject: [PATCH 41/46] [core] Rename all 'val' variables to 'value'. --- src/data-structures/binary-tree/avl-tree.ts | 26 ++-- .../binary-tree/binary-tree.ts | 36 +++--- src/data-structures/binary-tree/bst.ts | 32 ++--- src/data-structures/binary-tree/rb-tree.ts | 12 +- .../binary-tree/segment-tree.ts | 30 ++--- .../binary-tree/tree-multiset.ts | 36 +++--- src/data-structures/graph/abstract-graph.ts | 66 +++++----- src/data-structures/graph/directed-graph.ts | 26 ++-- src/data-structures/graph/map-graph.ts | 26 ++-- src/data-structures/graph/undirected-graph.ts | 24 ++-- src/data-structures/hash/hash-table.ts | 18 +-- .../linked-list/doubly-linked-list.ts | 122 +++++++++--------- .../linked-list/singly-linked-list.ts | 116 ++++++++--------- src/data-structures/queue/queue.ts | 2 +- src/interfaces/binary-tree.ts | 4 +- src/interfaces/graph.ts | 4 +- test/integration/bst.test.ts | 4 +- .../binary-tree/avl-tree.test.ts | 4 +- .../binary-tree/binary-index-tree.test.ts | 6 +- .../binary-tree/binary-tree.test.ts | 16 +-- .../data-structures/binary-tree/bst.test.ts | 8 +- .../binary-tree/rb-tree.test.ts | 6 +- .../binary-tree/tree-multiset.test.ts | 4 +- .../graph/abstract-graph.test.ts | 24 ++-- .../graph/directed-graph.test.ts | 24 ++-- .../data-structures/hash/hash-table.test.ts | 2 +- .../linked-list/doubly-linked-list.test.ts | 60 ++++----- .../linked-list/linked-list.test.ts | 2 +- .../linked-list/singly-linked-list.test.ts | 30 ++--- test/utils/big-o.ts | 14 +- 30 files changed, 392 insertions(+), 392 deletions(-) diff --git a/src/data-structures/binary-tree/avl-tree.ts b/src/data-structures/binary-tree/avl-tree.ts index 4fc9324..368f3f7 100644 --- a/src/data-structures/binary-tree/avl-tree.ts +++ b/src/data-structures/binary-tree/avl-tree.ts @@ -13,8 +13,8 @@ import {IBinaryTree} from '../../interfaces'; export class AVLTreeNode = AVLTreeNodeNested> extends BSTNode { height: number; - constructor(key: BTNKey, val?: V) { - super(key, val); + constructor(key: BTNKey, value?: V) { + super(key, value); this.height = 0; } } @@ -37,13 +37,13 @@ export class AVLTree = AVLTreeNode(key, val) as N; + override createNode(key: BTNKey, value?: V): N { + return new AVLTreeNode(key, value) as N; } /** @@ -51,13 +51,13 @@ export class AVLTree = AVLTreeNode = AVLTreeNode = BinaryTree /** * The value stored in the node. */ - val: V | undefined; + value: V | undefined; /** * The parent node of the current node. @@ -36,11 +36,11 @@ export class BinaryTreeNode = BinaryTree /** * Creates a new instance of BinaryTreeNode. * @param {BTNKey} key - The key associated with the node. - * @param {V} val - The value stored in the node. + * @param {V} value - The value stored in the node. */ - constructor(key: BTNKey, val?: V) { + constructor(key: BTNKey, value?: V) { this.key = key; - this.val = val; + this.value = value; } private _left: N | null | undefined; @@ -159,11 +159,11 @@ export class BinaryTree = BinaryTreeNode /** * Creates a new instance of BinaryTreeNode with the given key and value. * @param {BTNKey} key - The key for the new node. - * @param {V} val - The value for the new node. + * @param {V} value - The value for the new node. * @returns {N} - The newly created BinaryTreeNode. */ - createNode(key: BTNKey, val?: V): N { - return new BinaryTreeNode(key, val) as N; + createNode(key: BTNKey, value?: V): N { + return new BinaryTreeNode(key, value) as N; } /** @@ -185,10 +185,10 @@ export class BinaryTree = BinaryTreeNode /** * Add a node with the given key and value to the binary tree. * @param {BTNKey | N | null} keyOrNode - The key or node to add to the binary tree. - * @param {V} val - The value for the new node (optional). + * @param {V} value - The value for the new node (optional). * @returns {N | null | undefined} - The inserted node, or null if nothing was inserted, or undefined if the operation failed. */ - add(keyOrNode: BTNKey | N | null, val?: V): N | null | undefined { + add(keyOrNode: BTNKey | N | null, value?: V): N | null | undefined { const _bfs = (root: N, newNode: N | null): N | undefined | null => { const queue = new Queue([root]); while (queue.size > 0) { @@ -209,7 +209,7 @@ export class BinaryTree = BinaryTreeNode if (keyOrNode === null) { needInsert = null; } else if (typeof keyOrNode === 'number') { - needInsert = this.createNode(keyOrNode, val); + needInsert = this.createNode(keyOrNode, value); } else if (keyOrNode instanceof BinaryTreeNode) { needInsert = keyOrNode; } else { @@ -221,7 +221,7 @@ export class BinaryTree = BinaryTreeNode if (this.root) { if (existNode) { - existNode.val = val; + existNode.value = value; inserted = existNode; } else { inserted = _bfs(this.root, needInsert); @@ -252,15 +252,15 @@ export class BinaryTree = BinaryTreeNode // TODO not sure addMany not be run multi times return keysOrNodes.map((keyOrNode, i) => { if (keyOrNode instanceof BinaryTreeNode) { - return this.add(keyOrNode.key, keyOrNode.val); + return this.add(keyOrNode.key, keyOrNode.value); } if (keyOrNode === null) { return this.add(null); } - const val = values?.[i]; - return this.add(keyOrNode, val); + const value = values?.[i]; + return this.add(keyOrNode, value); }); } @@ -1212,15 +1212,15 @@ export class BinaryTree = BinaryTreeNode * @returns {N} - The destination node after the swap. */ protected _swap(srcNode: N, destNode: N): N { - const {key, val} = destNode; - const tempNode = this.createNode(key, val); + const {key, value} = destNode; + const tempNode = this.createNode(key, value); if (tempNode) { destNode.key = srcNode.key; - destNode.val = srcNode.val; + destNode.value = srcNode.value; srcNode.key = tempNode.key; - srcNode.val = tempNode.val; + srcNode.value = tempNode.value; } return destNode; diff --git a/src/data-structures/binary-tree/bst.ts b/src/data-structures/binary-tree/bst.ts index 4868953..7684bd8 100644 --- a/src/data-structures/binary-tree/bst.ts +++ b/src/data-structures/binary-tree/bst.ts @@ -12,8 +12,8 @@ import {IBinaryTree} from '../../interfaces'; import {Queue} from '../queue'; export class BSTNode = BSTNodeNested> extends BinaryTreeNode { - constructor(key: BTNKey, val?: V) { - super(key, val); + constructor(key: BTNKey, value?: V) { + super(key, value); } } @@ -41,12 +41,12 @@ export class BST = BSTNode> * The function creates a new binary search tree node with the given key and value. * @param {BTNKey} key - The key parameter is the key value that will be associated with * the new node. It is used to determine the position of the node in the binary search tree. - * @param [val] - The parameter `val` is an optional value that can be assigned to the node. It + * @param [value] - The parameter `value` is an optional value that can be assigned to the node. It * represents the value associated with the node in a binary search tree. * @returns a new instance of the BSTNode class with the specified key and value. */ - override createNode(key: BTNKey, val?: V): N { - return new BSTNode(key, val) as N; + override createNode(key: BTNKey, value?: V): N { + return new BSTNode(key, value) as N; } /** @@ -54,19 +54,19 @@ export class BST = BSTNode> * into the tree. * @param {BTNKey | N | null} keyOrNode - The `keyOrNode` parameter can be either a * `BTNKey` (which can be a number or a string), a `BSTNode` object, or `null`. - * @param [val] - The `val` parameter is the value to be assigned to the new node being added to the + * @param [value] - The `value` parameter is the value to be assigned to the new node being added to the * binary search tree. * @returns the inserted node (N) if it was successfully added to the binary search tree. If the node * was not added or if the parameters were invalid, it returns null or undefined. */ - override add(keyOrNode: BTNKey | N | null, val?: V): N | null | undefined { + override add(keyOrNode: BTNKey | N | null, value?: V): N | null | undefined { // TODO support node as a parameter let inserted: N | null = null; let newNode: N | null = null; if (keyOrNode instanceof BSTNode) { newNode = keyOrNode; } else if (typeof keyOrNode === 'number') { - newNode = this.createNode(keyOrNode, val); + newNode = this.createNode(keyOrNode, value); } else if (keyOrNode === null) { newNode = null; } @@ -81,7 +81,7 @@ export class BST = BSTNode> if (cur !== null && newNode !== null) { if (this._compare(cur.key, newNode.key) === CP.eq) { if (newNode) { - cur.val = newNode.val; + cur.value = newNode.value; } //Duplicates are not accepted. traversing = false; @@ -128,7 +128,7 @@ export class BST = BSTNode> /** * The `addMany` function is used to efficiently add multiple nodes to a binary search tree while * maintaining balance. - * @param {[BTNKey | N, N['val']][]} keysOrNodes - The `arr` parameter in the `addMany` function + * @param {[BTNKey | N, N['value']][]} keysOrNodes - The `arr` parameter in the `addMany` function * represents an array of keys or nodes that need to be added to the binary search tree. It can be an * array of `BTNKey` or `N` (which represents the node type in the binary search tree) or * `null @@ -154,15 +154,15 @@ export class BST = BSTNode> return super.addMany(keysOrNodes, data); } const inserted: (N | null | undefined)[] = []; - const combinedArr: [BTNKey | N, N['val']][] = keysOrNodes.map((value, index) => [value, data?.[index]]); + const combinedArr: [BTNKey | N, N['value']][] = keysOrNodes.map((value, index) => [value, data?.[index]]); let sorted = []; - function isNodeOrNullTuple(arr: [BTNKey | N, N['val']][]): arr is [N, N['val']][] { + function isNodeOrNullTuple(arr: [BTNKey | N, N['value']][]): arr is [N, N['value']][] { for (const [keyOrNode] of arr) if (keyOrNode instanceof BSTNode) return true; return false; } - function isBinaryTreeKeyOrNullTuple(arr: [BTNKey | N, N['val']][]): arr is [BTNKey, N['val']][] { + function isBinaryTreeKeyOrNullTuple(arr: [BTNKey | N, N['value']][]): arr is [BTNKey, N['value']][] { for (const [keyOrNode] of arr) if (typeof keyOrNode === 'number') return true; return false; } @@ -178,7 +178,7 @@ export class BST = BSTNode> throw new Error('Invalid input keysOrNodes'); } sortedKeysOrNodes = sorted.map(([keyOrNode]) => keyOrNode); - sortedData = sorted.map(([, val]) => val); + sortedData = sorted.map(([, value]) => value); const recursive = (arr: (BTNKey | null | N)[], data?: (V | undefined)[]) => { if (arr.length === 0) return; @@ -426,7 +426,7 @@ export class BST = BSTNode> if (l > r) return; const m = l + Math.floor((r - l) / 2); const midNode = sorted[m]; - this.add(midNode.key, midNode.val); + this.add(midNode.key, midNode.value); buildBalanceBST(l, m - 1); buildBalanceBST(m + 1, r); }; @@ -442,7 +442,7 @@ export class BST = BSTNode> if (l <= r) { const m = l + Math.floor((r - l) / 2); const midNode = sorted[m]; - this.add(midNode.key, midNode.val); + this.add(midNode.key, midNode.value); stack.push([m + 1, r]); stack.push([l, m - 1]); } diff --git a/src/data-structures/binary-tree/rb-tree.ts b/src/data-structures/binary-tree/rb-tree.ts index 56121f7..65edc63 100644 --- a/src/data-structures/binary-tree/rb-tree.ts +++ b/src/data-structures/binary-tree/rb-tree.ts @@ -3,8 +3,8 @@ import {IBinaryTree} from '../../interfaces'; import {BST, BSTNode} from './bst'; export class RBTreeNode = RBTreeNodeNested> extends BSTNode { - constructor(key: BTNKey, val?: V) { - super(key, val); + constructor(key: BTNKey, value?: V) { + super(key, value); this._color = RBColor.RED; } @@ -27,12 +27,12 @@ export class RBTree = RBTreeNode { + const dfs = (cur: SegmentTreeNode, index: number, sum: number, value?: SegmentTreeNodeVal) => { if (cur.start === cur.end && cur.start === index) { cur.sum = sum; - if (val !== undefined) cur.val = val; + if (value !== undefined) cur.value = value; return; } const mid = cur.start + Math.floor((cur.end - cur.start) / 2); if (index <= mid) { if (cur.left) { - dfs(cur.left, index, sum, val); + dfs(cur.left, index, sum, value); } } else { if (cur.right) { - dfs(cur.right, index, sum, val); + dfs(cur.right, index, sum, value); } } if (cur.left && cur.right) { @@ -185,7 +185,7 @@ export class SegmentTree { } }; - dfs(root, index, sum, val); + dfs(root, index, sum, value); } /** diff --git a/src/data-structures/binary-tree/tree-multiset.ts b/src/data-structures/binary-tree/tree-multiset.ts index e196af7..3af9da0 100644 --- a/src/data-structures/binary-tree/tree-multiset.ts +++ b/src/data-structures/binary-tree/tree-multiset.ts @@ -20,14 +20,14 @@ export class TreeMultisetNode< * The constructor function initializes a BinaryTreeNode object with a key, value, and count. * @param {BTNKey} key - The `key` parameter is of type `BTNKey` and represents the unique identifier * of the binary tree node. - * @param {V} [val] - The `val` parameter is an optional parameter of type `V`. It represents the value of the binary + * @param {V} [value] - The `value` parameter is an optional parameter of type `V`. It represents the value of the binary * tree node. If no value is provided, it will be `undefined`. * @param {number} [count=1] - The `count` parameter is a number that represents the number of times a particular value * occurs in a binary tree node. It has a default value of 1, which means that if no value is provided for the `count` * parameter when creating a new instance of the `BinaryTreeNode` class. */ - constructor(key: BTNKey, val?: V, count = 1) { - super(key, val); + constructor(key: BTNKey, value?: V, count = 1) { + super(key, value); this.count = count; } } @@ -59,13 +59,13 @@ export class TreeMultiset = TreeMultis * The function creates a new BSTNode with the given key, value, and count. * @param {BTNKey} key - The key parameter is the unique identifier for the binary tree node. It is used to * distinguish one node from another in the tree. - * @param {N} val - The `val` parameter represents the value that will be stored in the binary search tree node. + * @param {N} value - The `value` parameter represents the value that will be stored in the binary search tree node. * @param {number} [count] - The "count" parameter is an optional parameter of type number. It represents the number of * occurrences of the value in the binary search tree node. If not provided, the count will default to 1. * @returns A new instance of the BSTNode class with the specified key, value, and count (if provided). */ - override createNode(key: BTNKey, val?: V, count?: number): N { - return new TreeMultisetNode(key, val, count) as N; + override createNode(key: BTNKey, value?: V, count?: number): N { + return new TreeMultisetNode(key, value, count) as N; } /** @@ -74,22 +74,22 @@ export class TreeMultiset = TreeMultis * @param {BTNKey | N | null} keyOrNode - The `keyOrNode` parameter can be either a * `BTNKey` (which represents the key of the node to be added), a `N` (which represents a * node to be added), or `null` (which represents a null node). - * @param [val] - The `val` parameter represents the value associated with the key that is being + * @param [value] - The `value` parameter represents the value associated with the key that is being * added to the binary tree. * @param [count=1] - The `count` parameter represents the number of occurrences of the key/value * pair that will be added to the binary tree. It has a default value of 1, which means that if no * count is specified, the default count will be 1. * @returns The function `add` returns a value of type `N | null | undefined`. */ - override add(keyOrNode: BTNKey | N | null, val?: V, count = 1): N | null | undefined { + override add(keyOrNode: BTNKey | N | null, value?: V, count = 1): N | null | undefined { let inserted: N | null | undefined = undefined, newNode: N | null; if (keyOrNode instanceof TreeMultisetNode) { - newNode = this.createNode(keyOrNode.key, keyOrNode.val, keyOrNode.count); + newNode = this.createNode(keyOrNode.key, keyOrNode.value, keyOrNode.count); } else if (keyOrNode === null) { newNode = null; } else { - newNode = this.createNode(keyOrNode, val, count); + newNode = this.createNode(keyOrNode, value, count); } if (!this.root) { this._setRoot(newNode); @@ -103,7 +103,7 @@ export class TreeMultiset = TreeMultis if (cur) { if (newNode) { if (this._compare(cur.key, newNode.key) === CP.eq) { - cur.val = newNode.val; + cur.value = newNode.value; cur.count += newNode.count; this._setCount(this.count + newNode.count); traversing = false; @@ -199,7 +199,7 @@ export class TreeMultiset = TreeMultis const keyOrNode = keysOrNodes[i]; if (keyOrNode instanceof TreeMultisetNode) { - inserted.push(this.add(keyOrNode.key, keyOrNode.val, keyOrNode.count)); + inserted.push(this.add(keyOrNode.key, keyOrNode.value, keyOrNode.count)); continue; } @@ -233,7 +233,7 @@ export class TreeMultiset = TreeMultis if (l > r) return; const m = l + Math.floor((r - l) / 2); const midNode = sorted[m]; - this.add(midNode.key, midNode.val, midNode.count); + this.add(midNode.key, midNode.value, midNode.count); buildBalanceBST(l, m - 1); buildBalanceBST(m + 1, r); }; @@ -249,7 +249,7 @@ export class TreeMultiset = TreeMultis if (l <= r) { const m = l + Math.floor((r - l) / 2); const midNode = sorted[m]; - this.add(midNode.key, midNode.val, midNode.count); + this.add(midNode.key, midNode.value, midNode.count); stack.push([m + 1, r]); stack.push([l, m - 1]); } @@ -351,18 +351,18 @@ export class TreeMultiset = TreeMultis * @returns The method is returning the `destNode` after swapping its properties with the `srcNode`. */ protected override _swap(srcNode: N, destNode: N): N { - const {key, val, count, height} = destNode; - const tempNode = this.createNode(key, val, count); + const {key, value, count, height} = destNode; + const tempNode = this.createNode(key, value, count); if (tempNode) { tempNode.height = height; destNode.key = srcNode.key; - destNode.val = srcNode.val; + destNode.value = srcNode.value; destNode.count = srcNode.count; destNode.height = srcNode.height; srcNode.key = tempNode.key; - srcNode.val = tempNode.val; + srcNode.value = tempNode.value; srcNode.count = tempNode.count; srcNode.height = tempNode.height; } diff --git a/src/data-structures/graph/abstract-graph.ts b/src/data-structures/graph/abstract-graph.ts index 6005bcc..bd67db9 100644 --- a/src/data-structures/graph/abstract-graph.ts +++ b/src/data-structures/graph/abstract-graph.ts @@ -16,12 +16,12 @@ export abstract class AbstractVertex { * The function is a protected constructor that takes an key and an optional value as parameters. * @param {VertexKey} key - The `key` parameter is of type `VertexKey` and represents the identifier of the vertex. It is * used to uniquely identify the vertex object. - * @param {V} [val] - The parameter "val" is an optional parameter of type V. It is used to assign a value to the + * @param {V} [value] - The parameter "value" is an optional parameter of type V. It is used to assign a value to the * vertex. If no value is provided, it will be set to undefined. */ - protected constructor(key: VertexKey, val?: V) { + protected constructor(key: VertexKey, value?: V) { this._key = key; - this._val = val; + this._value = value; } private _key: VertexKey; @@ -34,14 +34,14 @@ export abstract class AbstractVertex { this._key = v; } - private _val: V | undefined; + private _value: V | undefined; - get val(): V | undefined { - return this._val; + get value(): V | undefined { + return this._value; } - set val(value: V | undefined) { - this._val = value; + set value(value: V | undefined) { + this._value = value; } } @@ -52,23 +52,23 @@ export abstract class AbstractEdge { * @param {number} [weight] - The `weight` parameter is an optional number that represents the weight of the object. If * a value is provided, it will be assigned to the `_weight` property. If no value is provided, the default value of 1 * will be assigned. - * @param {VO} [val] - The `val` parameter is of type `VO`, which means it can be any type. It is an optional parameter, + * @param {VO} [value] - The `value` parameter is of type `VO`, which means it can be any type. It is an optional parameter, * meaning it can be omitted when creating an instance of the class. */ - protected constructor(weight?: number, val?: E) { + protected constructor(weight?: number, value?: E) { this._weight = weight !== undefined ? weight : 1; - this._val = val; + this._value = value; this._hashCode = uuidV4(); } - private _val: E | undefined; + private _value: E | undefined; - get val(): E | undefined { - return this._val; + get value(): E | undefined { + return this._value; } - set val(value: E | undefined) { - this._val = value; + set value(value: E | undefined) { + this._value = value; } private _weight: number; @@ -119,9 +119,9 @@ export abstract class AbstractGraph< * In TypeScript, a subclass inherits the interface implementation of its parent class, without needing to implement the same interface again in the subclass. This behavior differs from Java's approach. In Java, if a parent class implements an interface, the subclass needs to explicitly implement the same interface, even if the parent class has already implemented it. * This means that using abstract methods in the parent class cannot constrain the grandchild classes. Defining methods within an interface also cannot constrain the descendant classes. When inheriting from this class, developers need to be aware that this method needs to be overridden. * @param key - * @param val + * @param value */ - abstract createVertex(key: VertexKey, val?: V): VO; + abstract createVertex(key: VertexKey, value?: V): VO; /** * In TypeScript, a subclass inherits the interface implementation of its parent class, without needing to implement the same interface again in the subclass. This behavior differs from Java's approach. In Java, if a parent class implements an interface, the subclass needs to explicitly implement the same interface, even if the parent class has already implemented it. @@ -129,9 +129,9 @@ export abstract class AbstractGraph< * @param srcOrV1 * @param destOrV2 * @param weight - * @param val + * @param value */ - abstract createEdge(srcOrV1: VertexKey, destOrV2: VertexKey, weight?: number, val?: E): EO; + abstract createEdge(srcOrV1: VertexKey, destOrV2: VertexKey, weight?: number, value?: E): EO; abstract deleteEdge(edge: EO): EO | null; @@ -170,13 +170,13 @@ export abstract class AbstractGraph< addVertex(vertex: VO): boolean; - addVertex(key: VertexKey, val?: V): boolean; + addVertex(key: VertexKey, value?: V): boolean; - addVertex(keyOrVertex: VertexKey | VO, val?: V): boolean { + addVertex(keyOrVertex: VertexKey | VO, value?: V): boolean { if (keyOrVertex instanceof AbstractVertex) { return this._addVertexOnly(keyOrVertex); } else { - const newVertex = this.createVertex(keyOrVertex, val); + const newVertex = this.createVertex(keyOrVertex, value); return this._addVertexOnly(newVertex); } } @@ -222,9 +222,9 @@ export abstract class AbstractGraph< addEdge(edge: EO): boolean; - addEdge(src: VO | VertexKey, dest: VO | VertexKey, weight?: number, val?: E): boolean; + addEdge(src: VO | VertexKey, dest: VO | VertexKey, weight?: number, value?: E): boolean; - addEdge(srcOrEdge: VO | VertexKey | EO, dest?: VO | VertexKey, weight?: number, val?: E): boolean { + addEdge(srcOrEdge: VO | VertexKey | EO, dest?: VO | VertexKey, weight?: number, value?: E): boolean { if (srcOrEdge instanceof AbstractEdge) { return this._addEdgeOnly(srcOrEdge); } else { @@ -232,7 +232,7 @@ export abstract class AbstractGraph< if (!(this.hasVertex(srcOrEdge) && this.hasVertex(dest))) return false; if (srcOrEdge instanceof AbstractVertex) srcOrEdge = srcOrEdge.key; if (dest instanceof AbstractVertex) dest = dest.key; - const newEdge = this.createEdge(srcOrEdge, dest, weight, val); + const newEdge = this.createEdge(srcOrEdge, dest, weight, value); return this._addEdgeOnly(newEdge); } else { throw new Error('dest must be a Vertex or vertex key while srcOrEdge is an Edge'); @@ -493,10 +493,10 @@ export abstract class AbstractGraph< const getMinOfNoSeen = () => { let min = Infinity; let minV: VO | null = null; - for (const [key, val] of distMap) { + for (const [key, value] of distMap) { if (!seen.has(key)) { - if (val < min) { - min = val; + if (value < min) { + min = value; minV = key; } } @@ -625,8 +625,8 @@ export abstract class AbstractGraph< if (vertexOrKey instanceof AbstractVertex) distMap.set(vertexOrKey, Infinity); } - const heap = new PriorityQueue<{key: number; val: VO}>({comparator: (a, b) => a.key - b.key}); - heap.add({key: 0, val: srcVertex}); + const heap = new PriorityQueue<{key: number; value: VO}>({comparator: (a, b) => a.key - b.key}); + heap.add({key: 0, value: srcVertex}); distMap.set(srcVertex, 0); preMap.set(srcVertex, null); @@ -656,7 +656,7 @@ export abstract class AbstractGraph< while (heap.size > 0) { const curHeapNode = heap.poll(); const dist = curHeapNode?.key; - const cur = curHeapNode?.val; + const cur = curHeapNode?.value; if (dist !== undefined) { if (cur) { seen.add(cur); @@ -677,7 +677,7 @@ export abstract class AbstractGraph< const distSrcToNeighbor = distMap.get(neighbor); if (distSrcToNeighbor) { if (dist + weight < distSrcToNeighbor) { - heap.add({key: dist + weight, val: neighbor}); + heap.add({key: dist + weight, value: neighbor}); preMap.set(neighbor, cur); distMap.set(neighbor, dist + weight); } diff --git a/src/data-structures/graph/directed-graph.ts b/src/data-structures/graph/directed-graph.ts index b3072a7..59a3860 100644 --- a/src/data-structures/graph/directed-graph.ts +++ b/src/data-structures/graph/directed-graph.ts @@ -15,11 +15,11 @@ export class DirectedVertex extends AbstractVertex { * The constructor function initializes a vertex with an optional value. * @param {VertexKey} key - The `key` parameter is of type `VertexKey` and represents the identifier of the vertex. It is * used to uniquely identify the vertex within a graph or data structure. - * @param {V} [val] - The "val" parameter is an optional parameter of type V. It is used to initialize the value of the + * @param {V} [value] - The "value" parameter is an optional parameter of type V. It is used to initialize the value of the * vertex. If no value is provided, the vertex will be initialized with a default value. */ - constructor(key: VertexKey, val?: V) { - super(key, val); + constructor(key: VertexKey, value?: V) { + super(key, value); } } @@ -32,11 +32,11 @@ export class DirectedEdge extends AbstractEdge { * @param {VertexKey} dest - The `dest` parameter represents the destination vertex of an edge. It is of type * `VertexKey`, which is likely a unique identifier for a vertex in a graph. * @param {number} [weight] - The weight parameter is an optional number that represents the weight of the edge. - * @param {E} [val] - The `val` parameter is an optional parameter of type `E`. It represents the value associated with + * @param {E} [value] - The `value` parameter is an optional parameter of type `E`. It represents the value associated with * the edge. */ - constructor(src: VertexKey, dest: VertexKey, weight?: number, val?: E) { - super(weight, val); + constructor(src: VertexKey, dest: VertexKey, weight?: number, value?: E) { + super(weight, value); this._src = src; this._dest = dest; } @@ -99,13 +99,13 @@ export class DirectedGraph< * The function creates a new vertex with an optional value and returns it. * @param {VertexKey} key - The `key` parameter is the unique identifier for the vertex. It is of type `VertexKey`, which * could be a number or a string depending on how you want to identify your vertices. - * @param [val] - The 'val' parameter is an optional value that can be assigned to the vertex. If a value is provided, - * it will be assigned to the 'val' property of the vertex. If no value is provided, the 'val' property will be + * @param [value] - The 'value' parameter is an optional value that can be assigned to the vertex. If a value is provided, + * it will be assigned to the 'value' property of the vertex. If no value is provided, the 'value' property will be * assigned the same value as the 'key' parameter * @returns a new instance of a DirectedVertex object, casted as type VO. */ - createVertex(key: VertexKey, val?: V): VO { - return new DirectedVertex(key, val ?? key) as VO; + createVertex(key: VertexKey, value?: V): VO { + return new DirectedVertex(key, value ?? key) as VO; } /** @@ -119,12 +119,12 @@ export class DirectedGraph< * @param {VertexKey} dest - The `dest` parameter is the identifier of the destination vertex for the edge. * @param {number} [weight] - The weight parameter is an optional number that represents the weight of the edge. If no * weight is provided, it defaults to 1. - * @param [val] - The 'val' parameter is an optional value that can be assigned to the edge. It can be of any type and + * @param [value] - The 'value' parameter is an optional value that can be assigned to the edge. It can be of any type and * is used to store additional information or data associated with the edge. * @returns a new instance of a DirectedEdge object, casted as type EO. */ - createEdge(src: VertexKey, dest: VertexKey, weight?: number, val?: E): EO { - return new DirectedEdge(src, dest, weight ?? 1, val) as EO; + createEdge(src: VertexKey, dest: VertexKey, weight?: number, value?: E): EO { + return new DirectedEdge(src, dest, weight ?? 1, value) as EO; } /** diff --git a/src/data-structures/graph/map-graph.ts b/src/data-structures/graph/map-graph.ts index 6be80f6..e7d6b5b 100644 --- a/src/data-structures/graph/map-graph.ts +++ b/src/data-structures/graph/map-graph.ts @@ -11,11 +11,11 @@ export class MapVertex extends DirectedVertex { * @param {number} long - The "long" parameter represents the longitude of a location. Longitude is a geographic * coordinate that specifies the east-west position of a point on the Earth's surface. It is measured in degrees, with * values ranging from -180 to 180. - * @param {V} [val] - The "val" parameter is an optional value of type V. It is not required to be provided when + * @param {V} [value] - The "value" parameter is an optional value of type V. It is not required to be provided when * creating an instance of the class. */ - constructor(key: VertexKey, val: V, lat: number, long: number) { - super(key, val); + constructor(key: VertexKey, value: V, lat: number, long: number) { + super(key, value); this._lat = lat; this._long = long; } @@ -49,11 +49,11 @@ export class MapEdge extends DirectedEdge { * a graph. * @param {VertexKey} dest - The `dest` parameter is the identifier of the destination vertex for an edge. * @param {number} [weight] - The weight parameter is an optional number that represents the weight of the edge. - * @param {E} [val] - The "val" parameter is an optional parameter of type E. It is used to store additional + * @param {E} [value] - The "value" parameter is an optional parameter of type E. It is used to store additional * information or data associated with the edge. */ - constructor(src: VertexKey, dest: VertexKey, weight?: number, val?: E) { - super(src, dest, weight, val); + constructor(src: VertexKey, dest: VertexKey, weight?: number, value?: E) { + super(src, dest, weight, value); } } @@ -102,15 +102,15 @@ export class MapGraph< * The function creates a new vertex with the given key, value, latitude, and longitude. * @param {VertexKey} key - The key parameter is the unique identifier for the vertex. It is of type VertexKey, which could * be a string or a number depending on how you define it in your code. - * @param [val] - The `val` parameter is an optional value that can be assigned to the `val` property of the vertex. It - * is of type `V`, which means it should be of the same type as the `val` property of the vertex class `VO`. + * @param [value] - The `value` parameter is an optional value that can be assigned to the `value` property of the vertex. It + * is of type `V`, which means it should be of the same type as the `value` property of the vertex class `VO`. * @param {number} lat - The `lat` parameter represents the latitude of the vertex. It is a number that specifies the * position of the vertex on the Earth's surface in the north-south direction. * @param {number} long - The `long` parameter represents the longitude coordinate of the vertex. * @returns The method is returning a new instance of the `MapVertex` class, casted as type `VO`. */ - override createVertex(key: VertexKey, val?: V, lat: number = this.origin[0], long: number = this.origin[1]): VO { - return new MapVertex(key, val, lat, long) as VO; + override createVertex(key: VertexKey, value?: V, lat: number = this.origin[0], long: number = this.origin[1]): VO { + return new MapVertex(key, value, lat, long) as VO; } /** @@ -121,11 +121,11 @@ export class MapGraph< * @param {number} [weight] - The `weight` parameter is an optional number that represents the weight of the edge. It * is used to assign a numerical value to the edge, which can be used in algorithms such as shortest path algorithms. * If the weight is not provided, it can be set to a default value or left undefined. - * @param [val] - The `val` parameter is an optional value that can be assigned to the edge. It can be of any type, + * @param [value] - The `value` parameter is an optional value that can be assigned to the edge. It can be of any type, * depending on the specific implementation of the `MapEdge` class. * @returns a new instance of the `MapEdge` class, cast as type `EO`. */ - override createEdge(src: VertexKey, dest: VertexKey, weight?: number, val?: E): EO { - return new MapEdge(src, dest, weight, val) as EO; + override createEdge(src: VertexKey, dest: VertexKey, weight?: number, value?: E): EO { + return new MapEdge(src, dest, weight, value) as EO; } } diff --git a/src/data-structures/graph/undirected-graph.ts b/src/data-structures/graph/undirected-graph.ts index 85a7e0b..39b63e7 100644 --- a/src/data-structures/graph/undirected-graph.ts +++ b/src/data-structures/graph/undirected-graph.ts @@ -15,11 +15,11 @@ export class UndirectedVertex extends AbstractVertex { * The constructor function initializes a vertex with an optional value. * @param {VertexKey} key - The `key` parameter is of type `VertexKey` and represents the identifier of the vertex. It is * used to uniquely identify the vertex within a graph or network. - * @param {V} [val] - The "val" parameter is an optional parameter of type V. It is used to initialize the value of the + * @param {V} [value] - The "value" parameter is an optional parameter of type V. It is used to initialize the value of the * vertex. If no value is provided, the vertex will be initialized with a default value. */ - constructor(key: VertexKey, val?: V) { - super(key, val); + constructor(key: VertexKey, value?: V) { + super(key, value); } } @@ -31,11 +31,11 @@ export class UndirectedEdge extends AbstractEdge { * @param {VertexKey} v2 - The parameter `v2` is a `VertexKey`, which represents the identifier of the second vertex in a * graph edge. * @param {number} [weight] - The weight parameter is an optional number that represents the weight of the edge. - * @param {E} [val] - The "val" parameter is an optional parameter of type E. It is used to store a value associated + * @param {E} [value] - The "value" parameter is an optional parameter of type E. It is used to store a value associated * with the edge. */ - constructor(v1: VertexKey, v2: VertexKey, weight?: number, val?: E) { - super(weight, val); + constructor(v1: VertexKey, v2: VertexKey, weight?: number, value?: E) { + super(weight, value); this._vertices = [v1, v2]; } @@ -77,13 +77,13 @@ export class UndirectedGraph< * The function creates a new vertex with an optional value and returns it. * @param {VertexKey} key - The `key` parameter is the unique identifier for the vertex. It is used to distinguish one * vertex from another in the graph. - * @param [val] - The `val` parameter is an optional value that can be assigned to the vertex. If a value is provided, + * @param [value] - The `value` parameter is an optional value that can be assigned to the vertex. If a value is provided, * it will be used as the value of the vertex. If no value is provided, the `key` parameter will be used as the value of * the vertex. * @returns The method is returning a new instance of the `UndirectedVertex` class, casted as type `VO`. */ - override createVertex(key: VertexKey, val?: VO['val']): VO { - return new UndirectedVertex(key, val ?? key) as VO; + override createVertex(key: VertexKey, value?: VO['value']): VO { + return new UndirectedVertex(key, value ?? key) as VO; } /** @@ -92,12 +92,12 @@ export class UndirectedGraph< * @param {VertexKey} v2 - The parameter `v2` represents the second vertex of the edge. * @param {number} [weight] - The `weight` parameter is an optional number that represents the weight of the edge. If * no weight is provided, it defaults to 1. - * @param [val] - The `val` parameter is an optional value that can be assigned to the edge. It can be of any type and + * @param [value] - The `value` parameter is an optional value that can be assigned to the edge. It can be of any type and * is used to store additional information or data associated with the edge. * @returns a new instance of the `UndirectedEdge` class, which is casted as type `EO`. */ - override createEdge(v1: VertexKey, v2: VertexKey, weight?: number, val?: EO['val']): EO { - return new UndirectedEdge(v1, v2, weight ?? 1, val) as EO; + override createEdge(v1: VertexKey, v2: VertexKey, weight?: number, value?: EO['value']): EO { + return new UndirectedEdge(v1, v2, weight ?? 1, value) as EO; } /** diff --git a/src/data-structures/hash/hash-table.ts b/src/data-structures/hash/hash-table.ts index bf0116e..26b4ddd 100644 --- a/src/data-structures/hash/hash-table.ts +++ b/src/data-structures/hash/hash-table.ts @@ -8,12 +8,12 @@ export class HashTableNode { key: K; - val: V; + value: V; next: HashTableNode | null; - constructor(key: K, val: V) { + constructor(key: K, value: V) { this.key = key; - this.val = val; + this.value = value; this.next = null; } } @@ -71,14 +71,14 @@ export class HashTable { * 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} val - The parameter `val` represents the value that you want to associate with the given key in the hash + * @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, val: V): void { + set(key: K, value: V): void { const index = this._hash(key); - const newNode = new HashTableNode(key, val); + const newNode = new HashTableNode(key, value); if (!this._buckets[index]) { this._buckets[index] = newNode; @@ -88,7 +88,7 @@ export class HashTable { while (currentNode) { if (currentNode.key === key) { // If the key already exists, update the value - currentNode.val = val; + currentNode.value = value; return; } if (!currentNode.next) { @@ -120,7 +120,7 @@ export class HashTable { while (currentNode) { if (currentNode.key === key) { - return currentNode.val; + return currentNode.value; } currentNode = currentNode.next; } @@ -259,7 +259,7 @@ export class HashTable { let currentNode = bucket; while (currentNode) { const newIndex = this._hash(currentNode.key); - const newNode = new HashTableNode(currentNode.key, currentNode.val); + const newNode = new HashTableNode(currentNode.key, currentNode.value); if (!newBuckets[newIndex]) { newBuckets[newIndex] = newNode; diff --git a/src/data-structures/linked-list/doubly-linked-list.ts b/src/data-structures/linked-list/doubly-linked-list.ts index b39a3ee..6c833bf 100644 --- a/src/data-structures/linked-list/doubly-linked-list.ts +++ b/src/data-structures/linked-list/doubly-linked-list.ts @@ -8,23 +8,23 @@ export class DoublyLinkedListNode { /** * The constructor function initializes the value, next, and previous properties of an object. - * @param {E} val - The "val" parameter is the value that will be stored in the node. It can be of any data type, as it + * @param {E} value - The "value" parameter is the value that will be stored in the node. It can be of any data type, as it * is defined as a generic type "E". */ - constructor(val: E) { - this._val = val; + constructor(value: E) { + this._value = value; this._next = null; this._prev = null; } - private _val: E; + private _value: E; - get val(): E { - return this._val; + get value(): E { + return this._value; } - set val(value: E) { - this._val = value; + set value(value: E) { + this._value = value; } private _next: DoublyLinkedListNode | null; @@ -104,10 +104,10 @@ export class DoublyLinkedList { /** * The push function adds a new node with the given value to the end of the doubly linked list. - * @param {E} val - The value to be added to the linked list. + * @param {E} value - The value to be added to the linked list. */ - push(val: E): void { - const newNode = new DoublyLinkedListNode(val); + push(value: E): void { + const newNode = new DoublyLinkedListNode(value); if (!this.head) { this.head = newNode; this.tail = newNode; @@ -121,15 +121,15 @@ export class DoublyLinkedList { /** * The addLast function adds a new node with the given value to the end of the doubly linked list. - * @param {E} val - The value to be added to the linked list. + * @param {E} value - The value to be added to the linked list. */ - addLast(val: E): void { - this.push(val); + addLast(value: E): void { + this.push(value); } /** * The `pop()` function removes and returns the value of the last node in a doubly linked list. - * @returns The method is returning the value of the removed node (removedNode.val) if the list is not empty. If the + * @returns The method is returning the value of the removed node (removedNode.value) if the list is not empty. If the * list is empty, it returns null. */ pop(): E | undefined { @@ -143,12 +143,12 @@ export class DoublyLinkedList { this.tail!.next = null; } this._length--; - return removedNode.val; + return removedNode.value; } /** * The `popLast()` function removes and returns the value of the last node in a doubly linked list. - * @returns The method is returning the value of the removed node (removedNode.val) if the list is not empty. If the + * @returns The method is returning the value of the removed node (removedNode.value) if the list is not empty. If the * list is empty, it returns null. */ popLast(): E | undefined { @@ -171,7 +171,7 @@ export class DoublyLinkedList { this.head!.prev = null; } this._length--; - return removedNode.val; + return removedNode.value; } /** @@ -185,11 +185,11 @@ export class DoublyLinkedList { /** * The unshift function adds a new node with the given value to the beginning of a doubly linked list. - * @param {E} val - The `val` parameter represents the value of the new node that will be added to the beginning of the + * @param {E} value - The `value` parameter represents the value of the new node that will be added to the beginning of the * doubly linked list. */ - unshift(val: E): void { - const newNode = new DoublyLinkedListNode(val); + unshift(value: E): void { + const newNode = new DoublyLinkedListNode(value); if (!this.head) { this.head = newNode; this.tail = newNode; @@ -203,11 +203,11 @@ export class DoublyLinkedList { /** * The addFirst function adds a new node with the given value to the beginning of a doubly linked list. - * @param {E} val - The `val` parameter represents the value of the new node that will be added to the beginning of the + * @param {E} value - The `value` parameter represents the value of the new node that will be added to the beginning of the * doubly linked list. */ - addFirst(val: E): void { - this.unshift(val); + addFirst(value: E): void { + this.unshift(value); } /** @@ -215,7 +215,7 @@ export class DoublyLinkedList { * @returns The method `getFirst()` returns the first node of the doubly linked list, or `null` if the list is empty. */ getFirst(): E | undefined { - return this.head?.val; + return this.head?.value; } /** @@ -223,7 +223,7 @@ export class DoublyLinkedList { * @returns The method `getLast()` returns the last node of the doubly linked list, or `null` if the list is empty. */ getLast(): E | undefined { - return this.tail?.val; + return this.tail?.value; } /** @@ -239,7 +239,7 @@ export class DoublyLinkedList { for (let i = 0; i < index; i++) { current = current!.next; } - return current!.val; + return current!.value; } /** @@ -262,15 +262,15 @@ export class DoublyLinkedList { /** * The function `findNodeByValue` searches for a node with a specific value in a doubly linked list and returns the * node if found, otherwise it returns null. - * @param {E} val - The `val` parameter is the value that we want to search for in the doubly linked list. - * @returns The function `findNodeByValue` returns a `DoublyLinkedListNode` if a node with the specified value `val` + * @param {E} value - The `value` parameter is the value that we want to search for in the doubly linked list. + * @returns The function `findNodeByValue` returns a `DoublyLinkedListNode` if a node with the specified value `value` * is found in the linked list. If no such node is found, it returns `null`. */ - getNode(val: E | null): DoublyLinkedListNode | null { + getNode(value: E | null): DoublyLinkedListNode | null { let current = this.head; while (current) { - if (current.val === val) { + if (current.value === value) { return current; } current = current.next; @@ -283,23 +283,23 @@ export class DoublyLinkedList { * The `insert` function inserts a value at a specified index in a doubly linked list. * @param {number} index - The index parameter represents the position at which the new value should be inserted in the * DoublyLinkedList. It is of type number. - * @param {E} val - The `val` parameter represents the value that you want to insert into the Doubly Linked List at the + * @param {E} value - The `value` parameter represents the value that you want to insert into the Doubly Linked List at the * specified index. * @returns The `insert` method returns a boolean value. It returns `true` if the insertion is successful, and `false` * if the index is out of bounds. */ - insertAt(index: number, val: E): boolean { + insertAt(index: number, value: E): boolean { if (index < 0 || index > this.length) return false; if (index === 0) { - this.unshift(val); + this.unshift(value); return true; } if (index === this.length) { - this.push(val); + this.push(value); return true; } - const newNode = new DoublyLinkedListNode(val); + const newNode = new DoublyLinkedListNode(value); const prevNode = this.getNodeAt(index - 1); const nextNode = prevNode!.next; newNode.prev = prevNode; @@ -365,7 +365,7 @@ export class DoublyLinkedList { prevNode!.next = nextNode; nextNode!.prev = prevNode; this._length--; - return removedNode!.val; + return removedNode!.value; } /** @@ -409,7 +409,7 @@ export class DoublyLinkedList { const array: E[] = []; let current = this.head; while (current) { - array.push(current.val); + array.push(current.value); current = current.next; } return array; @@ -439,11 +439,11 @@ export class DoublyLinkedList { * @returns The method `find` returns the first element in the linked list that satisfies the condition specified by * the callback function. If no element satisfies the condition, it returns `null`. */ - find(callback: (val: E) => boolean): E | null { + find(callback: (value: E) => boolean): E | null { let current = this.head; while (current) { - if (callback(current.val)) { - return current.val; + if (callback(current.value)) { + return current.value; } current = current.next; } @@ -452,16 +452,16 @@ export class DoublyLinkedList { /** * The function returns the index of the first occurrence of a given value in a linked list. - * @param {E} val - The parameter `val` is of type `E`, which means it can be any data type. It represents the value + * @param {E} value - The parameter `value` is of type `E`, which means it can be any data type. It represents the value * that we are searching for in the linked list. - * @returns The method `indexOf` returns the index of the first occurrence of the specified value `val` in the linked + * @returns The method `indexOf` returns the index of the first occurrence of the specified value `value` in the linked * list. If the value is not found, it returns -1. */ - indexOf(val: E): number { + indexOf(value: E): number { let index = 0; let current = this.head; while (current) { - if (current.val === val) { + if (current.value === value) { return index; } index++; @@ -478,11 +478,11 @@ export class DoublyLinkedList { * @returns The method `findBackward` returns the last value in the linked list that satisfies the condition specified by * the callback function. If no value satisfies the condition, it returns `null`. */ - findBackward(callback: (val: E) => boolean): E | null { + findBackward(callback: (value: E) => boolean): E | null { let current = this.tail; while (current) { - if (callback(current.val)) { - return current.val; + if (callback(current.value)) { + return current.value; } current = current.prev; } @@ -497,7 +497,7 @@ export class DoublyLinkedList { const array: E[] = []; let current = this.tail; while (current) { - array.push(current.val); + array.push(current.value); current = current.prev; } return array; @@ -518,15 +518,15 @@ export class DoublyLinkedList { /** * The `forEach` function iterates over each element in a linked list and applies a callback function to each element. - * @param callback - The callback parameter is a function that takes two arguments: val and index. The val argument + * @param callback - The callback parameter is a function that takes two arguments: value and index. The value argument * represents the value of the current node in the linked list, and the index argument represents the index of the * current node in the linked list. */ - forEach(callback: (val: E, index: number) => void): void { + forEach(callback: (value: E, index: number) => void): void { let current = this.head; let index = 0; while (current) { - callback(current.val, index); + callback(current.value, index); current = current.next; index++; } @@ -540,11 +540,11 @@ export class DoublyLinkedList { * DoublyLinkedList). * @returns The `map` function is returning a new instance of `DoublyLinkedList` that contains the mapped values. */ - map(callback: (val: E) => U): DoublyLinkedList { + map(callback: (value: E) => U): DoublyLinkedList { const mappedList = new DoublyLinkedList(); let current = this.head; while (current) { - mappedList.push(callback(current.val)); + mappedList.push(callback(current.value)); current = current.next; } return mappedList; @@ -557,12 +557,12 @@ export class DoublyLinkedList { * It is used to determine whether a value should be included in the filtered list or not. * @returns The filtered list, which is an instance of the DoublyLinkedList class. */ - filter(callback: (val: E) => boolean): DoublyLinkedList { + filter(callback: (value: E) => boolean): DoublyLinkedList { const filteredList = new DoublyLinkedList(); let current = this.head; while (current) { - if (callback(current.val)) { - filteredList.push(current.val); + if (callback(current.value)) { + filteredList.push(current.value); } current = current.next; } @@ -572,18 +572,18 @@ export class DoublyLinkedList { /** * The `reduce` function iterates over a linked list and applies a callback function to each element, accumulating a * single value. - * @param callback - The `callback` parameter is a function that takes two arguments: `accumulator` and `val`. It is + * @param callback - The `callback` parameter is a function that takes two arguments: `accumulator` and `value`. It is * used to perform a specific operation on each element of the linked list. * @param {U} initialValue - The `initialValue` parameter is the initial value of the accumulator. It is the starting * point for the reduction operation. * @returns The `reduce` method is returning the final value of the accumulator after iterating through all the * elements in the linked list. */ - reduce(callback: (accumulator: U, val: E) => U, initialValue: U): U { + reduce(callback: (accumulator: U, value: E) => U, initialValue: U): U { let accumulator = initialValue; let current = this.head; while (current) { - accumulator = callback(accumulator, current.val); + accumulator = callback(accumulator, current.value); current = current.next; } return accumulator; @@ -632,7 +632,7 @@ export class DoublyLinkedList { let current = this.head; while (current) { - yield current.val; + yield current.value; current = current.next; } } diff --git a/src/data-structures/linked-list/singly-linked-list.ts b/src/data-structures/linked-list/singly-linked-list.ts index fa443cc..d9a2818 100644 --- a/src/data-structures/linked-list/singly-linked-list.ts +++ b/src/data-structures/linked-list/singly-linked-list.ts @@ -8,22 +8,22 @@ export class SinglyLinkedListNode { /** * The constructor function initializes an instance of a class with a given value and sets the next property to null. - * @param {E} val - The "val" parameter is of type E, which means it can be any data type. It represents the value that + * @param {E} value - The "value" parameter is of type E, which means it can be any data type. It represents the value that * will be stored in the node of a linked list. */ - constructor(val: E) { - this._val = val; + constructor(value: E) { + this._value = value; this._next = null; } - private _val: E; + private _value: E; - get val(): E { - return this._val; + get value(): E { + return this._value; } - set val(value: E) { - this._val = value; + set value(value: E) { + this._value = value; } private _next: SinglyLinkedListNode | null; @@ -88,12 +88,12 @@ export class SinglyLinkedList { } /** - * The `push` function adds a new node with the given val to the end of a singly linked list. - * @param {E} val - The "val" parameter represents the value that you want to add to the linked list. It can be of + * The `push` function adds a new node with the given value to the end of a singly linked list. + * @param {E} value - The "value" parameter represents the value that you want to add to the linked list. It can be of * any type (E) as specified in the generic type declaration of the class or function. */ - push(val: E): void { - const newNode = new SinglyLinkedListNode(val); + push(value: E): void { + const newNode = new SinglyLinkedListNode(value); if (!this.head) { this.head = newNode; this.tail = newNode; @@ -105,12 +105,12 @@ export class SinglyLinkedList { } /** - * The `push` function adds a new node with the given val to the end of a singly linked list. - * @param {E} val - The "val" parameter represents the value that you want to add to the linked list. It can be of + * The `push` function adds a new node with the given value to the end of a singly linked list. + * @param {E} value - The "value" parameter represents the value that you want to add to the linked list. It can be of * any type (E) as specified in the generic type declaration of the class or function. */ - addLast(val: E): void { - this.push(val); + addLast(value: E): void { + this.push(value); } /** @@ -122,22 +122,22 @@ export class SinglyLinkedList { pop(): E | undefined { if (!this.head) return undefined; if (this.head === this.tail) { - const val = this.head.val; + const value = this.head.value; this.head = null; this.tail = null; this._length--; - return val; + return value; } let current = this.head; while (current.next !== this.tail) { current = current.next!; } - const val = this.tail!.val; + const value = this.tail!.value; current.next = null; this.tail = current; this._length--; - return val; + return value; } /** @@ -159,7 +159,7 @@ export class SinglyLinkedList { const removedNode = this.head; this.head = this.head.next; this._length--; - return removedNode.val; + return removedNode.value; } /** @@ -172,11 +172,11 @@ export class SinglyLinkedList { /** * The unshift function adds a new node with the given value to the beginning of a singly linked list. - * @param {E} val - The parameter "val" represents the value of the new node that will be added to the beginning of the + * @param {E} value - The parameter "value" represents the value of the new node that will be added to the beginning of the * linked list. */ - unshift(val: E): void { - const newNode = new SinglyLinkedListNode(val); + unshift(value: E): void { + const newNode = new SinglyLinkedListNode(value); if (!this.head) { this.head = newNode; this.tail = newNode; @@ -189,11 +189,11 @@ export class SinglyLinkedList { /** * The addFirst function adds a new node with the given value to the beginning of a singly linked list. - * @param {E} val - The parameter "val" represents the value of the new node that will be added to the beginning of the + * @param {E} value - The parameter "value" represents the value of the new node that will be added to the beginning of the * linked list. */ - addFirst(val: E): void { - this.unshift(val); + addFirst(value: E): void { + this.unshift(value); } /** @@ -209,7 +209,7 @@ export class SinglyLinkedList { for (let i = 0; i < index; i++) { current = current!.next; } - return current!.val; + return current!.value; } /** @@ -243,7 +243,7 @@ export class SinglyLinkedList { const removedNode = prevNode!.next; prevNode!.next = removedNode!.next; this._length--; - return removedNode!.val; + return removedNode!.value; } /** @@ -257,7 +257,7 @@ export class SinglyLinkedList { if (!valueOrNode) return false; let value: E; if (valueOrNode instanceof SinglyLinkedListNode) { - value = valueOrNode.val; + value = valueOrNode.value; } else { value = valueOrNode; } @@ -265,7 +265,7 @@ export class SinglyLinkedList { prev = null; while (current) { - if (current.val === value) { + if (current.value === value) { if (prev === null) { this.head = current.next; if (current === this.tail) { @@ -291,23 +291,23 @@ export class SinglyLinkedList { * The `insertAt` function inserts a value at a specified index in a singly linked list. * @param {number} index - The index parameter represents the position at which the new value should be inserted in the * linked list. It is of type number. - * @param {E} val - The `val` parameter represents the value that you want to insert into the linked list at the + * @param {E} value - The `value` parameter represents the value that you want to insert into the linked list at the * specified index. * @returns The `insert` method returns a boolean value. It returns `true` if the insertion is successful, and `false` * if the index is out of bounds. */ - insertAt(index: number, val: E): boolean { + insertAt(index: number, value: E): boolean { if (index < 0 || index > this.length) return false; if (index === 0) { - this.unshift(val); + this.unshift(value); return true; } if (index === this.length) { - this.push(val); + this.push(value); return true; } - const newNode = new SinglyLinkedListNode(val); + const newNode = new SinglyLinkedListNode(value); const prevNode = this.getNodeAt(index - 1); newNode.next = prevNode!.next; prevNode!.next = newNode; @@ -341,7 +341,7 @@ export class SinglyLinkedList { const array: E[] = []; let current = this.head; while (current) { - array.push(current.val); + array.push(current.value); current = current.next; } return array; @@ -375,11 +375,11 @@ export class SinglyLinkedList { * @returns The method `find` returns the first element in the linked list that satisfies the condition specified by * the callback function. If no element satisfies the condition, it returns `null`. */ - find(callback: (val: E) => boolean): E | null { + find(callback: (value: E) => boolean): E | null { let current = this.head; while (current) { - if (callback(current.val)) { - return current.val; + if (callback(current.value)) { + return current.value; } current = current.next; } @@ -397,7 +397,7 @@ export class SinglyLinkedList { let current = this.head; while (current) { - if (current.val === value) { + if (current.value === value) { return index; } index++; @@ -418,7 +418,7 @@ export class SinglyLinkedList { let current = this.head; while (current) { - if (current.val === value) { + if (current.value === value) { return current; } current = current.next; @@ -440,18 +440,18 @@ export class SinglyLinkedList { let existingValue: E; if (existingValueOrNode instanceof SinglyLinkedListNode) { - existingValue = existingValueOrNode.val; + existingValue = existingValueOrNode.value; } else { existingValue = existingValueOrNode; } - if (this.head.val === existingValue) { + if (this.head.value === existingValue) { this.unshift(newValue); return true; } let current = this.head; while (current.next) { - if (current.next.val === existingValue) { + if (current.next.value === existingValue) { const newNode = new SinglyLinkedListNode(newValue); newNode.next = current.next; current.next = newNode; @@ -505,7 +505,7 @@ export class SinglyLinkedList { let current = this.head; while (current) { - if (current.val === value) { + if (current.value === value) { count++; } current = current.next; @@ -516,15 +516,15 @@ export class SinglyLinkedList { /** * The `forEach` function iterates over each element in a linked list and applies a callback function to each element. - * @param callback - The callback parameter is a function that takes two arguments: val and index. The val argument + * @param callback - The callback parameter is a function that takes two arguments: value and index. The value argument * represents the value of the current node in the linked list, and the index argument represents the index of the * current node in the linked list. */ - forEach(callback: (val: E, index: number) => void): void { + forEach(callback: (value: E, index: number) => void): void { let current = this.head; let index = 0; while (current) { - callback(current.val, index); + callback(current.value, index); current = current.next; index++; } @@ -538,11 +538,11 @@ export class SinglyLinkedList { * SinglyLinkedList). * @returns The `map` function is returning a new instance of `SinglyLinkedList` that contains the mapped values. */ - map(callback: (val: E) => U): SinglyLinkedList { + map(callback: (value: E) => U): SinglyLinkedList { const mappedList = new SinglyLinkedList(); let current = this.head; while (current) { - mappedList.push(callback(current.val)); + mappedList.push(callback(current.value)); current = current.next; } return mappedList; @@ -555,12 +555,12 @@ export class SinglyLinkedList { * It is used to determine whether a value should be included in the filtered list or not. * @returns The filtered list, which is an instance of the SinglyLinkedList class. */ - filter(callback: (val: E) => boolean): SinglyLinkedList { + filter(callback: (value: E) => boolean): SinglyLinkedList { const filteredList = new SinglyLinkedList(); let current = this.head; while (current) { - if (callback(current.val)) { - filteredList.push(current.val); + if (callback(current.value)) { + filteredList.push(current.value); } current = current.next; } @@ -570,18 +570,18 @@ export class SinglyLinkedList { /** * The `reduce` function iterates over a linked list and applies a callback function to each element, accumulating a * single value. - * @param callback - The `callback` parameter is a function that takes two arguments: `accumulator` and `val`. It is + * @param callback - The `callback` parameter is a function that takes two arguments: `accumulator` and `value`. It is * used to perform a specific operation on each element of the linked list. * @param {U} initialValue - The `initialValue` parameter is the initial value of the accumulator. It is the starting * point for the reduction operation. * @returns The `reduce` method is returning the final value of the accumulator after iterating through all the * elements in the linked list. */ - reduce(callback: (accumulator: U, val: E) => U, initialValue: U): U { + reduce(callback: (accumulator: U, value: E) => U, initialValue: U): U { let accumulator = initialValue; let current = this.head; while (current) { - accumulator = callback(accumulator, current.val); + accumulator = callback(accumulator, current.value); current = current.next; } return accumulator; @@ -594,7 +594,7 @@ export class SinglyLinkedList { let current = this.head; while (current) { - yield current.val; + yield current.value; current = current.next; } } diff --git a/src/data-structures/queue/queue.ts b/src/data-structures/queue/queue.ts index abc7ad1..6f10f59 100644 --- a/src/data-structures/queue/queue.ts +++ b/src/data-structures/queue/queue.ts @@ -27,7 +27,7 @@ export class SkipQueue extends SinglyLinkedList { * @returns The `peek()` method is returning the value of the `head` node if it exists, otherwise it returns `undefined`. */ peek(): E | undefined { - return this.head?.val; + return this.head?.value; } } diff --git a/src/interfaces/binary-tree.ts b/src/interfaces/binary-tree.ts index 1437d6c..649cf27 100644 --- a/src/interfaces/binary-tree.ts +++ b/src/interfaces/binary-tree.ts @@ -2,9 +2,9 @@ import {BinaryTreeNode} from '../data-structures'; import {BinaryTreeDeletedResult, BTNKey, BinaryTreeNodeNested, BTNCallback} from '../types'; export interface IBinaryTree = BinaryTreeNodeNested> { - createNode(key: BTNKey, val?: N['val']): N; + createNode(key: BTNKey, value?: N['value']): N; - add(keyOrNode: BTNKey | N | null, val?: N['val']): N | null | undefined; + add(keyOrNode: BTNKey | N | null, value?: N['value']): N | null | undefined; delete>(identifier: ReturnType | null, callback: C): BinaryTreeDeletedResult[]; } diff --git a/src/interfaces/graph.ts b/src/interfaces/graph.ts index 7b968ae..8daabaa 100644 --- a/src/interfaces/graph.ts +++ b/src/interfaces/graph.ts @@ -1,7 +1,7 @@ import {VertexKey} from '../types'; export interface IGraph { - createVertex(key: VertexKey, val?: V): VO; + createVertex(key: VertexKey, value?: V): VO; - createEdge(srcOrV1: VertexKey, destOrV2: VertexKey, weight?: number, val?: E): EO; + createEdge(srcOrV1: VertexKey, destOrV2: VertexKey, weight?: number, value?: E): EO; } diff --git a/test/integration/bst.test.ts b/test/integration/bst.test.ts index 0a33db7..4a97a89 100644 --- a/test/integration/bst.test.ts +++ b/test/integration/bst.test.ts @@ -6,8 +6,8 @@ describe('Individual package BST operations test', () => { expect(bst).toBeInstanceOf(BST); bst.add(11, 11); bst.add(3, 3); - const idsOrVals = [15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5]; - bst.addMany(idsOrVals, idsOrVals, false); + const idsOrValues = [15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5]; + bst.addMany(idsOrValues, idsOrValues, false); expect(bst.root).toBeInstanceOf(BSTNode); if (bst.root) expect(bst.root.key).toBe(11); diff --git a/test/unit/data-structures/binary-tree/avl-tree.test.ts b/test/unit/data-structures/binary-tree/avl-tree.test.ts index e7e7d00..eb0cf8a 100644 --- a/test/unit/data-structures/binary-tree/avl-tree.test.ts +++ b/test/unit/data-structures/binary-tree/avl-tree.test.ts @@ -31,7 +31,7 @@ describe('AVL Tree Test', () => { expect(lesserSum).toBe(45); // node15 has type problem. After the uniform design, the generics of containers (DirectedGraph, BST) are based on the type of value. However, this design has a drawback: when I attempt to inherit from the Vertex or BSTNode classes, the types of the results obtained by all methods are those of the parent class. - expect(node15?.val).toBe(15); + expect(node15?.value).toBe(15); const dfs = tree.dfs(node => node, 'in'); expect(dfs[0].key).toBe(1); @@ -140,7 +140,7 @@ describe('AVL Tree Test recursively', () => { expect(lesserSum).toBe(45); // node15 has type problem. After the uniform design, the generics of containers (DirectedGraph, BST) are based on the type of value. However, this design has a drawback: when I attempt to inherit from the Vertex or BSTNode classes, the types of the results obtained by all methods are those of the parent class. - expect(node15?.val).toBe(15); + expect(node15?.value).toBe(15); const dfs = tree.dfs(node => node, 'in'); expect(dfs[0].key).toBe(1); diff --git a/test/unit/data-structures/binary-tree/binary-index-tree.test.ts b/test/unit/data-structures/binary-tree/binary-index-tree.test.ts index db4e912..4135fab 100644 --- a/test/unit/data-structures/binary-tree/binary-index-tree.test.ts +++ b/test/unit/data-structures/binary-tree/binary-index-tree.test.ts @@ -297,9 +297,9 @@ describe('', () => { } } - update(index: number, val: number): void { - this._tree.update(index + 1, val - this._nums[index]); - this._nums[index] = val; + update(index: number, value: number): void { + this._tree.update(index + 1, value - this._nums[index]); + this._nums[index] = value; } sumRange(left: number, right: number): number { diff --git a/test/unit/data-structures/binary-tree/binary-tree.test.ts b/test/unit/data-structures/binary-tree/binary-tree.test.ts index 2bd6647..e141fec 100644 --- a/test/unit/data-structures/binary-tree/binary-tree.test.ts +++ b/test/unit/data-structures/binary-tree/binary-tree.test.ts @@ -20,10 +20,10 @@ describe('BinaryTreeNode', () => { it('should set and get the value correctly', () => { const node: BinaryTreeNode = new BinaryTreeNode(1, 42); - expect(node.val).toBe(42); + expect(node.value).toBe(42); - node.val = 55; - expect(node.val).toBe(55); + node.value = 55; + expect(node.value).toBe(55); }); it('should set and get the left child correctly', () => { @@ -110,7 +110,7 @@ describe('BinaryTree', () => { const node4 = tree.get(4); expect(tree.has(node4)).toBe(false); expect(tree.has(node4, node => node)).toBe(false); - expect(tree.has('3', node => node.val?.toString())).toBe(true); + expect(tree.has('3', node => node.value?.toString())).toBe(true); }); it('should getDepth return correct depth', () => { @@ -343,9 +343,9 @@ describe('BinaryTree', () => { const nodeB = tree.get(3); expect(nodeA?.key).toBe(5); - expect(nodeA?.val).toBe('A'); + expect(nodeA?.value).toBe('A'); expect(nodeB?.key).toBe(3); - expect(nodeB?.val).toBe('B'); + expect(nodeB?.value).toBe('B'); }); it('should return null when getting a non-existent node', () => { @@ -437,14 +437,14 @@ describe('BinaryTree', () => { tree.add(3, 'B'); tree.add(7, 'C'); - const nodes = tree.getNodes('B', (node: BinaryTreeNode) => node.val); + const nodes = tree.getNodes('B', (node: BinaryTreeNode) => node.value); expect(nodes.length).toBe(1); expect(nodes[0].key).toBe(3); const nodesRec = tree.getNodes( 'B', - (node: BinaryTreeNode) => node.val, + (node: BinaryTreeNode) => node.value, false, tree.root, IterationType.RECURSIVE diff --git a/test/unit/data-structures/binary-tree/bst.test.ts b/test/unit/data-structures/binary-tree/bst.test.ts index b4d4a44..7d6a5ab 100644 --- a/test/unit/data-structures/binary-tree/bst.test.ts +++ b/test/unit/data-structures/binary-tree/bst.test.ts @@ -26,7 +26,7 @@ describe('BST operations test', () => { const nodeId10 = bst.get(10); expect(nodeId10?.key).toBe(10); - const nodeVal9 = bst.get(9, node => node.val); + const nodeVal9 = bst.get(9, node => node.value); expect(nodeVal9?.key).toBe(9); const leftMost = bst.getLeftMost(); @@ -236,7 +236,7 @@ describe('BST operations test', () => { expect(leftMost?.key).toBe(1); const node15 = objBST.get(15); - expect(node15?.val).toEqual({key: 15, keyA: 15}); + expect(node15?.value).toEqual({key: 15, keyA: 15}); const minNodeBySpecificNode = node15 && objBST.getLeftMost(node15); expect(minNodeBySpecificNode?.key).toBe(12); @@ -416,7 +416,7 @@ describe('BST operations test recursively', () => { const nodeId10 = bst.get(10); expect(nodeId10?.key).toBe(10); - const nodeVal9 = bst.get(9, node => node.val); + const nodeVal9 = bst.get(9, node => node.value); expect(nodeVal9?.key).toBe(9); const leftMost = bst.getLeftMost(); @@ -626,7 +626,7 @@ describe('BST operations test recursively', () => { expect(leftMost?.key).toBe(1); const node15 = objBST.get(15); - expect(node15?.val).toEqual({key: 15, keyA: 15}); + expect(node15?.value).toEqual({key: 15, keyA: 15}); const minNodeBySpecificNode = node15 && objBST.getLeftMost(node15); expect(minNodeBySpecificNode?.key).toBe(12); diff --git a/test/unit/data-structures/binary-tree/rb-tree.test.ts b/test/unit/data-structures/binary-tree/rb-tree.test.ts index afd016b..43d817f 100644 --- a/test/unit/data-structures/binary-tree/rb-tree.test.ts +++ b/test/unit/data-structures/binary-tree/rb-tree.test.ts @@ -16,10 +16,10 @@ describe('RBTreeNode', () => { it('should set and get the value correctly', () => { const node: RBTreeNode = new RBTreeNode(1, 42); - expect(node.val).toBe(42); + expect(node.value).toBe(42); - node.val = 55; - expect(node.val).toBe(55); + node.value = 55; + expect(node.value).toBe(55); }); it('should set and get the left child correctly', () => { diff --git a/test/unit/data-structures/binary-tree/tree-multiset.test.ts b/test/unit/data-structures/binary-tree/tree-multiset.test.ts index ab90ae2..c5c58c3 100644 --- a/test/unit/data-structures/binary-tree/tree-multiset.test.ts +++ b/test/unit/data-structures/binary-tree/tree-multiset.test.ts @@ -26,7 +26,7 @@ describe('TreeMultiset operations test', () => { const nodeId10 = treeMultiset.get(10); expect(nodeId10?.key).toBe(10); - const nodeVal9 = treeMultiset.get(9, node => node.val); + const nodeVal9 = treeMultiset.get(9, node => node.value); expect(nodeVal9?.key).toBe(9); const nodesByCount1 = treeMultiset.getNodes(1, node => node.count); @@ -266,7 +266,7 @@ describe('TreeMultiset operations test recursively', () => { const nodeId10 = treeMultiset.get(10); expect(nodeId10?.key).toBe(10); - const nodeVal9 = treeMultiset.get(9, node => node.val); + const nodeVal9 = treeMultiset.get(9, node => node.value); expect(nodeVal9?.key).toBe(9); const nodesByCount1 = treeMultiset.getNodes(1, node => node.count); diff --git a/test/unit/data-structures/graph/abstract-graph.test.ts b/test/unit/data-structures/graph/abstract-graph.test.ts index efd2250..b9dbefd 100644 --- a/test/unit/data-structures/graph/abstract-graph.test.ts +++ b/test/unit/data-structures/graph/abstract-graph.test.ts @@ -3,9 +3,9 @@ import {AbstractEdge, AbstractGraph, AbstractVertex, VertexKey} from '../../../. class MyVertex extends AbstractVertex { data?: V; - constructor(key: VertexKey, val?: V) { - super(key, val); - this.data = val; + constructor(key: VertexKey, value?: V) { + super(key, value); + this.data = value; } } @@ -14,11 +14,11 @@ class MyEdge extends AbstractEdge { src: VertexKey; dest: VertexKey; - constructor(srcOrV1: VertexKey, destOrV2: VertexKey, weight?: number, val?: E) { - super(weight, val); + constructor(srcOrV1: VertexKey, destOrV2: VertexKey, weight?: number, value?: E) { + super(weight, value); this.src = srcOrV1; this.dest = destOrV2; - this.data = val; + this.data = value; this._setHashCode(''); } } @@ -29,12 +29,12 @@ class MyGraph< VO extends MyVertex = MyVertex, EO extends MyEdge = MyEdge > extends AbstractGraph { - createVertex(key: VertexKey, val?: V): VO { - return new MyVertex(key, val) as VO; + createVertex(key: VertexKey, value?: V): VO { + return new MyVertex(key, value) as VO; } - createEdge(srcOrV1: VertexKey, destOrV2: VertexKey, weight?: number, val?: E): EO { - return new MyEdge(srcOrV1, destOrV2, weight, val) as EO; + createEdge(srcOrV1: VertexKey, destOrV2: VertexKey, weight?: number, value?: E): EO { + return new MyEdge(srcOrV1, destOrV2, weight, value) as EO; } deleteEdge(edge: EO): EO | null { @@ -92,9 +92,9 @@ describe('AbstractGraph Operation Test', () => { // const eBC = new MyEdge('B', 'C'); // const eCD = new MyEdge('C', 'D'); vA!.key = vA?.key || 1; - vA!.val = vA?.val ?? 2; + vA!.value = vA?.value ?? 2; - eAB!.val = eAB.val; + eAB!.value = eAB.value; const hs = eAB.hashCode; expect(hs).toBe(''); diff --git a/test/unit/data-structures/graph/directed-graph.test.ts b/test/unit/data-structures/graph/directed-graph.test.ts index 9b2c2a4..de01fc9 100644 --- a/test/unit/data-structures/graph/directed-graph.test.ts +++ b/test/unit/data-structures/graph/directed-graph.test.ts @@ -93,9 +93,9 @@ describe('DirectedGraph Operation Test', () => { }); class MyVertex extends DirectedVertex { - constructor(key: VertexKey, val?: V) { - super(key, val); - this._data = val; + constructor(key: VertexKey, value?: V) { + super(key, value); + this._data = value; } private _data: V | undefined; @@ -110,9 +110,9 @@ class MyVertex extends DirectedVertex { } class MyEdge extends DirectedEdge { - constructor(v1: VertexKey, v2: VertexKey, weight?: number, val?: E) { - super(v1, v2, weight, val); - this._data = val; + constructor(v1: VertexKey, v2: VertexKey, weight?: number, value?: E) { + super(v1, v2, weight, value); + this._data = value; } private _data: E | undefined; @@ -132,12 +132,12 @@ class MyDirectedGraph< VO extends MyVertex = MyVertex, EO extends MyEdge = MyEdge > extends DirectedGraph { - createVertex(key: VertexKey, val: V): VO { - return new MyVertex(key, val) as VO; + createVertex(key: VertexKey, value: V): VO { + return new MyVertex(key, value) as VO; } - createEdge(src: VertexKey, dest: VertexKey, weight?: number, val?: E): EO { - return new MyEdge(src, dest, weight ?? 1, val) as EO; + createEdge(src: VertexKey, dest: VertexKey, weight?: number, value?: E): EO { + return new MyEdge(src, dest, weight ?? 1, value) as EO; } setInEdgeMap(value: Map) { @@ -192,7 +192,7 @@ describe('Inherit from DirectedGraph and perform operations', () => { expect(edge1).toBeInstanceOf(MyEdge); if (edge1) { expect(edge1.data).toBe('val1'); - expect(edge1?.val).toBe('val1'); + expect(edge1?.value).toBe('val1'); expect(edge1).toBeInstanceOf(MyEdge); expect(edge1.src).toBe(1); expect(edge1).toEqual(edge2); @@ -214,7 +214,7 @@ describe('Inherit from DirectedGraph and perform operations', () => { expect(removedEdge).toBeInstanceOf(MyEdge); if (removedEdge) { - removedEdge && expect(removedEdge.val).toBe('edge-data1-2'); + removedEdge && expect(removedEdge.value).toBe('edge-data1-2'); removedEdge && expect(removedEdge.src).toBe(1); } expect(edgeAfterRemoval).toBeNull(); diff --git a/test/unit/data-structures/hash/hash-table.test.ts b/test/unit/data-structures/hash/hash-table.test.ts index 363afd0..284eb5f 100644 --- a/test/unit/data-structures/hash/hash-table.test.ts +++ b/test/unit/data-structures/hash/hash-table.test.ts @@ -7,7 +7,7 @@ describe('HashNode', () => { const hashNode = new HashTableNode(key, value); expect(hashNode.key).toBe(key); - expect(hashNode.val).toBe(value); + expect(hashNode.value).toBe(value); expect(hashNode.next).toBe(null); }); }); diff --git a/test/unit/data-structures/linked-list/doubly-linked-list.test.ts b/test/unit/data-structures/linked-list/doubly-linked-list.test.ts index 7174969..5812598 100644 --- a/test/unit/data-structures/linked-list/doubly-linked-list.test.ts +++ b/test/unit/data-structures/linked-list/doubly-linked-list.test.ts @@ -4,9 +4,9 @@ import {bigO, magnitude} from '../../../utils'; describe('DoublyLinkedListNode', () => { it('should DoublyLinkedListNode', () => { const node1 = new DoublyLinkedListNode(2); - expect(node1.val).toBe(2); - node1.val = 1; - expect(node1.val).toBe(1); + expect(node1.value).toBe(2); + node1.value = 1; + expect(node1.value).toBe(1); }); }); @@ -33,13 +33,13 @@ describe('DoublyLinkedList Operation Test', () => { it('should delete tail', () => { expect(list.delete(list.tail)).toBe(true); - expect(list.tail?.val).toBe(4); + expect(list.tail?.value).toBe(4); expect(list.delete(6)).toBe(false); - expect(list.tail?.val).toBe(4); + expect(list.tail?.value).toBe(4); }); it('should find null', () => { - expect(list.find(val => val === 6)).toBe(null); + expect(list.find(value => value === 6)).toBe(null); }); it('should indexOf -1', () => { @@ -47,7 +47,7 @@ describe('DoublyLinkedList Operation Test', () => { }); it('should findBackward null', () => { - expect(list.findBackward(val => val === 0)).toBe(null); + expect(list.findBackward(value => value === 0)).toBe(null); }); it('should insertAfter tail', () => { @@ -80,8 +80,8 @@ describe('DoublyLinkedList Operation Test', () => { list.push(2); list.push(3); expect(list.length).toBe(3); - expect(list.head!.val).toBe(1); - expect(list.tail!.val).toBe(3); + expect(list.head!.value).toBe(1); + expect(list.tail!.value).toBe(3); }); it('should pop elements from the end of the list', () => { @@ -90,8 +90,8 @@ describe('DoublyLinkedList Operation Test', () => { const poppedValue = list.pop(); expect(poppedValue).toBe(2); expect(list.length).toBe(1); - expect(list.head!.val).toBe(1); - expect(list.tail!.val).toBe(1); + expect(list.head!.value).toBe(1); + expect(list.tail!.value).toBe(1); }); it('should insert elements at specific positions', () => { list.push(1); @@ -114,7 +114,7 @@ describe('DoublyLinkedList Operation Test', () => { list.insertAt(5, 4); expect(list.length).toBe(6); expect(list.getAt(5)).toBe(4); - expect(list.tail!.val).toBe(4); + expect(list.tail!.value).toBe(4); }); it('should delete elements at specific positions', () => { @@ -126,12 +126,12 @@ describe('DoublyLinkedList Operation Test', () => { const deletedValue = list.deleteAt(0); expect(deletedValue).toBe(1); expect(list.length).toBe(2); - expect(list.head!.val).toBe(2); + expect(list.head!.value).toBe(2); // Deleting from the middle list.deleteAt(0); // Deleting the second element expect(list.length).toBe(1); - expect(list.head!.val).toBe(3); + expect(list.head!.value).toBe(3); // Deleting from the end list.deleteAt(0); @@ -147,12 +147,12 @@ describe('DoublyLinkedList Operation Test', () => { list.delete(2); expect(list.length).toBe(2); - expect(list.head!.val).toBe(1); - expect(list.tail!.val).toBe(3); + expect(list.head!.value).toBe(1); + expect(list.tail!.value).toBe(3); list.delete(1); expect(list.length).toBe(1); - expect(list.head!.val).toBe(3); + expect(list.head!.value).toBe(3); list.delete(3); expect(list.length).toBe(0); @@ -176,7 +176,7 @@ describe('DoublyLinkedList Operation Test', () => { list.push(2); list.push(3); - const mappedList = list.map(val => val * 2); + const mappedList = list.map(value => value * 2); expect(mappedList.toArray()).toEqual([2, 4, 6]); }); @@ -187,7 +187,7 @@ describe('DoublyLinkedList Operation Test', () => { list.push(3); list.push(4); - const filteredList = list.filter(val => val % 2 === 0); + const filteredList = list.filter(value => value % 2 === 0); expect(filteredList.toArray()).toEqual([2, 4]); }); @@ -198,7 +198,7 @@ describe('DoublyLinkedList Operation Test', () => { list.push(3); list.push(4); - const sum = list.reduce((acc, val) => acc + val, 0); + const sum = list.reduce((acc, value) => acc + value, 0); expect(sum).toBe(10); }); @@ -227,7 +227,7 @@ describe('DoublyLinkedList Operation Test', () => { list.push(2); list.push(3); - const found = list.find(val => val % 2 === 0); + const found = list.find(value => value % 2 === 0); expect(found).toBe(2); }); @@ -248,7 +248,7 @@ describe('DoublyLinkedList Operation Test', () => { list.push(3); list.push(4); - const lastEven = list.findBackward(val => val % 2 === 0); + const lastEven = list.findBackward(value => value % 2 === 0); expect(lastEven).toBe(4); }); @@ -283,8 +283,8 @@ describe('DoublyLinkedList Operation Test', () => { list.reverse(); expect(list.toArray()).toEqual([3, 2, 1]); - expect(list.head?.val).toBe(3); - expect(list.tail?.val).toBe(1); + expect(list.head?.value).toBe(3); + expect(list.tail?.value).toBe(1); }); it('should iterate over each element and apply a callback', () => { @@ -293,8 +293,8 @@ describe('DoublyLinkedList Operation Test', () => { list.push(3); const result: number[] = []; - list.forEach(val => { - result.push(val * 2); + list.forEach(value => { + result.push(value * 2); }); expect(result).toEqual([2, 4, 6]); @@ -305,7 +305,7 @@ describe('DoublyLinkedList Operation Test', () => { list.push(2); list.push(3); - const mappedList = list.map(val => val * 2); + const mappedList = list.map(value => value * 2); expect(mappedList.toArray()).toEqual([2, 4, 6]); }); @@ -316,7 +316,7 @@ describe('DoublyLinkedList Operation Test', () => { list.push(3); list.push(4); - const filteredList = list.filter(val => val % 2 === 0); + const filteredList = list.filter(value => value % 2 === 0); expect(filteredList.toArray()).toEqual([2, 4]); }); @@ -326,7 +326,7 @@ describe('DoublyLinkedList Operation Test', () => { list.push(2); list.push(3); - const sum = list.reduce((acc, val) => acc + val, 0); + const sum = list.reduce((acc, value) => acc + value, 0); expect(sum).toBe(6); }); @@ -387,7 +387,7 @@ describe('DoublyLinkedList Operation Test', () => { expect(insertSuccess).toBe(true); const getNode = objectList.getNode(newObj); // Use newObj instead of obj2 - expect(getNode?.val).toEqual(newObj); + expect(getNode?.value).toEqual(newObj); const deleted = objectList.delete(newObj); // Use newObj instead of obj2 expect(deleted).toBe(true); diff --git a/test/unit/data-structures/linked-list/linked-list.test.ts b/test/unit/data-structures/linked-list/linked-list.test.ts index 91b27fc..995f38a 100644 --- a/test/unit/data-structures/linked-list/linked-list.test.ts +++ b/test/unit/data-structures/linked-list/linked-list.test.ts @@ -26,7 +26,7 @@ describe('LinkedList Performance Test', () => { if (i === midIndex) { midSinglyNode = singlyList.getNode(i); } else if (i > midIndex && midSinglyNode) { - singlyList.insertBefore(midSinglyNode.val, i); + singlyList.insertBefore(midSinglyNode.value, i); } } diff --git a/test/unit/data-structures/linked-list/singly-linked-list.test.ts b/test/unit/data-structures/linked-list/singly-linked-list.test.ts index a3175d1..44d7138 100644 --- a/test/unit/data-structures/linked-list/singly-linked-list.test.ts +++ b/test/unit/data-structures/linked-list/singly-linked-list.test.ts @@ -4,9 +4,9 @@ import {bigO, magnitude} from '../../../utils'; describe('SinglyLinkedListNode', () => { it('should SinglyLinkedList', () => { const node1 = new SinglyLinkedListNode(2); - expect(node1.val).toBe(2); - node1.val = 1; - expect(node1.val).toBe(1); + expect(node1.value).toBe(2); + node1.value = 1; + expect(node1.value).toBe(1); }); }); @@ -75,7 +75,7 @@ describe('SinglyLinkedList Operation Test', () => { list.push(3); const element = list.getAt(1); expect(element).toBe(2); - expect(list.getNodeAt(2)?.val).toBe(3); + expect(list.getNodeAt(2)?.value).toBe(3); }); it('should return undefined for an out-of-bounds index', () => { @@ -382,7 +382,7 @@ describe('SinglyLinkedList Operation Test', () => { expect(insertSuccess).toBe(true); const getNode = objectList.getNode(newObj); // Use newObj instead of obj2 - expect(getNode?.val).toEqual(newObj); + expect(getNode?.value).toEqual(newObj); const deleted = objectList.delete(newObj); // Use newObj instead of obj2 expect(deleted).toBe(true); @@ -431,8 +431,8 @@ describe('SinglyLinkedList', () => { it('should push elements to the end of the list', () => { list.push(1); list.push(2); - expect(list.head!.val).toBe(1); - expect(list.tail!.val).toBe(2); + expect(list.head!.value).toBe(1); + expect(list.tail!.value).toBe(2); expect(list.length).toBe(2); }); @@ -441,8 +441,8 @@ describe('SinglyLinkedList', () => { list.push(2); const popped = list.pop(); expect(popped).toBe(2); - expect(list.head!.val).toBe(1); - expect(list.tail!.val).toBe(1); + expect(list.head!.value).toBe(1); + expect(list.tail!.value).toBe(1); expect(list.length).toBe(1); }); @@ -451,8 +451,8 @@ describe('SinglyLinkedList', () => { list.push(2); list.push(3); list.reverse(); - expect(list.head!.val).toBe(3); - expect(list.tail!.val).toBe(1); + expect(list.head!.value).toBe(3); + expect(list.tail!.value).toBe(1); // Add more assertions for reversed order. }); @@ -470,14 +470,14 @@ describe('SinglyLinkedList', () => { list.push(1); list.push(2); list.push(3); - expect(list.filter(val => val !== 2).toArray()).toEqual([1, 3]); + expect(list.filter(value => value !== 2).toArray()).toEqual([1, 3]); }); it('should forEach the list', () => { list.push(1); list.push(2); list.push(3); - list.forEach(val => val++); + list.forEach(value => value++); expect(list.toArray()).toEqual([1, 2, 3]); }); @@ -485,11 +485,11 @@ describe('SinglyLinkedList', () => { list.addLast(1); list.push(2); list.push(3); - expect(list.map(val => val * 2).toArray()).toEqual([2, 4, 6]); + expect(list.map(value => value * 2).toArray()).toEqual([2, 4, 6]); }); it('should reduce the list', () => { const list1 = SinglyLinkedList.fromArray([1, 2, 3]); - expect(list1.reduce((acc, val) => acc + val, 0)).toEqual(6); + expect(list1.reduce((acc, value) => acc + value, 0)).toEqual(6); }); }); diff --git a/test/utils/big-o.ts b/test/utils/big-o.ts index 43d7eca..6443e19 100644 --- a/test/utils/big-o.ts +++ b/test/utils/big-o.ts @@ -59,19 +59,19 @@ function findPotentialN(input: any): number { function linearRegression(x: number[], y: number[]) { const n = x.length; - const sumX = x.reduce((acc, val) => acc + val, 0); - const sumY = y.reduce((acc, val) => acc + val, 0); + const sumX = x.reduce((acc, value) => acc + value, 0); + const sumY = y.reduce((acc, value) => acc + value, 0); - const sumXSquared = x.reduce((acc, val) => acc + val ** 2, 0); - const sumXY = x.reduce((acc, val, i) => acc + val * y[i], 0); + const sumXSquared = x.reduce((acc, value) => acc + value ** 2, 0); + const sumXY = x.reduce((acc, value, i) => acc + value * y[i], 0); const slope = (n * sumXY - sumX * sumY) / (n * sumXSquared - sumX ** 2); const intercept = (sumY - slope * sumX) / n; - const yHat = x.map(val => slope * val + intercept); + const yHat = x.map(value => slope * value + intercept); - const totalVariation = y.map((val, i) => (val - yHat[i]) ** 2).reduce((acc, val) => acc + val, 0); - const explainedVariation = y.map(val => (val - sumY / n) ** 2).reduce((acc, val) => acc + val, 0); + const totalVariation = y.map((value, i) => (value - yHat[i]) ** 2).reduce((acc, value) => acc + value, 0); + const explainedVariation = y.map(value => (value - sumY / n) ** 2).reduce((acc, value) => acc + value, 0); const rSquared = 1 - totalVariation / explainedVariation; From 1822084407f513550dd6e2d1fd7617b6d0b49bdb Mon Sep 17 00:00:00 2001 From: Revone Date: Tue, 31 Oct 2023 08:43:54 +0800 Subject: [PATCH 42/46] [pkg] v1.39.6 published --- CHANGELOG.md | 3 ++- package-lock.json | 50 +++++++++++++++++++++++------------------------ package.json | 10 +++++----- 3 files changed, 32 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7dadcdc..4b077a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,10 +8,11 @@ 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.39.5](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) +## [v1.39.6](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) ### Changes +- [graph test] edge cases enriched [`#30`](https://github.com/zrwusa/data-structure-typed/pull/30) - [graph] Modify the data structure design of the graph to change the g… [`#29`](https://github.com/zrwusa/data-structure-typed/pull/29) - Optimization [`#23`](https://github.com/zrwusa/data-structure-typed/pull/23) - Optimization [`#20`](https://github.com/zrwusa/data-structure-typed/pull/20) diff --git a/package-lock.json b/package-lock.json index 9d349dd..6a3b471 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "data-structure-typed", - "version": "1.39.5", + "version": "1.39.6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "data-structure-typed", - "version": "1.39.5", + "version": "1.39.6", "license": "MIT", "devDependencies": { "@types/benchmark": "^2.1.3", @@ -15,17 +15,17 @@ "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", "auto-changelog": "^2.4.0", - "avl-tree-typed": "^1.39.4", + "avl-tree-typed": "^1.39.5", "benchmark": "^2.1.4", - "binary-tree-typed": "^1.39.4", - "bst-typed": "^1.39.4", + "binary-tree-typed": "^1.39.5", + "bst-typed": "^1.39.5", "dependency-cruiser": "^14.1.0", "eslint": "^8.50.0", "eslint-config-prettier": "^9.0.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.28.1", - "heap-typed": "^1.39.4", + "heap-typed": "^1.39.5", "istanbul-badges-readme": "^1.8.5", "jest": "^29.7.0", "prettier": "^3.0.3", @@ -2728,12 +2728,12 @@ } }, "node_modules/avl-tree-typed": { - "version": "1.39.4", - "resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.39.4.tgz", - "integrity": "sha512-hgX97KNfwuIu9byrhFF22WBqA1OgMk97bSDB8mKdhZ/5E9OecAglnh8vjeLqxAt0DUFUpghXJ+AenXoVlBYWmw==", + "version": "1.39.5", + "resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.39.5.tgz", + "integrity": "sha512-4KpwQrTkbo22Q/dHESzUX+T0m/Ho18fvoxeeH48k1O7vuIWeUWfqAJ3DcWuANWD6urMaICNb5xM/E4DHdlS0Yg==", "dev": true, "dependencies": { - "data-structure-typed": "^1.39.4" + "data-structure-typed": "^1.39.5" } }, "node_modules/babel-jest": { @@ -2927,12 +2927,12 @@ } }, "node_modules/binary-tree-typed": { - "version": "1.39.4", - "resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.39.4.tgz", - "integrity": "sha512-HC3ue5u5Db4mW0EkE8rd6Bq5wQB5DSQHm4R6DhUnd95TRV/diiqD8MUheVNddEm3vg+vgCwTKCvwsO3joBakQw==", + "version": "1.39.5", + "resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.39.5.tgz", + "integrity": "sha512-4+2vmkEmBnzGLCyiGJwRy2k86IDoG1PxfVjXp31H469iPzts5MpQoBgCOttuy9fzXZRQBZautroTNwjXZK2sWA==", "dev": true, "dependencies": { - "data-structure-typed": "^1.39.4" + "data-structure-typed": "^1.39.5" } }, "node_modules/brace-expansion": { @@ -3011,12 +3011,12 @@ } }, "node_modules/bst-typed": { - "version": "1.39.4", - "resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.39.4.tgz", - "integrity": "sha512-efEtQyABOUehz7b+zpnL5QUg8IsK/vnoaB+ws+NN9LHAYlcJ4DvhvdAJT4J7YfnthNOhVgV6b+XmIOnaviWKHw==", + "version": "1.39.5", + "resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.39.5.tgz", + "integrity": "sha512-vMyRR1piavhx8rTf81nzU/RMBY5p5++4fX4EZI9CXhgFAFormuj9h/7BP0BDMzeaQMILIo9ruBdeChMp/D6xnQ==", "dev": true, "dependencies": { - "data-structure-typed": "^1.39.4" + "data-structure-typed": "^1.39.5" } }, "node_modules/buffer-from": { @@ -3413,9 +3413,9 @@ } }, "node_modules/data-structure-typed": { - "version": "1.39.4", - "resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.39.4.tgz", - "integrity": "sha512-i2GtZluNIvGrQ6147oe7v0g2RV9KPDBT8bMbRDM+7cIHrQ3zr3w70W6yZx5scSKCvtg18kJ5lyXXPbEiY7zHsg==", + "version": "1.39.5", + "resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.39.5.tgz", + "integrity": "sha512-PyrhlHFxmkfMSwRG/83uw9GWLFBTjz8TCfbhMiq7Am+F/adoOnWuYT+gFUHtyRV7+ts+iIDXYfgkyiqm6ijL4g==", "dev": true }, "node_modules/debug": { @@ -4771,12 +4771,12 @@ } }, "node_modules/heap-typed": { - "version": "1.39.4", - "resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.39.4.tgz", - "integrity": "sha512-5qF7vdcFV9ZgIXZ3YyDZOHDZV9Ik+3Mv6Us2gStyyYGmMpgbENgAUxZmh8MDKJAH/Hf1DWK7TTGi0AQWPWKFWg==", + "version": "1.39.5", + "resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.39.5.tgz", + "integrity": "sha512-nZZLUskWW4t2i3en95o1iNwQ0duN49TPMfsPPsnpo7SJp3D4MiLiNQhfz16grf8pl/tvMOYGKCKhFdb2eqBgmQ==", "dev": true, "dependencies": { - "data-structure-typed": "^1.39.4" + "data-structure-typed": "^1.39.5" } }, "node_modules/html-escaper": { diff --git a/package.json b/package.json index de2f4c4..c5e40dd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "data-structure-typed", - "version": "1.39.5", + "version": "1.39.6", "description": "Data Structures of Javascript & TypeScript. Binary Tree, BST, Graph, Heap, Priority Queue, Linked List, Queue, Deque, Stack, AVL Tree, Tree Multiset, Trie, Directed Graph, Undirected Graph, Singly Linked List, Doubly Linked List, Max Heap, Max Priority Queue, Min Heap, Min Priority Queue.", "main": "dist/cjs/index.js", "module": "dist/mjs/index.js", @@ -61,17 +61,17 @@ "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", "auto-changelog": "^2.4.0", - "avl-tree-typed": "^1.39.4", + "avl-tree-typed": "^1.39.5", "benchmark": "^2.1.4", - "binary-tree-typed": "^1.39.4", - "bst-typed": "^1.39.4", + "binary-tree-typed": "^1.39.5", + "bst-typed": "^1.39.5", "dependency-cruiser": "^14.1.0", "eslint": "^8.50.0", "eslint-config-prettier": "^9.0.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.28.1", - "heap-typed": "^1.39.4", + "heap-typed": "^1.39.5", "istanbul-badges-readme": "^1.8.5", "jest": "^29.7.0", "prettier": "^3.0.3", From 3009c14c243b66c75156ef8f64fda87b3e987514 Mon Sep 17 00:00:00 2001 From: Revone Date: Tue, 31 Oct 2023 09:03:06 +0800 Subject: [PATCH 43/46] [queue] Added some alias methods. --- src/data-structures/queue/queue.ts | 35 ++++++++++++++++--- test/unit/data-structures/queue/queue.test.ts | 16 ++++----- 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/src/data-structures/queue/queue.ts b/src/data-structures/queue/queue.ts index 6f10f59..bc3a78c 100644 --- a/src/data-structures/queue/queue.ts +++ b/src/data-structures/queue/queue.ts @@ -5,7 +5,7 @@ */ import {SinglyLinkedList} from '../linked-list'; -export class SkipQueue extends SinglyLinkedList { +export class LinkedListQueue extends SinglyLinkedList { /** * The enqueue function adds a value to the end of an array. * @param {E} value - The value parameter represents the value that you want to add to the queue. @@ -22,12 +22,20 @@ export class SkipQueue extends SinglyLinkedList { return this.shift(); } + /** + * The `getFirst` function returns the value of the head node in a linked list, or `undefined` if the list is empty. + * @returns The `getFirst()` method is returning the value of the `head` node if it exists, otherwise it returns `undefined`. + */ + getFirst(): E | undefined { + return this.head?.value; + } + /** * The `peek` function returns the value of the head node in a linked list, or `undefined` if the list is empty. * @returns The `peek()` method is returning the value of the `head` node if it exists, otherwise it returns `undefined`. */ peek(): E | undefined { - return this.head?.value; + return this.getFirst(); } } @@ -101,7 +109,7 @@ export class Queue { shift(): E | undefined { if (this.size === 0) return undefined; - const first = this.peek(); + const first = this.getFirst(); this.offset += 1; if (this.offset * 2 < this.nodes.length) return first; @@ -113,13 +121,23 @@ export class Queue { return first; } + /** + * The `getFirst` function returns the first element of the array `_nodes` if it exists, otherwise it returns `null`. + * @returns The `getFirst()` method returns the first element of the data structure, represented by the `_nodes` array at + * the `_offset` index. If the data structure is empty (size is 0), it returns `null`. + */ + getFirst(): E | undefined { + return this.size > 0 ? this.nodes[this.offset] : undefined; + } + + /** * The `peek` function returns the first element of the array `_nodes` if it exists, otherwise it returns `null`. * @returns The `peek()` method returns the first element of the data structure, represented by the `_nodes` array at * the `_offset` index. If the data structure is empty (size is 0), it returns `null`. */ peek(): E | undefined { - return this.size > 0 ? this.nodes[this.offset] : undefined; + return this.getFirst(); } /** @@ -131,6 +149,15 @@ export class Queue { return this.size > 0 ? this.nodes[this.nodes.length - 1] : undefined; } + /** + * The `peekLast` function returns the last element in an array-like data structure, or null 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 + * array is empty, it returns `null`. + */ + peekLast(): E | undefined { + return this.getLast(); + } + /** * The enqueue function adds a value to the end of a queue. * @param {E} value - The value parameter represents the value that you want to add to the queue. diff --git a/test/unit/data-structures/queue/queue.test.ts b/test/unit/data-structures/queue/queue.test.ts index eb062f6..9e2a263 100644 --- a/test/unit/data-structures/queue/queue.test.ts +++ b/test/unit/data-structures/queue/queue.test.ts @@ -1,4 +1,4 @@ -import {SkipQueue, Queue} from '../../../../src'; +import {LinkedListQueue, Queue} from '../../../../src'; import {bigO, magnitude} from '../../../utils'; import {isDebugTest} from '../../../config'; @@ -168,11 +168,11 @@ describe('Queue', () => { expect(values).toEqual([1, 2, 3]); }); }); -describe('SkipQueue', () => { - let queue: SkipQueue; +describe('LinkedListQueue', () => { + let queue: LinkedListQueue; beforeEach(() => { - queue = new SkipQueue(); + queue = new LinkedListQueue(); }); it('should enqueue elements to the end of the queue', () => { @@ -197,7 +197,7 @@ describe('SkipQueue', () => { expect(queue.peek()).toBe('A'); }); - // Add more test cases for other methods of SkipQueue. + // Add more test cases for other methods of LinkedListQueue. }); describe('Queue Performance Test', () => { @@ -228,16 +228,16 @@ describe('Queue Performance Test', () => { expect(performance.now() - startTime2).toBeLessThan(bigO.CUBED * 100); }); - it('should numeric SkipQueue be efficient', function () { + it('should numeric LinkedListQueue be efficient', function () { const startTime = performance.now(); - const queue = new SkipQueue(); + const queue = new LinkedListQueue(); for (let i = 0; i < dataSize; i++) { queue.enqueue(i); } for (let i = 0; i < dataSize; i++) { queue.dequeue(); } - console.log(`SkipQueue Performance Test: ${performance.now() - startTime} ms`); + console.log(`LinkedListQueue Performance Test: ${performance.now() - startTime} ms`); expect(performance.now() - startTime).toBeLessThan(bigO.LINEAR * 100); }); }); From 1ec5a19172bab67897a1fae602be5b96c583d14f Mon Sep 17 00:00:00 2001 From: Revone Date: Tue, 31 Oct 2023 10:34:41 +0800 Subject: [PATCH 44/46] [core] Besides Binary Trees and Graphs, access control optimizations have been applied to member variables. --- src/data-structures/hash/coordinate-map.ts | 4 - src/data-structures/hash/coordinate-set.ts | 4 - src/data-structures/hash/hash-map.ts | 48 +++------ src/data-structures/hash/hash-table.ts | 24 ++--- src/data-structures/heap/heap.ts | 84 ++++++++++------ .../linked-list/doubly-linked-list.ts | 84 +++++----------- .../linked-list/singly-linked-list.ts | 71 +++++--------- .../linked-list/skip-linked-list.ts | 98 ++++++++++++++----- src/data-structures/queue/deque.ts | 85 +++++++--------- src/data-structures/queue/queue.ts | 25 ++--- src/data-structures/stack/stack.ts | 17 ++-- src/data-structures/tree/tree.ts | 36 ++----- src/data-structures/trie/trie.ts | 47 +++------ .../graph/abstract-graph.test.ts | 7 +- .../hash/coordinate-map.test.ts | 2 +- .../hash/coordinate-set.test.ts | 2 +- .../data-structures/hash/hash-map.test.ts | 1 - .../data-structures/hash/hash-table.test.ts | 6 +- .../linked-list/skip-list.test.ts | 31 ++++++ 19 files changed, 303 insertions(+), 373 deletions(-) diff --git a/src/data-structures/hash/coordinate-map.ts b/src/data-structures/hash/coordinate-map.ts index 64bdff7..02ffd45 100644 --- a/src/data-structures/hash/coordinate-map.ts +++ b/src/data-structures/hash/coordinate-map.ts @@ -60,8 +60,4 @@ export class CoordinateMap extends Map { override delete(key: number[]) { return super.delete(key.join(this._joint)); } - - protected _setJoint(v: string) { - this._joint = v; - } } diff --git a/src/data-structures/hash/coordinate-set.ts b/src/data-structures/hash/coordinate-set.ts index 0584d91..e7437eb 100644 --- a/src/data-structures/hash/coordinate-set.ts +++ b/src/data-structures/hash/coordinate-set.ts @@ -49,8 +49,4 @@ export class CoordinateSet extends Set { override delete(value: number[]) { return super.delete(value.join(this._joint)); } - - protected _setJoint(v: string) { - this._joint = v; - } } diff --git a/src/data-structures/hash/hash-map.ts b/src/data-structures/hash/hash-map.ts index f3a5213..9595be5 100644 --- a/src/data-structures/hash/hash-map.ts +++ b/src/data-structures/hash/hash-map.ts @@ -38,66 +38,42 @@ export class HashMap { }); } - private _initialCapacity: number; + protected _initialCapacity: number; get initialCapacity(): number { return this._initialCapacity; } - set initialCapacity(value: number) { - this._initialCapacity = value; - } - - private _loadFactor: number; + protected _loadFactor: number; get loadFactor(): number { return this._loadFactor; } - set loadFactor(value: number) { - this._loadFactor = value; - } - - private _capacityMultiplier: number; + protected _capacityMultiplier: number; get capacityMultiplier(): number { return this._capacityMultiplier; } - set capacityMultiplier(value: number) { - this._capacityMultiplier = value; - } - - private _size: number; + protected _size: number; get size(): number { return this._size; } - set size(value: number) { - this._size = value; - } - - private _table: Array>; + protected _table: Array>; get table(): Array> { return this._table; } - set table(value: Array>) { - this._table = value; - } - - private _hashFn: HashFunction; + protected _hashFn: HashFunction; get hashFn(): HashFunction { return this._hashFn; } - set hashFn(value: HashFunction) { - this._hashFn = value; - } - set(key: K, value: V): void { const loadFactor = this.size / this.table.length; if (loadFactor >= this.loadFactor) { @@ -118,7 +94,7 @@ export class HashMap { } this.table[index].push([key, value]); - this.size++; + this._size++; } get(key: K): V | undefined { @@ -145,7 +121,7 @@ export class HashMap { for (let i = 0; i < this.table[index].length; i++) { if (this.table[index][i][0] === key) { this.table[index].splice(i, 1); - this.size--; + this._size--; // Check if the table needs to be resized down const loadFactor = this.size / this.table.length; @@ -172,15 +148,15 @@ export class HashMap { } clear(): void { - this.size = 0; - this.table = new Array(this.initialCapacity); + this._size = 0; + this._table = new Array(this.initialCapacity); } isEmpty(): boolean { return this.size === 0; } - private _hash(key: K): number { + protected _hash(key: K): number { return this._hashFn(key); } @@ -190,7 +166,7 @@ export class HashMap { * @param {number} newCapacity - The newCapacity parameter is the desired capacity for the resized table. It represents * the number of buckets that the new table should have. */ - private resizeTable(newCapacity: number): void { + protected resizeTable(newCapacity: number): void { const newTable = new Array(newCapacity); for (const bucket of this._table) { // Note that this is this._table diff --git a/src/data-structures/hash/hash-table.ts b/src/data-structures/hash/hash-table.ts index 26b4ddd..783819f 100644 --- a/src/data-structures/hash/hash-table.ts +++ b/src/data-structures/hash/hash-table.ts @@ -21,8 +21,8 @@ export class HashTableNode { import {HashFunction} from '../../types'; export class HashTable { - private static readonly DEFAULT_CAPACITY = 16; - private static readonly LOAD_FACTOR = 0.75; + 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; @@ -31,42 +31,30 @@ export class HashTable { this._buckets = new Array | null>(this._capacity).fill(null); } - private _capacity: number; + protected _capacity: number; get capacity(): number { return this._capacity; } - set capacity(value: number) { - this._capacity = value; - } - - private _size: number; + protected _size: number; get size(): number { return this._size; } - private _buckets: Array | null>; + protected _buckets: Array | null>; get buckets(): Array | null> { return this._buckets; } - set buckets(value: Array | null>) { - this._buckets = value; - } - - private _hashFn: HashFunction; + protected _hashFn: HashFunction; get hashFn(): HashFunction { return this._hashFn; } - set hashFn(value: HashFunction) { - this._hashFn = value; - } - /** * 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 diff --git a/src/data-structures/heap/heap.ts b/src/data-structures/heap/heap.ts index 4f3fbe6..60d4533 100644 --- a/src/data-structures/heap/heap.ts +++ b/src/data-structures/heap/heap.ts @@ -8,17 +8,26 @@ import type {Comparator, DFSOrderPattern} from '../../types'; export class Heap { - protected nodes: E[] = []; - protected readonly comparator: Comparator; - constructor(options: {comparator: Comparator; nodes?: E[]}) { - this.comparator = options.comparator; + this._comparator = options.comparator; if (options.nodes && options.nodes.length > 0) { - this.nodes = options.nodes; + this._nodes = options.nodes; this.fix(); } } + protected _nodes: E[] = []; + + get nodes(): E[] { + return this._nodes; + } + + protected _comparator: Comparator; + + get comparator(): Comparator { + return this._comparator; + } + /** * Get the size (number of elements) of the heap. */ @@ -110,7 +119,7 @@ export class Heap { * Reset the nodes of the heap. Make the nodes empty. */ clear() { - this.nodes = []; + this._nodes = []; } /** @@ -118,7 +127,7 @@ export class Heap { * @param nodes */ refill(nodes: E[]) { - this.nodes = nodes; + this._nodes = nodes; this.fix(); } @@ -181,7 +190,7 @@ export class Heap { */ clone(): Heap { const clonedHeap = new Heap({comparator: this.comparator}); - clonedHeap.nodes = [...this.nodes]; + clonedHeap._nodes = [...this.nodes]; return clonedHeap; } @@ -268,28 +277,47 @@ export class FibonacciHeapNode { } export class FibonacciHeap { - root?: FibonacciHeapNode; - size = 0; - protected min?: FibonacciHeapNode; - protected readonly comparator: Comparator; - constructor(comparator?: Comparator) { this.clear(); - this.comparator = comparator || this.defaultComparator; + this._comparator = comparator || this.defaultComparator; if (typeof this.comparator !== 'function') { throw new Error('FibonacciHeap constructor: given comparator should be a function.'); } } + protected _root?: FibonacciHeapNode; + + get root(): FibonacciHeapNode | undefined { + return this._root; + } + + protected _size = 0; + + get size(): number { + return this._size; + } + + protected _min?: FibonacciHeapNode; + + get min(): FibonacciHeapNode | undefined { + return this._min; + } + + protected _comparator: Comparator; + + get comparator(): Comparator { + return this._comparator; + } + /** * Get the size (number of elements) of the heap. * @returns {number} The size of the heap. Returns 0 if the heap is empty. Returns -1 if the heap is invalid. */ clear(): void { - this.root = undefined; - this.min = undefined; - this.size = 0; + this._root = undefined; + this._min = undefined; + this._size = 0; } /** @@ -315,10 +343,10 @@ export class FibonacciHeap { this.mergeWithRoot(node); if (!this.min || this.comparator(node.element, this.min.element) <= 0) { - this.min = node; + this._min = node; } - this.size++; + this._size++; return this; } @@ -405,14 +433,14 @@ export class FibonacciHeap { this.removeFromRoot(z); if (z === z.right) { - this.min = undefined; - this.root = undefined; + this._min = undefined; + this._root = undefined; } else { - this.min = z.right; + this._min = z.right; this.consolidate(); } - this.size--; + this._size--; return z.element; } @@ -444,11 +472,11 @@ export class FibonacciHeap { // Update the minimum node if (!this.min || (heapToMerge.min && this.comparator(heapToMerge.min.element, this.min.element) < 0)) { - this.min = heapToMerge.min; + this._min = heapToMerge.min; } // Update the size - this.size += heapToMerge.size; + this._size += heapToMerge.size; // Clear the heap that was merged heapToMerge.clear(); @@ -481,7 +509,7 @@ export class FibonacciHeap { */ protected mergeWithRoot(node: FibonacciHeapNode): void { if (!this.root) { - this.root = node; + this._root = node; } else { node.right = this.root.right; node.left = this.root; @@ -497,7 +525,7 @@ export class FibonacciHeap { * @protected */ protected removeFromRoot(node: FibonacciHeapNode): void { - if (this.root === node) this.root = node.right; + if (this.root === node) this._root = node.right; if (node.left) node.left.right = node.right; if (node.right) node.right.left = node.left; } @@ -554,7 +582,7 @@ export class FibonacciHeap { for (let i = 0; i < this.size; i++) { if (A[i] && this.comparator(A[i]!.element, this.min!.element) <= 0) { - this.min = A[i]!; + this._min = A[i]!; } } } diff --git a/src/data-structures/linked-list/doubly-linked-list.ts b/src/data-structures/linked-list/doubly-linked-list.ts index 6c833bf..119ae71 100644 --- a/src/data-structures/linked-list/doubly-linked-list.ts +++ b/src/data-structures/linked-list/doubly-linked-list.ts @@ -6,45 +6,19 @@ * @license MIT License */ export class DoublyLinkedListNode { + value: E; + next: DoublyLinkedListNode | null; + prev: DoublyLinkedListNode | null; + /** * The constructor function initializes the value, next, and previous properties of an object. * @param {E} value - The "value" parameter is the value that will be stored in the node. It can be of any data type, as it * is defined as a generic type "E". */ constructor(value: E) { - this._value = value; - this._next = null; - this._prev = null; - } - - private _value: E; - - get value(): E { - return this._value; - } - - set value(value: E) { - this._value = value; - } - - private _next: DoublyLinkedListNode | null; - - get next(): DoublyLinkedListNode | null { - return this._next; - } - - set next(value: DoublyLinkedListNode | null) { - this._next = value; - } - - private _prev: DoublyLinkedListNode | null; - - get prev(): DoublyLinkedListNode | null { - return this._prev; - } - - set prev(value: DoublyLinkedListNode | null) { - this._prev = value; + this.value = value; + this.next = null; + this.prev = null; } } @@ -58,27 +32,19 @@ export class DoublyLinkedList { this._length = 0; } - private _head: DoublyLinkedListNode | null; + protected _head: DoublyLinkedListNode | null; get head(): DoublyLinkedListNode | null { return this._head; } - set head(value: DoublyLinkedListNode | null) { - this._head = value; - } - - private _tail: DoublyLinkedListNode | null; + protected _tail: DoublyLinkedListNode | null; get tail(): DoublyLinkedListNode | null { return this._tail; } - set tail(value: DoublyLinkedListNode | null) { - this._tail = value; - } - - private _length: number; + protected _length: number; get length(): number { return this._length; @@ -109,12 +75,12 @@ export class DoublyLinkedList { push(value: E): void { const newNode = new DoublyLinkedListNode(value); if (!this.head) { - this.head = newNode; - this.tail = newNode; + this._head = newNode; + this._tail = newNode; } else { newNode.prev = this.tail; this.tail!.next = newNode; - this.tail = newNode; + this._tail = newNode; } this._length++; } @@ -136,10 +102,10 @@ export class DoublyLinkedList { if (!this.tail) return undefined; const removedNode = this.tail; if (this.head === this.tail) { - this.head = null; - this.tail = null; + this._head = null; + this._tail = null; } else { - this.tail = removedNode.prev; + this._tail = removedNode.prev; this.tail!.next = null; } this._length--; @@ -164,10 +130,10 @@ export class DoublyLinkedList { if (!this.head) return undefined; const removedNode = this.head; if (this.head === this.tail) { - this.head = null; - this.tail = null; + this._head = null; + this._tail = null; } else { - this.head = removedNode.next; + this._head = removedNode.next; this.head!.prev = null; } this._length--; @@ -191,12 +157,12 @@ export class DoublyLinkedList { unshift(value: E): void { const newNode = new DoublyLinkedListNode(value); if (!this.head) { - this.head = newNode; - this.tail = newNode; + this._head = newNode; + this._tail = newNode; } else { newNode.next = this.head; this.head!.prev = newNode; - this.head = newNode; + this._head = newNode; } this._length++; } @@ -338,7 +304,7 @@ export class DoublyLinkedList { newNode.next = existingNode; existingNode.prev = newNode; if (existingNode === this.head) { - this.head = newNode; + this._head = newNode; } this._length++; return true; @@ -508,7 +474,7 @@ export class DoublyLinkedList { */ reverse(): void { let current = this.head; - [this.head, this.tail] = [this.tail, this.head]; + [this._head, this._tail] = [this.tail, this.head]; while (current) { const next = current.next; [current.prev, current.next] = [current.next, current.prev]; @@ -616,7 +582,7 @@ export class DoublyLinkedList { newNode.prev = existingNode; existingNode.next = newNode; if (existingNode === this.tail) { - this.tail = newNode; + this._tail = newNode; } this._length++; return true; diff --git a/src/data-structures/linked-list/singly-linked-list.ts b/src/data-structures/linked-list/singly-linked-list.ts index d9a2818..7c39cf6 100644 --- a/src/data-structures/linked-list/singly-linked-list.ts +++ b/src/data-structures/linked-list/singly-linked-list.ts @@ -6,34 +6,17 @@ * @license MIT License */ export class SinglyLinkedListNode { + value: E; + next: SinglyLinkedListNode | null; + /** * The constructor function initializes an instance of a class with a given value and sets the next property to null. * @param {E} value - The "value" parameter is of type E, which means it can be any data type. It represents the value that * will be stored in the node of a linked list. */ constructor(value: E) { - this._value = value; - this._next = null; - } - - private _value: E; - - get value(): E { - return this._value; - } - - set value(value: E) { - this._value = value; - } - - private _next: SinglyLinkedListNode | null; - - get next(): SinglyLinkedListNode | null { - return this._next; - } - - set next(value: SinglyLinkedListNode | null) { - this._next = value; + this.value = value; + this.next = null; } } @@ -47,27 +30,19 @@ export class SinglyLinkedList { this._length = 0; } - private _head: SinglyLinkedListNode | null; + protected _head: SinglyLinkedListNode | null; get head(): SinglyLinkedListNode | null { return this._head; } - set head(value: SinglyLinkedListNode | null) { - this._head = value; - } - - private _tail: SinglyLinkedListNode | null; + protected _tail: SinglyLinkedListNode | null; get tail(): SinglyLinkedListNode | null { return this._tail; } - set tail(value: SinglyLinkedListNode | null) { - this._tail = value; - } - - private _length: number; + protected _length: number; get length(): number { return this._length; @@ -95,11 +70,11 @@ export class SinglyLinkedList { push(value: E): void { const newNode = new SinglyLinkedListNode(value); if (!this.head) { - this.head = newNode; - this.tail = newNode; + this._head = newNode; + this._tail = newNode; } else { this.tail!.next = newNode; - this.tail = newNode; + this._tail = newNode; } this._length++; } @@ -123,8 +98,8 @@ export class SinglyLinkedList { if (!this.head) return undefined; if (this.head === this.tail) { const value = this.head.value; - this.head = null; - this.tail = null; + this._head = null; + this._tail = null; this._length--; return value; } @@ -135,7 +110,7 @@ export class SinglyLinkedList { } const value = this.tail!.value; current.next = null; - this.tail = current; + this._tail = current; this._length--; return value; } @@ -157,7 +132,7 @@ export class SinglyLinkedList { shift(): E | undefined { if (!this.head) return undefined; const removedNode = this.head; - this.head = this.head.next; + this._head = this.head.next; this._length--; return removedNode.value; } @@ -178,11 +153,11 @@ export class SinglyLinkedList { unshift(value: E): void { const newNode = new SinglyLinkedListNode(value); if (!this.head) { - this.head = newNode; - this.tail = newNode; + this._head = newNode; + this._tail = newNode; } else { newNode.next = this.head; - this.head = newNode; + this._head = newNode; } this._length++; } @@ -267,14 +242,14 @@ export class SinglyLinkedList { while (current) { if (current.value === value) { if (prev === null) { - this.head = current.next; + this._head = current.next; if (current === this.tail) { - this.tail = null; + this._tail = null; } } else { prev.next = current.next; if (current === this.tail) { - this.tail = prev; + this._tail = prev; } } this._length--; @@ -365,7 +340,7 @@ export class SinglyLinkedList { current = next; } - [this.head, this.tail] = [this.tail!, this.head!]; + [this._head, this._tail] = [this.tail!, this.head!]; } /** @@ -486,7 +461,7 @@ export class SinglyLinkedList { newNode.next = existingNode.next; existingNode.next = newNode; if (existingNode === this.tail) { - this.tail = newNode; + this._tail = newNode; } this._length++; return true; diff --git a/src/data-structures/linked-list/skip-linked-list.ts b/src/data-structures/linked-list/skip-linked-list.ts index 59842ae..0514863 100644 --- a/src/data-structures/linked-list/skip-linked-list.ts +++ b/src/data-structures/linked-list/skip-linked-list.ts @@ -33,46 +33,30 @@ export class SkipList { this._probability = probability; } - private _head: SkipListNode; + protected _head: SkipListNode; get head(): SkipListNode { return this._head; } - set head(value: SkipListNode) { - this._head = value; - } - - private _level: number; + protected _level: number; get level(): number { return this._level; } - set level(value: number) { - this._level = value; - } - - private _maxLevel: number; + protected _maxLevel: number; get maxLevel(): number { return this._maxLevel; } - set maxLevel(value: number) { - this._maxLevel = value; - } - - private _probability: number; + protected _probability: number; get probability(): number { return this._probability; } - set probability(value: number) { - this._probability = value; - } - /** * The add function adds a new node with a given key and value to a Skip List data structure. * @param {K} key - The key parameter represents the key of the node that needs to be added to the skip list. @@ -80,7 +64,7 @@ export class SkipList { * List. */ add(key: K, value: V): void { - const newNode = new SkipListNode(key, value, this.randomLevel()); + const newNode = new SkipListNode(key, value, this._randomLevel()); const update: SkipListNode[] = new Array(this.maxLevel).fill(this.head); let current = this.head; @@ -97,7 +81,7 @@ export class SkipList { } if (newNode.forward[0] !== null) { - this.level = Math.max(this.level, newNode.forward.length); + this._level = Math.max(this.level, newNode.forward.length); } } @@ -124,6 +108,10 @@ export class SkipList { return undefined; } + has(key: K): boolean { + return this.get(key) !== undefined; + } + /** * The `delete` function removes a node with a specific key from a Skip List data structure. * @param {K} key - The key parameter represents the key of the node that needs to be removed from the skip list. @@ -151,7 +139,7 @@ export class SkipList { update[i].forward[i] = current.forward[i]; } while (this.level > 0 && this.head.forward[this.level - 1] === null) { - this.level--; + this._level--; } return true; } @@ -160,10 +148,70 @@ export class SkipList { } /** - * The function "randomLevel" generates a random level based on a given probability and maximum level. + * Get the value of the first element (the smallest element) in the Skip List. + * @returns The value of the first element, or undefined if the Skip List is empty. + */ + getFirst(): V | undefined { + const firstNode = this.head.forward[0]; + return firstNode ? firstNode.value : undefined; + } + + /** + * Get the value of the last element (the largest element) in the Skip List. + * @returns The value of the last element, or undefined if the Skip List is empty. + */ + getLast(): V | undefined { + let current = this.head; + for (let i = this.level - 1; i >= 0; i--) { + while (current.forward[i]) { + current = current.forward[i]; + } + } + return current.value; + } + + /** + * Get the value of the first element in the Skip List that is greater than the given key. + * @param key - the given key. + * @returns The value of the first element greater than the given key, or undefined if there is no such element. + */ + higher(key: K): V | undefined { + let current = this.head; + for (let i = this.level - 1; i >= 0; i--) { + while (current.forward[i] && current.forward[i].key <= key) { + current = current.forward[i]; + } + } + const nextNode = current.forward[0]; + return nextNode ? nextNode.value : undefined; + } + + /** + * Get the value of the last element in the Skip List that is less than the given key. + * @param key - the given key. + * @returns The value of the last element less than the given key, or undefined if there is no such element. + */ + lower(key: K): V | undefined { + let current = this.head; + let lastLess = null; + + for (let i = this.level - 1; i >= 0; i--) { + while (current.forward[i] && current.forward[i].key < key) { + current = current.forward[i]; + } + if (current.key < key) { + lastLess = current; + } + } + + return lastLess ? lastLess.value : undefined; + } + + /** + * The function "_randomLevel" generates a random level based on a given probability and maximum level. * @returns the level, which is a number. */ - private randomLevel(): number { + protected _randomLevel(): number { let level = 1; while (Math.random() < this.probability && level < this.maxLevel) { level++; diff --git a/src/data-structures/queue/deque.ts b/src/data-structures/queue/deque.ts index 8d6490a..3dc8c58 100644 --- a/src/data-structures/queue/deque.ts +++ b/src/data-structures/queue/deque.ts @@ -19,43 +19,31 @@ export class ObjectDeque { if (capacity !== undefined) this._capacity = capacity; } - private _nodes: {[key: number]: E} = {}; + protected _nodes: {[key: number]: E} = {}; get nodes(): {[p: number]: E} { return this._nodes; } - private _capacity = Number.MAX_SAFE_INTEGER; + protected _capacity = Number.MAX_SAFE_INTEGER; get capacity(): number { return this._capacity; } - set capacity(value: number) { - this._capacity = value; - } - - private _first = -1; + protected _first = -1; get first(): number { return this._first; } - set first(value: number) { - this._first = value; - } - - private _last = -1; + protected _last = -1; get last(): number { return this._last; } - set last(value: number) { - this._last = value; - } - - private _size = 0; + protected _size = 0; get size(): number { return this._size; @@ -67,14 +55,14 @@ export class ObjectDeque { * structure. */ addFirst(value: E) { - if (this._size === 0) { - const mid = Math.floor(this._capacity / 2); + if (this.size === 0) { + const mid = Math.floor(this.capacity / 2); this._first = mid; this._last = mid; } else { this._first--; } - this._nodes[this._first] = value; + this.nodes[this.first] = value; this._size++; } @@ -83,14 +71,14 @@ export class ObjectDeque { * @param {E} value - The `value` parameter represents the value that you want to add to the end of the data structure. */ addLast(value: E) { - if (this._size === 0) { - const mid = Math.floor(this._capacity / 2); + if (this.size === 0) { + const mid = Math.floor(this.capacity / 2); this._first = mid; this._last = mid; } else { this._last++; } - this._nodes[this._last] = value; + this.nodes[this.last] = value; this._size++; } @@ -99,9 +87,9 @@ export class ObjectDeque { * @returns The value of the first element in the data structure. */ popFirst() { - if (!this._size) return; + if (!this.size) return; const value = this.getFirst(); - delete this._nodes[this._first]; + delete this.nodes[this.first]; this._first++; this._size--; return value; @@ -112,7 +100,7 @@ export class ObjectDeque { * @returns The element at the first position of the `_nodes` array. */ getFirst() { - if (this._size) return this._nodes[this._first]; + if (this.size) return this.nodes[this.first]; } /** @@ -120,9 +108,9 @@ export class ObjectDeque { * @returns The value that was removed from the data structure. */ popLast() { - if (!this._size) return; + if (!this.size) return; const value = this.getLast(); - delete this._nodes[this._last]; + delete this.nodes[this.last]; this._last--; this._size--; @@ -134,7 +122,7 @@ export class ObjectDeque { * @returns The last element in the array "_nodes" is being returned. */ getLast() { - if (this._size) return this._nodes[this._last]; + if (this.size) return this.nodes[this.last]; } /** @@ -145,7 +133,7 @@ export class ObjectDeque { * index, `null` is returned. */ get(index: number) { - return this._nodes[this._first + index] || null; + return this.nodes[this.first + index] || null; } /** @@ -153,25 +141,20 @@ export class ObjectDeque { * @returns The method is returning a boolean value indicating whether the size of the object is less than or equal to 0. */ isEmpty() { - return this._size <= 0; - } - - protected _seNodes(value: {[p: number]: E}) { - this._nodes = value; - } - - protected _setSize(value: number) { - this._size = value; + return this.size <= 0; } } // O(1) time complexity of obtaining the value // O(n) time complexity of adding at the beginning and the end export class ArrayDeque { + get nodes(): E[] { + return this._nodes; + } protected _nodes: E[] = []; get size() { - return this._nodes.length; + return this.nodes.length; } /** @@ -184,7 +167,7 @@ export class ArrayDeque { * @returns The return value is the new length of the array after the value has been added. */ addLast(value: E) { - return this._nodes.push(value); + return this.nodes.push(value); } /** @@ -192,7 +175,7 @@ export class ArrayDeque { * @returns The method `popLast()` returns the last element of the `_nodes` array, or `null` if the array is empty. */ popLast(): E | null { - return this._nodes.pop() ?? null; + return this.nodes.pop() ?? null; } /** @@ -201,7 +184,7 @@ export class ArrayDeque { * empty. */ popFirst(): E | null { - return this._nodes.shift() ?? null; + return this.nodes.shift() ?? null; } /** @@ -215,7 +198,7 @@ export class ArrayDeque { * `value` at the beginning. */ addFirst(value: E) { - return this._nodes.unshift(value); + return this.nodes.unshift(value); } /** @@ -224,7 +207,7 @@ export class ArrayDeque { * empty, it will return `null`. */ getFirst(): E | null { - return this._nodes[0] ?? null; + return this.nodes[0] ?? null; } /** @@ -232,7 +215,7 @@ export class ArrayDeque { * @returns The method `getLast()` returns the last element of the `_nodes` array, or `null` if the array is empty. */ getLast(): E | null { - return this._nodes[this._nodes.length - 1] ?? null; + return this.nodes[this.nodes.length - 1] ?? null; } /** @@ -247,7 +230,7 @@ export class ArrayDeque { * will be returned. If the element does not exist (i.e., the index is out of bounds), `null` will be returned. */ get(index: number): E | null { - return this._nodes[index] ?? null; + return this.nodes[index] ?? null; } /** @@ -259,7 +242,7 @@ export class ArrayDeque { * @returns The value that is being set at the specified index in the `_nodes` array. */ set(index: number, value: E) { - return (this._nodes[index] = value); + return (this.nodes[index] = value); } /** @@ -273,7 +256,7 @@ export class ArrayDeque { * are being removed, an empty array will be returned. */ insert(index: number, value: E) { - return this._nodes.splice(index, 0, value); + return this.nodes.splice(index, 0, value); } /** @@ -283,7 +266,7 @@ export class ArrayDeque { * @returns The method is returning an array containing the removed element. */ delete(index: number) { - return this._nodes.splice(index, 1); + return this.nodes.splice(index, 1); } /** @@ -292,6 +275,6 @@ export class ArrayDeque { * is 0, indicating that the array is empty. Otherwise, it returns `false`. */ isEmpty() { - return this._nodes.length === 0; + return this.nodes.length === 0; } } diff --git a/src/data-structures/queue/queue.ts b/src/data-structures/queue/queue.ts index bc3a78c..9991f38 100644 --- a/src/data-structures/queue/queue.ts +++ b/src/data-structures/queue/queue.ts @@ -51,26 +51,18 @@ export class Queue { this._offset = 0; } - private _nodes: E[]; + protected _nodes: E[]; get nodes(): E[] { return this._nodes; } - set nodes(value: E[]) { - this._nodes = value; - } - - private _offset: number; + protected _offset: number; get offset(): number { return this._offset; } - set offset(value: number) { - this._offset = value; - } - /** * The size function returns the number of elements in an array. * @returns {number} The size of the array, which is the difference between the length of the array and the offset. @@ -110,14 +102,14 @@ export class Queue { if (this.size === 0) return undefined; const first = this.getFirst(); - this.offset += 1; + this._offset += 1; if (this.offset * 2 < this.nodes.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.offset = 0; + this._nodes = this.nodes.slice(this.offset); + this._offset = 0; return first; } @@ -130,7 +122,6 @@ export class Queue { return this.size > 0 ? this.nodes[this.offset] : undefined; } - /** * The `peek` function returns the first element of the array `_nodes` if it exists, otherwise it returns `null`. * @returns The `peek()` method returns the first element of the data structure, represented by the `_nodes` array at @@ -157,7 +148,7 @@ export class Queue { peekLast(): E | undefined { return this.getLast(); } - + /** * The enqueue function adds a value to the end of a queue. * @param {E} value - The value parameter represents the value that you want to add to the queue. @@ -198,8 +189,8 @@ export class Queue { * The clear function resets the nodes array and offset to their initial values. */ clear(): void { - this.nodes = []; - this.offset = 0; + this._nodes = []; + this._offset = 0; } /** diff --git a/src/data-structures/stack/stack.ts b/src/data-structures/stack/stack.ts index 8656648..0b2bfce 100644 --- a/src/data-structures/stack/stack.ts +++ b/src/data-structures/stack/stack.ts @@ -4,6 +4,9 @@ * @class */ export class Stack { + get elements(): E[] { + return this._elements; + } protected _elements: E[]; /** @@ -31,7 +34,7 @@ export class Stack { * @returns A boolean value indicating whether the `_elements` array is empty or not. */ isEmpty(): boolean { - return this._elements.length === 0; + return this.elements.length === 0; } /** @@ -39,7 +42,7 @@ export class Stack { * @returns The size of the elements array. */ size(): number { - return this._elements.length; + return this.elements.length; } /** @@ -49,7 +52,7 @@ export class Stack { peek(): E | null { if (this.isEmpty()) return null; - return this._elements[this._elements.length - 1]; + return this.elements[this.elements.length - 1]; } /** @@ -58,7 +61,7 @@ export class Stack { * @returns The `push` method is returning the updated `Stack` object. */ push(element: E): Stack { - this._elements.push(element); + this.elements.push(element); return this; } @@ -70,7 +73,7 @@ export class Stack { pop(): E | null { if (this.isEmpty()) return null; - return this._elements.pop() || null; + return this.elements.pop() || null; } /** @@ -78,7 +81,7 @@ export class Stack { * @returns An array of type E. */ toArray(): E[] { - return this._elements.slice(); + return this.elements.slice(); } /** @@ -93,6 +96,6 @@ export class Stack { * @returns The `clone()` method is returning a new `Stack` object with a copy of the `_elements` array. */ clone(): Stack { - return new Stack(this._elements.slice()); + return new Stack(this.elements.slice()); } } diff --git a/src/data-structures/tree/tree.ts b/src/data-structures/tree/tree.ts index b2167d6..729365a 100644 --- a/src/data-structures/tree/tree.ts +++ b/src/data-structures/tree/tree.ts @@ -1,39 +1,15 @@ export class TreeNode { constructor(key: string, value?: V, children?: TreeNode[]) { - this._key = key; - this._value = value || undefined; - this._children = children || []; + this.key = key; + this.value = value || undefined; + this.children = children || []; } - private _key: string; + key: string; - get key(): string { - return this._key; - } + value?: V | undefined; - set key(value: string) { - this._key = value; - } - - private _value?: V | undefined; - - get value(): V | undefined { - return this._value; - } - - set value(value: V | undefined) { - this._value = value; - } - - private _children?: TreeNode[] | undefined; - - get children(): TreeNode[] | undefined { - return this._children; - } - - set children(value: TreeNode[] | undefined) { - this._children = value; - } + children?: TreeNode[] | undefined; addChildren(children: TreeNode | TreeNode[]) { if (!this.children) { diff --git a/src/data-structures/trie/trie.ts b/src/data-structures/trie/trie.ts index 780b562..08bd374 100644 --- a/src/data-structures/trie/trie.ts +++ b/src/data-structures/trie/trie.ts @@ -12,47 +12,26 @@ */ export class TrieNode { constructor(key: string) { - this._key = key; - this._isEnd = false; - this._children = new Map(); + this.key = key; + this.isEnd = false; + this.children = new Map(); } - private _key; + key: string; - get key(): string { - return this._key; - } + children: Map; - set key(v: string) { - this._key = v; - } - - protected _children: Map; - - get children(): Map { - return this._children; - } - - set children(v: Map) { - this._children = v; - } - - protected _isEnd: boolean; - - get isEnd(): boolean { - return this._isEnd; - } - - set isEnd(v: boolean) { - this._isEnd = v; - } + isEnd: boolean; } /** * Trie represents a Trie data structure. It provides basic Trie operations and additional methods. */ export class Trie { - private readonly _caseSensitive: boolean; + get caseSensitive(): boolean { + return this._caseSensitive; + } + protected _caseSensitive: boolean; constructor(words?: string[], caseSensitive = true) { this._root = new TrieNode(''); @@ -70,10 +49,6 @@ export class Trie { return this._root; } - set root(v: TrieNode) { - this._root = v; - } - /** * Add a word to the Trie structure. * @param {string} word - The word to add. @@ -277,7 +252,7 @@ export class Trie { return words; } - private _caseProcess(str: string) { + protected _caseProcess(str: string) { if (!this._caseSensitive) { str = str.toLowerCase(); // Convert str to lowercase if case-insensitive } diff --git a/test/unit/data-structures/graph/abstract-graph.test.ts b/test/unit/data-structures/graph/abstract-graph.test.ts index b9dbefd..a9f6774 100644 --- a/test/unit/data-structures/graph/abstract-graph.test.ts +++ b/test/unit/data-structures/graph/abstract-graph.test.ts @@ -54,12 +54,12 @@ class MyGraph< } edgesOf(vertexOrKey: VO | VertexKey): EO[] { - const a = typeof vertexOrKey === "string" ? vertexOrKey : "a"; + const a = typeof vertexOrKey === 'string' ? vertexOrKey : 'a'; return [new MyEdge(a, 'b') as EO]; } getNeighbors(vertexOrKey: VO | VertexKey): VO[] { - const a = typeof vertexOrKey === "string" ? vertexOrKey : "a"; + const a = typeof vertexOrKey === 'string' ? vertexOrKey : 'a'; return [new MyVertex(a, 'b') as VO]; } @@ -75,8 +75,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/coordinate-map.test.ts b/test/unit/data-structures/hash/coordinate-map.test.ts index 672b2b7..2601d13 100644 --- a/test/unit/data-structures/hash/coordinate-map.test.ts +++ b/test/unit/data-structures/hash/coordinate-map.test.ts @@ -57,7 +57,7 @@ describe('CoordinateMap', () => { class MyCoordinateMap extends CoordinateMap { constructor(joint?: string) { super(joint); - this._setJoint((joint += '-')); + this._joint = joint += '-'; } } diff --git a/test/unit/data-structures/hash/coordinate-set.test.ts b/test/unit/data-structures/hash/coordinate-set.test.ts index a05ec04..eb0a3ca 100644 --- a/test/unit/data-structures/hash/coordinate-set.test.ts +++ b/test/unit/data-structures/hash/coordinate-set.test.ts @@ -44,7 +44,7 @@ describe('MyCoordinateSet', () => { class MyCoordinateSet extends CoordinateSet { constructor(joint?: string) { super(joint); - this._setJoint((joint += '-')); + this._joint = joint += '-'; } } diff --git a/test/unit/data-structures/hash/hash-map.test.ts b/test/unit/data-structures/hash/hash-map.test.ts index 6cb66e2..de3e2c1 100644 --- a/test/unit/data-structures/hash/hash-map.test.ts +++ b/test/unit/data-structures/hash/hash-map.test.ts @@ -28,7 +28,6 @@ describe('HashMap', () => { it('should handle key collisions', () => { // Force a collision by setting two different keys to the same bucket - hashMap.hashFn = () => 0; // Override hash function to return the same index hashMap.set('key1', 1); hashMap.set('key2', 2); diff --git a/test/unit/data-structures/hash/hash-table.test.ts b/test/unit/data-structures/hash/hash-table.test.ts index 284eb5f..b786774 100644 --- a/test/unit/data-structures/hash/hash-table.test.ts +++ b/test/unit/data-structures/hash/hash-table.test.ts @@ -15,9 +15,9 @@ describe('HashNode', () => { describe('HashTable', () => { it('should initialize with default capacity', () => { const hashTable = new HashTable(); - hashTable.capacity = hashTable.capacity; - hashTable.buckets = hashTable.buckets; - hashTable.hashFn = hashTable.hashFn; + expect(hashTable.capacity).toBe(16); + expect(hashTable.buckets).toEqual(new Array(16).fill(null)); + expect(hashTable.hashFn('a')).toBe(6); expect(hashTable.capacity).toBe(16); expect(hashTable.size).toBe(0); expect(hashTable.buckets.length).toBe(16); 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 24c041e..e6d189b 100644 --- a/test/unit/data-structures/linked-list/skip-list.test.ts +++ b/test/unit/data-structures/linked-list/skip-list.test.ts @@ -53,3 +53,34 @@ describe('SkipList', () => { expect(skipList.get(4)).toBe('Four'); }); }); + +describe('SkipList', () => { + let skipList: SkipList; + + beforeEach(() => { + skipList = new SkipList(); + skipList.add(1, 'One'); + skipList.add(2, 'Two'); + skipList.add(3, 'Three'); + skipList.add(4, 'Four'); + }); + + test('getFirst() should return the getFirst element', () => { + expect(skipList.getFirst()).toBe('One'); + }); + + test('getLast() should return the getLast element', () => { + expect(skipList.getLast()).toBe('Four'); + }); + + test('higher(key) should return the getFirst element greater than the given key', () => { + expect(skipList.higher(2)).toBe('Three'); + expect(skipList.higher(3)).toBe('Four'); + expect(skipList.higher(4)).toBeUndefined(); + }); + + test('lower(key) should return the getLast element less than the given key', () => { + expect(skipList.lower(2)).toBe('One'); + expect(skipList.lower(1)).toBe(null); + }); +}); From 8712bbd3c9eb3a8e9b4c4d3348ea20ddb3a856af Mon Sep 17 00:00:00 2001 From: Revone Date: Tue, 31 Oct 2023 11:15:39 +0800 Subject: [PATCH 45/46] [core] All data structures have had their member variables access control optimized. --- src/data-structures/binary-tree/avl-tree.ts | 6 +- .../binary-tree/binary-indexed-tree.ts | 18 +--- .../binary-tree/binary-tree.ts | 59 ++++------- src/data-structures/binary-tree/bst.ts | 11 +-- src/data-structures/binary-tree/rb-tree.ts | 34 +++---- .../binary-tree/segment-tree.ts | 99 +++---------------- .../binary-tree/tree-multiset.ts | 17 ++-- src/data-structures/graph/abstract-graph.ts | 88 ++++------------- src/data-structures/graph/directed-graph.ts | 52 +++------- src/data-structures/graph/map-graph.ts | 39 ++------ src/data-structures/graph/undirected-graph.ts | 35 ++----- src/data-structures/hash/hash-map.ts | 2 +- src/data-structures/hash/tree-map.ts | 3 +- src/data-structures/hash/tree-set.ts | 3 +- src/data-structures/heap/heap.ts | 4 +- src/data-structures/heap/max-heap.ts | 2 +- src/data-structures/heap/min-heap.ts | 2 +- .../linked-list/doubly-linked-list.ts | 2 +- .../linked-list/singly-linked-list.ts | 2 +- src/data-structures/matrix/matrix.ts | 4 +- src/data-structures/matrix/matrix2d.ts | 2 +- src/data-structures/matrix/navigator.ts | 8 +- src/data-structures/matrix/vector2d.ts | 3 +- .../priority-queue/max-priority-queue.ts | 2 +- .../priority-queue/min-priority-queue.ts | 2 +- .../priority-queue/priority-queue.ts | 2 +- src/data-structures/queue/deque.ts | 10 +- src/data-structures/queue/queue.ts | 2 +- src/data-structures/stack/stack.ts | 11 ++- src/data-structures/tree/tree.ts | 10 +- src/data-structures/trie/trie.ts | 21 ++-- src/interfaces/binary-tree.ts | 2 +- src/types/data-structures/binary-tree/bst.ts | 2 +- src/types/data-structures/matrix/navigator.ts | 2 +- src/types/utils/utils.ts | 2 +- src/types/utils/validate-type.ts | 4 +- .../binary-tree/binary-index-tree.test.ts | 4 +- .../graph/abstract-graph.test.ts | 3 +- .../graph/directed-graph.test.ts | 8 +- .../data-structures/graph/map-graph.test.ts | 4 +- 40 files changed, 179 insertions(+), 407 deletions(-) diff --git a/src/data-structures/binary-tree/avl-tree.ts b/src/data-structures/binary-tree/avl-tree.ts index 368f3f7..d98a67c 100644 --- a/src/data-structures/binary-tree/avl-tree.ts +++ b/src/data-structures/binary-tree/avl-tree.ts @@ -21,8 +21,7 @@ export class AVLTreeNode = AVLTreeNodeNeste export class AVLTree = AVLTreeNode>> extends BST - implements IBinaryTree -{ + implements IBinaryTree { /** * This is a constructor function for an AVL tree data structure in TypeScript. * @param {AVLTreeOptions} [options] - The `options` parameter is an optional object that can be passed to the @@ -56,7 +55,6 @@ export class AVLTree = AVLTreeNode = AVLTreeNode) { - this._freqMap = value; - } - protected _msb: number; get msb(): number { return this._msb; } - set msb(value: number) { - this._msb = value; - } - protected _negativeCount: number; get negativeCount(): number { return this._negativeCount; } - set negativeCount(value: number) { - this._negativeCount = value; - } - get freq(): number { return this._freq; } @@ -232,9 +220,9 @@ export class BinaryIndexedTree { */ protected _updateNegativeCount(freqCur: number, freqNew: number): void { if (freqCur < 0 && freqNew >= 0) { - this.negativeCount--; + this._negativeCount--; } else if (freqCur >= 0 && freqNew < 0) { - this.negativeCount++; + this._negativeCount++; } } diff --git a/src/data-structures/binary-tree/binary-tree.ts b/src/data-structures/binary-tree/binary-tree.ts index 08a8dfd..e1b2446 100644 --- a/src/data-structures/binary-tree/binary-tree.ts +++ b/src/data-structures/binary-tree/binary-tree.ts @@ -43,7 +43,7 @@ export class BinaryTreeNode = BinaryTree this.value = value; } - private _left: N | null | undefined; + protected _left: N | null | undefined; /** * Get the left child node. @@ -63,7 +63,7 @@ export class BinaryTreeNode = BinaryTree this._left = v; } - private _right: N | null | undefined; + protected _right: N | null | undefined; /** * Get the right child node. @@ -108,8 +108,9 @@ export class BinaryTreeNode = BinaryTree * @template N - The type of the binary tree's nodes. */ export class BinaryTree = BinaryTreeNode>> - implements IBinaryTree -{ + implements IBinaryTree { + iterationType: IterationType = IterationType.ITERATIVE; + /** * Creates a new instance of BinaryTree. * @param {BinaryTreeOptions} [options] - The options for the binary tree. @@ -117,28 +118,11 @@ export class BinaryTree = BinaryTreeNode constructor(options?: BinaryTreeOptions) { if (options !== undefined) { const {iterationType = IterationType.ITERATIVE} = options; - this._iterationType = iterationType; + this.iterationType = iterationType; } } - private _iterationType: IterationType = IterationType.ITERATIVE; - - /** - * Get the iteration type used in the binary tree. - */ - get iterationType(): IterationType { - return this._iterationType; - } - - /** - * Set the iteration type for the binary tree. - * @param {IterationType} v - The new iteration type to set. - */ - set iterationType(v: IterationType) { - this._iterationType = v; - } - - private _root: N | null = null; + protected _root: N | null = null; /** * Get the root node of the binary tree. @@ -147,7 +131,7 @@ export class BinaryTree = BinaryTreeNode return this._root; } - private _size = 0; + protected _size = 0; /** * Get the number of nodes in the binary tree. @@ -170,7 +154,7 @@ export class BinaryTree = BinaryTreeNode * Clear the binary tree, removing all nodes. */ clear() { - this._root = null; + this._setRoot(null); this._size = 0; } @@ -229,9 +213,9 @@ export class BinaryTree = BinaryTreeNode } else { this._setRoot(needInsert); if (needInsert !== null) { - this._setSize(1); + this._size = 1; } else { - this._setSize(0); + this._size = 0; } inserted = this.root; } @@ -339,7 +323,7 @@ export class BinaryTree = BinaryTreeNode } } } - this._setSize(this.size - 1); + this._size = this.size - 1; bstDeletedResult.push({deleted: orgCurrent, needBalanced}); return bstDeletedResult; @@ -401,7 +385,7 @@ export class BinaryTree = BinaryTreeNode return -1; } - const stack: {node: N; depth: number}[] = [{node: beginRoot, depth: 0}]; + const stack: { node: N; depth: number }[] = [{node: beginRoot, depth: 0}]; let maxHeight = 0; while (stack.length > 0) { @@ -904,7 +888,7 @@ export class BinaryTree = BinaryTreeNode _traverse(beginRoot); } else { // 0: visit, 1: print - const stack: {opt: 0 | 1; node: N | null | undefined}[] = [{opt: 0, node: beginRoot}]; + const stack: { opt: 0 | 1; node: N | null | undefined }[] = [{opt: 0, node: beginRoot}]; while (stack.length > 0) { const cur = stack.pop(); @@ -1174,7 +1158,7 @@ export class BinaryTree = BinaryTreeNode * @returns The `*[Symbol.iterator]` method returns a generator object that yields the keys of the * binary tree nodes in a specific order. */ - *[Symbol.iterator](node = this.root): Generator { + * [Symbol.iterator](node = this.root): Generator { if (!node) { return; } @@ -1244,13 +1228,13 @@ export class BinaryTree = BinaryTreeNode if (parent.left === undefined) { parent.left = newNode; if (newNode) { - this._setSize(this.size + 1); + this._size = this.size + 1; } return parent.left; } else if (parent.right === undefined) { parent.right = newNode; if (newNode) { - this._setSize(this.size + 1); + this._size = this.size + 1; } return parent.right; } else { @@ -1274,14 +1258,5 @@ export class BinaryTree = BinaryTreeNode this._root = v; } - /** - * The function sets the value of the protected property "_size" to the given number. - * @param {number} v - The parameter "v" is a number that represents the size value that we want to - * set. - */ - protected _setSize(v: number) { - this._size = v; - } - // --- end additional methods --- } diff --git a/src/data-structures/binary-tree/bst.ts b/src/data-structures/binary-tree/bst.ts index 7684bd8..e033122 100644 --- a/src/data-structures/binary-tree/bst.ts +++ b/src/data-structures/binary-tree/bst.ts @@ -5,7 +5,7 @@ * @copyright Copyright (c) 2022 Tyler Zeng * @license MIT License */ -import type {BTNKey, BSTComparator, BSTNodeNested, BSTOptions, BTNCallback} from '../../types'; +import type {BSTComparator, BSTNodeNested, BSTOptions, BTNCallback, BTNKey} from '../../types'; import {CP, IterationType} from '../../types'; import {BinaryTree, BinaryTreeNode} from './binary-tree'; import {IBinaryTree} from '../../interfaces'; @@ -19,8 +19,7 @@ export class BSTNode = BSTNodeNested> extend export class BST = BSTNode>> extends BinaryTree - implements IBinaryTree -{ + implements IBinaryTree { /** * The constructor function initializes a binary search tree object with an optional comparator * function. @@ -72,7 +71,7 @@ export class BST = BSTNode> } if (this.root === null) { this._setRoot(newNode); - this._setSize(this.size + 1); + this._size = this.size + 1; inserted = this.root; } else { let cur = this.root; @@ -94,7 +93,7 @@ export class BST = BSTNode> } //Add to the left of the current node cur.left = newNode; - this._setSize(this.size + 1); + this._size = this.size + 1; traversing = false; inserted = cur.left; } else { @@ -109,7 +108,7 @@ export class BST = BSTNode> } //Add to the right of the current node cur.right = newNode; - this._setSize(this.size + 1); + this._size = this.size + 1; traversing = false; inserted = cur.right; } else { diff --git a/src/data-structures/binary-tree/rb-tree.ts b/src/data-structures/binary-tree/rb-tree.ts index 65edc63..3018dc7 100644 --- a/src/data-structures/binary-tree/rb-tree.ts +++ b/src/data-structures/binary-tree/rb-tree.ts @@ -5,24 +5,16 @@ import {BST, BSTNode} from './bst'; export class RBTreeNode = RBTreeNodeNested> extends BSTNode { constructor(key: BTNKey, value?: V) { super(key, value); - this._color = RBColor.RED; + this.color = RBColor.RED; } - private _color: RBColor; + color: RBColor; - get color(): RBColor { - return this._color; - } - - set color(value: RBColor) { - this._color = value; - } } export class RBTree = RBTreeNode>> extends BST - implements IBinaryTree -{ + implements IBinaryTree { constructor(options?: RBTreeOptions) { super(options); } @@ -38,7 +30,7 @@ export class RBTree = RBTreeNode = RBTreeNode = RBTreeNode = RBTreeNode = RBTreeNode = RBTreeNode = RBTreeNode = RBTreeNode = RBTreeNode = TreeMultisetNode>> extends AVLTree - implements IBinaryTree -{ + implements IBinaryTree { /** * The constructor function for a TreeMultiset class in TypeScript, which extends another class and sets an option to * merge duplicated values. @@ -93,7 +92,7 @@ export class TreeMultiset = TreeMultis } if (!this.root) { this._setRoot(newNode); - this._setSize(this.size + 1); + this._size = this.size + 1; newNode && this._setCount(this.count + newNode.count); inserted = this.root; } else { @@ -113,7 +112,7 @@ export class TreeMultiset = TreeMultis if (cur.left === undefined) { //Add to the left of the current node cur.left = newNode; - this._setSize(this.size + 1); + this._size = this.size + 1; this._setCount(this.count + newNode.count); traversing = false; @@ -127,7 +126,7 @@ export class TreeMultiset = TreeMultis if (cur.right === undefined) { //Add to the right of the current node cur.right = newNode; - this._setSize(this.size + 1); + this._size = this.size + 1; this._setCount(this.count + newNode.count); traversing = false; @@ -162,7 +161,7 @@ export class TreeMultiset = TreeMultis if (parent.left === undefined) { parent.left = newNode; if (newNode !== null) { - this._setSize(this.size + 1); + this._size = this.size + 1; this._setCount(this.count + newNode.count); } @@ -170,7 +169,7 @@ export class TreeMultiset = TreeMultis } else if (parent.right === undefined) { parent.right = newNode; if (newNode !== null) { - this._setSize(this.size + 1); + this._size = (this.size + 1); this._setCount(this.count + newNode.count); } return parent.right; @@ -321,7 +320,7 @@ export class TreeMultiset = TreeMultis } } } - this._setSize(this.size - 1); + this._size = this.size - 1; // TODO How to handle when the count of target node is lesser than current node's count this._setCount(this.count - orgCurrent.count); } diff --git a/src/data-structures/graph/abstract-graph.ts b/src/data-structures/graph/abstract-graph.ts index bd67db9..6cd5504 100644 --- a/src/data-structures/graph/abstract-graph.ts +++ b/src/data-structures/graph/abstract-graph.ts @@ -12,6 +12,9 @@ import {IGraph} from '../../interfaces'; import {Queue} from '../queue'; export abstract class AbstractVertex { + key: VertexKey; + value: V | undefined; + /** * The function is a protected constructor that takes an key and an optional value as parameters. * @param {VertexKey} key - The `key` parameter is of type `VertexKey` and represents the identifier of the vertex. It is @@ -20,32 +23,16 @@ export abstract class AbstractVertex { * vertex. If no value is provided, it will be set to undefined. */ protected constructor(key: VertexKey, value?: V) { - this._key = key; - this._value = value; + this.key = key; + this.value = value; } - private _key: VertexKey; - - get key(): VertexKey { - return this._key; - } - - set key(v: VertexKey) { - this._key = v; - } - - private _value: V | undefined; - - get value(): V | undefined { - return this._value; - } - - set value(value: V | undefined) { - this._value = value; - } } export abstract class AbstractEdge { + value: E | undefined; + weight: number; + /** * The above function is a protected constructor that initializes the weight, value, and hash code properties of an * object. @@ -56,31 +43,11 @@ export abstract class AbstractEdge { * meaning it can be omitted when creating an instance of the class. */ protected constructor(weight?: number, value?: E) { - this._weight = weight !== undefined ? weight : 1; - this._value = value; + this.weight = weight !== undefined ? weight : 1; + this.value = value; this._hashCode = uuidV4(); } - private _value: E | undefined; - - get value(): E | undefined { - return this._value; - } - - set value(value: E | undefined) { - this._value = value; - } - - private _weight: number; - - get weight(): number { - return this._weight; - } - - set weight(v: number) { - this._weight = v; - } - protected _hashCode: string; get hashCode(): string { @@ -91,15 +58,6 @@ export abstract class AbstractEdge { * In TypeScript, a subclass inherits the interface implementation of its parent class, without needing to implement the same interface again in the subclass. This behavior differs from Java's approach. In Java, if a parent class implements an interface, the subclass needs to explicitly implement the same interface, even if the parent class has already implemented it. * This means that using abstract methods in the parent class cannot constrain the grandchild classes. Defining methods within an interface also cannot constrain the descendant classes. When inheriting from this class, developers need to be aware that this method needs to be overridden. */ - - /** - * The function sets the value of the _hashCode property to the provided string. - * @param {string} v - The parameter "v" is of type string and represents the value that will be assigned to the - * "_hashCode" property. - */ - protected _setHashCode(v: string) { - this._hashCode = v; - } } export abstract class AbstractGraph< @@ -107,9 +65,8 @@ export abstract class AbstractGraph< E = any, VO extends AbstractVertex = AbstractVertex, EO extends AbstractEdge = AbstractEdge -> implements IGraph -{ - private _vertices: Map = new Map(); +> implements IGraph { + protected _vertices: Map = new Map(); get vertices(): Map { return this._vertices; @@ -556,14 +513,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); @@ -625,7 +582,7 @@ export abstract class AbstractGraph< if (vertexOrKey instanceof AbstractVertex) distMap.set(vertexOrKey, Infinity); } - const heap = new PriorityQueue<{key: number; value: VO}>({comparator: (a, b) => a.key - b.key}); + const heap = new PriorityQueue<{ key: number; value: VO }>({comparator: (a, b) => a.key - b.key}); heap.add({key: 0, value: srcVertex}); distMap.set(srcVertex, 0); @@ -854,7 +811,7 @@ export abstract class AbstractGraph< * `predecessor` property is a 2D array of vertices (or `null`) representing the predecessor vertices in the shortest * path between vertices in the */ - floyd(): {costs: number[][]; predecessor: (VO | null)[][]} { + floyd(): { costs: number[][]; predecessor: (VO | null)[][] } { const idAndVertices = [...this._vertices]; const n = idAndVertices.length; @@ -1040,7 +997,4 @@ export abstract class AbstractGraph< return vertexOrKey instanceof AbstractVertex ? vertexOrKey.key : vertexOrKey; } - protected _setVertices(value: Map) { - this._vertices = value; - } } diff --git a/src/data-structures/graph/directed-graph.ts b/src/data-structures/graph/directed-graph.ts index 59a3860..23fd02d 100644 --- a/src/data-structures/graph/directed-graph.ts +++ b/src/data-structures/graph/directed-graph.ts @@ -24,6 +24,9 @@ export class DirectedVertex extends AbstractVertex { } export class DirectedEdge extends AbstractEdge { + src: VertexKey; + dest: VertexKey; + /** * The constructor function initializes the source and destination vertices of an edge, along with an optional weight * and value. @@ -37,40 +40,19 @@ export class DirectedEdge extends AbstractEdge { */ constructor(src: VertexKey, dest: VertexKey, weight?: number, value?: E) { super(weight, value); - this._src = src; - this._dest = dest; - } - - private _src: VertexKey; - - get src(): VertexKey { - return this._src; - } - - set src(v: VertexKey) { - this._src = v; - } - - private _dest: VertexKey; - - get dest(): VertexKey { - return this._dest; - } - - set dest(v: VertexKey) { - this._dest = v; + this.src = src; + this.dest = dest; } } 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. */ @@ -78,13 +60,13 @@ export class DirectedGraph< super(); } - private _outEdgeMap: Map = new Map(); + protected _outEdgeMap: Map = new Map(); get outEdgeMap(): Map { return this._outEdgeMap; } - private _inEdgeMap: Map = new Map(); + protected _inEdgeMap: Map = new Map(); get inEdgeMap(): Map { return this._inEdgeMap; @@ -464,12 +446,4 @@ export class DirectedGraph< return false; } } - - protected _setOutEdgeMap(value: Map) { - this._outEdgeMap = value; - } - - protected _setInEdgeMap(value: Map) { - this._inEdgeMap = value; - } } diff --git a/src/data-structures/graph/map-graph.ts b/src/data-structures/graph/map-graph.ts index e7d6b5b..7edce9b 100644 --- a/src/data-structures/graph/map-graph.ts +++ b/src/data-structures/graph/map-graph.ts @@ -2,6 +2,9 @@ import {MapGraphCoordinate, VertexKey} from '../../types'; import {DirectedEdge, DirectedGraph, DirectedVertex} from './directed-graph'; export class MapVertex extends DirectedVertex { + lat: number; + long: number; + /** * The constructor function initializes an object with an key, latitude, longitude, and an optional value. * @param {VertexKey} key - The `key` parameter is of type `VertexKey` and represents the identifier of the vertex. @@ -16,28 +19,8 @@ export class MapVertex extends DirectedVertex { */ constructor(key: VertexKey, value: V, lat: number, long: number) { super(key, value); - this._lat = lat; - this._long = long; - } - - private _lat: number; - - get lat(): number { - return this._lat; - } - - set lat(value: number) { - this._lat = value; - } - - private _long: number; - - get long(): number { - return this._long; - } - - set long(value: number) { - this._long = value; + this.lat = lat; + this.long = long; } } @@ -78,26 +61,18 @@ export class MapGraph< this._bottomRight = bottomRight; } - private _origin: MapGraphCoordinate = [0, 0]; + protected _origin: MapGraphCoordinate = [0, 0]; get origin(): MapGraphCoordinate { return this._origin; } - set origin(value: MapGraphCoordinate) { - this._origin = value; - } - - private _bottomRight: MapGraphCoordinate | undefined; + protected _bottomRight: MapGraphCoordinate | undefined; get bottomRight(): MapGraphCoordinate | undefined { return this._bottomRight; } - set bottomRight(value: MapGraphCoordinate | undefined) { - this._bottomRight = value; - } - /** * The function creates a new vertex with the given key, value, latitude, and longitude. * @param {VertexKey} key - The key parameter is the unique identifier for the vertex. It is of type VertexKey, which could diff --git a/src/data-structures/graph/undirected-graph.ts b/src/data-structures/graph/undirected-graph.ts index 39b63e7..75f15fc 100644 --- a/src/data-structures/graph/undirected-graph.ts +++ b/src/data-structures/graph/undirected-graph.ts @@ -24,6 +24,8 @@ export class UndirectedVertex extends AbstractVertex { } export class UndirectedEdge extends AbstractEdge { + vertices: [VertexKey, VertexKey]; + /** * The constructor function creates an instance of a class with two vertex IDs, an optional weight, and an optional * value. @@ -36,29 +38,18 @@ export class UndirectedEdge extends AbstractEdge { */ constructor(v1: VertexKey, v2: VertexKey, weight?: number, value?: E) { super(weight, value); - this._vertices = [v1, v2]; - } - - private _vertices: [VertexKey, VertexKey]; - - get vertices() { - return this._vertices; - } - - set vertices(v: [VertexKey, VertexKey]) { - this._vertices = v; + this.vertices = [v1, v2]; } } 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 edges. */ @@ -265,12 +256,4 @@ export class UndirectedGraph< } return true; } - - /** - * The function sets the edges of a graph. - * @param v - A map where the keys are of type VO and the values are arrays of type EO. - */ - protected _setEdges(v: Map) { - this._edges = v; - } } diff --git a/src/data-structures/hash/hash-map.ts b/src/data-structures/hash/hash-map.ts index 9595be5..cb59fc3 100644 --- a/src/data-structures/hash/hash-map.ts +++ b/src/data-structures/hash/hash-map.ts @@ -133,7 +133,7 @@ export class HashMap { } } - *entries(): IterableIterator<[K, V]> { + * entries(): IterableIterator<[K, V]> { for (const bucket of this.table) { if (bucket) { for (const [key, value] of bucket) { diff --git a/src/data-structures/hash/tree-map.ts b/src/data-structures/hash/tree-map.ts index fe86360..a6d743d 100644 --- a/src/data-structures/hash/tree-map.ts +++ b/src/data-structures/hash/tree-map.ts @@ -1 +1,2 @@ -export class TreeMap {} +export class TreeMap { +} diff --git a/src/data-structures/hash/tree-set.ts b/src/data-structures/hash/tree-set.ts index 591aeda..65f14db 100644 --- a/src/data-structures/hash/tree-set.ts +++ b/src/data-structures/hash/tree-set.ts @@ -1 +1,2 @@ -export class TreeSet {} +export class TreeSet { +} diff --git a/src/data-structures/heap/heap.ts b/src/data-structures/heap/heap.ts index 60d4533..999454a 100644 --- a/src/data-structures/heap/heap.ts +++ b/src/data-structures/heap/heap.ts @@ -8,7 +8,7 @@ import type {Comparator, DFSOrderPattern} from '../../types'; export class Heap { - constructor(options: {comparator: Comparator; nodes?: E[]}) { + constructor(options: { comparator: Comparator; nodes?: E[] }) { this._comparator = options.comparator; if (options.nodes && options.nodes.length > 0) { this._nodes = options.nodes; @@ -48,7 +48,7 @@ export class Heap { * @returns A new Heap instance. * @param options */ - static heapify(options: {nodes: E[]; comparator: Comparator}): Heap { + static heapify(options: { nodes: E[]; comparator: Comparator }): Heap { return new Heap(options); } diff --git a/src/data-structures/heap/max-heap.ts b/src/data-structures/heap/max-heap.ts index be2c9b1..139ef64 100644 --- a/src/data-structures/heap/max-heap.ts +++ b/src/data-structures/heap/max-heap.ts @@ -11,7 +11,7 @@ import type {Comparator} from '../../types'; export class MaxHeap extends Heap { constructor( - options: {comparator: Comparator; nodes?: E[]} = { + options: { comparator: Comparator; nodes?: E[] } = { 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'); diff --git a/src/data-structures/heap/min-heap.ts b/src/data-structures/heap/min-heap.ts index dc86f87..5057017 100644 --- a/src/data-structures/heap/min-heap.ts +++ b/src/data-structures/heap/min-heap.ts @@ -11,7 +11,7 @@ import type {Comparator} from '../../types'; export class MinHeap extends Heap { constructor( - options: {comparator: Comparator; nodes?: E[]} = { + options: { comparator: Comparator; nodes?: E[] } = { 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'); diff --git a/src/data-structures/linked-list/doubly-linked-list.ts b/src/data-structures/linked-list/doubly-linked-list.ts index 119ae71..41b9dc9 100644 --- a/src/data-structures/linked-list/doubly-linked-list.ts +++ b/src/data-structures/linked-list/doubly-linked-list.ts @@ -594,7 +594,7 @@ export class DoublyLinkedList { /** * The function returns an iterator that iterates over the values of a linked list. */ - *[Symbol.iterator]() { + * [Symbol.iterator]() { 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 7c39cf6..04c0bbe 100644 --- a/src/data-structures/linked-list/singly-linked-list.ts +++ b/src/data-structures/linked-list/singly-linked-list.ts @@ -565,7 +565,7 @@ export class SinglyLinkedList { /** * The function returns an iterator that iterates over the values of a linked list. */ - *[Symbol.iterator]() { + * [Symbol.iterator]() { let current = this.head; while (current) { diff --git a/src/data-structures/matrix/matrix.ts b/src/data-structures/matrix/matrix.ts index 8f27617..4f1b8b8 100644 --- a/src/data-structures/matrix/matrix.ts +++ b/src/data-structures/matrix/matrix.ts @@ -7,14 +7,14 @@ */ // todo need to be improved export class MatrixNTI2D { - private readonly _matrix: Array>; + protected readonly _matrix: Array>; /** * The constructor creates a matrix with the specified number of rows and columns, and initializes all elements to a * given initial value or 0 if not provided. * @param options - An object containing the following properties: */ - constructor(options: {row: number; col: number; initialVal?: V}) { + constructor(options: { row: number; col: number; initialVal?: V }) { const {row, col, initialVal} = options; this._matrix = new Array(row).fill(undefined).map(() => new Array(col).fill(initialVal || 0)); } diff --git a/src/data-structures/matrix/matrix2d.ts b/src/data-structures/matrix/matrix2d.ts index ab9bfef..6ea16c5 100644 --- a/src/data-structures/matrix/matrix2d.ts +++ b/src/data-structures/matrix/matrix2d.ts @@ -8,7 +8,7 @@ import {Vector2D} from './vector2d'; export class Matrix2D { - private readonly _matrix: number[][]; + protected readonly _matrix: number[][]; /** * The constructor function initializes a Matrix2D object with either a default identity matrix, or a provided matrix diff --git a/src/data-structures/matrix/navigator.ts b/src/data-structures/matrix/navigator.ts index dd2f854..2aab50b 100644 --- a/src/data-structures/matrix/navigator.ts +++ b/src/data-structures/matrix/navigator.ts @@ -27,10 +27,10 @@ export class Character { export class Navigator { onMove: (cur: [number, number]) => void; - private readonly _matrix: T[][]; - private readonly _cur: [number, number]; - private _character: Character; - private readonly _VISITED: T; + protected readonly _matrix: T[][]; + protected readonly _cur: [number, number]; + protected _character: Character; + protected readonly _VISITED: T; /** * The constructor initializes the Navigator object with the given parameters and sets the current position as visited diff --git a/src/data-structures/matrix/vector2d.ts b/src/data-structures/matrix/vector2d.ts index 1b2ff44..2f62f4e 100644 --- a/src/data-structures/matrix/vector2d.ts +++ b/src/data-structures/matrix/vector2d.ts @@ -10,7 +10,8 @@ export class Vector2D { public x: number = 0, public y: number = 0, public w: number = 1 // needed for matrix multiplication - ) {} + ) { + } /** * The function checks if the x and y values of a point are both zero. diff --git a/src/data-structures/priority-queue/max-priority-queue.ts b/src/data-structures/priority-queue/max-priority-queue.ts index dbb0793..409c99f 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 type {Comparator} from '../../types'; export class MaxPriorityQueue extends PriorityQueue { constructor( - options: {comparator: Comparator; nodes?: E[]} = { + options: { comparator: Comparator; nodes?: E[] } = { 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'); diff --git a/src/data-structures/priority-queue/min-priority-queue.ts b/src/data-structures/priority-queue/min-priority-queue.ts index 8b8386f..da8ab64 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 type {Comparator} from '../../types'; export class MinPriorityQueue extends PriorityQueue { constructor( - options: {comparator: Comparator; nodes?: E[]} = { + options: { comparator: Comparator; nodes?: E[] } = { 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'); diff --git a/src/data-structures/priority-queue/priority-queue.ts b/src/data-structures/priority-queue/priority-queue.ts index edfbaf2..60deb98 100644 --- a/src/data-structures/priority-queue/priority-queue.ts +++ b/src/data-structures/priority-queue/priority-queue.ts @@ -10,7 +10,7 @@ import {Heap} from '../heap'; import {Comparator} from '../../types'; export class PriorityQueue extends Heap { - constructor(options: {comparator: Comparator; nodes?: E[]}) { + constructor(options: { comparator: Comparator; nodes?: E[] }) { super(options); } } diff --git a/src/data-structures/queue/deque.ts b/src/data-structures/queue/deque.ts index 3dc8c58..f0911ab 100644 --- a/src/data-structures/queue/deque.ts +++ b/src/data-structures/queue/deque.ts @@ -9,7 +9,8 @@ import {DoublyLinkedList} from '../linked-list'; // O(n) time complexity of obtaining the value // O(1) time complexity of adding at the beginning and the end -export class Deque extends DoublyLinkedList {} +export class Deque extends DoublyLinkedList { +} // O(1) time complexity of obtaining the value // O(n) time complexity of adding at the beginning and the end @@ -19,9 +20,9 @@ export class ObjectDeque { if (capacity !== undefined) this._capacity = capacity; } - protected _nodes: {[key: number]: E} = {}; + protected _nodes: { [key: number]: E } = {}; - get nodes(): {[p: number]: E} { + get nodes(): { [p: number]: E } { return this._nodes; } @@ -148,10 +149,11 @@ export class ObjectDeque { // O(1) time complexity of obtaining the value // O(n) time complexity of adding at the beginning and the end export class ArrayDeque { + protected _nodes: E[] = []; + get nodes(): E[] { return this._nodes; } - protected _nodes: E[] = []; get size() { return this.nodes.length; diff --git a/src/data-structures/queue/queue.ts b/src/data-structures/queue/queue.ts index 9991f38..6222f35 100644 --- a/src/data-structures/queue/queue.ts +++ b/src/data-structures/queue/queue.ts @@ -201,7 +201,7 @@ export class Queue { return new Queue(this.nodes.slice(this.offset)); } - *[Symbol.iterator]() { + * [Symbol.iterator]() { for (const item of this.nodes) { yield item; } diff --git a/src/data-structures/stack/stack.ts b/src/data-structures/stack/stack.ts index 0b2bfce..e343f09 100644 --- a/src/data-structures/stack/stack.ts +++ b/src/data-structures/stack/stack.ts @@ -4,11 +4,6 @@ * @class */ export class Stack { - get elements(): E[] { - return this._elements; - } - protected _elements: E[]; - /** * The constructor initializes an array of elements, which can be provided as an optional parameter. * @param {E[]} [elements] - The `elements` parameter is an optional parameter of type `E[]`, which represents an array @@ -19,6 +14,12 @@ export class Stack { this._elements = Array.isArray(elements) ? elements : []; } + protected _elements: E[]; + + get elements(): E[] { + return this._elements; + } + /** * The function "fromArray" creates a new Stack object from an array of elements. * @param {E[]} elements - The `elements` parameter is an array of elements of type `E`. diff --git a/src/data-structures/tree/tree.ts b/src/data-structures/tree/tree.ts index 729365a..e5a7e73 100644 --- a/src/data-structures/tree/tree.ts +++ b/src/data-structures/tree/tree.ts @@ -1,16 +1,14 @@ export class TreeNode { + key: string; + value?: V | undefined; + children?: TreeNode[] | undefined; + constructor(key: string, value?: V, children?: TreeNode[]) { this.key = key; this.value = value || undefined; this.children = children || []; } - key: string; - - value?: V | undefined; - - children?: TreeNode[] | undefined; - addChildren(children: TreeNode | TreeNode[]) { if (!this.children) { this.children = []; diff --git a/src/data-structures/trie/trie.ts b/src/data-structures/trie/trie.ts index 08bd374..25e31ca 100644 --- a/src/data-structures/trie/trie.ts +++ b/src/data-structures/trie/trie.ts @@ -11,28 +11,21 @@ * and a flag indicating whether it's the end of a word. */ export class TrieNode { + key: string; + children: Map; + isEnd: boolean; + constructor(key: string) { this.key = key; this.isEnd = false; this.children = new Map(); } - - key: string; - - children: Map; - - isEnd: boolean; } /** * Trie represents a Trie data structure. It provides basic Trie operations and additional methods. */ export class Trie { - get caseSensitive(): boolean { - return this._caseSensitive; - } - protected _caseSensitive: boolean; - constructor(words?: string[], caseSensitive = true) { this._root = new TrieNode(''); this._caseSensitive = caseSensitive; @@ -43,6 +36,12 @@ export class Trie { } } + protected _caseSensitive: boolean; + + get caseSensitive(): boolean { + return this._caseSensitive; + } + protected _root: TrieNode; get root() { diff --git a/src/interfaces/binary-tree.ts b/src/interfaces/binary-tree.ts index 649cf27..1e71463 100644 --- a/src/interfaces/binary-tree.ts +++ b/src/interfaces/binary-tree.ts @@ -1,5 +1,5 @@ import {BinaryTreeNode} from '../data-structures'; -import {BinaryTreeDeletedResult, BTNKey, BinaryTreeNodeNested, BTNCallback} from '../types'; +import {BinaryTreeDeletedResult, BinaryTreeNodeNested, BTNCallback, BTNKey} from '../types'; export interface IBinaryTree = BinaryTreeNodeNested> { createNode(key: BTNKey, value?: N['value']): N; diff --git a/src/types/data-structures/binary-tree/bst.ts b/src/types/data-structures/binary-tree/bst.ts index 6efe2d2..ad54f3c 100644 --- a/src/types/data-structures/binary-tree/bst.ts +++ b/src/types/data-structures/binary-tree/bst.ts @@ -1,5 +1,5 @@ import {BSTNode} from '../../../data-structures'; -import type {BTNKey, BinaryTreeOptions} from './binary-tree'; +import type {BinaryTreeOptions, BTNKey} from './binary-tree'; export type BSTComparator = (a: BTNKey, b: BTNKey) => number; diff --git a/src/types/data-structures/matrix/navigator.ts b/src/types/data-structures/matrix/navigator.ts index 9d8b9a9..34eddd9 100644 --- a/src/types/data-structures/matrix/navigator.ts +++ b/src/types/data-structures/matrix/navigator.ts @@ -1,6 +1,6 @@ export type Direction = 'up' | 'right' | 'down' | 'left'; -export type Turning = {[key in Direction]: Direction}; +export type Turning = { [key in Direction]: Direction }; export type NavigatorParams = { matrix: T[][]; diff --git a/src/types/utils/utils.ts b/src/types/utils/utils.ts index f4d26c4..1f3a505 100644 --- a/src/types/utils/utils.ts +++ b/src/types/utils/utils.ts @@ -1,5 +1,5 @@ export type ToThunkFn = () => ReturnType; -export type Thunk = () => ReturnType & {__THUNK__: symbol}; +export type Thunk = () => ReturnType & { __THUNK__: symbol }; export type TrlFn = (...args: any[]) => any; export type TrlAsyncFn = (...args: any[]) => any; diff --git a/src/types/utils/validate-type.ts b/src/types/utils/validate-type.ts index ac9ff28..3ebf451 100644 --- a/src/types/utils/validate-type.ts +++ b/src/types/utils/validate-type.ts @@ -1,6 +1,6 @@ -export type KeyValueObject = {[key: string]: any}; +export type KeyValueObject = { [key: string]: any }; -export type KeyValueObjectWithKey = {[key: string]: any; key: string | number | symbol}; +export type KeyValueObjectWithKey = { [key: string]: any; key: string | number | symbol }; export type NonNumberNonObjectButDefined = string | boolean | symbol | null; diff --git a/test/unit/data-structures/binary-tree/binary-index-tree.test.ts b/test/unit/data-structures/binary-tree/binary-index-tree.test.ts index 4135fab..7d63c02 100644 --- a/test/unit/data-structures/binary-tree/binary-index-tree.test.ts +++ b/test/unit/data-structures/binary-tree/binary-index-tree.test.ts @@ -286,8 +286,8 @@ function loopLowerBoundTests(bit: BinaryIndexedTree, values: number[]) { describe('', () => { class NumArrayDC { - private _tree: BinaryIndexedTree; - private readonly _nums: number[]; + protected _tree: BinaryIndexedTree; + protected readonly _nums: number[]; constructor(nums: number[]) { this._nums = nums; diff --git a/test/unit/data-structures/graph/abstract-graph.test.ts b/test/unit/data-structures/graph/abstract-graph.test.ts index a9f6774..5205c66 100644 --- a/test/unit/data-structures/graph/abstract-graph.test.ts +++ b/test/unit/data-structures/graph/abstract-graph.test.ts @@ -19,7 +19,6 @@ class MyEdge extends AbstractEdge { this.src = srcOrV1; this.dest = destOrV2; this.data = value; - this._setHashCode(''); } } @@ -96,6 +95,6 @@ describe('AbstractGraph Operation Test', () => { eAB!.value = eAB.value; const hs = eAB.hashCode; - expect(hs).toBe(''); + expect(hs.length).toBe(36); }); }); diff --git a/test/unit/data-structures/graph/directed-graph.test.ts b/test/unit/data-structures/graph/directed-graph.test.ts index de01fc9..ff8b2ad 100644 --- a/test/unit/data-structures/graph/directed-graph.test.ts +++ b/test/unit/data-structures/graph/directed-graph.test.ts @@ -98,7 +98,7 @@ class MyVertex extends DirectedVertex { this._data = value; } - private _data: V | undefined; + protected _data: V | undefined; get data(): V | undefined { return this._data; @@ -115,7 +115,7 @@ class MyEdge extends DirectedEdge { this._data = value; } - private _data: E | undefined; + protected _data: E | undefined; get data(): E | undefined { return this._data; @@ -141,11 +141,11 @@ class MyDirectedGraph< } setInEdgeMap(value: Map) { - super._setInEdgeMap(value); + this._inEdgeMap = value; } setOutEdgeMap(value: Map) { - super._setOutEdgeMap(value); + this._outEdgeMap = value; } } diff --git a/test/unit/data-structures/graph/map-graph.test.ts b/test/unit/data-structures/graph/map-graph.test.ts index 94555c7..31a4f4c 100644 --- a/test/unit/data-structures/graph/map-graph.test.ts +++ b/test/unit/data-structures/graph/map-graph.test.ts @@ -88,8 +88,8 @@ describe('MapGraph', () => { const edgeAB = new MapEdge('A', 'B', 50, 'Edge from A to B'); const edgeBC = new MapEdge('B', 'C', 60, 'Edge from B to C'); - mapGraph.origin = mapGraph.origin; - mapGraph.bottomRight = mapGraph.bottomRight; + expect(mapGraph.origin).toEqual([0, 0]); + expect(mapGraph.bottomRight).toEqual([100, 100]); mapGraph.addVertex(locationA); mapGraph.addVertex(locationB); From 10bbcffcef4ed5901867431a3d3eae891d190b9d Mon Sep 17 00:00:00 2001 From: Revone Date: Tue, 31 Oct 2023 11:22:21 +0800 Subject: [PATCH 46/46] [pkg] v1.40.0 published --- CHANGELOG.md | 2 +- package-lock.json | 50 +++++++++++++++---------------- package.json | 10 +++---- test/integration/avl-tree.test.ts | 2 +- test/integration/bst.test.ts | 4 +-- 5 files changed, 34 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b077a9..8652626 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.39.6](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) +## [v1.40.0](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) ### Changes diff --git a/package-lock.json b/package-lock.json index 6a3b471..8a15adf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "data-structure-typed", - "version": "1.39.6", + "version": "1.40.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "data-structure-typed", - "version": "1.39.6", + "version": "1.40.0", "license": "MIT", "devDependencies": { "@types/benchmark": "^2.1.3", @@ -15,17 +15,17 @@ "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", "auto-changelog": "^2.4.0", - "avl-tree-typed": "^1.39.5", + "avl-tree-typed": "^1.39.6", "benchmark": "^2.1.4", - "binary-tree-typed": "^1.39.5", - "bst-typed": "^1.39.5", + "binary-tree-typed": "^1.39.6", + "bst-typed": "^1.39.6", "dependency-cruiser": "^14.1.0", "eslint": "^8.50.0", "eslint-config-prettier": "^9.0.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.28.1", - "heap-typed": "^1.39.5", + "heap-typed": "^1.39.6", "istanbul-badges-readme": "^1.8.5", "jest": "^29.7.0", "prettier": "^3.0.3", @@ -2728,12 +2728,12 @@ } }, "node_modules/avl-tree-typed": { - "version": "1.39.5", - "resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.39.5.tgz", - "integrity": "sha512-4KpwQrTkbo22Q/dHESzUX+T0m/Ho18fvoxeeH48k1O7vuIWeUWfqAJ3DcWuANWD6urMaICNb5xM/E4DHdlS0Yg==", + "version": "1.39.6", + "resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.39.6.tgz", + "integrity": "sha512-Yejek2E2+TvXMfCTBjZ9vXYucbOi7sRKo9TJLTvN5FbZ82pnG5MRsik98IvluU0ZY9lEFwu7iFVnPSe2BFdWqQ==", "dev": true, "dependencies": { - "data-structure-typed": "^1.39.5" + "data-structure-typed": "^1.39.6" } }, "node_modules/babel-jest": { @@ -2927,12 +2927,12 @@ } }, "node_modules/binary-tree-typed": { - "version": "1.39.5", - "resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.39.5.tgz", - "integrity": "sha512-4+2vmkEmBnzGLCyiGJwRy2k86IDoG1PxfVjXp31H469iPzts5MpQoBgCOttuy9fzXZRQBZautroTNwjXZK2sWA==", + "version": "1.39.6", + "resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.39.6.tgz", + "integrity": "sha512-IkiWRDA+wni3ye5A1l+ogIxfvGflcBKmagU599GIffmkeuLlLVjP2tQyvqpCzEwVRtRO64zEBtL/p30RsNbeew==", "dev": true, "dependencies": { - "data-structure-typed": "^1.39.5" + "data-structure-typed": "^1.39.6" } }, "node_modules/brace-expansion": { @@ -3011,12 +3011,12 @@ } }, "node_modules/bst-typed": { - "version": "1.39.5", - "resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.39.5.tgz", - "integrity": "sha512-vMyRR1piavhx8rTf81nzU/RMBY5p5++4fX4EZI9CXhgFAFormuj9h/7BP0BDMzeaQMILIo9ruBdeChMp/D6xnQ==", + "version": "1.39.6", + "resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.39.6.tgz", + "integrity": "sha512-cP9BvJAlEZwLt3lgZFC1PdklD+nzG4ZqxNqEdSxNxvxlbc8RuhlLo6J2bCywnJN+zH/FyDQpM9iBEq07gEixWA==", "dev": true, "dependencies": { - "data-structure-typed": "^1.39.5" + "data-structure-typed": "^1.39.6" } }, "node_modules/buffer-from": { @@ -3413,9 +3413,9 @@ } }, "node_modules/data-structure-typed": { - "version": "1.39.5", - "resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.39.5.tgz", - "integrity": "sha512-PyrhlHFxmkfMSwRG/83uw9GWLFBTjz8TCfbhMiq7Am+F/adoOnWuYT+gFUHtyRV7+ts+iIDXYfgkyiqm6ijL4g==", + "version": "1.39.6", + "resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.39.6.tgz", + "integrity": "sha512-u9wQfa/7gHiW6Q1SxltLS+EoK8CQwuG7fdcMMrn4FdNgW6rPYfEqy2yNSDlJcbaEZANDQ58cjYLzbjXYQxlQvA==", "dev": true }, "node_modules/debug": { @@ -4771,12 +4771,12 @@ } }, "node_modules/heap-typed": { - "version": "1.39.5", - "resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.39.5.tgz", - "integrity": "sha512-nZZLUskWW4t2i3en95o1iNwQ0duN49TPMfsPPsnpo7SJp3D4MiLiNQhfz16grf8pl/tvMOYGKCKhFdb2eqBgmQ==", + "version": "1.39.6", + "resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.39.6.tgz", + "integrity": "sha512-Qi7NbDUnlCS5JSGfemizcJwtFMfGXsSUUZt+h9COTLlGvU4oTQ9t45G60cp4jEywSzXDNUBA/lLkjN8R2uvXJw==", "dev": true, "dependencies": { - "data-structure-typed": "^1.39.5" + "data-structure-typed": "^1.39.6" } }, "node_modules/html-escaper": { diff --git a/package.json b/package.json index c5e40dd..11aed58 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "data-structure-typed", - "version": "1.39.6", + "version": "1.40.0", "description": "Data Structures of Javascript & TypeScript. Binary Tree, BST, Graph, Heap, Priority Queue, Linked List, Queue, Deque, Stack, AVL Tree, Tree Multiset, Trie, Directed Graph, Undirected Graph, Singly Linked List, Doubly Linked List, Max Heap, Max Priority Queue, Min Heap, Min Priority Queue.", "main": "dist/cjs/index.js", "module": "dist/mjs/index.js", @@ -61,17 +61,17 @@ "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", "auto-changelog": "^2.4.0", - "avl-tree-typed": "^1.39.5", + "avl-tree-typed": "^1.39.6", "benchmark": "^2.1.4", - "binary-tree-typed": "^1.39.5", - "bst-typed": "^1.39.5", + "binary-tree-typed": "^1.39.6", + "bst-typed": "^1.39.6", "dependency-cruiser": "^14.1.0", "eslint": "^8.50.0", "eslint-config-prettier": "^9.0.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.28.1", - "heap-typed": "^1.39.5", + "heap-typed": "^1.39.6", "istanbul-badges-readme": "^1.8.5", "jest": "^29.7.0", "prettier": "^3.0.3", diff --git a/test/integration/avl-tree.test.ts b/test/integration/avl-tree.test.ts index b6832db..7bc298d 100644 --- a/test/integration/avl-tree.test.ts +++ b/test/integration/avl-tree.test.ts @@ -31,7 +31,7 @@ describe('AVL Tree Test', () => { expect(lesserSum).toBe(45); // node15 has type problem. After the uniform design, the generics of containers (DirectedGraph, BST) are based on the type of value. However, this design has a drawback: when I attempt to inherit from the Vertex or BSTNode classes, the types of the results obtained by all methods are those of the parent class. - expect(node15?.val).toBe(15); + expect(node15?.value).toBe(15); const dfs = tree.dfs(node => node, 'in'); expect(dfs[0].key).toBe(1); diff --git a/test/integration/bst.test.ts b/test/integration/bst.test.ts index 4a97a89..36ebe03 100644 --- a/test/integration/bst.test.ts +++ b/test/integration/bst.test.ts @@ -23,7 +23,7 @@ describe('Individual package BST operations test', () => { const nodeId10 = bst.get(10); expect(nodeId10?.key).toBe(10); - const nodeVal9 = bst.get(9, node => node.val); + const nodeVal9 = bst.get(9, node => node.value); expect(nodeVal9?.key).toBe(9); const leftMost = bst.getLeftMost(); @@ -230,7 +230,7 @@ describe('Individual package BST operations test', () => { expect(leftMost?.key).toBe(1); const node15 = objBST.get(15); - expect(node15?.val).toEqual({key: 15, keyA: 15}); + expect(node15?.value).toEqual({key: 15, keyA: 15}); const minNodeBySpecificNode = node15 && objBST.getLeftMost(node15); expect(minNodeBySpecificNode?.key).toBe(12);