연결 리스트가 뭐야? 🤔
연결 리스트는 마치 "사람들이 손을 잡고 줄서기" 하는 것과 같아요! 🤝
일상 예시로 설명하면:
- 놀이공원에서 줄서기 🎢
- 첫 번째 사람(HEAD)이 줄의 시작 👑
- 마지막 사람(TAIL)이 줄의 끝 🏁
- 각자 앞사람이 누군지만 알고 있음 👀
배열은 아파트처럼 연속된 집에 살지만 📢, 연결 리스트는 각자 다른 동네에 살면서 다음 집 주소만 알고 있는 느낌이에요! 🏘️
연결 리스트의 종류 🎯
1. 단일 연결 리스트 (Singly Linked List)
→ → → 한 방향으로만 이동 가능 🚶♂️
2. 이중 연결 리스트 (Doubly Linked List)
← → ← → 양방향 이동 가능 🚶♂️🚶♀️
3. 원형 연결 리스트 (Circular Linked List)
→ → → ↩️ 마지막이 첫 번째와 연결 🔄
연결 리스트 vs 배열 비교 ⚖️
메모리 | 연속적 | 흩어져 있음 |
접근 속도 | O(1) 빠름 ⚡ | O(n) 느림 🐌 |
삽입/삭제 | O(n) 느림 🐌 | O(1) 빠름 ⚡ |
메모리 사용 | 효율적 💪 | 포인터 추가 필요 📦 |
연결 리스트 주요 연산들 🛠️
1. 탐색 (Search) 🔍
"친구 찾기" 와 같아요!
- 첫 번째 사람부터 한 명씩 확인 👥
- 찾는 사람이 나올 때까지 계속 다음 사람에게 물어봄 🗣️
- 최악의 경우 마지막 사람까지 확인 😵
- 시간 복잡도: O(n)
2. 삽입 (Insert) ➕
"줄 새치기" 하는 상황!
- 새로운 사람이 3번째 위치에 끼어들고 싶다면? 🤷♀️
- 2번째 사람이 새로운 사람 손을 잡고 👫
- 새로운 사람이 기존 3번째 사람 손을 잡으면 완료! ✅
- 시간 복잡도: O(1) (위치를 안다면)
3. 삭제 (Delete) ➖
"줄에서 빠지기" 상황!
- 3번째 사람이 줄에서 나가고 싶다면? 🚪
- 2번째 사람이 4번째 사람 손을 바로 잡으면 완료! 🤝
- 3번째 사람은 자연스럽게 분리됨 👋
- 시간 복잡도: O(1) (위치를 안다면)
Node.js/백엔드에서 활용 사례 🚀
1. 메모리 관리
- 가비지 컬렉션에서 사용 ♻️
- 동적 메모리 할당 시 효율적 📊
2. 데이터베이스 인덱싱
- B-Tree 같은 구조의 기본 개념 🌳
- MongoDB의 내부 구조에도 활용 🍃
3. 캐시 구현 (LRU Cache)
- 최근 사용한 데이터 관리 📋
- Redis 같은 인메모리 DB에서 활용 ⚡
4. 이벤트 큐 (Event Queue)
- Node.js 이벤트 루프 구현 🔄
- 비동기 작업 처리 순서 관리 ⏰
실무에서 주의할 점 ⚠️
1. 메모리 누수 방지
- 삭제된 노드 참조 해제 필수 🧽
- 가비지 컬렉션 도움 받기 ♻️
2. 성능 고려사항
- 자주 탐색하는 데이터라면 배열 고려 🤔
- 삽입/삭제가 빈번하면 연결 리스트 유리 ✅
3. 메모리 단편화
- 노드들이 메모리에 흩어져 있어 캐시 효율성 떨어짐 📉
- 대량 데이터 처리 시 성능 이슈 가능 🐌
언제 연결 리스트를 사용할까? 🤷♂️
사용하면 좋은 경우 ✅
- 데이터 크기를 미리 알 수 없을 때 📏
- 삽입/삭제가 자주 발생할 때 🔄
- 메모리 효율성이 중요할 때 💾
사용하지 않는 게 좋은 경우 ❌
- 랜덤 접근이 자주 필요할 때 🎯
- 캐시 효율성이 중요할 때 ⚡
- 메모리가 제한적일 때 📦
추가로 알면 좋은 정보 💡
1. 더미 헤드 (Dummy Head) 기법
첫 번째 노드 처리를 쉽게 하는 트릭 🎩
2. 투 포인터 (Two Pointer) 기법
연결 리스트에서 중간 지점 찾기 등에 활용 🎯
3. 메모리 풀 (Memory Pool)
노드 생성/삭제 성능 향상 기법 🏊♂️
면접 답변 💼
"연결 리스트에 대해 설명해주세요"
연결 리스트는 각 노드가 데이터와 다음 노드의 주소를 가지고 있는 선형 자료구조입니다. 배열과 달리 메모리에 연속적으로 저장되지 않고, 포인터로 연결되어 있습니다. 탐색은 O(n)이지만 삽입/삭제는 O(1)의 시간복잡도를 가져 동적 데이터 관리에 효율적입니다. 단일, 이중, 원형 연결 리스트로 구분되며, 메모리 크기를 미리 알 수 없거나 삽입/삭제가 빈번한 상황에서 유용합니다.
연결 리스트에 대해서 설명해주세요.
연결 리스트(Linked List) 는 리스트 내의 요소(노드)들을 포인터로 연결하여 관리하는 선형 자료구조입니다. 각 노드는 데이터와 다음 요소에 대한 포인터를 가지고 있는데요. 이때, 첫 번째 노드를 HEAD, 마지막 노드를 TAIL 이라고 합니다. 연결 리스트는 메모리가 허용하는 한 요소를 계속 삽입할 수 있으며, 시각 복잡도는 탐색에는 O(n), 노드 삽입과 삭제는 O(1)라는 특징을 가지고 있습니다. 해당 아이디어로 파생된 자료구조는 단일 연결 리스트(Singly Linked List), 이중 연결 리스트(Doubly Linked List, Circular Linked List)가 존재합니다.
배열은 순차적인 데이터가 들어가기 때문에 메모리 영역을 연속적으로 사용합니다. 반면, 연결 리스트는 메모리 공간에 흩어져서 존재한다는 점에서 배열과 차이가 있습니다.
단일 연결 리스트의 탐색, 추가, 삭제에 대해서 더욱 자세히 설명해 주세요. 🤔
class SinglyLinkedList {
public Node head;
public Node tail;
public Node insert(int newValue) {
Node newNode = new Node(null, newValue);
if (head == null) {
head = newNode;
} else {
tail.next = newNode;
}
tail = newNode;
return newNode;
}
public Node find(int findValue) {
Node currentNode = head;
while (currentNode.value != findValue) {
currentNode = currentNode.next;
}
return currentNode;
}
public void appendNext(Node prevNode, int value) {
prevNode.next = new Node(prevNode.next, value);
}
public void deleteNext(Node prevNode) {
if (prevNode.next != null) {
prevNode.next = prevNode.next.next;
}
}
}
단일 연결 리스트에서 탐색은 최악의 경우, 시간 복잡도는 O(n)입니다. 왜냐하면, 노드를 탐색하기 위해서 HEAD의 포인터부터 데이터를 찾을 때까지 다음 요소를 반복적으로 탐색하기 때문입니다.
삽입의 경우, 삽입될 위치 이전에 존재하는 노드와 신규 노드의 포인터를 조작하면 됩니다. 가령, 3번 위치에 신규 노드를 삽입해야 한다면 2번 위치에 있는 노드의 포인터를 신규 노드를 가리키도록 하고, 신규 노드의 포인터는 기존 3번 노드의 위치를 가리키도록 하면 됩니다. 삭제는 삭제할 노드의 이전 노드가 삭제 대상 노드의 다음 노드를 가리키도록 수정하고, 삭제 대상 노드를 메모리에서 지우면 됩니다. 삽입과 삭제 연산 자체의 경우 시간 복잡도는 O(1)이지만, 탐색이 필요한 경우 선형 시간이 걸립니다.
'1일 1CS(Computer Science)' 카테고리의 다른 글
NAT 기능을 사용하는 이유를 알고 계신가요? (3) | 2025.06.23 |
---|---|
알고 있는 이미지 포맷과 각 포맷별 특징을 알려주세요. (4) | 2025.06.23 |
프로토타입 상속의 동작 방식에 대해 설명해주세요. (1) | 2025.06.20 |
AI시대, 지금이 소프트웨어 개발을 배우기에 가장 좋은 시기일지도 모릅니다 (1) | 2025.06.19 |
함수형 프로그래밍에 대해서 설명해주세요. (1) | 2025.06.19 |