C언어로 반복 깊이 우선 탐색(Iterative Deepening DFS) 구현 방법과 예제

C언어에서 반복 깊이 우선 탐색(Iterative Deepening DFS, IDS)은 그래프 탐색에서 깊이 우선 탐색(DFS)과 너비 우선 탐색(BFS)의 장점을 결합한 효율적인 알고리즘입니다. IDS는 메모리 사용량을 최소화하면서도 최적의 해답을 보장하는 알고리즘으로, 특히 깊이가 불확실하거나 메모리 제약이 있는 문제에서 유용합니다. 본 기사에서는 IDS의 기본 개념부터 C언어를 활용한 구현 방법, 실제 응용 사례까지 다루어, 알고리즘에 대한 이해를 높이고 실용적인 활용 방안을 제시합니다.

목차

반복 깊이 우선 탐색(IDS)의 개념과 필요성

반복 깊이 우선 탐색(IDS)이란?


반복 깊이 우선 탐색(Iterative Deepening Depth-First Search, IDS)은 깊이 우선 탐색(DFS)과 너비 우선 탐색(BFS)의 특징을 결합한 그래프 탐색 알고리즘입니다. IDS는 깊이 우선 탐색처럼 재귀적으로 동작하지만, 탐색 깊이를 점진적으로 증가시키며 너비 우선 탐색의 완전성을 유지합니다.

IDS가 필요한 이유

  1. 메모리 효율성: 너비 우선 탐색(BFS)은 탐색 중에 큐에 많은 노드를 저장해야 하므로 메모리 소비가 클 수 있습니다. IDS는 DFS 기반이므로 메모리 사용량이 적습니다.
  2. 해결 보장: 깊이 우선 탐색(DFS)은 무한 순환 가능성이 있지만, IDS는 탐색 깊이를 제한함으로써 이를 방지하며, 목표 상태를 찾지 못하면 더 깊은 단계로 이동합니다.
  3. 동적 깊이 탐색: IDS는 목표 상태의 깊이를 사전에 알 수 없을 때 유용합니다. 탐색 깊이를 점진적으로 증가시키며 최적의 솔루션을 찾아냅니다.

IDS의 장점

  • 최적성: 최소 비용 경로를 보장합니다.
  • 완전성: 목표 상태를 반드시 탐색합니다(탐색 범위 내에 있는 경우).
  • 적용성: 메모리가 제한된 환경에서 대규모 그래프 탐색에 적합합니다.

예제 상황


미로 문제에서 출구를 찾거나, 퍼즐 문제(예: 8퍼즐)에서 최적의 해를 찾는 데 IDS는 강력한 도구가 됩니다. 이처럼 탐색 깊이가 미리 정해지지 않은 문제에서 IDS의 효율성이 돋보입니다.

반복 깊이 우선 탐색의 작동 원리

작동 방식 개요


반복 깊이 우선 탐색(IDS)은 깊이 우선 탐색(DFS)을 기반으로 하며, 탐색 깊이를 점진적으로 증가시키며 모든 노드를 방문합니다. 각 단계에서 탐색 깊이 제한(depth limit)을 설정하고, 해당 깊이까지 노드를 탐색한 후 목표를 찾지 못하면 깊이를 1 증가시켜 다시 탐색을 반복합니다.

알고리즘 흐름

  1. 초기 깊이 제한 depth = 0을 설정합니다.
  2. DFS를 호출하여 현재 depth까지만 탐색을 수행합니다.
  3. 목표 상태를 발견하면 탐색을 종료합니다.
  4. 목표 상태를 찾지 못했을 경우, depth를 1 증가시키고 2단계를 반복합니다.

단계별 동작

1단계: 초기화


탐색할 그래프와 목표 노드, 시작 노드, 초기 깊이 제한을 설정합니다.

2단계: 깊이 제한 DFS 수행


DFS와 동일한 방식으로 동작하지만, 재귀 호출 전에 현재 깊이가 제한을 초과했는지 확인합니다. 제한을 초과하면 해당 경로 탐색을 중지합니다.

3단계: 반복 수행


