안녕하세요. 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;
}