Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added problem-1/01-undirected-graph.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added problem-1/02-adjacency-matrix.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added problem-1/03-adjacency-list.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
56 changes: 45 additions & 11 deletions problem-1/BFS.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,58 @@
const { Queue } = require('../data-structure/Queue');
const { Stack } = require('../data-structure/Stack');

class BFS {
#marked = [];
#visited = [];

#edgeTo = [];
#previousVertexOf = [];
Comment on lines -2 to +7
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

어떤 이름이 더 좋을까 고민해서 변경해 보셨군요. 도메인을 제대로 이해하지 못하면 이름 짓는 것 조차 어려울 수 있는데, 이를 통해 내가 얼마나 잘 이해했는지 확인해볼 수 있겠네요.


#s;
#startVertex;

constructor(graph, s) {
this.#marked = Array.from({ length: graph.v() }, () => false);
this.#edgeTo = Array.from({ length: graph.v() }, () => undefined);
this.#s = s;
this.#bfs(graph, s);
constructor(graph, startVertex) {
this.#visited = Array.from({ length: graph.sizeOfVertices() }, () => false);
this.#previousVertexOf = Array.from({ length: graph.sizeOfVertices() }, () => undefined);
this.#startVertex = startVertex;
this.#bfs(graph, startVertex);
}

#bfs(graph, s) {
#bfs(graph, startVertex) {
const queue = new Queue();

this.#visited[startVertex] = true;
queue.enqueue(startVertex);

while (!queue.isEmpty()) {
const currentVertex = queue.dequeue();

for (const adjacentVertex of graph.adjacencyList(currentVertex)) {
if (!this.#visited[adjacentVertex]) {
this.#previousVertexOf[adjacentVertex] = currentVertex;
this.#visited[adjacentVertex] = true;
queue.enqueue(adjacentVertex);
}
}
}
}

hasPathTo(v) {
// 해당 정점이 연결되어 있는지 안 되어 있는지 반환한다.
hasPathTo(vertex) {
return this.#visited[vertex];
}

pathTo(v) {
pathTo(vertex) {
// 해당 정점에 연결된 정점이 없다 = 해당 정점으로 갈 경로가 없다.
if (!this.hasPathTo(vertex)) {
return;
}

const pathToVertex = new Stack();
for (let item = vertex; item !== this.#startVertex; item = this.#previousVertexOf[item]) {
pathToVertex.push(item);
}

pathToVertex.push(this.#startVertex);

return pathToVertex;
}
}

Expand Down
30 changes: 29 additions & 1 deletion problem-1/ConnectedComponents.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,36 @@
class ConnectedComponents {
#visited = [];

#groupIds = [];

#groupId = 0;

constructor(graph) {
this.#visited = Array.from({ length: graph.sizeOfVertices() }, () => false);
this.#groupIds = Array.from({ length: graph.sizeOfVertices() }, () => undefined);

for (let i = 0; i < graph.sizeOfVertices(); i++) {
if (!this.#visited[i]) {
this.#dfs(graph, i);
this.#groupId++;
}
}
}

#dfs(graph, vertex) {
this.#visited[vertex] = true;
this.#groupIds[vertex] = this.#groupId; // 아이디를 기록한다.

// 인접한 정점을 모두 확인한다.
for (const adjacentVertex of graph.adjacencyList(vertex)) {
if (!this.#visited[adjacentVertex]) {
this.#dfs(graph, adjacentVertex);
}
}
}

connected(v, w) {
connected(vertex1, vertex2) {
return this.#groupIds[vertex1] === this.#groupIds[vertex2];
}
}

Expand Down
46 changes: 35 additions & 11 deletions problem-1/DFS.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,50 @@
const { Stack } = require('../data-structure/Stack');

class DFS {
#marked = [];
#visited = [];

#edgeTo = [];
#previousVertexOf = [];

#s;
#startVertex;

constructor(graph, s) {
this.#marked = Array.from({ length: graph.v() }, () => false);
this.#edgeTo = Array.from({ length: graph.v() }, () => undefined);
this.#s = s;
this.#dfs(graph, s);
constructor(graph, startVertex) {
this.#visited = Array.from({ length: graph.sizeOfVertices() }, () => false);
this.#previousVertexOf = Array.from({ length: graph.sizeOfVertices() }, () => undefined);
this.#startVertex = startVertex;
this.#dfs(graph, startVertex);
}

#dfs(grpah, v) {
#dfs(graph, currentVertex) {
// 선택한 정점의 방문 여부 체크
this.#visited[currentVertex] = true;

for (const adjacentVertex of graph.adjacencyList(currentVertex)) {
if (!this.#visited[adjacentVertex]) { // 방문한 적 없는 인접 정점일 경우
this.#previousVertexOf[adjacentVertex] = currentVertex; // currentVertex 로부터 방문했다고 기록한다.
this.#dfs(graph, adjacentVertex);
}
}
}

hasPathTo(v) {
// 해당 정점이 연결되어 있는지 안 되어 있는지 반환한다.
hasPathTo(vertex) {
return this.#visited[vertex];
}

pathTo(v) {
pathTo(vertex) {
// 해당 정점에 연결된 정점이 없다 = 해당 정점으로 갈 경로가 없다.
if (!this.hasPathTo(vertex)) {
return;
}

const pathToVertex = new Stack();
for (let item = vertex; item !== this.#startVertex; item = this.#previousVertexOf[item]) {
pathToVertex.push(item);
}

pathToVertex.push(this.#startVertex);

return pathToVertex;
}
}

Expand Down
35 changes: 18 additions & 17 deletions problem-1/Graph.js
Original file line number Diff line number Diff line change
@@ -1,35 +1,36 @@
const { Bag } = require('../data-structure/Bag');

class Graph {
#v;
#numberOfVertices;

#e;
#numberOfEdges;

#adj = [];
#adjacencyList = [];

constructor(v) {
this.#v = v;
for (let i = 0; i < this.#v; i++) {
this.#adj[i] = new Bag();
constructor(numberOfVertices) {
this.#numberOfVertices = numberOfVertices;

for (let i = 0; i < this.#numberOfVertices; i++) {
this.#adjacencyList[i] = new Bag();
}
}

addEdge(v, w) {
this.#adj[v].add(w);
this.#adj[w].add(v);
this.#e++;
addEdge(source, destination) {
this.#adjacencyList[source].add(destination);
this.#adjacencyList[destination].add(source);
this.#numberOfEdges++;
}

adj(v) {
return this.#adj[v];
adjacencyList(vertex) {
return this.#adjacencyList[vertex];
}

v() {
return this.#v;
sizeOfVertices() {
return this.#numberOfVertices;
}

e() {
return this.#e;
sizeOfEdges() {
return this.#numberOfEdges;
}
}

Expand Down
5 changes: 5 additions & 0 deletions problem-1/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,17 @@
8 1
4 1
```
![01-undirected-graph.png](01-undirected-graph.png)

2. 위의 그려진 그래프를 인접 행렬로 표현되는 데이터 구조를 그림으로 그려주세요.

![02-adjacency-matrix.png](02-adjacency-matrix.png)

3. 위의 그려진 그래프를 인접 리스트로 표현되는 데이터 구조로 그림으로
그려주세요.

![03-adjacency-list.png](03-adjacency-list.png)

4. 위의 그래프에서 10번 노드에서 6번 노드로 DFS를 할 때 어떤 경로를 통해서 가는지 구하는 함수를 구현해 주세요.

5. 마찬가지로 10번 노드에서 6번 노드로 BFS를 할 때 어떤 경로를 통해서 가는지 함수를 구하는 구현해 주세요.
Expand Down
32 changes: 16 additions & 16 deletions problem-2/Diagraph.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,34 @@
const { Bag } = require('../data-structure/Bag');

class Diagraph {
#v;
#numberOfVertices;

#e;
#numberOfEdges;

#adj = [];
#adjacencyList = [];

constructor(v) {
this.#v = v;
for (let i = 0; i < this.#v; i++) {
this.#adj[i] = new Bag();
constructor(numberOfVertices) {
this.#numberOfVertices = numberOfVertices;
for (let i = 0; i < this.#numberOfVertices; i++) {
this.#adjacencyList[i] = new Bag();
}
}

addEdge(v, w) {
this.#adj[v].add(w);
this.#e++;
addEdge(source, destination) {
this.#adjacencyList[source].add(destination);
this.#numberOfEdges++;
}

adj(v) {
return this.#adj[v];
adjacencyList(vertex) {
return this.#adjacencyList[vertex];
}

v() {
return this.#v;
sizeOfVertices() {
return this.#numberOfVertices;
}

e() {
return this.#e;
sizeOfEdges() {
return this.#numberOfEdges;
}
}

Expand Down
50 changes: 43 additions & 7 deletions problem-2/DirectedCycle.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,63 @@
const { Stack } = require('../data-structure/Stack');

class DirectedCycle {
#marked = [];
#visited = [];

#edgeTo = [];
#previousVertexOf = [];

#onStack = [];
#visiting = [];

#cycle;

constructor(diagraph) {
this.#marked = Array.from({ length: diagraph.v() }, () => false);
this.#edgeTo = Array.from({ length: diagraph.v() }, () => undefined);
this.#onStack = Array.from({ length: diagraph.v() }, () => false);
this.#visited = Array.from({ length: diagraph.sizeOfVertices() }, () => false);
this.#previousVertexOf = Array.from({ length: diagraph.sizeOfVertices() }, () => undefined);
this.#visiting = Array.from({ length: diagraph.sizeOfVertices() }, () => false);

for (let vertex = 0; vertex < diagraph.sizeOfVertices(); vertex++) {
if (!this.#visited[vertex]) {
this.#dfs(diagraph, vertex);
}
}
}

#dfs(diagraph, v) {
#dfs(diagraph, vertex) {
this.#visited[vertex] = true; // 방문했음을 체크
this.#visiting[vertex] = true; // 현재 방문 중임을 체크

// todo : 인접한 정점을 돌면서 순환 경로(cycle)이 있는지 체크하기
for (const adjacentVertex of diagraph.adjacencyList(vertex)) {
if (this.hasCycle()) { // 이미 순환경로가 있다면 종료
return;
}

if (!this.#visited[adjacentVertex]) { // 만약 방문한 적 없는 인접 정점이라면
this.#previousVertexOf[adjacentVertex] = vertex; // 현재 정점에서 방문했다고 기록
this.#dfs(diagraph, adjacentVertex); // 해당 인접 정점에 인접하는 정점을 돌면서 재귀적으로 실행
} else if (this.#visiting[adjacentVertex]) {
// 현재의 인접 정점이 방문도 했고, 현재 방문중인 정점이라면 -> 순환한다는 것
this.#cycle = new Stack(); // 순환 경로를 기록할 stack 생성

for (let v = vertex; v !== adjacentVertex; v = this.#previousVertexOf[v]) {
// 현재 정점이 어디에서부터 왔는지 거슬러 올라가면서 순환 경로 스택에 추가한다.
this.#cycle.push(v);
}

// 목적지와 출발지 담기
this.#cycle.push(adjacentVertex);
this.#cycle.push(vertex);
}
}

this.#visiting[vertex] = false;
}

hasCycle() {
return !!this.#cycle;
}

cycle() {
return this.#cycle;
}
}

Expand Down
23 changes: 17 additions & 6 deletions problem-2/DirectedDFS.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,26 @@
class DirectedDFS {
#marked = [];
#visited = [];

constructor(diagraph, s) {
this.#marked = Array.from({ length: diagraph.v() }, () => false);
this.#dfs(diagraph, s);
constructor(diagraph, startVertex) {
this.#visited = Array.from({ length: diagraph.sizeOfVertices() }, () => false);
this.#dfs(diagraph, startVertex);
}

#dfs(diagraph, v) {
#dfs(diagraph, vertex) {
// 현재 정점을 방문했다고 표시
this.#visited[vertex] = true;

// 인접한 정점에서 체크하기
for (const adjacentVertex of diagraph.adjacencyList(vertex)) {
// 현재의 인접한 정점에 방문한 적이 없을 경우
if (!this.#visited[adjacentVertex]) {
this.#dfs(diagraph, adjacentVertex);
}
}
}

reachable(v) {
reachable(vertex) {
return this.#visited[vertex]; // 방문한 적이 있는 정점이라면 도달 가능한 것.
}
}

Expand Down
Loading