목표 상태를 찾을 때까지 깊이 제한을 증가시키며 DFS를 반복 수행합니다.

의사 코드

function IDS(start, goal, max_depth):
    for depth from 0 to max_depth:
        result = DepthLimitedDFS(start, goal, depth)
        if result != NULL:
            return result
    return NULL

function DepthLimitedDFS(node, goal, depth):
    if depth == 0 and node == goal:
        return node
    if depth > 0:
        for each child of node:
            result = DepthLimitedDFS(child, goal, depth - 1)
            if result != NULL:
                return result
    return NULL

핵심 개념

  • 깊이 제한: 현재 탐색의 최대 깊이를 설정하여 무한 탐색 방지
  • 반복적 탐색: 깊이를 점진적으로 증가시키며 목표 상태를 찾기 위해 탐색을 반복
  • 완전성과 최적성: 목표 상태가 존재하면 반드시 탐색하며, 최적의 해를 보장

IDS는 이러한 방식으로 메모리 효율성과 해답 보장을 동시에 충족하며, 깊이를 모르는 문제에서도 효과적으로 적용됩니다.

IDS 알고리즘을 구현하기 위한 준비

필요한 자료구조


반복 깊이 우선 탐색(IDS)을 C언어로 구현하려면 탐색할 그래프와 스택 기반의 깊이 우선 탐색을 처리할 자료구조를 준비해야 합니다.

그래프 표현


그래프는 인접 리스트 또는 인접 행렬을 사용해 표현할 수 있습니다. IDS에서는 메모리 사용량을 최소화하는 인접 리스트가 적합합니다.

typedef struct Node {
    int id;
    struct Node* next;
} Node;

typedef struct Graph {
    int num_vertices;
    Node** adj_list;
} Graph;

스택 기반의 탐색


DFS를 구현하기 위해 스택이 필요하지만, 재귀 호출로 처리하면 추가 스택 자료구조 없이도 구현할 수 있습니다.

함수 정의

그래프 초기화 함수

  • 그래프의 노드와 간선을 정의하고 초기화하는 함수가 필요합니다.
Graph* create_graph(int vertices);
void add_edge(Graph* graph, int src, int dest);

DFS 및 IDS 탐색 함수

  • 반복 깊이 우선 탐색에서 사용할 DFS 함수는 탐색 깊이를 제한할 수 있어야 합니다.
int depth_limited_dfs(Graph* graph, int start, int goal, int depth_limit);
int iterative_deepening_dfs(Graph* graph, int start, int goal, int max_depth);

구현에 필요한 설정

노드 방문 여부 추적

  • 노드의 방문 상태를 저장하기 위해 배열이 필요합니다.
int* visited; // 각 노드의 방문 여부를 추적

종료 조건

  • IDS는 목표 상태를 발견하면 탐색을 종료하므로 이를 위한 조건을 설정합니다.
  • depth_limited_dfs 함수는 목표 노드에 도달하면 탐색을 중단하고 결과를 반환해야 합니다.

구현 준비 요약

  1. 그래프를 인접 리스트로 정의
  2. 탐색에 필요한 DFS 함수IDS 함수 설계
  3. 노드 방문 추적을 위한 배열 사용
  4. 재귀 호출을 통한 깊이 제한 DFS 설계

이 준비 과정을 통해 IDS를 효율적으로 구현할 수 있으며, 다음 단계에서 구현 코드를 작성할 예정입니다.

반복 깊이 우선 탐색 C언어 구현 코드

아래는 반복 깊이 우선 탐색(IDS)을 C언어로 구현한 코드입니다. 이 코드에는 그래프 초기화, 깊이 제한 DFS, 그리고 IDS 함수가 포함되어 있습니다.

코드 전체

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

// 노드 구조체 정의
typedef struct Node {
    int id;
    struct Node* next;
} Node;

// 그래프 구조체 정의
typedef struct Graph {
    int num_vertices;
    Node** adj_list;
} Graph;

