[STL] vector 벡터 정리 및 예제

2019. 7. 30. 00:24 기타/C++ STL

[STL] vector 벡터 정리 및 예제


vector 컨테이너는 대표적인 시퀀스 컨테이너로 배열과 비슷하여 사용이 쉬우며 자주 사용된다.


vector는 임의 접근 반복자(Random Access Iterator)를 지원하는 배열 기반 컨테이너이다.

vector의 가장 큰 특징 중 하나는 원소가 하나의 메모리 블록에 연속하게 저장된다는 것이다.


그렇다 보니 원소가 추가되거나 삽입될 때 메모리 재할당이 발생할 수 있고 상당한 비용을 지불하게 된다.

그래서 메모리 할당 크기를 알 수 있게 capacity() 함수를 제공하며 한번에 메모리를 할당할 수 있는 reserve() 함수도 제공된다.


원소가 연속하게 저장되므로 [] 연산자 또는 at 으로 읽기에는 빠르지만  insert(), erase(), push_back() 등은 비효율적으로 동작한다.


템플릿 형식

 template<typename T, typename Allocator = allocator<T>>

class vector

T는 vector 컨테이너 원소의 형식 



생성자 

 vector v

v는 빈 컨테이너이다. 

 vector v(n)

v는 기본값으로 초기화된 n개의 원소를 갖는다. 

 vector v(n,x)

v는 x 값으로 초기화된 n개의 원소를 갖는다. 

 vector v(v2)

v는 v2 컨테이너의 복사본이다.(복사 생성자 호출) 

 vector v(b,e)

v는 반복자 구간 [b,e)로 초기화된 원소를 갖는다. 



멤버함수 

 v.assign(n,x)

v에 x 값으로 n개의 원소를 할당한다. 

 v.assign(b,e)

 v를 반복자 구간 [b,e)로 할당한다.

 v.at(i)

v의 i번째 원소를 참조한다. 

 v.back()

v의 마지막 원소를 참조한다. 

 p=v.begin()

p는 v의 첫 원소를 가리키는 반복자 

 x=v.capacity()

x는 v에 할당된 공간의 크기 

 v.clear()

v의 모든 원소를 제거한다. 

 v.empty()

v가 비었는지 조사한다. 

 p=v.end()

p는 v의 끝을 표식하는 반복자 

 p=v.erase(p)

p가 가리키는 원소를 제거한다. q는 다음 원소를 가리킨다. 

 q=v.erase(b,e)

반복자 구간 [b,e)의 모든 원소를 제거한다. q는 다음 원소 

 v.front()

v의 첫 번째 원소를 참조한다. 
 q=v.insert(p,x)

p가 가리키는 위치에 x 값을 삽입한다. q는 삽입한 원소를 가리키는 반복자다. 

 v.insert(p,n,x)

p가 가리키는 위치에 n개의 x 값을 삽입한다. 
 v.insert(p,b,e)

p가 가리키는 위치에 반복자 구간 [b,e)의 원소를 삽입한다. 

 x=v.max_size()

x는 v가 담을 수 있는 최대 원소의 개수(메모리의 크기) 

 v.pop_back()

v의 마지막 원소를 제거한다. 
 v.push_back()v의 끝에 x를 추가한다. 

 p=v.rbegin()

p는 v의 역 순차열의 첫 원소를 가리키는 반복자다. 
 p=v.rend()

p는 v의 역 순차열의 끝을 표식하는 반복자 

 v.reserve(n)n개의 원소를 저장할 공간을 예약한다. 

 v.resize(n)

v의 크기를 n으로 변경하고 확장되는 공간의 값을 기본값으로 초기화 한다. 

 v.resize(n,x)

v의 크기를 n으로 변경하고 확장되는 공간의 값을 x 값으로 초기화한다. 
 v.size()v의 원소 갯수 

 v.swap(v2)

v와 v2를 swap한다. 



연산자 

 v1==v2

v1과 v2의 모든 원소가 같은가? (bool) 

 v1!=v2

v1과 v2의 모든 원소 중 하나라도 다른 원소가 있는가? 

 v1<v2

