Rylah's Study & Daily Life

STL 06. 시퀀스 컨테이너 (Vector) 본문

Study/STL

STL 06. 시퀀스 컨테이너 (Vector)

Rylah 2021. 12. 2. 01:00

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

 

Vector의 주요 인터페이스와 특징

 

템플릿 형식
template<typename T,
 typename Allocator = allocator<T>>
class vector
T는 vector 컨테이너 원소의 형식

<Vector의 템플릿 형식>

 

생성자
vector v v는 빈 컨테이너
vector v(n) v는 기본값(0)으로 초기화된 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번째 원소를 참조한다. (const, 비 const 버전이 존재하며 범위 점검을 포함한다.)
v.back() v의 마지막 원소를 참조한다. (const, 비 const 버전이 있음)
p = v.begin() p는 v의 첫번째 원소를 가리키는 반복자(const, 비 const 버전이 있음)
x = v.capacity() x는 v에 할당된 공간의 크기
v.clear() v의 모든 원소를 제거한다.
v.empty() v가 비었는지 조사한다.
p=v.end() p는 v의 끝을 표시하는 반복자다(const, 비 const 버전이 있음)
q=v.erase(p) p가 가리키는 원소를 제거한다. q는 다음 원소를 가리킨다.
q=v.erase(p,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(x) v의 끝에 x를 추가한다.
p = v.rbegin() p는 v의 역 순차열의 첫 원소로 가리키는 반복자다. (const, 비 const 버전이 있음)
p = v.rend() p는 v의 역 순차열의 끝을 표시하는 반복자(const, 비 const 버전이 있음)
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의 모든 원소 중 하나라도 다른 원소가 있는가? (bool)
v1 < v2 문자열 비교처럼 v2가 v1보다 큰가? (bool)
v1 <= v2 문자열 비교처럼 v2가 v1보다 크거나 같은가? (bool)
v1 > v2 문자열 비교처럼 v1이 v2보다 큰가? (bool)
v1 >= v2 문자열 비교처럼 v1이 v2보다 크거나 같은가? (bool)
v[i] v의 i번째 원소를 참조한다.(const, 비 const 버전이 있으며 범위 점검이 없음)

<vector의 인터페이스>

 

멤버 형식
allocator_type 메모리 관리자 형식
const_iterator cosnt 반복자 형식
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 원소의 형식

<vector의 템플릿 멤버 형식>

 

#include <iostream>
#include <vector>
#include <typeinfo>

using namespace std;

int main(void) {
	vector<int> v;
	v.push_back(10);
	v.push_back(20);
	v.push_back(40);
	v.push_back(60);
	v.push_back(120);
	
	for (int i = 0; i < v.size(); i++) {
		cout << v[i] << endl;
	}
	
	cout << typeid(vector<int>::size_type).name() << endl;
	
	for (vector<int>::size_type i = 0; i < v.size(); ++i)
		cout << v[i] << " ";
	cout << endl << endl;
	
	cout << "v.size() : " << v.size() << endl;
	cout << "v.capacity() : " << v.capacity() << endl;
	cout << "v.max_size() : " << v.max_size() << endl;
	cout << endl << endl;
	
	vector<int> v2;
	cout << "vector's capacity() " << endl;
	cout << "size : " << v2.size() << "  capacity() : " << v2.capacity() << endl;
	v2.push_back(10);
	cout << "size : " << v2.size() << "  capacity() : " << v2.capacity() << endl;
	v2.push_back(20);
	cout << "size : " << v2.size() << "  capacity() : " << v2.capacity() << endl;
	v2.push_back(40);
	cout << "size : " << v2.size() << "  capacity() : " << v2.capacity() << endl;
	v2.push_back(80); 
	cout << "size : " << v2.size() << "  capacity() : " << v2.capacity() << endl;
	v2.push_back(120);
	cout << "size : " << v2.size() << "  capacity() : " << v2.capacity() << endl;
	v2.push_back(240);
	cout << "size : " << v2.size() << "  capacity() : " << v2.capacity() << endl;
	v2.push_back(480);
	cout << "size : " << v2.size() << "  capacity() : " << v2.capacity() << endl;
	v2.push_back(960);
	cout << "size : " << v2.size() << "  capacity() : " << v2.capacity() << endl;
	v2.push_back(1920);
	cout << "size : " << v2.size() << "  capacity() : " << v2.capacity() << endl;
	v2.push_back(3840);
	cout << "size : " << v2.size() << "  capacity() : " << v2.capacity() << endl;
	
	return 0;
}

Dev C++과 Visual Studio 컴파일러 차이로 출력값에서 차이가 많이 난다.

&amp;amp;amp;lt;Dev C++ Output&amp;amp;amp;gt;
Visual Studio Output

- 차이점

1. typeid에서 값을 받아오는게 unsigned int vs y가 된다.

2. max_size에 최대 사이즈 수가 다르다.

3. capacity의 증가 폭이 다르다.

#include <iostream>
#include <vector>
#include <typeinfo>

using namespace std;

int main(void) {
	vector<int> v3;
	v3.reserve(8);
	cout << "vector's capacity() " << endl;
	cout << "size : " << v3.size() << "  capacity() : " << v3.capacity() << endl;
	v3.push_back(10);
	cout << "size : " << v3.size() << "  capacity() : " << v3.capacity() << endl;
	v3.push_back(20);
	cout << "size : " << v3.size() << "  capacity() : " << v3.capacity() << endl;
	v3.push_back(40);
	cout << "size : " << v3.size() << "  capacity() : " << v3.capacity() << endl;
	v3.push_back(80);
	cout << "size : " << v3.size() << "  capacity() : " << v3.capacity() << endl;
	v3.push_back(120);
	cout << "size : " << v3.size() << "  capacity() : " << v3.capacity() << endl;
	v3.push_back(240);
	cout << "size : " << v3.size() << "  capacity() : " << v3.capacity() << endl;
	v3.push_back(480);
	cout << "size : " << v3.size() << "  capacity() : " << v3.capacity() << endl;
	v3.push_back(960);
	cout << "size : " << v3.size() << "  capacity() : " << v3.capacity() << endl;
	v3.push_back(1920);
	cout << "size : " << v3.size() << "  capacity() : " << v3.capacity() << endl;
	v3.push_back(3840);
	cout << "size : " << v3.size() << "  capacity() : " << v3.capacity() << endl;

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

	return 0;
}

<위 : Dev C++, 아래 : Visual Studio 2019>

8까지의 메모리 크기(capacity)를 reserve 함수로 미리 할당해준 것이다.

 

 

#include <iostream>
#include <vector>
#include <typeinfo>

using namespace std;

int main(void) {
	vector<int> v4(5); // 0으로 초기화된 size가 5인 vector 컨테이너
	v4.push_back(10);
	v4.push_back(20);
	v4.push_back(40);
	v4.push_back(80);
	v4.push_back(160);

	for (vector<int>::size_type i = 0; i < v4.size(); ++i) {
		cout << v4[i] << " ";
	}
	cout << endl;
	vector<int> v5(5); // 0으로 초기화된 size가 5인 vector 컨테이너
	v5[0] = 10; // 0 -> 10
	v5[1] = 20; // 0 -> 20
	v5[2] = 40; // 0 -> 40
	v5[3] = 80; // 0 -> 80
	v5[4] = 160;// 0 -> 160
	for (vector<int>::size_type i = 0; i < v5.size(); ++i)
		cout << v5[i] << " ";
	cout << endl;

	return 0;
}

#include <iostream>
#include <vector>
#include <typeinfo>

using namespace std;

int main(void) {
	vector<int> v6(5); // 기본값 0 으로 초기화된 size가 5인 컨테이터 vector
	for (vector<int>::size_type i = 0; i < v6.size(); ++i) {
		cout << v6[i] << " ";
	}
	cout << endl;
	
	vector<int> v7(5, 0); // 기본값 0으로 초기화된 size가 5인 컨테이너 vector
	for (vector<int>::size_type i = 0; i < v7.size(); ++i) {
		cout << v7[i] << " ";
	}
	cout << endl;
	
	vector<int> v8(5, 10); // 기본값 10으로 초기화 된 size가 5인 컨테이너 vector 
	for (vector<int>::size_type i = 0; i < v8.size(); ++i) {
		cout << v8[i] << " ";
	}
	cout << endl;
	
	 
	return 0;
}

#include <iostream>
#include <vector>
#include <typeinfo>

using namespace std;

int main(void) {
	vector<int> v9(5); // 기본값이 0으로 초기화된 size가 5인 컨테이너 vector 
	
	v9[0] = 10;
	v9[1] = 50;
	v9[2] = 105;
	v9[3] = 185;
	v9[4] = 204;
	for (vector<int>::size_type i = 0; i < v9.size(); ++i) {
		cout << v9[i] << " ";
	}
	cout << endl;
	
	cout << "Size : " << v9.size() << "  Capacity : " << v9.capacity() << endl;
	
	
	v9.resize(10); // 기본값이 0으로 초기화된 size가 10인 컨테이너로 변경 
	for (vector<int>::size_type i = 0; i < v9.size(); ++i) {
		cout << v9[i] << " ";
	}
	cout << endl;
	cout << "Size : " << v9.size() << "  Capacity : " << v9.capacity() << endl;
	
	v9.resize(5); // 기본값이 0으로 초기화된 size가 5인 컨테이너로 변경 capacity는 변하지 않음
	for (vector<int>::size_type i = 0; i < v9.size(); ++i) {
		cout << v9[i] << " ";
	}
	cout << endl;
	cout << "Size : " << v9.size() << "  Capacity : " << v9.capacity() << endl;
	 
	
	
	
	return 0;
}

#include <iostream>
#include <vector>
#include <typeinfo>

using namespace std;

int main(void) {
	vector<int> v10(5);
	v10[0] = 104;
	v10[1] = 503;
	v10[2] = 10566;
	v10[3] = 1851;
	v10[4] = 2044;
	
	for (vector<int>::size_type i = 0; i < v10.size(); ++i)
		cout << v10[i] << " ";
	cout << endl;
	
	cout << "Size : " << v10.size() << "   Capacity : " << v10.capacity() << endl;
	
	v10.clear(); // v10을 비운다. 
	cout << "after V.Clear() " << endl << "Size : " << v10.size() << "   Capacity : " << v10.capacity() << endl;
	
	if (v10.empty()) // 비었다면 ?  실행된다. 
		cout << "v10에 원소가 없어요 " << endl;	
	
	return 0;
}

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

int main(void) {
	vector<int> v(5);
	cout << "Size : " << v.size() << "   Capacity : " << v.capacity() << endl;
	
	vector<int>().swap(v);
	// 기본 생성자로 만든 vector 컨테이너와 v 컨테이너를 Swap
	cout << "Size : " << v.size() << "   Capacity : " << v.capacity() << endl;
	
	
	return 0;
}

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

int main(void) {
	vector<int> v(5);
	cout << "Size : " << v.size() << "   Capacity : " << v.capacity() << endl;
	
	vector<int>().swap(v);
	// 기본 생성자로 만든 vector 컨테이너와 v 컨테이너를 Swap
	cout << "Size : " << v.size() << "   Capacity : " << v.capacity() << endl;
	cout << endl;
	
	vector<int> v1;
	v1.push_back(3002);
	v1.push_back(40921);
	v1.push_back(33940);
	
	vector<int> v2;
	v2.push_back(2912);
	v2.push_back(4921);
	v2.push_back(33940);
	
	for (vector<int>::size_type i = 0; i < v1.size(); ++i) {
		cout << v1[i] << ", " << v2[i] << endl;
	}
	cout << endl;
	
	v1.swap(v2); // v1과 v2를 Swap 
	for (vector<int>::size_type i = 0; i < v1.size(); ++i) {
		cout << v1[i] << ", " << v2[i] << endl;
	}
	cout << endl;
	return 0;
}

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

int main(void) {
	vector<int> v;
	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] << " ";
	}
	cout << endl;
	
	cout << v[0] << ", " <<  v.front() << endl; // 첫번째 원소 
	cout << v[4] << ", " <<  v.back() << endl; // 마지막 원소 
	return 0;
}

