Graph

연결되어 있는 객체 간의 관계를 표현할 수 있는 자료구조로 Tree도 그래프의 일종인데 그래프 중에서도 사이클이 허용되지 않는 그래프이다.



1. 개념

  • 정점(vertex) / 노드(node) : 위치
  • 간선(edge) / 링크(link) : 위치간의 관계
  • 인접 정점 : 간선에 의해 직접 연결된 노드
  • 차수 : 하나의 노드에 인접한 노드의 수
  • 경로 길이 : 경로를 구성하는 데 사용된 간선의 수
  • 단순 경로 : 경로 중에서 반복되는 간선이 없을 경우
  • 사이클 : 단순경로의 시작 정점과 종료 정점이 동일한 경로
  • 오일러 경로 : 모든 간선을 한 번만 통과하면서 처음 정점으로 돌아오는 경로
  • 오일러 정리 : 간선이 짝수일 때만 오일러 경로가 존재
  • 부분 그래프 : 원래의 그래프의 일부 정점 및 간선으로 이루어진 그래프



2. 그래프 종류

  • 영 그래프 (null graph) : 비어있는 그래프
  • 완전 그래프 (complete graph) : 모든 노드가 서로 연결되어 있는 그래프
  • 연결 그래프 (connected graph ) : 무방향 그래프에 있는 모든 노드쌍에 대해 항상 경로가 존재한 경우
  • 정규 그래프 (regular graph) : 모든 정점이 동일한 개수의 정점을 갖는 것 ( 모든 정점의 차수가 같은 그래프)
  • 이분 그래프 (bipartite graph) : 인접한 정점끼리 서로 다른 색으로 칠해서 모든 정점을 두 가지 색으로 칠할 수 있는 그래프 ( 모든 정점이 두 그룹으로 나눠지고 같은 그룹끼리는 인접하지 않은 그래프 )
  • 완전 이분 그래프 (complete bipartite graph) : 이분 그래프 중에서도 서로 다른 그룹이라면 서로 다른 그룹끼리 모두 연결되어 있는 그래프
  • 가중치 그래프 : 간선에 가중치가 주어진 그래프 ( 가중치는 양,음 모두 가질 수 있다. )
  • 밀집 그래프 : 간선이 많이 존재하는 그래프
  • 희소 그래프 : 간선이 적은 그래프



3. 표현 방법

1) 인접 행렬 (Adjacency Matrix) ( 2차원 배열 )

정점 사이의 관계를 나타내는 행렬

해당하는 위치의 값을 통해 vertex간의 연결 관계를 O(1)로 파악할 수 있어 두 정점의 인접 여부를 체크할 때 빠르다.

배열은 노드를 n개를 갖는다고 한다면 n^2만큼 메모리가 필요하기에 희소 그래프는 메모리 낭비가 될 수 있고 정점 개수가 동적으로 변하는 경우에는 효과적이지 않다.

간선의 개수가 많은 밀집 그래프 (Dense graph) 가 적합하다.


2) 인접 리스트 (Adjacency List) ( 연결 리스트 )

노드의 개수가 n개이고 노드의 개수가 e개인 무방향 그래프를 그리는데 있어 n개의 연결 리스트, n개의 헤드 포인터, 2e개의 노드가 필요하다.

정점의 개수가 동적으로 변하는 경우 효과적이다.

간선의 개수가 적은 희소 그래프 (Sparse graph) 가 적합하다.


3) 근접 행렬 (= 발생 행렬,부속 행렬) (Incidence Matrix) (2차원 배열)

정점과 간선의 관계를 나타내는 행렬로 그래프의 정점을 행으로, 간선을 열로, 두 정점간 연결상태를 2차원 배열로 표시하는 것이다.

정점보다 간선이 상대적으로 많은 그래프에서 저장공간과 메모리 절약을 위해 사용된다.



4. 시간 복잡도 ( Big-O)

자료구조시간 복잡도
저장 (storage)간선 추가 (Add Vertex)엣지 추가 (Add Edge)간선 삭제 (Remove Vertex)엣지 삭제 (Remove Edge)Query
인접 리스트 (Adjacency list)O(|V|+|E|)O(1)O(1)O(|V|+|E|)O(|E|)O(|V|)
인접 행렬 (Adjacency matrix)O(|V|^2)O(|V|^2)O(1)O(|V|^2)O(1)O(1)
근접 리스트 (Incidence list)O(|V|+|E|)O(1)O(1)O(|E|)O(|E|)O(|E|)
근접 행렬 (Incidence matrix))O(|V|+|E|)O(|V|+|E|)O(|V|+|E|)O(|V|+|E|)O(|V|+|E|)O(|E|)



