Skip to content

Lecture 24. 자료구조

개요

핵심 질문

  • 각 자료구조는 어떤 문제를 해결하기 위해 설계되었는가?
  • 시간·공간 복잡도는 어떻게 분석하는가?
  • AI 알고리즘에서 각 자료구조는 어떻게 활용되는가?

학습 목표

  • 배열·연결 리스트·스택·큐·해시 테이블·트리·그래프의 정의와 연산 복잡도를 설명할 수 있다.
  • 각 자료구조의 장단점을 비교하고 적합한 상황을 선택할 수 있다.
  • AI 개발자 관점에서 각 자료구조가 어떤 시스템에 활용되는지 연결할 수 있다.

핵심 개념

1. 복잡도 분석

시간 복잡도 (Time Complexity)

입력 크기 nn에 따른 연산 횟수의 점근적 관계.

빅 오 표기법 (Big-O Notation)

함수의 점근적 상한 — 실행 시간이 이 이상은 커지지 않는다.

O(g(n))={f(n)c>0, n0: f(n)cg(n) nn0} O(g(n)) = \{f(n) \mid \exists c > 0,\ n_0:\ f(n) \leq c \cdot g(n)\ \forall n \geq n_0\}

표기이름예시
O(1)O(1)상수 시간해시 테이블 조회, 배열 인덱스 접근
O(logn)O(\log n)로그 시간이진 탐색, BST 탐색
O(n)O(n)선형 시간배열 순회, 선형 탐색
O(nlogn)O(n \log n)선형 로그병합 정렬, 힙 정렬
O(n2)O(n^2)이차 시간버블 정렬, 인접 행렬 탐색
O(2n)O(2^n)지수 시간완전 탐색(부분집합)
  • 빅 세타 Θ\Theta: 평균적인 실행 시간 (점근적 정확한 경계)
  • 빅 오메가 Ω\Omega: 점근적 하한

공간 복잡도 (Space Complexity)

프로그램 실행에 필요한 메모리 자원의 양. 시간-공간 트레이드오프가 자주 발생한다.

AI 개발자 관점

  • 모델 추론 시간은 주로 행렬 곱의 O(n2)O(n^2) 또는 O(n3)O(n^3) 복잡도에 지배된다.
  • Transformer Self-Attention의 시간 복잡도는 시퀀스 길이 nn에 대해 O(n2d)O(n^2 d) → 긴 시퀀스 처리 병목의 수학적 원인.
  • FlashAttention은 메모리 접근 패턴을 최적화하여 같은 O(n2)O(n^2)이지만 실제 속도를 크게 개선한다.

2. 배열 (Array)

정의

동일한 타입의 원소들이 연속된 메모리 공간에 순차적으로 저장되는 자료구조.

연산 복잡도

연산복잡도이유
인덱스 접근O(1)O(1)기준 주소 + 오프셋 계산
탐색O(n)O(n)최악의 경우 전체 순회
삽입/삭제 (중간)O(n)O(n)이후 원소 전부 이동
삽입/삭제 (끝)O(1)O(1)이동 불필요
  • 정적 배열: 크기가 컴파일 타임에 고정
  • 동적 배열: 런타임에 크기 변경 가능 (Python list, C++ vector) — 용량 초과 시 새 배열 할당 후 복사 (O(n)O(n) amortized O(1)O(1))

AI 개발자 심화

  • 텐서(Tensor): 다차원 배열의 일반화. NumPy ndarray, PyTorch Tensor가 모두 내부적으로 연속 메모리 배열.
  • 메모리 레이아웃: Row-major(C order) vs Column-major(Fortran order) — 행렬 곱 방향에 따라 캐시 히트율이 달라져 실제 연산 속도에 영향.
  • Stride: 텐서의 각 차원에서 다음 원소로 이동하기 위한 메모리 건너뜀 수. tensor.stride()로 확인 가능. View 연산은 데이터를 복사하지 않고 stride만 변경.
  • 임베딩 룩업: Embedding 레이어는 사실 임베딩 행렬(2D 배열)에서 행 인덱스로 O(1)O(1) 접근하는 배열 연산.

3. 연결 리스트 (Linked List)

