지금까지 봐온 트리구조의 특성은 루트가 있고 아래로 자식노드들이 있으며, 이 부모노드와 자식노드를 이어주는 edge가 존재하며 방향은 부모노드에서 자식노드로 흘렀다. 또한 들어오는 곳은 한개이며 나가는 곳은 두개(혹은 여러개)인 구조였다.
그래프(Graph)는 위와 같은 구성이 아닌 방향도,들어오는 곳의 개수도, 자식노드가 없기도 하고 그 밖의 다양한 구조를 띄는것이 그래프이다. 트리는 그래프의 한 형태로 볼 수 있다. ( 여러가지 조건이 있는 방향 그래프 )
그래프 구조는 G = ( V, E )로 나타낼 수 있다.
G : Graph
V : Vertex set ( 트리에선 Node라고 했음 )
E : Edge set
위와 같은 구조가 있을 때
V = { 1, 2, 3, 4, 5, 6 }
E = { (1,2) , (2,3) , (1,5) , (3,4), (6,4), (2,1) ... }
|V| = n ( V 집합의 크기 )
|E| = m ( E 집합의 크기 )
로 표현할 수 있다.
그래프 구조는 위에서 아래로의 계층형 구조가 아니기 때문에 그래프 구조의 degree는 인접하게 이어진 edge의 수이며 그래프의 degree는 가장 큰 degree의 값이다. ( 4의 degree : 3 )
adjacency하다라는 말은 노드 3과 노드 2는 adjacency하다.
incident하다 E(2,3)은 노드 2와 3에 incident하다.
경로(path) : 1에서 3으로 가는 경로 ?
Cycle 구조 : 처음과 끝이 같은 경우
그래프를 표현한다는 것은 인접성 ( adjacency )를 나타내는 것이다.
단점 : 정보의 표현보다 낭비되는 메모리 ( 0인 개수 ) 가 너무 많아 효율이 떨어진다.
순서 상관 없이 linked list로 표현하는 방법이다.
인접 리스트 방법을 사용할 때 노드의 개수는 edge의 개수의 2배 만큼 생긴다. ( undirected 경우 양방향이기 때문이다. )
Binary tree를 순회할때 사용했던 in,pre,postorder 들이 DFS에 속한다.
하나의 자식노드를 방문하면 그 해당노드의 자식노드를 끝까지 파고들어 탐색 후 , 다음 분기(brach)에 있는 곳으로 이동하는 순회방법이다.
레벨 단위로 순회하는 것이 BFS이다.
DFS,BFS -Python 구현
class Graph:
def __init__(self):
self.graph = {}
def addInfo(self,start,edges):
self.graph[start] = edges
def addEdge(self,start,edge):
self.graph[start].append(edge)
def addVertex(self,Vertex):
self.graph[Vertex] = []
## BFS는 Queue구조로 구현가능하다.
def BFS(self,start):
Q = [start]
visited = [start]
while Q:
cur_V = Q.pop(0)
for next in self.graph[cur_V]:
if next not in visited:
Q.append(next)
visited.append(next)
return visited
## DFS는 스택과 재귀로 구현가능하다.
def DFS(self,start):
S = [start]
visited = []
while S:
cur_V = S.pop()
if cur_V not in visited:
visited.append(cur_V)
S.extend(self.graph[cur_V][::-1])
return visited
def DFS_recursive(self,start,visited=[]):
visited.append(start)
for next in self.graph[start]:
if next not in visited:
self.DFS_recursive(next,visited)
return visited
if __name__=="__main__":
G = Graph()
G.addInfo('A',['C','D','E'])
G.addInfo('B',['F','C'])
G.addInfo('C',['A','B'])
G.addInfo('D',['A','F'])
G.addInfo('E',['A'])
G.addInfo('F',['D','B'])
print(G.BFS('A'))
print(G.DFS('A'))
print(G.DFS_recursive('A'))