본문 바로가기
SBS아카데미/게임프로그래밍

[C++ - TIL] 원형 연결 리스트의 중복 데이터 제거 및 포인터 관리

by musukie 2025. 8. 7.

🎮 주제 : 원형 연결 리스트의 중복 데이터 제거 및 포인터 관리

태그 : #C++ #자료구조 #원형연결리스트 #중복삭제 #포인터 #메모리관리


📌 학습 요약

  • 원형 연결 리스트(Circular Linked List) 구조 : 마지막 노드(head)의 next가 첫 번째 노드(head->next)를 가리키는 순환 구조의 특성을 이해하고 순회 로직 설계
  • 중복 데이터 전수 삭제 : 리스트 전체를 1회 순회하며 특정 데이터와 일치하는 모든 노드를 찾아 메모리를 해제하는 remove 함수 구현
  • 특수 케이스 예외 처리 : 삭제 대상이 리스트의 시작점이나 끝점일 경우, 기존에 구현된 pop_front와 pop_back을 호출하여 코드 재사용성 및 안정성 확보
  • 포인터 갱신 전략 : 노드 삭제 후 previousNode와 currentNode의 위치 관계가 깨지지 않도록 다음 탐색 위치를 정확히 지정하는 포인터 조작 기법 습득

🛠 주요 코드 및 구현 상세

1. 중복 노드 삭제 (remove) 함수

void remove(T data) {
    if (head == nullptr) {
        cout << "Linked list is empty" << endl;
        return;
    }

    Node* currentNode = head;      // 탐색을 시작할 현재 노드
    Node* previousNode = nullptr;  // 현재 노드의 이전 노드 추적
    int count = size;              // 순회 중 size가 변하므로 초기 크기 고정

    for (int i = 0; i < count; i++) {
        if (currentNode->data == data) {
            // 1. 마지막 노드(head)인 경우
            if (currentNode == head) {
                currentNode = currentNode->next;
                pop_back(); 
            }
            // 2. 첫 번째 노드(head->next)인 경우
            else if (currentNode == head->next) {
                currentNode = currentNode->next;
                pop_front();
            }
            // 3. 중간 노드인 경우
            else {
                previousNode->next = currentNode->next;
                delete currentNode;
                currentNode = previousNode->next; // 삭제된 다음 노드로 이동
                size--;
            }
        }
        else {
            // 삭제하지 않을 경우에만 previousNode 갱신
            previousNode = currentNode;
            currentNode = previousNode->next;
        }
    }
}

✅ 주요 문법 및 개념 정리

구분 일반 연결 리스트 원형 연결 리스트

끝 노드의 next nullptr 첫 번째 노드의 주소
탐색 종료 조건 next == nullptr 순회 횟수가 size에 도달
삽입/삭제 이점 - 양방향 접근 없이도 끝 노드에서 시작 노드 접근 가능
주의 사항 무한 루프 위험 낮음 잘못된 포인터 관리 시 무한 루프 위험 높음

💡 주의 : 삭제 후 포인터 갱신

  • 실수 : 노드를 delete 한 후 currentNode = currentNode->next를 시도함
    • 이미 삭제된 메모리의 next 멤버에 접근하는 것은 런타임 오류의 원인이 됨
  • 해결 : 삭제 전 previousNode->next를 미리 업데이트하거나, 위 코드처럼 previousNode->next를 통해 새 위치를 할당받아야 안전함

✨ 느낀 점

  • 중복 삭제 시 포인터 관리를 아주 세밀하게 하지 않으면 논리적 연결이 끊어지거나 메모리 오류가 발생하기 쉽다는 점을 다시금 깨달음
  • pop_front, pop_back 같이 검증된 함수를 내부에서 활용하는 것이 코드의 가독성과 유지보수성을 얼마나 높여주는지 경험함
  • 처음에는 노드 삭제 후 size 감소나 포인터 이동을 누락하는 실수가 있었으나, 리스트의 상태 변화를 단계별로 시뮬레이션하며 해결함
  • 원형 구조 특성상 head의 위치가 유동적일 수 있으므로 탐색 기준을 명확히 잡는 것이 중요하다는 것을 배움