배움 저장소

[홍정모의 따라하며 배우는 C++] 16. 표준 템플릿 라이브러리 본문

Programming Language/C++

[홍정모의 따라하며 배우는 C++] 16. 표준 템플릿 라이브러리

시옷지읏 2022. 1. 1. 17:32

16.1 표준 템플릿 라이브러리, 컨테이너 소개

Standard Template Libraries and Containers


- STL은 Standard Template Library의 줄임말이다. Algorithms, Containers, Iterators, Functions가 있다.

- STL과 Standard Library를 구분하지 않고 사용하기도 한다.

- Standard Library를 특별히 공부하기 보다 필요할 때 필요한 내용을 찾아서 사용함이 현명하다.

ㄴ https://en.cppreference.com/w/cpp/header

 

Container

여러 자료형을 쉽게 다룰 수 있도록 만든 클래스로 여러 기능이 멤버함수로 구현되어있다.

https://en.cppreference.com/w/cpp/container

 

Containers library - cppreference.com

The Containers library is a generic collection of class templates and algorithms that allow programmers to easily implement common data structures like queues, lists and stacks. There are three classes of containers -- sequence containers, associative cont

en.cppreference.com

 

container는 3가지 종류로 나뉜다. sequeunce container, associative container, container adapter.

(1) Sequence Container

ㄴ vector : 메모리 맨 뒤에 데이터를 추가할 수 있다.

ㄴ deque : 메모리 맨 앞/뒤 상관없이 데이터를 추가할 수 있다.

deque<int> deq; // #include <deque>
for (unsigned i = 0; i < 10; ++i) {
    deq.push_front(i);
    deq.push_back(i);
}

 

(2) Associatvie Container

ㄴ set : set은 중복되는 값은 무시한다.

set<int> test_set; // include <set>
test_set.insert(1);
test_set.insert(1);
test_set.insert(2);

for(auto& e:test_set)
    cout << e << " ";

위 코드에서 1을 두 번 삽입하였으나 한 번만 저장됨을 알 수 있다.

>> 1 2

 

ㄴ multiset : set과 달리 중복되는 값도 넣을 수 있다

multiset<int> test_set; // include <set>
test_set.insert(1);
test_set.insert(2);
test_set.insert(1);

for(auto& e:test_set)
    cout << e << " ";

아래 출력값을 보자. 순서가 바뀌어있다. 1 2 1이 출력될 거 같지만 중복되는 값은 함께 묶어준다.

>> 1 1 2

 

ㄴmap : key와 value를 대응하여 사용한다. 연산자 [ ]가 오버로딩되어 있다. 

등록되지 않은 key에 value를 할당하면 새로운 공간을 만든다. 등록된 key에 value를 할당하면 다른 값을 삽입한다.

map<char, int> test_map;
test_map['c'] = 3;
test_map['b'] = 2;
test_map['a'] = 1;

cout << test_map['a'] << endl;
test_map['a'] = 10;
cout << test_map['a'] << endl;

for(auto& e:test_map)
    cout << "k:" << e.first << " v:" << e.second << endl;

이 때 출력값이 정렬되어있음을 확인하자. 위 코드에서 'c' - 'b' - 'a' 순서로 key를 사용하였다. 자료구조 때 배운다.

>> 1
>> 10
>> k:a v:10
>> k:b v:2
>> k:c v:3

 

ㄴmultimap : multimap은 동일한 key에 여러 값을 담을 수 있다.

- 아래는 'c'-'b'-'a'순서로 값을 삽입하였지만 정렬되어 출력된다.

multimap<char, int> test_multimap; // include <map>
test_multimap.insert(std::pair('c', 3)); // Before C++ 14,
test_multimap.insert(std::pair('b', 2)); // you have to use pair
test_multimap.insert(std::pair('a', 1)); // like this
test_multimap.insert(std::pair('a', 10)); // pair<char,int>('a',1)

cout << test_multimap.count('a') << endl; // how many key 'a'

for(auto& e:test_multimap)
    cout << "k:" << e.first << " v:" << e.second << endl;

count( )는 해당 key가 몇 개의 값을 가지고있는지 출력한다.

>> 2
>> k:a v:1
>> k:a v:10
>> k:b v:2
>> k:c v:3

 

(3) container adapters

ㄴstack : FIFO구조이다. FIFO(First In Last Out으로 먼저 들어온 값이 나중에 나간다)

 

멤버함수 push vs emplace

- push는 인자로 들어온 인스턴스사용한다. 단일 인스턴스만 사용가능하다.