// 그래프 생성
Graph* create_graph(int vertices) {
    Graph* graph = (Graph*)malloc(sizeof(Graph));
    graph->num_vertices = vertices;
    graph->adj_list = (Node**)malloc(vertices * sizeof(Node*));
    for (int i = 0; i < vertices; i++) {
        graph->adj_list[i] = NULL;
    }
    return graph;
}

// 간선 추가
void add_edge(Graph* graph, int src, int dest) {
    Node* new_node = (Node*)malloc(sizeof(Node));
    new_node->id = dest;
    new_node->next = graph->adj_list[src];
    graph->adj_list[src] = new_node;
}

// 깊이 제한 DFS
int depth_limited_dfs(Graph* graph, int start, int goal, int depth_limit, int* visited) {
    if (start == goal) {
        return 1; // 목표 상태 발견
    }
    if (depth_limit == 0) {
        return 0; // 깊이 제한 초과
    }
    visited[start] = 1; // 노드 방문 표시

    Node* temp = graph->adj_list[start];
    while (temp != NULL) {
        if (!visited[temp->id]) {
            if (depth_limited_dfs(graph, temp->id, goal, depth_limit - 1, visited)) {
                return 1; // 경로 발견
            }
        }
        temp = temp->next;
    }
    visited[start] = 0; // 다른 경로 탐색을 위해 방문 해제
    return 0; // 목표 상태 미발견
}

// 반복 깊이 우선 탐색 (IDS)
int iterative_deepening_dfs(Graph* graph, int start, int goal, int max_depth) {
    int* visited = (int*)malloc(graph->num_vertices * sizeof(int));
    for (int depth = 0; depth <= max_depth; depth++) {
        for (int i = 0; i < graph->num_vertices; i++) {
            visited[i] = 0; // 방문 배열 초기화
        }
        if (depth_limited_dfs(graph, start, goal, depth, visited)) {
            free(visited);
            return 1; // 목표 상태 발견
        }
    }
    free(visited);
    return 0; // 목표 상태 미발견
}

// 테스트 함수
int main() {
    // 그래프 초기화
    Graph* graph = create_graph(6);
    add_edge(graph, 0, 1);
    add_edge(graph, 0, 2);
    add_edge(graph, 1, 3);
    add_edge(graph, 1, 4);
    add_edge(graph, 2, 5);

    // IDS 실행
    int start = 0, goal = 5, max_depth = 3;
    if (iterative_deepening_dfs(graph, start, goal, max_depth)) {
        printf("Goal node %d found starting from node %d\n", goal, start);
    } else {
        printf("Goal node %d not found within depth %d\n", goal, max_depth);
    }

    return 0;
}

주요 구현 설명

  1. 그래프 생성 및 간선 추가
  • create_graphadd_edge 함수로 인접 리스트 방식으로 그래프를 생성합니다.
  1. 깊이 제한 DFS
  • depth_limited_dfs 함수는 주어진 깊이 제한 내에서 탐색하며, 목표 노드 발견 여부를 반환합니다.
  1. IDS 탐색
  • iterative_deepening_dfs 함수는 깊이를 점진적으로 증가시키며 depth_limited_dfs를 반복 호출합니다.
  1. 테스트 실행
  • 테스트 코드에서는 노드 0에서 시작하여 노드 5를 탐색하며, 탐색 결과를 출력합니다.

결과 예시

Goal node 5 found starting from node 0

이 코드는 IDS 알고리즘의 구조를 간결히 설명하며, 사용자 정의 그래프와 목표 상태를 설정해 확장 가능합니다.

IDS의 시간 복잡도와 공간 복잡도 분석

반복 깊이 우선 탐색(IDS)은 깊이 우선 탐색(DFS)과 너비 우선 탐색(BFS)의 장점을 결합한 알고리즘으로, 효율성에 대한 분석이 중요합니다. 이 섹션에서는 IDS의 시간 복잡도와 공간 복잡도를 분석합니다.

시간 복잡도

IDS는 DFS를 반복 수행하며 깊이를 점진적으로 증가시킵니다. 이로 인해 목표 상태를 찾기 위해 탐색 깊이 d와 각 깊이에서 탐색 가능한 노드 수를 고려해야 합니다.

1. DFS와의 비교


