The Graph's API has been optimized.

This commit is contained in:
Revone 2023-08-28 11:15:04 +08:00
parent 363c66490a
commit de5a001b6a
10 changed files with 296 additions and 403 deletions

526
README.md
View file

@ -204,22 +204,6 @@ wide range of data structures
DFS, DFSIterative, BFS, morris, Bellman-Ford Algorithm, Dijkstra's Algorithm, Floyd-Warshall Algorithm, Tarjan's Algorithm
# How
[API Docs](https://data-structure-typed-docs.vercel.app)
[Live Examples](https://data-structure-typed-examples.vercel.app)
![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/examples/dfs-pre-order.webp)
![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/examples/test-graphs.webp)
![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/examples/cut-off-trees-for-golf.webp)
![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/examples/parenthesis-check.webp)
<a href="https://data-structure-typed-examples.vercel.app" target="_blank">Live Examples</a>
## install
### yarn
@ -236,367 +220,160 @@ npm install data-structure-typed
### Binary Search Tree (BST) snippet
#### TS
```typescript
import {BST, BSTNode} from 'data-structure-typed';
const tree = new BST();
expect(tree).toBeInstanceOf(BST);
const ids = [11, 3, 15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5];
tree.addMany(ids);
expect(tree.root).toBeInstanceOf(BSTNode);
if (tree.root) expect(tree.root.id).toBe(11);
expect(tree.count).toBe(16);
expect(tree.has(6)).toBe(true);
const node6 = tree.get(6);
expect(node6 && tree.getHeight(node6)).toBe(2);
expect(node6 && tree.getDepth(node6)).toBe(3);
const nodeId10 = tree.get(10, 'id');
expect(nodeId10?.id).toBe(10);
const nodeVal9 = tree.get(9, 'val');
expect(nodeVal9?.id).toBe(9);
const nodesByCount1 = tree.getNodes(1, 'count');
expect(nodesByCount1.length).toBe(16);
const leftMost = tree.getLeftMost();
const bst = new BST();
bst.add(11);
bst.add(3);
bst.addMany([15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5]);
bst.size === 16; // true
bst.has(6); // true
const node6 = bst.get(6);
bst.getHeight(6) === 2; // true
bst.getHeight() === 5; // true
bst.getDepth(6) === 3; // true
const leftMost = bst.getLeftMost();
leftMost?.id === 1; // true
expect(leftMost?.id).toBe(1);
bst.remove(6);
bst.get(6); // null
bst.isAVLBalanced(); // true or false
const bfsIDs = bst.BFS();
bfsIDs[0] === 11; // true
expect(bfsIDs[0]).toBe(11);
const objBST = new BST<BSTNode<{ id: number, keyA: number }>>();
objBST.add(11, {id: 11, keyA: 11});
objBST.add(3, {id: 3, keyA: 3});
objBST.addMany([{id: 15, keyA: 15}, {id: 1, keyA: 1}, {id: 8, keyA: 8},
{id: 13, keyA: 13}, {id: 16, keyA: 16}, {id: 2, keyA: 2},
{id: 6, keyA: 6}, {id: 9, keyA: 9}, {id: 12, keyA: 12},
{id: 14, keyA: 14}, {id: 4, keyA: 4}, {id: 7, keyA: 7},
{id: 10, keyA: 10}, {id: 5, keyA: 5}]);
objBST.remove(11);
const avlTree = new AVLTree();
avlTree.addMany([11, 3, 15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5])
avlTree.isAVLBalanced(); // true
avlTree.remove(10);
avlTree.isAVLBalanced(); // true
const node15 = tree.get(15);
const minNodeBySpecificNode = node15 && tree.getLeftMost(node15);
expect(minNodeBySpecificNode?.id).toBe(12);
```
#### JS
```javascript
const {BST, BSTNode} = require('data-structure-typed');
const subTreeSum = node15 && tree.subTreeSum(node15);
expect(subTreeSum).toBe(70);
const bst = new BST();
bst.add(11);
bst.add(3);
bst.addMany([15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5]);
bst.size === 16; // true
bst.has(6); // true
const node6 = bst.get(6);
bst.getHeight(6) === 2; // true
bst.getHeight() === 5; // true
bst.getDepth(6) === 3; // true
const leftMost = bst.getLeftMost();
leftMost?.id === 1; // true
expect(leftMost?.id).toBe(1);
bst.remove(6);
bst.get(6); // null
bst.isAVLBalanced(); // true or false
const bfsIDs = bst.BFS();
bfsIDs[0] === 11; // true
expect(bfsIDs[0]).toBe(11);
const objBST = new BST();
objBST.add(11, {id: 11, keyA: 11});
objBST.add(3, {id: 3, keyA: 3});
objBST.addMany([{id: 15, keyA: 15}, {id: 1, keyA: 1}, {id: 8, keyA: 8},
{id: 13, keyA: 13}, {id: 16, keyA: 16}, {id: 2, keyA: 2},
{id: 6, keyA: 6}, {id: 9, keyA: 9}, {id: 12, keyA: 12},
{id: 14, keyA: 14}, {id: 4, keyA: 4}, {id: 7, keyA: 7},
{id: 10, keyA: 10}, {id: 5, keyA: 5}]);
objBST.remove(11);
const avlTree = new AVLTree();
avlTree.addMany([11, 3, 15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5])
avlTree.isAVLBalanced(); // true
avlTree.remove(10);
avlTree.isAVLBalanced(); // true
const lesserSum = tree.lesserSum(10);
expect(lesserSum).toBe(45);
expect(node15).toBeInstanceOf(BSTNode);
if (node15 instanceof BSTNode) {
const subTreeAdd = tree.subTreeAdd(node15, 1, 'count');
expect(subTreeAdd).toBeDefined();
}
const node11 = tree.get(11);
expect(node11).toBeInstanceOf(BSTNode);
if (node11 instanceof BSTNode) {
const allGreaterNodesAdded = tree.allGreaterNodesAdd(node11, 2, 'count');
expect(allGreaterNodesAdded).toBeDefined();
}
const dfsInorderNodes = tree.DFS('in', 'node');
expect(dfsInorderNodes[0].id).toBe(1);
expect(dfsInorderNodes[dfsInorderNodes.length - 1].id).toBe(16);
tree.balance();
expect(tree.isBalanced()).toBe(true);
const bfsNodesAfterBalanced = tree.BFS('node');
expect(bfsNodesAfterBalanced[0].id).toBe(8);
expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].id).toBe(16);
const removed11 = tree.remove(11, true);
expect(removed11).toBeInstanceOf(Array);
expect(removed11[0]).toBeDefined();
expect(removed11[0].deleted).toBeDefined();
if (removed11[0].deleted) expect(removed11[0].deleted.id).toBe(11);
expect(tree.isAVLBalanced()).toBe(true);
expect(node15 && tree.getHeight(node15)).toBe(2);
const removed1 = tree.remove(1, true);
expect(removed1).toBeInstanceOf(Array);
expect(removed1[0]).toBeDefined();
expect(removed1[0].deleted).toBeDefined();
if (removed1[0].deleted) expect(removed1[0].deleted.id).toBe(1);
expect(tree.isAVLBalanced()).toBe(true);
expect(tree.getHeight()).toBe(4);
// The code for removing these nodes (4, 10, 15, 5, 13, 3, 8, 6, 7, 9, 14) in sequence has been omitted.
expect(tree.isAVLBalanced()).toBe(false);
const bfsIDs = tree.BFS();
expect(bfsIDs[0]).toBe(2);
expect(bfsIDs[1]).toBe(12);
expect(bfsIDs[2]).toBe(16);
const bfsNodes = tree.BFS('node');
expect(bfsNodes[0].id).toBe(2);
expect(bfsNodes[1].id).toBe(12);
expect(bfsNodes[2].id).toBe(16);
```
### Directed Graph simple snippet
#### TS or JS
```typescript
import {DirectedGraph, DirectedVertex, DirectedEdge, VertexId} from 'data-structure-typed';
import {DirectedGraph} from 'data-structure-typed';
let graph: DirectedGraph<DirectedVertex, DirectedEdge>;
beforeEach(() => {
graph = new DirectedGraph();
});
it('should add vertices', () => {
const vertex1 = new DirectedVertex('A');
const vertex2 = new DirectedVertex('B');
graph._addVertexOnly(vertex1);
graph._addVertexOnly(vertex2);
expect(graph.hasVertex(vertex1)).toBe(true);
expect(graph.hasVertex(vertex2)).toBe(true);
});
it('should add edges', () => {
const vertex1 = new DirectedVertex('A');
const vertex2 = new DirectedVertex('B');
const edge = new DirectedEdge('A', 'B');
graph._addVertexOnly(vertex1);
graph._addVertexOnly(vertex2);
graph._addEdgeOnly(edge);
expect(graph.hasEdge('A', 'B')).toBe(true);
expect(graph.hasEdge('B', 'A')).toBe(false);
});
it('should remove edges', () => {
const vertex1 = new DirectedVertex('A');
const vertex2 = new DirectedVertex('B');
const edge = new DirectedEdge('A', 'B');
graph._addVertexOnly(vertex1);
graph._addVertexOnly(vertex2);
graph._addEdgeOnly(edge);
expect(graph.removeEdge(edge)).toBe(edge);
expect(graph.hasEdge('A', 'B')).toBe(false);
});
it('should perform topological sort', () => {
const vertexA = new DirectedVertex('A');
const vertexB = new DirectedVertex('B');
const vertexC = new DirectedVertex('C');
const edgeAB = new DirectedEdge('A', 'B');
const edgeBC = new DirectedEdge('B', 'C');
graph._addVertexOnly(vertexA);
graph._addVertexOnly(vertexB);
graph._addVertexOnly(vertexC);
graph._addEdgeOnly(edgeAB);
graph._addEdgeOnly(edgeBC);
const topologicalOrder = graph.topologicalSort();
if (topologicalOrder) expect(topologicalOrder.map(v => v.id)).toEqual(['A', 'B', 'C']);
});
const graph = new DirectedGraph();
graph.addVertex('A');
graph.addVertex('B');
graph.hasVertex('A'); // true
graph.hasVertex('B'); // true
graph.hasVertex('C'); // false
graph.addEdge('A', 'B');
graph.hasEdge('A', 'B'); // true
graph.hasEdge('B', 'A'); // false
graph.removeEdgeSrcToDest('A', 'B');
graph.hasEdge('A', 'B'); // false
graph.addVertex('C');
graph.addEdge('A', 'B');
graph.addEdge('B', 'C');
const topologicalOrderIds = graph.topologicalSort(); // ['A', 'B', 'C']
```
### Directed Graph complex snippet
### Undirected Graph snippet
#### TS or JS
```typescript
import {DirectedGraph, DirectedVertex, DirectedEdge, VertexId} from 'data-structure-typed';
import {UndirectedGraph} from 'data-structure-typed';
class MyVertex extends DirectedVertex {
private _data: string;
get data(): string {
return this._data;
}
set data(value: string) {
this._data = value;
}
constructor(id: VertexId, data: string) {
super(id);
this._data = data;
}
}
class MyEdge extends DirectedEdge {
private _data: string;
get data(): string {
return this._data;
}
set data(value: string) {
this._data = value;
}
constructor(v1: VertexId, v2: VertexId, weight: number, data: string) {
super(v1, v2, weight);
this._data = data;
}
}
describe('DirectedGraph Test3', () => {
const myGraph = new DirectedGraph<MyVertex, MyEdge>();
it('should test graph operations', () => {
const vertex1 = new MyVertex(1, 'data1');
const vertex2 = new MyVertex(2, 'data2');
const vertex3 = new MyVertex(3, 'data3');
const vertex4 = new MyVertex(4, 'data4');
const vertex5 = new MyVertex(5, 'data5');
const vertex6 = new MyVertex(6, 'data6');
const vertex7 = new MyVertex(7, 'data7');
const vertex8 = new MyVertex(8, 'data8');
const vertex9 = new MyVertex(9, 'data9');
myGraph._addVertexOnly(vertex1);
myGraph._addVertexOnly(vertex2);
myGraph._addVertexOnly(vertex3);
myGraph._addVertexOnly(vertex4);
myGraph._addVertexOnly(vertex5);
myGraph._addVertexOnly(vertex6);
myGraph._addVertexOnly(vertex7);
myGraph._addVertexOnly(vertex8);
myGraph._addVertexOnly(vertex9);
myGraph._addEdgeOnly(new MyEdge(1, 2, 10, 'edge-data1-2'));
myGraph._addEdgeOnly(new MyEdge(2, 1, 20, 'edge-data2-1'));
expect(myGraph.getEdge(1, 2)).toBeTruthy();
expect(myGraph.getEdge(2, 1)).toBeTruthy();
expect(myGraph.getEdge(1, '100')).toBeFalsy();
myGraph.removeEdgeBetween(1, 2);
expect(myGraph.getEdge(1, 2)).toBeFalsy();
myGraph._addEdgeOnly(new MyEdge(3, 1, 3, 'edge-data-3-1'));
myGraph._addEdgeOnly(new MyEdge(1, 9, 19, 'edge-data1-9'));
myGraph._addEdgeOnly(new MyEdge(9, 7, 97, 'edge-data9-7'));
myGraph._addEdgeOnly(new MyEdge(7, 9, 79, 'edge-data7-9'));
myGraph._addEdgeOnly(new MyEdge(1, 4, 14, 'edge-data1-4'));
myGraph._addEdgeOnly(new MyEdge(4, 7, 47, 'edge-data4-7'));
myGraph._addEdgeOnly(new MyEdge(1, 2, 12, 'edge-data1-2'));
myGraph._addEdgeOnly(new MyEdge(2, 3, 23, 'edge-data2-3'));
myGraph._addEdgeOnly(new MyEdge(3, 5, 35, 'edge-data3-5'));
myGraph._addEdgeOnly(new MyEdge(5, 7, 57, 'edge-data5-7'));
myGraph._addEdgeOnly(new MyEdge(7, 3, 73, 'edge-data7-3'));
const topologicalSorted = myGraph.topologicalSort();
expect(topologicalSorted).toBeNull();
const minPath1to7 = myGraph.getMinPathBetween(1, 7);
expect(minPath1to7).toBeInstanceOf(Array);
if (minPath1to7 && minPath1to7.length > 0) {
expect(minPath1to7).toHaveLength(3);
expect(minPath1to7[0]).toBeInstanceOf(MyVertex);
expect(minPath1to7[0].id).toBe(1);
expect(minPath1to7[1].id).toBe(9);
expect(minPath1to7[2].id).toBe(7);
}
const fordResult1 = myGraph.bellmanFord(1);
expect(fordResult1).toBeTruthy();
expect(fordResult1.hasNegativeCycle).toBeUndefined();
const {distMap, preMap, paths, min, minPath} = fordResult1;
expect(distMap).toBeInstanceOf(Map);
expect(distMap.size).toBe(9);
expect(distMap.get(vertex1)).toBe(0);
expect(distMap.get(vertex2)).toBe(12);
expect(distMap.get(vertex3)).toBe(35);
expect(distMap.get(vertex4)).toBe(14);
expect(distMap.get(vertex5)).toBe(70);
expect(distMap.get(vertex6)).toBe(Infinity);
expect(distMap.get(vertex7)).toBe(61);
expect(distMap.get(vertex8)).toBe(Infinity);
expect(distMap.get(vertex9)).toBe(19);
expect(preMap).toBeInstanceOf(Map);
expect(preMap.size).toBe(0);
expect(paths).toBeInstanceOf(Array);
expect(paths.length).toBe(0);
expect(min).toBe(Infinity);
expect(minPath).toBeInstanceOf(Array);
const floydResult = myGraph.floyd();
expect(floydResult).toBeTruthy();
if (floydResult) {
const {costs, predecessor} = floydResult;
expect(costs).toBeInstanceOf(Array);
expect(costs.length).toBe(9);
expect(costs[0]).toEqual([32, 12, 35, 14, 70, Infinity, 61, Infinity, 19]);
expect(costs[1]).toEqual([20, 32, 23, 34, 58, Infinity, 81, Infinity, 39]);
expect(costs[2]).toEqual([3, 15, 38, 17, 35, Infinity, 64, Infinity, 22]);
expect(costs[3]).toEqual([123, 135, 120, 137, 155, Infinity, 47, Infinity, 126]);
expect(costs[4]).toEqual([133, 145, 130, 147, 165, Infinity, 57, Infinity, 136]);
expect(costs[5]).toEqual([Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity]);
expect(costs[6]).toEqual([76, 88, 73, 90, 108, Infinity, 137, Infinity, 79]);
expect(costs[7]).toEqual([Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity, Infinity]);
expect(costs[8]).toEqual([173, 185, 170, 187, 205, Infinity, 97, Infinity, 176]);
expect(predecessor).toBeInstanceOf(Array);
expect(predecessor.length).toBe(9);
expect(predecessor[0]).toEqual([vertex2, null, vertex2, null, vertex3, null, vertex4, null, null]);
expect(predecessor[1]).toEqual([null, vertex1, null, vertex1, vertex3, null, vertex4, null, vertex1]);
expect(predecessor[5]).toEqual([null, null, null, null, null, null, null, null, null]);
expect(predecessor[7]).toEqual([null, null, null, null, null, null, null, null, null]);
expect(predecessor[8]).toEqual([vertex7, vertex7, vertex7, vertex7, vertex7, null, null, null, vertex7]);
}
const dijkstraRes12tt = myGraph.dijkstra(1, 2, true, true);
expect(dijkstraRes12tt).toBeTruthy();
if (dijkstraRes12tt) {
const {distMap, minDist, minPath, paths, preMap, seen} = dijkstraRes12tt;
expect(distMap).toBeInstanceOf(Map);
expect(distMap.size).toBe(9);
expect(distMap.get(vertex1)).toBe(0);
expect(distMap.get(vertex2)).toBe(12);
expect(distMap.get(vertex3)).toBe(Infinity);
expect(distMap.get(vertex4)).toBe(14);
expect(distMap.get(vertex5)).toBe(Infinity);
expect(distMap.get(vertex6)).toBe(Infinity);
expect(distMap.get(vertex7)).toBe(Infinity);
expect(distMap.get(vertex8)).toBe(Infinity);
expect(distMap.get(vertex9)).toBe(19);
expect(minDist).toBe(12);
expect(minPath).toBeInstanceOf(Array);
expect(minPath.length).toBe(2);
expect(minPath[0]).toBe(vertex1);
expect(minPath[1]).toBe(vertex2);
expect(paths).toBeInstanceOf(Array);
expect(paths.length).toBe(9);
expect(paths[0]).toBeInstanceOf(Array);
expect(paths[0][0]).toBe(vertex1);
expect(paths[1]).toBeInstanceOf(Array);
expect(paths[1][0]).toBe(vertex1);
expect(paths[1][1]).toBe(vertex2);
expect(paths[2]).toBeInstanceOf(Array);
expect(paths[2][0]).toBe(vertex3);
expect(paths[3]).toBeInstanceOf(Array);
expect(paths[3][0]).toBe(vertex1);
expect(paths[3][1]).toBe(vertex4);
expect(paths[4]).toBeInstanceOf(Array);
expect(paths[4][0]).toBe(vertex5);
expect(paths[5]).toBeInstanceOf(Array);
expect(paths[5][0]).toBe(vertex6);
expect(paths[6]).toBeInstanceOf(Array);
expect(paths[6][0]).toBe(vertex7);
expect(paths[7]).toBeInstanceOf(Array);
expect(paths[7][0]).toBe(vertex8);
expect(paths[8]).toBeInstanceOf(Array);
expect(paths[8][0]).toBe(vertex1);
expect(paths[8][1]).toBe(vertex9);
}
});
});
const graph = new UndirectedGraph();
graph.addVertex('A');
graph.addVertex('B');
graph.addVertex('C');
graph.addVertex('D');
graph.removeVertex('C');
graph.addEdge('A', 'B');
graph.addEdge('B', 'D');
const dijkstraResult = graph.dijkstra('A');
Array.from(dijkstraResult?.seen ?? []).map(vertex => vertex.id) // ['A', 'B', 'D']
```
[API Docs](https://data-structure-typed-docs.vercel.app)
[Live Examples](https://data-structure-typed-examples.vercel.app)
![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/examples/dfs-pre-order.webp)
![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/examples/test-graphs.webp)
![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/examples/cut-off-trees-for-golf.webp)
![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/examples/parenthesis-check.webp)
<a href="https://data-structure-typed-examples.vercel.app" target="_blank">Live Examples</a>
## API docs
@ -875,29 +652,40 @@ describe('DirectedGraph Test3', () => {
![complexities of data structures](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/assets/data-structure-complexities.jpg)
![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/binary-tree/bst-rotation.gif)
[//]: # (![]&#40;https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/binary-tree/bst-rotation.gif&#41;)
![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/binary-tree/avl-tree-inserting.gif)
[//]: # ()
[//]: # (![]&#40;https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/binary-tree/avl-tree-inserting.gif&#41;)
![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/graph/tarjan.webp)
[//]: # ()
[//]: # (![]&#40;https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/graph/tarjan.webp&#41;)
![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/graph/adjacency-list.jpg)
[//]: # ()
[//]: # (![]&#40;https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/graph/adjacency-list.jpg&#41;)
![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/graph/adjacency-list-pros-cons.jpg)
[//]: # ()
[//]: # (![]&#40;https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/graph/adjacency-list-pros-cons.jpg&#41;)
![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/graph/adjacency-matrix.jpg)
[//]: # ()
[//]: # (![]&#40;https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/graph/adjacency-matrix.jpg&#41;)
![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/graph/adjacency-matrix-pros-cons.jpg)
[//]: # ()
[//]: # (![]&#40;https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/graph/adjacency-matrix-pros-cons.jpg&#41;)
![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/graph/dfs-can-do.jpg)
[//]: # ()
[//]: # (![]&#40;https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/graph/dfs-can-do.jpg&#41;)
![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/graph/edge-list.jpg)
[//]: # ()
[//]: # (![]&#40;https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/graph/edge-list.jpg&#41;)
![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/graph/edge-list-pros-cons.jpg)
[//]: # ()
[//]: # (![]&#40;https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/graph/edge-list-pros-cons.jpg&#41;)
![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/graph/max-flow.jpg)
[//]: # ()
[//]: # (![]&#40;https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/graph/max-flow.jpg&#41;)
![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/graph/mst.jpg)
[//]: # ()
[//]: # (![]&#40;https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/graph/mst.jpg&#41;)
[//]: # (![]&#40;https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/graph/tarjan-articulation-point-bridge.png&#41;)

View file

@ -1,6 +1,6 @@
{
"name": "data-structure-typed",
"version": "1.18.7",
"version": "1.18.8",
"description": "Explore our comprehensive Javascript Data Structure / TypeScript Data Structure Library, meticulously crafted to empower developers with a versatile set of essential data structures. Our library includes a wide range of data structures, such as 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, Doubly Linked List, Priority Queue, Max Priority Queue, Min Priority Queue, Queue, ObjectDeque, ArrayDeque, Stack, and Trie. Each data structure is thoughtfully designed and implemented using TypeScript to provide efficient, reliable, and easy-to-use solutions for your programming needs. Whether you're optimizing algorithms, managing data, or enhancing performance, our TypeScript Data Structure Library is your go-to resource. Elevate your coding experience with these fundamental building blocks for software development.",
"main": "dist/index.js",
"scripts": {

View file

@ -199,7 +199,7 @@ export abstract class AbstractGraph<V extends AbstractVertex<any>, E extends Abs
addEdge(edge: E): boolean
addEdge(src: V | VertexId, dest: V | VertexId, weight: number, val?: E['val']): boolean
addEdge(src: V | VertexId, dest: V | VertexId, weight?: number, val?: E['val']): boolean
addEdge(srcOrEdge: V | VertexId | E, dest?: V | VertexId, weight?: number, val?: E['val']): boolean {
if (srcOrEdge instanceof AbstractEdge) {

View file

@ -330,13 +330,17 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
return destinations;
}
/**
* The `topologicalSort` function performs a topological sort on a directed graph and returns the sorted vertices in
* reverse order, or null if the graph contains a cycle.
* @returns The function `topologicalSort()` returns an array of `V` or `VertexId` objects in
* topological order, or `null` if there is a cycle in the graph.
* The `topologicalSort` function performs a topological sort on a graph and returns an array of vertices or vertex IDs
* in the sorted order, or null if the graph contains a cycle.
* @param {'vertex' | 'id'} [propertyName] - The `propertyName` parameter is an optional parameter that specifies the
* property to use for sorting the vertices. It can have two possible values: 'vertex' or 'id'. If 'vertex' is
* specified, the vertices themselves will be used for sorting. If 'id' is specified, the ids of
* @returns an array of vertices or vertex IDs in topological order, or null if there is a cycle in the graph.
*/
topologicalSort(): Array<V | VertexId> | null {
topologicalSort(propertyName?: 'vertex' | 'id'): Array<V | VertexId> | null {
propertyName = propertyName ?? 'id';
// 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 | VertexId, TopologicalStatus> = new Map<V | VertexId, TopologicalStatus>();
@ -344,7 +348,7 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
statusMap.set(entry[1], 0);
}
const sorted: (V | VertexId)[] = [];
let sorted: (V | VertexId)[] = [];
let hasCycle = false;
const dfs = (cur: V | VertexId) => {
statusMap.set(cur, 1);
@ -369,6 +373,7 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
if (hasCycle) return null;
if (propertyName === 'id') sorted = sorted.map(vertex => vertex instanceof DirectedVertex ? vertex.id : vertex);
return sorted.reverse();
}

View file

@ -4,13 +4,14 @@ describe('BST operations test', () => {
it('should perform various operations on a Binary Search Tree with numeric values', () => {
const bst = new BST();
expect(bst).toBeInstanceOf(BST);
const values = [11, 3, 15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5];
bst.addMany(values);
bst.add(11);
bst.add(3);
bst.addMany([15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5]);
expect(bst.root).toBeInstanceOf(BSTNode);
if (bst.root) expect(bst.root.id).toBe(11);
expect(bst.size).toBe(16);
expect(bst.count).toBe(16);
expect(bst.has(6)).toBe(true);
@ -194,16 +195,15 @@ describe('BST operations test', () => {
});
it('should perform various operations on a Binary Search Tree with object values', () => {
const objBST = new BST<BSTNode<{ id: number, keyA: number }>>({autoIncrementId: false});
const objBST = new BST<BSTNode<{ id: number, keyA: number }>>();
expect(objBST).toBeInstanceOf(BST);
const values = [{id: 11, keyA: 11}, {id: 3, keyA: 3}, {id: 15, keyA: 15}, {id: 1, keyA: 1}, {
id: 8,
keyA: 8
}, {id: 13, keyA: 13}, {id: 16, keyA: 16}, {id: 2, keyA: 2}, {id: 6, keyA: 6}, {id: 9, keyA: 9}, {
id: 12,
keyA: 12
}, {id: 14, keyA: 14}, {id: 4, keyA: 4}, {id: 7, keyA: 7}, {id: 10, keyA: 10}, {id: 5, keyA: 5}];
objBST.add(11, {id: 11, keyA: 11});
objBST.add(3, {id: 3, keyA: 3});
const values = [{id: 15, keyA: 15}, {id: 1, keyA: 1}, {id: 8, keyA: 8},
{id: 13, keyA: 13}, {id: 16, keyA: 16}, {id: 2, keyA: 2},
{id: 6, keyA: 6}, {id: 9, keyA: 9}, {id: 12, keyA: 12},
{id: 14, keyA: 14}, {id: 4, keyA: 4}, {id: 7, keyA: 7},
{id: 10, keyA: 10}, {id: 5, keyA: 5}];
objBST.addMany(values);

View file

@ -0,0 +1,54 @@
import {AVLTree, BST, BSTNode} from '../../../../src';
describe('Overall BinaryTree Test', () => {
it('should perform various operations on BinaryTree', () => {
const bst = new BST();
bst.add(11);
bst.add(3);
bst.addMany([15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5]);
bst.size === 16; // true
expect(bst.size).toBe(16); // true
bst.has(6); // true
expect(bst.has(6)).toBe(true); // true
const node6 = bst.get(6);
bst.getHeight(6) === 2; // true
bst.getHeight() === 5; // true
bst.getDepth(6) === 3; // true
expect(bst.getHeight(6)).toBe(2); // true
expect(bst.getHeight()).toBe(5); // true
expect(bst.getDepth(6)).toBe(3); // true
const leftMost = bst.getLeftMost();
leftMost?.id === 1; // true
expect(leftMost?.id).toBe(1);
bst.remove(6);
bst.get(6); // null
expect(bst.get(6)).toBeNull();
bst.isAVLBalanced(); // true or false
expect(bst.isAVLBalanced()).toBe(true);
const bfsIDs = bst.BFS();
bfsIDs[0] === 11; // true
expect(bfsIDs[0]).toBe(11);
const objBST = new BST<BSTNode<{ id: number, keyA: number }>>();
objBST.add(11, {id: 11, keyA: 11});
objBST.add(3, {id: 3, keyA: 3});
objBST.addMany([{id: 15, keyA: 15}, {id: 1, keyA: 1}, {id: 8, keyA: 8},
{id: 13, keyA: 13}, {id: 16, keyA: 16}, {id: 2, keyA: 2},
{id: 6, keyA: 6}, {id: 9, keyA: 9}, {id: 12, keyA: 12},
{id: 14, keyA: 14}, {id: 4, keyA: 4}, {id: 7, keyA: 7},
{id: 10, keyA: 10}, {id: 5, keyA: 5}]);
objBST.remove(11);
const avlTree = new AVLTree();
avlTree.addMany([11, 3, 15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5])
avlTree.isAVLBalanced(); // true
expect(avlTree.isAVLBalanced()).toBe(true); // true
avlTree.remove(10);
avlTree.isAVLBalanced(); // true
expect(avlTree.isAVLBalanced()).toBe(true); // true
});
});

View file

@ -1,4 +1,4 @@
const orderReducedBy = 3; // reduction of magnitude's order compared to the baseline magnitude
const orderReducedBy = 2; // reduction of magnitude's order compared to the baseline magnitude
export const magnitude = {
CONSTANT: Math.floor(Number.MAX_SAFE_INTEGER / Math.pow(10, orderReducedBy)),

View file

@ -59,7 +59,7 @@ describe('DirectedGraph Operation Test', () => {
graph.addEdge(edgeBC);
const topologicalOrder = graph.topologicalSort();
if (topologicalOrder) expect(topologicalOrder.map(v => v instanceof DirectedVertex ? v.id : '')).toEqual(['A', 'B', 'C']);
if (topologicalOrder) expect(topologicalOrder).toEqual(['A', 'B', 'C']);
});
});

View file

@ -0,0 +1,50 @@
import {DirectedGraph, UndirectedGraph} from '../../../../src';
describe('Overall Graph Operation Test', () => {
it('Overall DirectedGraph Operation Test', () => {
const graph = new DirectedGraph();
graph.addVertex('A');
graph.addVertex('B');
graph.hasVertex('A'); // true
graph.hasVertex('B'); // true
graph.hasVertex('C'); // false
expect(graph.hasVertex('A')).toBe(true); // true
expect(graph.hasVertex('B')).toBe(true); // true
expect(graph.hasVertex('C')).toBe(false); // false
graph.addEdge('A', 'B');
graph.hasEdge('A', 'B'); // true
graph.hasEdge('B', 'A'); // false
expect(graph.hasEdge('A', 'B')).toBe(true); // true
expect(graph.hasEdge('B', 'A')).toBe(false); // false
graph.removeEdgeSrcToDest('A', 'B');
graph.hasEdge('A', 'B'); // false
expect(graph.hasEdge('A', 'B')).toBe(false); // false
graph.addVertex('C');
graph.addEdge('A', 'B');
graph.addEdge('B', 'C');
const topologicalOrderIds = graph.topologicalSort();
expect(topologicalOrderIds).toEqual(['A', 'B', 'C'])
});
it('Overall UndirectedGraph Operation Test', () => {
const graph = new UndirectedGraph();
graph.addVertex('A');
graph.addVertex('B');
graph.addVertex('C');
graph.addVertex('D');
graph.removeVertex('C');
graph.addEdge('A', 'B');
graph.addEdge('B', 'D');
const dijkstraResult = graph.dijkstra('A');
Array.from(dijkstraResult?.seen ?? []).map(vertex => vertex.id) // ['A', 'B', 'D']
expect(Array.from(dijkstraResult?.seen ?? []).map(vertex => vertex.id)).toEqual(['A', 'B', 'D']);
});
});

View file

@ -46,19 +46,15 @@ describe('UndirectedGraph Operation Test', () => {
});
it('should perform topological sort', () => {
const vertexA = new UndirectedVertex('A');
const vertexB = new UndirectedVertex('B');
const vertexC = new UndirectedVertex('C');
const edgeAB = new UndirectedEdge('A', 'B');
const edgeBC = new UndirectedEdge('B', 'C');
graph.addVertex(vertexA);
graph.addVertex(vertexB);
graph.addVertex(vertexC);
graph.addEdge(edgeAB);
graph.addEdge(edgeBC);
graph.addVertex('A');
graph.addVertex('B');
graph.addVertex('C');
graph.addVertex('D');
graph.removeVertex('C');
graph.addEdge('A', 'B');
graph.addEdge('B', 'D');
const dijkstraResult = graph.dijkstra('A');
// TODO to be tested
expect(Array.from(dijkstraResult?.seen ?? []).map(vertex => vertex.id)).toEqual(['A', 'B', 'D']);
});
});