version 0.9.16 published

This commit is contained in:
Revone 2023-08-11 22:46:43 +08:00
parent 7b885191fd
commit 0770aeb2d1
69 changed files with 879 additions and 868 deletions

View file

@ -2,7 +2,7 @@
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/data-structure-ts.iml" filepath="$PROJECT_DIR$/.idea/data-structure-ts.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/data-structure-typed.iml" filepath="$PROJECT_DIR$/.idea/data-structure-typed.iml" />
</modules>
</component>
</project>

40
package-lock.json generated
View file

@ -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
}
}
}

View file

@ -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": {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 357 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 856 KiB

View file

@ -1,10 +1,5 @@
import {BST, BSTNode} from './bst';
import {BinaryTreeNodeId} from './binary-tree';
export interface AVLTreeDeleted<T> {
deleted: AVLTreeNode<T> | null;
needBalanced: AVLTreeNode<T> | null;
}
import type {AVLTreeDeleted, BinaryTreeNodeId} from '../types';
export class AVLTreeNode<T> extends BSTNode<T> {
override clone(): AVLTreeNode<T> {

View file

@ -5,6 +5,10 @@ export class BinaryIndexedTree {
this._sumTree = new Array<number>(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);
}
}

View file

@ -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<T> = { deleted: BinaryTreeNode<T> | null | undefined, needBalanced: BinaryTreeNode<T> | null };
export type ResultByProperty<T> = T | BinaryTreeNode<T> | number | BinaryTreeNodeId;
export type ResultsByProperty<T> = ResultByProperty<T>[];
export interface BinaryTreeNodeObj<T> {
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<T> {
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<T> {
}
protected _val: T;
get val(): T {
return this._val;
}
@ -38,6 +41,7 @@ export class BinaryTreeNode<T> {
}
protected _left?: BinaryTreeNode<T> | null;
get left(): BinaryTreeNode<T> | null | undefined {
return this._left;
}
@ -51,6 +55,7 @@ export class BinaryTreeNode<T> {
}
protected _right?: BinaryTreeNode<T> | null;
get right(): BinaryTreeNode<T> | null | undefined {
return this._right;
}
@ -63,7 +68,8 @@ export class BinaryTreeNode<T> {
this._right = v;
}
protected _parent: BinaryTreeNode<T> | null | undefined = undefined;
protected _parent: BinaryTreeNode<T> | null | undefined;
get parent(): BinaryTreeNode<T> | null | undefined {
return this._parent;
}
@ -73,6 +79,7 @@ export class BinaryTreeNode<T> {
}
protected _familyPosition: FamilyPosition = FamilyPosition.root;
get familyPosition(): FamilyPosition {
return this._familyPosition;
}
@ -82,6 +89,7 @@ export class BinaryTreeNode<T> {
}
protected _count = 1;
get count(): number {
return this._count;
}
@ -100,12 +108,6 @@ export class BinaryTreeNode<T> {
this._height = v;
}
constructor(id: BinaryTreeNodeId, val: T, count?: number) {
this._id = id;
this._val = val;
this._count = count ?? 1;
}
swapLocation(swapNode: BinaryTreeNode<T>): BinaryTreeNode<T> {
const {val, count, height} = swapNode;
const tempNode = new BinaryTreeNode<T>(swapNode.id, val);
@ -131,55 +133,15 @@ export class BinaryTreeNode<T> {
}
export class BinaryTree<T> {
protected _root: BinaryTreeNode<T> | null = null;
public get root(): BinaryTreeNode<T> | null {
return this._root;
}
protected set root(v: BinaryTreeNode<T> | 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<T> = [];
protected _visitedNode: BinaryTreeNode<T>[] = [];
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<T> {
}
}
protected _root: BinaryTreeNode<T> | null = null;
protected get root(): BinaryTreeNode<T> | null {
return this._root;
}
protected set root(v: BinaryTreeNode<T> | 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<T> | null {
return val !== null ? new BinaryTreeNode(id, val, count) : null;
}
@ -393,8 +393,8 @@ export class BinaryTree<T> {
return _getMaxHeight(beginRoot);
} else {
const stack: BinaryTreeNode<T>[] = [];
let node: BinaryTreeNode<T> | null | undefined = beginRoot, last: BinaryTreeNode<T> | null = null,
depths: Map<BinaryTreeNode<T>, number> = new Map();
let node: BinaryTreeNode<T> | null | undefined = beginRoot, last: BinaryTreeNode<T> | null = null;
const depths: Map<BinaryTreeNode<T>, number> = new Map();
while (stack.length > 0 || node) {
if (node) {
@ -405,8 +405,8 @@ export class BinaryTree<T> {
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<T> {
return _getMinHeight(beginRoot);
} else {
const stack: BinaryTreeNode<T>[] = [];
let node: BinaryTreeNode<T> | null | undefined = beginRoot, last: BinaryTreeNode<T> | null = null,
depths: Map<BinaryTreeNode<T>, number> = new Map();
let node: BinaryTreeNode<T> | null | undefined = beginRoot, last: BinaryTreeNode<T> | null = null;
const depths: Map<BinaryTreeNode<T>, number> = new Map();
while (stack.length > 0 || node) {
if (node) {
@ -447,8 +447,8 @@ export class BinaryTree<T> {
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<T> {
return result;
}
protected _pushByPropertyNameStopOrNot(cur: BinaryTreeNode<T>, result: (BinaryTreeNode<T> | 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<T>, 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<T> {
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<T> | null {
return this.root;
}
getLeftMost(): BinaryTreeNode<T> | null;
getLeftMost(node: BinaryTreeNode<T>): BinaryTreeNode<T>;
getLeftMost(node?: BinaryTreeNode<T> | null): BinaryTreeNode<T> | null {
node = node ?? this.root;
if (!node) return node;
@ -598,7 +536,7 @@ export class BinaryTree<T> {
return _traverse(node);
} else {
// Indirect implementation of iteration using tail recursion optimization
const _traverse = trampoline((cur: BinaryTreeNode<T>): ThunkOrValue<BinaryTreeNode<T> | null> => {
const _traverse = trampoline((cur: BinaryTreeNode<T>) => {
if (!cur.left) return cur;
return _traverse.cont(cur.left);
});
@ -608,7 +546,9 @@ export class BinaryTree<T> {
}
getRightMost(): BinaryTreeNode<T> | null;
getRightMost(node: BinaryTreeNode<T>): BinaryTreeNode<T>;
getRightMost(node?: BinaryTreeNode<T> | null): BinaryTreeNode<T> | null {
node = node ?? this.root;
if (!node) return node;
@ -622,7 +562,7 @@ export class BinaryTree<T> {
return _traverse(node);
} else {
// Indirect implementation of iteration using tail recursion optimization
const _traverse = trampoline((cur: BinaryTreeNode<T>): ThunkOrValue<BinaryTreeNode<T> | null> => {
const _traverse = trampoline((cur: BinaryTreeNode<T>) => {
if (!cur.right) return cur;
return _traverse.cont(cur.right);
});
@ -653,7 +593,7 @@ export class BinaryTree<T> {
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<T> {
}
BFS(): BinaryTreeNodeId[];
BFS(nodeOrPropertyName: 'id'): BinaryTreeNodeId[];
BFS(nodeOrPropertyName: 'val'): T[];
BFS(nodeOrPropertyName: 'node'): BinaryTreeNode<T>[];
BFS(nodeOrPropertyName: 'count'): number[];
BFS(nodeOrPropertyName ?: NodeOrPropertyName): ResultsByProperty<T> {
nodeOrPropertyName = nodeOrPropertyName ?? 'id';
this._resetResults();
@ -801,10 +746,15 @@ export class BinaryTree<T> {
}
DFS(): BinaryTreeNodeId[];
DFS(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'id'): BinaryTreeNodeId[];
DFS(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'val'): T[];
DFS(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'node'): BinaryTreeNode<T>[];
DFS(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'count'): number[];
DFS(pattern ?: 'in' | 'pre' | 'post', nodeOrPropertyName ?: NodeOrPropertyName): ResultsByProperty<T> {
pattern = pattern ?? 'in';
nodeOrPropertyName = nodeOrPropertyName ?? 'id';
@ -834,9 +784,13 @@ export class BinaryTree<T> {
}
DFSIterative(): BinaryTreeNodeId[];
DFSIterative(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'id'): BinaryTreeNodeId[];
DFSIterative(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'val'): T[];
DFSIterative(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'node'): BinaryTreeNode<T>[];
DFSIterative(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'count'): number[];
/**
@ -889,10 +843,15 @@ export class BinaryTree<T> {
}
levelIterative(node: BinaryTreeNode<T> | null): BinaryTreeNodeId[];
levelIterative(node: BinaryTreeNode<T> | null, nodeOrPropertyName?: 'id'): BinaryTreeNodeId[];
levelIterative(node: BinaryTreeNode<T> | null, nodeOrPropertyName?: 'val'): T[];
levelIterative(node: BinaryTreeNode<T> | null, nodeOrPropertyName?: 'node'): BinaryTreeNode<T>[];
levelIterative(node: BinaryTreeNode<T> | null, nodeOrPropertyName?: 'count'): number[];
levelIterative(node: BinaryTreeNode<T> | null, nodeOrPropertyName ?: NodeOrPropertyName): ResultsByProperty<T> {
nodeOrPropertyName = nodeOrPropertyName || 'id';
node = node || this.root;
@ -918,10 +877,15 @@ export class BinaryTree<T> {
}
listLevels(node: BinaryTreeNode<T> | null): BinaryTreeNodeId[][];
listLevels(node: BinaryTreeNode<T> | null, nodeOrPropertyName?: 'id'): BinaryTreeNodeId[][];
listLevels(node: BinaryTreeNode<T> | null, nodeOrPropertyName?: 'val'): T[][];
listLevels(node: BinaryTreeNode<T> | null, nodeOrPropertyName?: 'node'): BinaryTreeNode<T>[][];
listLevels(node: BinaryTreeNode<T> | null, nodeOrPropertyName?: 'count'): number[][];
listLevels(node: BinaryTreeNode<T> | null, nodeOrPropertyName?: NodeOrPropertyName): ResultByProperty<T>[][] {
nodeOrPropertyName = nodeOrPropertyName || 'id';
node = node || this.root;
@ -977,9 +941,11 @@ export class BinaryTree<T> {
getPredecessor(node: BinaryTreeNode<T>): BinaryTreeNode<T> {
if (node.left) {
let predecessor: BinaryTreeNode<T> | null = node.left;
while (predecessor.right && predecessor.right !== node) {
predecessor = predecessor.right;
let predecessor: BinaryTreeNode<T> | 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<T> {
}
morris(): BinaryTreeNodeId[];
morris(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'id'): BinaryTreeNodeId[];
morris(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'val'): T[];
morris(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'node'): BinaryTreeNode<T>[];
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<T> {
return this._getResultByPropertyName(nodeOrPropertyName);
}
protected _resetResults() {
this._visitedId = [];
this._visitedVal = [];
this._visitedNode = [];
this._visitedCount = [];
this._visitedLeftSum = [];
}
protected _pushByPropertyNameStopOrNot(cur: BinaryTreeNode<T>, result: (BinaryTreeNode<T> | 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<T>, 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<T> {
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 ---
}

View file

@ -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<T> = { deleted: BSTNode<T> | null, needBalanced: BSTNode<T> | 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<T> extends BinaryTreeNode<T> {
}
export class BST<T> extends BinaryTree<T> {
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<T> extends BinaryTree<T> {
_height(this.root);
} else {
const stack: BSTNode<T>[] = [];
let node: BSTNode<T> | null | undefined = this.root, last: BSTNode<T> | null = null,
depths: Map<BSTNode<T>, number> = new Map();
let node: BSTNode<T> | null | undefined = this.root, last: BSTNode<T> | null = null;
const depths: Map<BSTNode<T>, number> = new Map();
while (stack.length > 0 || node) {
if (node) {
@ -385,8 +367,8 @@ export class BST<T> extends BinaryTree<T> {
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<T> extends BinaryTree<T> {
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
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

View file

@ -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]);

View file

@ -1,8 +1,5 @@
import {BST, BSTNode} from './bst';
import {BinaryTreeNodeId} from './binary-tree';
export type TreeMultiSetDeletedResult<T> = { deleted: BSTNode<T> | null, needBalanced: BSTNode<T> | null };
import type {BinaryTreeNodeId, TreeMultiSetDeletedResult} from '../types';
export class TreeMultiSet<T> extends BST<T> {
override createNode(id: BinaryTreeNodeId, val: T, count?: number): BSTNode<T> {

View file

@ -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

View file

@ -1,60 +1,14 @@
import {arrayRemove, uuidV4} from '../../utils';
import {PriorityQueue} from '../priority-queue';
export type VertexId = string | number;
export type DijkstraResult<V> =
{ distMap: Map<V, number>, preMap: Map<V, V | null>, seen: Set<V>, paths: V[][], minDist: number, minPath: V[] }
| null;
export interface I_Graph<V, E> {
containsVertex(vertexOrId: V | VertexId): boolean;
getVertex(vertexOrId: VertexId | V): V | null;
getVertexId(vertexOrId: V | VertexId): VertexId;
vertexSet(): Map<VertexId, V>;
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<V extends AbstractVertex, E extends AbstractEdge> implements I_Graph<V, E> {
export abstract class AbstractGraph<V extends AbstractVertex, E extends AbstractEdge> implements IGraph<V, E> {
protected _vertices: Map<VertexId, V> = new Map<VertexId, V>();
@ -192,7 +143,7 @@ export abstract class AbstractGraph<V extends AbstractVertex, E extends Abstract
if (!visiting.get(neighbor)) {
path.push(neighbor);
dfs(neighbor, dest, visiting, path);
arrayRemove(path, vertex => vertex === neighbor);
arrayRemove(path, (vertex: AbstractVertex) => vertex === neighbor);
}
}
@ -296,7 +247,7 @@ export abstract class AbstractGraph<V extends AbstractVertex, E extends Abstract
if (!visiting.get(neighbor)) {
path.push(neighbor);
dfs(neighbor, dest, visiting, path);
arrayRemove(path, vertex => vertex === neighbor);
arrayRemove(path, (vertex: AbstractVertex) => vertex === neighbor);
}
}
@ -338,7 +289,8 @@ export abstract class AbstractGraph<V extends AbstractVertex, E extends Abstract
}
for (const vertex of vertices) {
distMap.set(vertex[1], Infinity);
const vertexOrId = vertex[1];
if (vertexOrId instanceof AbstractVertex) distMap.set(vertexOrId, Infinity);
}
distMap.set(srcVertex, 0);
preMap.set(srcVertex, null);
@ -359,15 +311,19 @@ export abstract class AbstractGraph<V extends AbstractVertex, E extends Abstract
const getPaths = (minV: V | null) => {
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<V extends AbstractVertex, E extends Abstract
}
for (const vertex of vertices) {
distMap.set(vertex[1], Infinity);
const vertexOrId = vertex[1];
if (vertexOrId instanceof AbstractVertex) distMap.set(vertexOrId, Infinity);
}
const heap = new PriorityQueue<{ id: number, val: V }>({comparator: (a, b) => a.id - b.id});
@ -460,15 +417,19 @@ export abstract class AbstractGraph<V extends AbstractVertex, E extends Abstract
const getPaths = (minV: V | null) => {
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<V extends AbstractVertex, E extends Abstract
let min = Infinity;
let minPath: V[] = [];
// TODO
let hasNegativeCycle: boolean | undefined = undefined;
let hasNegativeCycle: boolean | undefined;
if (scanNegativeCycle) hasNegativeCycle = false;
if (!srcVertex) return {hasNegativeCycle, distMap, preMap, paths, min, minPath};
@ -598,15 +559,18 @@ export abstract class AbstractGraph<V extends AbstractVertex, E extends Abstract
if (genPath) {
for (const vertex of vertices) {
const path: V[] = [vertex[1]];
let parent = preMap.get(vertex[1]);
while (parent !== undefined) {
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 !== undefined) {
path.push(parent);
parent = preMap.get(parent);
}
const reversed = path.reverse();
if (vertex[1] === minDest) minPath = reversed;
paths.push(reversed);
}
const reversed = path.reverse();
if (vertex[1] === minDest) minPath = reversed;
paths.push(reversed);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 907 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 921 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 777 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

View file

@ -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 {IDirectedGraph, TopologicalStatus, VertexId} from '../types';
export class DirectedVertex extends AbstractVertex {
constructor(id: VertexId) {
@ -34,25 +35,8 @@ export class DirectedEdge extends AbstractEdge {
}
}
export interface I_DirectedGraph<V, E> {
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<V extends DirectedVertex, E extends DirectedEdge> extends AbstractGraph<V, E> implements I_DirectedGraph<V, E> {
export class DirectedGraph<V extends DirectedVertex, E extends DirectedEdge> extends AbstractGraph<V, E> implements IDirectedGraph<V, E> {
protected _outEdgeMap: Map<V, E[]> = new Map<V, E[]>();
@ -120,12 +104,12 @@ export class DirectedGraph<V extends DirectedVertex, E extends DirectedEdge> ext
const srcOutEdges = this._outEdgeMap.get(src);
if (srcOutEdges) {
arrayRemove<E>(srcOutEdges, edge => edge.dest === dest.id);
arrayRemove<E>(srcOutEdges, (edge: DirectedEdge) => edge.dest === dest.id);
}
const destInEdges = this._inEdgeMap.get(dest);
if (destInEdges) {
removed = arrayRemove<E>(destInEdges, edge => edge.src === src.id)[0] || null;
removed = arrayRemove<E>(destInEdges, (edge: DirectedEdge) => edge.src === src.id)[0] || null;
}
return removed;
}
@ -137,12 +121,12 @@ export class DirectedGraph<V extends DirectedVertex, E extends DirectedEdge> 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<V extends DirectedVertex, E extends DirectedEdge> 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<V extends DirectedVertex, E extends DirectedEdge> 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<vector<int>> g;
// vector<int> color;
// int last;
@ -247,14 +231,14 @@ export class DirectedGraph<V extends DirectedVertex, E extends DirectedEdge> 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<V, TopologicalStatus> = new Map<V, TopologicalStatus>();
const statusMap: Map<V | VertexId, TopologicalStatus> = new Map<V, TopologicalStatus>();
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) {

View file

@ -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<V extends UndirectedVertex, E extends UndirectedEdge> extends AbstractGraph<V, E> {
protected _edges: Map<V, E[]> = new Map();
constructor() {
super();
}
protected _edges: Map<V, E[]> = new Map();
getEdge(v1: V | null | VertexId, v2: V | null | VertexId): E | null {
let edges: E[] | undefined = [];
@ -74,11 +75,11 @@ export class UndirectedGraph<V extends UndirectedVertex, E extends UndirectedEdg
const v1Edges = this._edges.get(vertex1);
let removed: E | null = null;
if (v1Edges) {
removed = arrayRemove<E>(v1Edges, e => e.vertices.includes(vertex2.id))[0] || null;
removed = arrayRemove<E>(v1Edges, (e: UndirectedEdge) => e.vertices.includes(vertex2.id))[0] || null;
}
const v2Edges = this._edges.get(vertex2);
if (v2Edges) {
arrayRemove<E>(v2Edges, e => e.vertices.includes(vertex1.id));
arrayRemove<E>(v2Edges, (e: UndirectedEdge) => e.vertices.includes(vertex1.id));
}
return removed;
}

View file

@ -1,4 +1,4 @@
export class CoordinateSet<V> extends Map<any, V> {
export class CoordinateMap<V> extends Map<any, V> {
private readonly _joint: string = '_';
constructor(joint?: string) {

View file

@ -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';

View file

@ -1,17 +1,8 @@
import {PriorityQueue} from '../priority-queue';
export interface HeapOptions<T> {
priority?: (element: T) => number;
}
export interface HeapItem<T> {
priority: number;
element: T | null;
}
import type {HeapItem, HeapOptions} from '../types';
/**
* @copyright 2021 Pablo Rios <zrwusa@gmail.com>
* @copyright 2021 Tyler Zeng <zrwusa@gmail.com>
* @license MIT
*
* @abstract

View file

@ -1,10 +1,11 @@
/**
* @copyright 2020 Pablo Rios <zrwusa@gmail.com>
* @copyright 2020 Tyler Zeng <zrwusa@gmail.com>
* @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

View file

@ -1,10 +1,11 @@
/**
* @copyright 2020 Pablo Rios <zrwusa@gmail.com>
* @copyright 2020 Tyler Zeng <zrwusa@gmail.com>
* @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

View file

@ -8,4 +8,5 @@ export * from './heap';
export * from './priority-queue';
export * from './matrix';
export * from './trie';
export * from './types';

View file

@ -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<T> {
val: T;
@ -18,8 +12,6 @@ export class DoublyLinkedListNode<T> {
}
}
export type DoublyLinkedListGetBy = 'node' | 'val';
export class DoublyLinkedList<T> {
private _first: DoublyLinkedListNode<T> | null = null;
private _last: DoublyLinkedListNode<T> | null = null;

View file

@ -1,16 +1,4 @@
/** Type used for filter and find methods, returning a boolean */
type TTestFunction<NodeData> = (
data: NodeData,
index: number,
list: SinglyLinkedList<NodeData>,
) => boolean;
/** Type used for map and forEach methods, returning anything */
type TMapFunction<NodeData> = (
data: any,
index: number,
list: SinglyLinkedList<NodeData>,
) => 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<NodeData = any> {
*/
export class SinglyLinkedList<NodeData = any> {
/** The head of the list, the first node */
public head: SinglyLinkedListNode<NodeData> | null;
/** The tail of the list, the last node */
public tail: SinglyLinkedListNode<NodeData> | 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<NodeData = any> {
return new SinglyLinkedList(...iterable);
}
/** The head of the list, the first node */
public head: SinglyLinkedListNode<NodeData> | null;
/** The tail of the list, the last node */
public tail: SinglyLinkedListNode<NodeData> | 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

View file

@ -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++) {

View file

@ -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<T> {
matrix: T[][],
turning: Turning,
onMove: (cur: [number, number]) => void
init: {
cur: [number, number],
charDir: Direction,
VISITED: T,
}
}
export class Navigator<T = number> {
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<T>) {
this._matrix = matrix;

View file

@ -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

View file

@ -1,9 +1,10 @@
import {PriorityQueue, PriorityQueueOptions} from './priority-queue';
import {PriorityQueue} from './priority-queue';
import type {PriorityQueueOptions} from '../types';
export class MaxPriorityQueue<T = number> extends PriorityQueue<T> {
constructor(options: PriorityQueueOptions<T>) {
constructor(options?: PriorityQueueOptions<T>) {
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;
}

View file

@ -1,9 +1,10 @@
import {PriorityQueue, PriorityQueueOptions} from './priority-queue';
import {PriorityQueue} from './priority-queue';
import type {PriorityQueueOptions} from '../types';
export class MinPriorityQueue<T = number> extends PriorityQueue<T> {
constructor(options: PriorityQueueOptions<T>) {
constructor(options?: PriorityQueueOptions<T>) {
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;
}

View file

@ -1,25 +1,8 @@
export type PriorityQueueComparator<T> = (a: T, b: T) => number;
export interface PriorityQueueOptions<T> {
nodes?: T[];
isFix?: boolean;
comparator: PriorityQueueComparator<T>;
}
export type PriorityQueueDFSOrderPattern = 'pre' | 'in' | 'post';
import type {PriorityQueueComparator, PriorityQueueDFSOrderPattern, PriorityQueueOptions} from '../types';
export class PriorityQueue<T = number> {
protected nodes: T[] = [];
get size(): number {
return this.nodes.length;
}
protected readonly _comparator: PriorityQueueComparator<T> = (a: T, b: T) => {
const aKey = a as unknown as number, bKey = b as unknown as number;
return aKey - bKey;
};
constructor(options: PriorityQueueOptions<T>) {
const {nodes, comparator, isFix = true} = options;
this._comparator = comparator;
@ -31,64 +14,18 @@ export class PriorityQueue<T = number> {
}
}
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<T>(options: PriorityQueueOptions<T>) {
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<T>(options: Omit<PriorityQueueOptions<T>, 'isFix'>) {
return new PriorityQueue({...options, isFix: true}).isValid();
}
offer(node: T) {
@ -194,14 +131,69 @@ export class PriorityQueue<T = number> {
return visitedNode;
}
static heapify<T>(options: PriorityQueueOptions<T>) {
const heap = new PriorityQueue(options);
heap._fix();
return heap;
protected readonly _comparator: PriorityQueueComparator<T> = (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<T>(options: Omit<PriorityQueueOptions<T>, '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 ---

View file

@ -50,7 +50,7 @@ export class ObjectDeque<T> {
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<T> {
pollLast() {
if (!this._size) return;
let value = this.peekLast();
const value = this.peekLast();
delete this._nodes[this._last];
this._last--;
this._size--;

View file

@ -1,7 +1,6 @@
/**
* @license MIT
* @copyright 2020 Pablo
*
* @copyright 2020 Tyler Zeng <zrwusa@gmail.com>
* @class
*/
export class Queue<T> {
@ -17,6 +16,17 @@ export class Queue<T> {
this._offset = 0;
}
/**
* Creates a queue from an existing array.
* @public
* @static
* @param {array} elements
* @return {Queue}
*/
static fromArray<T>(elements: T[]): Queue<T> {
return new Queue(elements);
}
/**
* Adds an element at the back of the queue.
* @public
@ -109,15 +119,4 @@ export class Queue<T> {
clone(): Queue<T> {
return new Queue(this._nodes.slice(this._offset));
}
/**
* Creates a queue from an existing array.
* @public
* @static
* @param {array} elements
* @return {Queue}
*/
static fromArray<T>(elements: T[]): Queue<T> {
return new Queue(elements);
}
}

View file

@ -1,7 +1,6 @@
/**
* @license MIT
* @copyright 2020 Pablo Rios <zrwusa@gmail.com>
*
* @copyright 2020 Tyler Zeng <zrwusa@gmail.com>
* @class
*/
export class Stack<T> {
@ -15,6 +14,17 @@ export class Stack<T> {
this._elements = Array.isArray(elements) ? elements : [];
}
/**
* Creates a stack from an existing array
* @public
* @static
* @param {array} [elements]
* @return {Stack}
*/
static fromArray<T>(elements: T[]): Stack<T> {
return new Stack(elements);
}
/**
* Checks if the stack is empty.
* @public
@ -90,15 +100,4 @@ export class Stack<T> {
clone(): Stack<T> {
return new Stack(this._elements.slice());
}
/**
* Creates a stack from an existing array
* @public
* @static
* @param {array} [elements]
* @return {Stack}
*/
static fromArray<T>(elements: T[]): Stack<T> {
return new Stack(elements);
}
}

View file

@ -1,91 +1,51 @@
export type ArgumentTypes<T extends (...args: any[]) => 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<T> extends Function {
__THUNK__: typeof THUNK_SYMBOL;
(): T;
export const isThunk = (fnOrValue: any) => {
return typeof fnOrValue === 'function' && fnOrValue.__THUNK__ === THUNK_SYMBOL
}
export type ThunkOrValue<T> = T | Thunk<T>;
type ToThunkFn = () => ReturnType<TrlFn>;
export type UnwrapThunkDeep<T> = {
0: T extends Thunk<infer U> ? UnwrapThunkDeep<U> : T;
}[
T extends ThunkOrValue<T> ? 0 : never
];
type Thunk = () => ReturnType<ToThunkFn> & { __THUNK__: typeof THUNK_SYMBOL };
export const isThunk = <T>(value: any): value is Thunk<T> => {
return typeof value === 'function' && value.__THUNK__ === THUNK_SYMBOL;
};
export const toThunk = <R>(fn: () => R): Thunk<R> => {
const thunk = () => fn();
thunk.__THUNK__ = THUNK_SYMBOL;
return thunk;
};
export type UnwrapPromise<T> = T extends Promise<infer U> ? Exclude<U, Promise<T>> : T;
export type Unbox<T> = UnwrapThunkDeep<UnwrapPromise<T>>;
export type Cont<A extends any[], R> = (...args: A) => Thunk<Unbox<R>>;
export interface Trampoline<F extends ((...args: any[]) => any)> {
(...args: ArgumentTypes<F>): Unbox<ReturnType<F>>;
cont: Cont<ArgumentTypes<F>, ReturnType<F>>;
export const toThunk = (fn: ToThunkFn): Thunk => {
const thunk = () => fn()
thunk.__THUNK__ = THUNK_SYMBOL
return thunk
}
export interface TrampolineAsync<F extends ((...args: any[]) => any)> {
(...args: ArgumentTypes<F>): Promise<Unbox<ReturnType<F>>>;
cont: Cont<ArgumentTypes<F>, ReturnType<F>>;
}
export const trampoline = <F extends ((...args: any[]) => any)>(fn: F): Trampoline<F> => {
const cont = (...args: ArgumentTypes<F>) => toThunk(() => fn(...args));
type TrlFn = (...args: any[]) => any;
export const trampoline = (fn: TrlFn) => {
const cont = (...args: [...Parameters<TrlFn>]) => toThunk(() => fn(...args))
return Object.assign(
(...args: ArgumentTypes<F>): Unbox<ReturnType<F>> => {
let result: ThunkOrValue<ReturnType<F>> = fn(...args);
(...args: [...Parameters<TrlFn>]) => {
let result = fn(...args)
while (isThunk<ReturnType<F>>(result)) {
result = result();
while (isThunk(result) && typeof result === 'function') {
result = result()
}
return result;
return result
},
{cont},
);
};
{cont}
)
}
export const trampolineAsync = <F extends ((...args: any[]) => any)>(fn: F): TrampolineAsync<F> => {
const cont = (...args: ArgumentTypes<F>) => toThunk(() => fn(...args));
type TrlAsyncFn = (...args: any[]) => any;
export const trampolineAsync = (fn: TrlAsyncFn) => {
const cont = (...args: [...Parameters<TrlAsyncFn>]) => toThunk(() => fn(...args))
return Object.assign(
async (...args: ArgumentTypes<F>): Promise<Unbox<ReturnType<F>>> => {
let result: ThunkOrValue<ReturnType<F>> = await fn(...args);
async (...args: [...Parameters<TrlAsyncFn>]) => {
let result = await fn(...args)
while (isThunk<ReturnType<F>>(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<number> => {
return n
// Note: calling factorial.cont instead of factorial directly
? factorial.cont(n - 1, acc * n)
: acc;
});
// factorial(32768)
{cont}
)
}

View file

@ -1,5 +1,13 @@
export class TrieNode {
protected _children: Map<string, TrieNode> = new Map<string, TrieNode>();
protected _value;
constructor(v: string) {
this._value = v;
this._isEnd = false;
this._children = new Map<string, TrieNode>();
}
protected _children: Map<string, TrieNode>;
get children(): Map<string, TrieNode> {
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[] = [];

View file

@ -0,0 +1,51 @@
export type VertexId = string | number;
export type DijkstraResult<V> =
{ distMap: Map<V, number>, preMap: Map<V, V | null>, seen: Set<V>, paths: V[][], minDist: number, minPath: V[] }
| null;
export interface IGraph<V, E> {
containsVertex(vertexOrId: V | VertexId): boolean;
getVertex(vertexOrId: VertexId | V): V | null;
getVertexId(vertexOrId: V | VertexId): VertexId;
vertexSet(): Map<VertexId, V>;
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[];
}

View file

@ -0,0 +1,6 @@
import {AVLTreeNode} from '../binary-tree';
export interface AVLTreeDeleted<T> {
deleted: AVLTreeNode<T> | null;
needBalanced: AVLTreeNode<T> | null;
}

View file

@ -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<T> = { deleted: BinaryTreeNode<T> | null | undefined, needBalanced: BinaryTreeNode<T> | null };
export type ResultByProperty<T> = T | BinaryTreeNode<T> | number | BinaryTreeNodeId;
export type ResultsByProperty<T> = ResultByProperty<T>[];
export interface BinaryTreeNodeObj<T> {
id: BinaryTreeNodeId;
val: T;
count?: number;
}

View file

@ -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<T> = { deleted: BSTNode<T> | null, needBalanced: BSTNode<T> | null };

View file

@ -0,0 +1,18 @@
import {VertexId} from './abstract-graph';
export interface IDirectedGraph<V, E> {
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;

View file

@ -0,0 +1 @@
export type DoublyLinkedListGetBy = 'node' | 'val';

View file

@ -0,0 +1,8 @@
export interface HeapOptions<T> {
priority?: (element: T) => number;
}
export interface HeapItem<T> {
priority: number;
element: T | null;
}

View file

@ -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';

View file

@ -0,0 +1,13 @@
export type Direction = 'up' | 'right' | 'down' | 'left';
export type Turning = { [key in Direction]: Direction };
export interface NavigatorParams<T> {
matrix: T[][],
turning: Turning,
onMove: (cur: [number, number]) => void
init: {
cur: [number, number],
charDir: Direction,
VISITED: T,
}
}

View file

@ -0,0 +1,9 @@
export type PriorityQueueComparator<T> = (a: T, b: T) => number;
export interface PriorityQueueOptions<T> {
nodes?: T[];
isFix?: boolean;
comparator: PriorityQueueComparator<T>;
}
export type PriorityQueueDFSOrderPattern = 'pre' | 'in' | 'post';

View file

@ -0,0 +1 @@
export type SegmentTreeNodeVal = number;

View file

@ -0,0 +1,15 @@
import {SinglyLinkedList} from '../linked-list';
/** Type used for filter and find methods, returning a boolean */
export type TTestFunction<NodeData> = (
data: NodeData,
index: number,
list: SinglyLinkedList<NodeData>,
) => boolean;
/** Type used for map and forEach methods, returning anything */
export type TMapFunction<NodeData> = (
data: any,
index: number,
list: SinglyLinkedList<NodeData>,
) => any;

View file

@ -0,0 +1,3 @@
import {BSTNode} from '../binary-tree';
export type TreeMultiSetDeletedResult<T> = { deleted: BSTNode<T> | null, needBalanced: BSTNode<T> | null };

View file

@ -74,9 +74,9 @@ export type DebounceOptions = {
};
export interface DebouncedFunction<F extends Procedure> {
(this: ThisParameterType<F>, ...args: Parameters<F>): void;
cancel: () => void;
(this: ThisParameterType<F>, ...args: [...Parameters<F>]): void;
}
export type MonthKey =
@ -123,10 +123,10 @@ export class TreeNode<T> {
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<T> {
export type OrderType = 'InOrder' | 'PreOrder' | 'PostOrder'
export type DeepProxy<T> = T extends (...args: any[]) => infer R
? (...args: [...Parameters<T>]) => DeepProxy<R>
: T extends object
? { [K in keyof T]: DeepProxy<T[K]> }
: 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> = T extends (...args: infer Args) => infer R
? Args extends [infer Arg, ...infer RestArgs]
? (arg: Arg) => CurryFunc<(...args: RestArgs) => R>
: R
: T;

View file

@ -1 +0,0 @@
export * from './utils';

View file

1
src/utils/index.ts Normal file
View file

@ -0,0 +1 @@
export * from './utils';

View file

@ -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 = <T, K extends keyof T>(obj: T, names: K[]): Array<T[K]> => {
return names.map(i => obj[i]);
};
export const getValue = <T, K extends keyof T>(obj: T, names: K[]): Array<T[K]> => 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 = <T>(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<Item>(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 = <T>(otherArray: T[], limitKeys?: string[]) => {
return function (current: T) {
@ -349,17 +265,11 @@ export const comparerArray = <T>(otherArray: T[], limitKeys?: string[]) => {
};
};
export const onlyInA = <T>(a: T[], b: T[]) => {
return a.filter(comparerArray(b));
};
export const onlyInA = <T>(a: T[], b: T[]) => a.filter(comparerArray(b));
export const onlyInB = <T>(a: T[], b: T[]) => {
return b.filter(comparerArray(a));
};
export const onlyInB = <T>(a: T[], b: T[]) => b.filter(comparerArray(a));
export const diffAB = <T>(a: T[], b: T[]) => {
return onlyInA(a, b).concat(onlyInB(a, b));
};
export const diffAB = <T>(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<T = number, T1 = number>(array1: T[], array2: T1[], options?
}
}
return isToObj ? zippedObjCoords : zipped;
}
}

View file

@ -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"
]