DFS는 전체 노드를 한 번씩 방문하므로, 노드 수가 N일 때 시간 복잡도는 O(N)입니다.

2. IDS의 특징


IDS는 깊이 제한을 점진적으로 증가시키며 각 깊이에서 새로운 DFS를 수행합니다.

  • 탐색 깊이가 d이고, 각 노드의 평균 자식 수가 b(branching factor)일 경우, IDS에서 각 깊이에서 방문하는 노드 수는 다음과 같습니다:
  • 깊이 0: 1
  • 깊이 1: b
  • 깊이 2: b^2
  • 깊이 d: b^d

따라서 IDS의 총 시간 복잡도는 모든 깊이의 노드를 합한 값으로 계산됩니다:
[
O(b^0 + b^1 + b^2 + \ldots + b^d) = O(b^d)
]

IDS는 최종 깊이에서 대부분의 노드를 방문하므로, DFS와 동일한 O(b^d)의 시간 복잡도를 가집니다.

공간 복잡도

IDS는 깊이 우선 탐색(DFS) 기반으로 작동하므로, 탐색 중에 활성화된 호출 스택에 저장되는 노드 수가 중요합니다.

1. DFS와의 비교


DFS는 현재 경로를 따라가기 위해 깊이 d까지의 노드를 스택에 저장하므로 공간 복잡도는 O(d)입니다.

2. IDS의 특징


IDS 역시 깊이 제한을 설정하고 DFS를 수행하므로, 한 번의 탐색에서 사용하는 메모리는 DFS와 동일하게 O(d)입니다.

메모리 효율성


IDS는 깊이 제한을 반복적으로 증가시키며 탐색하므로 메모리 사용량이 일정하며, 너비 우선 탐색(BFS)의 O(b^d)보다 훨씬 적은 O(d)를 사용합니다.

정리

알고리즘시간 복잡도공간 복잡도
DFS(O(b^d))(O(d))
BFS(O(b^d))(O(b^d))
IDS(O(b^d))(O(d))

IDS의 장점

  • 시간 복잡도: DFS와 동일하며 BFS와 비교해 손실이 없습니다.
  • 공간 복잡도: BFS보다 훨씬 적은 메모리를 사용하여 메모리 효율성이 높습니다.

IDS는 시간 복잡도와 공간 복잡도 사이에서 균형을 맞춘 효율적인 알고리즘으로, 특히 메모리가 제한된 환경에서 활용도가 높습니다.

IDS의 응용 예제

반복 깊이 우선 탐색(IDS)은 특정 조건에서 효율적으로 사용할 수 있는 알고리즘으로, 다양한 실제 문제에서 활용됩니다. 여기서는 IDS의 응용 사례와 예제를 통해 이해를 심화합니다.

응용 1: 퍼즐 문제 해결


IDS는 퍼즐 문제(예: 8퍼즐, 15퍼즐)에서 최적의 해를 찾는 데 유용합니다. 이러한 문제는 목표 상태를 찾기 위해 탐색 깊이를 점차적으로 늘려야 할 때가 많습니다.

예시: 8퍼즐 문제


8퍼즐에서 초기 상태에서 목표 상태로 이동하는 최단 경로를 탐색합니다. IDS는 상태 공간 트리를 깊이 제한을 설정해 탐색하며, 목표 상태를 찾기 위해 깊이를 반복적으로 증가시킵니다.

주요 이점

  • 메모리 사용량을 줄이면서 최단 경로를 보장
  • 목표 상태가 깊은 곳에 있는 경우에도 효율적으로 탐색

응용 2: 게임 트리 탐색


IDS는 체스, 바둑 등 게임에서 상태 공간을 탐색하는 데 사용됩니다. 제한된 시간 내에서 최적의 수를 찾기 위해 탐색 깊이를 제한하며 점진적으로 확장합니다.

예시: 체스 엔진


체스 엔진은 여러 수를 탐색하여 최적의 수를 결정해야 합니다. IDS는 초기 깊이에서 탐색을 시작하며, 제한 시간을 초과하지 않는 범위에서 탐색 깊이를 점진적으로 증가시킵니다.