정의

노드(데이터 + 다음 노드 포인터)들이 포인터로 연결된 자료구조. 메모리가 불연속적으로 배치된다.

종류

종류특징
단일 연결 리스트단방향 탐색, 각 노드에 next 포인터 1개
이중 연결 리스트양방향 탐색, prev + next 포인터 2개
환형 연결 리스트꼬리가 헤드를 가리켜 원형 구성

연산 복잡도

연산복잡도비고
인덱스 접근O(n)O(n)헤드부터 순차 탐색
탐색O(n)O(n)
삽입/삭제 (위치 알 때)O(1)O(1)포인터 변경만
삽입/삭제 (위치 탐색 포함)O(n)O(n)

배열 vs 연결 리스트

배열연결 리스트
메모리연속 (캐시 친화)불연속 (캐시 비효율)
인덱스 접근O(1)O(1)O(n)O(n)
삽입/삭제O(n)O(n)O(1)O(1) (위치 알 때)
크기 변경어려움유연

AI 개발자 심화

  • 동적 계산 그래프: PyTorch의 자동 미분은 내부적으로 연산 노드들을 연결 리스트 구조로 관리하여 역전파 경로를 추적한다.
  • KV Cache: LLM 추론 시 이전 토큰의 Key·Value를 캐싱할 때 시퀀셜 메모리 구조로 관리.

4. 스택 (Stack)

정의

한쪽 끝(top)에서만 삽입·삭제가 가능한 후입선출(LIFO, Last-In First-Out) 자료구조.

핵심 연산

  • Push: top에 원소 삽입 O(1)O(1)
  • Pop: top에서 원소 제거 O(1)O(1)
  • Peek: top 원소 조회 O(1)O(1)

주요 활용

  • 함수 호출 스택(Call Stack): 재귀 함수 실행 순서 관리
  • 수식 파싱: 괄호 검사, 후위 표기법 변환
  • DFS 구현: 방문 스택
  • 되돌리기(Undo) 기능

AI 개발자 심화

  • 역전파 실행 순서: 순전파 중 각 연산의 중간 결과와 로컬 그래디언트를 스택 구조로 저장하고, 역방향으로 순서대로 꺼내며 연쇄 법칙 적용.
  • 재귀 → 스택 변환: 깊은 재귀로 구현된 트리 순회나 DFS는 콜 스택 오버플로 위험이 있으므로 명시적 스택으로 변환하여 처리.

5. 큐 (Queue)

정의

한쪽(rear)으로 삽입, 다른 쪽(front)으로 삭제하는 선입선출(FIFO, First-In First-Out) 자료구조.

핵심 연산

  • Enqueue: rear에 원소 삽입 O(1)O(1)
  • Dequeue: front에서 원소 제거 O(1)O(1)

변형

종류특징
원형 큐배열 기반, 양 끝을 원형으로 연결하여 공간 재사용
덱 (Deque)양쪽에서 삽입·삭제 모두 가능
우선순위 큐우선순위가 높은 원소를 먼저 처리, 힙으로 구현 O(logn)O(\log n)

주요 활용

  • BFS 구현
  • 작업 스케줄링, 버퍼(네트워크 패킷, 프린터 대기열)
  • 슬라이딩 윈도우

