[C++ 자료 구조와 알고리즘] #3 자료 구조 (3) - std::vector (C++ STL container), std::vector 기반 stack과 queue

Programming/C++ · 2023. 5. 18. 22:04

안녕하세요. C++을 다루기 위한 기본 적인 자료 구조와 코딩 테스트 등에서 응용될 수 있는 알고리즘을 알아보는 시간을 가지겠습니다.

 

이번 게시물은 std::vector를 간단히 설명해 보려 합니다. 

게시물 끝에 std::vector를 사용한 stack과 queue 구현 예시도 있으니까 참고 바랍니다!

 

1) 특징

std::vector는 C++ 표준 라이브러리에서 제공하는 동적 배열 컨테이너입니다. 동적 배열은 크기를 동적으로 조정할 수 있는 배열로, 필요에 따라 크기를 증가/감소시킬 수 있습니다. std::vector는 배열의 크기, 원소 삽입, 원소 삭제, 검색 등 다양한 기능을 활용할 수 있기 때문에 유연한 데이터 구조를 구현할 수 있습니다.

 

2) 속성 (Attributes)

std::vector는 헤더를 포함해서 사용할 수 있습니다.

다음과 같은 std::vector의 주요 속성과 멤버 함수를 통해 해당 자료 구조를 활용하는 방법을 자세하게 알아보겠습니다.

 

일단 std::vector가 가지고 있는 주요 속성은 다음과 같습니다.

 

  • size()
    size_t size() const;
    std::vector에 저장된 원소의 개수를 반환합니다.
    즉, 현재 std::vector의 크기를 알려줍니다.
  • capacity()
    size_t capacity() const;
    std::vector가 현재 메모리에서 할당한 용량을 반환합니다.
    std::vector의 용량은 실제 원소를 저장할 수 있는 최대 공간입니다.
    capacity()는 원소를 추가할 때 재할당을 최소화하는 데 사용됩니다.
  • max_size()
    size_t max_size() const;
    std::vector가 최대로 저장할 수 있는 원소의 개수를 반환합니다.
    이는 특정 시스템의 제약에 따라 다를 수 있으며, 일반적으로 매우 큰 값을 가집니다.
  • empty()
    bool empty() const;
    std::vector가 비어있는지 여부를 반환합니다.
    비어있으면 true, 비어있지 않으면 false를 반환합니다.
  • operator[]
    T& operator[](size_t pos);
    const T& operator[](size_t pos) const;
    지정된 인덱스에 해당하는 원소에 접근합니다.
    대괄호 연산자를 사용하여 인덱스 위치의 원소를 읽거나 수정할 수 있습니다.
  • front()
    T& front();
    const T& front() const;
    std::vector의 첫 번째 원소에 대한 참조를 반환합니다.
  • back()
    T& back();
    const T& back() const;
    std::vector의 마지막 원소에 대한 참조를 반환합니다.

 

3) 속성 사용 예시

 

1. 크기 및 용량 (Size and Capacity)

- size(): std::vector에 저장된 원소의 개수를 반환합니다.

- capacity(): std::vector의 현재 할당된 용량을 반환합니다.

#include <vector>
#include <iostream>

int main() {
    std::vector<int> vec;

    // 원소 추가
    vec.push_back(1);
    vec.push_back(2);
    vec.push_back(3);

    // 크기와 용량 출력
    std::cout << "Size: " << vec.size() << std::endl;         // 출력: Size: 3
    std::cout << "Capacity: " << vec.capacity() << std::endl; // 출력: Capacity: 4

    return 0;
}

 

2. 원소 접근 (Element Access)

- operator[]: 인덱스를 사용하여 특정 위치의 원소에 접근합니다.

- at(): 인덱스를 사용하여 특정 위치의 원소에 접근하며, 범위를 검사하여 예외를 처리합니다.

- front(): 첫 번째 원소에 접근합니다.

- back(): 마지막 원소에 접근합니다.

#include <vector>
#include <iostream>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};

    // 원소 접근
    std::cout << "Element at index 2: " << vec[2] << std::endl; // 출력: Element at index 2: 3
    std::cout << "Element at index 4: " << vec.at(4) << std::endl; // 출력: Element at index 4: 5
    std::cout << "First element: " << vec.front() << std::endl; // 출력: First element: 1
    std::cout << "Last element: " << vec.back() << std::endl; // 출력: Last element: 5

    return 0;
}

 

3. 원소 추가 및 삭제 (Element Insertion and Deletion)

