[ 시퀀스 컨테이너 ]

 

시퀀스 컨테이너느 저장 원소가 삽입 순서에 따라 상대적인 위치(순서)를 갖는 컨테이너 vector, list, deque 입니다. 





vector는 시퀀스 컨테이너이므로 원소의 저장 위치(순서)가  정해지며 배열 기반 컨테이너이므로 원소가 하나의

메모리 블록에 할당됩니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
#include <vector>
using namespace std;
 
int main( )
    vector<int> v; 
 
    v.push_back(10); 
    v.push_back(20);
    v.push_back(30);
    v.push_back(40);
    v.push_back(50);
 
    /** 
    /* size_type은 원소의 개수나 [] 연산자 등의 index로 사용하는 형식
    /* 이왕이면 컴파일러의 경고 타입을 없애고 보기좋은 코드 작성
    */
    for(vector<int>::size_type i = 0 ; i < v.size() ; ++i)
        cout << v[i] << endl;   
 
    cout << typeid(vector<int>::size_type).name() << endl;    
    
    system("pause");
    return 0;
}

 

 

위의 예제에서 사용되었던 typeid(T)는 T에 대한 typeinfo 객체를 리턴 해줍니다.

 

vector는 크기를 반환하는 세 멤버함수 size(), capacity(), max_size()를 가집니다.

 

size() : 저장 원소의 개수

capacity() : 실제 할당된 메모리 공간의 크기 ( vector만 가지는 멤버함수 )

max_size() : 컨테이너가 담을 수 있는 최대 원소의 개수

 

※ 중요 ※

vector는 원소가 하나의 메모리 블록에 연속(배열 기반 컨테이너)으로 저장 됩니다.

원소가 추가될 때마다 메모리를 재할당하고 이전원소를 모두 복사해야 한다면 너무나 비효율적입니다.

 

이떄 조금이나마 재할당에 드는 성능 문제를 보완 하고자 만들어진 개념이 capacity 입니다.

원소가 추가될 때마다 메모리를 재할당하지 않고 미리 넉넉한 메모리를 확보하면 재할당과 이전 원소를 복사하는 데 드는 비용을 줄일 수 있습니다. 이것은 컨테이너 중 vector만이 가지고 있는 중요한 특징 입니다.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include <iostream>
#include <vector>
using namespace std;
 
