벡터(vector)는 시퀀스 컨테이너(Sequence Container) 중 하나로 순서를 유지하는 선형 자료구조이다.
vector 는 배열처럼 데이터들을 메모리상에 순서대로 보관한다.
데이터들이 메모리상에 붙어있어 캐시 적중률(Cache Hit Rate) 이 높고 할당이 다소 어렵다.
vector 는 자동으로 메모리가 할당되는 동적 배열로 vector 생성 시 Heap 메모리에 동적으로 할당된다.

vector 는 기본적으로 맨 뒤에서 원소의 삽입/삭제가 가능하며, 중간에서의 원소 삽입/삭제도 가능하지만
크게 효율적이지는 않다.
vector 에 대한 일반적인 연산의 복잡도는 다음과 같다.
O(1)O(1)O(N)<aside> 💡 장점
</aside>
vector 의 맨 뒤에서 원소 삽입/삭제 시 효율적이다.<aside> 💡 단점
</aside>
vector 헤더파일#include <vector>
vector 의 선언std::vector<Type> VectorName;
vector 생성자 (편의상 int)| std::vector<int> v; | 비어있는 벡터 v를 생성 |
|---|---|
| std::vector<int> v(n); | 기본값(0)으로 초기화된 n 개의 원소를 갖는 벡터 v를 생성 |
| std::vector<int> v(n, m); | m으로 초기화된 n 개의 원소를 갖는 벡터 v를 생성 |
| std::vector<int> v2(v1); | 벡터 v1을 복사하여 벡터 v2를 생성 |
std::vector<int> v;
| v.push_back(n) | 벡터 맨 뒤에 원소 n 삽입 |
|---|---|
| v.pop_back() | 벡터의 마지막 원소를 제거 |
| v.front() | 첫 번째 원소의 참조를 반환 |
| v.back() | 마지막 원소의 참조를 반환 |
| v.begin() | 첫 번째 원소를 가리키는 iterator를 반환 |
| v.end() | 마지막 원소의 다음을 가리키는 iterator를 반환 |
| v.at(index) | index 번째 원소를 반환. (유효 index 인지 체크하기 때문에 안전하나 v[index] 보다 느림) |
| v[index] | index 번째 원소를 반환. (유효 index 인지 체크하지 않아 v.at(index)보다 빠름) |
| v.assign(n, m) | m의 값으로 n개의 원소를 할당 |
| v.clear() | 모든 원소를 제거. (size는 0이 되고, capacity는 유지) |
| v.size() | 원소의 개수를 반환 |
| v.capacity() | 할당된 공간(메모리)의 크기를 반환 |
| v.empty() | 벡터 v가 비어있으면(size == 0) true를 반환 |
| v.shrink_to_fit() | capacity의 크기를 벡터의 실제 크기에 맞춤 |
| v.reserve(n) | n개 원소 만큼 capacity를 미리 동적할당함 |
| v.resize(n) | size를 n 으로 변경. size가 커진 경우 빈 곳을 0(기본값)으로 초기화, |
| 작아진 경우 뒤에서부터 원소 삭제 | |
| v.resize(n, m) | size를 n 으로 변경. size가 커진 경우 빈 곳을 m으로 초기화, 작아진 경우 뒤에서부터 원소 삭제 |
| v.insert(iter, m) | iter가 가리키는 위치에 m의 값을 삽입한 후 해당 위치를 가리키는 iterator를 반환 |
| (뒤의 원소들은 밀려남.) | |
| v.insert(iter, k, m) | iter가 가리키는 위치부터 k개의 m값을 삽입한 후 해당 위치를 가리키는 iterator를 반환 |
| (뒤의 원소들은 밀려남.) | |
| v.erase(iter) | iter가 가리키는 원소를 제거한 후 해당 위치를 가리키는 iterator를 반환. capacity는 유지 |
| v.erase(start, end) | start 반복자부터 end 반복자 전까지 [start, end) 원소를 제거한 후 해당 위치를 |
가리키는 iterator를 반환. capacity는 유지 |
|
| v.rbegin() | 마지막 원소를 가리키는 reverse_iterator를 반환 |
| v.rend() | 첫 번째 원소의 앞을 가리키는 reverse_iterator를 반환 |
| v2.swap(v1) | v1 벡터와 v2 벡터를 서로 바꿈 (벡터에 할당된 capacity를 줄이고 싶을 때 사용하기도 함) |
vector 의 size 와 capacity 를 같은 개념으로 받아 들이면 안된다.
size : 원소의 개수capacity : 할당된 공간(메모리)의 크기
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v;
// vector의 원소를 1개씩 증가시킴
for (int i = 0; i < 10; i++)
{
v.push_back(1);
std::cout << "size = " << v.size() << ", capacity = " << v.capacity() << std::endl;
}
return 0;
}
size = 1, capacity = 1
size = 2, capacity = 2
size = 3, capacity = 3
size = 4, capacity = 4
size = 5, capacity = 6
size = 6, capacity = 6
size = 7, capacity = 9
size = 8, capacity = 9
size = 9, capacity = 9
size = 10, capacity = 13
size 는 원소의 개수가 증가할 때마다 1씩 증가하는 반면, capacity는 size 가 capacity 를
초과할 때마다 약 1.5배씩 증가하였다.
vector 에 capacity 가 있는 이유는 vector 의 메모리를 새로 할당할 때 기존 메모리 영역에 이어서
할당하는 것이 아니라 새로운 메모리 영역에 메모리를 할당한 후 기존 원소들을 전부 복사하기 때문이다.
만약, vector 에 push_back 이 일어날 때마다 동적할당을 하게 된다면, 새로이 메모리 영역을 할당하고,
복사하는 비용이 많이 들어 비효율적일 것이다. 따라서 이 과정을 최대한 피하기 위해 미리 정해준 규칙에
따라 capacity 를 증가시키면서 메모리의 여유분을 확보하는 것이다.
vector 의 원소 삽입/삭제 과정을 간략히 하면 다음과 같이 진행된다.


