*구조적 프로그래밍* 과 *자료구조* — *제어의 *틀* 과 *데이터의 *형태* 가 *서로를 *부른다*
“GoTo 는 *해로 운가?”* — 1968 년 Dijkstra 의 짧은 편지 가 프로그래밍 의 *형태 를 *바꾸었다. 그 8 년 후 Wirth 의 책 — 알고리즘 + 자료구조 = 프로그램. 둘은 *별개 의 주제 *같지만 — *깊이 들여다 보면 *같은 *질문 의 *두 *얼굴. 이 글은 그 연결.
TL;DR
| 차원 | 구조적 프로그래밍 | 자료구조 |
|---|---|---|
| 본질 | 제어 흐름 (행위) 의 명확화 | 데이터 (상태) 의 형태 부여 |
| 시조 | Dijkstra (1968) | Knuth / Wirth (1968 ~ 76) |
| 단위 | 순차 / 선택 / 반복 | 시퀀스 / 트리 / 그래프 / 해시 |
| 목적 | 증명 가능 한 *흐름 | 효율 적 *접근 / 변형 |
| 공통 | 복잡도 *분할 + *명명 |
핵심 통찰 :
자료구조 가 *제어 구조 를 결정 한다 — 그 반대 도 같다. 둘은 *서로 의 *거울.
1. 구조적 프로그래밍 — Dijkstra 의 *짧은 *편지
1968 년의 역사 적 순간
Edsger Dijkstra 가 Communications of the ACM 에 한 페이지 편지 를 보냈다. 제목 — “Go To Statement Considered Harmful”.
요지 :
“goto 가 *프로그램 의 *동적 흐름 을 *예측 불가능 하게 만든다. 3 가지 제어 구조 — *순차 (sequence), *선택 (selection), *반복 (iteration) — 만 으로 모든 알고리즘 을 표현 가능 하다.”*
이 주장 이 프로그래밍 의 *방향 을 바꾸었다. FORTRAN / COBOL 의 *goto 지옥 시대* 가 끝나고 C 의 *블록 / for / while 구조 시대 로.
구조적 프로그래밍 의 *3 가지 구조
1. Sequence — A; B; C; (순차 실행)
2. Selection — if / case (조건 분기)
3. Iteration — for / while (반복)
이 3 가지 만으로 *Turing-complete. 즉 모든 계산 가능 한 알고리즘 을 goto 없이 *표현 가능. 수학적 *증명 도 함께 등장.
왜 *중요한가
- 읽을 수 있는 *코드 — 위에서 아래로 흐름
- 국 소 *추론 가능 — 함수 안 *만 *보면 동작 이해
- 증명 + 테스트 가능 — 흐름이 *예측 가능
- 버그 ↓
2. 자료구조 — Wirth 의 *공식
1976 년 Niklaus Wirth 의 유명한 책
“Algorithms + Data Structures = Programs”.
이 한 줄 공식 이 컴퓨터 과학 교육의 *기둥. 의미 :
프로그램은 *알고리즘 (행위) + 자료구조 (상태) 의 합. 둘 중 하나 만 으론 *불완전.*
자료구조 의 *5 가지 *기본
1. Array / Sequence — 인덱스 접근
2. Linked List — 순차 + 동적 크기
3. Tree — 계층
4. Hash Table — O(1) 키 접근
5. Graph — 일반 관계
이 5 가지 + 변종 (스택, 큐, 우선순위 큐, 트라이, B-Tree, …) 이 컴퓨터 과학 의 *기본 어휘.
각 자료구조 의 *시간 복잡도
| 자료구조 | 검색 | 삽입 | 삭제 |
|---|---|---|---|
| Array | O(n) | O(n) | O(n) |
| Sorted Array | O(log n) | O(n) | O(n) |
| Linked List | O(n) | O(1) | O(1) |
| Binary Search Tree (균형) | O(log n) | O(log n) | O(log n) |
| Hash Table (평균) | O(1) | O(1) | O(1) |
| Heap | O(1) min | O(log n) | O(log n) |
복잡도 의 차이 가 현장 의 *성능 의 차이. 수 백 만 *데이터 에서 log n vs n 은 체감 100 배 *차이.
3. 둘은 *어떻게 *만나는가
자료구조 의 *형태 가 제어 구조 의 *모양 을 부른다.*
이게 핵심 명제. 예 :
Sequence (Array / List) → 순차 반복
for item in array:
process(item)
Array 의 *순차 *접근 은 for 루프 와 자연 짝. 제어 와 *데이터 가 *같은 형태.
Tree → 재귀
def traverse(node):
if node is None: return
visit(node)
traverse(node.left)
traverse(node.right)
Tree 의 *재귀 구조 가 재귀 호출 과 짝. for 루프로 *Tree 순회 한다 면 명시 적 *스택 필요 — 자연 스럽지 않음.
Graph → BFS / DFS
def bfs(start):
queue = [start]
while queue:
node = queue.pop(0)
for neighbor in node.neighbors:
queue.append(neighbor)
Graph 의 *복잡 관계 가 큐 + while 루프 와 짝. Tree 의 재귀 와 *비슷 하지만 *순환 가능 해 방문 표시 추가.
Hash Table → O(1) 직접 접근
if key in cache: # O(1) 조회
return cache[key]
해시 의 *직접 접근 은 조건문 의 *짧음 과 짝. 반복 없이 *답 으로 직행.
4. 역 방향 — 제어 구조 가 *데이터 *형태 를 *드러낸다
같은 명제 의 반대 방향 도 성립.
for 루프 → *시퀀스 의 *증거
for (int i = 0; i < n; i++) { ... }
이 코드 자체 가 “나는 0 ~ n-1 의 *시퀀스 를 처리한다” 라고 *자료구조 를 *드러낸다.
재귀 → 트리 / 분할 정복
int sum(int[] arr, int lo, int hi) {
if (lo == hi) return arr[lo];
int mid = (lo + hi) / 2;
return sum(arr, lo, mid) + sum(arr, mid+1, hi);
}
분할 정복 의 *재귀 가 반복적 *반 *나누기 — 암묵 적 *Binary Tree.
while + 큐 → 그래프 탐색
위의 BFS 예제 — 코드 만 봐도 “그래프 가 그릴 수 있다”.
→ 좋은 코드 는 *자료구조 가 *읽힌다. 자료구조 가 읽히지 않는 *코드 는 나쁘다.*
5. 추상화 의 *두 *축
컴퓨터 과학 의 추상화 는 두 축 :
제어 (행위)
│
│
│
────────────┼──────────── 상태 (데이터)
│
│
│
- 구조적 프로그래밍 = 제어 축의 추상화 *질서
- 자료구조 = 데이터 축의 추상화 *질서
둘은 직교 하지 않고 서로 *의존. 좋은 시스템 은 둘 다 *깊이 *고려.
OO — 두 축의 *합 친 *추상
class Stack<T> {
private List<T> items; // 자료구조 (상태)
public void push(T x) { ... } // 제어 + 상태
public T pop() { ... }
}
객체지향 의 클래스 는 상태 + 행위 를 *함께 *캡슐화. Wirth 의 공식 의 *진화 한 형태.
FP (함수형) — 불변 데이터 + 순수 함수
sumTree (Leaf x) = x
sumTree (Node l v r) = sumTree l + v + sumTree r
자료구조 가 패턴 매칭 으로 직접 *해체. 제어 가 *자료구조 를 *반영. Wirth 공식 의 *극단적 *순수 형태.
6. 왜 *둘을 *함께 배워야 하는가
학생 의 흔한 오류
- 자료구조 만 *외움 (리스트 / 트리 / 해시 등) — 언제 *어떻게 *적용 하는지 모름
- 제어 흐름 만 *코드 짜기 — 데이터 *모양 의 최적 *놓침
- 문제 해결 시 *자료구조 가 *떠 오르지 않음
통합 적 *훈련
문제 → *어떤 자료구조* 가 적합한가?
→ *그 자료구조* 의 *자연 스러운 *제어 흐름* 은?
→ *코드 *작성*
이 3 단계 가 알고리즘 풀이 의 *표준 순서.
예 — 최단 경로 찾기
- 그래프 자료구조 (인접 리스트)
- BFS 의 while + queue 제어
- 방문 표시 + 부모 추적 — 재구성
→ 문제 의 *모양 → 자료구조 → 제어 흐름 의 자연스러운 연결.
7. 현장 의 *증거 — 왜 *고급 개발자 가 *자료구조 직관이 *결정적
본인 7 년차 시점 에서 자료구조 직감 이 *결정적 *순간들 :
7.1. DB 인덱스 의 *왜 *빠른가
- B-Tree 자료구조 가 log n 검색 보장
- Hash Index 가 O(1) but 범위 검색 불가
- 인덱스 선택 = 자료구조 선택
→ DB 인덱스 의 *근본 은 자료구조. 알면 명확. 모르면 암기.
7.2. Java HashMap 의 *충돌 처리
- Java 8 부터 — 충돌 시 *Linked List → Tree 로 전환
- Linked List 의 *worst case O(n) → Tree 의 O(log n) 로 복원
- 알고리즘 의 안 정 성 보장
이걸 알면 — HashMap 의 *성능 의 비밀 이 직 관.
7.3. Kafka 의 *Topic 의 *파티션
- Topic = 그래프 의 *분할
- Partition = 시퀀스 (offset 순서)
- Consumer Group = 분할 정복
→ Kafka 는 *그래프 + 시퀀스 의 *조합. 자료구조 의 *언어 로 *Kafka 를 본다.
7.4. Elasticsearch 의 *역 색인 (Inverted Index)
- 역 색인 = 단어 → 문서 ID 리스트 의 해시 + 소트 시퀀스
- 검색 = *해시 조회 + 시퀀스 교집합
→ 이 자료구조 가 Elasticsearch 의 *모든 검색 성능 의 근본.
8. 추상 의 *수준 *높이기
입문 (1 년차)
- for / while / if / 함수 등 기본 제어
- Array / List / Map 의 기본 사용
중급 (3 년차)
- 재귀 의 *자연 스러운 적용
- Tree / Graph 의 *직접 구현 + 활용
- Big-O 의 *직 관
고급 (5 년차+)
- 자료구조 ↔ 제어 *연결 직 감 — 문제 보면 자료구조 와 제어 흐름 이 동시에 *떠 오름
- 시스템 의 *자료구조 분석 — 내부 가 *어떻게 *구성 되어 있는지
- 맞춤 자료구조 *설계 — 표준 자료구조 조합 / 변형
→ 연차 별 *능력 의 *연속선. 자료구조 + 제어 의 통합 적 직 감 이 시니어 의 *진짜 *능력.
9. 흔한 *오류 패턴
9.1. 자료구조 *선택 *잘못
// ❌ 자주 *contains 호출* 인데 List 사용
List<String> blacklist = ...;
if (blacklist.contains(item)) { ... } // O(n)
→ HashSet 으로 변경 → O(1).
9.2. 불필요한 *복잡 자료구조
// ❌ *5 개 *원소* 인데 *Red-Black Tree*
TreeSet<Integer> small = new TreeSet<>();
small.add(1); small.add(2); ... // 5 개
→ Array 가 충분. Big-O 가 *작은 n 에서 *역효과.
9.3. Stream 의 *남용
// ❌ 단순 합 계
int sum = list.stream().mapToInt(i -> i).sum();
→ for 루프 가 더 명확. 작은 데이터 에선 오버헤드.
→ **자료구조 와 *제어 흐름 의 *균형 이 현장 의 *기술.
10. Refactoring *의 *진짜 *기준
리팩터링 시 질문 :
- 이 코드 의 *제어 흐름 이 자연 스러운가?
- 그 흐름 이 *어떤 자료구조 를 드러내고 있는가?
- 그 자료구조 가 *적합 한가?
이 3 질문 으로 대부분 의 *코드 의 *문제점 이 드러난다. 변수 명 / 함수 분할 / 인터페이스 같은 표면적 개선 보다 근본 적.
11. 역사 적 *교훈
60 년 의 *공통 점
- 구조적 프로그래밍 (1968) → 복잡 한 흐름의 *제어
- 자료구조 (1976) → 복잡 한 데이터 의 *모양 부여
- 객체 지향 (1980s) → 상태 + 행위 통합
- 함수형 (2010s 부활) → 불변 + 패턴 매칭
- Reactive (2015+) → 비동기 시퀀스
→ 모두 *Dijkstra + Wirth 의 *연 장. 통제 + 자료 의 추상 화 진화.
현대 의 *연 장
- 마이크로서비스 — 서비스 가 *데이터 단위
- Event Sourcing — 상태 의 *시퀀스 표현
- CQRS — 제어 (Command) vs 자료 (Query) 분리
- Vector DB — 벡터 라는 *자료구조 의 전 면화
→ Wirth 의 공식 — *진화 만 *할 뿐 *틀린 적 없음.
12. 마치며
구조적 프로그래밍 과 자료구조 는 *두 *언어 의 같은 *문법. 제어 가 *데이터 를 *부르고 데이터 가 제어 를 *부른다.
3 줄 요약 :
- 자료구조 와 제어 의 *직 관 적 *연결 이 시니어 의 *능력 — 문제 보면 둘 다 *떠 오름.
- 새 시스템 (DB / Kafka / ES) 의 깊이 = *자료구조 의 *깊이 — 자료구조 모르면 시스템 도 *얕다.
- 리팩터링 의 진짜 기준 = *자료구조 의 *적합성 — 표면 변수 명 보다 훨씬 *중요.
7 년차 회고 :
“학부 시절 *자료구조 가 *왜 *중요한지 *몰랐다. 7년이 지난 지금 — *없으면 *어떤 시스템도 *얕다 는 게 몸 으로 *느낌.”*
다음 글 — 알고리즘 의 *직 관 *— Big-O 너머 의 *실 무 *비용 *지도. 같은 시리즈로.
본 글은 7년차 백엔드 엔지니어의 *학문 적 회고. 학문 의 분류 는 *나라 / 교재 마다 다르다. 해석은 *내 시각 일 뿐. Dijkstra, Wirth, Knuth 의 원전 을 직 접 읽으면 *더 깊은 *교훈.