챕터6. 실습 문제

2025. 3. 28. 08:46Programming Languages/C++

6.6 실습 문제

문제 1: 동적 메모리를 사용한 간단한 문자열 클래스

#include <iostream>
#include <cstring>

class MyString {
private:
    char* buffer;
    size_t length;
    
public:
    // 기본 생성자
    MyString() : buffer(nullptr), length(0) {
        buffer = new char[1];
        buffer[0] = '\0';
    }
    
    // 매개변수가 있는 생성자
    MyString(const char* str) : buffer(nullptr), length(0) {
        if (str) {
            length = strlen(str);
            buffer = new char[length + 1];
            strcpy(buffer, str);
        } else {
            buffer = new char[1];
            buffer[0] = '\0';
        }
    }
    
    // 복사 생성자
    MyString(const MyString& other) : buffer(nullptr), length(other.length) {
        buffer = new char[length + 1];
        strcpy(buffer, other.buffer);
    }
    
    // 이동 생성자
    MyString(MyString&& other) noexcept : buffer(nullptr), length(0) {
        // 리소스 이동
        buffer = other.buffer;
        length = other.length;
        
        // 원본 객체 무효화
        other.buffer = nullptr;
        other.length = 0;
    }
    
    // 소멸자
    ~MyString() {
        delete[] buffer;
    }
    
    // 복사 대입 연산자
    MyString& operator=(const MyString& other) {
        if (this != &other) {
            // 기존 리소스 해제
            delete[] buffer;
            
            // 새 리소스 할당
            length = other.length;
            buffer = new char[length + 1];
            strcpy(buffer, other.buffer);
        }
        return *this;
    }
    
    // 이동 대입 연산자
    MyString& operator=(MyString&& other) noexcept {
        if (this != &other) {
            // 기존 리소스 해제
            delete[] buffer;
            
            // 리소스 이동
            buffer = other.buffer;
            length = other.length;
            
            // 원본 객체 무효화
            other.buffer = nullptr;
            other.length = 0;
        }
        return *this;
    }
    
    // 문자열 길이 반환
    size_t getLength() const {
        return length;
    }
    
    // C 스타일 문자열 반환
    const char* getCString() const {
        return buffer;
    }
    
    // 두 문자열 연결
    MyString concat(const MyString& other) const {
        size_t newLength = length + other.length;
        char* newBuffer = new char[newLength + 1];
        
        strcpy(newBuffer, buffer);
        strcat(newBuffer, other.buffer);
        
        MyString result;
        delete[] result.buffer;
        result.buffer = newBuffer;
        result.length = newLength;
        
        return result;
    }
    
    // 문자열 출력
    void print() const {
        std::cout << buffer << std::endl;
    }
};

int main() {
    // 기본 생성자
    MyString str1;
    std::cout << "str1 (빈 문자열): ";
    str1.print();
    
    // 매개변수가 있는 생성자
    MyString str2("Hello, World!");
    std::cout << "str2: ";
    str2.print();
    std::cout << "str2 길이: " << str2.getLength() << std::endl;
    
    // 복사 생성자
    MyString str3 = str2;
    std::cout << "str3 (str2 복사): ";
    str3.print();
    
    // 대입 연산자
    str1 = str3;
    std::cout << "str1 = str3: ";
    str1.print();
    
    // 문자열 연결
    MyString str4 = str1.concat(MyString(" C++ is fun!"));
    std::cout << "연결된 문자열: ";
    str4.print();
    
    // 이동 생성자 및 이동 대입 연산자 테스트
    MyString str5 = std::move(str4);
    std::cout << "str5 (str4에서 이동): ";
    str5.print();
    
    // str4는 이제 비어 있어야 함
    std::cout << "이동 후 str4 길이: " << str4.getLength() << std::endl;
    std::cout << "이동 후 str4: ";
    str4.print();
    
    return 0;
}

문제 2: 링크드 리스트 구현

#include <iostream>

// 노드 구조체
struct Node {
    int data;
    Node* next;
    
    // 생성자
    Node(int value) : data(value), next(nullptr) {}
};

// 연결 리스트 클래스
class LinkedList {
private:
    Node* head;
    
public:
    // 기본 생성자
    LinkedList() : head(nullptr) {}
    
    // 소멸자
    ~LinkedList() {
        clear();
    }
    
    // 리스트의 앞에 노드 추가
    void pushFront(int value) {
        Node* newNode = new Node(value);
        newNode->next = head;
        head = newNode;
    }
    
    // 리스트의 끝에 노드 추가
    void pushBack(int value) {
        Node* newNode = new Node(value);
        
        // 빈 리스트인 경우
        if (head == nullptr) {
            head = newNode;
            return;
        }
        
        // 마지막 노드 찾기
        Node* current = head;
        while (current->next != nullptr) {
            current = current->next;
        }
        
        // 마지막 노드에 새 노드 연결
        current->next = newNode;
    }
    
