그래프 - 깊이우선탐색

2022. 1. 29. 15:05·자료구조
728x90
반응형

# [C언어로 쉽게 풀어쓴 자료구조(천인국)]를 공부하고 주요 내용을 정리하고자 작성하는 글입니다.

# 해당 게시글에 대한 모든 피드백 환영합니다. 

 

깊이우선 탐색 Depth First Search: DFS

시작 정점에서 한 방향으로 직진하다가
더 이상 갈 수 없게 되면
다시 가장 가까운 갈림길로 돌아와서
다른 방향으로 다시 탐색을 진행하는 것

 

0. 알고리즘

  • 그래프의 시작 정점에서 출발 ==> 시작정점 = v
  • 정점 v 방문했다고 표시
  • 정점 v의 인접정점 집합에 대해서 ( u ∈ 인접정점 집합 )
  • 정점 u를 아직 방문안했으면
  • 시작정점을 u로 설정해서 위의 과정 다시 수행
  • 만약 인접정점 집합이 공집합이면 리턴
depth_first_search(v):
	v를 방문했다고 표시
	for all u in (v의 인접정점) do
    		if (u 아직 방문 안했으면)
        			then depth_first_search(u)

 

1. 인접행렬을 이용해 dfs 순서 알아내기

# c언어로 구현

#include <stdio.h>
#include <stdlib.h>

#define TRUE 1
#define FALSE 0
#define MAX_VERTICES 50

// 방문한 정점을 저장할 배열
int visited[MAX_VERTICES];

typedef struct GraphType {
	int n; //정점의 개수
	int adj_mat[MAX_VERTICES][MAX_VERTICES]; //인접행렬
} GraphType;

//그래프 초기화
void init(GraphType* g)
{
	int r, c;
	g->n = 0; //정점의 개수는 0으로 초기화
	for (r = 0; r < MAX_VERTICES; r++) // 인접행렬의 모든 원소들 0으로 초기화
	{
		for (c = 0; c < MAX_VERTICES; c++)
			g->adj_mat[r][c] = 0;
	}
}
// 정점 삽입 연산
void insert_vertex(GraphType* g, int v)
{
	if ((g->n) + 1 > MAX_VERTICES)
	{
		fprintf(stderr, "그래프: 정점의 개수 초과\n");
		return;
	}
	g->n++; // 정점을 삽입하는 것은 실질적으로 행렬에 영향을 주지 않음
	// 그저 정점의 개수만 증가시켜 주면 된다.
}
// 간선 삽입 연산
void insert_edge(GraphType* g, int start, int end)
{
	if (start >= g->n || end >= g->n) {
		fprintf(stderr, "그래프: 정점 번호 오류\n");
		return;
	}
	g->adj_mat[start][end] = 1;
	g->adj_mat[end][start] = 1;
	// 정점을 우선 삽입한 뒤에 
	// 해당 정점 번호를 이용해 간선을 삽입하기
}
// 깊이우선탐색 함수
void dfs_mat(GraphType* g, int v)
{
	int u;
	// 1. 시작정점 v 방문했음 표시 및 출력
	visited[v] = TRUE;
	printf("정점 %2d -> ", v);
	// 2. 정점 v의 인접정점 중에서
	for (u = 0; u < g->n; u++) {
		// 3. 아직 방문 안했고, 정점 v랑 연결된 정점이 있으면
		if ((visited[u] == FALSE) && (g->adj_mat[v][u])) {
			// 4. 그 정점에 대해 위의 과정 수행
			dfs_mat(g, u);
		}
		// 5. 만약 위의 조건을 만족하는 정점이 없으면 그 전 함수 호출로 리턴.
	}
}
int main()
{
	GraphType* g;
	g = (GraphType*)malloc(sizeof(GraphType));
	init(g);
	for (int i = 0; i < 4; i++) {
		insert_vertex(g, i);
	}
	insert_edge(g, 0, 1);
	insert_edge(g, 0, 2);
	insert_edge(g, 0, 3);
	insert_edge(g, 1, 2);
	insert_edge(g, 2, 3);
	
	printf("깊이 우선 탐색\n");
	dfs_mat(g, 0);
	printf("\n");

	free(g);
	return 0;
}

# 결과

# 그림으로 이해하기

 

2. 인접리스트를 이용해 dfs 순서 알아내기

# 코드

#include <stdio.h>
#include <stdlib.h>
#define MAX_VERTICE 50
#define TRUE 1
#define FALSE 0

// 각 정점마다 하나의 연결리스트가 필요하다
// 정점의 개수만큼의 포인터 배열(헤더노드)이 필요하다
// 하나의 노드 ==> GraphNode
// 포인터 배열의 이름 ==> adj_list

typedef struct GraphNode {		// 하나의 노드
	int vertex;					// 데이터 필드: 정점의 값을 저장할 곳
	struct GraphNode* link;		// 링크 필드: 인접정점을 가리킬 포인터 
	// 가리킬 변수의 타입이 하나의 정점이기 때문에 GraphNode 타입으로 선언해야 한다.
} GraphNode;