이러한 방식으로 원소 삽입/삭제 과정이 일어나는 이유는 vector 는 원소들을 하나의 메모리 블록에
연속적으로 저장하기 때문이다.
따라서 vector 의 중간 부분에서 삽입/삭제 시에는 뒤쪽 원소들을 복사하기 때문에 비효율적이지만
벡터의 맨 뒷 부분에서 삽입/삭제 시에는 원소를 이동시키는 과정이 필요없어 효율적으로 작동한다.
vector 는 원소를 하나의 메모리 블록에 연속적으로 저장하기 때문에 임의 접근(Random Access) 이
가능하다. 즉, vector 의 n 번째 원소에 접근하기 위해 일일히 처음부터 원소를 세는 것이 아니라 n 번째
원소로 바로 접근할 수 있다.
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v;
std::vector<int>::iterator it;
// [1][2][3][4][5] vector 생성
for (int i = 0; i < 5; i++)
v.push_back(i + 1);
std::cout << "원본 벡터" << std::endl;
for (it = v.begin(); it != v.end(); ++it)
std::cout << (*it) << " ";
// 3번째 원소 v[2] 임의 접근
v[2] = 0;
// 3번째 원소 출력
std::cout << "\\n\\n3번째 원소 v[2] = " << v[2] << std::endl;
std::cout << "\\n임의 접근 후 벡터" << std::endl;
for (it = v.begin(); it != v.end(); ++it)
std::cout << (*it) << " ";
return 0;
}
원본 벡터
1 2 3 4 5
3번째 원소 v[2] = 0
임의 접근 후 벡터
1 2 0 4 5
reserve#include <iostream>
#include <vector>
int main()
{
std::vector<int> v;
// capacity 를 미리 동적할당
v.reserve(5);
std::cout << "capacity : " << v.capacity() << std::endl;
std::cout << "size : " << v.size() << std::endl;
// 원소 추가
std::cout << "\\n원소 추가" << std::endl;
for (int i = 0; i < v.capacity(); i++)
{
v.push_back(i);
std::cout << v[i] << " ";
}
// 공간 늘어 날 때
v.reserve(10);
std::cout << "\\n\\n공간 늘어 날 때" << std::endl;
std::cout << "capacity : " << v.capacity() << std::endl;
std::cout << "size : " << v.size() << std::endl;
for (int i = 0; i < v.size(); i++)
{
std::cout << v[i] << " ";
}
// 공간 줄어 들 때
v.reserve(2);
std::cout << "\\n\\n공간 줄어 들 때" << std::endl;
std::cout << "capacity : " << v.capacity() << std::endl;
std::cout << "size : " << v.size() << std::endl;
for (int i = 0; i < v.size(); i++)
{
std::cout << v[i] << " ";
}
return 0;
}