Skip to content

Commit e02b3a5

Browse files
committed
add bfs and dfs, change directory structure
1 parent f34d29f commit e02b3a5

File tree

16 files changed

+328
-63
lines changed

16 files changed

+328
-63
lines changed

.eslintrc.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"jest/no-focused-tests": "error",
2020
"jest/no-identical-title": "error",
2121
"jest/prefer-to-have-length": "warn",
22-
"jest/valid-expect": "error"
22+
"jest/valid-expect": "error",
23+
"no-plusplus": [2, { "allowForLoopAfterthoughts": true }]
2324
}
2425
}

README.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ My personal note learn JavaScript
44
## Curriculum
55
This curriculum based on the one of (ACM-ICPC-Preparation)[https://github.com/NAU-ACM/ACM-ICPC-Preparation], but didn't follow the order.
66

7-
| | Data Structure | Algorithm | Tutorial | Questions |
8-
| --- | -------------- | --------- | -------- | --------- |
9-
| 1 | <ul><li>[Queue](/dataStructure/queue/queue.js)</li><li>[Stack](/dataStructure/stack/stack.js)</li></ul> | <ul><li>DFS</li><li>BFS</li></ul> | [Data Structures: Stacks and Queues (Youtube)](https://www.youtube.com/watch?v=wjI1WNcIntg) | <ul><li>[ Valid Parentheses](https://leetcode.com/problems/valid-parentheses/)</li><li>[Largest Rectangle in Histogram](https://leetcode.com/problems/largest-rectangle-in-histogram/)[\(my solution\)](/questions/largestRectangleArea.js)</li></ul>|
7+
| | Data Structure | Algorithm |
8+
| --- | -------------- | --------- |
9+
| 1 | <ul><li>[Queue](/dataStructure/queue/README.md)</li><li>[Stack](/dataStructure/stack/README.md)</li></ul> | <ul><li>DFS</li><li>[BFS](/algorithm/Graph/bfs/README.md)</li></ul> |
1010

1111
## algorithm
1212
1. [useful tricky (tricky methods depends on JavaScript features)](/algorithm/useful_trick.md)

algorithm/Graph/bfs/README.md

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Breadth-First-Search (BFS)
2+
Search algorithm used to traverse or serach through a graph. Start from a grpah vertex, and **traverse** all this vertext's neighboor nodes first, then move to next level.
3+
4+
## Implement Keys
5+
- For graph, we need to maintain a `visited array` to record which node is visited.
6+
- For BFS, we use queue. The FIFO data structure promise to traverse all nodes in the higher level before go to next level.
7+
- [source code](bfs.js) (I used my own queue, but in face we can just use JavaScript's array to simulate a queue, use `shift` to dequeue, `push` to enqueue).
8+
9+
## Questions
10+
- [clone graph](https://leetcode.com/problems/clone-graph/)
11+
12+
## Resource
13+
- [Graph Traversals - Breadth First and Depth First (Youtube)](https://www.youtube.com/watch?v=bIA8HEEUxZI)
14+
- [The Breadth First search algorithm (Khanacademy)](https://www.khanacademy.org/computing/computer-science/algorithms/breadth-first-search/a/the-breadth-first-search-algorithm)
15+
- [GeeksforGeeks](https://www.geeksforgeeks.org/breadth-first-search-or-bfs-for-a-graph/)

algorithm/Graph/bfs/bfs.js

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// return a BFS traversal of a graph
2+
import Queue from '../../../dataStructure/queue/queue';
3+
4+
const bfs = (graph, start) => {
5+
const visited = [];
6+
const result = [];
7+
const queue = new Queue(); // can also use JavaScript array
8+
9+
queue.add(start);
10+
const startIndex = graph.vertices.indexOf(start);
11+
visited[startIndex] = 1;
12+
13+
while (!queue.isEmpty()) {
14+
const cur = queue.remove();
15+
result.push(cur);
16+
const index = graph.vertices.indexOf(cur);
17+
visited[index] = 1;
18+
19+
const neighbors = graph.adjList.get(cur);
20+
neighbors.forEach((n) => {
21+
const nIndex = graph.vertices.indexOf(n);
22+
if (visited[nIndex]) {
23+
return;
24+
}
25+
26+
visited[nIndex] = 1;
27+
queue.add(n);
28+
});
29+
}
30+
31+
return result;
32+
};
33+
34+
export default bfs;

algorithm/Graph/bfs/bfs.test.js

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import bfs from './bfs';
2+
import Graph from '../../../dataStructure/graph/graph';
3+
4+
describe('Graph BFS', () => {
5+
const g = new Graph();
6+
const vertices = ['A', 'B', 'C', 'D', 'E', 'F'];
7+
8+
// adding vertices
9+
for (let i = 0; i < vertices.length; i++) {
10+
g.addVertex(vertices[i]);
11+
}
12+
13+
// adding edges
14+
g.addEdge('A', 'B');
15+
g.addEdge('A', 'D');
16+
g.addEdge('A', 'E');
17+
g.addEdge('B', 'C');
18+
g.addEdge('D', 'E');
19+
g.addEdge('E', 'F');
20+
g.addEdge('E', 'C');
21+
g.addEdge('C', 'F');
22+
23+
24+
it('return correct BFS traversal', () => {
25+
expect(bfs(g, 'A')).toEqual(['A', 'B', 'D', 'E', 'C', 'F']);
26+
});
27+
});

algorithm/Graph/dfs/dfs.js

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// return a DFS traversal of given graph
2+
import Stack from '../../../dataStructure/stack/stack';
3+
4+
const stackDfs = (graph, start) => {
5+
const stack = new Stack();
6+
const visited = [];
7+
const result = [];
8+
9+
const startIndex = graph.vertices.indexOf(start);
10+
visited[startIndex] = 1;
11+
stack.push(start);
12+
result.push(start);
13+
14+
while (!stack.isEmpty()) {
15+
const cur = stack.peek();
16+
const index = graph.vertices.indexOf(cur);
17+
if (!visited[index]) {
18+
result.push(cur);
19+
visited[index] = 1;
20+
}
21+
22+
const neighbors = graph.adjList.get(cur);
23+
const firstUnvisitedN = neighbors.find((n) => {
24+
const nIndex = graph.vertices.indexOf(n);
25+
return !visited[nIndex];
26+
});
27+
if (firstUnvisitedN) {
28+
stack.push(firstUnvisitedN);
29+
} else {
30+
stack.pop();
31+
}
32+
}
33+
34+
return result;
35+
};
36+
37+
// recursive version
38+
const recursiveDfsHelper = (graph, cur, visited, result) => {
39+
visited[graph.vertices.indexOf(cur)] = 1; // eslint-disable-line no-param-reassign
40+
result.push(cur);
41+
const neighbors = graph.adjList.get(cur);
42+
neighbors.forEach((n) => {
43+
if (!visited[graph.vertices.indexOf(n)]) {
44+
recursiveDfsHelper(graph, n, visited, result);
45+
}
46+
});
47+
};
48+
49+
const recursiveDfs = (graph, start) => {
50+
const visited = [];
51+
const result = [];
52+
53+
recursiveDfsHelper(graph, start, visited, result);
54+
55+
return result;
56+
};
57+
58+
export { stackDfs, recursiveDfs };

algorithm/Graph/dfs/dfs.test.js

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { stackDfs, recursiveDfs } from './dfs';
2+
import Graph from '../../../dataStructure/graph/graph';
3+
4+
const g = new Graph();
5+
const vertices = ['A', 'B', 'C', 'D', 'E', 'F'];
6+
7+
// adding vertices
8+
for (let i = 0; i < vertices.length; i++) {
9+
g.addVertex(vertices[i]);
10+
}
11+
12+
// adding edges
13+
g.addEdge('A', 'B');
14+
g.addEdge('A', 'D');
15+
g.addEdge('A', 'E');
16+
g.addEdge('B', 'C');
17+
g.addEdge('D', 'E');
18+
g.addEdge('E', 'F');
19+
g.addEdge('E', 'C');
20+
g.addEdge('C', 'F');
21+
22+
describe('Graph DFS stack version', () => {
23+
it('return correct DFS traversal', () => {
24+
expect(stackDfs(g, 'A')).toEqual(['A', 'B', 'C', 'E', 'D', 'F']);
25+
});
26+
});
27+
28+
describe('Graph DFS recursive version', () => {
29+
it('return correct DFS traversal', () => {
30+
expect(recursiveDfs(g, 'A')).toEqual(['A', 'B', 'C', 'E', 'D', 'F']);
31+
});
32+
});

algorithm/String/README.md

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
## Array
2+
### Get max, second max value of array of numbers
3+
```JavaScript
4+
const max = Math.max(...nums); // for es5, use Math.max.apply(null, nums);
5+
6+
nums[nums.indexOf(max);] = -Infinity;
7+
const secondMax = Math.max(...nums);
8+
```
9+
10+
## String
11+
### reverse string
12+
```JavaScript
13+
return s.split('').reverse().join('')
14+
```
15+
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,4 @@
1-
## Array
2-
### Get max, second max value of array of numbers
3-
```JavaScript
4-
const max = Math.max(...nums); // for es5, use Math.max.apply(null, nums);
5-
6-
nums[nums.indexOf(max);] = -Infinity;
7-
const secondMax = Math.max(...nums);
8-
```
9-
10-
## String
11-
### reverse string
12-
```JavaScript
13-
return s.split('').reverse().join('')
14-
```
15-
16-
### KMP
1+
# KMP
172
KMP is an algorithm which can be used to do pattern searching (check substring, palindrome).
183

194
The KMP matching algorithm uses degenerating property (pattern having same sub-patterns appearing more than once in the pattern) of the pattern and improves the worst case complexity to O(n). The basic idea behind KMP’s algorithm is: whenever we detect a mismatch (after some matches), we already know some of the characters in the text of the next window.
@@ -22,5 +7,3 @@ Two steps:
227
1. preprocess: get the get lps (longest proper prefix which is also suffix) array of pattern string. `lps[i]` means the lps for substring(0, i + 1).
238

249
2. search: when **mismatch**, let's say the index of pattern is j, text string index is i, which means `pattern[0, j - 1] == text[i - j, i - 1]`, and from `lps[j - 1]`, we can get the lps length. So in text[i - j, i - 1], there is a `prefix == suffix` whose length is lps[i - 1]. So, we know that the suffix of `text[0, i - 1]` will match prefix of `pattern[0, lps[j - 1]]`, so the next comparision is between `text[i]` and `pattern[lps[j - 1]]`.
25-
26-
Example: [Pattern Searching](/String/kmp.js)

algorithm/String/kmp.js renamed to algorithm/String/kmp/kmp.js

+31-34
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
* Pattern Searching
33
*
44
* Given a text txt[0..n-1] and a pattern pat[0..m-1],
5-
* write a function search(char pat[], char txt[]) that prints all occurrences index of pat[] in txt[].
5+
* write a function search(char pat[],
6+
* char txt[]) that prints all occurrences index of pat[] in txt[].
67
* You may assume that n > m.
78
*
89
* KMP (Knuth Morris Pratt) Pattern Searching
@@ -13,58 +14,54 @@
1314
* O(n)
1415
*/
1516

17+
// compute longest proper prefix (longest proper prefix which is also suffix)
18+
const computeLPS = function computeLPS(pat) {
19+
let prevLen = 0;
20+
let curIndex = 1;
21+
const lps = [0];
22+
23+
while (curIndex < pat.length) {
24+
if (pat.charAt(curIndex) === pat.charAt(prevLen)) {
25+
prevLen += 1;
26+
lps.push(prevLen);
27+
curIndex += 1;
28+
} else if (prevLen !== 0) {
29+
prevLen = lps[prevLen - 1];
30+
} else {
31+
lps.push(0);
32+
curIndex += 1;
33+
}
34+
}
35+
36+
return lps;
37+
};
1638

17-
function KMPStringMatching(pat, txt) {
39+
const KMPStringMatching = function KMPStringMatching(pat, txt) {
1840
const result = [];
1941
const lps = computeLPS(pat);
2042

21-
let patIndex = 0, txtIndex = 0;
43+
let patIndex = 0;
44+
let txtIndex = 0;
2245

2346
while (txtIndex < txt.length) {
2447
if (pat.charAt(patIndex) === txt.charAt(txtIndex)) {
25-
patIndex++;
26-
txtIndex++;
48+
patIndex += 1;
49+
txtIndex += 1;
2750
}
2851

2952
if (patIndex === pat.length) {
3053
result.push(txtIndex - patIndex);
3154
patIndex = lps[patIndex - 1];
32-
}
33-
34-
else if (txtIndex < txt.length && pat.charAt(patIndex) !== txt.charAt(txtIndex)) {
55+
} else if (txtIndex < txt.length && pat.charAt(patIndex) !== txt.charAt(txtIndex)) {
3556
if (patIndex !== 0) {
3657
patIndex = lps[patIndex - 1];
3758
} else {
38-
txtIndex++;
59+
txtIndex += 1;
3960
}
4061
}
4162
}
4263

4364
return result;
44-
}
45-
46-
// compute longest proper prefix (longest proper prefix which is also suffix)
47-
function computeLPS(pat) {
48-
let prevLen = 0;
49-
let curIndex = 1;
50-
const lps = [0];
51-
52-
while (curIndex < pat.length) {
53-
if (pat.charAt(curIndex) === pat.charAt(prevLen)) {
54-
prevLen++;
55-
lps.push(prevLen);
56-
curIndex++;
57-
} else {
58-
if (prevLen !== 0) {
59-
prevLen = lps[prevLen - 1];
60-
} else {
61-
lps.push(0);
62-
curIndex++;
63-
}
64-
}
65-
}
66-
67-
return lps;
68-
}
65+
};
6966

7067
export default KMPStringMatching;
File renamed without changes.

dataStructure/graph/graph.js

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Undirected Graph class TODO: remove vertex
2+
export default class Graph {
3+
/**
4+
* initialize a graph
5+
*/
6+
constructor() {
7+
this.vertices = [];
8+
this.adjList = new Map();
9+
}
10+
11+
/**
12+
* add vertice
13+
* @param {} vertice - vertice name (index)
14+
*/
15+
addVertex(vertice) {
16+
this.vertices.push(vertice);
17+
this.adjList.set(vertice, []);
18+
}
19+
20+
/**
21+
* connet two vertices
22+
* @param {*} v1 - name of first vertice
23+
* @param {*} v2 - name of second vertice
24+
*/
25+
addEdge(v1, v2) {
26+
this.adjList.get(v1).push(v2);
27+
this.adjList.get(v2).push(v1);
28+
}
29+
30+
toString() {
31+
let str = '';
32+
this.vertices.forEach((v) => {
33+
str += `${v} -> ${this.adjList.get(v).toString()} \n`;
34+
});
35+
36+
return str;
37+
}
38+
}

0 commit comments

Comments
 (0)