typedef struct GraphType {		// 그래프 전체
	int n;						// 해당 그래프의 정점의 개수
	GraphNode* adj_list[MAX_VERTICE]; // 헤더노드 집합; 각 연결 리스트의 첫번째 노드를 가리킴.
} GraphType;

int visited[MAX_VERTICE];

// 그래프 초기화
void init_adjList(GraphType* g) 
{
	int v;
	g->n = 0; //그래프 정점의 개수 0으로 초기화
	for (v = 0; v < MAX_VERTICE; v++) 
	{
		g->adj_list[v] = NULL;
	}
}
// 정점 삽입 연산: 값이 v인 정점을 삽입한다.
void insert_vertex_adjList(GraphType* g, int v) 
{ // v: 삽입합 노드의 값
	if ((g->n) + 1 > MAX_VERTICE) 
	{
		fprintf(stderr, "그래프: 정점의 개수 초과\n");
		return;
	}
	g->n++;
}
// 간선 삽입 연산: 정점 u와 v를 연결한다 : 정점 u에 간선 (u,v)를 맨 처음에 삽입
void insert_edge_adjList(GraphType* g, int u, int v) 
{
	if (u >= g->n || v >= g->n) 
	{
		fprintf(stderr, "그래프: 정점 번호 오류\n");
		return;
	}
	GraphNode* node = (GraphNode*)malloc(sizeof(GraphNode));
	if (node == NULL) {
		printf("malloc 오류: 할당 안됨\n");
		return;
	}
	node->vertex = v;
	node->link = g->adj_list[u];
	g->adj_list[u] = node;	// adj_list의 한 원소는 GraphNode를 가리키는 포인터 타입이니까 할당 가능
}
// 깊이우선탐색 연결리스트로 구현
void dfs_list(GraphType* g, int v)
{
	GraphNode* u;
	// 1. 시작정점 v 방문했음 표시 및 출력
	visited[v] = TRUE;
	printf("정점 %2d -> ", v);
	// 2. 정점 v의 인접정점 중에서
	for (u = g->adj_list[v]; u != NULL; u = u->link) 
	{
		// 3. 아직 방문 안했으면 (간선이 존재하는지 확인 안함)
		if ((visited[u->vertex] == FALSE)) 
		{
			// 4. 그 정점에 대해 위의 과정 수행
			dfs_list(g, u->vertex);
		}
		// 5. 만약 위의 조건을 만족하는 정점이 없으면 그 전 함수 호출로 리턴.
	}
}
int main()
{
	GraphType* g;
	g = (GraphType*)malloc(sizeof(GraphType));
	init_adjList(g);
	for (int i = 0; i < 4; i++) {
		insert_vertex_adjList(g, i);
	}
	insert_edge_adjList(g, 0, 1);
	insert_edge_adjList(g, 0, 2);
	insert_edge_adjList(g, 0, 3);
	insert_edge_adjList(g, 1, 2);
	insert_edge_adjList(g, 2, 3);

	printf("깊이 우선 탐색\n");
	dfs_list(g, 0);
	printf("\n");

	free(g);
	return 0;
}

# 결과

# 그림으로 이해하기

 

3. 스택 stack을 이용해 dfs 순서 알아내기

# 알고리즘

dfs_iterative(graph, v):
	스택 stack을 생성한다
	stack.push(v) 
	while(not is empty(stack)) do
		v = s.pop()
		if( v 아직 방문 안했으면)
			v를 방문했다고 표시
			for all u in (v의 인접정점) do
				if (u 아직 방문 안했으면)
					stack.push(u)

# 그림으로 이해하기

그림1

위의 그림1 의 그래프에 대해 다음과 같이 깊이우선 탐색이 실시됩니다.

 

 

728x90
반응형
저작자표시 (새창열림)

'자료구조' 카테고리의 다른 글

그래프 - Kruskal의 MST 알고리즘  (0) 2022.01.30
그래프 - 최소비용신장트리  (0) 2022.01.30
그래프 - 너비우선탐색  (0) 2022.01.29
그래프 - 표현방법(인접행렬/인접리스트)  (0) 2022.01.28
그래프 - 개념/ 주요 용어 정리  (0) 2022.01.28
'자료구조' 카테고리의 다른 글
  • 그래프 - 최소비용신장트리
  • 그래프 - 너비우선탐색
  • 그래프 - 표현방법(인접행렬/인접리스트)
  • 그래프 - 개념/ 주요 용어 정리
heeya16
heeya16
개발 공부 냠냠
  • heeya16
    개발자 희야
    heeya16
  • 전체
    오늘
    어제
    • 분류 전체보기 (106)
      • 코딩테스트 (66)
        • 프로그래머스 (38)
        • SWEA (2)
        • BAEKJOON (26)
      • 알고리즘 (7)
      • 자료구조 (19)
      • 프로젝트 (5)
      • 취업 주르륵 (3)
      • 데이터베이스 (0)
      • IT지식 (2)
  • 블로그 메뉴

    • 홈
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    1003
    10448
    10773
    10월
    10진수
    11047
    11399
    11403
    11866
    1449
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.0
heeya16
그래프 - 깊이우선탐색
상단으로

티스토리툴바