코딩 중급

std::vector에 관한 거의 모든 것

태장고 21302 2021. 11. 16. 00:35

목차

1. vector의 기본 사용법

2. vector를 배열처럼 사용하는 방법

3. vector에 구조체 넣고/접근하는 방법

4. vector 정렬

 

vector는 가변길이 배열이다. 가변길이 배열이란? 배열의 크기를 정해두는 것이 아니라, 코드를 진행하면서 배열의 크기를 결정하는 배열을 말한다( 즉, 배열의 크기를 정하지 않아도 된다. ). 오늘은 이 vector라는 놈에 대해 알아보자.

 

vector의 기본 사용법

우리가 배열을 사용할 때, 변수를 배열에 저장하기 위해서는 해당 인덱스에 직접 접근해야 했다. 하지만 vector는 조금 다른? 저장 방법을 가지고 있다. vector는 가변길이 배열로 코드를 진행하면서 배열의 크기를 진행할 수 있다고 했는데, 이것이 왜 가능할까?

 

이것을 이해하기 위해서 우리가 띄어쓰기가 없는 문장을 쓴다고 생각해 보자!

글자 하나를 쓰면 이 문장의 길이는 1이 됨을 알 수 있다. 그 다음 글자를 하나 더 쓰면 문장의 길이가 2개가 됨을 알 수 있다. 이렇게 쭉 진행하다보면? N번째 글자를 쓴 뒤는 문장의 길이가 N이 됨을 알 수 있다.

 

vector도 이것과 비슷하게 진행이 된다. 위에서 글자를 써 나가는 것처럼 변수를 계속해서 뒤에 붙여 나가는 방식이다.

여기서 배열과 다른점이 있다면; 배열은 인덱스에 직접 접근해서 값을 저장하기 때문에 원하는 위치부터 접근해서 값을 채울 수 있지만, vector의 경우 변수를 뒤에 계속 붙이면 무조건 0번째 인덱스부터 붙여지게 된다.

 

예시 코드는 다음과 같다.

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

vector<int> a; // int형 값을 저장할 수 있는 vector를 선언

int main()
{
    int n; scanf("%d", &n);
    for(int i=1; i<=n; i++) {
        int t; scanf("%d", &t); // t 스캔
        a.push_back(t); // 스캔한 t를 a라는 vector a의 맨 뒤에 붙임.
    }

    printf("%d\n", a.size()); // vector a의 크기를 출력
    for(int i=0; i<n; i++)
        printf("%d ", a[i]); // vector의 인덱스에 접근해 출력

    return 0;
}

using namespace std는 귀차니즘을? 줄여준다. 원래 vector에 관련된 기능을 사용하려면 std::을 붙여줘야 하는데, 이걸 전부 써주는 귀찮음을 줄이기 위해 이것을 써 주는 것이다.

 

부가적으로 몇가지 기능이 더 있는데... 많이 쓰는 기능 위주로 다뤄 보자!

 

1. empty

 - vector내 값이 존재하는지에 대한 여부를 알 수 있는 기능이다.

2. pop_back

 - vector의 맨 마지막 값을 제거해 준다.

3. clear

 - vector내 모든 값을 지운다. ( vector를 초기화 한다고 생각해도 됨! )

 

이 외에도 back, erase, 등의 기능이 있지만 사용할 일이 있다면 아래 vector reference에서 찾아서 쓰자!

https://www.cplusplus.com/reference/vector/vector/

--vector reference

 

vector를 배열처럼 사용하는 방법

2 - 1 vector를 배열로 쓰면 좋은점

 배열을 main 함수 안에서 선언할 때, 가능한 최대 크기는 몇일까? 직접 실험해 본 결과 1000000( 100만 ) 정도 크기가 최대이다. 그럼 전역으로 선언할 경우에는? 이것도 직접 실험해 본 결과 1000000000( 10억 ) 정도 크기가 최대이다. 하지만 vector로 배열을 선언할 경우 이 최대가 뚤리게 된다. 전역의 경우에는 10억을 넘어가도 어느 정도는 배열로 수용이 가능하다. ( 본인 20억 크기로 선언해 봤는데, 틀어놨던 노래가 멈췄다가 다시 틀어지는거 보고 좀 쫄려서 더 큰 경우는 실험하지 않았다. ) 중요한 것은 이게 아니라 main함수 안에서 크기 10억의 배열을 vector로 선언하면 가능하다는 것이다.

//쓰는 중~

 

2 - 2 vector를 배열로 쓰는 방법

vector를 배열처럼 사용하는 방법은 생각보다 그리 어렵지 않다. 지금까지 배열의 크기를 지정해 선언할 때에는 배열이름 뒤에 대괄호를 쓰고 그 안에 크기를 써 넣었다. vector의 경우에도 크게? 다르지 않다. vector의 이름 옆에 소괄호를 해 주고, 그 안에 원하는 크기를 정해주면 된다. 외에도 한가지 방법이 있는데, resize를 이용한 방법이다. 예시 코드는 다음과 같다.

// normal

int main()
{
    int n; scanf("%d", &n);
    vector<int> a(n); // vector a의 크기를 지정하면서 선언
    for(int i=0; i<n; i++) scanf("%d", &a[i]); //인덱스에 직접 접근
}

// using resize

vector<int> a; // vector 선언

int main()
{
    int n; scanf("%d", &n);
    a.resize(n); // vector의 크기 지정
    for(int i=0; i<n; i++) scanf("%d", &a[i]);
}

 

vector에 구조체 넣고/접근하는 방법

