다익스트라
■ 다익스트라 알고리즘
1) 정의 :
자료구조로 graph 사용,
" 노드 + 가중치를 가진 간선 "을 이용하여 최단경로를 계산
2) graph 자료구조 참조
참조 : korshika.tistory.com/42?category=957674
3) 시간복잡도 :
O( E * log(E) ) ≒ O( E * log( V) )
> "최대의 경우"
모든 간선 E에 대해서 dist_history= [ ]가 한번씩 계산이 되기 때문에
간선을 queue에 작업하는 평균 시간 복잡도 O( log(E) )를 곱하면
최대 O( E * log(E) ) 에 비례,
> 일반적으로 노드는 간선보다 적기 때문에,
O( E * log( V) ) 라고 쓸 수도 있다
■ 코드 구현
1) 코드 이해코드 설명 참조 : Link
2) 코드 - 파이썬
import heapq # 복잡도 N log(N)
/*
# 유향 그래프
graph = {
'A': {'B': 8, 'C': 1, 'D': 2},
'B': {},
'C': {'B': 5, 'D': 2},
'D': {'E': 3, 'F': 5},
'E': {'F': 1},
'F': {'A': 5}
}
*/
def dijkstra(graph, start):
q = []
recordDist = {node: float('inf') for node in graph}
recordDist[start] = 0 # 시작 위치 0 distance
heapq.heappush(q, [recordDist[start], start])
while q :
curNodeDist, curNodeName = heapq.heappop(q) # 현재에서 가장 비용 낮은 순 탐색
"""
지금 방문한 node가 queue에 담긴 시점은
recordDist가 [section-b]에서 업데이트 되기 전일 수 있음
따라서 [section-a]에서 체크해줌
"""
# [section-a]
if recordDist[curNodeName] < curNodeDist:
# 여기서 연결된 노드는 더 이상 볼필요가 없음, 이미 갱신되어서
# 옛날에 queue에 담긴 탐색 결과가 더 비용이 많이 들기 때문
continue
# [section-b]
for new_dest, new_dist in graph[curNodeName].items():
total_dist = curNodeDist + new_dist
if total_dist < recordDist[new_dest]:
recordDist[new_dest] = total_dist
heapq.heappush(q, [total_dist, new_dest])
return recordDist
3) 예제
> 밑에 예제에서 확인가능 하지만, 유향 그래프로 설정하여도 되고 안해도 됨
> nested dictionary 사용
# 유향 그래프
graph = {
'A': {'B': 8, 'C': 1, 'D': 2},
'B': {},
'C': {'B': 5, 'D': 2},
'D': {'E': 3, 'F': 5},
'E': {'F': 1},
'F': {'A': 5}
}
import heapq # 우선순위 큐 구현을 위함
def dijkstra(graph, start):
distances = {node: float('inf') for node in graph} # start로 부터의 거리 값을 저장하기 위함
distances[start] = 0 # 시작 값은 0이어야 함
queue = []
heapq.heappush(queue, [distances[start], start]) # 시작 노드부터 탐색 시작 하기 위함.
while queue: # queue에 남아 있는 노드가 없으면 끝
print(f'graph : {graph}')
print(f'distances : {distances}')
print(f'before queue : {queue}')
current_distance, current_destination = heapq.heappop(queue) # 탐색 할 노드, 거리를 가져옴.
print(f'current_distance : {current_distance}, current_destination : {current_destination}')
print(f'distances[current_destination] : {distances[current_destination]}, current_distance : {current_distance}')
if distances[current_destination] < current_distance: # 기존에 있는 거리보다 길다면, 볼 필요도 없음
continue
for new_destination, new_distance in graph[current_destination].items():
distance = current_distance + new_distance # 해당 노드를 거쳐 갈 때 거리
if distance < distances[new_destination]: # 알고 있는 거리 보다 작으면 갱신
print(f'renew {new_destination} from {distances[new_destination]} to {distance}')
distances[new_destination] = distance
heapq.heappush(queue, [distance, new_destination]) # 다음 인접 거리를 계산 하기 위해 큐에 삽입
print(f'next queue : {queue}')
print('\n'*2)
return distances
print(dijkstra(graph, 'A'))
>>>
graph : {'A': {'B': 8, 'C': 1, 'D': 2}, 'B': {}, 'C': {'B': 5, 'D': 2}, 'D': {'E': 3, 'F': 5}, 'E': {'F': 1}, 'F': {'A': 5}}
distances : {'A': 0, 'B': inf, 'C': inf, 'D': inf, 'E': inf, 'F': inf}
before queue : [[0, 'A']]
current_distance : 0, current_destination : A
distances[current_destination] : 0, current_distance : 0
renew B from inf to 8
renew C from inf to 1
renew D from inf to 2
next queue : [[1, 'C'], [8, 'B'], [2, 'D']]
graph : {'A': {'B': 8, 'C': 1, 'D': 2}, 'B': {}, 'C': {'B': 5, 'D': 2}, 'D': {'E': 3, 'F': 5}, 'E': {'F': 1}, 'F': {'A': 5}}
distances : {'A': 0, 'B': 8, 'C': 1, 'D': 2, 'E': inf, 'F': inf}
before queue : [[1, 'C'], [8, 'B'], [2, 'D']]
current_distance : 1, current_destination : C
distances[current_destination] : 1, current_distance : 1
renew B from 8 to 6
next queue : [[2, 'D'], [8, 'B'], [6, 'B']]
graph : {'A': {'B': 8, 'C': 1, 'D': 2}, 'B': {}, 'C': {'B': 5, 'D': 2}, 'D': {'E': 3, 'F': 5}, 'E': {'F': 1}, 'F': {'A': 5}}
distances : {'A': 0, 'B': 6, 'C': 1, 'D': 2, 'E': inf, 'F': inf}
before queue : [[2, 'D'], [8, 'B'], [6, 'B']]
current_distance : 2, current_destination : D
distances[current_destination] : 2, current_distance : 2
renew E from inf to 5
renew F from inf to 7
next queue : [[5, 'E'], [7, 'F'], [6, 'B'], [8, 'B']]
graph : {'A': {'B': 8, 'C': 1, 'D': 2}, 'B': {}, 'C': {'B': 5, 'D': 2}, 'D': {'E': 3, 'F': 5}, 'E': {'F': 1}, 'F': {'A': 5}}
distances : {'A': 0, 'B': 6, 'C': 1, 'D': 2, 'E': 5, 'F': 7}
before queue : [[5, 'E'], [7, 'F'], [6, 'B'], [8, 'B']]
current_distance : 5, current_destination : E
distances[current_destination] : 5, current_distance : 5
renew F from 7 to 6
next queue : [[6, 'B'], [6, 'F'], [8, 'B'], [7, 'F']]
graph : {'A': {'B': 8, 'C': 1, 'D': 2}, 'B': {}, 'C': {'B': 5, 'D': 2}, 'D': {'E': 3, 'F': 5}, 'E': {'F': 1}, 'F': {'A': 5}}
distances : {'A': 0, 'B': 6, 'C': 1, 'D': 2, 'E': 5, 'F': 6}
before queue : [[6, 'B'], [6, 'F'], [8, 'B'], [7, 'F']]
current_distance : 6, current_destination : B
distances[current_destination] : 6, current_distance : 6
next queue : [[6, 'F'], [7, 'F'], [8, 'B']]
graph : {'A': {'B': 8, 'C': 1, 'D': 2}, 'B': {}, 'C': {'B': 5, 'D': 2}, 'D': {'E': 3, 'F': 5}, 'E': {'F': 1}, 'F': {'A': 5}}
distances : {'A': 0, 'B': 6, 'C': 1, 'D': 2, 'E': 5, 'F': 6}
before queue : [[6, 'F'], [7, 'F'], [8, 'B']]
current_distance : 6, current_destination : F
distances[current_destination] : 6, current_distance : 6
next queue : [[7, 'F'], [8, 'B']]
graph : {'A': {'B': 8, 'C': 1, 'D': 2}, 'B': {}, 'C': {'B': 5, 'D': 2}, 'D': {'E': 3, 'F': 5}, 'E': {'F': 1}, 'F': {'A': 5}}
distances : {'A': 0, 'B': 6, 'C': 1, 'D': 2, 'E': 5, 'F': 6}
before queue : [[7, 'F'], [8, 'B']]
current_distance : 7, current_destination : F
distances[current_destination] : 6, current_distance : 7
graph : {'A': {'B': 8, 'C': 1, 'D': 2}, 'B': {}, 'C': {'B': 5, 'D': 2}, 'D': {'E': 3, 'F': 5}, 'E': {'F': 1}, 'F': {'A': 5}}
distances : {'A': 0, 'B': 6, 'C': 1, 'D': 2, 'E': 5, 'F': 6}
before queue : [[8, 'B']]
current_distance : 8, current_destination : B
distances[current_destination] : 6, current_distance : 8
{'A': 0, 'B': 6, 'C': 1, 'D': 2, 'E': 5, 'F': 6}
참조:
[알고리즘] Dijikstra 최단경로 알고리즘
다익스트라 알고리즘의 pseudo-code와 C 코드는 위키피디아에 잘 나와 있으므로 그곳을 참고한다. 이 글은 어떻게 그 알고리즘을 생각하게 되었을까 를 내 나름대로 생각해 본 후 그에 대하여 쓴
gyrfalcon.tistory.com
www.fun-coding.org/Chapter20-shortest-live.html
파이썬과 컴퓨터 사이언스(고급 알고리즘): 최단 경로 알고리즘의 이해 - 잔재미코딩
2단계: 우선순위 큐에서 추출한 (A, 0) [노드, 첫 노드와의 거리] 를 기반으로 인접한 노드와의 거리 계산¶ 우선순위 큐에서 노드를 꺼냄 처음에는 첫 정점만 저장되어 있으므로, 첫 정점이 꺼내짐
www.fun-coding.org
justkode.kr/algorithm/python-dijkstra
Python으로 다익스트라(dijkstra) 알고리즘 구현하기
최단 경로 알고리즘은 지하철 노선도, 네비게이션 등 다방면에 사용되는 알고리즘입니다. 이번 시간에는 Python을 이용해 하나의 시작 정점으로 부터 모든 다른 정점까지의 최단 경로를 찾는 최
justkode.kr
smlee729.github.io/python/network%20analysis/2015/04/12/1-dijkstra.html
Dijkstra 알고리즘을 이용한 Minimum Cost Search | Jacob's Coding Playground
이번에 살펴볼 알고리즘은 아주 아주 많이 사용되고 또 중요한 Dijkstra 알고리즘에 대해서 알아보겠습니다. 특히나 graph theory에서는 안쓰이는 곳이 없을 정도로 많이 사용되니 반드시 잘 숙지하
smlee729.github.io