- emplace는 해당 인스턴스를 사용하지 않고 새로운 생성자를 호출한다. emplace는 여러 인스턴스를 사용할 수 있다.

stack<int> stk; // #include <stack>
stk.push(1);    // 'push' add a copy
stk.emplace(2); // 'emplace' construct new obj

cout << stk.top() << endl;
stk.pop();
cout << stk.top() << endl;

 

ㄴqueue : LIFO를 사용한다. LIFO(Last in First Out으로 나중에 들어온 값이 먼저 나간다.)

std::queue<int> que; // #include<queue>
que.push(1);
que.push(2);
que.push(3);

cout << que.front() << " " << que.back() << endl;
que.pop();
cout << que.front() << " " << que.back() << endl;
>> 1 3
>> 2 3

 

ㄴpriority queue : queue에 정렬기능이 더해져있다.

클래스를 만들어 priority queue에서 사용하려면 비교 연산자를 오버로딩해야 한다.

priority_queue<int> p_que; // #include <queue>
for(const int i: {7, 2, 4, 8, 6, 3, 9, 1, 5})
    p_que.push(i);

while(p_que.size()) {
    int size = p_que.size();
    cout << p_que.top() << " ";
    p_que.pop();
}
>> 9 8 7 6 5 4 3 2 1

 

16.2 STL 반복자 소개

Iterators


Iterator(반복자)를 활용한 예제이다

vector<int> container;
for (unsigned i = 0; i < 10; ++i)
    container.push_back(i);

//vector<int>::iterator itr;
vector<int>::const_iterator itr;
/* Iteraotr with while-loop */
itr = container.begin();
while (itr != container.end()) {
    cout << *itr << " ";
    ++itr;
}
cout << endl;


/* Iteraotr with for-loop */
for (auto iter = container.begin(); iter != container.end(); ++iter)
    cout << *iter << " ";
cout << endl;

container를 변경하여도 위 iterator를 사용할 수 있어 유용하다. 아래 예제 모두 위에있는 코드로 실행할 수 있다.

list<int> container;
for (unsigned i = 0; i < 10; ++i)
    container.push_back(i);

list<int>::const_iterator itr;
array<int,10> container;
for (unsigned i = 0; i < 10; ++i)
    container[i] = i;

array<int, 10>::const_iterator itr;
set<int> container;
for (unsigned i = 0; i < 10; ++i)
    container.insert(i);

set<int>::const_iterator itr;

map은 출력할 때 first와 second가 나뉘어져 있으므로 위의 실행코드를 조금 고쳐주어야 한다.

map<char,int> container;
for (unsigned i = 0; i < 10; ++i)
    container[char('a'+i)] = i;

map<char,int>::const_iterator itr;

 

16.3 STL 알고리즘 소개


STL container를 유용하게 사용할 수 있도록 도와주는 STL 알고리즘을 알아보자.

https://en.cppreference.com/w/cpp/algorithm

 

Algorithms library - cppreference.com

The algorithms library defines functions for a variety of purposes (e.g. searching, sorting, counting, manipulating) that operate on ranges of elements. Note that a range is defined as [first, last) where last refers to the element past the last element to

en.cppreference.com

 

<algorithm>에서 자주 사용하는 함수

vector<int> container;
for(int i=0; i<10; ++i)
    container.push_back(i);

/* get MIN */
auto itr = min_element(container.begin(), container.end());
cout << *itr << endl;

/* get MAX */
itr = max_element(container.begin(), container.end());
cout << *itr << endl;

/* find 4, insert -1 infrot of it */
itr = find(container.begin(), container.end(), 4);
container.insert(itr, -1);
for(auto&e : container) cout << e << " ";
cout << endl;

/* Sort */
sort(container.begin(), container.end());
for (auto& e : container) cout << e << " ";
cout << endl;

/* Sort Reversed order */
reverse(container.begin(), container.end());
for (auto& e : container) cout << e << " ";
cout << endl;

 

이 때 list는 sort함수를 호출하면 에러가 발생한다. 내부에 구현된 멤버함수 sort를 사용해주자. 자료구조에서 list와 vector의 차이를 알게되면 왜 이렇게 되는지 알게된다. STL container에 따라 사용법이 조금씩 달라짐을 확인하자. 

list<int> li;

// sort(li.begin(), li.end()); // Error!
li.sort();

직접 구현한 클래스에서 STL 알고리즘을 사용하려면 비교연산자 오버로딩을 해주자.

Comments