문자열 비교처럼 v2가 v1보다 큰가? 

 v1>v2

문자열 비교처럼 v1이 v2보다 큰가? 

 v[i]

v의 i번째 원소를 참조한다. 



멤버 형식 

 allocator_type

 메모리 관리자 형식 

 const_iterator

 const 반복자 형식 

 const_pointer

 const value_type* 형식 

 const_reference

 const value_type& 형식 

 const_reverse_iterator

 const 역 반복자 형식 

 difference_type

 두 반복자 차이의 형식 

 iterator

 반복자 형식 

 pointer

 value_type* 형식 

 reference

 value_type& 형식 

 reverse_iterator

 역 반복자 형식 

 size_type 첨자(index)나 원소의 개수 등의 형식 

 value_type

 원소의 형식 


시퀀스 컨테이너는 차례차례 원소를 추가하고 제거하는 push_back()과 pop_back()을 가지며, 첫 원소와 마짐가 원소를 참조하는 front()와 back()을 가진다. 또한, 지정한 위치에 원소를 삽입할 수 있는 insert()를 가진다.


vector는 앞쪽이 막혀 있는 형태로 앞쪽에는 원소를 추가/제거할 수 없으며 뒤쪽에만 추가/제거할 수 있다.


* vector 사용 예제 1


#include <iostream>
#include <vector>
using namespace std;

int main(){

    vector<int> v;
    v.reserve(8);        // 벡터 메모리 공간 8 예약 할당

    v.push_back(10);
    v.push_back(20);
    v.push_back(30);
    v.push_back(40);
    v.push_back(50);

    for (vector<int>::size_type i = 0; i < v.size(); ++i)
        cout << v[i] << endl;
    cout << endl;

    cout << "size : " << v.size()                // 벡터 원소 개수
        << " capacity : " << v.capacity()            // 벡터의 할당된 메모리의 크기
        << "  max_size : " << v.max_size() << endl;    // 최대 저장 가능한 원소 개수


    cout << endl << "-- resize(10) -- " << endl;
    
    v.resize(10);            // 벡터의 원소 갯수를 10개로 확장, 추가된 공간은 디폴트 0으로 채워진다.
    
    for (vector<int>::size_type i = 0; i < v.size(); ++i)   // 벡터의 size 타입으로 i를 지정한다 (unsigned int) 
        cout << v[i] << endl;
    cout << endl;

    cout << "size : " << v.size()
        << " capacity : " << v.capacity()
        << "  max_size : " << v.max_size() << endl;


    cout << endl << "-- resize(3) -- " << endl;

    v.resize(3);            // 벡터의 원소 갯수를 3개로 축소, capacity는 변화 없다.

    for (vector<int>::size_type i = 0; i < v.size(); ++i)
        cout << v[i] << endl;
    cout << endl;

    cout << "size : " << v.size()                
        << " capacity : " << v.capacity()            
        << "  max_size : " << v.max_size() << endl;


    cout << endl << "-- vector clear() -- " << endl;

    v.clear();    // 벡터 비운다    capacity(메모리) 는 그대로 남아있다.

    if (v.empty()){    // 벡터에 원소가 없는지 확인한다.
        cout << "벡터에 원소가 없다." << endl;
    }

    cout << "size : " << v.size()
        << " capacity : " << v.capacity()
        << "  max_size : " << v.max_size() << endl;

    return 0;
}


결과 :

10

20

30

40

50


size : 5 capacity : 8 max_size : 1073741823


-- resize<10> --

10

20

30

40

50

0

0

0

0

0


size : 10 capacity : 12 max_size : 1073741823


-- resize<3> --

10

20

30


size : 3 capacity : 12 max_size : 1073741823

벡터에 원소가 없다.

size : 0 capacity : 12 max_size : 1073741823


- v.reserve(8) : 벡터의 메모리 공간(capacity) 을 미리 할당한다. * 추가할당이 아님

- vector<int>::size_type : 벡터의 size 의 반환 타입을 가져온다 (unsigned int)

