연결 리스트란 노드 구조 배열 vs 연결 단일 vs 이중 언제 쓰나 📝 문제풀이
◀ 이전 📋 목차 CH 05 ▶
🔗 CHAPTER 04 · 자료구조

흩어진 데이터를, 연결로 이어 붙인다

배열은 데이터를 한 덩어리로 붙여 놓지만, 연결 리스트(Linked List)는 데이터를 여기저기 흩어 두고 화살표로 이어요. 그 대신 맨 앞 삽입·삭제가 아주 빨라져요. 배열과 뭐가 다른지 확실히 잡아봐요.

🎯 이 장을 끝내면
🔗
연결 리스트란
데이터를 "화살표"로 이어 붙인 구조
한 덩어리가 아니라, 흩어진 칸을 연결로 잇는다고 생각해요.
🚂 연결 리스트 = 기차 칸 연결 리스트(Linked List)는 데이터가 노드(node)라는 작은 칸에 하나씩 담겨 여기저기 흩어져 있어요. 그리고 각 노드는 다음 노드를 가리키는 연결(포인터/참조)을 하나씩 들고 있어요.
기차를 떠올려 보세요. 칸(노드) 하나하나가 연결 고리(next)로 다음 칸에 이어져 있죠. 맨 앞 칸을 잡고 따라가면 전체를 지나갈 수 있어요. 이 첫 노드head라고 불러요. 💡 배열이 한 줄로 딱 붙은 좌석이라면, 연결 리스트는 흩어진 칸을 고리로 이어 붙인 기차예요. 그래서 칸을 중간에 끼우거나 빼기가 쉬워요.
🔤
포인터(pointer) / 참조(reference) — "다른 데이터가 어디 있는지 가리키는 화살표"예요. 값 자체를 복사해서 들고 있는 게 아니라, 그 값이 있는 위치(주소)만 기억해 두는 거죠. 연결 리스트의 next가 바로 이 화살표라서, 노드를 연결할 땐 값을 옮기지 않고 화살표만 다시 걸면 끝이에요.
📈 도식 — 노드가 다음 노드를 가리켜요
head
 │
 ▼
[ 10 | next ] ──▶ [ 20 | next ] ──▶ [ 30 | next ] ──▶ null

// 각 칸 = 노드(값 + 다음 노드 참조)
// 마지막 노드의 next 는 null (더 이상 이어질 칸이 없다는 표시)
맨 앞 head에서 시작해 next를 따라가면 10 → 20 → 30 순서로 지나가요. 마지막 노드의 nextnull이면 "여기가 끝"이라는 뜻이에요.
연결 리스트 노드 head next O(1) 앞 삽입 O(n) 접근 코딩테스트
🔤
빅오 표기법(Big-O Notation) — "데이터가 늘어날수록 걸리는 시간이 얼마나 늘어나는가"를 대략적으로 나타내는 표기예요. O(1)은 데이터가 아무리 많아져도 항상 한 번 만에 끝난다는 뜻이고, O(n)은 데이터 개수(n)만큼 하나씩 다 확인해야 한다는 뜻이에요. 예를 들어 연결 리스트에서 5번째 칸을 찾으려면 head부터 1·2·3·4·5번째 칸까지 한 칸씩 세며 지나가야 하니 O(n)인 거예요.
🖼️ 그림으로 보기 — 연결 리스트 = 노드들의 사슬
head 10 next 20 next 30 next null (끝 표시)
각 노드가 다음 노드의 위치(주소)를 가리켜요. 그래서 중간 삽입·삭제는 화살표만 바꾸면 O(1).
🧱
노드 구조
노드 = 값 + 다음 노드 참조
연결 리스트를 이루는 가장 작은 부품이에요.

연결 리스트의 부품인 노드(node)는 딱 두 가지를 들고 있어요. 하나는 담고 있는 값(data), 다른 하나는 다음 노드를 가리키는 참조(next)예요. 이 두 개만 있으면 노드들을 줄줄이 이을 수 있어요.

🔤
null — "가리키는 대상이 없다"는 뜻의 특별한 값이에요. 연결 리스트에서는 다음 노드가 없다, 즉 여기가 끝이라는 표시로 써요. 노드를 막 만들었을 땐 아직 아무 데도 안 이어졌으니 nextnull이고, 다른 노드와 연결되면 그때부터 그 노드를 가리키게 돼요.
🧱 노드 하나를 코드로
class Node {
  constructor(data) {
    this.data = data;   // 이 노드가 담는 값
    this.next = null;   // 다음 노드를 가리키는 참조 (없으면 null)
  }
}

// 노드 세 개를 손으로 이어 붙이기
const a = new Node(10);
const b = new Node(20);
const c = new Node(30);
a.next = b;   // 10 ──▶ 20
b.next = c;   // 20 ──▶ 30
// c.next 는 null → c 가 마지막 노드

const head = a;   // 첫 노드를 head 로 잡는다
a.next = b처럼 참조만 바꾸면 노드가 이어져요. 값을 옮겨 담는 게 아니라 화살표(연결)만 다시 거는 거예요. 💡 핵심은 "노드는 값 하나 + 다음 노드로 가는 화살표 하나"예요. 이 그림만 확실하면 연결 리스트의 절반은 이해한 거예요.
🚶 처음부터 따라가며 출력하기
let cur = head;          // head 부터 시작
while (cur !== null) {   // 끝(null)을 만날 때까지
  console.log(cur.data); // 10, 20, 30 순서로 출력
  cur = cur.next;        // 다음 노드로 이동
}
배열처럼 arr[2]로 바로 못 가고, head부터 next를 따라 한 칸씩 걸어가야 해요. 이게 뒤에서 나올 인덱스 접근 O(n)의 이유예요.
⚖️
배열 vs 연결
이 표 하나가 이번 장의 핵심이에요
"뭘 잘하고 뭘 못하나"를 정확히 나눠서 기억해요.

