3 minute read

클래스로 구현한 코드

#include <bits/stdc++.h>
#define ll long long
using namespace std;
#define X first
#define Y second
class Deque
{
    struct Node // 노드 구조체 정의
    {
        int data; // 정수 데이터를 저장하기 위한 변수
        Node* prev; // 이전 노드를 가리키는 포인터
        Node* next; // 다음 노드를 가리키는 포인터

        Node(int data) : data(data), prev(nullptr), next(nullptr) {} // 생성자에서 데이터와 포인터 초기화
    };

    Node* head; // 덱의 첫 번째 노드를 가리키는 포인터
    Node* tail; // 덱의 마지막 노드를 가리키는 포인터
    int size;
public:
    Deque() : head(nullptr), tail(nullptr), size(0) {} // 생성자에서 head와 tail 초기화

    ~Deque() // 소멸자
    {
        Node* temp; // 임시 포인터 생성

        // 노드를 방문하며 메모리를 해제합니다.
        while (head != nullptr)
        {
            temp = head; // head를 temp에 저장
            head = head->next; // head가 두 번째 노드를 가리키도록 설정
            delete temp; // 첫 번째 노드 메모리 해제
        }
    }
    void sizze()
    {
        cout << size << "\n";
    }

    bool isEmpty() // 덱이 비어있는지 확인
    {
        return head == nullptr;
    }

    void push_front(int value) // 앞쪽에 노드를 추가
    {
        Node* newNode = new Node(value); // 새 노드 생성 및 초기화

        if (isEmpty()) // 덱이 비어있을 경우
        {
            head = tail = newNode; // head와 tail이 새 노드를 가리키게 함
        }
        else
        {
            newNode->next = head; // 새 노드의 다음 노드를 현재 head로 설정
            head->prev = newNode; // 현재 head의 이전 노드를 새 노드로 설정
            head = newNode; // head를 새 노드로 설정
        }
        size++;
    }

    void push_back(int value) // 뒤쪽에 노드를 추가
    {
        Node* newNode = new Node(value); // 새 노드 생성 및 초기화

        if (isEmpty()) // 덱이 비어있을 경우
        {
            head = tail = newNode; // head와 tail이 새 노드를 가리키게 함
        }
        else
        {
            newNode->prev = tail; // 새 노드의 이전 노드를 현재 tail로 설정
            tail->next = newNode; // 현재 tail의 다음 노드를 새 노드로 설정
            tail = newNode; // tail을 새 노드로 설정
        }
        size++;
    }

    void pop_front() // 앞쪽 노드를 삭제
    {
        if (!isEmpty()) // 덱이 비어있지 않다면
        {
            size--;
            Node* temp = head; // 현재 head를 temp에 저장
            head = head->next; // head가 다음 노드를 가리키도록 설정
            if (head != nullptr)
            {
                head->prev = nullptr; // 새로운 head의 이전 노드를 nullptr로 설정
            }
            else
            {
                tail = nullptr; // 덱이 비어있다면 tail도 nullptr로 설정
            }
            cout << temp->data << "\n";
            delete temp; // 삭제할 노드 메모리 해제
        }
        else
            cout << "-1\n";
    }

    void pop_back() // 뒤쪽 노드를 삭제
    {
        if (!isEmpty()) // 덱이 비어있지 않다면
        {
            size--;
            Node* temp = tail; // 현재 tail을 temp에 저장
            tail = tail->prev; // tail이 이전 노드를 가리키도록 설정
            if (tail != nullptr)
            {
                tail->next = nullptr; // 새로운 tail의 다음 노드를 nullptr로 설정
            }
            else
            {
                head = nullptr; // 덱이 비어있다면 head도 nullptr로 설정
            }
            cout << temp->data << "\n";
            delete temp; // 삭제할 노드 메모리 해제
        }
        else
            cout << "-1\n";
    }

    int front() // 앞쪽 노드의 데이터를 가져옴
    {
        return isEmpty() ? -1 : head->data;
    }

    int back() // 뒤쪽 노드의 데이터를 가져옴
    {
        return isEmpty() ? -1 : tail->data;
    }
};
int main(void) {
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    int n; cin >> n;
    Deque q;
    for (int i = 0; i < n; i++)
    {
        string s; cin >> s;
        if (s == "push_back")
        {
            int data; cin >> data;
            q.push_back(data);
        }
        if (s == "push_front")
        {
            int data; cin >> data;
            q.push_front(data);
        }
        if (s == "pop_front")
        {
            q.pop_front();
        }
        if (s == "pop_back")
        {
            q.pop_back();
        }
        if (s == "size")
            q.sizze();
        if (s == "empty")
            cout << q.isEmpty() << "\n";
        if (s == "front")
            cout << q.front() << "\n";
        if (s == "back")
            cout << q.back() << "\n";
    }
    return 0;
}

boj 10866번 코드이다.
덱을 구현할때

  if (head != nullptr)
            {
                head->prev = nullptr; // 새로운 head의 이전 노드를 nullptr로 설정
            }
            else
            {
                tail = nullptr; // 덱이 비어있다면 tail도 nullptr로 설정
            }

이 부분이 중요한데 그 이유는

nullptr을 가리키지 않으면 해당 포인터는 예상치 못한 메모리 위치를 가리키게 됩니다. 이렇게 초기화되지 않은 포인터를 “와일드 포인터(wild pointer)”라고 부릅니다. 이러한 와일드 포인터는 메모리 관련 오류와 같은 런타임 오류의 원인이 될 수 있습니다. 예를 들어, 덱에서 마지막 요소가 삭제되었을 때 head와 tail 포인터를 nullptr로 설정하지 않으면, 이 포인터들은 아직 삭제된 노드를 가리키게 됩니다. 그리고 이 상태에서 다른 메서드를 호출하게 되면, 이미 삭제된 노드에 접근하려고 시도하면서 런타임 오류가 발생할 수 있습니다. 그래서 코드에서 마지막 요소가 삭제된 후 head와 tail을 nullptr로 설정하여 덱이 비어 있음을 표시하고, 다른 메서드가 호출될 때 올바르게 작동하도록 합니다. 이렇게 설정함으로써 “와일드 포인터”가 발생하는 것을 막고 안전한 프로그램 작동을 보장할 수 있습니다.

Leave a comment