C++ STL08 :: 시퀀스 컨테이너
STL 컨테이너는 시퀀스 컨테이너와 연관 컨테이너로 나눌 수 있다.
시퀀스 컨테이너가 저장 원소가 삽입 순서에 따라 상대적인 위치(순서)를 갖는 컨테이너이며, 연관 컨테이너는 특정 정렬 규칙에 따라 저장 원소가 정렬되는 컨테이너이다.
* 시퀀스 컨테이너
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 | #include<iostream> #include<vector> #include <algorithm> #include<list> #include<stack> 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); for (vector<int>::size_type i = 0; i < v.size(); ++i) cout << v[i] << endl; cout << typeid(vector<int>::size_type).name() << endl; //vector<int>::size_type: vector의 크기, 첨자 형식을 위한 typedef 멤버 형식이다. return 0; } | cs |
* 참조
참조는 값을 복사하지 않고 같은 메모리 공간의 이름(참조) 이다.
*capacity()
vector만 가지는 멤버 변수이다. 메모리 재할당 문제를 해결하고 성능 문제를 보안시켰다.
즉, 미리 넉넉한 메모리를 확보하면 재할당과 이전 원소를 복사하는데 드는 비용을 줄일 수 있다.
메모리 예약 함수 reverse() 메모리 예약 함수를 제공한다.
reverse()를 사용하면 미리 메모리를 할당해 capacity를 결정하고 vector에 원소가 추가되더라도 메모리를 재할당 하지 않는다.
*vector의 주요 특징 정리
vector는 임의 접근 반복자를 지원하는 배열 기반 컨테이너이다. vector의 가장 큰 특징중 하나는 원소가 하나의 메모리 블록에 연속(배열 기반 컨테이너)하게 저장된다는 것이다. 그러다 보니, 원소가 추가되거나 삽입될때 메모리 재할당이 발생할 수 있고 상당한 비용을 지불하게 된다.
또한 벡터는 시퀀스 기반 컨테이너이다. 시퀀스 기반 컨테이너는 원소가 서로 상대적인 위치(순서)를 유지하므로 가장 앞 요소와 가장 뒤 요소를 참조하는 front(), back(0 멤버함수를 제공하여 컨테이너 끝에 추가하고 제거하는 push_back(), pop_back() 멤버 함수를 제공한다. 하지만, vecotr에는 배열기반 컨테이너이므로 push_front()와 pop_front() 멤버 함수는 제공하지 않는다. 이 두함수는 vector에 매우 비 효율적으로 작동한다.
*deque의 주요 특징 정리
deque는 시퀀스 컨테이너 이며 배열 기반 컨테이너이다. vector와 유사하다. vector와 다른점은 원소가 메모리 블록에 연속하게 저장되지만 하나의 메모리블록이 아닌 여러 메모리 블록에 나뉘어 저장된다는 것이다.
vector는 모든 원소를 뒤쪽으로만 밀어낼 수 있지만, deque는 뒤쪽이나 앞쪽으로 밀어낼 수 있다.
at() 과 [] 연산자를 지원한다.
*list 컨테이너
list 컨테이너는 vector와 deque처럼 시퀀스 컨테이너로 원소가 상대적인 순서를 유지한다. list 는 노드 기반 컨테이너로 원소가 노드 단위로 저장되며 list는 이중 연결 리스트로 구현된다.
*list의 주요 특징 정리
list는 시퀀스 컨테이너이며 노드 기반 컨테이너 이다. 그래서 순차열 중간에 삽입, 제거가 빈번하게 발생하며 원소의 상대적인 순서가 중요하다면 list 컨테이너를 사용한다. list는 이중 연결 리스트 구조로 원소를 앞, 뒤 에 모두 추가할수있는 push_front(), pop_front() ... 멤버함수를 제공한다.
또한, 시퀀스 컨테이너이므로 가장 첫 원소와 마지막 원소의 참조를 반환하는 front()와 back()멤버함수를 제공한다.
단, 노드 기반 컨테이너 이므로 [] 연산자나 at() 멤버함수는 제공하지 않는다.
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 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 | #include<iostream> #include<vector> #include <algorithm> #include<list> #include<stack> using namespace std; int main() { /* vector의 capacity() 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] << endl; cout << typeid(vector<int>::size_type).name() << endl; //vector<int>::size_type: vector의 크기, 첨자 형식을 위한 typedef 멤버 형식이다. cout << v.size() << endl; //저장 원소 개수 cout << v.capacity() << endl; //실제 할당된 메모리 공간의 크기 cout << v.max_size() << endl; //컨테이가 담을 수 있는최대 원소의 개수 */ /* vector의 reserve() vector<int> v; v.reserve(8); cout << "size : " << v.size() << " capacity :" << v.capacity() << endl; v.push_back(10); cout << "size : " << v.size() << " capacity :" << v.capacity() << endl; v.push_back(20); cout << "size : " << v.size() << " capacity :" << v.capacity() << endl; v.push_back(30); cout << "size : " << v.size() << " capacity :" << v.capacity() << endl; v.push_back(40); cout << "size : " << v.size() << " capacity :" << v.capacity() << endl; v.push_back(50); cout << "size : " << v.size() << " capacity :" << v.capacity() << endl; v.push_back(60); cout << "size : " << v.size() << " capacity :" << v.capacity() << endl; v.push_back(70); cout << "size : " << v.size() << " capacity :" << v.capacity() << endl; v.push_back(80); cout << "size : " << v.size() << " capacity :" << v.capacity() << endl; v.push_back(90); */ /*vector의 생성자 vector<int> v1(5); //0으로 초기화된 size가 5인 컨테이너 v1.push_back(10); v1.push_back(20); v1.push_back(30); v1.push_back(40); v1.push_back(50); for (vector<int>::size_type i = 0; i < v1.size(); ++i) cout << v1[i] << ""; cout << endl; vector<int> v2(5); //0으로 초기화된 size가 5인 컨테이너 v2[0] = 10; v2[1] = 20; v2[2] = 30; v2[3] = 40; v2[4] = 50; //0에서 10,20,30,40,50 으로 수정했다. for (vector<int>::size_type i = 0; i < v2.size(); ++i) cout << v2[i] << " "; vector<int> v3(5,10) for(vector<int>::size_type i=0; i<v3.size(); ++i) cout<<v3[i]<< ""; //10으로 초기화됨 v3.resize(10); //기본값 10으로 초기화된 size가 10인 컨테이너로 확장된다. for(vector<int>::size_type i = 0; i<v.size(); ++i) cout<<v[i]<<""; cout<<endl; cout<<"size :"<<v.size()<<" capacity :"<<v.capacity()<<endl; //capacity는 10으로 확장됨 v.resize(5); //capacity는 변함이 없음 for(vector<int>::size_type i =0; i<v.size(); ++i) cout<<v[i]<<""; cout<<endl; cout<<"size : "<<v.size()<<" capacity:"<<v.capacity()<<endl; v3. clear(); // 비운다. clear() 해도 capacity는 여전히 사라지지 않는다. 남아있게 된다. if(v3. empty()) { cout<<"v3에 원소가 없습니다."<<endl; } vector<int>().swap(v3); //기본 생성자로 만든 vector 컨테이너와 v3 컨테이너를 swap 한다. capacity는 0이 된다. vector<int> v4; v4.push_back(10); v4.push_back(20); v4.push_back(30); v4.push_back(40); v4.push_back(50); v4.front() = 100; //첫번째 원소를 100으로 v4.back() = 500; //마지막 원소를 500으로 for(vector<int>::size_type i=0; i< v.size(); ++i) cout<<v[i]<<endl; //시퀀스 컨테이너 중 배열 기반 컨테이너인 vector와 deque는 일반 배열처럼 임의 위치의 원소를 참조하는 두 인터페이스를 제공한다. // [ ]연산자와 at() 멤버 함수이다. //두 인터페이스의 기능은 같지만 [ ] 연산자는 범위 점검을 하지 않아 속도가 빠르며 at() 멤버함수는 범위를 점검하므로 속도가 느리다. v4.at(0) = 1000; //범위 점검 있는 0 index 원소의 참조 v4.at(4) = 5000; //범위 점검 있는 4 index 원소의 참조 //결과적으로 [] 연산자와 at() 멤버함수의 기능이나 결과는 같다. try { cout<<v4.at(0)<<endl; cout<<v4.at(3)<<endl; cout<<v4.at(6)<<endl; //throw out_of_range 예외 } catch(out_of_range &e) { cout<<e.what()<<endl; } //왜? 범위를 체크하기 때문이다. //v.assign(5,2); // 5개의 원소값을 2로 할당 //begin()과 end() 멤버 함수를 사용한 간단한 예제. 위와 차이가 있다. for(vector<int> :: iterator iter = v4.begin(); iter!=v4.end(); ++iter) cout<<*iter<<""; //반복자를 사용할 경우에는 다음을 선언한다. vector<int> :: iterator iter = v.begin(); iter += 2 ; // +2 한 위치의 원소(30)을 가리킨다. //상수 반복자를 사용하면 const 포인터처럼 데이터를 읽기 전용으로 안전하게 사용할 수 있다. vector<int>::const_iterator citer = v4.begin(); cout<<*citer<<endl; //가리키는 원소의 상수 참조 , 주의 해야 할것은 동작하여 반복자를 이동할 수 없으므로 사용에 주의해야 한다. vector<int>::iterator iter2; iter2 = v.insert(iter, 100); //iter에는 값이 있다. 10,20,30,40,50 가정, 그래서 iter를 삽입하게 되면 한칸 밀리게 된다. v.insert(iter, 3, 100); //iter가 가리키는 위치에 정수 100을 3개 삽입 v2.insert(iter, v.begin(), v.end()); //iter가 가리키는 위치에 [v.begin(), v.end()) 구간의 원소를 삽입한다. //원래 10,20,30,40,50 의 수가 있다고 치면 10 20 100 100 100 30 40 50 이고 //100 10 20 100 100 100 30 40 50 200 300 으로 된다. //특정 위치의 원소를 제거하려면 erase 멤버 함수를 사용한다. erase는 반복자를 사용하여 원소를 한개 혹은 여러개 제거할 수 있다. cout << endl; return 0; */ return 0; } | cs |
'C++ STL' 카테고리의 다른 글
C++STL11 :: map<key,value> (0) | 2020.09.23 |
---|---|
C++STL10 :: adjacent_find() (0) | 2019.01.05 |
C++ STL09 :: 연관 컨테이너 (0) | 2018.12.30 |
C++STL07 :: STL 소개(2) (0) | 2018.12.30 |
댓글
이 글 공유하기
다른 글
-
C++STL11 :: map<key,value>
C++STL11 :: map<key,value>
2020.09.23 -
C++STL10 :: adjacent_find()
C++STL10 :: adjacent_find()
2019.01.05 -
C++ STL09 :: 연관 컨테이너
C++ STL09 :: 연관 컨테이너
2018.12.30 -
C++STL07 :: STL 소개(2)
C++STL07 :: STL 소개(2)
2018.12.30