[C++] stl vector 벡터 사용 방법 및 예제 모음

C++로 코딩하다보면 제일 많이 쓰이는 stl 표준 라이브러리의 벡터 자료구조의 생성방법부터 꼭 알아야하는 메서드까지 예제와 함께 다루어 보겠습니다.

vector vs array 벡터와 배열의 차이

먼저 많은 분들이 비슷하다고 생각하는 벡터와 배열의 차이를 한 번 알아보겠습니다.

벡터배열
크기동적고정
메모리배열 보다 많이 사용벡터 보다 적게 사용
접근방식포인터 기반인덱스 기반
접근속도느림빠름

벡터와 배열 둘 다 데이터를 순차적으로 저장하지만, 가장 큰 차이점이라 하면 벡터는 동적으로 크기를 변경할 수 있다는 점입니다.

따라서, 넣어야할 데이터의 개수가 확실치 않을 때 벡터를 사용하는 것이 좋습니다. (배열의 경우 한 번 크기가 정해지면 바꿀 수 없기 때문입니다.)

벡터는 데이터에 대한 접근을 포인터로 하기 때문에 배열보다는 접근속도가 느릴 수 밖에 없습니다. (하지만 이러한 포인터 기반 접근방식이 배열과 다르게 동적 할당을 가능하게 하는 부분입니다.)

vector 생성 방법

다음은 벡터의 생성 방법 및 초기화입니다. 당연하게도 사용하려면 <vector> 헤더파일을 추가해주어야 하며, 편리성을 위해 “using namespace std;”를 사용하겠습니다.

기본적으로 생성할 때 구문은 vector<“자료형”> “벡터 변수명” 구조입니다. 아래 예시에서 편의상 벡터에 넣을 데이터의 자료형을 “int”로 하였습니다.

#include <vector>

using namespace std;

// 빈 벡터 v1 생성
vector<int> v1; 

// 크기가 10이며 0으로 채워진 벡터 v2 생성
vector<int> v2(10);

// 크기가 10이며 1로 채워진 벡터 v3 생성
vector<int> v3(10,1);

// 1,2,3,4,5,6이 순차적으로 들어있는 벡터 v4 생성
vector<int> v4 = { 1, 2, 3, 4, 5, 6}

// 2차원 벡터 v6 생성
vector<vector<int>> v6;

// 벡터 v5를 복사한 벡터 v7 생성
vector<int> v7(v5);

vector 메서드

메서드들의 종류가 다양하다보니 크게 네가지로 나누어 정리하였습니다.

반복자와 관련된 메서드, 사이즈와 관련된 메서드, 벡터의 구조나 데이터를 수정하는 메서드, 데이터 접근 관련 메서드로 나누었습니다.

반복자 iterators

  • begin(): 벡터의 첫 번째 요소를 가리키는 반복자를 반환합니다.
  • end(): 벡터의 마지막 요소를 가리키는 반복자를 반환합니다.
#include <iostream> 
#include <vector> 
using namespace std;   
int main() 
{ 
    vector<int> a; //int 값들을 담는 벡터 a를 선언
   
   //벡터 a에게 1부터 7까지의 숫자를 넣기
    for (int i = 1; i <=7 ; i++) 
        a.push_back(i); 

    //반복자를 이용하여 벡터의 첫 번째 요소부터 마지막까지 출력
    cout << "begin()과 end() 메서드를 이용하여 출력\n"; 
    for (auto i = a.begin(); i != a.end(); ++i) 
        cout << *i << " "; 
   
   // begin()과 end()와 같지만 constant한 cbegin(), cend()
    cout << "\ncbegin()과 cend() 메서드를 이용하여 출력\n"; 
    for (auto i = a.cbegin(); i != a.cend(); ++i) 
        cout << *i << " "; 
   
   // begin()과 end()와 같지만 reverse한 rbegin(), rend()
    cout << "\nrbegin()과 rend() 메서드를 이용하여 출력\n"; 
    for (auto ir = a.rbegin(); ir != a.rend(); ++ir) 
        cout << *ir << " "; 
  
    // begin()과 end()와 같지만 constant 하고 reverse한 crbegin(), crend()
    cout << "\ncrbegin()과 crend() 메서드를 이용하여 출력\n"; 
    for (auto ir = a.crbegin(); ir != a.crend(); ++ir) 
        cout << *ir << " "; 
  
    return 0; 
} 

결과값:

벡터 begin end cbegin cend rbegin rend crbegin crend

예제에서 볼 수 있듯이 begin()과 end() 메서드 이외에도 constant 또는 reverse 또는 constant하며 reverse인 반복자를 반환하는 메서드들도 있습니다.

사이즈