#include <iostream>
#include <vector>

using namespace std;

int main(void) {
	vector<int> v;
	v.push_back(10);
	v.push_back(40);
	v.push_back(70);
	v.push_back(120);
	v.push_back(150);

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

	cout << v[0] << ", " << v.front() << endl; // 첫번째 원소
	cout << v[4] << ", " << v.back() << endl; // 마지막 원소
	cout << endl;
	v.front() = 32768; // 첫번째 원소 수정
	v.back() = 65536; // 마지막 원소 수정
	for (vector<int>::size_type i = 0; i < v.size(); ++i) {
		cout << v[i] << " ";
	}
	cout << endl << endl;
	v[0] = 5030; // 범위 점검 없는 0 index 참조
	v[4] = 2105; // 범위 점검 없는 4 index 참조
	for (vector<int>::size_type i = 0; i < v.size(); ++i) {
		cout << v[i] << " ";
	}
	cout << endl << endl;

	v.at(0) = 249495; // 범위 점검 있는 0 index 원소의 참조
	v.at(4) = 594942; // 범위 점검 있는 4 index 원소의 참조
	for (vector<int>::size_type i = 0; i < v.size(); ++i) {
		cout << v[i] << " ";
	}
	cout << endl << endl;
	// [] 연산자와 at의 기능이나 결과는 동일
	// 범위 점검의 여부가 차이임 at 함수는 in range이면 참조해서 반환하고 아니면 out of range 예외를 발생함.

	try {
		cout << v.at(0) << endl;
		cout << v.at(3) << endl;
		cout << v.at(6) << endl; // throw out_of_range 예외
	}
	catch (out_of_range& e) {
		cout << e.what() << endl << endl;
	}
	
	vector<int> v1(5, 1); // 초기값 1의 5개의 원소를 가지는 컨테이너 vector 생성

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

	v1.assign(5, 2); // 5개 원소 값을 2로 할당
	for (vector<int>::size_type i = 0; i < v1.size(); ++i) {
		cout << v1[i] << " ";
	}
	cout << endl << endl;

	vector<int> v2;
	v2.push_back(50);
	v2.push_back(550);
	v2.push_back(750);
	v2.push_back(1250);
	v2.push_back(2250);

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

	for (vector<int>::iterator iter = v2.begin(); iter != v2.end(); ++iter)
		cout << *iter << " ";
	cout << endl << endl;

	vector<int> v3; 
	v3.push_back(50);
	v3.push_back(150);
	v3.push_back(603);
	v3.push_back(202);
	v3.push_back(6035);

	vector<int>::iterator iter = v3.begin(); // 시작 원소 50을 가리킨다.
	cout << *iter << endl;

	iter += 2; // 원소 603을 가리킨다.
	cout << *iter << endl;

	iter -= 1; // 원소 150을 가리킨다.
	cout << *iter << endl;
	cout << endl << endl;

	vector<int> v4;
	v4.push_back(3204);
	v4.push_back(3201);
	v4.push_back(3202);
	v4.push_back(3203);
	v4.push_back(3206);

	vector<int>::iterator iter_a = v4.begin();
	vector<int>::const_iterator c_iter_a = v4.begin();

	cout << *iter_a << endl; // 가리키는 원소의 참조
	cout << *c_iter_a << endl;

	cout << *++iter_a << endl;
	cout << *++c_iter_a << endl;

	*iter_a = 100; // 일반 반복자는 가리키는 원소를 변경 할 수 있음
	//*c_iter_a = 500; // const는 상수라서 변경이 불가능
	cout << *iter_a << endl;
	cout << endl << endl;

	vector<int> v5;
	int arrayF[5]{ 83000, 73000, 13000, 53000, 23000 };
	v5.push_back(83204);
	v5.push_back(73201);
	v5.push_back(13202);
	v5.push_back(53203);
	v5.push_back(23206);

	vector<int>::iterator iter5 = v5.begin(); // iter5는 다음 원소로 이동 가능하고 원소의 변경이 가능한 반복자이다.
	int* p = arrayF;
	cout << *iter << ", " << *p << endl; // iter5는 p처럼 동작한다.

	vector<int>::const_iterator citer5 = v5.begin(); // citer5는 다음 원소로 이동이 가능하지만 원소의 변경이 불가능한 반복자이다.
	const int* cp = arrayF;
	cout << *citer5 << ", " << *cp << endl; //citer5는 cp처럼 동작한다.

	const vector<int>::iterator iter5_const = v5.begin(); // iter5_const는 다음 원소로 이동이 불가능하고 원소의 변경은 가능한 반복자이다.
	int* const p_const = arrayF; // iter5_const는 p_const처럼 동작한다.
	cout << *iter5_const << ", " << *p_const << endl;

	const vector<int>::const_iterator citer5_const = v5.begin(); // citer5_const는 다음 원소로 이동이 불가능하고 원소의 변경이 불가능한 반복자이다.
	const int* const cp_const = arrayF; // citer5_const는 cp_const처럼 동작한다.
	cout << *citer5_const << ", " << *cp_const << endl;


	return 0;
}

