Node가 왜 가능한지AddAtHead, AddAtTail, Insert, Remove)의 연결 순서template <typename T>
struct Node {
explicit Node(const T& data = T()) : data(data) {}
T data{};
Node* prev = nullptr;
Node* next = nullptr;
};
핵심:
Node*는 Node “객체 자체”가 아니라 Node의 주소를 저장합니다.Node 안에 Node*가 있어도 무한 중첩이 아니라, 링크(연결)만 만들어집니다.| 항목 | 단방향(Singly) | 양방향(Doubly) |
|---|---|---|
| 링크 | next | prev + next |
| 뒤로 이동 | 어려움 | 가능 |
| 중간 삭제 | 이전 노드 찾기 필요 | 이전/다음 링크 바로 갱신 가능 |
| 구현 난이도 | 낮음 | 조금 높음 |
실무 감각:
구조:
[HeadDummy] <-> [data1] <-> [data2] <-> ... <-> [TailDummy]
빈 리스트:
HeadDummy <-> TailDummy
_head->next는 항상 첫 데이터 노드 또는 _tail_tail->prev는 항상 마지막 데이터 노드 또는 _head_head->next == _tailNode<T>* node = _head;
while (node != nullptr) {
Node<T>* toDelete = node; // 1) 삭제 대상 백업
node = node->next; // 2) 먼저 다음으로 이동
delete toDelete; // 3) 삭제
}
포인트:
Node<T>* AddAtHead(const T& data)
{
Node<T>* node = new Node<T>(data);
Node<T>* nextNode = _head->next;
node->prev = _head;
node->next = nextNode;
_head->next = node;
nextNode->prev = node;
return node;
}
Node<T>* AddAtTail(const T& data)
{
Node<T>* node = new Node<T>(data);
Node<T>* prevNode = _tail->prev;
node->prev = prevNode;
node->next = _tail;
prevNode->next = node;
_tail->prev = node;
return node;
}
핵심:
Node<T>* GetNode(int index)
{
if (index < 0)
return nullptr;
Node<T>* node = _head->next;
for (int i = 0; i < index; ++i) {
if (node == _tail)
return nullptr;
node = node->next;
}
return (node == _tail) ? nullptr : node;
}
void Insert(Node<T>* posNode, const T& data)
{
if (posNode == nullptr || posNode == _head)
return;
Node<T>* node = new Node<T>(data);
Node<T>* prevNode = posNode->prev;
node->prev = prevNode;
node->next = posNode;
prevNode->next = node;
posNode->prev = node;
}
Node<T>* Remove(Node<T>* node)
{
if (node == nullptr || node == _head || node == _tail)
return nullptr; // 더미 삭제 금지
Node<T>* prevNode = node->prev;
Node<T>* nextNode = node->next;
prevNode->next = nextNode;
nextNode->prev = prevNode;
delete node;
return nextNode;
}
정답:
실전 예:
Remove에서 더미 노드를 삭제하면 왜 위험한가?