주요 이점

  • 탐색 시간에 따라 유연하게 작동
  • 메모리 효율성으로 인해 대규모 상태 공간에서도 사용 가능

응용 3: 로봇 경로 탐색


IDS는 로봇이 미로와 같은 복잡한 환경에서 최단 경로를 찾는 데 활용됩니다. 목표 지점까지의 경로를 점진적으로 탐색하며, 경로를 발견하지 못하면 깊이를 늘립니다.

예시: 미로 탈출


로봇이 출발점에서 목표 지점까지 이동하는 경로를 탐색합니다. IDS는 깊이 제한을 설정해 무한 루프를 방지하며, 목표 지점에 도달할 때까지 반복합니다.

주요 이점

  • 메모리 제한이 있는 임베디드 시스템에서 사용 가능
  • 최단 경로를 보장

응용 4: 웹 크롤링


웹 크롤링에서 IDS는 URL의 탐색 깊이를 제한하면서 데이터를 수집하는 데 사용됩니다.

예시: 깊이 제한 크롤링


웹 크롤러가 특정 사이트에서 최대 N 깊이까지 링크를 따라가며 데이터를 수집합니다. IDS를 사용하면 깊이별로 탐색 범위를 제어할 수 있습니다.

주요 이점

  • 크롤링 범위를 유연하게 조정 가능
  • 메모리와 CPU 리소스를 효율적으로 사용

코드 예제: 미로 탐색

#include <stdio.h>

#define MAX 5

int maze[MAX][MAX] = {
    {0, 1, 0, 0, 0},
    {0, 1, 0, 1, 0},
    {0, 0, 0, 1, 0},
    {0, 1, 1, 1, 0},
    {0, 0, 0, 0, 0}
};

int goal_x = 4, goal_y = 4;

int depth_limited_search(int x, int y, int depth_limit) {
    if (x == goal_x && y == goal_y) return 1;
    if (depth_limit == 0) return 0;

    int dx[] = {0, 1, 0, -1};
    int dy[] = {1, 0, -1, 0};

    for (int i = 0; i < 4; i++) {
        int nx = x + dx[i];
        int ny = y + dy[i];

        if (nx >= 0 && ny >= 0 && nx < MAX && ny < MAX && maze[nx][ny] == 0) {
            maze[x][y] = -1; // 방문 표시
            if (depth_limited_search(nx, ny, depth_limit - 1)) {
                return 1;
            }
            maze[x][y] = 0; // 방문 표시 제거
        }
    }
    return 0;
}

int iterative_deepening_search(int max_depth) {
    for (int depth = 0; depth <= max_depth; depth++) {
        if (depth_limited_search(0, 0, depth)) {
            return 1;
        }
    }
    return 0;
}

int main() {
    if (iterative_deepening_search(10)) {
        printf("Goal found!\n");
    } else {
        printf("Goal not found within depth limit.\n");
    }
    return 0;
}

결과


위 코드를 실행하면 미로에서 목표 지점을 성공적으로 탐색합니다.

응용 정리


IDS는 퍼즐, 게임, 로봇 경로 탐색, 웹 크롤링 등 다양한 문제에 활용되며, 메모리 효율성과 최적성을 동시에 제공하는 유용한 알고리즘입니다.

IDS와 다른 그래프 탐색 알고리즘 비교

반복 깊이 우선 탐색(IDS)은 깊이 우선 탐색(DFS)과 너비 우선 탐색(BFS)의 장점을 결합한 알고리즘입니다. 이 섹션에서는 IDS를 BFS 및 DFS와 비교하여 각 알고리즘의 특징, 장단점, 그리고 적합한 사용 사례를 정리합니다.

기본 비교

알고리즘특징완전성최적성시간 복잡도공간 복잡도
DFS깊이 우선으로 노드 탐색아니요아니요(O(b^d))(O(d))
BFS너비 우선으로 노드 탐색(O(b^d))(O(b^d))
IDS반복적으로 깊이를 늘려가며 탐색(O(b^d))(O(d))
  • (b): 그래프의 평균 branching factor (노드 당 자식 수)
  • (d): 목표 상태까지의 깊이