    // 특정 위치에 노드 삽입
    bool insertAt(int position, int value) {
        // 위치가 0보다 작으면 실패
        if (position < 0) {
            return false;
        }
        
        // 위치가 0이면 앞에 추가
        if (position == 0) {
            pushFront(value);
            return true;
        }
        
        // 삽입 위치의 이전 노드 찾기
        Node* current = head;
        for (int i = 0; i < position - 1; i++) {
            if (current == nullptr) {
                return false;  // 위치가 범위를 벗어남
            }
            current = current->next;
        }
        
        // 현재 노드가 nullptr이면 위치가 범위를 벗어남
        if (current == nullptr) {
            return false;
        }
        
        // 새 노드 생성 및 연결
        Node* newNode = new Node(value);
        newNode->next = current->next;
        current->next = newNode;
        
        return true;
    }
    
    // 리스트의 앞에서 노드 제거
    bool popFront() {
        if (head == nullptr) {
            return false;  // 빈 리스트
        }
        
        Node* temp = head;
        head = head->next;
        delete temp;
        
        return true;
    }
    
    // 리스트의 끝에서 노드 제거
    bool popBack() {
        if (head == nullptr) {
            return false;  // 빈 리스트
        }
        
        // 리스트에 노드가 하나만 있는 경우
        if (head->next == nullptr) {
            delete head;
            head = nullptr;
            return true;
        }
        
        // 마지막 노드의 이전 노드 찾기
        Node* current = head;
        while (current->next->next != nullptr) {
            current = current->next;
        }
        
        // 마지막 노드 삭제
        delete current->next;
        current->next = nullptr;
        
        return true;
    }
    
    // 특정 위치의 노드 제거
    bool removeAt(int position) {
        if (head == nullptr || position < 0) {
            return false;
        }
        
        // 첫 번째 노드 제거
        if (position == 0) {
            return popFront();
        }
        
        // 제거할 노드의 이전 노드 찾기
        Node* current = head;
        for (int i = 0; i < position - 1; i++) {
            if (current->next == nullptr) {
                return false;  // 위치가 범위를 벗어남
            }
            current = current->next;
        }
        
        // 제거할 노드가 없는 경우
        if (current->next == nullptr) {
            return false;
        }
        
        // 노드 제거
        Node* temp = current->next;
        current->next = temp->next;
        delete temp;
        
        return true;
    }
    
    // 특정 값 검색
    bool contains(int value) const {
        Node* current = head;
        
        while (current != nullptr) {
            if (current->data == value) {
                return true;
            }
            current = current->next;
        }
        
        return false;
    }
    
    // 특정 값의 첫 번째 인덱스 찾기
    int indexOf(int value) const {
        Node* current = head;
        int index = 0;
        
        while (current != nullptr) {
            if (current->data == value) {
                return index;
            }
            current = current->next;
            index++;
        }
        
        return -1;  // 값을 찾지 못함
    }
    
    // 모든 노드 제거
    void clear() {
        while (head != nullptr) {
            Node* temp = head;
            head = head->next;
            delete temp;
        }
    }
    
    // 리스트가 비어 있는지 확인
    bool isEmpty() const {
        return head == nullptr;
    }
    
    // 리스트 출력
    void print() const {
        if (isEmpty()) {
            std::cout << "빈 리스트" << std::endl;
            return;
        }
        
        Node* current = head;
        while (current != nullptr) {
            std::cout << current->data;
            if (current->next != nullptr) {
                std::cout << " -> ";
            }
            current = current->next;
        }
        std::cout << std::endl;
    }
};

int main() {
    LinkedList list;
    
    // 노드 추가
    std::cout << "노드 추가(1, 2, 3): ";
    list.pushBack(1);
    list.pushBack(2);
    list.pushBack(3);
    list.print();
    
    // 앞에 노드 추가
    std::cout << "앞에 노드 추가(0): ";
    list.pushFront(0);
    list.print();
    
    // 특정 위치에 노드 삽입
    std::cout << "위치 2에 노드 삽입(10): ";
    list.insertAt(2, 10);
    list.print();
    
    // 앞에서 노드 제거
    std::cout << "앞에서 노드 제거: ";
    list.popFront();
    list.print();
    
    // 끝에서 노드 제거
    std::cout << "끝에서 노드 제거: ";
    list.popBack();
    list.print();
    
    // 특정 위치의 노드 제거
    std::cout << "위치 1의 노드 제거: ";
    list.removeAt(1);
    list.print();
    
    // 값 검색
    int searchValue = 1;
    std::cout << searchValue << "이 리스트에 "
              << (list.contains(searchValue) ? "있습니다." : "없습니다.") << std::endl;
    
    // 값의 인덱스 찾기
    int findValue = 2;
    int index = list.indexOf(findValue);
    if (index != -1) {
        std::cout << findValue << "의 인덱스: " << index << std::endl;
    } else {
        std::cout << findValue << "을 찾을 수 없습니다." << std::endl;
    }
    
    // 모든 노드 제거
    std::cout << "모든 노드 제거 후: ";
    list.clear();
    list.print();
    
    return 0;
}

'Programming Languages > C++' 카테고리의 다른 글

클래스 템플릿 기초  (0) 2025.03.28
템플릿  (0) 2025.03.28
고급 포인터 주제  (0) 2025.03.28
참조  (0) 2025.03.28
동적 메모리 할당  (0) 2025.03.28