배열은 데이터가 한 줄로 붙어 있어서 인덱스로 위치를 바로 계산할 수 있어요. 그래서 arr[5] 접근이 O(1)이에요. 대신 중간에 값을 끼우거나 빼면 뒤 요소를 전부 밀어야 하니 O(n)이에요.

연결 리스트는 반대예요. 데이터가 흩어져 있어 인덱스로 바로 못 가고 head부터 따라가야 하므로 접근이 O(n)이에요. 하지만 맨 앞에 노드를 끼우거나 빼는 건 화살표(연결)만 바꾸면 되니 O(1)이에요.

연산배열 (Array)연결 리스트 (Linked List)
인덱스로 접근 get(i)O(1) 바로 계산O(n) head부터 따라감
맨 앞 삽입/삭제O(n) 전부 밀어야 함O(1) 연결만 바꿈
맨 뒤 삽입 (tail 알 때)O(1) 보통O(1) tail 알 때
값 탐색 (찾기)O(n)O(n)
메모리 배치연속(한 덩어리)흩어짐 + next 참조 저장
✂️ 맨 앞 삽입이 왜 O(1)인가
// head 앞에 값 5 를 새로 끼우기
function pushFront(head, value) {
  const node = new Node(value);
  node.next = head;   // 새 노드가 기존 head 를 가리키게
  return node;        // 새 노드가 새로운 head 가 됨
}
// [10]▶[20]▶null 에서
// head = pushFront(head, 5)  →  [5]▶[10]▶[20]▶null
뒤 요소를 하나도 밀지 않아요. 참조 두 개만 바꾸면 끝 → O(1). 배열이라면 모든 요소를 한 칸씩 뒤로 밀어야 해서 O(n)이에요. 💡 한 문장 요약: 배열은 "접근이 빠르고 앞 삽입이 느림", 연결 리스트는 "접근이 느리고 앞 삽입이 빠름". 서로 정반대예요.
💡
탐색은 둘 다 O(n)이에요. "특정 값이 어디 있나 찾기"는 배열이든 연결 리스트든 하나씩 확인해야 하므로 O(n). 차이가 나는 건 인덱스 접근앞쪽 삽입/삭제예요.
↔️
단일 vs 이중
화살표가 한 방향이냐, 양방향이냐
종류는 딱 두 개만 알아도 충분해요.
➡️ 단일 연결 리스트 (Singly Linked List) 각 노드가 다음 노드(next)만 가리켜요. 한 방향(앞 → 뒤)으로만 이동할 수 있어요. 구조가 단순하고 메모리를 덜 써요.
[10 | next] ──▶ [20 | next] ──▶ [30 | next] ──▶ null
↔️ 이중 연결 리스트 (Doubly Linked List) 각 노드가 다음(next)과 이전(prev)둘 다 가리켜요. 그래서 앞뒤 양방향으로 오갈 수 있어요. 대신 참조를 하나 더 저장하니 메모리를 조금 더 써요.
null ◀── [prev | 10 | next] ◀──▶ [prev | 20 | next] ──▶ null
//        각 노드가 prev 와 next 를 모두 가짐 → 뒤로도 이동 가능
💡 뒤로도 걸어가야 하거나, 어떤 노드에서 바로 앞 노드를 알아야 할 때 이중 연결 리스트가 편해요. (예: 브라우저 뒤로/앞으로 가기)
🧭
언제 쓰나
삽입·삭제가 잦고, 인덱스 접근이 드물 때
현실에선 배열을 더 자주 쓰지만, 개념과 면접엔 꼭 필요해요.
🎯 연결 리스트가 유리한 상황 1. 앞쪽 삽입·삭제가 잦다 — 맨 앞에 계속 끼우고 빼면 연결 리스트가 O(1)로 유리해요.
2. 인덱스로 콕 집어 접근할 일이 드물다arr[i]처럼 무작위 접근이 많으면 배열이 훨씬 나아요.
3. 크기가 자주 변한다 — 필요할 때 노드를 붙이면 되니, 미리 크기를 정할 필요가 없어요.
🧭
실무 팁. 사실 실무에선 배열(동적 배열)을 훨씬 자주 써요. 요즘 컴퓨터는 연속된 메모리 접근이 매우 빨라서, 이론상 O(n)이어도 배열이 더 빠른 경우가 많거든요. 그래도 스택·큐·해시 충돌 처리 등 내부에서 연결 리스트 개념이 쓰이고, 면접 단골 주제라 원리는 꼭 알아둬야 해요.
🧪
이 과목의 실습 랩에서 방금 배운 노드·연결을 직접 코드로 짜고 실행·채점해볼 수 있어요. 상단 🧪 실습 버튼에서 열려요. head부터 따라가며 출력하는 함수를 손으로 짜보면 감이 확 와요.
🧠 이 장 핵심 요약
📝
문제풀이 · 점검
배운 걸 가볍게 점검해봐요
시험이 아니라 "내가 이해했나" 확인용이에요. 틀려도 바로 해설이 나와요.
🧪
문제를 풀면 즉시 정답과 해설이 나오고, 위쪽 바에 점수가 쌓여요. 손으로 직접 짜보고 싶으면 상단 🧪 실습 랩으로!
CH 05 🗂️ 해시맵과 셋 — key로 O(1)에 찾는 마법, 그 원리와 함정