5. 탐색

1) 깊이 우선 탐색( DFS )

시작 노드에서 출발하여 먼저 다음 노드로 향하면서 탐색한 곳은 표시를 해두고 더이상 갈 수 있는 노드가 없다면 이전 노드에서 다른 노드로 향하여 모든 노드를 탐색하는 방식. Stack 을 사용하여 구현.

Psuedo Code

노드를 방문했다고 표시
해당 노드 출력
for 연결되어 있는 모든 노드 확인
    if 방문 하지 않고 연결되어 있는 노드
        재귀 함수

c++을 이용한 코드 예


2) 너비 우선 탐색( BFS )

시작 정점으로부터 가까운 정점을 먼저 방문하고 멀리 떨어져 있는 정점을 나중에 방문하는 순회 방법으로, 를 이용하여 노드를 삽입하고 방문한 노드는 큐에서 빼내는 방식으로 구현한다.

Psuedo Code

노드를 방문했다고 표시
queue에 노드번호 삽입
while 큐가 비어있을때까지
    queue pop
    pop값 출력
    for 노드에 연결되어있는 모든 노드 탐색
        if 방문하지 않은 노드라면
            큐에 삽입
            노드 방문표시

c++을 이용한 코드 예



6. 신장 트리 (Spanning Tree)

  • 그래프 내의 모든 정점을 포함하는 트리
  • 모든 정점들이 연결되어 있어야 하고 사이클은 포함되지 않는 형태
  • n개의 노드를 정확이 n-1개의 간선으로 연결된다.
  • 하나의 그래프에는 많은 신장 트리 존재 가능

1) Psuedo Code

노드 방문 표시
for 인접한 노드 탐색
    if 방문하지 않은 노드
        간선 표시
        재귀함수



7. 최소 비용 신장 트리 (MST)

  • 신장 트리 중에서 사용된 간선들의 가중치 합이 최소인 신장 트리
  • 모든 정점들이 연결되어 있어야 하고 사이클은 포함되지 않는 형태
  • n개의 노드를 정확이 n-1개의 간선으로 연결된다.

한마디로 무방향의 가중치가 있는 연결 그래프이다.


1) 알고리즘 종류

Krustkal MST

탐욕적인 방법( Greedy Method )

- 간선 선택 기반 알고리즘
- 희소그래프에 적합 ( V > E )
- 간선 선택 단계에서 사이클을 포함하지 않고 최소 비용 간선을 선택
- 트리집합을 병합하면서 하나의 트리로 확장

과정

  1. 그래프의 가중치를 이용하여 오름차순 정렬
  2. 정렬된 리스트에서 사이클 포함하지 않은 간선 선택
  3. 선택한 간선을 MST 집합에 추가

edge 정렬이 속도를 결정짓기 때문에 egde 수가 적은 희소 그래프 유리하다.

Kruskal algorithm 설명 보기


Prim MST

탐욕적인 방법( Greedy Method )

- 정점 선택 기반
- 밀집 그래프에 적합 ( V < E)
- 시작 정점부터 출발하여 신장 트리 집합을 단계적으로 확장

과정

  1. 시작 정점 MST에 추가
  2. 앞 단계의 MST에 인접한 정점들 중 최소 간선 정점 선택
  3. MST가 n-1개 간선을 가질때 까지 반복

Prim algorithm 설명 보기



8. 그래프 알고리즘 복잡도

알고리즘시간 복잡도
평균 (Average)최악 (Worst)
Kruskal 알고리즘Θ( |E| log|E| )O( |V|^2)
프림 알고리즘 (Prim’s algorithm))Θ( |E| log|V| )O( |V|^2 )
다익스트라 알고리즘 (Dijkstra’s algorithm)Θ( |E| log|V| )O( |V|^2 )
벨먼-포드 알고리즘 (Bellman-Ford algorithm)Θ( |E| * |V| )Θ( |V|^3 )
플로이드-워셜 알고리즘 (Floyd-Warshall algorithm)Θ( |V|^3 )O( |V|^3 )
A* 알고리즘 (A* search algorithm)Θ( |E| )O( b^d )
위상 정렬 (Topological sort)Θ( |V| + |E| )O( |V| + |E| )
Tags :

Related Posts

최장 증가 수열

최장 증가 수열

