트리: 작은 가지를 연결하고 읽는 순서부터 배웁니다
폴더 A·B·C 예제로 트리와 순회를 배웁니다. 전위와 층별 방문을 손으로 따라간 뒤 이진 트리·BST·MST의 목적을 구분합니다.
먼저 작은 예제로 원리를 익히고, 마지막에 전체 구현을 펼쳐 보세요. 앞쪽 예제는 각각 독립적으로 브라우저 개발자 도구 Console에서 실행합니다. 같은 이름을 다시 선언했다는 오류가 나오면 새로고침 후 해당 예제를 실행하세요. 출력 뒤에 콘솔이 별도로 보여주는 undefined는 마지막 명령의 반환값일 수 있습니다.

1. 폴더 안에 폴더가 있는 모습을 떠올려 보세요
프로젝트 폴더 A 아래에 B와 C가 있고, B 아래에 D와 E가 있다고 해 보겠습니다. A에서 출발해 아래로 가지를 따라갑니다. 이런 계층을 표현할 때 트리를 사용합니다. 항목 하나는 노드, 항목 사이의 연결은 간선이라고 부릅니다. 루트는 맨 위의 시작 항목 A입니다.
| 항목 | 바로 아래 자식 | A에서 내려가는 길 |
|---|---|---|
| A | B, C | 시작점 |
| B | D, E | A → B |
| C | 없음 | A → C |
| D | 없음 | A → B → D |
| E | 없음 | A → B → E |
B의 부모는 A이고, D와 E의 부모는 B입니다. 자식이 없는 C·D·E를 리프라고 합니다. 여기서는 하나의 항목에 부모가 여러 개 생기거나, 아래로 따라갔는데 다시 자기 자신에게 돌아오는 연결은 없습니다. 실제 파일 시스템의 바로가기 같은 특수 연결은 이번 예제에서 제외합니다.
이번에 배울 핵심은 노드를 어떻게 연결해 두는가, 그리고 어떤 순서로 읽는가입니다. 트리 종류의 이름을 모두 외우는 일은 뒤로 미뤄도 됩니다.
2. 자식이 최대 두 개인 이진 트리를 만들어 봅니다
각 항목에 왼쪽과 오른쪽 자식 자리를 하나씩 둔 것을 이진 트리라고 합니다. 두 자식이 반드시 있어야 하는 것은 아닙니다. 아래 코드는 A 아래에 B와 C만 있는 작은 트리입니다. 각 예제는 브라우저 Console에서 독립적으로 실행할 수 있습니다.
const root = {
value: 'A',
left: { value: 'B', left: null, right: null },
right: { value: 'C', left: null, right: null }
};
console.log(root.value);
console.log(root.left.value);
console.log(root.right.value);
A
B
C
value는 현재 노드의 값입니다. left와 right에는 다음 노드 객체를 넣습니다. root.left.value는 “A의 왼쪽으로 한 번 가서 그 값 B를 읽어라”라는 뜻입니다. null은 그 자식 자리가 비었다는 표시입니다. 객체를 가리키는 참조와 헷갈린다면 실제 객체는 따로 있고 연결을 따라 읽는다고 생각해 보세요.
이진 트리라는 이름만으로 왼쪽 값이 더 작다는 뜻은 아닙니다. 지금은 A·B·C의 위치만 정했습니다. 값을 비교하는 별도 규칙을 추가한 것이 뒤에서 비교할 BST입니다.
3. 전체 항목을 읽는 순서를 먼저 정합니다
트리의 항목을 하나씩 읽는 일을 순회라고 합니다. 첫 표의 A(B(D,E),C)를 읽을 때 A를 적은 다음 B 쪽을 끝까지 보고 C로 넘어가면 A → B → D → E → C가 됩니다. 이를 전위 순회라고 합니다. “현재 항목 먼저, 그다음 왼쪽 전체, 마지막 오른쪽 전체”가 규칙입니다.
| 지금 처리 | 다음 행동 | 지금까지 적은 값 |
|---|---|---|
| A | A를 적고 B로 내려감 | A |
| B | B를 적고 D로 내려감 | A, B |
| D | D를 적고, 자식이 없어 B로 돌아감 | A, B, D |
| E | B의 남은 오른쪽을 읽고 A로 돌아감 | A, B, D, E |
| C | A의 남은 오른쪽을 읽음 | A, B, D, E, C |
const root = { value: 'A',
left: { value: 'B', left: { value: 'D' }, right: { value: 'E' } },
right: { value: 'C' } };
const result = [];
function visit(node) {
if (node == null) return;
result.push(node.value);
visit(node.left);
visit(node.right);
}
visit(root);
console.log(result.join(', '));
A, B, D, E, C
visit은 노드 하나를 받아 같은 일을 반복하는 함수입니다. 첫 조건은 자식이 없으면 그 길을 멈춥니다. 여기서 == null은 null과 생략된 속성의 undefined 둘 다 확인하려고 썼습니다. 그래서 D·E·C의 빈 자식 속성을 생략해도 됩니다.
현재 값을 적은 다음 visit(node.left)를 호출합니다. 이 호출이 왼쪽 아래를 모두 처리하고 돌아와야 다음 줄인 visit(node.right)가 실행됩니다. 함수가 자기 자신을 호출하는 재귀입니다. B를 처리하는 동안에도 “B가 끝나면 A의 오른쪽 C를 처리해야 한다”는 순서가 기억됩니다. 아주 깊은 트리는 호출 한도를 넘을 수 있으므로 아래 참고용 전체 코드는 별도 스택을 사용하는 반복문 버전입니다.
D에서 실제로 돌아오는 순서를 풀어 보면 이렇습니다. visit(D)는 D를 기록하고, 없는 왼쪽 자식을 호출했다가 즉시 돌아옵니다. 없는 오른쪽도 같은 방식으로 끝납니다. 이제 visit(D) 자체가 끝나므로, D를 호출했던 visit(B)의 왼쪽 호출 다음 줄로 돌아옵니다. 그 줄이 visit(B.right)이므로 다음에는 E를 처리합니다. 돌아온다는 것은 처음부터 다시 시작하는 것이 아니라, 호출했던 자리 바로 다음 줄을 이어 실행한다는 뜻입니다.
확인 문제: 값을 기록하는 줄을 두 visit 호출 사이로 옮기면 무엇부터 나올까요?
정답과 이유 보기
D부터 나옵니다. 왼쪽을 먼저 처리하고 현재 값을 적는 중위 순회가 되어 D, B, E, A, C 순서입니다. “현재 값을 언제 기록하는가”만 달라도 출력 순서가 바뀝니다. 일반 이진 트리에서 이 순서가 자동으로 정렬 순서는 아닙니다.
4. 한 층씩 보고 싶다면 큐로 예약합니다
폴더의 깊이별 목록이 필요하다면 A → B → C → D → E처럼 읽고 싶습니다. 이때 아직 읽지 않은 항목을 큐에 넣습니다. A를 꺼내며 B·C를 예약하고, B를 꺼내며 D·E를 맨 뒤에 붙입니다. 먼저 기다리던 C가 D·E보다 먼저 나옵니다.
| 꺼낸 항목 | 그 항목의 자식을 뒤에 넣은 후 대기줄 | 기록한 순서 |
|---|---|---|
| 시작 전 | A | 없음 |
| A | B, C | A |
| B | C, D, E | A, B |
| C | D, E | A, B, C |
| D | E | A, B, C, D |
| E | 비어 있음 | A, B, C, D, E |
const root = { value: 'A',
left: { value: 'B', left: { value: 'D' }, right: { value: 'E' } },
right: { value: 'C' } };
const queue = [root];
const result = [];
while (queue.length > 0) {
const node = queue.shift();
result.push(node.value);
if (node.left != null) queue.push(node.left);
if (node.right != null) queue.push(node.right);
}
console.log(result.join(', '));
A, B, C, D, E
shift는 줄의 맨 앞을 꺼내고 push는 맨 뒤에 붙입니다. 자식이 있는지 확인한 뒤 넣어야 빈 자리를 노드로 처리하지 않습니다. 이 코드는 작은 트리의 순서 관찰용입니다. 노드가 많을 때는 아래 전체 구현처럼 head 인덱스로 읽을 위치를 옮기면 매번 배열 앞을 당기는 작업을 피할 수 있습니다.
5. BST와 MST는 이름이 비슷해도 목적이 다릅니다
| 이름 | 지금 떠올릴 질문 | 작은 예 |
|---|---|---|
| 트리 | 서로 어떻게 가지로 연결되는가? | 폴더 A 아래 B와 C |
| 이진 트리 | 왼쪽·오른쪽 자리가 있는가? | A.left=B, A.right=C |
| BST | 비교해서 찾을 방향을 고를 수 있는가? | 10보다 작은 5는 왼쪽, 큰 15는 오른쪽 |
| MST | 모든 장소를 가장 적은 총비용으로 이을 수 있는가? | 연결 비용 1, 2, 4 중 비용 1과 2를 선택 |
BST는 각 노드의 왼쪽 부분 전체가 더 작고 오른쪽 부분 전체가 더 크다는 규칙으로 검색합니다. MST는 도로 후보 A-B(1), B-C(2), A-C(4)에서 세 장소를 모두 잇는 연결을 고르는 문제입니다. A-B와 B-C를 고르면 총비용 3입니다. 최소 연결 비용을 구하는 일이지 값을 크기순으로 찾거나 한 출발점의 최단 경로를 구하는 일이 아닙니다.
지금은 전위와 층별 순서를 손으로 설명하고, BST와 MST의 목적을 구분할 수 있으면 충분합니다. 아래 전체 구현을 펼칠 때는 네 가지 순회 중 먼저 이해한 preorder와 breadthFirst 부분부터 읽어 보세요. 중위·후위와 높이 공식은 다음에 읽어도 됩니다.
관련 코딩테스트 문제로 이어서 연습합니다
이 자료구조의 블로그 연습 문제와 해설에서 배운 동작을 적용해 보세요. 먼저 작은 예시를 직접 처리한 뒤 입력 전체를 다루는 코드로 확장하면 됩니다. 아래 전체 구현은 연결된 문제의 기존 메서드와 반환 형식을 유지합니다.
전체 구현 · 상세 설명 · 예외와 성능 분석 펼치기
여기부터는 필요한 기능을 골라 읽는 참고 영역입니다. 새로운 파일로 전체 코드를 실행할 때는 아래 Node.js 실행 안내를 따르세요. 앞쪽의 작은 브라우저 실습과 전체 파일을 한 콘솔에 이어 붙이지 마세요. 기능별 입력 조건과 반환 형식은 아래 설명을 기준으로 합니다.
트리·이진 트리·BST·MST는 서로 다른 질문에 답합니다
트리는 정점들이 연결되어 있고 사이클이 없는 무방향 그래프입니다. 두 정점 사이의 단순 경로가 하나뿐이라는 성질 때문에 계층의 부모를 정할 수 있습니다. 정점이 n개인 비어 있지 않은 트리의 간선은 n-1개이며, 정점 하나만 있어도 트리입니다. 연결되지 않은 여러 트리는 포리스트라고 부릅니다.
트리 중 한 정점을 루트로 정하면 루트 방향의 이웃이 부모, 반대 방향이 자식이 됩니다. 부모가 같은 노드는 형제이고 자식이 없는 노드는 리프입니다. 깊이는 루트에서 해당 노드까지의 간선 수, 높이는 루트에서 가장 먼 리프까지의 간선 수로 셉니다. 따라서 루트 하나의 높이는 0입니다. 레벨을 1부터 세는 자료와 수치를 비교할 때 기준을 먼저 확인해야 합니다.
| 개념 | 정하는 조건 | 정하지 않는 것 |
|---|---|---|
| 트리 | 연결되어 있고 사이클이 없음 | 자식 수·키 순서·가중치 최적성 |
| 이진 트리 | 각 노드에 왼쪽·오른쪽 자리가 최대 하나씩 | 왼쪽 값이 더 작다는 조건 |
| 이진 탐색 트리(BST) | 왼쪽 부분 트리의 키 < 노드 키 < 오른쪽 부분 트리의 키 | 높이 균형 |
| 최소 신장 트리(MST) | 가중 무방향 연결 그래프의 모든 정점을 잇는 최소 비용 선택 | 키 검색 순서·출발점별 최단 거리 |
배열과 연결 표현 중 무엇을 저장할 것인가
완전 이진 트리는 루트를 1번 칸에 두면 i의 왼쪽 자식이 2i, 오른쪽이 2i+1인 배열로 표현할 수 있습니다. 빈자리가 거의 없어 위치만으로 부모·자식을 찾습니다. 반대로 한쪽으로 길게 뻗은 트리에 같은 배치를 적용하면 쓰지 않는 칸이 급격히 늘어납니다. 이런 모양에는 left와 right 참조를 가진 노드가 자연스럽습니다.
자식 수가 제한되지 않는 일반 트리는 children 배열로 표현할 수 있습니다. 또 첫 자식-다음 형제 표현은 노드마다 두 연결만 둡니다. A의 자식이 B,C,D라면 A.left=B, B.right=C, C.right=D처럼 저장합니다. 이때 right는 자식이 아니라 형제이므로 아래의 일반 이진 트리 순회를 그대로 적용하면 계층 의미가 달라집니다.
완전·포화·정 이진 트리와 높이
| 이름 | 정의 | 확인할 점 |
|---|---|---|
| 완전(complete) | 마지막 층을 제외한 층이 가득 차고 마지막 층은 왼쪽부터 채움 | 힙 배열 표현에 적합 |
| 포화(perfect) | 모든 내부 노드가 두 자식을 갖고 모든 리프의 깊이가 같음 | 모든 층이 가득 참 |
| 정·엄격(full/strict) | 각 노드의 자식 수가 0 또는 2 | 리프의 깊이가 같을 필요는 없음 |
간선 기준 높이 h인 이진 트리에는 최대 2^(h+1)-1개의 노드가 있습니다. n ≥ 1인 이진 트리의 가능한 최소 높이는 ceil(log2(n+1))-1입니다. 노드 7개면 최소 높이는 2지만 8개는 최소 3입니다. 이 식은 가능한 최솟값일 뿐, 실제 삽입 순서가 나쁜 BST가 그 높이를 가진다는 보장은 아닙니다.
순회를 구현하기 전에 방문 순서를 정합니다
전위는 노드-왼쪽-오른쪽, 중위는 왼쪽-노드-오른쪽, 후위는 왼쪽-오른쪽-노드입니다. 같은 연결을 읽더라도 값을 기록하는 시점이 다릅니다. 계층을 부모부터 보여 줄 때는 전위, 자식 결과를 모아 부모를 처리할 때는 후위가 알맞습니다. 중위가 정렬 결과가 되는 것은 일반 이진 트리가 아니라 BST일 때입니다.
아래 코드는 {value,left,right} 형태의 유효한 이진 트리를 받습니다. 없는 자식은 null 또는 생략이며 빈 트리는 null입니다. 노드 값은 중복되어도 되지만 같은 노드 객체가 두 부모에 공유되거나 사이클을 만들면 안 됩니다. 그런 입력을 검증하는 그래프 알고리즘이 아니라 이미 트리인 구조의 순회입니다.
전체 코드를 tree.cjs로 저장하고 Node.js에서 node ./tree.cjs를 실행합니다. CommonJS 파일 한 개로 네 순서를 모두 출력합니다. 함수 자체는 재귀를 사용하지 않아 깊은 트리에서 JavaScript 호출 스택 한도를 직접 소모하지 않습니다. 다만 큰 객체의 JSON 직렬화 한도나 메모리 한도까지 없애는 것은 아닙니다.
'use strict';
function traversals(root) {
const preorder = [];
const inorder = [];
const postorder = [];
const breadthFirst = [];
if (root == null) return { preorder, inorder, postorder, breadthFirst };
const preStack = [root];
while (preStack.length > 0) {
const node = preStack.pop();
preorder.push(node.value);
if (node.right != null) preStack.push(node.right);
if (node.left != null) preStack.push(node.left);
}
const inStack = [];
let current = root;
while (current != null || inStack.length > 0) {
while (current != null) {
inStack.push(current);
current = current.left;
}
current = inStack.pop();
inorder.push(current.value);
current = current.right;
}
const postStack = [[root, false]];
while (postStack.length > 0) {
const [node, expanded] = postStack.pop();
if (expanded) {
postorder.push(node.value);
continue;
}
postStack.push([node, true]);
if (node.right != null) postStack.push([node.right, false]);
if (node.left != null) postStack.push([node.left, false]);
}
const queue = [root];
let head = 0;
while (head < queue.length) {
const node = queue[head];
head += 1;
breadthFirst.push(node.value);
if (node.left != null) queue.push(node.left);
if (node.right != null) queue.push(node.right);
}
return { preorder, inorder, postorder, breadthFirst };
}
module.exports = { traversals };
if (require.main === module) {
const root = {
value: 'A',
left: { value: 'B', left: { value: 'D' }, right: { value: 'E' } },
right: { value: 'C', right: { value: 'F' } }
};
console.log(JSON.stringify(traversals(root)));
}
실행 출력
{"preorder":["A","B","D","E","C","F"],"inorder":["D","B","E","A","C","F"],"postorder":["D","E","B","F","C","A"],"breadthFirst":["A","B","C","D","E","F"]}
스택은 아직 끝내지 않은 작업을 기억합니다
전위의 스택은 방문 예정 노드입니다. 스택은 마지막에 넣은 항목부터 꺼내므로 오른쪽을 먼저 넣고 왼쪽을 나중에 넣어야 왼쪽부터 처리합니다. 이 순서를 바꾸면 오른쪽 우선 전위가 되며, 단순한 성능 차이가 아니라 결과 계약이 바뀝니다.
중위의 내부 반복문은 왼쪽 끝까지 내려가며 노드를 보류합니다. 왼쪽에 더 갈 곳이 없어야 스택에서 노드를 꺼내 값을 기록하고 오른쪽으로 이동합니다. “스택 안의 노드는 왼쪽 작업을 기다리는 조상”이라는 의미를 잡으면 current와 스택을 모두 조건에 넣는 이유가 보입니다.
후위는 [노드, 확장 여부]를 쌓습니다. 처음 만났을 때 자기 자신을 expanded=true로 다시 넣은 뒤 자식들을 올립니다. 자식 작업이 모두 빠져나온 뒤 표시된 자신이 나타나므로 값은 마지막에 기록됩니다. 같은 노드를 두 번 작업 항목으로 다룰 뿐 결과에 두 번 넣지는 않습니다.
| A의 왼쪽 B(D,E), 오른쪽 C(오른쪽 F) | 방문 결과 | 사용한 기억 |
|---|---|---|
| 전위 | A,B,D,E,C,F | 오른쪽 후에 왼쪽을 push |
| 중위 | D,B,E,A,C,F | 왼쪽 경로의 조상을 보류 |
| 후위 | D,E,B,F,C,A | 자식 처리 후 재방문 표시 |
| 너비 우선 | A,B,C,D,E,F | 발견 순서대로 큐 뒤에 추가 |
너비 우선은 먼저 발견한 노드부터 처리합니다. head를 증가시키고 자식은 queue 뒤에 넣으므로 같은 깊이의 기존 노드를 다음 깊이보다 먼저 읽습니다. 배열 앞을 shift하지 않는 대신 이미 읽은 항목도 배열에 남습니다. 따라서 이 코드의 큐 저장 공간은 최대 폭만이 아니라 전체 노드 수에 비례합니다.
BST의 순서와 MST의 비용을 혼동하지 않기
루트 30, 왼쪽 15(자식 10,20), 오른쪽 40(오른쪽 50)인 BST에서 25를 찾으면 30→15→20→없는 오른쪽으로 진행합니다. 비교할 때마다 반대 부분 트리를 배제할 수 있는 이유는 해당 부분 트리의 모든 키가 순서 조건을 만족하기 때문입니다. 그렇다고 매번 노드 수를 절반씩 버리는 것은 아니므로 편향되면 탐색은 O(n)입니다.

