Skip to content

Commit f9ef9b4

Browse files
committed
Added features in Graph and added its typings
1 parent 02b3c60 commit f9ef9b4

File tree

3 files changed

+175
-3
lines changed

3 files changed

+175
-3
lines changed

src/graph/adj-list.js

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export class AdjacencyList {
99
/**
1010
* It adds node to the map and assign an empty list
1111
* If the node is already added to the map, then nothing happens
12-
* @param {any} node
12+
* @param {string|number} node
1313
*/
1414
addNode(node) {
1515
if (!this.edges.get(node)) {
@@ -19,12 +19,27 @@ export class AdjacencyList {
1919

2020
/**
2121
* It removes the node from the map
22-
* @param {any} node
22+
* @param {string|number} node
2323
*/
2424
removeNode(node) {
25+
// Remove all the edges formed by this node
26+
this.edges.forEach((val, key) => {
27+
this.removeEdge(key, node);
28+
});
29+
30+
// finally remove the node
2531
this.edges.delete(node);
2632
}
2733

34+
/**
35+
* It adds an edge from vertex fromVertex to vertex toVertex
36+
* If the verticies are not present then it first adds the missing vertex
37+
* If the graph is a diGraph then it will add edge between toVertex and fromVertex
38+
*
39+
* @param {string|number} fromVertex
40+
* @param {string|number} toVertex
41+
* @param {number} weight
42+
*/
2843
addEdge(fromVertex, toVertex, weight) {
2944
if (!this.edges.has(fromVertex)) {
3045
this.addNode(fromVertex);
@@ -40,4 +55,46 @@ export class AdjacencyList {
4055
this.edges.get(toVertex).insert(fromVertex, { weight });
4156
}
4257
}
58+
59+
/**
60+
* Remove an edge from start vertex to end vertex
61+
* @param {string|number} fromVertex
62+
* @param {string|number} toVertex
63+
*/
64+
removeEdge(fromVertex, toVertex) {
65+
if (this.edges.has(fromVertex)) {
66+
const deleteEdge = this.edges.get(fromVertex).delete(toVertex);
67+
if (deleteEdge && deleteEdge.constructor === Error) {
68+
return new Error(`No edge present between ${fromVertex} and ${toVertex}`);
69+
}
70+
} else {
71+
return new Error(`No edge present between ${fromVertex} and ${toVertex}`);
72+
}
73+
74+
// if the graph is undirected and id its the first call to the removeEdge method
75+
// set stopRecursion to true and call removeEdge method again by
76+
// swapping the parameters.
77+
if (!this.diGraph && !this.removeEdge.stopRecursion) {
78+
this.removeEdge.stopRecursion = true;
79+
this.removeEdge(toVertex, fromVertex);
80+
} else {
81+
if (this.removeEdge.stopRecursion) {
82+
this.removeEdge.stopRecursion = undefined;
83+
}
84+
}
85+
}
86+
87+
/**
88+
* It returns the weight of the edge. If the edge is not found then it returns undefined
89+
* @param {string|number} fromVertex
90+
* @param {string|number} toVertex
91+
*/
92+
getEdgeWeight(fromVertex, toVertex) {
93+
let weight;
94+
if (this.edges.has(fromVertex)) {
95+
const lookup = this.edges.get(fromVertex).lookup(toVertex);
96+
weight = lookup.hasVal ? lookup.currentNode.details.weight : void 0;
97+
}
98+
return weight ? weight : new Error(`Edge not found between ${fromVertex} and ${toVertex}`);
99+
}
43100
}

src/graph/adj-list.spec.js

Lines changed: 105 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { AdjacencyList } from './adj-list';
33
describe('Adjacency List', () => {
44
let adjList;
55
beforeEach(() => {
6-
adjList = new AdjacencyList();
6+
adjList = new AdjacencyList(true);
77
});
88

99
it('should create adjacency list object', () => {
@@ -85,4 +85,108 @@ describe('Adjacency List', () => {
8585
expect(lookupA.hasVal).toBeTruthy();
8686
});
8787
});
88+
89+
describe('Delete Edge Operation', () => {
90+
beforeEach(() => {
91+
adjList.addEdge('A', 'B');
92+
adjList.addEdge('A', 'C');
93+
});
94+
95+
it('should delete edge A -> C', () => {
96+
expect(adjList.edges.size).toBe(3);
97+
const vertexA = adjList.edges.get('A');
98+
expect(vertexA.len).toBe(2);
99+
expect(vertexA.lookup('C').hasVal).toBeTruthy();
100+
adjList.removeEdge('A', 'C');
101+
expect(vertexA.len).toBe(1);
102+
expect(vertexA.lookup('C').hasVal).toBeFalsy();
103+
});
104+
it('should return error while deleting edge D -> A', () => {
105+
expect(adjList.removeEdge('D', 'A').message).toBe('No edge present between D and A');
106+
});
107+
108+
describe('For undirectional Graph', () => {
109+
let undirectedList;
110+
beforeEach(() => {
111+
undirectedList = new AdjacencyList(false);
112+
undirectedList.addEdge('A', 'B');
113+
undirectedList.addEdge('A', 'C');
114+
});
115+
116+
it('should delete edge A -> C and edge C -> A', () => {
117+
expect(undirectedList.edges.size).toBe(3);
118+
const msg = undirectedList.removeEdge('A', 'C');
119+
expect(undirectedList.edges.get('A').lookup('C').hasVal).toBeFalsy();
120+
expect(undirectedList.edges.get('C').lookup('A').hasVal).toBeFalsy();
121+
expect(msg).toBe(void 0);
122+
});
123+
});
124+
});
125+
126+
describe('Delete Vertex Operation', () => {
127+
beforeEach(() => {
128+
adjList.addEdge('A', 'B');
129+
adjList.addEdge('A', 'C');
130+
});
131+
132+
it('should delete vertex C and finally edge A -> C', () => {
133+
expect(adjList.edges.size).toBe(3);
134+
expect(adjList.edges.get('A').len).toBe(2);
135+
expect(adjList.edges.get('A').lookup('C').hasVal).toBeTruthy();
136+
137+
adjList.removeNode('C');
138+
expect(adjList.edges.size).toBe(2);
139+
expect(adjList.edges.get('A').len).toBe(1);
140+
expect(adjList.edges.get('A').lookup('C').hasVal).toBeFalsy();
141+
});
142+
143+
describe('For undirectional Graph', () => {
144+
let undirectedList;
145+
beforeEach(() => {
146+
undirectedList = new AdjacencyList(false);
147+
undirectedList.addEdge('A', 'B');
148+
undirectedList.addEdge('A', 'C');
149+
});
150+
151+
it('should delete node C and also edges A -> C and C -> A', () => {
152+
expect(undirectedList.edges.size).toBe(3);
153+
expect(undirectedList.edges.get('A').len).toBe(2);
154+
expect(undirectedList.edges.get('A').lookup('C').hasVal).toBeTruthy();
155+
expect(undirectedList.edges.get('C').len).toBe(1);
156+
expect(undirectedList.edges.get('C').lookup('A').hasVal).toBeTruthy();
157+
158+
undirectedList.removeNode('C');
159+
160+
expect(undirectedList.edges.size).toBe(2);
161+
expect(undirectedList.edges.get('A').len).toBe(1);
162+
expect(undirectedList.edges.get('A').lookup('C').hasVal).toBeFalsy();
163+
expect(undirectedList.edges.has('C')).toBeFalsy();
164+
});
165+
});
166+
});
167+
168+
describe('Get edge weight', () => {
169+
beforeEach(() => {
170+
adjList.addEdge('A', 'B', 200);
171+
adjList.addEdge('A', 'C', 150);
172+
adjList.addEdge('B', 'C', 250);
173+
});
174+
175+
it('should get 200 as weight between edge A and B', () => {
176+
const weight = adjList.getEdgeWeight('A', 'B');
177+
expect(weight).toBe(200);
178+
});
179+
it('should get 150 as weight between edge A and C', () => {
180+
const weight = adjList.getEdgeWeight('A', 'C');
181+
expect(weight).toBe(150);
182+
});
183+
it('should get Error for weight between edge A and D', () => {
184+
const weight = adjList.getEdgeWeight('A', 'D');
185+
expect(weight.message).toBe('Edge not found between A and D');
186+
});
187+
it('should get Error for weight between edge D and A', () => {
188+
const weight = adjList.getEdgeWeight('D', 'A');
189+
expect(weight.message).toBe('Edge not found between D and A');
190+
});
191+
});
88192
});

typings/data-structures.d.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,15 @@ declare namespace DataStructures {
1717
right(): BST;
1818
right(node: BST): void;
1919
}
20+
21+
class AdjacencyList {
22+
constructor(isDiGraph: boolean);
23+
diGraph: boolean;
24+
edges: Map<string | number, BST>;
25+
addNode(node: string | number): void;
26+
removeNode(node: string | number): void;
27+
addEdge(fromVertex: string | number, toVertex: string | number, weight: number): void;
28+
removeEdge(fromVertex: string | number, toVertex: string | number): void | Error;
29+
getEdgeWeight(fromVertex: string | number, toVertex: string | number): number | Error;
30+
}
2031
}

0 commit comments

Comments
 (0)