3 - 1 구조체를 벡터에 넣는 이유

 pair 라는 것에 대해 알고 있다면, pair 써서 자료를 묶으면 되지 굳이 왜 구조체를 vector에 넣는지 의문을 가질 수도 있다. 실제로 문제를 풀다보면, vector와 pair을 이용한 그래프탐색 문제가 많아서 이런 생각을 할 수도 있다. 하지만, 만약 저장해야 하는 변수가 단순한 좌표값이 아니라 3개 이상이라면? 또는 배열을 저장해야 한다면? 이런 경우에 구조체를 선언해야 하기 때문에 구조체를 vector에 넣는 방법을 알아두는 것은 그리 나쁜 장사가 아니다.

 

그리고 이번 글을 쓰면서 알게 된 사실인데, 구조체 배열을 사용하면 배열의 크기를 100만까지만 선언할 수 있지만, vector에 구조체를 넣어 사용할 경우 10억까지 인덱스를 사용할 수 있다. ( 구조체를 이용한 정렬 문제 중 큰 문제일 경우, 구조체 배열을 에러가 날 가능성이 크다. ( 주요 에러 : Runtime error ) )

 

자 이제 본격적으로 구조체를 vector에 넣고 사용하는 방법을 알아보자.

 

3 - 2 구조체를 벡터에 넣는 방법

 vector에 구조체를 넣는 방법은 크게 2가지가 있다.

 

 3 - 2 - 1 vector를 배열로 만들고 구조체 입력

  평소 배열에 스캔하던거랑 똑같다. 다만 평소에 100만 개의 데이터 밖에 처리 못하던 것을 10억 개의 데이터도 처리가 가능하게 될 뿐이다. 예시 코드는 다음과 같다.

struct point { // 구조체 선언
    int a, b, c;
};

int main()
{
    int n; scanf("%d", &n);
    vector<point> a(n); // 구조체 벡터 선언 후 크기 설정
    for(int i=0; i<n; i++)
        scanf("%d%d%d", &a[i].a, &a[i].b, &a[i].c);

    return 0;
}

 

 3 - 2 - 2 구조체 이름 선언하고 값 입력해서 넣기

이거의 경우 조금 달라 보일 수 있는데, 그러려니~ 하고 이해해 보자. 구조체의 이름을 먼저 선언해 주어야 한다. 그런 다음 구조체의 각 값에 입력받은 값을 저장해 주고, vector에 넣어준다. 예시 코드는 다음과 같다.

struct point {
    int a, b, c;
};

vector<point> v; // 구조체 벡터 선언

int main()
{
    int n; scanf("%d", &n);
    for(int i=0; i<n; i++) {
        int x, y, z; scanf("%d%d%d", &x, &y, &z);
        point t; // 구조체의 이름 설정
        t.a = x; t.b = y; t.c = z; // 구조체의 각 값에 입력받은 값을 저장
        v.push_back({t.a, t.b, t.c}); // vector에 붙임
    }

    return 0;
}

이렇게 2가지 경우로 구조체를 vector에 넣을 수 있다. 이런 다음에 접근은 어떻게 할 수 있을까?

 

3 - 3 원하는 값에 접근하는 방법

 vector의 인덱스에 먼저 접근한 후에, 구조체에 접근해 주면 된다. ( 즉, 배열과 동일하다. )

struct point {
    int a, b, c;
};

vector<point> v;

int main()
{
    for(int i=0; i<n; i++) {
        printf("%d %d %d\n", v[i].a, v[i].b, v[i].c); // 벡터 안 구조체에 접근
    }
}

 

vector 정렬 ( algorithm 헤더의 sort 를 이용 )

vector 정렬을 하려고 포인터가 난무하는 정렬을 짜는데, 굳이 그럴 필요 없다. 다음과 같은 방법을 통해 쉽게 정렬할 수 있다.

 

1. 1차원 벡터 정렬

 배열에서는 시작 인덱스에서 시작해, 마지막 수가 채워진 인덱스를 알아야 정렬을 할 수 있었다. 하지만 vector의 경우에는 다음과 같이 해 주면 처음부터 끝까지 오름차순으로 정렬해 준다. 만약 내림차순으로 정렬하고 싶다면 함수를 사용하면 되는데, 사용방법은 구조체 정렬할 때와 동일하다. ( 왜인지는 모름 )

bool cmp(int a, int b) { return a>b; } // 정렬 함수

vector<int> a;

int main()
{
    int n; scanf("%d", &n);
    for(int i=0; i<n; i++) {
    	int t; scanf("%d", &t);
        a.push_back(t);
    }

    sort(a.begin(), a.end()); // 오름차순 정렬
    sort(a.begin(), a.end(), cmp); // 내림차순 정렬
}

 

2. 구조체 vector 정렬

 

구조체 vector 정렬도 원래 하던 것과 크게 다르지 않다. 구조체 배열을 정렬할 때 우리는 함수를 만들어서 정렬하였는데, 비교 변수 앞에는 구조체의 이름을 써 주었다. vector의 경우에도 다를 것이 없다.

struct point {  
    int x, y;  
};  
  
bool cmp(point p, point q) {  
    return p.x > q.x;  
}

int main()  
{
    int n; scanf("%d", &n);
    vector<point> a(n);
    for(int i=0; i<n; i++) {  
        scanf("%d", &a[i].x); // 구조체 벡터의 원소 스캔
        a[i].y = i+1;
    }  
  
    sort(a.begin(), a.end(), cmp); // 구조체 벡터 정렬
}

 

여기까지 vector에 대해 알아보았다. ( 쓰느라 고생한 나 자신 넘 칭찬하고~ ) 이해가 되지 않거나 의문이 드는 내용은 댓글에 써 주시면 대답해 드리겠습니다. 이상입니다!