첫 정점을 기준으로 배열을 선언하여 첫 정점에서 각 정점까지의 거리를 저장
우선순위 큐에서 추출한 (A, 0)노드인 첫 노드와의 거리를 기반으로 인접한 노드와의 거리 계산
우선순위 큐에서 (C, 1) 노드인 첫 노드와의 거리를 기반으로 인접한 노드와의 거리 계산
이런식으로 계속 새로운 인접노드를 확인하고 배열을 최소거리로 업데이트 해주면서 반복해준다
큐에서 꺼낸 노드의 비용이 배열에 적혀있는 비용보다 크거나 같다면 비교할 필요도없이 스킵하면된다
배열을 이용한 구현
Graph g = new Graph(8);
g.input(1, 2, 3);
g.input(1, 5, 4);
g.input(1, 4, 4);
g.input(2, 3, 2);
g.input(3, 4, 1);
g.input(4, 5, 2);
g.input(5, 6, 4);
g.input(4, 7, 6);
g.input(7, 6, 3);
g.input(3, 8, 3);
g.input(6, 8, 2);
g.dijkstra(1);
class Graph
{
private int N;
private int[][] maps;
public Graph(int n)
{
this.N = n;
maps = new int[N+1][N+1];
}
public void input (int i, int j, int w)
{
maps[i][j] = w;
maps[j][i] = w;
}
public void dijkstra(int v)
{
int[] distances = new int[N+1];
boolean[] visited = new boolean[N+1];
for (int i = 1; i < N+1; i++)
distances[i] = Integer.MAX_VALUE;
distances[v] = 0;
visited[v] = true;
for (int i = 1; i < N+1; i++)
{
if (!visited[i] && maps[v][i] != 0) //방문했고 0이 아니라면 (방문했으면 무한값은 아니다)
distances[i] = maps[v][i];
}
for (int all = 0; all < N-1; all++)
{
int min = Integer.MAX_VALUE;
int min_idx = -1;
for (int i = 1; i < N+1; i++) {
if (!visited[i] && distances[i] != Integer.MAX_VALUE) {
if (distances[i] < min){
min = distances[i];
min_idx = i;
}
}
}
visited[min_idx] = true;
for (int i = 1; i < N+1; i++) {
if (!visited[i] && maps[min_idx][i] != 0){
if (distances[i] > distances[min_idx] + maps[min_idx][i])
{
distances[i] = distances[min_idx] + maps[min_idx][i];
}
}
}
for (int i = 1; i < N+1; i++)
System.out.print(distances[i] + " ");
System.out.println();
}
}
}
Priority Queue를 이용한 구현
public class Dijkstra_algorithm {
public static void main(String[] args) throws IOException {
Dijkstra_pq(0);
}
private static void Dijkstra_pq(int start) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
//정점의 개수 , 간선의 개수
int V = Integer.parseInt(st.nextToken());
int E = Integer.parseInt(st.nextToken());
List<Edge>[] adj = new ArrayList[V];
for (int i = 0; i < V; i++)
adj[i] = new ArrayList<>();
//간선의 출발, 도착, 가중치를 읽어들여서 그래프의 연결상태를 저장
for (int i = 0; i < E; i++) {
//출발 노드, 도착 노드, 가중치
st = new StringTokenizer(br.readLine());
int from = Integer.parseInt(st.nextToken());
int dest = Integer.parseInt(st.nextToken());
int weigth = Integer.parseInt(st.nextToken());
adj[from].add(new Edge(dest, weigth));
}
//우선순위 큐, 방문 체크
PriorityQueue<Edge> pq = new PriorityQueue<>();
boolean[] check = new boolean[V];
//첫노드로부터의 모든 노드들의 거리배열
Edge[] D = new Edge[V];
//배열중 출발 노드만 거리가 0 나머지는 최대값으로 설정
for (int i = 0; i < V; i++){
if (i == start)
D[i] = new Edge(i, 0);
else
D[i] = new Edge(i, Integer.MAX_VALUE);
}
//우선순위큐에 시작 노드를 넣고 시작
pq.add(D[start]);
while (!pq.isEmpty())
{
//우선순위 큐에 가장 위에있는 노드 및 가중치를 가져온다
Edge nowV = pq.poll();
//edge.v에 연결되어있는 간선 리스트를 가져온다
for (Edge nextV : adj[nowV.v]){
//시작노드부터 다음 노드에 대한 기존 가중치보다 지금까지의 경로 + 다음 노드로의 경로 가중치 합이 더 작다면 변경
if (!check[nextV.v] && D[nextV.v].weight > D[nowV.v].weight + nextV.weight) {
D[nextV.v].weight = D[nowV.v].weight + nextV.weight;
pq.add(D[nextV.v]);
}
}
check[nowV.v] = true;
}
System.out.println(Arrays.toString(D));
}
}
class Edge implements Comparable<Edge> {
int v, weight;
public Edge(int v, int weight) {
this.v = v;
this.weight = weight;
}
@Override
public int compareTo(Edge o) {
return Integer.compare(this.weight, o.weight);
}
@Override
public String toString() {
return weight + " ";
}
}
입력
4 5
0 1 2
0 2 3
1 3 1
0 3 5
1 2 1
출력
[0 , 2 , 3 , 3 ]
1 각 노드마다 인접한 간선들을 모두 검사하는 과정
2 우선순위 큐에 노드/거리 정보를 넣고 삭제(poll)하는 과정
과정 1 시간복잡도
각 노드는 최대 한 번씩 방문하므로(첫노드와 해당노드간 길이 있다면), 최대 그래프의 모든 간선의 개수인 O(E)이다
과정 2 시간복잡도
우선순위 큐에 가장 많은 (노드, 거리)정보가 들어가는 경우는 그래프의 모든 간선이 검사 될 때마다, 배열의 최단 거리가 변경되고, 우선순위 큐에 (노드, 거리)가 추가되는 경우이다
따라서, 이 때 추가는 간선마다 최대 한번씩 일어날 수 있으므로 최대 O(E)의 시간이 소요되며, O(E)개의 (노드, 거리)정보에 대해 우선순위 큐를 유지하는 작업은 MinHeap유지시간인 O(logE)가 걸린다
결론적으로 O(E * logE) 이다
과정1 + 2의 시간복잡도가 소요되고 O(ElogE)의 시간이 소요된다
안녕하세요. 패스트캠퍼스입니다. 자료구조/알고리즘은 강의에서 나온 자료의 코드를 그대로 업로드하시거나, 아예 자료 설명과 이미지까지 모두 그대로 올린 경우가 다수 보여집니다. 저작권 침해 사례로 모두 우선 캡쳐하였습니다. 이미 관련 자료에도 저작권적인 유의사항을 기재하였음에도, 이렇게 업로드 하신 부분에 대해, 저작권 침해 의도가 의심할만한 정황이 많습니다. 이에 금주 재방문시까지도 관련 블로그글이 그대로 남아 있을 경우, 저작권 침해 의도가 상당함을 인지하고, 법적 절차를 진행하겠습니다. 따라서, 관련 글들은 모두 내려주시길 마지막으로 안내드립니다.