위에서 아래로 일방향, 계층구조인 트리와 다르게
그래프는 어떤 노드들과도 연결될 수 있다.
마치 지하철 노선도 처럼
다양한 그래프 종류들!
출처: https://laboputer.github.io/ps/2017/09/29/graph/
그래프는
연결점(노드)과 연결점 사이를 잇는 간선으로 이루어져 있다.
그래프는 표현하는 방법은
크게 3가지가 있다.
1. 인접리스트 (adjacency list)
모든 노드에 연결된 노드들을 순서대로 기록한 리스트
연결된 노드만 기록한다.
파이썬에서 딕셔너리를 써서 키 : 값으로 적어서 사용 많이 함.
출처: https://www.lavivienpost.net/graph-implementation-as-adjacency-list/
const graph = [[2,3],[1,3],[1,2,4],[3]]
2. 인접행렬 (adjacency matrix )
그래프에서 어느 연결점(노드)들이 변(간선)으로 연결되었는지 나타내는 정사각 행렬
출처 : 위키백과
가로 123456 세로 123456 노드
(가로,세로) (1,1) 자기 자신은 연결할 수 없어서 0
(1,2) 연결되어서 1 임
무방향 그래프에서 인접행렬은 다음과 같이 대칭이다.
const graph = [
[0, 1, 0, 0, 1, 0],
[1, 0, 1, 0, 1, 0],
[0, 1, 0, 1, 1, 0],
[0, 0, 1, 0, 1, 1],
[1, 1, 0, 1, 0, 0],
[0, 0, 0, 1, 0, 0]
]
3. 암시적 그래프
그래프의 정점과 간선을 직접적으로 표현하지 않고,
필요한 상황에서 동적으로 그래프의 일부 또는 전체를 생성하거나 탐색 하는 방식이다.
연결표시를 하지 않아도 주변이 연결되어있음을 암시적으로 알 수 있는 경우!
ex) 미로 찾기 문제
DFS(깊이우선탐색) vs BFS(너비우선탐색)
출처: 나무위키
DFS(깊이우선탐색)
노드의 간선을 타고 깊이를 우선적으로 탐색함
스택 또는 재귀함수로 구현
스택: 쌓아놓은 더미. 마지막으로 넣은 걸 먼저 꺼낼 수 있음.
(
왼쪽 살펴서 있으면 깊이 끝까지 탐색 후 오른쪽.
오른쪽 노드가 다시 첫번째 노드가 되어서 왼쪽 깊이 탐색 후 오른쪽.
반복되어 재귀함수로 구현 가능. )
BFS(너비우선탐색)
전체 너비, 행순으로 탐색함
큐로 구현
큐: 버스 앞에 줄선 사람. 먼저 선 사람이 버스 탈 수 있음.
코드는 차후에 정리해보겟음..
컴백함. 정리해보겠음
--------------------
chatgpt한테 물어봄
DFS(깊이우선탐색) 알고리즘 코드구현
def dfs (graph, start, visited ):
visited.add(start)
print (start, end=' ' )
for adjacent_node in graph[start]:
if adjacent_node not in visited:
dfs(graph, adjacent_node, visited)
graph = {
'A' : ['B' , 'C' ],
'B' : ['A' , 'D' , 'E' ],
'C' : ['A' , 'F' ],
'D' : ['B' ],
'E' : ['B' , 'F' ],
'F' : ['C' , 'E' ]
}
visited = set ()
print ("깊이 우선 탐색 결과:" )
dfs(graph, 'A' , visited)
그래프의 모든 노드를 깊이를 우선하여 탐색하는 DFS는
재귀함수 또는 스택으로 구현될 수 있다.
여기서는 재귀함수로 구현됨
코드풀이~
시작노드를 방문처리하고
그 시작노드의 인접노드가 방문하지 않은 노드라면
해당 노드를 다시 시작노드로 설정해서 재귀함수~ (다시 그 시작노드로 방문처리하고 반복)
스택으로 구현한 코드
def dfs (graph, start ):
visited = set ()
stack = [start]
while stack:
node = stack.pop()
if node not in visited:
visited.add(node)
print (node, end=' ' )
for adjacent_node in graph[node]:
if adjacent_node not in visited:
stack.append(adjacent_node)
graph = {
'A' : ['B' , 'C' ],
'B' : ['A' , 'D' , 'E' ],
'C' : ['A' , 'F' ],
'D' : ['B' ],
'E' : ['B' , 'F' ],
'F' : ['C' , 'E' ]
}
print ("깊이 우선 탐색 결과:" )
dfs(graph, 'A' )
BFS 너비탐색 알고리즘 코드구현
from collections import deque
def bfs (graph, start ):
visited = set ()
queue = deque([start])
visited.add(start)
while queue:
node = queue.popleft()
print (node, end=' ' )
for adjacent_node in graph[node]:
if adjacent_node not in visited:
queue.append(adjacent_node)
visited.add(adjacent_node)
graph = {
'A' : ['B' , 'C' ],
'B' : ['A' , 'D' , 'E' ],
'C' : ['A' , 'F' ],
'D' : ['B' ],
'E' : ['B' , 'F' ],
'F' : ['C' , 'E' ]
}
print ("너비 우선 탐색 결과:" )
bfs(graph, 'A' )
코드풀이는 다음과 같다~
선택한 시작 노드 주변을 확인.
(인접노드 확인).
확인할 애들을 큐에 저장
확인마친, 즉 방문한 애들은 방문집합에 저장.
큐가 텅빌때까지 반복
확인할 노드는 큐에서 꺼내서 씀. 맨 처음 넣은 앞에서부터 꺼낼거임
그래프의 현재 노드 주변에 있는 애들을 for문 반복문으로 다 확인해볼것임
방문집합에 해당 노드가 없다면 방문안한거니까
아까 꺼냈던 노드를 큐에다가 다시 추가
그리고 그 노드에 방문(그 노드를 탐색)한거니까 방문집합에 그 노드를 넣는다.