#include <iostream>
#include <vector>
using namespace std;
int main(void) {
	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>::iterator iter; // 정방향 반복자
	vector<int>::reverse_iterator r_iter; //역방향 반복자

	for (iter = v.begin(); iter != v.end(); ++iter)
		cout << *iter << " ";
	cout << endl;

	for (r_iter = v.rbegin(); r_iter != v.rend(); ++r_iter)
		cout << *r_iter << " ";
	cout << endl << endl;

	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>::iterator iter1 = v1.begin() + 2;
	vector<int>::iterator iter2;
	// iter1가 가리키는 위치에 정수 100을 삽입
	// iter2는 삽입한 정수를 가리키는 반복자

	iter2 = v1.insert(iter1, 100);
	for (iter1 = v1.begin(); iter1 != v1.end(); ++iter1)
		cout << *iter1 << " ";
	cout << endl;
	cout << *iter2 << endl;
	cout << endl;

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

	vector<int>::iterator iter3 = v2.begin() + 2;
	//iter가 가리키는 위치에 정수 100을 3개 삽입1
	v2.insert(iter3, 3, 100);
	for (iter3 = v2.begin(); iter3 != v2.end(); ++iter3) {
		cout << *iter3 << " ";
	}
	cout << endl;

	vector<int> v3;
	v3.push_back(100);
	v3.push_back(200);
	v3.push_back(300);

	iter3 = v3.begin() + 1;
	// iter3가 가리키는 위치에 [v3.begin(), v3.end()) 구간의 원소 삽입
	v3.insert(iter3, v2.begin(), v2.end());

	for (iter3 = v3.begin(); iter3 != v3.end(); ++iter3)
		cout << *iter3 << " ";
	cout << endl << endl;

	vector<int> v4;
	v4.push_back(10);
	v4.push_back(20);
	v4.push_back(30);
	v4.push_back(40);
	v4.push_back(50);
	v4.push_back(60);
	
	vector<int>::iterator iter4;
	vector<int>::iterator iter5;

	for (iter4 = v4.begin(); iter4 != v4.end(); ++iter4)
		cout << *iter4 << " ";
	cout << endl;

	iter4 = v4.begin() + 2;
	// iter가 가리키는 위치의 원소를 제거하기 위함이다. iter4의 다음 원소는 40이고 원소 30을 제거한다.
	iter5 = v4.erase(iter4);

	for (iter4 = v4.begin(); iter4 != v4.end(); ++iter4)
		cout << *iter4 << " ";
	cout << endl;

	// [v4.begin() + 1, v4.end() ) 구간 원소 제거
	iter5 = v4.erase(v4.begin() + 1, v4.end());

	for (iter4 = v4.begin(); iter4 != v4.end(); ++iter4)
		cout << *iter4 << " ";
	cout << endl << endl;

	vector<int> v5;
	v5.push_back(50);
	v5.push_back(150);
	v5.push_back(250);
	v5.push_back(350);
	v5.push_back(450);

	vector<int> v6(v5.begin(), v5.end()); // 순차열 v5.begin(), v5.end()로 v6 초기화 생성자로 초기화 하는 방법
	vector<int>::iterator iter6;
	for (iter6 = v6.begin(); iter6 != v6.end(); ++iter6)
		cout << *iter6 << " ";
	cout << endl;

	vector<int> v7;
	v7.assign(v5.begin(), v5.end());
	// v7에 순차열 [v5.begin(), v5.end()) 할당 , assign으로 초기화 하는 방법
	for (iter6 = v7.begin(); iter6 != v7.end(); ++iter6)
		cout << *iter6 << " ";
	cout << endl;


	vector<int> v8;
	v8.push_back(10);
	v8.push_back(120);
	v8.push_back(140);
	v8.push_back(160);
	v8.push_back(180);
	v8.push_back(200);

	vector<int> v9;
	v9.push_back(10);
	v9.push_back(120);
	v9.push_back(150);

	if (v8 == v9) // 원소 갯수, 원소값이 모두 일치해야 출력
		cout << "v1 == v2" << endl;
	if (v8 != v9) // 모든 원소가 같은게 아니면 출력
		cout << "v1 != v2" << endl;
	if (v8 < v9) // 원소 하나하나 비교해서 v9 원소가 크면 true 
		cout << "v1 < v2" << endl;

	return 0;
}