iterator
- 포인터와 상당히 비슷하며, 컨테이너에 저장되어 있는 원소들을 참조할 때 사용
- 알고리즘 마다 각기 다른 방식으로 컨테이너를 훑어가기 때문에, 반복자에도 여러가지 종류가 있음.
- iterator는 실제 값이 없는 end() 위치를 가질 수 있다.
- iterator를 기반으로 하는 insert, erase 함수는 iterator 값을 반환한다
vector<int> a;
auto it = a.end();
for(int i = 0; i < 10; i++) {
it = a.insert(it, i); // 요소 삽입 후 해당 지점의 iterator값을 반환
}
for(it x: a) {
cout << x << ',';
}
cout << endl;
compile result) 9, 8 ,7, 6, 5, 4, 3, 2, 1
insert 함수는 입력받은 좌측에 요소를 삽입한다.
Container별 차이점
- vector, deque에서의 insert, erase는 O(n) (시간초과 가능성↑)
- list에서의 insert, erase는 O(1)
- list에서의 iterator는 증감연산자(++/--) 만 지원 한다.
vector<int> a(2);
deque<int> b(2);
list<int> c(2);
vector<int>::iterator ia;
deque<int>::iterator ib;
list<int>::iterator ic;
ia = a.begin();
ib = b.begin();
ic = c.begin();
ia++;
ib++;
ic++;
--ia;
--ib;
--ic;
ia = a.begin() + 1;
ib = b.begin() + 1;
//ic = c.begin() + 1; << ERROR;
list 에서 iterator의 +/- 주소 연산이 불가능하다.
why?) list는 논리적 연결 구조이기 때문에 물리적 주소 이동 개념인 주소 연산이 불가능.
vector<int> a = {1,2,3,4,5};
deque<int> b = {5,4,3,2,1};
list<int> c = {10,20,30,40,50};
int i;
for(i = 0; i < a.size(); i++) cout << a[i] << ',';
cout << '\n';
for(i = 0; i < b.size(); i++) cout << b[i] << ',';
cout << '\n';
//for(i=0; i < c.size(); i++) cout << c[i] << ','; << ERROR
- vector, deque는 일반 배열 형태로 표현 가능.
- list는 일반 배열 형태로 표현 불가능
Vector
- #include <vector>
- 자동으로 메모리가 할당되는 배열
- 길이를 변경할 수 있는 배열
선언 >> vector<data type> 변수명;
vector<int> v1; // 길이가 0인 벡터
vector<int> v2(10); // 길이가 10인 벡터
vector<int> v3(15, 1); // 길이가 15이고, 초기값이 '1'인 벡터
vector<int> v4 = {1, 2, 3, 4, 5};
Vector 멤버 함수
- vector<int> v 라고 가정.
- n은 임의의 숫자.
v.front() : 0번째 요소의 값 참조.
v.back() : 마지막 요소의 값 참조.
v.push_back(n) : 마지막 원소 뒤에 n 삽입.
v.pop_back() : 배열 마지막 요소 제거.
v.claer() : 모든 원소를 제거. 메모리는 남아 있음.
v.resize(n) : 크기를 n으로 변경함. 더 커졌을 경우 디폴트 값 0 으로 초기화.
v.size() : 원소 갯수를 리턴함.
v.empty() : vector의 empty 유무를 리턴함.
v.begin() : 첫번째 원소를 가리킴 (iterator)
v.end() : 마지막의 다음을 가리킴 (iterator)
v.insert(x,y,z) : x번째 위치에 y개의 z값을 삽입함.
v.erase(iterator) : iterator가 가리키는 원소를 제거함.
v.erase(start,end) : start이상 부터 end 미만까지 원소 제거함.
vector<int> v = {1,2,3,4,5}; // [1,2,3,4,5]
v.push_back(6) // [1,2,3,4,5,6]
v.pop_back() // [1,2,3,4,5]
v.clear() // []
v.resize(5) // [0,0,0,0,0]
vector<int> v = {1,2,3,4,5}; // [1,2,3,4,5]
cout << "size = " << v.size() << endl; // size = 5
cout << "empty = " << v.empty() << endl; // empty = 0 (false)
v.claer();
cout << "empty = " << v.empty() << endl; // empty = 1 (true)
vector<int> v = {1,2,3,4,5}; // [1,2,3,4,5]
cout << "front = " << v.front() << endl; // front = 1
cout << "v[1] = " << v[1] << endl; // a[1] = 2 : 일반 배열처럼 사용 가능
cout << "back = " << v.back() << endl; // back = 5
vector<int> v = {1,2,3}; // [1,2,3]
auto it = v.begin(); // it = v.begin (맨 앞 요소 가리킴)
v.insert(it, 4); // [4,1,2,3]
it = v.begin() + 1; // it = v.begin + 1 (맨 앞에서 +1 가리킴)
v.insert(it, 5, 0); // [4,0,0,0,0,0,1,2,3]
it = v.begin() + 2; // it = v.begin + 2 (맨 앞에서 +2 가리킴)
vector<int> a = {10, 20} // 임의의 새로운 벡터 생성.
v.insert(it, b.begin(), b.end()); // [4,0,10,20,0,0,0,0,1,2,3]
vector<int> v = {1,2,3,4,5}; // [1,2,3,4,5]
v.erase(v.begin()+2); // [1,2,4,5]
v.erase(v.begin()+1, v.begin()+3); // [1,5]
deque(덱)
- #include <deque>
- vector의 단점을 보완하기 위해 만들어진 container
- 배열기반의 구조이며, 여러개의 메모리 블록을 할당하고 하나의 블록처럼 여기는 기능 제공.
- 데이터의 삽입과 삭제가 front와 back에서 이루어 질 수 있음.
- vector의 멤버 변수와 거의 유사함. vector에서도 90% 이상 사용
선언 >> deque<data type> 변수명;
deque <int> d; // 비어있는 deque를 생성.
deque <int> d(10); // default 값으로 초기화 된 10개의 원소를 가진 d 생성.
deque <int> d(10,4); // 4의 값으로 초기화 된 10개의 원소를 가진 d 생성.
deque의 멤버 함수
deque<int> d 라고 가정.
n은 임의의 숫자
- d.push_front(n) : d의 첫 번째 원소 앞에 n을 삽입
- d.pop_front() : d의 첫 번째 원소를 제거
- d.push_back(n) : d의 마지막 원소 뒤에 n을 삽입
- d.pop_back() : d의 마지막 원소를 제거
- d.assign(x,y) : x의 값으로 y개의 원소 할당
- d.at(index) : index번째 원소를 참조 *유효범위 점검 o, 속도 느림
- d[index] : index번째 원소를 참조 *유효범위 점검 x, 속도 빠름
- d.front() : 첫 번째 원소를 참조
- d.back() : 마지막 원소를 참조
- d.clear() : 모든 원소를 제거.
- d.size() : 원소의 개수를 리턴
- d.insert(x,y,z) : x번째 위치에 y개의 z를 삽입. 삽입 시 앞 뒤 원소 개수를 비교하여 적은 쪽으로 미루어 삽입.
- d.insert(x,y) : x번째 위치에 y값을 삽입. 삽입한 곳의 iterator 반환
- d.erase(iter) : iter가 가리키는 원소 제거. 제거 후 앞 뒤 원소 개수 판단하여 적은쪽으로 원소를 당겨 채움
- d.empty() : d의 empty 여부 반환 (true or false)
- d.rbegin() : 맨 마지막원소를 첫번째 원소 처럼 가리킴. iterator와 사용.
- d.rend() : 맨 첫번째 원소의 "앞"을 마지막 원소의 "다음" 처럼 가리킴. iterator와 사용
- d2.swap(d1) : d1과 d2를 바꿈.
deque<int> d;
d.push_back(1); // [1]
d.push.front(2); // [2,1]
d.push.back(3); // [2,1,3]
d.pop_back(); // [2,1]
d.pop_front(); // [1]
List
- 각각의 요소가 연결된 자료 구조
- array, vector, deque는 중간에 데이터 삽입/삭제 시 데이터 재정렬 때문에 O(n)
- list는 중간 고리(link) 만 변경 연결하면 되는 구조 O(1)
- 원소를 탐색할 때 임의접근 반복자는 불가능, 양방향 반복자(++, --) 를 이용하여 탐색
- 멤버 함수를 사용하여 양방향 삽입, 삭제 가능, 노드 중간에 삽입, 삭제도 가능.
선언 >> list<data type> 변수 이름;
list<int> l;
list<string> l;
멤버 함수
- list<int> l 로 선언 했다고 가정.
- n은 임의의 숫자
- 이전 게시물의 중복되는 함수들은 작성하지 않았음. 유용한 함수 위주
- l.remove(n) : n과 같은 원소를 모두 제거
- l.remove_if(bool) : 단항 조건자 bool에 해당하는 원소를 모두 제거
- l.reverse : 원소들의 순차열을 뒤집음.
- l.sort() : 모든 원소를 오름차순으로 정렬. 파라미터로 이항조건자가 오면 그 기준으로 정렬
list<int> l = {2, 1, -5, 4, -3, 6, -7}; // 2 1 -5 4 -3 6 -7
l.sort(); // -7, -5, -3, 1, 2, 4, 6
l.sort(greater<int>()); // 6, 4, 2, 1, -3, -5, -7
l.sort([](int &u, int &v) { // 1, 2, -3, 4, -5, 6, -7
return abs(u) < abs(v);
});
l.reverse(); // -7, 6, -5, 4, -3, 2, 1
Stack
- #include <stack>
- LIFO(Last in First out) 방식. (먼저 들어간 자료가 나중에 나옴)
- 재귀적 함수를 호출할 때 사용
- 그래프의 깊이 우선 탐색(DFS)에서 사용
선언)) stack<Data Type> 변수이름;
내부 컨테이너 구조를 바꾸는 형식은 stack<Data Type, Container Type> 변수이름;
stack<int> st;
stack<string> st;
stack<int, list<int>> st;
stack<stack, vector<string>> st;
주요 함수
- stack.push(value) : value를 삽입함.
- stack.top() : 맨 위에 있는 인자 반환.
- stack.pop() : top이 가리키는 value를 삭제 함
- stack.empty() : 스택의 empty 여부를 true or false로 반환함.
stack<int> s1;
for(int i = 1; i <= 5; i++) s1.push(i);
for(int i = 0; i < s1.size(); i++) {
cout << s1.top() << ','; /// 5,4,3,
s1.pop();
}
cout << endl;
cout << "s1.size() = " << s1.size() << endl; // s1.size() = 2
for(int i = 10; i >= 6; i--) s1.push(i);
cout << "size = " << s1.size() << endl; //size = 7
cout << "empty = " << s1.empty() << endl; //empty = 0
while(!s1.empty() {
cout << s1.top() << ',';
s1.pop(); // 6,7,8,9,10,2,1,
}
cout << endl;
cout << "size = " << s1.size() << endl; // size = 0
cout <, "empty = " << s1.empty() << endl; // empty = 1
기본 자료형
- stack의 기본 자료 구조(defalut)는 deque.
deque<int> d = {1,2,4,5,3};
stack<int> s1(d);
for(int i = 0; i < 5; i++) {
cout << s1.top() << ','; // 3,5,4,2,1
s1.pop();
}
cout << endl;
vector<int> v = {5,4,3,2,1};
stack<int, vector<int>> s2(v);
for(int i = 0; i < 5; i++) {
cout << s2.top() << ','; // 1,2,3,4,5
s2.pop();
}
cout << endl;
list<int> l = {1,3,2,4,5};
stack<int, list<int>> s3(l);
for(int i = 0; i < 5; i++) {
cout << s3.top() << ','; // 5,4,2,3,1
s3.pop();
}
cout << endl;
Queue
- #include <queue>
- FIFO(First in, First out) 방식으로 동작
- deque와 list container에 붙어서 사용. (vector 는 불가능 / 앞에서 빼주는 기능 지원 x)
- BFS(너비우선탐색)
선언)) queue <Data Type> 변수이름;
내부 컨테이너 구조를 바꾸는 형식은 queue <Data Type, Container Type> 변수이름;
queue<int> q;
queue<string, list<string>> q;
주요 함수
- queue.push(value) : 맨 뒤에 value를 집어 넣는다.
- queue.front() : 맨 앞의 원소를 참조
- queue.back() : 마지막 원소를 참조
- queue.pop() : 맨 앞에 있는 원소를 삭제
deque<int> d = {1,2,4,5,3};
queue<int> q(d);
for(int i = 0 ; i < 2; i++) {
cout << q.front() << ',' >> q.back() << endl; /// 1,3
q.pop(); /// 2,3
}
cout << "size = " << q.size() << endl; /// size = 3
cout << "size = " << q.empty() << endl; /// empty = 0
priority_queue (우선순위 큐)
- #include <queue>
- 정렬기준 기본값은 내림차순 ( 높은 수를 위에 배치)
- vector container 기반으로 설정 되어 있음.
기본 생성자 )) priority_queue <Data Type> 변수이름;
내부 컨테이너 변경)) priority_queue <Data Type, Container Type> 변수이름;
정렬 기준 변경 )) priority_queue <Data Type, Container Type, 정렬기준> 변수 이름;
priority_queue<int> pq;
priority_queue<int, deque<int>> pq;
priority_queue<int, vector<int>, greater<int>> pq;
'C++' 카테고리의 다른 글
[C++] <algorithm> 라이브러리 속 유용한 함수 (0) | 2021.12.15 |
---|---|
[C++] Lamda Function와 Function variable (0) | 2021.12.15 |
[C++] Associative Container (Map, Set) (0) | 2021.12.14 |
[C++] Auto, Pair, Tuple 자료형과 Range-based for (0) | 2021.12.14 |