벡터의 사이즈와 관련된 메서드들은 주로 다음과 같습니다.

  • size(): 현재 벡터안에 있는 요소(데이터)의 개수를 반환합니다.
  • max_size(): 벡터가 가질 수 있는 최대 개수의 요소를 반환합니다.
  • capacity(): 벡터에게 할당된 저장공간 사이즈를 반환합니다.
  • resize(n): n을 매개변수로 넣으면 n개의 요소를 담을 수 있게 사이즈를 바꿉니다.
  • empty(): 현재 벡터가 비어있는지 아닌지 반환합니다.
#include <iostream>
#include <vector> 
using namespace std; 
int main() 
{ 
   //int 값들을 담는 벡터 a를 선언
   vector<int> a; 
   
   //벡터 a에게 1부터 5까지의 숫자를 넣기
    for (int i = 1; i <= 5; i++) 
        a.push_back(i); 
  
    //벡터의 size() 출력
    cout << "size() : " << a.size(); 
   
    //벡터의 capacity() 출력
    cout << "\ncapacity() : " << a.capacity(); 
    
    //벡터의 최대 크기 max_size() 출력
    cout << "\nmax_size() : " << a.max_size(); 
  
    // resize()로 4로 사이즈 변경
    a.resize(4); 
  
    // resize()로 사이즈 바꾼 후 size() 출력
    cout << "\nSize : " << a.size(); 
  
    // empty()로 벡터가 비어있는지 확인
    if (a.empty() == false) 
        cout << "\n벡터가 비어있지 않습니다."; 
    else
        cout << "\n벡터가 비어있습니다."; 
  
  
    return 0; 
} 

결과값:

벡터 sizee max_size capacity resize empty

여기서 좀 헷갈리실 수 있는 size, capacity와 max_size의 차이점에 대해 한 번 짚고 넘어가보겠습니다.

size는 벡터가 현재 가진 요소의 개수를 의미하고, capacity는 현재 벡터에게 할당된 사이즈라고 생각하시면 됩니다.

따라서 요소를 벡터에 계속해서 넣어 5개였던 size가 8개를 넘어가면 메모리 재할당(reallocate)이 발생하며 모든 값들을 새로운 메모리 공간에 복사하고 기존 벡터를 없애버립니다. 이러한 과정때문에 퍼포먼스가 저하될 수 있습니다.

이를 예방하기 위해 사용하게될 벡터의 사이즈를 대략 알고 있다면 reserve(n) 메서드를 통해 n 만큼 미리 벡터에게 할당해줄 수 있습니다. (필요보다 너무 많이 할당하는 것도 메모리 비효율적입니다.)

또한 shrink_to_fit() 메서드를 활용하여 capacity() 즉 할당된 크기를 벡터의 실제 요소 개수인 size()에 맞출 수 있습니다.

max_size는 한마디로 현재 시스템에서 벡터가 생성될 수 있는 절대적 최대 크기입니다.

수정

  • assign(): 새로운 값을 현재 벡터안에 있는 요소에게 부여합니다.
  • push_back(): 벡터 맨 뒤에 새로운 요소를 넣습니다.
  • pop_back(): 벡터 맨 뒤에 있는 요소를 제거합니다.
  • insert(): 지정한 위치에 새로운 요소를 넣습니다.
  • erase(): 지정한 위치에 있는 요소 또는 구간에 있는 요소들을 제거합니다.
  • swap(): 같은 자료형을 가지고 있는 두 벡터의 컨텐츠를 서로 바꿉니다.
  • clear(): 벡터 안 모든 요소들을 제거합니다.
#include <iostream> 
#include <vector> 
using namespace std; 
  