주어진 수열에서 오름차순으로 정렬된 가장 긴 부분 수열이다. 예를 들어, 341256784134라는 수열에서 LIS는 345678 or 125678 이 된다. 1. 찾는 방법 LIS의 크기 구하는 방법은 dp와 이분탐색에 따라 방법이 나뉘며 경로 추적(trace) 방법은 두 방법 모두 인덱스를 가리키는 배열을 하나 추가하여, 탐색하면서 해당 값의 앞의 수열 인덱스를 저장하는 방법으로 구현한다....

Read More
오브젝트: 코드로 이해하는 객체지향 설계

오브젝트: 코드로 이해하는 객체지향 설계

  • Books
  • 2021년 11월 12일

1. 객체지향 설계 설계란 코드를 배치하는 것이다. 좋은 설계란 오늘 요구하는 기능을 온전히 수행하면서 내일의 변경을 매끄럽게 수용할 수 있는 설계 요구사항은 항상 변하기 마련이다. 2. 객체지향 프로그래밍 부모 클래스에 기본적인 알고리즘의 흐름을 구현하고 중간에 필요한 처리를 자식 클래스에게 위임하는 디자인 패턴을 TEMPLATE METHOD 패턴 이라고 한다. 자식 클래스가 부모 클래스를 대신 하는 것이 업캐스팅 다형성이란 동일한 메시지를 수신했을 때 객체의 타입에 따라 다르게 응답할 수 있는 능력 상속은 구현 상속이 아니라 인터페이스 상속을 위해 사용해야 한다. 대부분의 사람들은 코드 재사용을 상속의 주된 목적이라고 생각하지만 이것은 오해다. 인터페이스를 재사용할 목적이 아니라 구현을 재사용할 목적으로 상속을 사용하면 변경에 취약한 코드를 낳게 될 확률이 높다. 상속의 가장 큰 문제점은 캡슐화를 위반한다는 것. 상속의 두번째 단점은 설계가 유연하지 않다는 것 3. 역할, 책임, 협력 코드를 재사용하는 경우에는 상속보다 합성을 선호하는 것이 옳지만 다형성을 위해 인터페이스를 재사용하는 경우에는 상속과 합성을 함께 조합해서 사용할 수 밖에 없다. 객체지향 패러다임의 관점에서 핵심은 역할, 책임, 협력이다. 객체지향 설계에서 가장 중요한 것은 책임이다. 객체에게 얼마나 적절한 책임을 할당하느냐가 설계의 전체적인 품질을 결정한다. 역할을 구현하는 가장 일반적인 방법은 추상 클래스와 인터페이스를 사용하는 것 협력의 관점에서 추상 클래스와 인터페이스는 구체 클래스들이 따라야 하는 책임의 집합을 서술한 것이다. 추상 클래스는 책임의 일부를 구현해 놓은 것이고 인터페이스는 일체의 구현 없이 책임의 집합만을 나열해 놓았다는 차이가 있지만 협력의 관점에서는 둘 모두 역할을 정의할 수 있는 구현 방법이라는 공통점을 공유한다. 4. 메시지와 인터페이스 강조하고 싶은 것은 소프트웨어 설계에 법칙이란 존재하지 않는다 라는 것이다. 원칙을 맹신하지 마라. 원칙이 적절한 상황과 부적절한 상황을 판단할 수 있는 안목을 길러라. 설계는 트레이드오프의 산물이다. 소프트웨어 설계에 존재하는 몇 안되는 법칙 중 하나는 경우에 따라 다르다 라는 사실을 명심해라. 프로시저는 부수효과를 발생시킬 수 있지만 반환할 수 없다. 함수는 값을 반환할 수 있지만 부수효과는 발생시킬 수 없다. 5. 객체 분해 하향식은 이미 완전히 이해된 사실을 서술하기에 적합한 방법이다. 그러나 하향식은 새로운 것을 개발하고, 설계하고, 발견하는 데는 적합한 방법이 아니다. 이것은 수학과 아주 유사하다. 수학 교과서는 계산의 과정을 논리적인 순서로 서술한다. 공인되고 증명된 이론이 뒤이은 이론을 증명하기 위해 사용된다....

Read More
함수

함수

1. 함수 생성 방법 func키워드를 이용해서 함수를 선언할 수 있고 가장 기본적으로 만드는 main도 함수 이다. 2. 매개변수(인자) 1) 전달 방식 Java처럼 primitive자료형은 pass by value, reference자료형은 pass by refernece가 아닌 go는 C처럼 *을 이용해서 value인지 reference인지 정해서 넘겨줄 수 있다....

Read More