- v.resize(10) : 벡터의 원소 갯수를 수정한다. (size 를 줄여도 capacity는 그대로다)

- v.clear() : 벡터를 비운다 (capacity 크기는 그대로다)

- v.empty() : 벡터가 비워져 있는지 확인한다.


* for문으로 vector를 탐색할 때, v.size() 만큼 i를 돌리려면, v.size()의 타입과 i 가 같아야 한다.


* v.capacity()는 벡터에 할당된 메모리 공간이다.

새로운 원소가 벡터에 추가되면 메모리 공간이 추가적으로 할당된다.

매번 새로운 원소가 들어올 때마다 새로운 메모리가 할당되는 것은 비효율적이다.

capacity가 모자랄 경우 capacity/2 만큼의 capacity를 늘려간다.

만약 입력될 원소의 갯수를 알 수 있다면 reserve 를 사용하여 미리 capapcity 메모리를 할당해 놓으면 효율적이다.


* v.clear()를 사용하면 벡터의 원소를 비운다.

하지만 capacity는 그대로 남아 있다. 비어있는 벡터인데 메모리를 할당하고 있는 것은 아깝다.

이럴경우 clear()를 사용하기 보다 . 임시 벡터와 swap 을 통해 교환하면 메모리까지 해제할 수 있다.


#include <iostream>
#include <vector>
using namespace std;

int main(){

    vector<int> v(5);    // 0으로 초기화된 5개의 원소
    cout << "size : " << v.size() << " capacity : " << v.capacity() << endl;

    vector<int>().swap(v);        // 임의 벡터와 교환한다.
    cout << "size : " << v.size() << " capacity : " << v.capacity() << endl;

    vector<int> v1;
    v1.push_back(10);
    v1.push_back(20);
    v1.push_back(30);
    v1.push_back(40);
    v1.push_back(50);

    cout << v1[0] << ", " << v1.at(0) << ", " << v1.front() << endl; // 첫번째 원소
    cout << v1[4] << ", " << v1.at(4) << ", " << v1.back() << endl; //  마지막 원소

    v1.front() = 100;
    v1.back() = 500;

    cout << v1[0] << ", " << v1.at(0) << ", "<< v1.front() << endl; // 첫번째 원소
    cout << v1[4] << ", " << v1.at(4) << ", " << v1.back() << endl; //  마지막 원소

    try{

        cout << v.at(10) << endl;        // 범위를 벋어난 호출 throw out_of_range 예외
    
    } catch (out_of_range &e){
        cout << e.what() << endl;
    }

    return 0;
}




결과 :

size : 5 capacity : 5

size : 0 capacity : 0

10, 10, 10

50, 50, 50

100, 100, 100

500, 500, 500

invalid vector<T> subscript 



* vector<int>().swap(v); : 임의 벡터와 swap을 하면서 벡터를 비우고 할당된 메모리(capacity)까지 해제한다.


* v.front()는 벡터의 첫번째 요소를 반환하고 v.back()는 마지막 요소를 반환한다.


* 벡터의 임의 요소에 접근하는 방법으로는 [] 연산자와 at 멤버함수가 있다.

[] 연산자를 사용하면 접근이 빠르지만 범위 점검을 하지 않는다.

at() 멤버 함수를 사용하여 접근하면 범위 점검을 수행하며, 범위에 벗어난 요소에 접근하면 out_of_range 예외를 throw 하여 예외를 처리할 수 있다.



출처: https://hyeonstorage.tistory.com/324?category=614599 [개발이 하고 싶어요]

'기타 > C++ STL' 카테고리의 다른 글

[STL] multiset 정리 및 예제  (0) 2019.07.30
[STL] set 정리 및 예제  (0) 2019.07.30
[STL] list 정리 및 예제  (0) 2019.07.30
[STL] deque 정리 및 예제  (0) 2019.07.30
[STL] not2 함수  (0) 2019.07.30
[STL] 역방향 반복자 (reverse_iterator)  (1) 2019.07.30
[STL] 스택(stack) 기본 예제  (0) 2019.07.30
[STL] sort() 정렬 예제  (0) 2019.07.30