AI 개발자 심화

  • 빔 서치 (Beam Search): 텍스트 생성에서 상위 kk개 후보를 유지하며 탐색. 우선순위 큐로 각 스텝에서 확률이 높은 토큰 시퀀스를 효율적으로 관리.
  • 데이터 로더 버퍼: PyTorch DataLoader는 내부적으로 큐를 사용하여 CPU 전처리와 GPU 연산을 파이프라인화한다.
  • 경험 재생 버퍼 (Replay Buffer): DQN에서 과거 경험 (s,a,r,s)(s, a, r, s')을 원형 큐에 저장하고 랜덤 샘플링하여 상관관계 제거.

6. 해시 테이블 (Hash Table)

정의

키(Key)를 해시 함수로 변환하여 배열의 인덱스에 대응시키는 자료구조.

index=h(key)modM \text{index} = h(\text{key}) \mod M

해시 함수 (Hash Function)

임의 길이의 입력 → 고정 길이의 해시 값으로 변환하는 단방향 함수.

좋은 해시 함수의 조건:

  • 결정론적: 같은 입력 → 항상 같은 출력
  • 균등 분포: 해시 값이 버킷 전체에 고루 분포
  • 빠른 계산: O(1)O(1) 또는 입력 길이에 비례

연산 복잡도

연산평균최악 (충돌 심할 때)
탐색O(1)O(1)O(n)O(n)
삽입O(1)O(1)O(n)O(n)
삭제O(1)O(1)O(n)O(n)

해시 충돌 해결

방법설명특징
체이닝 (Chaining)같은 버킷에 연결 리스트로 연결구현 단순, 메모리 오버헤드
개방 주소법다른 빈 버킷에 저장캐시 친화적
선형 조사법다음 인덱스 순차 탐색군집화 문제
이차 조사법제곱 간격으로 탐색군집화 완화
이중 해싱두 번째 해시 함수로 간격 결정군집화 최소화

부하율 (Load Factor)

α=nM(n:저장된 원소 수, M:버킷 수) \alpha = \frac{n}{M} \quad (n: \text{저장된 원소 수},\ M: \text{버킷 수})

α\alpha가 커질수록 충돌 확률 증가. 일반적으로 α>0.7\alpha > 0.7이면 리해싱(rehashing).

AI 개발자 심화

  • 토크나이저 어휘 사전: GPT, BERT의 토크나이저는 토큰 문자열 → 정수 ID 매핑에 해시맵을 사용. 수십만 개 어휘에서 O(1)O(1) 인코딩/디코딩.
  • 임베딩 룩업 테이블: nn.Embedding은 정수 인덱스 → 임베딩 벡터의 해시 테이블 기반 매핑.
  • 특성 해싱 (Feature Hashing): 고차원 범주형 특성을 해시로 고정 차원 벡터에 매핑 — 메모리 절약, 충돌 허용.
  • 중복 제거: 데이터 전처리 중 중복 샘플 제거 시 해시 기반 set 자료구조 활용.

7. 트리 (Tree)

정의

노드(Node)와 간선(Edge)으로 구성된 계층적 자료구조. 사이클이 없는 연결 그래프.

기본 용어

용어설명
루트 노드최상위 노드, 부모 없음
리프 노드최하위 노드, 자식 없음
깊이(Depth)루트에서 해당 노드까지의 간선 수
높이(Height)루트에서 가장 깊은 리프까지의 간선 수
차수(Degree)자식 노드의 수

트리의 순회

방법순서특징
전위(Pre-order)루트 → 왼쪽 → 오른쪽트리 복사, 직렬화
중위(In-order)왼쪽 → 루트 → 오른쪽BST에서 오름차순 출력
후위(Post-order)왼쪽 → 오른쪽 → 루트하위 노드 먼저 처리
레벨(BFS)레벨 순서최단 경로, BFS 탐색

주요 트리 종류

이진 탐색 트리 (BST)

  • 왼쪽 서브트리: 루트보다 작은 값
  • 오른쪽 서브트리: 루트보다 큰 값
  • 탐색·삽입·삭제: 평균 O(logn)O(\log n), 최악(편향) O(n)O(n)

힙 (Heap)

완전 이진 트리 기반. 우선순위 큐 구현에 사용.

  • 최대 힙: 부모 ≥ 자식
  • 최소 힙: 부모 ≤ 자식
  • 삽입·삭제: O(logn)O(\log n), 최대·최솟값 조회: O(1)O(1)

자가 균형 트리 (AVL, Red-Black Tree)

삽입·삭제 후에도 트리 높이 O(logn)O(\log n) 유지.

  • Red-Black 트리: 삽입·삭제 O(logn)O(\log n), 색상 규칙으로 균형 유지
  • 실제 활용: 대부분의 언어 표준 라이브러리의 정렬된 맵(C++ std::map, Java TreeMap)

B-트리 / B+트리

  • 하나의 노드에 여러 키를 저장하는 다진 탐색 트리
  • 디스크 I/O 최소화 — 한 번의 블록 읽기로 많은 키 비교 가능
  • B+트리: 실제 데이터를 모두 리프 노드에 저장, 리프 노드를 연결 리스트로 연결 → 범위 검색 효율적

트라이 (Trie)

문자열을 문자 단위로 노드에 저장하는 트리. 문자열 탐색 O(L)O(L) (LL: 문자열 길이).

AI 개발자 심화

  • 결정 트리 (Decision Tree): 트리 구조로 분류·회귀를 수행. 각 노드에서 특성 기준으로 분기. XGBoost·LightGBM·CatBoost 모두 앙상블 결정 트리.
  • MCTS (Monte Carlo Tree Search): AlphaGo·AlphaZero에서 사용. 게임 상태를 트리 노드로 표현하고 UCB(Upper Confidence Bound)로 탐험·활용 균형.

UCB(v)=wini+clnNni \text{UCB}(v) = \frac{w_i}{n_i} + c\sqrt{\frac{\ln N}{n_i}}

  • wiw_i: 노드 ii의 누적 보상, nin_i: 방문 횟수, NN: 부모 방문 횟수, cc: 탐험 계수
  • 토크나이저 트라이: BPE(Byte Pair Encoding) 토크나이저 구현에 트라이를 활용하여 빠른 문자열 매칭.
  • 벡터 DB 인덱스 (HNSW): 계층적 그래프 구조로 근사 최근접 이웃 탐색 수행 — 트리와 그래프의 혼합 구조.

8. 그래프 (Graph)

정의

정점(Vertex)과 간선(Edge)으로 구성된 자료구조. 트리는 그래프의 특수 케이스(사이클 없는 연결 그래프).

G=(V,E) G = (V, E)

그래프의 종류

종류설명
무방향 그래프간선에 방향 없음
방향 그래프 (DAG 포함)간선에 방향 있음
가중치 그래프간선에 비용(가중치) 부여
연결 그래프임의의 두 정점 사이에 경로 존재
DAGDirected Acyclic Graph — 방향 있고 사이클 없음

그래프 표현 방식

인접 행렬: O(V2)O(V^2) 공간, 간선 존재 확인 O(1)O(1)

Aij={wij(i,j)E0otherwise A_{ij} = \begin{cases} w_{ij} & (i, j) \in E \\ 0 & \text{otherwise} \end{cases}

인접 리스트: O(V+E)O(V + E) 공간, 희소 그래프에 효율적

주요 탐색 알고리즘

깊이 우선 탐색 (DFS)

스택(또는 재귀)을 사용하여 최대한 깊이 탐색.

  • 시간 복잡도: O(V+E)O(V + E)
  • 활용: 사이클 탐지, 위상 정렬, 연결 요소 탐색

너비 우선 탐색 (BFS)

큐를 사용하여 레벨 단위로 탐색.

  • 시간 복잡도: O(V+E)O(V + E)
  • 활용: 비가중치 그래프 최단 경로

최단 경로 알고리즘

다익스트라 알고리즘 (단일 출발, 비음수 가중치):

d[v]=minuvisited(d[u]+w(u,v)) d[v] = \min_{u \in \text{visited}} \left(d[u] + w(u, v)\right)

우선순위 큐 사용 시 시간 복잡도: O((V+E)logV)O((V + E)\log V)

벨만-포드 알고리즘: 음수 가중치 허용, O(VE)O(VE)

플로이드-워셜: 모든 쌍 최단 경로, O(V3)O(V^3)

위상 정렬 (Topological Sort)

DAG에서 모든 간선 (u,v)(u, v)에 대해 uuvv보다 먼저 오는 순서.

  • Kahn 알고리즘 (BFS 기반): 진입 차수가 0인 정점부터 처리
  • 시간 복잡도: O(V+E)O(V + E)

AI 개발자 심화

  • 계산 그래프 (Computational Graph): 신경망의 순전파·역전파는 DAG 위에서 이루어진다. PyTorch의 autograd 엔진은 DAG를 역방향 위상 정렬 순서로 순회하며 그래디언트를 계산한다.
  • GNN (Graph Neural Network): 그래프 데이터(소셜 네트워크, 분자 구조, 지식 그래프)를 직접 처리하는 신경망. 각 노드가 이웃 노드의 특성을 집계(Message Passing)하여 표현 업데이트.

hv(k)=UPDATE ⁣(hv(k1), AGGREGATE ⁣({hu(k1):uN(v)})) \mathbf{h}_v^{(k)} = \text{UPDATE}\!\left(\mathbf{h}_v^{(k-1)},\ \text{AGGREGATE}\!\left(\{\mathbf{h}_u^{(k-1)} : u \in \mathcal{N}(v)\}\right)\right)

  • 지식 그래프 (Knowledge Graph): 엔티티(노드)와 관계(간선)로 구성. RAG 시스템에서 구조화된 외부 지식으로 활용.
  • 분자 설계: 원자(노드)·결합(간선)을 그래프로 표현 → GNN으로 물성 예측·신약 후보 생성.
  • 추천 시스템: 사용자-아이템 이분 그래프에 GNN 적용 → 협업 필터링.

9. 정렬 알고리즘

주요 정렬 알고리즘 비교

알고리즘평균최악공간안정
버블 정렬O(n2)O(n^2)O(n2)O(n^2)O(1)O(1)
삽입 정렬O(n2)O(n^2)O(n2)O(n^2)O(1)O(1)
선택 정렬O(n2)O(n^2)O(n2)O(n^2)O(1)O(1)
퀵 정렬O(nlogn)O(n\log n)O(n2)O(n^2)O(logn)O(\log n)
병합 정렬O(nlogn)O(n\log n)O(nlogn)O(n\log n)O(n)O(n)
힙 정렬O(nlogn)O(n\log n)O(nlogn)O(n\log n)O(1)O(1)
계수 정렬O(n+k)O(n+k)O(n+k)O(n+k)O(k)O(k)

정렬의 비교 기반 하한: Ω(nlogn)\Omega(n\log n) (결정 트리 논증).

AI 개발자 심화

  • Top-K 추출: LLM의 Top-K 샘플링, 추천 시스템의 Top-K 아이템 추출에서 전체 정렬 대신 힙을 이용한 부분 정렬 O(nlogk)O(n\log k) 사용.
  • Argsort: PyTorch torch.argsort는 인덱스 기반 정렬 — 어텐션 점수 랭킹, 특성 중요도 정렬에 활용.

수식 정리

시간 복잡도 빅 오 정의

f(n)=O(g(n))c,n0: f(n)cg(n), nn0 f(n) = O(g(n)) \Leftrightarrow \exists c, n_0:\ f(n) \leq c \cdot g(n),\ \forall n \geq n_0

주요 자료구조 복잡도 요약

자료구조탐색삽입삭제공간
배열O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)
해시 테이블O(1)O(1) avgO(1)O(1) avgO(1)O(1) avgO(n)O(n)
이진 탐색 트리O(logn)O(\log n) avgO(logn)O(\log n) avgO(logn)O(\log n) avgO(n)O(n)
O(n)O(n)O(logn)O(\log n)O(logn)O(\log n)O(n)O(n)
그래프 (인접 리스트)O(V+E)O(V+E)O(1)O(1)O(E)O(E)O(V+E)O(V+E)

Self-Attention 복잡도

O(n2d)(n:시퀀스 길이, d:차원) O(n^2 d) \quad (n: \text{시퀀스 길이},\ d: \text{차원})

MCTS UCB

UCB(v)=wini+clnNni \text{UCB}(v) = \frac{w_i}{n_i} + c\sqrt{\frac{\ln N}{n_i}}

GNN 메시지 패싱

hv(k)=UPDATE ⁣(hv(k1), uN(v)hu(k1)) \mathbf{h}_v^{(k)} = \text{UPDATE}\!\left(\mathbf{h}_v^{(k-1)},\ \bigoplus_{u \in \mathcal{N}(v)} \mathbf{h}_u^{(k-1)}\right)

다익스트라 갱신 조건

d[v]>d[u]+w(u,v)d[v]d[u]+w(u,v) d[v] > d[u] + w(u,v) \Rightarrow d[v] \leftarrow d[u] + w(u,v)