DFS와의 비교

유사점

  • 두 알고리즘 모두 깊이 우선으로 탐색합니다.
  • 현재 경로만 저장하므로 메모리 사용량이 적습니다.

차이점

항목DFSIDS
완전성무한 그래프나 사이클이 있을 경우 보장되지 않음항상 완전성을 보장
최적성보장되지 않음최적 경로를 보장
탐색 방식한 번의 깊이 우선 탐색반복적으로 깊이를 증가시키며 탐색

사용 사례

  • DFS는 빠르게 해를 찾는 경우 적합하지만, 무한 루프 방지가 필요합니다.
  • IDS는 최적의 해를 찾고, 메모리를 효율적으로 사용해야 할 때 유리합니다.

BFS와의 비교

유사점

  • 두 알고리즘 모두 완전성과 최적성을 보장합니다.
  • 목표 상태를 탐색할 때, 목표 상태의 깊이에 따라 성능이 결정됩니다.

차이점

항목BFSIDS
메모리 사용량많은 메모리 사용 ((O(b^d)))적은 메모리 사용 ((O(d)))
탐색 방식모든 노드를 한 층씩 탐색깊이를 점진적으로 증가시키며 탐색
적합한 문제메모리 제약이 없는 환경메모리 제약이 있는 환경

사용 사례

  • BFS는 메모리 사용량이 충분한 경우 빠르게 모든 해를 탐색할 수 있습니다.
  • IDS는 메모리 사용량이 제한적이고, 최적 경로를 찾는 것이 중요한 문제에서 적합합니다.

DFS, BFS, IDS의 요약 비교

알고리즘강점약점주요 사용 사례
DFS메모리 효율성, 간단한 구현무한 루프 가능성, 최적성 부족해를 빠르게 찾는 문제
BFS완전성, 최적성 보장높은 메모리 사용량짧고 최적의 경로가 필요한 문제
IDS완전성, 최적성, 메모리 효율성반복으로 인해 시간 소모메모리 제한, 깊이 모르는 문제

결론

  • DFS: 단순 탐색 문제에서 빠른 탐색이 필요한 경우 유용.
  • BFS: 모든 경로를 확인해야 하거나 최적 해가 중요한 문제에 적합.
  • IDS: 메모리 효율성과 최적성, 완전성을 모두 요구하는 문제에서 최적의 선택.

IDS는 BFS의 완전성과 최적성을 유지하면서 DFS의 메모리 효율성을 결합하여, 그래프 탐색에서 강력한 도구로 활용됩니다.

IDS 구현 시 발생할 수 있는 오류와 해결법

반복 깊이 우선 탐색(IDS)을 구현할 때 발생할 수 있는 일반적인 문제와 이를 해결하기 위한 방법을 소개합니다. IDS는 DFS와 BFS의 장점을 결합한 알고리즘이지만, 구현 시 세부적인 오류가 발생할 가능성이 있습니다.

문제 1: 무한 루프

원인

  • 그래프가 순환 구조를 가질 경우, 이미 방문한 노드를 다시 탐색하면서 무한 루프가 발생할 수 있습니다.
  • 깊이 제한을 제대로 설정하지 않으면 특정 경로를 반복 탐색할 수 있습니다.

해결법

  1. 노드 방문 추적
  • visited 배열 또는 플래그를 사용해 이미 방문한 노드를 추적하여 중복 탐색을 방지합니다.
   visited[node] = 1; // 방문 표시
  1. 깊이 제한 조건 확인
  • 탐색을 시작하기 전에 현재 깊이가 제한을 초과하는지 확인합니다.
   if (current_depth > depth_limit) return 0;

문제 2: 그래프 표현 오류

원인

  • 그래프를 인접 리스트나 인접 행렬로 올바르게 초기화하지 않으면 탐색 중 에러가 발생합니다.
  • 노드 연결 정보를 잘못 정의하거나 누락할 경우, 탐색 경로가 잘못됩니다.

