Theme:

현실 세계의 관계는 단순한 "연결/비연결"이 아닙니다. 방향이 있고, 비용이 다릅니다. 이런 현실을 그래프로 어떻게 표현할까요?

방향 그래프 (Directed Graph)

방향 그래프는 간선에 방향 이 있는 그래프입니다. A에서 B로의 간선이 있다고 해서 B에서 A로의 간선이 있는 것은 아닙니다.

PLAINTEXT
방향 그래프:
  A → B
  ↑   ↓
  D ← C

무방향 그래프:
  A — B
  |   |
  D — C

인접 리스트로 표현

JAVA
public class DirectedGraph {
    private List<List<Integer>> adjList;
    private int vertices;

    public DirectedGraph(int vertices) {
        this.vertices = vertices;
        adjList = new ArrayList<>();
        for (int i = 0; i < vertices; i++) {
            adjList.add(new ArrayList<>());
        }
    }

    // 방향 그래프: u → v만 추가
    public void addEdge(int u, int v) {
        adjList.get(u).add(v);
        // adjList.get(v).add(u);  ← 이 줄이 없음!
    }

    // 진입 차수(in-degree) 계산
    public int[] calculateInDegree() {
        int[] inDegree = new int[vertices];
        for (int u = 0; u < vertices; u++) {
            for (int v : adjList.get(u)) {
                inDegree[v]++;
            }
        }
        return inDegree;
    }
}

인접 행렬로 표현

JAVA
// 방향 그래프의 인접 행렬은 비대칭
// A=0, B=1, C=2, D=3
// A→B, B→C, C→D, D→A
int[][] matrix = {
    {0, 1, 0, 0},  // A → B
    {0, 0, 1, 0},  // B → C
    {0, 0, 0, 1},  // C → D
    {1, 0, 0, 0}   // D → A
};

가중치 그래프 (Weighted Graph)

간선에 비용, 거리, 시간 등의 가중치가 붙은 그래프입니다.

PLAINTEXT
     5
  A ───→ B
  │       │
 3│       │2
  ↓       ↓
  D ←──── C
     4

인접 리스트로 표현

JAVA
public class WeightedGraph {
    static class Edge {
        int to;
        int weight;

        Edge(int to, int weight) {
            this.to = to;
            this.weight = weight;
        }
    }

    private List<List<Edge>> adjList;
    private int vertices;

    public WeightedGraph(int vertices) {
        this.vertices = vertices;
        adjList = new ArrayList<>();
        for (int i = 0; i < vertices; i++) {
            adjList.add(new ArrayList<>());
        }
    }

    public void addEdge(int u, int v, int weight) {
        adjList.get(u).add(new Edge(v, weight));
    }

    public List<Edge> neighbors(int u) {
        return adjList.get(u);
    }
}

인접 행렬로 표현

JAVA
// 가중치 인접 행렬: 0 대신 가중치 값, 연결 없으면 무한대
int INF = Integer.MAX_VALUE;
int[][] matrix = {
    {0,   5, INF,   3},  // A: B(5), D(3)
    {INF, 0,   2, INF},  // B: C(2)
    {INF, INF, 0,   4},  // C: D(4)
    {INF, INF, INF, 0}   // D: 없음
};

현실 세계를 그래프로 모델링

1. SNS 팔로우 관계 — 방향 무가중치 그래프

JAVA
// A가 B를 팔로우 → 방향 간선 A → B
DirectedGraph sns = new DirectedGraph(userCount);
sns.addEdge(alice, bob);     // Alice → Bob (팔로우)
// Bob은 Alice를 팔로우하지 않을 수 있음

// 인기 사용자 = 진입 차수(follower 수)가 높은 정점
int[] inDegree = sns.calculateInDegree();
// inDegree[bob] = Bob의 팔로워 수

실제 Twitter/Instagram은 이 구조를 기반으로 합니다.

2. 도로 네트워크 — 방향 가중치 그래프

JAVA
// 교차로 = 정점, 도로 = 간선, 거리/시간 = 가중치
WeightedGraph roadNetwork = new WeightedGraph(intersectionCount);

// 일방통행도 표현 가능
roadNetwork.addEdge(gangnam, yeoksam, 5);    // 강남→역삼: 5분
roadNetwork.addEdge(yeoksam, gangnam, 7);    // 역삼→강남: 7분 (역방향 다를 수 있음)

// 네비게이션 = Dijkstra 알고리즘으로 최단 경로 계산
int[] shortestTime = dijkstra(roadNetwork, startIntersection);

3. API 호출 그래프 — 방향 가중치 그래프

마이크로서비스 아키텍처에서 서비스 간 호출 관계를 그래프로 표현할 수 있습니다.

JAVA
// 서비스 = 정점, API 호출 = 간선, 지연 시간 = 가중치
WeightedGraph serviceGraph = new WeightedGraph(serviceCount);

