-
반응형
1. 크루스칼 알고리즘 동작 원리...?
a) 간선의 가중치를 오름차순으로 sort
b) (sort 되었으니까) 간선을 하나씩 확인하며
사이클 발생 O: MST에 포함 X
사이클 발생 X: MST에 포함 O
c) 모든 간선에 대해 b) 과정을 해줌
사실 수업을 들을 때도 말로만 설명을 들으니까 확실히 이해가 되지 않아서
코드를 짠 후, 그 코드를 분석해보았다.
2. 크루스칼 알고리즘 코드 분석
graph = { 'vertices':['A','B','C','D','E','F','G'], 'edges':[ (7, 'A', 'B'), (5, 'A', 'D'), (7, 'B', 'A'), (8, 'B', 'C'), (9, 'B', 'D'), (7, 'B', 'E'), (8, 'C', 'B'), (5, 'C', 'E'), (5, 'D', 'A'), (9, 'D', 'B'), (7, 'D', 'E'), (6, 'D', 'F'), (7, 'E', 'B'), (5, 'E', 'C'), (7, 'E', 'D'), (8, 'E', 'F'), (9, 'E', 'G'), (6, 'F', 'D'), (8, 'F', 'E'), (11, 'F', 'G'), (9, 'G', 'E'), (11, 'G', 'F') ] } parent = dict() #각각의 노드마다 부모노드 저장 rank = dict() #각각의 노드마다 rank def make_set(node): #초기화 함수) parent[node] = node rank[node] = 0 def find(node): #path compression기법 사용하여 최상위 정점 확인 if parent[node] != node: parent[node] = find(parent[node]) return parent[node] def union(node_v, node_u): #각각의 루트노드를 찾아내기(find함수 활용) root1 = find(node_v) root2 = find(node_u) #union-by rank 기법 if rank[root1]>rank[root2]: #rank가 낮은 root노드의 parent를 rank가 높은 곳과 연결 parent[root2] = root1 else: parent[root1] = root2 if rank[root1] == rank[root2]: #같으면 일단 합쳐주고 붙임 당한 노드의 랭크를 올려주기 rank[root2] += 1 def kruskal(graph): mst = list() #노드 초기화 for node in graph['vertices']: make_set(node) #graph의 edge를 간선 가중치 기준으로 오름차순 sort edges = graph['edges'] edges.sort()#edges는 sort된 간선정보 for edge in edges: #sort된 간선들을 하나씩 합치는 작업(사이클 없이) weight, node_v, node_u = edge if find(node_v) != find(node_u): union(node_v, node_u) mst.append(edge) return mst
- 초기 세팅: edge 정보를 (weight, node_v, node_u) 형태로 세팅 / 각 노드마다 부모 노드를 저장하는 parent(dictionary) / 각 노드마다의 rank를 저장하는 rank(dictionary)
- 모든 정점 A~G에 대해 make_set() 함수를 통해 초기화를 해줌 (parent를 자기 자신으로 설정, rank를 0으로 설정)
- graph dictionary에 있는 edges 리스트를 weight 기준으로 sort 하여 edges 리스트에 담아줌
- edges안에 있는 요소들을 하나씩 훑어주면서
a) node_v와 node_u가 같은 root_node를 가지고 있으면 skip -> 사이클이 생길 수 있기 때문
예를 들어 이 상황에서 C와 F를 연결한다고 하자
C와 F의 root_node는 모두 E이고 둘을 연결했을 때 사이클이 생기는 것을 확인할 수 있다.
b) 사이클 생성 여부를 판단한 뒤
c) path compression기법을 사용하여 node_v와 node_u의 root_node를 찾아낸다.
d) union-by rank기법을 사용하여 rank를 적절히 조절해준 뒤, 노드를 연결시켜준다.
e) b)에서 사이클을 만들지 않은 edge들을 weight 오름차순대로 하나씩 mst리스트에 append 해주면
mst에 들어간 edge들을 순서대로 확인할 수 있다.
정리를 나름대로 해보긴 했는데, 쉽게 설명을 못한 것 같네요 ㅠㅠ
3. 시간 복잡도...?
- O(E log E) E는 간선
1. 각 노드를 초기화할 때 -> O(V)
2. 간선을 가중치 기준으로 오름차순 sort 할 때 -> O(E log E) 퀵 소트 사용하면
3. 간선을 한 바퀴 돌면서 합치는 과정 -> O(E)
결국 sorting 하는 프로세스를 제외하면 상수 시간 복잡도이기 때문에
전체 시간 복잡도는 O(E log E)이다.
반응형'IT > 자료구조 & 알고리즘' 카테고리의 다른 글
[자료구조] 신장트리(Spanning Tree) & 최소 신장 트리(MST) (0) 2021.08.21 [알고리즘] 깊이 우선 탐색(DFS) (Python) (0) 2021.08.08 [알고리즘] 너비 우선 탐색(BFS) (Python) (0) 2021.08.08 [자료구조] 그래프(Graph) (Python) (0) 2021.08.08 댓글