int main() 
{ 
    // int 자료형을 담을 수 있는 벡터 a 선언
    vector<int> a; 
  
    // 벡터 a에게 7을 4번 반복하여 넣기
    a.assign(4, 7); 
    
    // 벡터 a의 요소들 전부 출력
    cout << "assign(4,7)한 후: "; 
    for (int i = 0; i < a.size(); i++) 
        cout << a[i] << " "; 
  
    // 벡터 a의 마지막 위치에 10 넣기
    a.push_back(10); 
    int n = a.size(); 
    cout << "\npush_back(10)하고 벡터 a의 마지막 요소: " << a[n - 1]; 
  
    // 벡터 a의 마지막 요소 제거
    a.pop_back(); 
  
    // 벡터 a의 요소들 전부 출력
    cout << "\npop_back()한 후 벡터 a 모든 요소 출력: "; 
    for (int i = 0; i < a.size(); i++) 
        cout << a[i] << " "; 
  
    // 벡터 맨 첫 번째 위치에 3 넣기
    a.insert(a.begin(), 3); 
   
   // 벡터 a의 첫 번째 요소 출력
    cout << "\na.insert(a.begin(), 3)하고 첫 번째 요소 출력: " << a[0]; 
  
    // 벡터 a의 첫 번째 요소 지우기
    a.erase(a.begin()); 
    
   // 벡터 a의 새로운 첫 번째 요소 출력
    cout << "\na.erase(a.begin())로 첫 번째 요소 제거 후 새로운 첫 번째 요소: " << a[0]; 
  
   
    // 벡터 값 모두 지우기 clear()
    a.clear(); 
   
    // 모든 요소를 erase()를 통해 제거한 후 벡터 a의 사이즈 출력
    cout << "\na.clear()로 모든 요소 제거 후 a의 사이즈: " << a.size(); 
  
    // int 자료형을 넣을 벡터 a1과 a2 선언
    vector<int> a1, a2; 
   

    //a1과 a2 벡터에게 각각 3,4 와 5,6 넣기
    a1.push_back(3); 
    a1.push_back(4); 
    a2.push_back(5); 
    a2.push_back(6); 
  
   //벡터 a1 출력
    cout << "\n\n벡터 a1 출력: "; 
    for (int i = 0; i < a1.size(); i++) 
        cout << a1[i] << " "; 
  
    //벡터 a2 출력
    cout << "\n벡터 a2 출력: "; 
    for (int i = 0; i < a2.size(); i++) 
        cout << a2[i] << " "; 
  
    // a1과 a2 벡터 swap()
    a1.swap(a2); 
  
   //a1 벡터와 a2 벡터를 swap한 후 a1 출력
    cout << "\na1.swap(a2)한 후 \n벡터 a1: "; 
    for (int i = 0; i < a1.size(); i++) 
        cout << a1[i] << " "; 
  
    //a1 벡터와 a2 벡터를 swap한 후 a2 출력
    cout << "\n벡터 a2: "; 
    for (int i = 0; i < a2.size(); i++) 
        cout << a2[i] << " "; 
    return 0;
} 

결과값:

벡터 assign push_back pop_back insert erase swap clear

접근

  • 벡터[g]: 벡터 g+1 번째 위치에 있는 요소 반환
  • at(g): 벡터 g+1 번째 위치에 있는 요소 반환
  • front(): 벡터의 첫 번째 요소 반환
  • back(): 벡터의 마지막 요소 반환
#include <iostream>
#include <vector>
using namespace std;

int main() {
  // int 자료형을 담을 수 있는 벡터 a 선언
  vector<int> a;

  // 벡터 a에게 10부터 100까지 10단위로 넣기
  for (int i = 1; i <= 10; i++)
    a.push_back(i * 10);

  // 벡터 a의 모든 요소 출력
  cout << "벡터 a의 모든 요소: ";
  for (int i = 0; i < a.size(); i++)
    cout << a[i] << " ";

  // 벡터의 세 번째 요소 출력
  cout << "\na[2] = " << a[2];

  // 벡터의 5 번째 요소 출력
  cout << "\na.at(4) = " << a.at(4);

  // 벡터 a의 첫 번째 요소 출력
  cout << "\na.front() = " << a.front();

  // 벡터 a의 마지막 요소 출력
  cout << "\na.back() = " << a.back();

  return 0;
}

결과값:

벡터 at front back

2차원 벡터

마지막 2차원 벡터 관련 예제로 포스팅 마무리하겠습니다.

#include <iostream> 
#include <vector> 
using namespace std; 
  
// for 반복문에 쓰일 2차원 벡터 행과 열의 개수를 지정
#define row 3
#define col 3
  
int main() 
{ 
    // 벡터안에 또 다른 int자료형 벡터를 넣어서 2차원 벡터 선언
    vector< vector<int> > a; 
  
    // 벡터안에 넣을 요소 값 
    int num = 10; 
  
    // 2차원 벡터 행 추가
    for (int i = 0; i < row; i++) { 
        // 2차원 벡터 열들의 값을 가진 벡터 a1 선언
        vector<int> a1; 
       
       // a1에게 한 행에 있는 열의 값들 넣기
        for (int j = 0; j < col; j++) { 
            a1.push_back(num); 
            num += 5; 
        } 
  
        // 2차원 벡터 a에게 1차원 벡터 a1을 넣어서 한 행 완성
        a.push_back(a1); 
    } 
  
    // 2차원 벡터 a 출력
    cout<<"2차원 벡터 a의 값들:"<<"\n";
    for (int i = 0; i < a.size(); i++) { 
        for (int j = 0; j < a[i].size(); j++) 
            cout << a[i][j] << " "; 
        cout << endl; 
    } 

    return 0;
}

결과값:

2차원 벡터

이렇게 요소마다 5씩 증가하는 3×3 2차원 벡터를 생성했습니다.

답글 남기기