MST는 이미 주어진 가중 무방향 연결 그래프에서 간선을 선택하는 최적화 문제입니다. 예를 들어 AB=1, AC=4, BC=2, BD=5, CD=3이라면 AB,BC,CD를 고른 합 6이 최소 신장 트리입니다. 원래 그래프의 모든 정점을 잇되 사이클이 없는 n-1개 간선을 선택합니다. 가중치 동률이 있으면 최소 해가 여러 개일 수 있습니다.
| 알고리즘 | 유지하는 상태 | 다음 선택 |
|---|---|---|
| 크루스칼 | 서로 떨어진 여러 연결 요소 | 전체 간선의 가중치 순서에서 사이클을 만들지 않는 간선 |
| 프림 | 시작 정점에서 자란 하나의 연결 영역 | 현재 영역과 바깥을 잇는 간선 중 최소 비용 |
위 예에서 크루스칼은 AB(1), BC(2), CD(3)를 받아들입니다. 프림을 A에서 시작해도 AB를 고르고, 경계 간선 중 BC, 다음 CD를 고릅니다. 출발점 하나에서 다른 정점까지의 거리 합이나 각각의 최단 경로를 최소화하는 문제가 아니므로 다익스트라와 목표를 섞지 않아야 합니다. 연결되지 않았다면 모든 정점을 잇는 트리는 없고 최소 신장 포리스트를 구합니다.
복잡도와 선택 기준
n은 노드 수, h는 간선 기준 높이입니다. 네 순회는 각 노드를 상수 번 다루므로 각각 O(n) 시간입니다. 전위·중위·표시를 둔 후위의 보조 스택은 O(h+1)이고, 이 코드의 BFS 큐는 O(n)입니다. 반환하는 네 배열이 각각 n개 값을 보관하므로 함수 전체 추가 공간은 O(n)입니다. 출력 공간을 빼고 BFS를 무조건 O(폭)이라고 적으면 실제 구현과 맞지 않습니다.
이진 트리의 모양을 다루는 문제라면 먼저 순회 순서를 고르고, 정렬된 동적 키 검색이면 BST를 검토하며, 연결 비용 최적화라면 가중 그래프와 MST 알고리즘을 선택합니다. 그래프의 기본 용어는 그래프 이론 기초, 행렬 표기는 행렬 기초에서 이어 볼 수 있습니다.
경계 확인과 연습
빈 트리, 루트만 있는 트리, 모든 값이 같은 트리, 오른쪽으로만 긴 트리를 따로 확인하세요. 값 중복은 방문을 생략할 이유가 되지 않습니다. 노드 식별과 노드에 저장한 값을 구별하는 습관은 이어지는 그래프 순회에서도 중요합니다.
JavaScript 트리 순회 연습: 깊이별 노드 묶기에서 직접 구현을 적용해 보세요.
삽입·탐색·삭제 구현은 JavaScript 이진 탐색 트리 구현으로 이어집니다.
함께 연습하고 확인할 자료
Binary Tree Level Order Traversal: 이진 트리를 레벨 순서로 방문하는 외부 연습입니다. 플랫폼의 노드 형식과 제출 인터페이스는 공식 페이지에서 확인하세요.
관련 개념 참고: Princeton Algorithms — Minimum Spanning Trees, Princeton — Binary Search Trees, BlogFlow — 기존 트리 자료구조 글 공식 자료와 문제 페이지는 2026년 9월 10일 확인했습니다. 외부 문제의 지문·예시를 복제하지 않고 이 글의 예제와 창작 문제를 별도로 구성했습니다.
직접 실습: 연산 비용으로 구조를 설명합니다
실습 주제: 트리 자료구조 차이: 이진 트리 BST MST 구분하기
- 본문 구현에서 저장되는 값과 연결 관계를 그림으로 적습니다.
- 조회·삽입·삭제 중 이 구조가 가장 자주 수행할 연산을 고릅니다.
- 연산 전후에도 유지되어야 하는 규칙을 한 문장으로 적습니다.
- 배열이나 Map 같은 다른 구조로 바꿨을 때 시간·공간 비용을 비교합니다.
풀이 기준과 확인 결과
메서드 이름만 외우지 말고 한 번의 연산에서 어떤 값과 연결이 바뀌는지 추적하세요. 빈 구조, 원소 한 개, 중복값, 연속 삽입·삭제를 실행했을 때 본문이 설명한 불변식이 유지되면 성공입니다.
테스트 체크리스트
- 빈 구조에 대한 조회·삭제 처리
- 첫 원소와 마지막 원소 변경
- 중복값 또는 동일 우선순위 처리
- 입력 크기가 커졌을 때 예상 복잡도 유지
이 글이 도움이 되었나요?
자료구조 학습 순서
필수 18개 · 전체 18개
읽음 기록 관리
전체 과정 목차 (18개)
- 필수 학습 · 자료구조 선택 가이드: 연산 비용으로 배열·스택·큐·Set 고르기
- 필수 학습 · JavaScript 배열: 인덱스 조회와 삽입·삭제 비용
- 필수 학습 · JavaScript Map·Set: 값 조회와 중복 제거 실습
- 필수 학습 · 자료구조 스택 쉽게 이해하기: push pop으로 문제 풀이 감 잡기
- 필수 학습 · 큐와 FIFO: head 인덱스로 JavaScript 대기열 만들기
- 필수 학습 · 단방향 연결 리스트: head·tail 삽입과 삭제
- 필수 학습 · JavaScript 원형 덱 구현: 양끝 삽입·삭제와 고정 용량 버퍼
- 필수 학습 · JavaScript 문자열 해시 테이블 구현: 충돌 처리와 리사이즈, NFC 정규화
- 필수 학습 · 트리 자료구조 차이: 이진 트리 BST MST 구분하기 현재 글
- 필수 학습 · JavaScript 이진 탐색 트리 구현: 중복 키와 세 가지 삭제 처리
- 필수 학습 · JavaScript 최소 힙 구현: 우선순위 큐의 push·pop과 비교 함수
- 필수 학습 · JavaScript 그래프 구현: 인접 리스트·인접 행렬 비교와 BFS
- 필수 학습 · JavaScript Union-Find: 경로 압축과 크기 합치기로 연결 상태 관리하기
- 필수 학습 · JavaScript Trie: Unicode 접두사 검색과 안전한 삭제 구현
- 필수 학습 · JavaScript Fenwick Tree: lowbit로 구간 합과 단일 증가 갱신 구현
- 필수 학습 · JavaScript 반복형 세그먼트 트리: 구간 합·단일 대입·결합 순서
- 필수 학습 · JavaScript LRU 캐시: Map과 이중 연결 리스트의 불변식
- 필수 학습 · JavaScript AVL 트리: 높이 불변식과 LL·RR·LR·RL 삽입 회전
새 글 받아보기
RSS 리더에서 BlogFlow의 새 글을 확인할 수 있습니다.