int main( )
    vector<int> v; 
    vector<int> v_reserve;
 
    cout <<"size: "<< v.size() <<"  capacity: " << v.capacity() <<endl; // 0, 0
    v.push_back(10); // 메모리 재할당과 원소 복사 ( capacity + 이전 capacity / 2 )
    cout <<"size: "<< v.size() <<"  capacity: " << v.capacity() <<endl; // 1, 1
    v.push_back(20); // 메모리 재할당과 원소 복사 ( capacity + 이전 capacity / 2 )
    cout <<"size: "<< v.size() <<"  capacity: " << v.capacity() <<endl; // 2, 2
    v.push_back(30); // 메모리 재할당과 원소 복사 ( capacity + 이전 capacity / 2 )
    cout <<"size: "<< v.size() <<"  capacity: " << v.capacity() <<endl; // 3, 3
    v.push_back(40); // 메모리 재할당과 원소 복사 ( capacity + 이전 capacity / 2 )
    cout <<"size: "<< v.size() <<"  capacity: " << v.capacity() <<endl; // 4, 4                                             
    v.push_back(50); // 메모리 재할당과 원소 복사 ( capacity + 이전 capacity / 2 )
    cout <<"size: "<< v.size() <<"  capacity: " << v.capacity() <<endl; // 5, 6
    v.push_back(60);
    cout <<"size: "<< v.size() <<"  capacity: " << v.capacity() <<endl; // 6, 6 
    v.push_back(70); // 메모리 재할당과 원소 복사 ( capacity + 이전 capacity / 2 )
    cout <<"size: "<< v.size() <<"  capacity: " << v.capacity() <<endl; // 7, 9
    v.push_back(80);
    cout <<"size: "<< v.size() <<"  capacity: " << v.capacity() <<endl; // 8, 9
    v.push_back(90);
    cout <<"size: "<< v.size() <<"  capacity: " << v.capacity() <<endl; // 9, 9
 
    for(vector<int>::size_type i = 0 ; i < v.size() ; ++i)
        cout << v[i] << " ";   
    cout << endl;
    cout << endl;
 
    // reserve 함수 사용
    v_reserve.reserve(8);
    cout <<"size: "<< v_reserve.size() <<"  capacity: " << v_reserve.capacity() <<endl; // 0, 8
    v_reserve.push_back(10); 
    cout <<"size: "<< v_reserve.size() <<"  capacity: " << v_reserve.capacity() <<endl; // 1, 8
    v_reserve.push_back(20); 
    cout <<"size: "<< v_reserve.size() <<"  capacity: " << v_reserve.capacity() <<endl; // 2, 8
    v_reserve.push_back(30); 
    cout <<"size: "<< v_reserve.size() <<"  capacity: " << v_reserve.capacity() <<endl; // 3, 8
    v_reserve.push_back(40); 
    cout <<"size: "<< v_reserve.size() <<"  capacity: " << v_reserve.capacity() <<endl; // 4, 8                                             
    v_reserve.push_back(50); 
    cout <<"size: "<< v_reserve.size() <<"  capacity: " << v_reserve.capacity() <<endl; // 5, 8
    v_reserve.push_back(60);
    cout <<"size: "<< v_reserve.size() <<"  capacity: " << v_reserve.capacity() <<endl; // 6, 8 
    v_reserve.push_back(70); 
    cout <<"size: "<< v_reserve.size() <<"  capacity: " << v_reserve.capacity() <<endl; // 7, 8
    v_reserve.push_back(80);
    cout <<"size: "<< v_reserve.size() <<"  capacity: " << v_reserve.capacity() <<endl; // 8, 8
    v_reserve.push_back(90);// 메모리 재할당과 원소 복사 ( capacity + 이전 capacity / 2 )
    cout <<"size: "<< v_reserve.size() <<"  capacity: " << v_reserve.capacity() <<endl; // 9, 12
 
    for(vector<int>::size_type i = 0 ; i < v_reserve.size() ; ++i)
        cout << v_reserve[i] << " ";   
    cout << endl;
 
    system("pause");    
    return 0;
}

 

위의 예제에서 보면 vector는

 

1. 미리저장할 메모리의 크기(capacity)를 크게 하면 원소가 추가돼도 메모리의 크기가 변하지 않게 됩니다.

2. 원소를 추가하려 할때 메모리의 크기(capacity)가 원소의 개수(size)보다 크지 않다면 메모리 재할당을 수행하게 됩니다.( 같다면 )

 

결국 vector는 이러한 메모리 재할당과 이전 원소 복사 문제가 발생할 수 있습니다. 그래서 vector는 미리 메모리를 할당할 수 있는 메모리 예약 함수 reserve()를 제공합니다. reserve()를 사용하면 미리 메모리를 할당해 capacity를 결정하고 vector에 원소가 추가되더라도 메모리를 재할당 하지 않습니다.

 

 

[ vector 생성자 사이즈 변경및 초기화 ]

1
2
3
4
5
// 기본값 0으로 초기화된 size가 5인 컨테이너
    vector<int> v1(5);        // 0,0,0,0,0    
    // 기본값 10으로 초기화된 size가 5인 컨테이너
    vector<int> v2(5,10);    // 10,10,10,10,10
 

 

[ vector resize함수 사용, 사이즈변경및 초기화 ]

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    vector<int> v3(5); // 이 선언으로 0,0,0,0,0 원소가 있다.
    // 원소가 있으므로, push_back하지 않고 변경해준다.
    v3[0] = 10; 
    v3[1] = 20;
    v3[2] = 30;
    v3[3] = 40;
    v3[4] = 50;    
 
    // resize함수로 초기값이 0인 size가 10인 컨테이너 생성
    v3.resize(10);// 10,20,30,40,50,0,0,0,0,0
 
    // 사이즈는 줄었지만, capacity는 변경없음( size : 5,  capacity : 10 )
    v3.resize(5); // 10,20,30,40,50    
    // resize(10, 100 ) : size를 10으로 확장하고 추가되는 원소를 100으로 초기화

 