해결법

  1. 그래프 초기화 확인
  • 그래프 초기화 코드에서 모든 노드와 간선이 정확히 설정되었는지 확인합니다.
   for (int i = 0; i < num_vertices; i++) {
       graph->adj_list[i] = NULL;
   }
  1. 간선 추가 함수 점검
  • 간선 추가 함수가 올바른 노드 간 연결을 수행하는지 확인합니다.
   void add_edge(Graph* graph, int src, int dest) {
       Node* new_node = (Node*)malloc(sizeof(Node));
       new_node->id = dest;
       new_node->next = graph->adj_list[src];
       graph->adj_list[src] = new_node;
   }

문제 3: 깊이 제한 초과 탐색

원인

  • depth_limited_dfs 함수에서 깊이 제한 조건을 무시하고 탐색을 계속 수행할 수 있습니다.

해결법

  1. 깊이 조건 추가
  • DFS 재귀 호출 전에 깊이 제한을 초과했는지 확인합니다.
   if (depth_limit == 0) return 0;
  1. 반환 조건 설정
  • 목표 상태에 도달하지 못했을 경우 재귀 호출을 중단하고 적절히 반환합니다.

문제 4: 메모리 누수

원인

  • 동적 메모리를 사용하는 경우, 탐색 후 메모리를 해제하지 않으면 누수가 발생합니다.

해결법

  1. 노드 메모리 해제
  • 탐색이 종료되면 동적으로 할당된 메모리를 해제합니다.
   free(graph->adj_list[i]);
   free(graph->adj_list);
   free(graph);
  1. 정리 코드 추가
  • main 함수 종료 전에 메모리 해제를 위한 별도의 함수(free_graph)를 작성합니다.

문제 5: 목표 상태 탐색 실패

원인

  • 목표 상태가 그래프에 존재하지 않거나, 탐색 경로가 올바르게 설정되지 않은 경우.
  • 깊이 제한이 너무 작아서 목표 상태에 도달하지 못할 수 있습니다.

해결법

  1. 목표 상태 확인
  • 탐색 전에 목표 상태가 그래프에 존재하는지 확인합니다.
  1. 충분한 깊이 설정
  • 최대 탐색 깊이를 충분히 크게 설정하여 탐색 경로가 막히지 않도록 합니다.

코드 수정 예시

문제를 해결한 depth_limited_dfs 함수의 예:

int depth_limited_dfs(Graph* graph, int start, int goal, int depth_limit, int* visited) {
    if (start == goal) return 1; // 목표 상태 발견
    if (depth_limit == 0) return 0; // 깊이 제한 초과

    visited[start] = 1; // 노드 방문 표시
    Node* temp = graph->adj_list[start];

    while (temp != NULL) {
        if (!visited[temp->id]) {
            if (depth_limited_dfs(graph, temp->id, goal, depth_limit - 1, visited)) {
                return 1; // 경로 발견
            }
        }
        temp = temp->next;
    }
    visited[start] = 0; // 방문 해제
    return 0; // 목표 상태 미발견
}

결론


IDS는 완전성과 최적성을 보장하는 강력한 알고리즘이지만, 구현 시 주의해야 할 오류가 많습니다. 무한 루프 방지, 그래프 초기화 확인, 메모리 관리, 깊이 제한 조건 설정 등의 과정을 철저히 점검해야 안정적으로 작동합니다.

요약

반복 깊이 우선 탐색(IDS)은 깊이 우선 탐색(DFS)과 너비 우선 탐색(BFS)의 장점을 결합한 알고리즘으로, 메모리 효율성과 완전성, 최적성을 동시에 제공합니다. IDS의 작동 원리와 구현 방법을 통해 메모리 사용량을 최소화하면서 최적의 경로를 탐색할 수 있습니다. IDS는 퍼즐 해결, 게임 트리 탐색, 로봇 경로 탐색 등 다양한 분야에서 활용되며, 구현 시에는 무한 루프 방지, 그래프 초기화, 메모리 관리 등을 철저히 점검해야 합니다. 본 기사를 통해 IDS의 개념과 응용 방법을 명확히 이해하고, C언어로 효율적인 구현을 수행할 수 있습니다.

목차