본문 바로가기
회고록

👩🏼‍💻TIL : 9. 그래프에 대해 알아보자!

by NOHCODING 2022. 10. 7.
반응형

00. 자료구조를 공부하는 이유?

상황에 맞는 방식으로 데이터를 저장하고 사용하기 위해 자료구조를 공부해야한다. 또한 데이터 사이에 어떤 관계가 있는가를 중점을 두고 자료구조를 사용하자.

 

 

01. 그래프란?

연결 데이터를 저장 할 수 있는 자료구조이다. 

 

 (1) 연결 데이터 혹은 연결 관계?

      ① 위치 데이터(ex. 지하철 앱)

      ② 사회 연결망(ex. 친구관계)

      ③ 통신 : 수많은 컴퓨터들의 연결관계 

      ④ 생물 : 유전자와 단백질의 상호작용 관계

 

02. 그래프 용어

   ① 노드 : 그래프에서 하나의 데이터 단위를 나타내는 객체

   ② 엣지 : 그래프에서 두 노드의 직접적인 연결 관계 데이터(ex. 페이스북 유저 그래프)

   인접 : 두 노드가 엣지로 연결되어 있으면 '인접해 있다'라고 한다.

   경로 : 엣지들이 연결되어 있는 것을 경로라고 한다.

   ⑤ 사이클 : 특정 노드에서 다시 그 노드로 돌아오는 경로는 사이클이라고 함.

   ⑥ 차수 : 한 노드가 가지고 있는 엣지의 수 

 

03. 무방향 그래프(undirected graph) 

  - 무방향그래프 : 쌍방향일 경우 무방향그래프라고 표현한다.

 

04. 방향 그래프(directed graph)

 방향 그래프에서는 엣지들이 방향을 가진다. 인스타그램의 팔로우 관계처럼 한 유저가 다른 유저를 팔로우 하는 일방적인 관계를 나타낼 수 있게 해준다. 방향그래프에서 차수는 출력차수와 입력차수로 나뉜다. 

 

    ① 출력 차수 : 노드에서 나가는 엣지의 수

    ② 입력 차수 : 노드에서 들어가는 차수를 입력

 

 

05. 가중치 그래프(weighted graph)

    ① 무 가중치 그래프 : 모든 엣지의 값이 동일한 그래프

    ② 가중치 그래프 : 엣지의 값이 다른 그래프

 

 

06.  인접행렬 VS 인접리스트

인접 행렬이란 "총 노드의  수  x 총 노드의 수" 만큼의 행렬을 만든다. 그리고 여기에 노드들간의 인접 데이터를 저장한다. 

인접 리스트란 각 노드가 자신과 인접한 노드들을 가리키는 레퍼런스를 저장하고 있다. 

 

    V : V는 그래프 안에 있는 모든 노드들의 집합이다. 그래프에 있는 하나의 데이터 객체를 노드라고 부르지만 Vertex라는 표현을 사용하기도 한다. Vertex의 가장 앞 알파벳을 따서 V라고 한다.

   ② E : E는 그래프 안에 있는 모든 엣지들의 집합이다. 엣지를 영어로 쓰면 Edge이다.

   그래프를 사용할 땐 O(n)O(\lg(n)) 이런 점근 표기법 대신 O(V)O(E)O(\lg(V))

   엣지가 가장 많을 때 : 모든 노드가 서로 다른 노드에 연결되어 있는 경우 (무방향 그래프 : V^2/2,  방향그래프 : V^2 ) 

   ⑤ 노드를 저장하는 공간 : 노드를 저장하는데에는 O(V)의 공간을 사용한다고 할 수 있음

   ⑥ 인접리스트가 차지하는 공간 총 V개의 배열 또는 파이썬 리스트를 저장해야 할때 . V^2에 비례하기 때문에 일단 최소 O(V) 만큼의 공간을 차지한다. 인접 리스트는 최악의 경우 엣지 데이터를  O(V^2)로 저장한다. 

    ⑦

    ⑧ 두 노드가 연결되었는지 확인하는데 걸리는 시간 :

        - 인접행렬을 이용(두 노드가 인접했는지 아닌지를 으로 알아낼 수 있다. )

        - 인접리시트의 경우 한 노드 안에 특정 데이터가 저장됐는지를 탐색해야한다. 선형 탐색을 해야하기 때문에 리스트 안에  있는 데이터를 다 돌아야 해서 최악의 경우 V개의 요소를 확인해야한다. 

   ⑨ 한 노드에 연결된 모든 노드들을 알아내는데 걸리는 시간 : 인접 행렬의 경우 배열을 다 돌아야하지만 인접리스트의 경우 각 노드가 자신과 인접한 노드들에 대한 레퍼런스만 가지고 있다. 물론 최악의 경우 한 노드가 다른 모든 노드들과 연결되어 있으면, 인접 행렬과 마찬가지로 총 V번 돌아서 인접행렬을 사용하는거보다 더 빨리 실행된다.

 

 

 

