프로그래밍/알고리즘, 프로그래밍 언어
[알고리즘] 인접 리스트(adjacency list) 자료구조- JavaScript
제이콥J
2021. 8. 23. 13:11
인접리스트 자료구조
- 정점이 어떤 정점과 인접한지를 리스트의 형태로 표현
- 메모리를 효율적으로 사용하고 싶을 때 사용
- 구조 : 시작점을 key로, '도착점들의 배열'을 값으로 가지는 객체 형태
// 인접리스트 예시 by JavaScript
{
a: [c, d], // a에서는 c와 d로 향하는 간선 있음
b: [a, c, d], // b에서는 a, c, d로 향하는 간선 있음
c : [a], // c에서는 a로 향하는 간선 있음
d : [b, c] // d에서는 b와 c로 향하는 간선 있음
}
코드 작성 포인트
1. 인접 리스트를 객체에 담기 위한 변수 선언
2. 정점을 추가하는 메소드를 구현하되, 이미 있는 정점이면 그대로 놔두기
3. 두 정점 사이 간선을 추가하는 메소드 구현 : 키의 값인 배열에 push 메소드로 요소 추가
4. 두 정점 사이 간선을 삭제하는 메소드 구현 : 배열에서 정점의 인덱스를 찾고, splice 메소드로 해당 요소 삭제
5. 정점을 삭제하는 메소드 구현 (정점과 이어진 간선도 함께 제거)
- 방법1 : 키의 값인 배열을 모두 순회하여, 삭제하려는 정점에 해당하는 요소를 splice 메소드로 간선을 삭제
- 방법2 : 삭제하려는 정점과 인접하는 정점들을 순회하여, 간선 삭제 메소드를 사용하여 간선을 삭제
코드 구현 (JavaScript)
- undefined와 null을 false 로 변경하기 (Boolean type으로 변경) : 앞에 !!를 붙여주기
- 반복문으로 모든 정점의 값인 배열을 순회하기 : Object.values(객체명) 메소드 사용
// undirected graph (무향 그래프) && adjacency list (인접 리스트)
class GraphWithAdjacencyList {
// 정점들과 인접 리스트를 담을 객체 생성
constructor() {
this.vertices = {};
}
// 정점을 추가하는 메소드 구현
addVertex(vertex) {
// 넘겨받은 인자(정점)는 키가 되며, 빈 배열을 값으로 할당
// 이미 존재하는 정점이라면, 덮어 씌워지지 않아야 함
this.vertices[vertex] = this.vertices[vertex] || [];
}
// 정점의 존재여부를 boolean 타입으로 반환하는 메소드 구현
contains(vertex) {
return !!this.vertices[vertex];
}
// 두 정점 사이 간선을 추가하는 메소드 구현 (무방향 그래프이므로 쌍방 구현)
addEdge(fromVertex, toVertex) {
// 넘겨받은 2개의 정점 모두 존재해야 하며, 아닐 경우 아무것도 하지 않기
if (!this.contains(fromVertex) || !this.contains(toVertex)) {
return;
}
// fromVertex의 인접 리스트에 toVertex를 추가
if (!this.hasEdge(fromVertex, toVertex)) {
this.vertices[fromVertex].push(toVertex);
}
// toVertex의 인접 리스트에 fromVertex를 추가
if (!this.hasEdge(toVertex, fromVertex)) {
this.vertices[toVertex].push(fromVertex)
}
}
// fromVertex와 toVertex 사이 간선의 존재여부를 확인하는 메소드
hasEdge(fromVertex, toVertex) {
// 만약 정점(fromVertex)이 존재하지 않는다면 false 반환
if (!this.contains(fromVertex)) {
return false;
}
// 존재한다면 해당 정점의 리스트에 toVertex가 포함되어 있는지 여부 반환
return !!this.vertices[fromVertex].includes(toVertex);
}
// 두 정점 사이 간선을 삭제하는 메소드
removeEdge(fromVertex, toVertex) {
// 인자로 넘겨받은 두 정점이 모두 존재하지 않는다면 아무것도 하지 않기
if (!this.contains(fromVertex) || !this.contains(toVertex)) {
return;
}
// fromVertex의 인접 리스트에 있는 toVertex를 삭제하기
if (this.hasEdge(fromVertex, toVertex)) {
const index = this.vertices[fromVertex].indexOf(toVertex);
this.vertices[fromVertex].splice(index, 1);
}
// toVertex의 인접 리스트에 있는 fromVertex를 삭제하기
if (this.hasEdge(toVertex, fromVertex)) {
const index = this.vertices[toVertex].indexOf(fromVertex);
this.vertices[toVertex].splice(index, 1);
}
}
// 정점을 삭제하는 메소드 구현 (간선도 함께 삭제하기)
removeVertex(vertex) {
// 인자로 받은 정점(vertex)가 존재할 경우에만 진행
if (this.contains(vertex)) {
// 모든 정점들의 리스트를 순회하여 전달인자의 정점(vertex)과 이어진 간선 제거
for (let arr of Object.values(this.vertices)) {
let idx = arr.indexOf(vertex);
arr.splice(idx,1)
}
// 전달인자로 주어진 정점을 삭제
delete this.vertices[vertex];
}
}
}
- 전달인자 vertex와 인접한 정점들만 순회하면서 removeEdge로 간선을 삭제하기
// removeVertex의 레퍼런스 코드
removeVertex(vertex) {
// 인자로 받은 정점(vertex)가 존재할 경우에만 진행
if (this.contains(vertex)) {
// 전달인자의 정점과 인접한 정점들만 removeEdge 메소드로 삭제
while (this.vertices[vertex].length > 0) {
this.removeEdge(this.vertices[vertex][0], vertex);
}
// 최종적으로 해당 정점을 삭제합니다
delete this.vertices[vertex];
}
}
반응형