- 원소 추가 및 삭제 (Element Insertion and Deletion)
- push_back(): std::vector의 끝에 원소를 추가합니다.

- pop_back(): std::vector의 끝에서 원소를 제거합니다.

- insert(): 특정 위치에 원소를 삽입합니다.

- erase(): 특정 위치의 원소를 제거합니다.

#include <vector>
#include <iostream>

int main() {
std::vector<int> vec;
// 원소 추가
vec.push_back(1);
vec.push_back(2);
vec.push_back(3);

// 원소 출력
std::cout << "Elements: ";
for (int num : vec) {
    std::cout << num << " ";
}
std::cout << std::endl; // 출력: Elements: 1 2 3

// 원소 삭제
vec.pop_back();

// 삽입 및 삭제
vec.insert(vec.begin() + 1, 4); // 인덱스 1 위치에 4 삽입

// 범위 기반 삭제
vec.erase(vec.begin() + 2); // 인덱스 2 위치의 원소 제거

// 원소 출력
std::cout << "Updated Elements: ";
for (int num : vec) {
    std::cout << num << " ";
}
std::cout << std::endl; // 출력: Updated Elements: 1 4

return 0;
}

 

4. 벡터 크기 조절 (Resizing the Vector) 

- resize(): std::vector의 크기를 조절합니다. 크기를 증가시키면 추가된 원소는 기본값으로 초기화됩니다.

- reserve(): std::vector의 용량을 미리 예약합니다. 예약된 용량은 원소를 추가할 때 재할당을 최소화하여 성능을 향상합니다.

#include <vector>
#include <iostream>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};

    // 크기 변경
    vec.resize(3);

    // 용량 예약
    vec.reserve(10);

    // 크기와 용량 출력
    std::cout << "Size: " << vec.size() << std::endl;         // 출력: Size: 3
    std::cout << "Capacity: " << vec.capacity() << std::endl; // 출력: Capacity: 10

    return 0;
}

 

5. 반복자 활용 (Iterator Usage)

- begin(): std::vector의 첫 번째 원소를 가리키는 반복자를 반환합니다.

- end(): std::vector의 마지막 다음 위치를 가리키는 반복자를 반환합니다.

#include <vector>
#include <iostream>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};

    // 반복자를 사용하여 원소 출력
    std::cout << "Elements: ";
    for (auto it = vec.begin(); it != vec.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl; // 출력: Elements: 1 2 3 4 5

    return 0;
}

 

4) std::vector를 활용한 stack과 queue 구현 예시

 

1. Stack 구현 예시

#include <vector>
#include <iostream>

template<typename T>
class Stack {
private:
    std::vector<T> data;

public:
    void push(const T& value) {
        data.push_back(value);
    }

    void pop() {
        if (!empty()) {
            data.pop_back();
        }
    }

    const T& top() const {
        return data.back();
    }

    bool empty() const {
        return data.empty();
    }

    size_t size() const {
        return data.size();
    }
};

int main() {
    Stack<int> stack;

    stack.push(1);
    stack.push(2);
    stack.push(3);

    std::cout << "Size: " << stack.size() << std::endl;       // 출력: Size: 3
    std::cout << "Top: " << stack.top() << std::endl;         // 출력: Top: 3

    stack.pop();

    std::cout << "Size: " << stack.size() << std::endl;       // 출력: Size: 2
    std::cout << "Top: " << stack.top() << std::endl;         // 출력: Top: 2

    return 0;
}

 

2. Queue 구현 예시

#include <vector>
#include <iostream>

template<typename T>
class Queue {
private:
    std::vector<T> data;

public:
    void enqueue(const T& value) {
        data.push_back(value);
    }

    void dequeue() {
        if (!empty()) {
            data.erase(data.begin());
        }
    }

    const T& front() const {
        return data.front();
    }

    bool empty() const {
        return data.empty();
    }

    size_t size() const {
        return data.size();
    }
};

int main() {
    Queue<int> queue;

    queue.enqueue(1);
    queue.enqueue(2);
    queue.enqueue(3);

    std::cout << "Size: " << queue.size() << std::endl;       // 출력: Size: 3
    std::cout << "Front: " << queue.front() << std::endl;     // 출력: Front: 1

    queue.dequeue();

    std::cout << "Size: " << queue.size() << std::endl;       // 출력: Size: 2
    std::cout << "Front: " << queue.front() << std::endl;     // 출력: Front: 2

    return 0;
}
반응형