08. Breadth First Search (BFS)

너비우선탐색으로 시작을 정점으로부터 가까운 정점을 먼저 방문하고 멀리 떨어져 있는 정점을 나중에 방문하는 순회방법이다.

 

전처리: O(V)

큐에서 노드 넣고 빼기: O(V)

인접한 노드들을 도는데 걸리는 시간 O(E)

더보기

① 큐에서 가장 앞 노드를 꺼낸다.

② 이 노드에 인접해 있는 노드들을 돌면서: 

        ① 처음 방문한 노드면 :

              ① 방문한 노드로 표시한다

              ② 큐에 넣는다. 

def bfs(graph, start_node):
    """시작 노드에서 bfs를 실행하는 함수"""
    queue = deque()  # 빈 큐 생성

    # 모든 노드를 방문하지 않은 노드로 표시
    for station_node in graph.values():
        station_node.visited = False

    # 시작점 노드를 방문 표시한 후 큐에 넣어준다
    start_node.visited = True
    queue.append(start_node)
    
    while queue:  # 큐에 노드가 있는 동안
        current_station = queue.popleft()  # 큐의 가장 앞 데이터를 갖고 온다
        for neighbor in current_station.adjacent_stations:  # 인접한 노드를 돌면서
            if not neighbor.visited:  # 방문하지 않은 노드면
                neighbor.visited = True  # 방문 표시를 하고
                queue.append(neighbor)  # 큐에 넣는다

 

 

09. Depth First Search(DFS)

①   스택에서 가장 위 노드를 꺼낸다. 

②   방문처리 표시를 한다.

③  해당 노드에 인접해 있는 노드들을 돌면서, 

        확인한 노드면 

        표시한다.

       ③ 스택에 넣는다.

     

from collections import deque


def dfs(graph, start_node):
    """dfs 함수"""
    stack = deque()  # 빈 스택 생성

    # 모든 노드를 처음 보는 노드로 초기화
    for station_node in graph.values():
        station_node.visited = 0

    start_node.visited = 1  # 시작 노드를 스택에 넣는다는 표시(옅은 회색)를 하고
    stack.append(start_node)  # 스택에 넣습니다

    while stack:  # 스택에 노드가 남아 있을 때까지
        current_node = stack.pop()  # 스택 가장 위(뒤) 데이터를 갖고 온다
        current_node.visited = 2  # 현재 노드를 방문 표시한다
        for neighbor in current_node.adjacent_stations:
            if neighbor.visited == 0:  # 처음 보는 노드들만
                neighbor.visited = 1  # 스택에 넣는다는 표시를 하고
                stack.append(neighbor)  # 스택에 넣습니다

 

10. 그래프를 사용할 때 끊기는게 많을 때는 어떻게 사용해야할까?

11. 스트링으로 key와 value값을 사용해야할때, 중복 값이 있으면 어떻게 해야할까?

반응형

댓글