Lecture 24. 자료구조
개요
핵심 질문
- 각 자료구조는 어떤 문제를 해결하기 위해 설계되었는가?
- 시간·공간 복잡도는 어떻게 분석하는가?
- AI 알고리즘에서 각 자료구조는 어떻게 활용되는가?
학습 목표
- 배열·연결 리스트·스택·큐·해시 테이블·트리·그래프의 정의와 연산 복잡도를 설명할 수 있다.
- 각 자료구조의 장단점을 비교하고 적합한 상황을 선택할 수 있다.
- AI 개발자 관점에서 각 자료구조가 어떤 시스템에 활용되는지 연결할 수 있다.
핵심 개념
1. 복잡도 분석
시간 복잡도 (Time Complexity)
입력 크기 에 따른 연산 횟수의 점근적 관계.
빅 오 표기법 (Big-O Notation)
함수의 점근적 상한 — 실행 시간이 이 이상은 커지지 않는다.
| 표기 | 이름 | 예시 |
|---|---|---|
| 상수 시간 | 해시 테이블 조회, 배열 인덱스 접근 | |
| 로그 시간 | 이진 탐색, BST 탐색 | |
| 선형 시간 | 배열 순회, 선형 탐색 | |
| 선형 로그 | 병합 정렬, 힙 정렬 | |
| 이차 시간 | 버블 정렬, 인접 행렬 탐색 | |
| 지수 시간 | 완전 탐색(부분집합) |
- 빅 세타 : 평균적인 실행 시간 (점근적 정확한 경계)
- 빅 오메가 : 점근적 하한
공간 복잡도 (Space Complexity)
프로그램 실행에 필요한 메모리 자원의 양. 시간-공간 트레이드오프가 자주 발생한다.
AI 개발자 관점
- 모델 추론 시간은 주로 행렬 곱의 또는 복잡도에 지배된다.
- Transformer Self-Attention의 시간 복잡도는 시퀀스 길이 에 대해 → 긴 시퀀스 처리 병목의 수학적 원인.
- FlashAttention은 메모리 접근 패턴을 최적화하여 같은 이지만 실제 속도를 크게 개선한다.
2. 배열 (Array)
정의
동일한 타입의 원소들이 연속된 메모리 공간에 순차적으로 저장되는 자료구조.
연산 복잡도
| 연산 | 복잡도 | 이유 |
|---|---|---|
| 인덱스 접근 | 기준 주소 + 오프셋 계산 | |
| 탐색 | 최악의 경우 전체 순회 | |
| 삽입/삭제 (중간) | 이후 원소 전부 이동 | |
| 삽입/삭제 (끝) | 이동 불필요 |
- 정적 배열: 크기가 컴파일 타임에 고정
- 동적 배열: 런타임에 크기 변경 가능 (Python
list, C++vector) — 용량 초과 시 새 배열 할당 후 복사 ( amortized )
AI 개발자 심화
- 텐서(Tensor): 다차원 배열의 일반화. NumPy ndarray, PyTorch Tensor가 모두 내부적으로 연속 메모리 배열.
- 메모리 레이아웃: Row-major(C order) vs Column-major(Fortran order) — 행렬 곱 방향에 따라 캐시 히트율이 달라져 실제 연산 속도에 영향.
- Stride: 텐서의 각 차원에서 다음 원소로 이동하기 위한 메모리 건너뜀 수.
tensor.stride()로 확인 가능. View 연산은 데이터를 복사하지 않고 stride만 변경. - 임베딩 룩업: Embedding 레이어는 사실 임베딩 행렬(2D 배열)에서 행 인덱스로 접근하는 배열 연산.
3. 연결 리스트 (Linked List)
정의
노드(데이터 + 다음 노드 포인터)들이 포인터로 연결된 자료구조. 메모리가 불연속적으로 배치된다.
종류
| 종류 | 특징 |
|---|---|
| 단일 연결 리스트 | 단방향 탐색, 각 노드에 next 포인터 1개 |
| 이중 연결 리스트 | 양방향 탐색, prev + next 포인터 2개 |
| 환형 연결 리스트 | 꼬리가 헤드를 가리켜 원형 구성 |
연산 복잡도
| 연산 | 복잡도 | 비고 |
|---|---|---|
| 인덱스 접근 | 헤드부터 순차 탐색 | |
| 탐색 | ||
| 삽입/삭제 (위치 알 때) | 포인터 변경만 | |
| 삽입/삭제 (위치 탐색 포함) |
배열 vs 연결 리스트
| 배열 | 연결 리스트 | |
|---|---|---|
| 메모리 | 연속 (캐시 친화) | 불연속 (캐시 비효율) |
| 인덱스 접근 | ||
| 삽입/삭제 | (위치 알 때) | |
| 크기 변경 | 어려움 | 유연 |
AI 개발자 심화
- 동적 계산 그래프: PyTorch의 자동 미분은 내부적으로 연산 노드들을 연결 리스트 구조로 관리하여 역전파 경로를 추적한다.
- KV Cache: LLM 추론 시 이전 토큰의 Key·Value를 캐싱할 때 시퀀셜 메모리 구조로 관리.
4. 스택 (Stack)
정의
한쪽 끝(top)에서만 삽입·삭제가 가능한 후입선출(LIFO, Last-In First-Out) 자료구조.
핵심 연산
- Push: top에 원소 삽입
- Pop: top에서 원소 제거
- Peek: top 원소 조회
주요 활용
- 함수 호출 스택(Call Stack): 재귀 함수 실행 순서 관리
- 수식 파싱: 괄호 검사, 후위 표기법 변환
- DFS 구현: 방문 스택
- 되돌리기(Undo) 기능
AI 개발자 심화
- 역전파 실행 순서: 순전파 중 각 연산의 중간 결과와 로컬 그래디언트를 스택 구조로 저장하고, 역방향으로 순서대로 꺼내며 연쇄 법칙 적용.
- 재귀 → 스택 변환: 깊은 재귀로 구현된 트리 순회나 DFS는 콜 스택 오버플로 위험이 있으므로 명시적 스택으로 변환하여 처리.
5. 큐 (Queue)
정의
한쪽(rear)으로 삽입, 다른 쪽(front)으로 삭제하는 선입선출(FIFO, First-In First-Out) 자료구조.
핵심 연산
- Enqueue: rear에 원소 삽입
- Dequeue: front에서 원소 제거
변형
| 종류 | 특징 |
|---|---|
| 원형 큐 | 배열 기반, 양 끝을 원형으로 연결하여 공간 재사용 |
| 덱 (Deque) | 양쪽에서 삽입·삭제 모두 가능 |
| 우선순위 큐 | 우선순위가 높은 원소를 먼저 처리, 힙으로 구현 |
주요 활용
- BFS 구현
- 작업 스케줄링, 버퍼(네트워크 패킷, 프린터 대기열)
- 슬라이딩 윈도우
AI 개발자 심화
- 빔 서치 (Beam Search): 텍스트 생성에서 상위 개 후보를 유지하며 탐색. 우선순위 큐로 각 스텝에서 확률이 높은 토큰 시퀀스를 효율적으로 관리.
- 데이터 로더 버퍼: PyTorch DataLoader는 내부적으로 큐를 사용하여 CPU 전처리와 GPU 연산을 파이프라인화한다.
- 경험 재생 버퍼 (Replay Buffer): DQN에서 과거 경험 을 원형 큐에 저장하고 랜덤 샘플링하여 상관관계 제거.
6. 해시 테이블 (Hash Table)
정의
키(Key)를 해시 함수로 변환하여 배열의 인덱스에 대응시키는 자료구조.
해시 함수 (Hash Function)
임의 길이의 입력 → 고정 길이의 해시 값으로 변환하는 단방향 함수.
좋은 해시 함수의 조건:
- 결정론적: 같은 입력 → 항상 같은 출력
- 균등 분포: 해시 값이 버킷 전체에 고루 분포
- 빠른 계산: 또는 입력 길이에 비례
연산 복잡도
| 연산 | 평균 | 최악 (충돌 심할 때) |
|---|---|---|
| 탐색 | ||
| 삽입 | ||
| 삭제 |
해시 충돌 해결
| 방법 | 설명 | 특징 |
|---|---|---|
| 체이닝 (Chaining) | 같은 버킷에 연결 리스트로 연결 | 구현 단순, 메모리 오버헤드 |
| 개방 주소법 | 다른 빈 버킷에 저장 | 캐시 친화적 |
| 선형 조사법 | 다음 인덱스 순차 탐색 | 군집화 문제 |
| 이차 조사법 | 제곱 간격으로 탐색 | 군집화 완화 |
| 이중 해싱 | 두 번째 해시 함수로 간격 결정 | 군집화 최소화 |
부하율 (Load Factor)
가 커질수록 충돌 확률 증가. 일반적으로 이면 리해싱(rehashing).
AI 개발자 심화
- 토크나이저 어휘 사전: GPT, BERT의 토크나이저는 토큰 문자열 → 정수 ID 매핑에 해시맵을 사용. 수십만 개 어휘에서 인코딩/디코딩.
- 임베딩 룩업 테이블:
nn.Embedding은 정수 인덱스 → 임베딩 벡터의 해시 테이블 기반 매핑. - 특성 해싱 (Feature Hashing): 고차원 범주형 특성을 해시로 고정 차원 벡터에 매핑 — 메모리 절약, 충돌 허용.
- 중복 제거: 데이터 전처리 중 중복 샘플 제거 시 해시 기반 set 자료구조 활용.
7. 트리 (Tree)
정의
노드(Node)와 간선(Edge)으로 구성된 계층적 자료구조. 사이클이 없는 연결 그래프.
기본 용어
| 용어 | 설명 |
|---|---|
| 루트 노드 | 최상위 노드, 부모 없음 |
| 리프 노드 | 최하위 노드, 자식 없음 |
| 깊이(Depth) | 루트에서 해당 노드까지의 간선 수 |
| 높이(Height) | 루트에서 가장 깊은 리프까지의 간선 수 |
| 차수(Degree) | 자식 노드의 수 |
트리의 순회
| 방법 | 순서 | 특징 |
|---|---|---|
| 전위(Pre-order) | 루트 → 왼쪽 → 오른쪽 | 트리 복사, 직렬화 |
| 중위(In-order) | 왼쪽 → 루트 → 오른쪽 | BST에서 오름차순 출력 |
| 후위(Post-order) | 왼쪽 → 오른쪽 → 루트 | 하위 노드 먼저 처리 |
| 레벨(BFS) | 레벨 순서 | 최단 경로, BFS 탐색 |
주요 트리 종류
이진 탐색 트리 (BST)
- 왼쪽 서브트리: 루트보다 작은 값
- 오른쪽 서브트리: 루트보다 큰 값
- 탐색·삽입·삭제: 평균 , 최악(편향)
힙 (Heap)
완전 이진 트리 기반. 우선순위 큐 구현에 사용.
- 최대 힙: 부모 ≥ 자식
- 최소 힙: 부모 ≤ 자식
- 삽입·삭제: , 최대·최솟값 조회:
자가 균형 트리 (AVL, Red-Black Tree)
삽입·삭제 후에도 트리 높이 유지.
- Red-Black 트리: 삽입·삭제 , 색상 규칙으로 균형 유지
- 실제 활용: 대부분의 언어 표준 라이브러리의 정렬된 맵(C++
std::map, JavaTreeMap)
B-트리 / B+트리
- 하나의 노드에 여러 키를 저장하는 다진 탐색 트리
- 디스크 I/O 최소화 — 한 번의 블록 읽기로 많은 키 비교 가능
- B+트리: 실제 데이터를 모두 리프 노드에 저장, 리프 노드를 연결 리스트로 연결 → 범위 검색 효율적
트라이 (Trie)
문자열을 문자 단위로 노드에 저장하는 트리. 문자열 탐색 (: 문자열 길이).
AI 개발자 심화
- 결정 트리 (Decision Tree): 트리 구조로 분류·회귀를 수행. 각 노드에서 특성 기준으로 분기. XGBoost·LightGBM·CatBoost 모두 앙상블 결정 트리.
- MCTS (Monte Carlo Tree Search): AlphaGo·AlphaZero에서 사용. 게임 상태를 트리 노드로 표현하고 UCB(Upper Confidence Bound)로 탐험·활용 균형.
- : 노드 의 누적 보상, : 방문 횟수, : 부모 방문 횟수, : 탐험 계수
- 토크나이저 트라이: BPE(Byte Pair Encoding) 토크나이저 구현에 트라이를 활용하여 빠른 문자열 매칭.
- 벡터 DB 인덱스 (HNSW): 계층적 그래프 구조로 근사 최근접 이웃 탐색 수행 — 트리와 그래프의 혼합 구조.
8. 그래프 (Graph)
정의
정점(Vertex)과 간선(Edge)으로 구성된 자료구조. 트리는 그래프의 특수 케이스(사이클 없는 연결 그래프).
그래프의 종류
| 종류 | 설명 |
|---|---|
| 무방향 그래프 | 간선에 방향 없음 |
| 방향 그래프 (DAG 포함) | 간선에 방향 있음 |
| 가중치 그래프 | 간선에 비용(가중치) 부여 |
| 연결 그래프 | 임의의 두 정점 사이에 경로 존재 |
| DAG | Directed Acyclic Graph — 방향 있고 사이클 없음 |
그래프 표현 방식
인접 행렬: 공간, 간선 존재 확인
인접 리스트: 공간, 희소 그래프에 효율적
주요 탐색 알고리즘
깊이 우선 탐색 (DFS)
스택(또는 재귀)을 사용하여 최대한 깊이 탐색.
- 시간 복잡도:
- 활용: 사이클 탐지, 위상 정렬, 연결 요소 탐색
너비 우선 탐색 (BFS)
큐를 사용하여 레벨 단위로 탐색.
- 시간 복잡도:
- 활용: 비가중치 그래프 최단 경로
최단 경로 알고리즘
다익스트라 알고리즘 (단일 출발, 비음수 가중치):
우선순위 큐 사용 시 시간 복잡도:
벨만-포드 알고리즘: 음수 가중치 허용,
플로이드-워셜: 모든 쌍 최단 경로,
위상 정렬 (Topological Sort)
DAG에서 모든 간선 에 대해 가 보다 먼저 오는 순서.
- Kahn 알고리즘 (BFS 기반): 진입 차수가 0인 정점부터 처리
- 시간 복잡도:
AI 개발자 심화
- 계산 그래프 (Computational Graph): 신경망의 순전파·역전파는 DAG 위에서 이루어진다. PyTorch의
autograd엔진은 DAG를 역방향 위상 정렬 순서로 순회하며 그래디언트를 계산한다. - GNN (Graph Neural Network): 그래프 데이터(소셜 네트워크, 분자 구조, 지식 그래프)를 직접 처리하는 신경망. 각 노드가 이웃 노드의 특성을 집계(Message Passing)하여 표현 업데이트.
- 지식 그래프 (Knowledge Graph): 엔티티(노드)와 관계(간선)로 구성. RAG 시스템에서 구조화된 외부 지식으로 활용.
- 분자 설계: 원자(노드)·결합(간선)을 그래프로 표현 → GNN으로 물성 예측·신약 후보 생성.
- 추천 시스템: 사용자-아이템 이분 그래프에 GNN 적용 → 협업 필터링.
9. 정렬 알고리즘
주요 정렬 알고리즘 비교
| 알고리즘 | 평균 | 최악 | 공간 | 안정 |
|---|---|---|---|---|
| 버블 정렬 | ✓ | |||
| 삽입 정렬 | ✓ | |||
| 선택 정렬 | ✗ | |||
| 퀵 정렬 | ✗ | |||
| 병합 정렬 | ✓ | |||
| 힙 정렬 | ✗ | |||
| 계수 정렬 | ✓ |
정렬의 비교 기반 하한: (결정 트리 논증).
AI 개발자 심화
- Top-K 추출: LLM의 Top-K 샘플링, 추천 시스템의 Top-K 아이템 추출에서 전체 정렬 대신 힙을 이용한 부분 정렬 사용.
- Argsort: PyTorch
torch.argsort는 인덱스 기반 정렬 — 어텐션 점수 랭킹, 특성 중요도 정렬에 활용.
수식 정리
시간 복잡도 빅 오 정의
주요 자료구조 복잡도 요약
| 자료구조 | 탐색 | 삽입 | 삭제 | 공간 |
|---|---|---|---|---|
| 배열 | ||||
| 해시 테이블 | avg | avg | avg | |
| 이진 탐색 트리 | avg | avg | avg | |
| 힙 | ||||
| 그래프 (인접 리스트) |
Self-Attention 복잡도
MCTS UCB
GNN 메시지 패싱
다익스트라 갱신 조건