serviceGraph.addEdge(gateway, userService, 10);     // 게이트웨이 → 유저 서비스: 10ms
serviceGraph.addEdge(userService, authService, 5);   // 유저 → 인증: 5ms
serviceGraph.addEdge(gateway, orderService, 15);     // 게이트웨이 → 주문: 15ms
serviceGraph.addEdge(orderService, paymentService, 20); // 주문 → 결제: 20ms

이 그래프로 할 수 있는 분석:

  • ** 크리티컬 패스 **: 가장 긴 경로 → 전체 응답 시간의 병목
  • ** 순환 의존성 **: 사이클 감지 → 아키텍처 문제
  • ** 장애 전파 **: 특정 서비스 장애 시 영향받는 서비스 범위

4. 웹 페이지 — 방향 그래프

PLAINTEXT
PageRank:
- 웹 페이지 = 정점
- 하이퍼링크 = 방향 간선
- Google의 PageRank는 이 방향 그래프에서 각 페이지의 "중요도"를 계산

5. 작업 의존성 — DAG (방향 비순환 그래프)

JAVA
// 빌드 시스템: 작업 간 의존성
// compile → test → package → deploy
WeightedGraph buildPipeline = new WeightedGraph(4);
buildPipeline.addEdge(compile, test, 30);      // 컴파일(30초) 후 테스트
buildPipeline.addEdge(test, pack, 60);          // 테스트(60초) 후 패키징
buildPipeline.addEdge(pack, deploy, 10);        // 패키징(10초) 후 배포

음수 가중치의 문제

가중치가 음수인 경우 특별한 주의가 필요합니다.

PLAINTEXT
     2
  A ───→ B
  │       │
 5│       │-10
  ↓       ↓
  D ←──── C
     3

Dijkstra는 음수 가중치를 처리하지 못합니다

Dijkstra는 "이미 확정한 최단 거리는 변하지 않는다"는 가정에 기반합니다. 음수 가중치가 있으면 이 가정이 깨집니다.

Bellman-Ford 알고리즘

JAVA
public int[] bellmanFord(int vertices, List<int[]> edges, int start) {
    int[] dist = new int[vertices];
    Arrays.fill(dist, Integer.MAX_VALUE);
    dist[start] = 0;

    // V-1번 반복
    for (int i = 0; i < vertices - 1; i++) {
        for (int[] edge : edges) {
            int u = edge[0], v = edge[1], w = edge[2];
            if (dist[u] != Integer.MAX_VALUE && dist[u] + w < dist[v]) {
                dist[v] = dist[u] + w;
            }
        }
    }

    // 음수 사이클 감지: V번째 반복에서도 갱신이 발생하면 음수 사이클
    for (int[] edge : edges) {
        int u = edge[0], v = edge[1], w = edge[2];
        if (dist[u] != Integer.MAX_VALUE && dist[u] + w < dist[v]) {
            throw new RuntimeException("음수 사이클 존재!");
        }
    }

    return dist;
}

Spring/백엔드에서의 활용

서비스 의존성 시각화

JAVA
@Component
public class ServiceDependencyGraph {
    private final Map<String, List<Dependency>> graph = new HashMap<>();

    @Data
    @AllArgsConstructor
    static class Dependency {
        String target;
        double avgLatency; // 평균 지연 시간
        int callCount;     // 호출 횟수
    }

    // Micrometer/Zipkin 등에서 수집한 데이터로 그래프 구축
    public void addCall(String from, String to, double latency) {
        graph.computeIfAbsent(from, k -> new ArrayList<>())
             .add(new Dependency(to, latency, 1));
    }

    // 크리티컬 패스 분석: 가장 긴 경로 찾기
    public List<String> findCriticalPath(String start) {
        // DAG에서 최장 경로 = 위상 정렬 후 DP
        // ...
    }
}

그래프 알고리즘 선택 가이드

문제그래프 유형알고리즘
최단 경로 (양수)가중치 방향Dijkstra
최단 경로 (음수)가중치 방향Bellman-Ford
모든 쌍 최단 경로가중치 방향Floyd-Warshall
최소 신장 트리가중치 무방향Kruskal/Prim
위상 정렬방향 비순환Kahn/DFS
연결 요소무방향BFS/DFS/Union-Find

정리

  • ** 방향 그래프 **는 간선에 방향이 있어, 팔로우 관계나 API 호출 관계를 표현합니다.
  • ** 가중치 그래프 **는 간선에 비용이 있어, 거리, 시간, 대역폭 등을 표현합니다.
  • 도로 네트워크, SNS, MSA 서비스 호출 등 ** 현실의 대부분의 관계 **는 방향 가중치 그래프로 모델링됩니다.
  • 음수 가중치가 있으면 Dijkstra 대신 Bellman-Ford 를 사용해야 합니다.
  • 그래프 모델링 능력은 백엔드 아키텍처 이해와 문제 해결에 직접적으로 도움이 됩니다.
댓글 로딩 중...