mirror of
https://github.com/zrwusa/data-structure-typed.git
synced 2024-11-23 12:54:04 +00:00
The Graph's API has been optimized.
This commit is contained in:
parent
363c66490a
commit
de5a001b6a
526
README.md
526
README.md
|
@ -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)
|
||||
[//]: # (![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/binary-tree/bst-rotation.gif))
|
||||
|
||||
![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/binary-tree/avl-tree-inserting.gif)
|
||||
[//]: # ()
|
||||
[//]: # (![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/binary-tree/avl-tree-inserting.gif))
|
||||
|
||||
![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/graph/tarjan.webp)
|
||||
[//]: # ()
|
||||
[//]: # (![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/graph/tarjan.webp))
|
||||
|
||||
![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/graph/adjacency-list.jpg)
|
||||
[//]: # ()
|
||||
[//]: # (![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/graph/adjacency-list.jpg))
|
||||
|
||||
![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/graph/adjacency-list-pros-cons.jpg)
|
||||
[//]: # ()
|
||||
[//]: # (![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/graph/adjacency-list-pros-cons.jpg))
|
||||
|
||||
![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/graph/adjacency-matrix.jpg)
|
||||
[//]: # ()
|
||||
[//]: # (![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/graph/adjacency-matrix.jpg))
|
||||
|
||||
![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/graph/adjacency-matrix-pros-cons.jpg)
|
||||
[//]: # ()
|
||||
[//]: # (![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/graph/adjacency-matrix-pros-cons.jpg))
|
||||
|
||||
![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/graph/dfs-can-do.jpg)
|
||||
[//]: # ()
|
||||
[//]: # (![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/graph/dfs-can-do.jpg))
|
||||
|
||||
![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/graph/edge-list.jpg)
|
||||
[//]: # ()
|
||||
[//]: # (![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/graph/edge-list.jpg))
|
||||
|
||||
![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/graph/edge-list-pros-cons.jpg)
|
||||
[//]: # ()
|
||||
[//]: # (![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/graph/edge-list-pros-cons.jpg))
|
||||
|
||||
![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/graph/max-flow.jpg)
|
||||
[//]: # ()
|
||||
[//]: # (![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/graph/max-flow.jpg))
|
||||
|
||||
![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/graph/mst.jpg)
|
||||
[//]: # ()
|
||||
[//]: # (![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/graph/mst.jpg))
|
||||
|
||||
[//]: # (![](https://github.com/zrwusa/assets/blob/master/images/data-structure-typed/graph/tarjan-articulation-point-bridge.png))
|
||||
|
||||
|
|
|
@ -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": {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
54
tests/unit/data-structures/binary-tree/overall.test.ts
Normal file
54
tests/unit/data-structures/binary-tree/overall.test.ts
Normal 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
|
||||
|
||||
});
|
||||
});
|
|
@ -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)),
|
||||
|
|
|
@ -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']);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
50
tests/unit/data-structures/graph/overall.test.ts
Normal file
50
tests/unit/data-structures/graph/overall.test.ts
Normal 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']);
|
||||
});
|
||||
});
|
|
@ -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']);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue