diff --git a/.idea/modules.xml b/.idea/modules.xml index eaebbb7..be7ecd0 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -2,7 +2,7 @@ - + \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 50cf0c9..4116668 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,25 +1,32 @@ { "name": "data-structure-typed", - "version": "0.8.6", - "lockfileVersion": 2, + "version": "0.9.16", + "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "data-structure-typed", - "version": "0.8.6", + "version": "0.9.16", "license": "ISC", "dependencies": { "lodash": "^4.17.21" }, "devDependencies": { - "@types/lodash": "^4.14.178", + "@types/lodash": "^4.14.197", + "@types/node": "^20.4.9", "typescript": "^4.6.2" } }, "node_modules/@types/lodash": { - "version": "4.14.195", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.195.tgz", - "integrity": "sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg==", + "version": "4.14.197", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.197.tgz", + "integrity": "sha512-BMVOiWs0uNxHVlHBgzTIqJYmj+PgCo4euloGF+5m4okL3rEYzM2EEv78mw8zWSMM57dM7kVIgJ2QDvwHSoCI5g==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.4.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.9.tgz", + "integrity": "sha512-8e2HYcg7ohnTUbHk8focoklEQYvemQmu9M/f43DZVx43kHn0tE3BY/6gSDxS7k0SprtS0NHvj+L80cGLnoOUcQ==", "dev": true }, "node_modules/lodash": { @@ -40,24 +47,5 @@ "node": ">=4.2.0" } } - }, - "dependencies": { - "@types/lodash": { - "version": "4.14.195", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.195.tgz", - "integrity": "sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg==", - "dev": true - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "dev": true - } } } diff --git a/package.json b/package.json index 0a5a2dc..8fc6e62 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,10 @@ { "name": "data-structure-typed", - "version": "0.8.18", + "version": "0.9.16", "description": "Hash (CoordinateSet, CoordinateMap) Heap (MaxHeap, MinHeap) Binary Tree (AVL Tree, Binary Indexed Tree, Binary Search Tree, Segment Tree, Tree Multiset) Graph (Directed Graph, Undirected Graph) Linked List (Singly Linked List, Doubly Linked List) Matrix Priority Queue (Max Priority Queue, Min Priority Queue) Queue (Queue, Dequeue) Stack Trie", "main": "dist/index.js", "scripts": { + "build": "rm -rf dist && npx tsc", "test": "echo \"Error: no test specified\" && exit 1" }, "repository": { @@ -11,51 +12,27 @@ "url": "git+https://github.com/zrwusa/data-structure-typed.git" }, "keywords": [ + "Binary Tree", + "AVL Tree", + "Binary Search Tree (BST)", + "Tree Multiset", + "Segment Tree", + "Binary Indexed Tree", + "Graph", + "Directed Graph", + "Undirected Graph", + "Singly Linked List", "Hash", "CoordinateSet", "CoordinateMap", "Heap", - "MaxHeap", - "MinHeap", - "Binary", - "Tree", - "AVL", - "Tree", - "Binary", - "Indexed", - "Tree", - "Binary", - "Search", - "Tree", - "Segment", - "Tree", - "Tree", - "Multiset", - "Graph", - "Directed", - "Graph", - "Undirected", - "Graph", - "Linked", - "List", - "Singly", - "Linked", - "List", - "Doubly", - "Linked", - "List", - "Matrix", - "Priority", + "Doubly Linked List", + "Priority Queue", + "Max Priority Queue", + "Min Priority Queue", "Queue", - "Max", - "Priority", - "Queue", - "Min", - "Priority", - "Queue", - "Queue", - "Queue", - "Dequeue", + "ObjectDeque", + "ArrayDeque", "Stack", "Trie" ], @@ -67,7 +44,8 @@ "homepage": "https://github.com/zrwusa/data-structure-typed#readme", "types": "dist/index.d.ts", "devDependencies": { - "@types/lodash": "^4.14.178", + "@types/lodash": "^4.14.197", + "@types/node": "^20.4.9", "typescript": "^4.6.2" }, "dependencies": { diff --git a/src/assets/complexities-diff.jpg b/src/assets/complexities-diff.jpg deleted file mode 100644 index 53248a9..0000000 Binary files a/src/assets/complexities-diff.jpg and /dev/null differ diff --git a/src/assets/data-structure-complexities.jpg b/src/assets/data-structure-complexities.jpg deleted file mode 100644 index 6f3f284..0000000 Binary files a/src/assets/data-structure-complexities.jpg and /dev/null differ diff --git a/src/data-structures/binary-tree/avl-tree.ts b/src/data-structures/binary-tree/avl-tree.ts index 3de4505..4089aea 100644 --- a/src/data-structures/binary-tree/avl-tree.ts +++ b/src/data-structures/binary-tree/avl-tree.ts @@ -1,10 +1,5 @@ import {BST, BSTNode} from './bst'; -import {BinaryTreeNodeId} from './binary-tree'; - -export interface AVLTreeDeleted { - deleted: AVLTreeNode | null; - needBalanced: AVLTreeNode | null; -} +import type {AVLTreeDeleted, BinaryTreeNodeId} from '../types'; export class AVLTreeNode extends BSTNode { override clone(): AVLTreeNode { diff --git a/src/data-structures/binary-tree/binary-indexed-tree.ts b/src/data-structures/binary-tree/binary-indexed-tree.ts index 01d85e7..51fe68c 100644 --- a/src/data-structures/binary-tree/binary-indexed-tree.ts +++ b/src/data-structures/binary-tree/binary-indexed-tree.ts @@ -5,6 +5,10 @@ export class BinaryIndexedTree { this._sumTree = new Array(n + 1).fill(0); } + static lowBit(x: number) { + return x & (-x); + } + update(i: number, delta: number) { while (i < this._sumTree.length) { this._sumTree[i] += delta; @@ -26,8 +30,4 @@ export class BinaryIndexedTree { throw 'Index out of bounds'; return this.getPrefixSum(end) - this.getPrefixSum(start); } - - static lowBit(x: number) { - return x & (-x); - } } diff --git a/src/data-structures/binary-tree/binary-tree.ts b/src/data-structures/binary-tree/binary-tree.ts index 4d53a2b..f99d9ec 100644 --- a/src/data-structures/binary-tree/binary-tree.ts +++ b/src/data-structures/binary-tree/binary-tree.ts @@ -1,25 +1,27 @@ -import {ThunkOrValue, trampoline} from '../trampoline'; - -export type BinaryTreeNodePropertyName = 'id' | 'val' | 'count'; -export type NodeOrPropertyName = 'node' | BinaryTreeNodePropertyName; -export type DFSOrderPattern = 'in' | 'pre' | 'post'; -export type BinaryTreeNodeId = number; -export type BinaryTreeDeleted = { deleted: BinaryTreeNode | null | undefined, needBalanced: BinaryTreeNode | null }; -export type ResultByProperty = T | BinaryTreeNode | number | BinaryTreeNodeId; -export type ResultsByProperty = ResultByProperty[]; - -export interface BinaryTreeNodeObj { - id: BinaryTreeNodeId; - val: T; - count?: number; -} +import {trampoline} from '../trampoline'; +import type { + BinaryTreeDeleted, + BinaryTreeNodeId, + BinaryTreeNodePropertyName, + DFSOrderPattern, + NodeOrPropertyName, + ResultByProperty, + ResultsByProperty +} from '../types'; export enum FamilyPosition {root, left, right} export enum LoopType { iterative = 1, recursive = 2} export class BinaryTreeNode { + constructor(id: BinaryTreeNodeId, val: T, count?: number) { + this._id = id; + this._val = val; + this._count = count ?? 1; + } + protected _id: BinaryTreeNodeId; + get id(): BinaryTreeNodeId { return this._id; } @@ -29,6 +31,7 @@ export class BinaryTreeNode { } protected _val: T; + get val(): T { return this._val; } @@ -38,6 +41,7 @@ export class BinaryTreeNode { } protected _left?: BinaryTreeNode | null; + get left(): BinaryTreeNode | null | undefined { return this._left; } @@ -51,6 +55,7 @@ export class BinaryTreeNode { } protected _right?: BinaryTreeNode | null; + get right(): BinaryTreeNode | null | undefined { return this._right; } @@ -63,7 +68,8 @@ export class BinaryTreeNode { this._right = v; } - protected _parent: BinaryTreeNode | null | undefined = undefined; + protected _parent: BinaryTreeNode | null | undefined; + get parent(): BinaryTreeNode | null | undefined { return this._parent; } @@ -73,6 +79,7 @@ export class BinaryTreeNode { } protected _familyPosition: FamilyPosition = FamilyPosition.root; + get familyPosition(): FamilyPosition { return this._familyPosition; } @@ -82,6 +89,7 @@ export class BinaryTreeNode { } protected _count = 1; + get count(): number { return this._count; } @@ -100,12 +108,6 @@ export class BinaryTreeNode { this._height = v; } - constructor(id: BinaryTreeNodeId, val: T, count?: number) { - this._id = id; - this._val = val; - this._count = count ?? 1; - } - swapLocation(swapNode: BinaryTreeNode): BinaryTreeNode { const {val, count, height} = swapNode; const tempNode = new BinaryTreeNode(swapNode.id, val); @@ -131,55 +133,15 @@ export class BinaryTreeNode { } export class BinaryTree { - protected _root: BinaryTreeNode | null = null; - public get root(): BinaryTreeNode | null { - return this._root; - } - - protected set root(v: BinaryTreeNode | null) { - if (v) { - v.parent = null; - v.familyPosition = FamilyPosition.root; - } - this._root = v; - } - - protected _size = 0; - get size(): number { - return this._size; - } - - protected set size(v: number) { - this._size = v; - } - - protected _count = 0; - get count(): number { - return this._count; - } - - protected set count(v: number) { - this._count = v; - } - - private readonly _autoIncrementId: boolean = false; - private _maxId: number = -1; - private readonly _isDuplicatedVal: boolean = false; - protected _loopType: LoopType = LoopType.iterative; protected _visitedId: BinaryTreeNodeId[] = []; protected _visitedVal: Array = []; protected _visitedNode: BinaryTreeNode[] = []; protected _visitedCount: number[] = []; protected _visitedLeftSum: number[] = []; - - protected _resetResults() { - this._visitedId = []; - this._visitedVal = []; - this._visitedNode = []; - this._visitedCount = []; - this._visitedLeftSum = []; - } + private readonly _autoIncrementId: boolean = false; + private _maxId: number = -1; + private readonly _isDuplicatedVal: boolean = false; constructor(options?: { loopType?: LoopType, @@ -198,6 +160,44 @@ export class BinaryTree { } } + protected _root: BinaryTreeNode | null = null; + + protected get root(): BinaryTreeNode | null { + return this._root; + } + + protected set root(v: BinaryTreeNode | null) { + if (v) { + v.parent = null; + v.familyPosition = FamilyPosition.root; + } + this._root = v; + } + + protected _size = 0; + + protected get size(): number { + return this._size; + } + + protected set size(v: number) { + this._size = v; + } + + protected _count = 0; + + protected get count(): number { + return this._count; + } + + protected set count(v: number) { + this._count = v; + } + + getCount(): number { + return this._count; + } + createNode(id: BinaryTreeNodeId, val: T | null, count?: number): BinaryTreeNode | null { return val !== null ? new BinaryTreeNode(id, val, count) : null; } @@ -393,8 +393,8 @@ export class BinaryTree { return _getMaxHeight(beginRoot); } else { const stack: BinaryTreeNode[] = []; - let node: BinaryTreeNode | null | undefined = beginRoot, last: BinaryTreeNode | null = null, - depths: Map, number> = new Map(); + let node: BinaryTreeNode | null | undefined = beginRoot, last: BinaryTreeNode | null = null; + const depths: Map, number> = new Map(); while (stack.length > 0 || node) { if (node) { @@ -405,8 +405,8 @@ export class BinaryTree { if (!node.right || last === node.right) { node = stack.pop(); if (node) { - let leftHeight = node.left ? depths.get(node.left) ?? -1 : -1; - let rightHeight = node.right ? depths.get(node.right) ?? -1 : -1; + const leftHeight = node.left ? depths.get(node.left) ?? -1 : -1; + const rightHeight = node.right ? depths.get(node.right) ?? -1 : -1; depths.set(node, 1 + Math.max(leftHeight, rightHeight)); last = node; node = null; @@ -435,8 +435,8 @@ export class BinaryTree { return _getMinHeight(beginRoot); } else { const stack: BinaryTreeNode[] = []; - let node: BinaryTreeNode | null | undefined = beginRoot, last: BinaryTreeNode | null = null, - depths: Map, number> = new Map(); + let node: BinaryTreeNode | null | undefined = beginRoot, last: BinaryTreeNode | null = null; + const depths: Map, number> = new Map(); while (stack.length > 0 || node) { if (node) { @@ -447,8 +447,8 @@ export class BinaryTree { if (!node.right || last === node.right) { node = stack.pop(); if (node) { - let leftMinHeight = node.left ? depths.get(node.left) ?? -1 : -1; - let rightMinHeight = node.right ? depths.get(node.right) ?? -1 : -1; + const leftMinHeight = node.left ? depths.get(node.left) ?? -1 : -1; + const rightMinHeight = node.right ? depths.get(node.right) ?? -1 : -1; depths.set(node, 1 + Math.min(leftMinHeight, rightMinHeight)); last = node; node = null; @@ -514,76 +514,14 @@ export class BinaryTree { return result; } - protected _pushByPropertyNameStopOrNot(cur: BinaryTreeNode, result: (BinaryTreeNode | null | undefined)[], nodeProperty: BinaryTreeNodeId | T, propertyName ?: BinaryTreeNodePropertyName, onlyOne ?: boolean) { - switch (propertyName) { - case 'id': - if (cur.id === nodeProperty) { - result.push(cur); - return !!onlyOne; - } - break; - case 'count': - if (cur.count === nodeProperty) { - result.push(cur); - return !!onlyOne; - } - break; - case 'val': - if (cur.val === nodeProperty) { - result.push(cur); - return !!onlyOne; - } - break; - default: - if (cur.id === nodeProperty) { - result.push(cur); - return !!onlyOne; - } - break; - } - } - - protected _accumulatedByPropertyName(node: BinaryTreeNode, nodeOrPropertyName ?: NodeOrPropertyName) { - nodeOrPropertyName = nodeOrPropertyName ?? 'id'; - - switch (nodeOrPropertyName) { - case 'id': - this._visitedId.push(node.id); - break; - case 'val': - this._visitedVal.push(node.val); - break; - case 'node': - this._visitedNode.push(node); - break; - case 'count': - this._visitedCount.push(node.count); - break; - default: - this._visitedId.push(node.id); - break; - } - } - - protected _getResultByPropertyName(nodeOrPropertyName ?: NodeOrPropertyName): ResultsByProperty { - nodeOrPropertyName = nodeOrPropertyName ?? 'id'; - - switch (nodeOrPropertyName) { - case 'id': - return this._visitedId; - case 'val': - return this._visitedVal; - case 'node': - return this._visitedNode; - case 'count': - return this._visitedCount; - default: - return this._visitedId; - } + getRoot(): BinaryTreeNode | null { + return this.root; } getLeftMost(): BinaryTreeNode | null; + getLeftMost(node: BinaryTreeNode): BinaryTreeNode; + getLeftMost(node?: BinaryTreeNode | null): BinaryTreeNode | null { node = node ?? this.root; if (!node) return node; @@ -598,7 +536,7 @@ export class BinaryTree { return _traverse(node); } else { // Indirect implementation of iteration using tail recursion optimization - const _traverse = trampoline((cur: BinaryTreeNode): ThunkOrValue | null> => { + const _traverse = trampoline((cur: BinaryTreeNode) => { if (!cur.left) return cur; return _traverse.cont(cur.left); }); @@ -608,7 +546,9 @@ export class BinaryTree { } getRightMost(): BinaryTreeNode | null; + getRightMost(node: BinaryTreeNode): BinaryTreeNode; + getRightMost(node?: BinaryTreeNode | null): BinaryTreeNode | null { node = node ?? this.root; if (!node) return node; @@ -622,7 +562,7 @@ export class BinaryTree { return _traverse(node); } else { // Indirect implementation of iteration using tail recursion optimization - const _traverse = trampoline((cur: BinaryTreeNode): ThunkOrValue | null> => { + const _traverse = trampoline((cur: BinaryTreeNode) => { if (!cur.right) return cur; return _traverse.cont(cur.right); }); @@ -653,7 +593,7 @@ export class BinaryTree { curr = curr.left; } curr = stack.pop()!; - if (prev >= curr.id) return false; + if (!(curr) || prev >= curr.id) return false; prev = curr.id; curr = curr.right; } @@ -779,10 +719,15 @@ export class BinaryTree { } BFS(): BinaryTreeNodeId[]; + BFS(nodeOrPropertyName: 'id'): BinaryTreeNodeId[]; + BFS(nodeOrPropertyName: 'val'): T[]; + BFS(nodeOrPropertyName: 'node'): BinaryTreeNode[]; + BFS(nodeOrPropertyName: 'count'): number[]; + BFS(nodeOrPropertyName ?: NodeOrPropertyName): ResultsByProperty { nodeOrPropertyName = nodeOrPropertyName ?? 'id'; this._resetResults(); @@ -801,10 +746,15 @@ export class BinaryTree { } DFS(): BinaryTreeNodeId[]; + DFS(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'id'): BinaryTreeNodeId[]; + DFS(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'val'): T[]; + DFS(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'node'): BinaryTreeNode[]; + DFS(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'count'): number[]; + DFS(pattern ?: 'in' | 'pre' | 'post', nodeOrPropertyName ?: NodeOrPropertyName): ResultsByProperty { pattern = pattern ?? 'in'; nodeOrPropertyName = nodeOrPropertyName ?? 'id'; @@ -834,9 +784,13 @@ export class BinaryTree { } DFSIterative(): BinaryTreeNodeId[]; + DFSIterative(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'id'): BinaryTreeNodeId[]; + DFSIterative(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'val'): T[]; + DFSIterative(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'node'): BinaryTreeNode[]; + DFSIterative(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'count'): number[]; /** @@ -889,10 +843,15 @@ export class BinaryTree { } levelIterative(node: BinaryTreeNode | null): BinaryTreeNodeId[]; + levelIterative(node: BinaryTreeNode | null, nodeOrPropertyName?: 'id'): BinaryTreeNodeId[]; + levelIterative(node: BinaryTreeNode | null, nodeOrPropertyName?: 'val'): T[]; + levelIterative(node: BinaryTreeNode | null, nodeOrPropertyName?: 'node'): BinaryTreeNode[]; + levelIterative(node: BinaryTreeNode | null, nodeOrPropertyName?: 'count'): number[]; + levelIterative(node: BinaryTreeNode | null, nodeOrPropertyName ?: NodeOrPropertyName): ResultsByProperty { nodeOrPropertyName = nodeOrPropertyName || 'id'; node = node || this.root; @@ -918,10 +877,15 @@ export class BinaryTree { } listLevels(node: BinaryTreeNode | null): BinaryTreeNodeId[][]; + listLevels(node: BinaryTreeNode | null, nodeOrPropertyName?: 'id'): BinaryTreeNodeId[][]; + listLevels(node: BinaryTreeNode | null, nodeOrPropertyName?: 'val'): T[][]; + listLevels(node: BinaryTreeNode | null, nodeOrPropertyName?: 'node'): BinaryTreeNode[][]; + listLevels(node: BinaryTreeNode | null, nodeOrPropertyName?: 'count'): number[][]; + listLevels(node: BinaryTreeNode | null, nodeOrPropertyName?: NodeOrPropertyName): ResultByProperty[][] { nodeOrPropertyName = nodeOrPropertyName || 'id'; node = node || this.root; @@ -977,9 +941,11 @@ export class BinaryTree { getPredecessor(node: BinaryTreeNode): BinaryTreeNode { if (node.left) { - let predecessor: BinaryTreeNode | null = node.left; - while (predecessor.right && predecessor.right !== node) { - predecessor = predecessor.right; + let predecessor: BinaryTreeNode | null | undefined = node.left; + while (!(predecessor) || predecessor.right && predecessor.right !== node) { + if (predecessor) { + predecessor = predecessor.right; + } } return predecessor; } else { @@ -988,10 +954,15 @@ export class BinaryTree { } morris(): BinaryTreeNodeId[]; + morris(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'id'): BinaryTreeNodeId[]; + morris(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'val'): T[]; + morris(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'node'): BinaryTreeNode[]; + morris(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'count'): number[]; + /** * The time complexity of Morris traversal is O(n), it's may slower than others * The space complexity Morris traversal is O(1) because no using stack @@ -1084,5 +1055,81 @@ export class BinaryTree { return this._getResultByPropertyName(nodeOrPropertyName); } + protected _resetResults() { + this._visitedId = []; + this._visitedVal = []; + this._visitedNode = []; + this._visitedCount = []; + this._visitedLeftSum = []; + } + + protected _pushByPropertyNameStopOrNot(cur: BinaryTreeNode, result: (BinaryTreeNode | null | undefined)[], nodeProperty: BinaryTreeNodeId | T, propertyName ?: BinaryTreeNodePropertyName, onlyOne ?: boolean) { + switch (propertyName) { + case 'id': + if (cur.id === nodeProperty) { + result.push(cur); + return !!onlyOne; + } + break; + case 'count': + if (cur.count === nodeProperty) { + result.push(cur); + return !!onlyOne; + } + break; + case 'val': + if (cur.val === nodeProperty) { + result.push(cur); + return !!onlyOne; + } + break; + default: + if (cur.id === nodeProperty) { + result.push(cur); + return !!onlyOne; + } + break; + } + } + + protected _accumulatedByPropertyName(node: BinaryTreeNode, nodeOrPropertyName ?: NodeOrPropertyName) { + nodeOrPropertyName = nodeOrPropertyName ?? 'id'; + + switch (nodeOrPropertyName) { + case 'id': + this._visitedId.push(node.id); + break; + case 'val': + this._visitedVal.push(node.val); + break; + case 'node': + this._visitedNode.push(node); + break; + case 'count': + this._visitedCount.push(node.count); + break; + default: + this._visitedId.push(node.id); + break; + } + } + + protected _getResultByPropertyName(nodeOrPropertyName ?: NodeOrPropertyName): ResultsByProperty { + nodeOrPropertyName = nodeOrPropertyName ?? 'id'; + + switch (nodeOrPropertyName) { + case 'id': + return this._visitedId; + case 'val': + return this._visitedVal; + case 'node': + return this._visitedNode; + case 'count': + return this._visitedCount; + default: + return this._visitedId; + } + } + // --- end additional methods --- } \ No newline at end of file diff --git a/src/data-structures/binary-tree/bst.ts b/src/data-structures/binary-tree/bst.ts index 2393f23..1b136d1 100644 --- a/src/data-structures/binary-tree/bst.ts +++ b/src/data-structures/binary-tree/bst.ts @@ -1,14 +1,5 @@ -import { - BinaryTree, - BinaryTreeNode, - BinaryTreeNodeId, - BinaryTreeNodePropertyName, - FamilyPosition, - LoopType, -} from './binary-tree'; - -export type BSTComparator = (a: BinaryTreeNodeId, b: BinaryTreeNodeId) => number; -export type BSTDeletedResult = { deleted: BSTNode | null, needBalanced: BSTNode | null }; +import type {BinaryTreeNodeId, BinaryTreeNodePropertyName, BSTComparator, BSTDeletedResult} from '../types'; +import {BinaryTree, BinaryTreeNode, FamilyPosition, LoopType,} from './binary-tree'; export enum CP {lt = -1, eq = 0, gt = 1} @@ -19,15 +10,6 @@ export class BSTNode extends BinaryTreeNode { } export class BST extends BinaryTree { - protected _comparator: BSTComparator = (a, b) => a - b; - - protected _compare(a: BinaryTreeNodeId, b: BinaryTreeNodeId): CP { - const compared = this._comparator(a, b); - if (compared > 0) return CP.gt; - else if (compared < 0) return CP.lt; - else return CP.eq; - } - constructor(options?: { comparator?: BSTComparator, loopType?: LoopType @@ -373,8 +355,8 @@ export class BST extends BinaryTree { _height(this.root); } else { const stack: BSTNode[] = []; - let node: BSTNode | null | undefined = this.root, last: BSTNode | null = null, - depths: Map, number> = new Map(); + let node: BSTNode | null | undefined = this.root, last: BSTNode | null = null; + const depths: Map, number> = new Map(); while (stack.length > 0 || node) { if (node) { @@ -385,8 +367,8 @@ export class BST extends BinaryTree { if (!node.right || last === node.right) { node = stack.pop(); if (node) { - let left = node.left ? depths.get(node.left) ?? -1 : -1; - let right = node.right ? depths.get(node.right) ?? -1 : -1; + const left = node.left ? depths.get(node.left) ?? -1 : -1; + const right = node.right ? depths.get(node.right) ?? -1 : -1; if (Math.abs(left - right) > 1) return false; depths.set(node, 1 + Math.max(left, right)); last = node; @@ -400,5 +382,14 @@ export class BST extends BinaryTree { return balanced; } + protected _comparator: BSTComparator = (a, b) => a - b; + + protected _compare(a: BinaryTreeNodeId, b: BinaryTreeNodeId): CP { + const compared = this._comparator(a, b); + if (compared > 0) return CP.gt; + else if (compared < 0) return CP.lt; + else return CP.eq; + } + // --- end additional functions } \ No newline at end of file diff --git a/src/data-structures/binary-tree/diagrams/avl-tree-inserting.gif b/src/data-structures/binary-tree/diagrams/avl-tree-inserting.gif new file mode 100644 index 0000000..46a3d48 Binary files /dev/null and b/src/data-structures/binary-tree/diagrams/avl-tree-inserting.gif differ diff --git a/src/data-structures/binary-tree/diagrams/bst-rotation.gif b/src/data-structures/binary-tree/diagrams/bst-rotation.gif new file mode 100644 index 0000000..a314ba8 Binary files /dev/null and b/src/data-structures/binary-tree/diagrams/bst-rotation.gif differ diff --git a/src/data-structures/binary-tree/diagrams/segment-tree.png b/src/data-structures/binary-tree/diagrams/segment-tree.png new file mode 100644 index 0000000..c02cc27 Binary files /dev/null and b/src/data-structures/binary-tree/diagrams/segment-tree.png differ diff --git a/src/data-structures/binary-tree/segment-tree.ts b/src/data-structures/binary-tree/segment-tree.ts index c6139d2..43bc89f 100644 --- a/src/data-structures/binary-tree/segment-tree.ts +++ b/src/data-structures/binary-tree/segment-tree.ts @@ -1,7 +1,15 @@ -export type SegmentTreeNodeVal = number; +import type {SegmentTreeNodeVal} from '../types'; export class SegmentTreeNode { + constructor(start: number, end: number, sum: number, val?: SegmentTreeNodeVal | null) { + this._start = start; + this._end = end; + this._sum = sum; + this._val = val || null; + } + protected _start = 0; + get start(): number { return this._start; } @@ -11,6 +19,7 @@ export class SegmentTreeNode { } protected _end = 0; + get end(): number { return this._end; } @@ -20,6 +29,7 @@ export class SegmentTreeNode { } protected _val: SegmentTreeNodeVal | null = null; + get val(): SegmentTreeNodeVal | null { return this._val; } @@ -29,6 +39,7 @@ export class SegmentTreeNode { } protected _sum = 0; + get sum(): number { return this._sum; } @@ -38,6 +49,7 @@ export class SegmentTreeNode { } protected _left: SegmentTreeNode | null = null; + get left(): SegmentTreeNode | null { return this._left; } @@ -47,6 +59,7 @@ export class SegmentTreeNode { } protected _right: SegmentTreeNode | null = null; + get right(): SegmentTreeNode | null { return this._right; } @@ -54,23 +67,12 @@ export class SegmentTreeNode { set right(v: SegmentTreeNode | null) { this._right = v; } - - constructor(start: number, end: number, sum: number, val?: SegmentTreeNodeVal | null) { - this._start = start; - this._end = end; - this._sum = sum; - this._val = val || null; - } } export class SegmentTree { protected _values: number[] = []; protected _start = 0; protected _end: number; - protected _root: SegmentTreeNode | null; - get root(): SegmentTreeNode | null { - return this._root; - } constructor(values: number[], start?: number, end?: number) { start = start || 0; @@ -81,6 +83,12 @@ export class SegmentTree { this._root = this.build(start, end); } + protected _root: SegmentTreeNode | null; + + get root(): SegmentTreeNode | null { + return this._root; + } + build(start: number, end: number): SegmentTreeNode { if (start === end) { return new SegmentTreeNode(start, end, this._values[start]); diff --git a/src/data-structures/binary-tree/tree-multiset.ts b/src/data-structures/binary-tree/tree-multiset.ts index d615a02..6e5449d 100644 --- a/src/data-structures/binary-tree/tree-multiset.ts +++ b/src/data-structures/binary-tree/tree-multiset.ts @@ -1,8 +1,5 @@ import {BST, BSTNode} from './bst'; -import {BinaryTreeNodeId} from './binary-tree'; - -export type TreeMultiSetDeletedResult = { deleted: BSTNode | null, needBalanced: BSTNode | null }; - +import type {BinaryTreeNodeId, TreeMultiSetDeletedResult} from '../types'; export class TreeMultiSet extends BST { override createNode(id: BinaryTreeNodeId, val: T, count?: number): BSTNode { diff --git a/src/data-structures/diagrams/README.md b/src/data-structures/diagrams/README.md new file mode 100644 index 0000000..ae3e799 --- /dev/null +++ b/src/data-structures/diagrams/README.md @@ -0,0 +1,5 @@ +// 操作 常见名称 Ada Java JavaScript C++ Python Perl PHP Ruby // 尾部插入 inject, snoc Append offerLast push push_back append push +array_push push // 头部插入 push, cons Prepend offerFirst unshift push_front appendleft unshift array_unshift unshift // +尾部删除 eject Delete_Last pollLast pop pop_back pop pop array_pop pop // 头部删除 pop Delete_First pollFirst shift pop_front +popleft shift array_shift shift // 查看尾部 Last_Element peekLast [length - 1] back [-1] $array[-1] end +last // 查看头部 First_Element peekFirst [0] front [0] $array[0] reset first diff --git a/src/data-structures/graph/abstract-graph.ts b/src/data-structures/graph/abstract-graph.ts index 217aff4..7e953bf 100644 --- a/src/data-structures/graph/abstract-graph.ts +++ b/src/data-structures/graph/abstract-graph.ts @@ -1,60 +1,14 @@ import {arrayRemove, uuidV4} from '../../utils'; import {PriorityQueue} from '../priority-queue'; - -export type VertexId = string | number; -export type DijkstraResult = - { distMap: Map, preMap: Map, seen: Set, paths: V[][], minDist: number, minPath: V[] } - | null; - -export interface I_Graph { - - containsVertex(vertexOrId: V | VertexId): boolean; - - getVertex(vertexOrId: VertexId | V): V | null; - - getVertexId(vertexOrId: V | VertexId): VertexId; - - vertexSet(): Map; - - addVertex(v: V): boolean; - - removeVertex(vertexOrId: V | VertexId): boolean; - - removeAllVertices(vertices: V[] | VertexId[]): boolean; - - degreeOf(vertexOrId: V | VertexId): number; - - edgesOf(vertexOrId: V | VertexId): E[]; - - containsEdge(src: V | VertexId, dest: V | VertexId): boolean; - - // containsEdge(e: E): boolean; - - getEdge(srcOrId: V | VertexId, destOrId: V | VertexId): E | null; - - // getAllEdges(src: V, dest: V): E[]; - - edgeSet(): E[]; - - addEdge(edge: E): boolean; - - removeEdgeBetween(srcOrId: V | VertexId, destOrId: V | VertexId): E | null; - - removeEdge(edge: E): E | null; - - // removeAllEdges(v1: VertexId | V, v2: VertexId | V): (E | null)[]; - - // removeAllEdges(edges: E[] | [VertexId, VertexId]): boolean; - - setEdgeWeight(srcOrId: V | VertexId, destOrId: V | VertexId, weight: number): boolean; - - getMinPathBetween(v1: V | VertexId, v2: V | VertexId, isWeight?: boolean): V[] | null; - - getNeighbors(vertexOrId: V | VertexId): V[]; -} +import type {DijkstraResult, IGraph, VertexId} from '../types'; export class AbstractVertex { + constructor(id: VertexId) { + this._id = id; + } + private _id: VertexId; + public get id(): VertexId { return this._id; } @@ -62,15 +16,20 @@ export class AbstractVertex { public set id(v: VertexId) { this._id = v; } - - constructor(id: VertexId) { - this._id = id; - } } export abstract class AbstractEdge { + static DEFAULT_EDGE_WEIGHT = 1; + + protected constructor(weight?: number) { + if (weight === undefined) weight = AbstractEdge.DEFAULT_EDGE_WEIGHT; + this._weight = weight; + this._hashCode = uuidV4(); + } + private _weight: number; + get weight(): number { return this._weight; } @@ -88,18 +47,10 @@ export abstract class AbstractEdge { set hashCode(v: string) { this._hashCode = v; } - - protected constructor(weight?: number) { - if (weight === undefined) weight = AbstractEdge.DEFAULT_EDGE_WEIGHT; - this._weight = weight; - this._hashCode = uuidV4(); - } - - static DEFAULT_EDGE_WEIGHT = 1; } // Connected Component === Largest Connected Sub-Graph -export abstract class AbstractGraph implements I_Graph { +export abstract class AbstractGraph implements IGraph { protected _vertices: Map = new Map(); @@ -192,7 +143,7 @@ export abstract class AbstractGraph vertex === neighbor); + arrayRemove(path, (vertex: AbstractVertex) => vertex === neighbor); } } @@ -296,7 +247,7 @@ export abstract class AbstractGraph vertex === neighbor); + arrayRemove(path, (vertex: AbstractVertex) => vertex === neighbor); } } @@ -338,7 +289,8 @@ export abstract class AbstractGraph { for (const vertex of vertices) { - const path: V[] = [vertex[1]]; - let parent = preMap.get(vertex[1]); - while (parent) { - path.push(parent); - parent = preMap.get(parent); + const vertexOrId = vertex[1]; + + if (vertexOrId instanceof AbstractVertex) { + const path: V[] = [vertexOrId]; + let parent = preMap.get(vertexOrId); + while (parent) { + path.push(parent); + parent = preMap.get(parent); + } + const reversed = path.reverse(); + if (vertex[1] === minV) minPath = reversed; + paths.push(reversed); } - const reversed = path.reverse(); - if (vertex[1] === minV) minPath = reversed; - paths.push(reversed); } }; @@ -449,7 +405,8 @@ export abstract class AbstractGraph({comparator: (a, b) => a.id - b.id}); @@ -460,15 +417,19 @@ export abstract class AbstractGraph { for (const vertex of vertices) { - const path: V[] = [vertex[1]]; - let parent = preMap.get(vertex[1]); - while (parent) { - path.push(parent); - parent = preMap.get(parent); + const vertexOrId = vertex[1]; + if (vertexOrId instanceof AbstractVertex) { + const path: V[] = [vertexOrId]; + let parent = preMap.get(vertexOrId); + while (parent) { + path.push(parent); + parent = preMap.get(parent); + } + const reversed = path.reverse(); + if (vertex[1] === minV) minPath = reversed; + paths.push(reversed); } - const reversed = path.reverse(); - if (vertex[1] === minV) minPath = reversed; - paths.push(reversed); + } }; @@ -551,7 +512,7 @@ export abstract class AbstractGraph { - incomingEdgesOf(vertex: V): E[]; - - outgoingEdgesOf(vertex: V): E[]; - - inDegreeOf(vertexOrId: V | VertexId): number; - - outDegreeOf(vertexOrId: V | VertexId): number; - - getEdgeSrc(e: E): V | null; - - getEdgeDest(e: E): V | null; -} - -// 0 means unknown, 1 means visiting, 2 means visited; -export type TopologicalStatus = 0 | 1 | 2; - // Strongly connected, One direction connected, Weakly connected -export class DirectedGraph extends AbstractGraph implements I_DirectedGraph { +export class DirectedGraph extends AbstractGraph implements IDirectedGraph { protected _outEdgeMap: Map = new Map(); @@ -120,12 +104,12 @@ export class DirectedGraph ext const srcOutEdges = this._outEdgeMap.get(src); if (srcOutEdges) { - arrayRemove(srcOutEdges, edge => edge.dest === dest.id); + arrayRemove(srcOutEdges, (edge: DirectedEdge) => edge.dest === dest.id); } const destInEdges = this._inEdgeMap.get(dest); if (destInEdges) { - removed = arrayRemove(destInEdges, edge => edge.src === src.id)[0] || null; + removed = arrayRemove(destInEdges, (edge: DirectedEdge) => edge.src === src.id)[0] || null; } return removed; } @@ -137,12 +121,12 @@ export class DirectedGraph ext if (src && dest) { const srcOutEdges = this._outEdgeMap.get(src); if (srcOutEdges && srcOutEdges.length > 0) { - arrayRemove(srcOutEdges, edge => edge.src === src.id); + arrayRemove(srcOutEdges, (edge: DirectedEdge) => edge.src === src.id); } const destInEdges = this._inEdgeMap.get(dest); if (destInEdges && destInEdges.length > 0) { - removed = arrayRemove(destInEdges, edge => edge.dest === dest.id)[0]; + removed = arrayRemove(destInEdges, (edge: DirectedEdge) => edge.dest === dest.id)[0]; } } @@ -194,7 +178,7 @@ export class DirectedGraph ext return this.getVertex(e.dest); } - getDestinations(vertex: V | null): V[] { + getDestinations(vertex: V | VertexId | null): V[] { if (vertex === null) { return []; } @@ -215,7 +199,7 @@ export class DirectedGraph ext * when stored with adjacency list time: O(V+E) * when stored with adjacency matrix time: O(V^2) */ - topologicalSort(): V[] | null { + topologicalSort(): (V | VertexId)[] | null { // vector> g; // vector color; // int last; @@ -247,14 +231,14 @@ export class DirectedGraph ext // } // 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); } - const sorted: V[] = []; + const sorted: (V | VertexId)[] = []; let hasCycle = false; - const dfs = (cur: V) => { + const dfs = (cur: V | VertexId) => { statusMap.set(cur, 1); const children = this.getDestinations(cur); for (const child of children) { diff --git a/src/data-structures/graph/undirected-graph.ts b/src/data-structures/graph/undirected-graph.ts index 34d8b48..14e9928 100644 --- a/src/data-structures/graph/undirected-graph.ts +++ b/src/data-structures/graph/undirected-graph.ts @@ -1,5 +1,6 @@ import {arrayRemove} from '../../utils'; -import {AbstractEdge, AbstractGraph, AbstractVertex, VertexId} from './abstract-graph'; +import {AbstractEdge, AbstractGraph, AbstractVertex} from './abstract-graph'; +import type {VertexId} from '../types'; export class UndirectedVertex extends AbstractVertex { constructor(id: VertexId) { @@ -8,6 +9,11 @@ export class UndirectedVertex extends AbstractVertex { } export class UndirectedEdge extends AbstractEdge { + constructor(v1: VertexId, v2: VertexId, weight?: number) { + super(weight); + this._vertices = [v1, v2]; + } + private _vertices: [VertexId, VertexId]; public get vertices() { @@ -17,20 +23,15 @@ export class UndirectedEdge extends AbstractEdge { public set vertices(v: [VertexId, VertexId]) { this._vertices = v; } - - constructor(v1: VertexId, v2: VertexId, weight?: number) { - super(weight); - this._vertices = [v1, v2]; - } } export class UndirectedGraph extends AbstractGraph { + protected _edges: Map = new Map(); + constructor() { super(); } - protected _edges: Map = new Map(); - getEdge(v1: V | null | VertexId, v2: V | null | VertexId): E | null { let edges: E[] | undefined = []; @@ -74,11 +75,11 @@ export class UndirectedGraph(v1Edges, e => e.vertices.includes(vertex2.id))[0] || null; + removed = arrayRemove(v1Edges, (e: UndirectedEdge) => e.vertices.includes(vertex2.id))[0] || null; } const v2Edges = this._edges.get(vertex2); if (v2Edges) { - arrayRemove(v2Edges, e => e.vertices.includes(vertex1.id)); + arrayRemove(v2Edges, (e: UndirectedEdge) => e.vertices.includes(vertex1.id)); } return removed; } diff --git a/src/data-structures/hash/coordinate-map.ts b/src/data-structures/hash/coordinate-map.ts index ada0907..6d75d33 100644 --- a/src/data-structures/hash/coordinate-map.ts +++ b/src/data-structures/hash/coordinate-map.ts @@ -1,4 +1,4 @@ -export class CoordinateSet extends Map { +export class CoordinateMap extends Map { private readonly _joint: string = '_'; constructor(joint?: string) { diff --git a/src/data-structures/hash/index.ts b/src/data-structures/hash/index.ts index 5d31238..b4d9dd7 100644 --- a/src/data-structures/hash/index.ts +++ b/src/data-structures/hash/index.ts @@ -1 +1,6 @@ export * from './hash-table'; +export * from './coordinate-map'; +export * from './coordinate-set'; +export * from './pair'; +export * from './tree-map'; +export * from './tree-set'; diff --git a/src/data-structures/heap/heap.ts b/src/data-structures/heap/heap.ts index c60e08a..ddda170 100644 --- a/src/data-structures/heap/heap.ts +++ b/src/data-structures/heap/heap.ts @@ -1,17 +1,8 @@ import {PriorityQueue} from '../priority-queue'; - -export interface HeapOptions { - priority?: (element: T) => number; -} - -export interface HeapItem { - priority: number; - element: T | null; -} - +import type {HeapItem, HeapOptions} from '../types'; /** - * @copyright 2021 Pablo Rios + * @copyright 2021 Tyler Zeng * @license MIT * * @abstract diff --git a/src/data-structures/heap/max-heap.ts b/src/data-structures/heap/max-heap.ts index b207cdf..75f9941 100644 --- a/src/data-structures/heap/max-heap.ts +++ b/src/data-structures/heap/max-heap.ts @@ -1,10 +1,11 @@ /** - * @copyright 2020 Pablo Rios + * @copyright 2020 Tyler Zeng * @license MIT */ -import {Heap, HeapItem, HeapOptions} from './heap'; +import {Heap} from './heap'; import {PriorityQueue} from '../priority-queue'; +import type {HeapItem, HeapOptions} from '../types'; /** * @class MaxHeap diff --git a/src/data-structures/heap/min-heap.ts b/src/data-structures/heap/min-heap.ts index e639089..9e709b6 100644 --- a/src/data-structures/heap/min-heap.ts +++ b/src/data-structures/heap/min-heap.ts @@ -1,10 +1,11 @@ /** - * @copyright 2020 Pablo Rios + * @copyright 2020 Tyler Zeng * @license MIT */ -import {Heap, HeapItem, HeapOptions} from './heap'; +import {Heap} from './heap'; import {PriorityQueue} from '../priority-queue'; +import type {HeapItem, HeapOptions} from '../types'; /** * @class MinHeap diff --git a/src/data-structures/index.ts b/src/data-structures/index.ts index 5a154bd..188bd8e 100644 --- a/src/data-structures/index.ts +++ b/src/data-structures/index.ts @@ -8,4 +8,5 @@ export * from './heap'; export * from './priority-queue'; export * from './matrix'; export * from './trie'; +export * from './types'; diff --git a/src/data-structures/linked-list/doubly-linked-list.ts b/src/data-structures/linked-list/doubly-linked-list.ts index fe411a6..81bf360 100644 --- a/src/data-structures/linked-list/doubly-linked-list.ts +++ b/src/data-structures/linked-list/doubly-linked-list.ts @@ -1,10 +1,4 @@ -// 操作 常见名称 Ada Java JavaScript C++ Python Perl PHP Ruby -// 尾部插入 inject, snoc Append offerLast push push_back append push array_push push -// 头部插入 push, cons Prepend offerFirst unshift push_front appendleft unshift array_unshift unshift -// 尾部删除 eject Delete_Last pollLast pop pop_back pop pop array_pop pop -// 头部删除 pop Delete_First pollFirst shift pop_front popleft shift array_shift shift -// 查看尾部 Last_Element peekLast [length - 1] back [-1] $array[-1] end last -// 查看头部 First_Element peekFirst [0] front [0] $array[0] reset first +import type {DoublyLinkedListGetBy} from '../types'; export class DoublyLinkedListNode { val: T; @@ -18,8 +12,6 @@ export class DoublyLinkedListNode { } } -export type DoublyLinkedListGetBy = 'node' | 'val'; - export class DoublyLinkedList { private _first: DoublyLinkedListNode | null = null; private _last: DoublyLinkedListNode | null = null; diff --git a/src/data-structures/linked-list/singly-linked-list.ts b/src/data-structures/linked-list/singly-linked-list.ts index 29ea7de..54686b1 100644 --- a/src/data-structures/linked-list/singly-linked-list.ts +++ b/src/data-structures/linked-list/singly-linked-list.ts @@ -1,16 +1,4 @@ -/** Type used for filter and find methods, returning a boolean */ -type TTestFunction = ( - data: NodeData, - index: number, - list: SinglyLinkedList, -) => boolean; - -/** Type used for map and forEach methods, returning anything */ -type TMapFunction = ( - data: any, - index: number, - list: SinglyLinkedList, -) => any; +import type {TMapFunction, TTestFunction} from '../types'; /** * The class which represents one link or node in a linked list @@ -104,6 +92,23 @@ export class SinglyLinkedListNode { */ export class SinglyLinkedList { + /** The head of the list, the first node */ + public head: SinglyLinkedListNode | null; + /** The tail of the list, the last node */ + public tail: SinglyLinkedListNode | null; + /** Internal size reference */ + private size: number; + + constructor(...args: NodeData[]) { + this.head = null; + this.tail = null; + this.size = 0; + + for (let i = 0; i < arguments.length; i++) { + this.append(args[i]); + } + } + /** * The length of the list */ @@ -123,25 +128,6 @@ export class SinglyLinkedList { return new SinglyLinkedList(...iterable); } - /** The head of the list, the first node */ - public head: SinglyLinkedListNode | null; - - /** The tail of the list, the last node */ - public tail: SinglyLinkedListNode | null; - - /** Internal size reference */ - private size: number; - - constructor(...args: NodeData[]) { - this.head = null; - this.tail = null; - this.size = 0; - - for (let i = 0; i < arguments.length; i++) { - this.append(args[i]); - } - } - /** * Get the node val at a specified index, zero based * ```ts diff --git a/src/data-structures/matrix/matrix2d.ts b/src/data-structures/matrix/matrix2d.ts index 20e81c2..cd6e360 100644 --- a/src/data-structures/matrix/matrix2d.ts +++ b/src/data-structures/matrix/matrix2d.ts @@ -16,21 +16,10 @@ export class Matrix2D { } } - /** - * Return the matrix values - */ - public get m(): number[][] { - return this._matrix - } - public static get empty(): number[][] { return [[], [], []] } - public get toVector(): Vector2D { - return new Vector2D(this._matrix[0][0], this._matrix[1][0]) - } - /** * Initialize an identity matrix */ @@ -41,6 +30,17 @@ export class Matrix2D { [0, 0, 1]] } + /** + * Return the matrix values + */ + public get m(): number[][] { + return this._matrix + } + + public get toVector(): Vector2D { + return new Vector2D(this._matrix[0][0], this._matrix[1][0]) + } + public static add(matrix1: Matrix2D, matrix2: Matrix2D): Matrix2D { const result = Matrix2D.empty for (let i = 0; i < 3; i++) { diff --git a/src/data-structures/matrix/navigator.ts b/src/data-structures/matrix/navigator.ts index a80b5b6..3e27745 100644 --- a/src/data-structures/matrix/navigator.ts +++ b/src/data-structures/matrix/navigator.ts @@ -1,5 +1,4 @@ -type Direction = 'up' | 'right' | 'down' | 'left'; -type Turning = { [key in Direction]: Direction }; +import type {Direction, NavigatorParams, Turning} from '../types'; export class Character { direction: Direction; @@ -11,23 +10,12 @@ export class Character { } } -interface NavigatorParams { - matrix: T[][], - turning: Turning, - onMove: (cur: [number, number]) => void - init: { - cur: [number, number], - charDir: Direction, - VISITED: T, - } -} - export class Navigator { + onMove: (cur: [number, number]) => void; private readonly _matrix: T[][]; private readonly _cur: [number, number]; private _character: Character; private readonly _VISITED: T; - onMove: (cur: [number, number]) => void; constructor({matrix, turning, onMove, init: {cur, charDir, VISITED}}: NavigatorParams) { this._matrix = matrix; diff --git a/src/data-structures/matrix/vector2d.ts b/src/data-structures/matrix/vector2d.ts index 27a1e3d..293dc22 100644 --- a/src/data-structures/matrix/vector2d.ts +++ b/src/data-structures/matrix/vector2d.ts @@ -1,4 +1,39 @@ -class Vector2D { +export class Vector2D { + constructor( + public x: number = 0, + public y: number = 0, + public w: number = 1 // needed for matrix multiplication + ) { + } + + /** + * Set x and y both to zero + */ + public get isZero(): boolean { + return this.x === 0 && this.y === 0 + } + + /** + * The length / magnitude of the vector + */ + public get length(): number { + return Math.sqrt((this.x * this.x) + (this.y * this.y)) + } + + /** + * The squared length of the vector + */ + public get lengthSq(): number { + return (this.x * this.x) + (this.y * this.y) + } + + /** + * Return the vector with rounded values + */ + public get rounded(): Vector2D { + return new Vector2D(Math.round(this.x), Math.round(this.y)) + } + public static add(vector1: Vector2D, vector2: Vector2D): Vector2D { return new Vector2D(vector1.x + vector2.x, vector1.y + vector2.y) } @@ -80,6 +115,22 @@ class Vector2D { return (vector1.x * vector2.x) + (vector1.y * vector2.y) } + // /** + // * Transform vectors based on the current tranformation matrices: translation, rotation and scale + // * @param vectors The vectors to transform + // */ + // public static transform(vector: Vector2D, transformation: Matrix2D): Vector2D { + // return Matrix2D.multiplyByVector(transformation, vector) + // } + + // /** + // * Transform vectors based on the current tranformation matrices: translation, rotation and scale + // * @param vectors The vectors to transform + // */ + // public static transformList(vectors: Vector2D[], transformation: Matrix2D): Vector2D[] { + // return vectors.map(vector => Matrix2D.multiplyByVector(transformation, vector)) + // } + /** * The distance between this and the vector */ @@ -126,29 +177,6 @@ class Vector2D { return new Vector2D(randX, randY) } - // /** - // * Transform vectors based on the current tranformation matrices: translation, rotation and scale - // * @param vectors The vectors to transform - // */ - // public static transform(vector: Vector2D, transformation: Matrix2D): Vector2D { - // return Matrix2D.multiplyByVector(transformation, vector) - // } - - // /** - // * Transform vectors based on the current tranformation matrices: translation, rotation and scale - // * @param vectors The vectors to transform - // */ - // public static transformList(vectors: Vector2D[], transformation: Matrix2D): Vector2D[] { - // return vectors.map(vector => Matrix2D.multiplyByVector(transformation, vector)) - // } - - constructor( - public x: number = 0, - public y: number = 0, - public w: number = 1 // needed for matrix multiplication - ) { - } - /** * Check wether both x and y are zero */ @@ -156,34 +184,6 @@ class Vector2D { this.x = 0 this.y = 0 } - - /** - * Set x and y both to zero - */ - public get isZero(): boolean { - return this.x === 0 && this.y === 0 - } - - /** - * The length / magnitude of the vector - */ - public get length(): number { - return Math.sqrt((this.x * this.x) + (this.y * this.y)) - } - - /** - * The squared length of the vector - */ - public get lengthSq(): number { - return (this.x * this.x) + (this.y * this.y) - } - - /** - * Return the vector with rounded values - */ - public get rounded(): Vector2D { - return new Vector2D(Math.round(this.x), Math.round(this.y)) - } } export default Vector2D \ No newline at end of file diff --git a/src/data-structures/priority-queue/max-priority-queue.ts b/src/data-structures/priority-queue/max-priority-queue.ts index 539e79a..e1a1b53 100644 --- a/src/data-structures/priority-queue/max-priority-queue.ts +++ b/src/data-structures/priority-queue/max-priority-queue.ts @@ -1,9 +1,10 @@ -import {PriorityQueue, PriorityQueueOptions} from './priority-queue'; +import {PriorityQueue} from './priority-queue'; +import type {PriorityQueueOptions} from '../types'; export class MaxPriorityQueue extends PriorityQueue { - constructor(options: PriorityQueueOptions) { + constructor(options?: PriorityQueueOptions) { super({ - nodes: options.nodes, comparator: (a: T, b: T) => { + nodes: options?.nodes, comparator: options?.comparator ? options.comparator : (a: T, b: T) => { const aKey = a as unknown as number, bKey = b as unknown as number; return bKey - aKey; } diff --git a/src/data-structures/priority-queue/min-priority-queue.ts b/src/data-structures/priority-queue/min-priority-queue.ts index 74c4226..ae0a6dd 100644 --- a/src/data-structures/priority-queue/min-priority-queue.ts +++ b/src/data-structures/priority-queue/min-priority-queue.ts @@ -1,9 +1,10 @@ -import {PriorityQueue, PriorityQueueOptions} from './priority-queue'; +import {PriorityQueue} from './priority-queue'; +import type {PriorityQueueOptions} from '../types'; export class MinPriorityQueue extends PriorityQueue { - constructor(options: PriorityQueueOptions) { + constructor(options?: PriorityQueueOptions) { super({ - nodes: options.nodes, comparator: (a: T, b: T) => { + nodes: options?.nodes, comparator: options?.comparator ? options.comparator : (a: T, b: T) => { const aKey = a as unknown as number, bKey = b as unknown as number; return aKey - bKey; } diff --git a/src/data-structures/priority-queue/priority-queue.ts b/src/data-structures/priority-queue/priority-queue.ts index 127769a..c5bc7b8 100644 --- a/src/data-structures/priority-queue/priority-queue.ts +++ b/src/data-structures/priority-queue/priority-queue.ts @@ -1,25 +1,8 @@ -export type PriorityQueueComparator = (a: T, b: T) => number; - -export interface PriorityQueueOptions { - nodes?: T[]; - isFix?: boolean; - comparator: PriorityQueueComparator; -} - -export type PriorityQueueDFSOrderPattern = 'pre' | 'in' | 'post'; +import type {PriorityQueueComparator, PriorityQueueDFSOrderPattern, PriorityQueueOptions} from '../types'; export class PriorityQueue { protected nodes: T[] = []; - get size(): number { - return this.nodes.length; - } - - protected readonly _comparator: PriorityQueueComparator = (a: T, b: T) => { - const aKey = a as unknown as number, bKey = b as unknown as number; - return aKey - bKey; - }; - constructor(options: PriorityQueueOptions) { const {nodes, comparator, isFix = true} = options; this._comparator = comparator; @@ -31,64 +14,18 @@ export class PriorityQueue { } } - protected _compare(a: number, b: number) { - return this._comparator(this.nodes[a], this.nodes[b]) > 0; + get size(): number { + return this.nodes.length; } - protected _swap(a: number, b: number) { - const temp = this.nodes[a]; - this.nodes[a] = this.nodes[b]; - this.nodes[b] = temp; + static heapify(options: PriorityQueueOptions) { + const heap = new PriorityQueue(options); + heap._fix(); + return heap; } - protected _isValidIndex(index: number): boolean { - return index > -1 && index < this.nodes.length; - } - - protected _getParent(child: number): number { - return Math.floor((child - 1) / 2); - } - - protected _getLeft(parent: number): number { - return (2 * parent) + 1; - } - - protected _getRight(parent: number): number { - return (2 * parent) + 2; - } - - protected _getComparedChild(parent: number) { - let min = parent; - const left = this._getLeft(parent), right = this._getRight(parent); - - if (left < this.size && this._compare(min, left)) { - min = left; - } - if (right < this.size && this._compare(min, right)) { - min = right; - } - return min; - } - - protected _heapifyUp(start: number) { - while (start > 0 && this._compare(this._getParent(start), start)) { - const parent = this._getParent(start); - this._swap(start, parent); - start = parent; - } - } - - protected _heapifyDown(start: number) { - let min = this._getComparedChild(start); - while (this._compare(start, min)) { - this._swap(min, start); - start = min; - min = this._getComparedChild(start); - } - } - - protected _fix() { - for (let i = Math.floor(this.size / 2); i > -1; i--) this._heapifyDown(i); + static isPriorityQueueified(options: Omit, 'isFix'>) { + return new PriorityQueue({...options, isFix: true}).isValid(); } offer(node: T) { @@ -194,14 +131,69 @@ export class PriorityQueue { return visitedNode; } - static heapify(options: PriorityQueueOptions) { - const heap = new PriorityQueue(options); - heap._fix(); - return heap; + protected readonly _comparator: PriorityQueueComparator = (a: T, b: T) => { + const aKey = a as unknown as number, bKey = b as unknown as number; + return aKey - bKey; + }; + + protected _compare(a: number, b: number) { + return this._comparator(this.nodes[a], this.nodes[b]) > 0; } - static isPriorityQueueified(options: Omit, 'isFix'>) { - return new PriorityQueue({...options, isFix: true}).isValid(); + protected _swap(a: number, b: number) { + const temp = this.nodes[a]; + this.nodes[a] = this.nodes[b]; + this.nodes[b] = temp; + } + + protected _isValidIndex(index: number): boolean { + return index > -1 && index < this.nodes.length; + } + + protected _getParent(child: number): number { + return Math.floor((child - 1) / 2); + } + + protected _getLeft(parent: number): number { + return (2 * parent) + 1; + } + + protected _getRight(parent: number): number { + return (2 * parent) + 2; + } + + protected _getComparedChild(parent: number) { + let min = parent; + const left = this._getLeft(parent), right = this._getRight(parent); + + if (left < this.size && this._compare(min, left)) { + min = left; + } + if (right < this.size && this._compare(min, right)) { + min = right; + } + return min; + } + + protected _heapifyUp(start: number) { + while (start > 0 && this._compare(this._getParent(start), start)) { + const parent = this._getParent(start); + this._swap(start, parent); + start = parent; + } + } + + protected _heapifyDown(start: number) { + let min = this._getComparedChild(start); + while (this._compare(start, min)) { + this._swap(min, start); + start = min; + min = this._getComparedChild(start); + } + } + + protected _fix() { + for (let i = Math.floor(this.size / 2); i > -1; i--) this._heapifyDown(i); } // --- end additional methods --- diff --git a/src/data-structures/queue/deque.ts b/src/data-structures/queue/deque.ts index ab9acf4..49b8b4d 100644 --- a/src/data-structures/queue/deque.ts +++ b/src/data-structures/queue/deque.ts @@ -50,7 +50,7 @@ export class ObjectDeque { pollFirst() { if (!this._size) return; - let value = this.peekFirst(); + const value = this.peekFirst(); delete this._nodes[this._first]; this._first++; this._size--; @@ -63,7 +63,7 @@ export class ObjectDeque { pollLast() { if (!this._size) return; - let value = this.peekLast(); + const value = this.peekLast(); delete this._nodes[this._last]; this._last--; this._size--; diff --git a/src/data-structures/queue/queue.ts b/src/data-structures/queue/queue.ts index 9349e1b..19501df 100644 --- a/src/data-structures/queue/queue.ts +++ b/src/data-structures/queue/queue.ts @@ -1,7 +1,6 @@ /** * @license MIT - * @copyright 2020 Pablo - * + * @copyright 2020 Tyler Zeng * @class */ export class Queue { @@ -17,6 +16,17 @@ export class Queue { this._offset = 0; } + /** + * Creates a queue from an existing array. + * @public + * @static + * @param {array} elements + * @return {Queue} + */ + static fromArray(elements: T[]): Queue { + return new Queue(elements); + } + /** * Adds an element at the back of the queue. * @public @@ -109,15 +119,4 @@ export class Queue { clone(): Queue { return new Queue(this._nodes.slice(this._offset)); } - - /** - * Creates a queue from an existing array. - * @public - * @static - * @param {array} elements - * @return {Queue} - */ - static fromArray(elements: T[]): Queue { - return new Queue(elements); - } } diff --git a/src/data-structures/stack/stack.ts b/src/data-structures/stack/stack.ts index 333878a..f6b7c92 100644 --- a/src/data-structures/stack/stack.ts +++ b/src/data-structures/stack/stack.ts @@ -1,7 +1,6 @@ /** * @license MIT - * @copyright 2020 Pablo Rios - * + * @copyright 2020 Tyler Zeng * @class */ export class Stack { @@ -15,6 +14,17 @@ export class Stack { this._elements = Array.isArray(elements) ? elements : []; } + /** + * Creates a stack from an existing array + * @public + * @static + * @param {array} [elements] + * @return {Stack} + */ + static fromArray(elements: T[]): Stack { + return new Stack(elements); + } + /** * Checks if the stack is empty. * @public @@ -90,15 +100,4 @@ export class Stack { clone(): Stack { return new Stack(this._elements.slice()); } - - /** - * Creates a stack from an existing array - * @public - * @static - * @param {array} [elements] - * @return {Stack} - */ - static fromArray(elements: T[]): Stack { - return new Stack(elements); - } } diff --git a/src/data-structures/trampoline.ts b/src/data-structures/trampoline.ts index 5799af9..916e34d 100644 --- a/src/data-structures/trampoline.ts +++ b/src/data-structures/trampoline.ts @@ -1,91 +1,51 @@ -export type ArgumentTypes any> = - T extends (...args: infer A) => any - ? A - : never; +export const THUNK_SYMBOL = Symbol('thunk') -export const THUNK_SYMBOL: unique symbol = Symbol('thunk'); - -export interface Thunk extends Function { - __THUNK__: typeof THUNK_SYMBOL; - - (): T; +export const isThunk = (fnOrValue: any) => { + return typeof fnOrValue === 'function' && fnOrValue.__THUNK__ === THUNK_SYMBOL } -export type ThunkOrValue = T | Thunk; +type ToThunkFn = () => ReturnType; -export type UnwrapThunkDeep = { - 0: T extends Thunk ? UnwrapThunkDeep : T; -}[ - T extends ThunkOrValue ? 0 : never - ]; +type Thunk = () => ReturnType & { __THUNK__: typeof THUNK_SYMBOL }; -export const isThunk = (value: any): value is Thunk => { - return typeof value === 'function' && value.__THUNK__ === THUNK_SYMBOL; -}; - -export const toThunk = (fn: () => R): Thunk => { - const thunk = () => fn(); - thunk.__THUNK__ = THUNK_SYMBOL; - return thunk; -}; -export type UnwrapPromise = T extends Promise ? Exclude> : T; - -export type Unbox = UnwrapThunkDeep>; - -export type Cont = (...args: A) => Thunk>; - -export interface Trampoline any)> { - (...args: ArgumentTypes): Unbox>; - - cont: Cont, ReturnType>; +export const toThunk = (fn: ToThunkFn): Thunk => { + const thunk = () => fn() + thunk.__THUNK__ = THUNK_SYMBOL + return thunk } -export interface TrampolineAsync any)> { - (...args: ArgumentTypes): Promise>>; - - cont: Cont, ReturnType>; -} - -export const trampoline = any)>(fn: F): Trampoline => { - const cont = (...args: ArgumentTypes) => toThunk(() => fn(...args)); +type TrlFn = (...args: any[]) => any; +export const trampoline = (fn: TrlFn) => { + const cont = (...args: [...Parameters]) => toThunk(() => fn(...args)) return Object.assign( - (...args: ArgumentTypes): Unbox> => { - let result: ThunkOrValue> = fn(...args); + (...args: [...Parameters]) => { + let result = fn(...args) - while (isThunk>(result)) { - result = result(); + while (isThunk(result) && typeof result === 'function') { + result = result() } - return result; + return result }, - {cont}, - ); -}; + {cont} + ) +} -export const trampolineAsync = any)>(fn: F): TrampolineAsync => { - const cont = (...args: ArgumentTypes) => toThunk(() => fn(...args)); +type TrlAsyncFn = (...args: any[]) => any; +export const trampolineAsync = (fn: TrlAsyncFn) => { + const cont = (...args: [...Parameters]) => toThunk(() => fn(...args)) return Object.assign( - async (...args: ArgumentTypes): Promise>> => { - let result: ThunkOrValue> = await fn(...args); + async (...args: [...Parameters]) => { + let result = await fn(...args) - while (isThunk>(result)) { - result = await result(); + while (isThunk(result) && typeof result === 'function') { + result = await result() } - return result; + return result }, - {cont}, - ); -}; - - -const factorial = trampoline((n: number, acc: number = 1): ThunkOrValue => { - return n - // Note: calling factorial.cont instead of factorial directly - ? factorial.cont(n - 1, acc * n) - : acc; -}); - -// factorial(32768) + {cont} + ) +} \ No newline at end of file diff --git a/src/data-structures/trie/trie.ts b/src/data-structures/trie/trie.ts index 1cd8455..a964071 100644 --- a/src/data-structures/trie/trie.ts +++ b/src/data-structures/trie/trie.ts @@ -1,5 +1,13 @@ export class TrieNode { - protected _children: Map = new Map(); + protected _value; + + constructor(v: string) { + this._value = v; + this._isEnd = false; + this._children = new Map(); + } + + protected _children: Map; get children(): Map { return this._children; @@ -9,7 +17,7 @@ export class TrieNode { this._children = v; } - protected _isEnd = false; + protected _isEnd: boolean; get isEnd(): boolean { return this._isEnd; @@ -18,10 +26,28 @@ export class TrieNode { set isEnd(v: boolean) { this._isEnd = v; } + + get val(): string { + return this._value; + } + + set val(v: string) { + this._value = v; + } } export class Trie { + constructor(words?: string[]) { + this._root = new TrieNode(''); + if (words) { + for (const i of words) { + this.put(i); + } + } + } + protected _root: TrieNode; + get root() { return this._root; } @@ -30,16 +56,12 @@ export class Trie { this._root = v; } - constructor() { - this._root = new TrieNode(); - } - - put(input: string): boolean { + put(word: string): boolean { let cur = this._root; - for (const c of input) { + for (const c of word) { let nodeC = cur.children.get(c); if (!nodeC) { - nodeC = new TrieNode(); + nodeC = new TrieNode(c); cur.children.set(c, nodeC); } cur = nodeC; @@ -48,7 +70,6 @@ export class Trie { return true; } - has(input: string): boolean { let cur = this._root; for (const c of input) { @@ -107,7 +128,7 @@ export class Trie { } /** - * Can present as a prefix or word + * Can present as a abs prefix or word * @param input */ isPrefix(input: string): boolean { @@ -120,6 +141,35 @@ export class Trie { return true; } + /** + * Check if the input string is the common prefix of all the words + * @param input + */ + isCommonPrefix(input: string): boolean { + let commonPre = ''; + const dfs = (cur: TrieNode) => { + commonPre += cur.val; + if (commonPre === input) return; + if (cur.isEnd) return; + if (cur && cur.children && cur.children.size === 1) dfs(Array.from(cur.children.values())[0]); + else return; + } + dfs(this._root); + return commonPre === input; + } + + // Retrieve the longest common prefix of all the words + getLongestCommonPrefix(): string { + let commonPre = ''; + const dfs = (cur: TrieNode) => { + commonPre += cur.val; + if (cur.isEnd) return; + if (cur && cur.children && cur.children.size === 1) dfs(Array.from(cur.children.values())[0]); + else return; + } + dfs(this._root); + return commonPre; + } getAll(prefix = ''): string[] { const words: string[] = []; diff --git a/src/data-structures/types/abstract-graph.ts b/src/data-structures/types/abstract-graph.ts new file mode 100644 index 0000000..074c618 --- /dev/null +++ b/src/data-structures/types/abstract-graph.ts @@ -0,0 +1,51 @@ +export type VertexId = string | number; +export type DijkstraResult = + { distMap: Map, preMap: Map, seen: Set, paths: V[][], minDist: number, minPath: V[] } + | null; + +export interface IGraph { + + containsVertex(vertexOrId: V | VertexId): boolean; + + getVertex(vertexOrId: VertexId | V): V | null; + + getVertexId(vertexOrId: V | VertexId): VertexId; + + vertexSet(): Map; + + addVertex(v: V): boolean; + + removeVertex(vertexOrId: V | VertexId): boolean; + + removeAllVertices(vertices: V[] | VertexId[]): boolean; + + degreeOf(vertexOrId: V | VertexId): number; + + edgesOf(vertexOrId: V | VertexId): E[]; + + containsEdge(src: V | VertexId, dest: V | VertexId): boolean; + + // containsEdge(e: E): boolean; + + getEdge(srcOrId: V | VertexId, destOrId: V | VertexId): E | null; + + // getAllEdges(src: V, dest: V): E[]; + + edgeSet(): E[]; + + addEdge(edge: E): boolean; + + removeEdgeBetween(srcOrId: V | VertexId, destOrId: V | VertexId): E | null; + + removeEdge(edge: E): E | null; + + // removeAllEdges(v1: VertexId | V, v2: VertexId | V): (E | null)[]; + + // removeAllEdges(edges: E[] | [VertexId, VertexId]): boolean; + + setEdgeWeight(srcOrId: V | VertexId, destOrId: V | VertexId, weight: number): boolean; + + getMinPathBetween(v1: V | VertexId, v2: V | VertexId, isWeight?: boolean): V[] | null; + + getNeighbors(vertexOrId: V | VertexId): V[]; +} \ No newline at end of file diff --git a/src/data-structures/types/avl-tree.ts b/src/data-structures/types/avl-tree.ts new file mode 100644 index 0000000..3f0c154 --- /dev/null +++ b/src/data-structures/types/avl-tree.ts @@ -0,0 +1,6 @@ +import {AVLTreeNode} from '../binary-tree'; + +export interface AVLTreeDeleted { + deleted: AVLTreeNode | null; + needBalanced: AVLTreeNode | null; +} \ No newline at end of file diff --git a/src/data-structures/types/binary-tree.ts b/src/data-structures/types/binary-tree.ts new file mode 100644 index 0000000..25b3a0e --- /dev/null +++ b/src/data-structures/types/binary-tree.ts @@ -0,0 +1,15 @@ +import {BinaryTreeNode} from '../binary-tree'; + +export type BinaryTreeNodePropertyName = 'id' | 'val' | 'count'; +export type NodeOrPropertyName = 'node' | BinaryTreeNodePropertyName; +export type DFSOrderPattern = 'in' | 'pre' | 'post'; +export type BinaryTreeNodeId = number; +export type BinaryTreeDeleted = { deleted: BinaryTreeNode | null | undefined, needBalanced: BinaryTreeNode | null }; +export type ResultByProperty = T | BinaryTreeNode | number | BinaryTreeNodeId; +export type ResultsByProperty = ResultByProperty[]; + +export interface BinaryTreeNodeObj { + id: BinaryTreeNodeId; + val: T; + count?: number; +} \ No newline at end of file diff --git a/src/data-structures/types/bst.ts b/src/data-structures/types/bst.ts new file mode 100644 index 0000000..dd18b61 --- /dev/null +++ b/src/data-structures/types/bst.ts @@ -0,0 +1,5 @@ +import {BSTNode} from '../binary-tree'; +import type {BinaryTreeNodeId} from './binary-tree'; + +export type BSTComparator = (a: BinaryTreeNodeId, b: BinaryTreeNodeId) => number; +export type BSTDeletedResult = { deleted: BSTNode | null, needBalanced: BSTNode | null }; diff --git a/src/data-structures/types/directed-graph.ts b/src/data-structures/types/directed-graph.ts new file mode 100644 index 0000000..aea9be5 --- /dev/null +++ b/src/data-structures/types/directed-graph.ts @@ -0,0 +1,18 @@ +import {VertexId} from './abstract-graph'; + +export interface IDirectedGraph { + incomingEdgesOf(vertex: V): E[]; + + outgoingEdgesOf(vertex: V): E[]; + + inDegreeOf(vertexOrId: V | VertexId): number; + + outDegreeOf(vertexOrId: V | VertexId): number; + + getEdgeSrc(e: E): V | null; + + getEdgeDest(e: E): V | null; +} + +// 0 means unknown, 1 means visiting, 2 means visited; +export type TopologicalStatus = 0 | 1 | 2; \ No newline at end of file diff --git a/src/data-structures/types/doubly-linked-list.ts b/src/data-structures/types/doubly-linked-list.ts new file mode 100644 index 0000000..6576f6d --- /dev/null +++ b/src/data-structures/types/doubly-linked-list.ts @@ -0,0 +1 @@ +export type DoublyLinkedListGetBy = 'node' | 'val'; \ No newline at end of file diff --git a/src/data-structures/types/heap.ts b/src/data-structures/types/heap.ts new file mode 100644 index 0000000..8292add --- /dev/null +++ b/src/data-structures/types/heap.ts @@ -0,0 +1,8 @@ +export interface HeapOptions { + priority?: (element: T) => number; +} + +export interface HeapItem { + priority: number; + element: T | null; +} \ No newline at end of file diff --git a/src/data-structures/types/index.ts b/src/data-structures/types/index.ts new file mode 100644 index 0000000..be0ddae --- /dev/null +++ b/src/data-structures/types/index.ts @@ -0,0 +1,13 @@ +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 './directed-graph'; +export * from './priority-queue'; +export * from './heap'; +export * from './singly-linked-list'; +export * from './doubly-linked-list'; +export * from './navigator'; +export * from './utils'; \ No newline at end of file diff --git a/src/data-structures/types/navigator.ts b/src/data-structures/types/navigator.ts new file mode 100644 index 0000000..0676678 --- /dev/null +++ b/src/data-structures/types/navigator.ts @@ -0,0 +1,13 @@ +export type Direction = 'up' | 'right' | 'down' | 'left'; +export type Turning = { [key in Direction]: Direction }; + +export interface NavigatorParams { + matrix: T[][], + turning: Turning, + onMove: (cur: [number, number]) => void + init: { + cur: [number, number], + charDir: Direction, + VISITED: T, + } +} diff --git a/src/data-structures/types/priority-queue.ts b/src/data-structures/types/priority-queue.ts new file mode 100644 index 0000000..48e398a --- /dev/null +++ b/src/data-structures/types/priority-queue.ts @@ -0,0 +1,9 @@ +export type PriorityQueueComparator = (a: T, b: T) => number; + +export interface PriorityQueueOptions { + nodes?: T[]; + isFix?: boolean; + comparator: PriorityQueueComparator; +} + +export type PriorityQueueDFSOrderPattern = 'pre' | 'in' | 'post'; \ No newline at end of file diff --git a/src/data-structures/types/segment-tree.ts b/src/data-structures/types/segment-tree.ts new file mode 100644 index 0000000..e7f6012 --- /dev/null +++ b/src/data-structures/types/segment-tree.ts @@ -0,0 +1 @@ +export type SegmentTreeNodeVal = number; diff --git a/src/data-structures/types/singly-linked-list.ts b/src/data-structures/types/singly-linked-list.ts new file mode 100644 index 0000000..9295841 --- /dev/null +++ b/src/data-structures/types/singly-linked-list.ts @@ -0,0 +1,15 @@ +import {SinglyLinkedList} from '../linked-list'; + +/** Type used for filter and find methods, returning a boolean */ +export type TTestFunction = ( + data: NodeData, + index: number, + list: SinglyLinkedList, +) => boolean; + +/** Type used for map and forEach methods, returning anything */ +export type TMapFunction = ( + data: any, + index: number, + list: SinglyLinkedList, +) => any; diff --git a/src/data-structures/types/tree-multiset.ts b/src/data-structures/types/tree-multiset.ts new file mode 100644 index 0000000..74ae62a --- /dev/null +++ b/src/data-structures/types/tree-multiset.ts @@ -0,0 +1,3 @@ +import {BSTNode} from '../binary-tree'; + +export type TreeMultiSetDeletedResult = { deleted: BSTNode | null, needBalanced: BSTNode | null }; diff --git a/src/types/utils.ts b/src/data-structures/types/utils.ts similarity index 84% rename from src/types/utils.ts rename to src/data-structures/types/utils.ts index cc89256..cb7b1f3 100644 --- a/src/types/utils.ts +++ b/src/data-structures/types/utils.ts @@ -74,9 +74,9 @@ export type DebounceOptions = { }; export interface DebouncedFunction { - (this: ThisParameterType, ...args: Parameters): void; - cancel: () => void; + + (this: ThisParameterType, ...args: [...Parameters]): void; } export type MonthKey = @@ -123,10 +123,10 @@ export class TreeNode { if (!this.children) { this.children = []; } - if (children instanceof Array) { - this.children = this.children.concat(children); - } else { + if (children instanceof TreeNode) { this.children.push(children); + } else { + this.children = this.children.concat(children); } } @@ -155,4 +155,19 @@ export class TreeNode { export type OrderType = 'InOrder' | 'PreOrder' | 'PostOrder' +export type DeepProxy = T extends (...args: any[]) => infer R + ? (...args: [...Parameters]) => DeepProxy + : T extends object + ? { [K in keyof T]: DeepProxy } + : T; + +export type DeepProxyOnChange = (target: any, property: string | symbol, value: any, receiver: any, descriptor: any, result: any) => void; + +export type DeepProxyOnGet = (target: any, property: string | symbol, value: any, receiver: any, descriptor: any, result: any) => void; + +export type CurryFunc = T extends (...args: infer Args) => infer R + ? Args extends [infer Arg, ...infer RestArgs] + ? (arg: Arg) => CurryFunc<(...args: RestArgs) => R> + : R + : T; diff --git a/src/types/index.ts b/src/types/index.ts deleted file mode 100644 index 04bca77..0000000 --- a/src/types/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './utils'; diff --git a/src/types/patches/index.d.ts b/src/types/patches/index.d.ts deleted file mode 100644 index e69de29..0000000 diff --git a/src/utils/index.ts b/src/utils/index.ts new file mode 100644 index 0000000..038522d --- /dev/null +++ b/src/utils/index.ts @@ -0,0 +1 @@ +export * from './utils'; \ No newline at end of file diff --git a/src/utils.ts b/src/utils/utils.ts similarity index 79% rename from src/utils.ts rename to src/utils/utils.ts index e9ea9dd..612908e 100644 --- a/src/utils.ts +++ b/src/utils/utils.ts @@ -1,5 +1,5 @@ -import _ from 'lodash'; -import {AnyFunction} from './types'; +import * as _ from 'lodash'; +import {AnyFunction} from '../data-structures/types'; export type JSONSerializable = { [key: string]: any @@ -21,7 +21,7 @@ export function randomText(length: number) { } export const uuidV4 = function () { - return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { + return 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'.replace(/[x]/g, function (c) { const r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); }); @@ -60,25 +60,15 @@ export function incrementId(prefix?: string) { }; } -export const getValue = (obj: T, names: K[]): Array => { - return names.map(i => obj[i]); -}; +export const getValue = (obj: T, names: K[]): Array => names.map(i => obj[i]); -export const isObject = (object: string | JSONObject | boolean | AnyFunction | number) => { - return object != null && typeof object === 'object'; -}; +export const isObject = (object: string | JSONObject | boolean | AnyFunction | number) => object != null && typeof object === 'object'; -export const looseEqual = (a: any, b: any): boolean => { - return a == b; -}; +export const looseEqual = (a: any, b: any): boolean => a == b; -export const strictEqual = (a: any, b: any): boolean => { - return a === b; -}; +export const strictEqual = (a: any, b: any): boolean => a === b; -export const strictObjectIsEqual = (a: any, b: any): boolean => { - return Object.is(a, b); -}; +export const strictObjectIsEqual = (a: any, b: any): boolean => Object.is(a, b); export const deepObjectStrictEqual = (object1: JSONSerializable, object2: JSONSerializable) => { const keys1 = Object.keys(object1); @@ -100,10 +90,6 @@ export const deepObjectStrictEqual = (object1: JSONSerializable, object2: JSONSe return true; }; -export const isTypeEqual = (obj: unknown) => { - const m = obj as unknown as T; -}; - export function reverseColor(oldColor: string) { const oldColorTemp = '0x' + oldColor.replace(/#/g, ''); const str = '000000' + (0xFFFFFF - Number(oldColorTemp)).toString(16); @@ -152,48 +138,62 @@ export const addDays = (date: Date, days: number): Date => { }; export class WaitManager { + private _time30 = 20000; + private readonly _nXSpeed: number = 1; + + constructor(nXSpeed?: number) { + if (nXSpeed === undefined) nXSpeed = 1; + this._nXSpeed = nXSpeed; + } + private _time1 = 1000; + get time1(): number { return this._time1 / this._nXSpeed; } private _time2 = 2000; + get time2(): number { return this._time2 / this._nXSpeed; } private _time3 = 3000; + get time3(): number { return this._time3 / this._nXSpeed; } private _time4 = 4000; + get time4(): number { return this._time4 / this._nXSpeed; } private _time10 = 10000; + get time10(): number { return this._time10 / this._nXSpeed; } private _time20 = 20000; + get time20(): number { return this._time20 / this._nXSpeed; } - private _time30 = 20000; - get time50(): number { return this._time30 / this._nXSpeed; } private _time60 = 60000; + get time60(): number { return this._time60 / this._nXSpeed; } private _cusTime = 1000; + get cusTime(): number { return this._cusTime / this._nXSpeed; } @@ -201,13 +201,6 @@ export class WaitManager { set cusTime(v: number) { this._cusTime = v; } - - private readonly _nXSpeed: number = 1; - - constructor(nXSpeed?: number) { - if (nXSpeed === undefined) nXSpeed = 1; - this._nXSpeed = nXSpeed; - } } export const wait = async (ms: number, resolveValue?: any) => { @@ -219,78 +212,6 @@ export const wait = async (ms: number, resolveValue?: any) => { }); }; -export class AuthAPIError extends Error { - protected serverErrorStack; - protected serverErrorCode; - - constructor(serverErrorMessage: string, serverErrorCode?: string, serverErrorStack?: string) { - super(serverErrorMessage); - if (serverErrorStack) { - this.serverErrorStack = serverErrorStack; - } - if (serverErrorCode) { - this.serverErrorCode = serverErrorCode; - } - this.name = new.target.name; - if (typeof (Error as any).captureStackTrace === 'function') { - (Error as any).captureStackTrace(this, new.target); - } - if (typeof Object.setPrototypeOf === 'function') { - Object.setPrototypeOf(this, new.target.prototype); - } else { - (this as any).__proto__ = new.target.prototype; - } - } -} - -export class BunnyAPIError extends Error { - protected serverErrorStack; - protected serverErrorCode; - - constructor(serverErrorMessage: string, serverErrorCode?: string, serverErrorStack?: string) { - super(serverErrorMessage); - if (serverErrorStack) { - this.serverErrorStack = serverErrorStack; - } - if (serverErrorCode) { - this.serverErrorCode = serverErrorCode; - } - this.name = new.target.name; - if (typeof (Error as any).captureStackTrace === 'function') { - (Error as any).captureStackTrace(this, new.target); - } - if (typeof Object.setPrototypeOf === 'function') { - Object.setPrototypeOf(this, new.target.prototype); - } else { - (this as any).__proto__ = new.target.prototype; - } - } -} - -export class NomicsAPIError extends Error { - protected serverErrorStack; - protected serverErrorCode; - - constructor(serverErrorMessage: string, serverErrorCode?: string, serverErrorStack?: string) { - super(serverErrorMessage); - if (serverErrorStack) { - this.serverErrorStack = serverErrorStack; - } - if (serverErrorCode) { - this.serverErrorCode = serverErrorCode; - } - this.name = new.target.name; - if (typeof (Error as any).captureStackTrace === 'function') { - (Error as any).captureStackTrace(this, new.target); - } - if (typeof Object.setPrototypeOf === 'function') { - Object.setPrototypeOf(this, new.target.prototype); - } else { - (this as any).__proto__ = new.target.prototype; - } - } -} - export function extractValue(data: { key: string, value: Item }[]) { let result: Item[] = []; if (data && data.length > 0) { @@ -328,14 +249,9 @@ export function randomDate(start?: Date, end?: Date, specificProbabilityStart?: return new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime())); } +export const capitalizeWords = (str: string) => str.replace(/(?:^|\s)\S/g, (a: string) => a.toUpperCase()); -export const capitalizeWords = (str: string) => { - return str.replace(/(?:^|\s)\S/g, (a: string) => a.toUpperCase()); -}; - -export const capitalizeFirstLetter = (str: string) => { - return str.charAt(0).toUpperCase() + str.slice(1); -}; +export const capitalizeFirstLetter = (str: string) => str.charAt(0).toUpperCase() + str.slice(1); export const comparerArray = (otherArray: T[], limitKeys?: string[]) => { return function (current: T) { @@ -349,17 +265,11 @@ export const comparerArray = (otherArray: T[], limitKeys?: string[]) => { }; }; -export const onlyInA = (a: T[], b: T[]) => { - return a.filter(comparerArray(b)); -}; +export const onlyInA = (a: T[], b: T[]) => a.filter(comparerArray(b)); -export const onlyInB = (a: T[], b: T[]) => { - return b.filter(comparerArray(a)); -}; +export const onlyInB = (a: T[], b: T[]) => b.filter(comparerArray(a)); -export const diffAB = (a: T[], b: T[]) => { - return onlyInA(a, b).concat(onlyInB(a, b)); -}; +export const diffAB = (a: T[], b: T[]) => onlyInA(a, b).concat(onlyInB(a, b)); export class StringUtil { // camelCase @@ -413,8 +323,18 @@ export class StringUtil { } } -type ToCase = 'camel' | 'snake' | 'pascal' | 'constant' | 'kebab' | 'lower' | 'title' | 'sentence' | 'path' | 'dot'; -export const deepKeysConvert = (obj: any, toType?: ToCase): any => { +export type CaseType = + 'camel' + | 'snake' + | 'pascal' + | 'constant' + | 'kebab' + | 'lower' + | 'title' + | 'sentence' + | 'path' + | 'dot'; +export const deepKeysConvert = (obj: any, toType?: CaseType): any => { const _toType = toType || 'snake'; if (Array.isArray(obj)) { return obj.map(v => deepKeysConvert(v, _toType)); @@ -501,13 +421,6 @@ export const deepReplaceValues = (obj: JSONSerializable, keyReducerMap: { [key i return newObject; }; -// function getCallStackSize() { -// let count = 0, fn = arguments.callee; -// while ( (fn = fn.caller) ) { -// count++; -// } -// return count; -// } // TODO determine depth and pass root node as a param through callback export const deepAdd = (obj: JSONSerializable, keyReducerMap: { [key in string]: (item: JSONSerializable) => any }, isItemRootParent?: boolean) => { const newObject = _.clone(obj) as JSONObject | []; @@ -529,7 +442,6 @@ export const deepAdd = (obj: JSONSerializable, keyReducerMap: { [key in string]: const styleString = (color: string) => `color: ${color}; font-weight: bold`; - const styleHeader = (header: string) => `%c[${header}]`; export const bunnyConsole = { @@ -544,7 +456,6 @@ export const bunnyConsole = { } }; - export const timeStart = () => { return performance ? performance.now() : new Date().getTime(); }; @@ -601,5 +512,4 @@ export function zip(array1: T[], array2: T1[], options? } } return isToObj ? zippedObjCoords : zipped; -} - +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 8bccfa9..a9d74e7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,18 +3,17 @@ "declaration": true, "outDir": "./dist", "module": "commonjs", - "target": "es6", + "target": "es5", "lib": [ - "es6", - "dom", - "dom.iterable", +// "es2015", "esnext" ], "strict": true, "esModuleInterop": true, "moduleResolution": "node", "declarationDir": "./dist", - "skipLibCheck": true + "skipLibCheck": true, + "downlevelIteration": true, // "allowJs": true, // "allowSyntheticDefaultImports": true, @@ -23,12 +22,16 @@ // "resolveJsonModule": true, // "isolatedModules": true, // "noEmit": true, + "typeRoots": [ + "node_modules/@types" + ] }, + "include": [ "src", - "node_modules/data-structure-typed" ], "exclude": [ +// "node_modules/data-structure-typed", "node_modules", "dist" ]