[ vector의 clear()함수와 empty() 함수 ]

 

1
2
3
4
5
6
7
8
9
10
11
    v3.clear(); // size : 0 capacity : 5
    // ※clear한다고 해서 메모리(capacity)가 제거되지 않음
    if( v3.empty() ){
        cout<<"비었다"<<endl;
    }
 
    /**
    * 메모리(capacity)를 완전히 제거하는방법
    */    
    //임시객체 기본생성자로 만든vector컨테어나와 v3 swap한다
    vector<int>().swap(v3); // size : 0, capacity : 0

 

[ swap함수를 이용하여 원소교환 ]

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
vector<int> v4;
    v4.push_back(10);
    v4.push_back(20);
    v4.push_back(30);
    vector<int> v5;
    v5.push_back(100);
    v5.push_back(200);
    v5.push_back(300);
    v4.swap(v5);
 
    //v4의 원소들과 v5원소들이 교환됨
    for(vector<int>::size_type i = 0; i < v4.size(); ++i){
        cout<< v4[i] << "," << v5[i] <<endl;
    }
    cout<<endl;



[ front(), back() 함수 ]

 

1
2
3
4
5
6
7
8
9
10
cout<< v4[0] << "," << v4.front() <<endl; // v4[0]은 v4.at(0)과 같음
    cout<< v4[2] << "," << v4.back() <<endl;
 
    // 원소 수정    
    v4.front() = 10;    
    v4.at(1)   = 20;
    v4.back()  = 30;    
    cout<< v4[0] << "," << v4.front() <<endl;
    cout<< v4[1] << "," << v4.at(1) <<endl;
    cout<< v4[2] << "," << v4.back() <<endl;

 

 

vector와 deque은 일반 배열처럼 임의 취치의 원소를 참조하는 두 인터페이스르 제공합니다.

 

[] 연산자 :  범위 점검을 하지 않아 속도가 빠르며

at(index) 멤버함수 : 범위 점검을 해서 안전함, 범위가 넘어가면 out_of_range 예외 발생

 

 

[ assign() 멤버 함수 ]

 

1
2
    vector<int> v6(5, 1); // 초기값1인 5개의 원소를 갖는 컨테이너 생성
    v6.assign(5, 10); // 5개의 원소값을 2로 할당(n개의 원소에 x의값을 할당합니다.)

 

 

[ begin(), end() 멤버 함수, 상수 반복자 ]

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    vector<int>::iterator Iter;
    vector<int>::const_iterator const_Iter;
 
    for( Iter = v6.begin(); Iter != v6.end(); ++Iter ){
        cout<< *Iter << endl;
    }
    cout<<endl;
 
    const_Iter = Iter = v6.begin();
    cout<< *(++Iter) <<endl;
    cout<< *(++const_Iter) <<endl;
 
    *Iter = 40;
//    *const_Iter = 50; 상수반복자는 원소변경 못함( const int* )

 

 

[ const키워드와 반복자 ]

 

1
2
3
4
vector<int>::iterator Iter; //다음원소 이동가능, 원소변경 가능
vector<int>::const_iterator const_Iter;//다음원소 이동가능, 원소변경 불가능
const vector<int>::iterator Iter_const;//다음원소 이동불가능, 원소변경 가능
const vector<int>::const_iterator const_Iter_const; //둘다 불가능
 

반대로 동작하는 역방향 반복자( reverse_Iterator )

reverse_iterator는 vector에 반복자 어댑터로 typedef되어 있습니다.

 

 

