공부/C++

C++ Vector Container 정리

상연 2020. 11. 1. 18:02

목차

    cplusplus 사이트 Reference를 참고하며 공부해봤습니다.

    틀린 내용이 있다면 댓글로 지적 부탁드립니다.


    Vector

    • 벡터는 크기가 변할 수 잇는 배열을 나타내는 'Sequence Container'이다.

      순차 컨테이너란? 원소가 들어오는 대로 저장한다는 의미, 별도의 정렬없이 들어오는 순서대로 저장된다.

    • 벡터는 배열과 마찬가지로 요소에도 연속적인 저장 위치를 사용한다.

      이는 해당 요소의 포인터의 오프셋을 사용하여 배열과 마찬가지로 효율적으로 요소에 접근할 수 있다.
      하지만, 선언하면서 저장공간을 정해줘야하는 배열과는 다르게 벡터는 동적으로 변경할 수 있다.

    • 내부적으로 벡터는 동적으로 할당된 어레이를 사용하여 요소를 저장한다.

      즉, 새 요소를 삽입할 때 크기가 커지기 위해 이 배열을 재할당해야 할 수도 있다.
      이는 새 배열을 할당하고 모든 요소를 새 배열에 이동해야 함을 의미한다. 하지만 이는 처리 시간의 측면에서 많은 비용이 들기 때문에 벡터는 하나의 요소가 추가 될 때마다 재 할당하지는 않는다.

    • 대신 여분의 저장공간을 미리 할당한다.

      따라서 벡터는 요소를 포함하는데 필요한 저장공간보다 실제 용량이 더 클 수 있다.

    즉, 배열에 비해 벡터는 저장공간을 관리하고, 효율적으로 동적으로 확장할 수 잇는 대신 좀 더 많은 메모리를 소비한다.

    다만, 다른 동적 순차 컨테이너(Deque, lists...) 에 비하면 벡터는 요소에 접근하는 것, 맨 앞과 뒤에 요소를 추가할 수 있는 점이 효율적이다. 대신에 요소 중간에 요소를 삽입하거나 제거하는 작업에서는 성능이 나쁜 편이다.

    Vector 속성

    1. Sequence (순차)
    2. Dyanamic Array (동적배열)
    3. Allocator-aware (할당자 인식)

    생산자

    1. vector<자료형> v;
      비어있는 vector v 생성

    2. vector<자료형> v(5);
      자료형의 기본값으로 초기화 된 5개의 원소를 가지는 vector v 생성

    3. vector<자료형> v(5, 지정값);
      지정값으로 초기화 된 5개의 원소를 가지는 vector v를 생성합니다.

    4. vector<자료형> v(iter1, iter2);
      iter1 ~ iter2 까지의 범위의 요소를 할당한 vector v를 생성합니다.

    5. vector<자료형> v(v2);
      같은 자료형인 v2의 요소를 복사하여 가진 vector v1를 생성합니다.

    반복자

    반복자를 통해 내부에 있는 데이터의 한 위치를 가리킬 수 있다.

    이름 설명
    begin 컨테이너의 시작 요소를 가리키는 반복자를 반환한다.
    end 컨테이너의 시작 요소를 가리키는 반복자를 반환한다.
    cbegin begin과 같지만, 반복자가 가리키는 대상을 수정할 수 없습니다.
    cend end와 같지만, 반복자가 가리키는 대상을 수정할 수 없습니다.
    vector<int>::iterator iter=v.begin();

    만일 이렇게 iter에 벡터 v의 시작점을 저장했다고 하자.

    1. 전/후위 연산자

    ++iter 혹은 iter-- 등을 활용하여 반복자가 다음/이전 원소를 가리키도록 이동시킬 수 있다.

    1. *iter
      iter가 가리키는 요소(객체)를 반환한다.

    2. iter[n]
      iter + n 번째 요소(객체)를 반환한다.

    3. iter += n
      현재 iter위치에서 n개 뒤의 요소를 반환한다.

    용량(?) Capacity

    1. v.size()
      컨테이너의 크기를 반환한다.(int 형)

    2. v.max_size()
      컨테이너가 가질 수 있는 가장 큰 수를 반환한다.(unsigned_int 형)

    3. v.resize()
      컨테이너 요소를 재조정한다.

    / resizing vector
    #include <iostream>
    #include <vector>
    
    int main ()
    {
      std::vector<int> myvector;
    
      // set some initial content:
      for (int i=1;i<10;i++) myvector.push_back(i);
    
      myvector.resize(5);
      myvector.resize(8,100);
      myvector.resize(12);
    
      std::cout << "myvector contains:";
      for (int i=0;i<myvector.size();i++)
        std::cout << ' ' << myvector[i];
      std::cout << '\n';
    
      return 0;
    }

    출력

    myvector contains: 1 2 3 4 5 100 100 100 0 0 0 0

    초기 벡터가

    1 2 3 4 5 6 7 8 9 로 초기화

    resize(5)로 인해

    1 2 3 4 5 로 조정

    resize(8, 100)로 인해

    1 2 3 4 5 100 100 100 조정

    resize(12)로 인해

    1 2 3 4 5 100 100 100 0 0 0 0 으로 조정된 것이다.

    1. v.capacity()
      앞에서, 벡터는 미리 어느정도 용량을 확보한 상태로 동적배열을 운용한다고 했다.
      그렇다면 그 어느정도 확보한다는 기준은 어떻게 되는 것인가??

    답은, 새로운 요소가 들어갈 공간이 없을때마다, 현재 저장공간의 2배로 공간을 늘리는 것이다.
    이는 이 capacity 함수를 통해 알 수 있는데

    #include <iostream>
    #include <vector>
    using namespace std;
    
    int main() {
        vector <int> v;
    
        for(int i=0; i<100; i++){
            v.push_back(i);
            cout << i << "번째 Vector Size : " << v.size() << " Vector Capacity " << v.capacity() << endl;
        }
    }

    출력

    0번째 Vector Size : 1 Vector Capacity 1
    1번째 Vector Size : 2 Vector Capacity 2
    2번째 Vector Size : 3 Vector Capacity 4
    3번째 Vector Size : 4 Vector Capacity 4
    4번째 Vector Size : 5 Vector Capacity 8
    5번째 Vector Size : 6 Vector Capacity 8
    6번째 Vector Size : 7 Vector Capacity 8
    7번째 Vector Size : 8 Vector Capacity 8
    8번째 Vector Size : 9 Vector Capacity 16
    9번째 Vector Size : 10 Vector Capacity 16
    10번째 Vector Size : 11 Vector Capacity 16
    11번째 Vector Size : 12 Vector Capacity 16
    12번째 Vector Size : 13 Vector Capacity 16
    13번째 Vector Size : 14 Vector Capacity 16
    14번째 Vector Size : 15 Vector Capacity 16
    15번째 Vector Size : 16 Vector Capacity 16
    16번째 Vector Size : 17 Vector Capacity 32
    17번째 Vector Size : 18 Vector Capacity 32
    18번째 Vector Size : 19 Vector Capacity 32
    19번째 Vector Size : 20 Vector Capacity 32
    20번째 Vector Size : 21 Vector Capacity 32
    21번째 Vector Size : 22 Vector Capacity 32
    22번째 Vector Size : 23 Vector Capacity 32
    23번째 Vector Size : 24 Vector Capacity 32
    24번째 Vector Size : 25 Vector Capacity 32
    25번째 Vector Size : 26 Vector Capacity 32
    26번째 Vector Size : 27 Vector Capacity 32
    27번째 Vector Size : 28 Vector Capacity 32
    28번째 Vector Size : 29 Vector Capacity 32
    29번째 Vector Size : 30 Vector Capacity 32
    30번째 Vector Size : 31 Vector Capacity 32
    31번째 Vector Size : 32 Vector Capacity 32
    32번째 Vector Size : 33 Vector Capacity 64
    33번째 Vector Size : 34 Vector Capacity 64
    34번째 Vector Size : 35 Vector Capacity 64
    35번째 Vector Size : 36 Vector Capacity 64
    36번째 Vector Size : 37 Vector Capacity 64
    37번째 Vector Size : 38 Vector Capacity 64
    38번째 Vector Size : 39 Vector Capacity 64
    39번째 Vector Size : 40 Vector Capacity 64
    40번째 Vector Size : 41 Vector Capacity 64
    41번째 Vector Size : 42 Vector Capacity 64
    42번째 Vector Size : 43 Vector Capacity 64
    43번째 Vector Size : 44 Vector Capacity 64
    44번째 Vector Size : 45 Vector Capacity 64
    45번째 Vector Size : 46 Vector Capacity 64
    46번째 Vector Size : 47 Vector Capacity 64
    47번째 Vector Size : 48 Vector Capacity 64
    48번째 Vector Size : 49 Vector Capacity 64
    49번째 Vector Size : 50 Vector Capacity 64
    50번째 Vector Size : 51 Vector Capacity 64
    51번째 Vector Size : 52 Vector Capacity 64
    52번째 Vector Size : 53 Vector Capacity 64
    53번째 Vector Size : 54 Vector Capacity 64
    54번째 Vector Size : 55 Vector Capacity 64
    55번째 Vector Size : 56 Vector Capacity 64
    56번째 Vector Size : 57 Vector Capacity 64
    57번째 Vector Size : 58 Vector Capacity 64
    58번째 Vector Size : 59 Vector Capacity 64
    59번째 Vector Size : 60 Vector Capacity 64
    60번째 Vector Size : 61 Vector Capacity 64
    61번째 Vector Size : 62 Vector Capacity 64
    62번째 Vector Size : 63 Vector Capacity 64
    63번째 Vector Size : 64 Vector Capacity 64
    64번째 Vector Size : 65 Vector Capacity 128
    65번째 Vector Size : 66 Vector Capacity 128
    66번째 Vector Size : 67 Vector Capacity 128
    67번째 Vector Size : 68 Vector Capacity 128
    68번째 Vector Size : 69 Vector Capacity 128
    69번째 Vector Size : 70 Vector Capacity 128
    70번째 Vector Size : 71 Vector Capacity 128
    71번째 Vector Size : 72 Vector Capacity 128
    72번째 Vector Size : 73 Vector Capacity 128
    73번째 Vector Size : 74 Vector Capacity 128
    74번째 Vector Size : 75 Vector Capacity 128
    75번째 Vector Size : 76 Vector Capacity 128
    76번째 Vector Size : 77 Vector Capacity 128
    77번째 Vector Size : 78 Vector Capacity 128
    78번째 Vector Size : 79 Vector Capacity 128
    79번째 Vector Size : 80 Vector Capacity 128
    80번째 Vector Size : 81 Vector Capacity 128
    81번째 Vector Size : 82 Vector Capacity 128
    82번째 Vector Size : 83 Vector Capacity 128
    83번째 Vector Size : 84 Vector Capacity 128
    84번째 Vector Size : 85 Vector Capacity 128
    85번째 Vector Size : 86 Vector Capacity 128
    86번째 Vector Size : 87 Vector Capacity 128
    87번째 Vector Size : 88 Vector Capacity 128
    88번째 Vector Size : 89 Vector Capacity 128
    89번째 Vector Size : 90 Vector Capacity 128
    90번째 Vector Size : 91 Vector Capacity 128
    91번째 Vector Size : 92 Vector Capacity 128
    92번째 Vector Size : 93 Vector Capacity 128
    93번째 Vector Size : 94 Vector Capacity 128
    94번째 Vector Size : 95 Vector Capacity 128
    95번째 Vector Size : 96 Vector Capacity 128
    96번째 Vector Size : 97 Vector Capacity 128
    97번째 Vector Size : 98 Vector Capacity 128
    98번째 Vector Size : 99 Vector Capacity 128
    99번째 Vector Size : 100 Vector Capacity 128

    1. v.empty()
      해당 컨테이너가 비어있는지 아닌지 판단하여 bool형태의 자료형을 반환한다.
      비었으면 True, 비지 않았다면 False

    2. v.reverse()
      해당 컨테이너가 저장된 순서의 반대로 저장한다.

    1. v.shrink_to_fit (C++ 11 이상)
      이건 예제 코드를 보고 이해하는 것이 빠를 것 같다.
    // vector::shrink_to_fit
    #include <iostream>
    #include <vector>
    
    int main ()
    {
      std::vector<int> myvector (100);
      std::cout << "1. capacity of myvector: " << myvector.capacity() << '\n';
    
      myvector.resize(10);
      std::cout << "2. capacity of myvector: " << myvector.capacity() << '\n';
    
      myvector.shrink_to_fit();
      std::cout << "3. capacity of myvector: " << myvector.capacity() << '\n';
    
      return 0;
    }

    이를 보면 처음 벡터는 100의 크기로 초기화 되어있었다.
    하지만 10으로 resize 되면서 11~100까지의 요소는 사라졌는데, 그럼에도 할당된 용량은 100으로 그대로여서
    대략 90의 용량이 낭비되어 있다는 것이다.

    따라서 shrink_to_fit 을 해 주면
    현재 사용하고 있는 요소에 맞춰 할당 용량을 맞춰준다고 보면 될 것 같다.

    요소 접근자

    1. operator[]
      벡터 컨테이너의 위치 n에 있는 요소를 반환한다.
      ex) v[3] -> v 컨테이너의 4번째 요소 반환 (요소의 index는 0부터 시작함)

    2. at()
      operator[]와 유사한 기능을 수행한다.
      다만, 컨테이너의 범위를 점검하기 때문에 operator보다 안정성이 있다.

    Vector at vs operator[]

    1. front(), back()
      이름 그대로 컨테이너의 첫번째, 마지막 요소를 반환한다.

    수정자

    1. assign
      컨테이너에 새로운 내용을 넣는다. 이전에 있던 요소는 전부 사라지고 새로운 내용이 들어간다.
    #include <iostream>
    #include <vector>
    using namespace std;
    
    int main() {
        vector<int> v1(8, 2); // v1 = {2, 2, 2, 2, 2, 2, 2, 2}
    
        cout << " v1 : ";
        for(int i=0; i<v1.size(); i++){
            cout << v1[i];
        }
        cout << endl;
    
        cout << "v1의 capacity : " << v1.capacity() << endl;
    
        //assign의 첫 번째 방법 
        //첫번째 인자에 요소의 개수, 두번째 인자에 요소값
        //두번째인자의 값을 첫번째 인자의 개수만큼 채워넣는다.
    
        v1.assign(3, 2); // v1 = {2, 2, 2}
    
        cout << " v1 : ";
        for(int i=0; i<v1.size(); i++){
            cout << v1[i];
        }
        cout << endl;
    
    
        cout << "v1의 capacity : " << v1.capacity() << endl;
    
        //assign의 두 번째 방법
        //주어진 범위를 복사해서 요소를 옮긴다. 
    
        // 처음과 같이 초기화
        vector <int> v3(8, 2); // v3 = {2, 2, 2, 2, 2, 2, 2, 2}
        vector <int> v2(9, 3); // 새로운 벡터 v2 생성
    
        cout << " 3 : ";
        for(int i=0; i<v3.size(); i++){
            cout << v3[i];
        }
        cout << endl;
        cout << "v3의 capacity : " << v3.capacity() << endl;
    
        v3.assign(v2.begin(), v2.end());
        //v2의 첫번째 요소부터 마지막 요소까지 v1에 할당.
    
        cout << " v3 : ";
        for(int i=0; i<v3.size(); i++){
            cout << v3[i];
        }
        cout << endl;
        cout << "v3의 capacity : " << v3.capacity() << endl;
        // your code goes here
        return 0;
    }

    출력

    v1 : 22222222
    v1의 capacity : 8
    v1 : 222
    v1의 capacity : 8
    3 : 22222222
    v3의 capacity : 8
    v3 : 333333333
    v3의 capacity : 9

    코드와 출력문을 보면 알 수 있지만
    이전의 내용은 사라지고 새로 채워지지만, 요소가 줄어든다 해서 capacity가 변하진 않는다.

    1. push_back
      컨테이너의 마지막에 새로운 요소를 추가한다.
      요소를 추가할 때 현재 컨테이너의 용량을 초과하게 되는 경우에는, 현재 컨테이너 용량의 두배만큼의 컨테이너를 새로 할당한 후 기존의 요소를 복사한 후 새로운 요소가 추가된다.

    2. pop_back
      컨테이너의 마지막 요소를 제거한다.

    3. insert
      특정 위치에 요소를 추가한다.
      벡터는 배열이기 때문에 이러한 방법은 벡터에서 그리 효율적이진 않다.

    insert 사용방법

    1. insert( 추가할 위치 인덱스(iter), 추가할 내용)
      지정한 위치에 원하는 요소를 추가한다.
    2. insert( 추가할 위치 인덱스(iter), 추가할 요소의 개수, 추가할 내용)
      지정한 위치부터 추가할 내용을 개수만큼 추가한다.
    3. insert( 추가할 위치 인덱스(iter), iter1, iter2)
      지정한 위치부터 다른 컨테이너의 iter1~iter2까지의 요소를 복사해와서 넣는다.
    1. erase
      특정 위치의 요소를 제거하거나, 범위내의 요소를 제거한다.
      iterator erase (const_iterator position);
      iterator erase (const_iterator first, const_iterator last);

    2. swap
      동일한 유형의 다른 벡터 컨테이너의 내용과 교체된다.

      // swap vectors
      #include <iostream>
      #include <vector>
      

    int main ()
    {
    std::vector foo (3,100); // three ints with a value of 100
    std::vector bar (5,200); // five ints with a value of 200

    foo.swap(bar);

    std::cout << "foo contains:";
    for (unsigned i=0; i<foo.size(); i++)
    std::cout << ' ' << foo[i];
    std::cout << '\n';

    std::cout << "bar contains:";
    for (unsigned i=0; i<bar.size(); i++)
    std::cout << ' ' << bar[i];
    std::cout << '\n';

    return 0;
    }

    ```

    출력

    foo는 다음을 포함합니다 : 200200200200200
    막대 포함 : 100100100

    1. clear
      벡터에서 모든 요소를 제거하고 컨테이너 크기를 0으로 유지한다.

    1학기때 이렇게 공부했으면 C++ A+ 받았을 거 같은데,,, 이미 좀 늦은 것 같다.
    cplusplus.com Reference를 참고했다.