[ insert() 멤버함수 ]

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    vector<int>::iterator Iter_v6 = v6.begin()+2; //10,20,30,40,50에서 30을 가르킴    
 
    // Iter_v6가 가르키는 위치에 100을 삽입하고 삽입한 100의 위치를 가르키는 반복자
    // 를 리턴하여 Iter_insertPos에 대입한다.
    vector<int>::iterator Iter_InsertPos = v6.insert(Iter_v6, 100);
    
 
    // Iter_InsertPos가 가리키는 위치에 정수 200을 3개 삽입
    v6.insert(Iter_InsertPos, 3, 200 );
 
 
    // Iter_InsertPos가 가리키는 위치에 v4의 구간 [b,e)의 원소 삽입
    vector<int> v7;
    v7.push_back(100);
    v7.push_back(200);
    v7.push_back(300);
    Iter_v6 = v6.begin(); //10을 가르킴
    v6.insert(Iter_v6, v7.begin(), v7.end() );
    
    for( Iter_v6 = v6.begin(); Iter_v6 != v6.end(); ++Iter_v6 ) {
        cout<< *Iter_v6 <<endl;
    }

 

[ erase() 멤버함수 ]

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <iostream>
#include <vector>
 
using namespace std;
 
int main(){
    
    /**
    * erase() 멤버함수
    */
 
    vector<int> v;
    v.push_back(10);
    v.push_back(20);
    v.push_back(30);
    v.push_back(40);
    v.push_back(50);
 
    vector<int>::const_iterator Iter = v.begin()+1;
    //Iter가 가르키는 위치의 원소 20 을 제거합니다. 제거된 원소의 다음원소를 리턴
    //리턴된 반복자를 erase_Iter에 대입합니다. 30
    vector<int>::const_iterator erase_Iter = v.erase( Iter );
 
    for( Iter = v.begin(); Iter != v.end(); ++Iter ){
        cout<< *Iter << endl;
    }
    cout<<endl;
    cout<<"제거후 리턴된 반복자가 가르키는 값 : "<< *erase_Iter <<endl;
    cout<<endl;
 
    // 구간 [b,e) 사이의 모든 원소를 지운다. 10만 남겨놓고 30,40,50 지움
    // erase()멤버함수에서 리턴되는 반복자는 NULL을 가르키게된다.v.end()
    v.erase(v.begin()+1, v.end());
    for( Iter = v.begin(); Iter != v.end(); ++Iter ){
        cout<< *Iter << endl;
    }    
 
    system("pause");
    return 0;
}

 

[ 반복자로 동작하는 생성자와 assign() 멤버함수 ]

 

1
2
3
vector<int> v2(v.begin(), v.end()); // 순차열[b,e) 생성자로 초기화
vector<int> v3;
v3.assign(v2.begin(), v2.end()); //순차열 [b,e) v3에 할당

 

vector의 생성자는 반복자를 통해서 초기화될 수 있으며 assign() 멤버 함수도 반복자를 통해 할당될 수 있습니다.

 

 

[ vector와 vector의 비교 컨테이너 연산자 ]

 

컨테이너 연산자 : ==, !=, <, <=, >, >=

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>
#include <vector>
using namespace std;
 
int main(){
 
    vector<int> v1;
    v1.push_back(10);
    v1.push_back(20);
    v1.push_back(30);
    v1.push_back(40);
    v1.push_back(50);
    vector<int> v2;
    v2.push_back(10);
    v2.push_back(20);
    v2.push_back(50);
 
    if( v1 == v2 ){ //모든원소가 같다면
        cout<<"v1 == v2"<<endl;
    }
    if( v1 != v2 ){ //모든원소가 같지 않다면
        cout<<"v1 != v2"<<endl;
    }
 
    // 순차열의 원소를 하나씩 순서대로 비교하여
    // v2의 원소가 크다면 참 아니면 거짓
    // 10 == 10, 20 == 20, 30 < 50 여기서 v2가 큼
    if( v1 < v2 ){ 
        cout<<"v1 < v2"<<endl;
    }
 
    system("pause");
    return 0;
}


+ Recent posts