본문 바로가기
Language/C++

14.STL

by 아무키 2023. 12. 25.
반응형

STL : Standard template library

템플릿을 사용해 구현된 컨테이너의 집합

널리 사용되는 자료구조와 알고리즘이 구현되어 있음

시간 복잡도는 레퍼런스 문서에서 찾아 볼 수 있다.

Powerful, reusable, adaptable, generic, HUGE

 

구성요쇼

컨테이너

→ 객체 또는 기본 자료형의 집합

→ array, vector, deque, stack, set, map, etc.

→ 각 컨테이너는 관련된 헤더 파일 포함 필요 (#include <컨테이너 이름>)

알고리즘

→ 컨테이너의 요소들을 다루기 위한 알고리즘

→ find, max, count, accumulate, sort, etc.

반복자(iterators)

→ 컨테이너의 요소들에 대한 순회 및 접근

→ forward, reverse, by value, by reference, constant, etc.

 

컨테이너의 종류

Sequential 컨테이너

→ 삽입 순서를 유지하는 컨테이너

→ array, vector, list, forward_list, deque

Associative 컨테이너

→ 순서가 없거나, 미리 정해진 규칙에 따라 저장하는 컨테이너

→ set, multi set, map, multi map

컨테이너 어댑터

→ 다른 컨테이너들의 변형 응용

→ stack, queue, priority queue

 

컨테이너의 공통 기능

default constructor

overloaded constructors

copy constructors

move constructors

destructor

copy assignment (operator=)

move assignment (operator=)

size()

empty()

insert

operator< and operator≤…

swap

earse

clear

begin and end

rbegin and rend

cbegin and cend

crbegin and crend

 

요소는 복사되어 컨테이너에 저장됨

기본 자료형은 모두 가능

사용자 정의 자료형(클래스)은 복사가 가능하고, 대입이 가능해야 함

→ 즉 복사생성자 / 대입 연산자 필요하다. ← 포인터 멤버 변수가 없다면 ok

Associative 컨테이너의 경우, 비교 연산을 수행할 수 있어야 한다.

→ 즉 operator<, operator== 오버로딩 필요

 

반복자 (iterator)

 

컨테이너의 요소에 대해 추상적인 접근을 가능하게 하는 기능

→ 추상적 : 컨테이너가 무슨 종류인지, 어떻게 구현되어 있는지 알 필요 없다

..포인터와 유사하게 사용 가능

..대부분의 컨테이너는 반복자를 사용해 순환(traverse) 가능

→ stack, queue는 제외

반복자의 선언

반복자가 사용될 컨테이너의 타입을 명시적으로 표기

vector<int>::iterator it1;
//컨테이너 타입<컨테이너 내 요소의 자료형>
list<string>::iterator it2;

map<string, string>::iterator it3;

set<char>::iterator it4;
#include <iostream>
#include <vector>

int main(){
	std::vector<int> v{1 ,2, 3};
	std::set<int> s{1,2,3};

	vector<int>::iterator it1;
	set<int>::iterator it2;

	return 0;
}

 

반복자의 begin과 end

vector<int> v{1,2,3};

// v.begin()은 1
// v.end()은 마지막 요소(3)의 뒤를 가리킴에 주의

 

반복자의 사용

for문과 반복자를 사용한 vector 순환

vector<int> v{1, 2, 3};

for(auto it = v.begin(); it != v.end(); it++){
	cout << *it << ' ';
}

//1 2 3

while(it != v.end()){
	cout << *it << ' ';
	++it;
}

// 1 2 3

 

반복자의 초기화

vector<int> v{1,2,3}; // 벡터 컨테이너의 선언
vector<int>::iterator it = v.begin();
//벡터 컨테이너의 반복자 선언 및 초기화
auto it = v.begin();
//벡터 컨테이너의 반복자의 효율적인 선언 및 초기화 문법

 

auto 키워드

자동으로 타입을 추정해주는 키워드

타입이 길어질 경우 사용하면 편리

→ 남용할 경우 코드의 가독성을 해칠 수 있다.

int Add(int a, int b){
	return a + b;
}

int main(){
	int a = 5;
	auto b = 5;
	auto c = b;

	auto d = Add(2,3);
}
int main(){
	vector<int> v{1, 4, 7};
	auto it = v.begein();
	it += 2;

	cout << *it; // 7이 출력 됨

 

역 반복자(reverse iterator)

역순으로 동작

마지막 요소가 첫 요소가 되는 반복자

++및 —를 반대 방향으로 생각

vector<int> v{1,2,3};

vector<int>::reverse_iterator it = v.rbegin();

while(it != v.rend()){
	cout << *it <<' ';
	++it;
}

// 3 2 1

 

STL의 알고리즘 (STL Algorithms)

 

반복자에 의해 지정된 요소 집합에 대해 수행되는 알고리즘

매우 다양한 알고리즘이 구현되어 있다.

알고리즘을 사용하기 위해 함수를 인자로써 제공해야 하는 경우가 존재

함수를 인자로써 제공하는 방법

→ Functor

→ Function pointer

→ Lambda expression(C++ 11)

 

알고리즘과 반복자

#include <algorithm>

컨테이너에 따라서 적용할 수 있는 알고리즘이 다름

모든 알고리즘은 반복자를 인자로 필요로 함

 

반복자의 유효성

반복자가 유효하지 않을 수 있다.

예를 들어 iterator가 가리키고 있는 요소가 삭제되면?

→iterator가 유효하지 않아짐

 

알고리즘 예시 1 : find

find 알고리즘은 컨테이너 내 어떤 요소가 첫 번째로 나타나는 지점을 찾아줌

해당 지점을 가리키는 반복자를 반환하거나, end()를 반환함

→ end()를 반환하는 경우, 해당 요소가 컨테이너 내에 없다는 뜻

vector<int> v{1, 3, 4};

auto loc = find(v.begin(), v.end(), 3;

if(loc != v.end()){
	cout << *loc << endl; // 2
}

 

find 알고리즘의 사용을 위해서는 요소들을 비교할 수 있어야 함

operator==이 사용되므로, 클래스의 경우 오버로딩이 필요

→ 오버로딩이 되어있어야만 아래 코드처럼 사용 가능

v<Player> team{...}
Player p{"Ha", 100 ,12};

auto loc = find(team.begin(), team.end(), p);

if(loc != v.end()){
	cout << *loc << endl;
}

 

알고리즘 예시 2, for_each

for_each 알고리즘은 컨테이너 내 각 요소를 인자로 함수를 호출

 

컨테이너의 각 요소를 제곱하는 경우의 예제

함수를 인자로 넘기는 방법

→ functor

→ function pointer

→ lambda expression

 

Functor 사용

함수(처럼 사용 가능한) 객체

→( ) 연산자의 오버로딩

struct Square_Functor{
	void operator()(int x) // () 연산자 오버로딩
	{
		cout << x * x << ' ';
	}
};
Square_Functor square; // function object

vector<int> v{1,2,3,4};

for_each(v.begin(), v.end(), square);
//1 4 9 16

 

function pointer의 사용

함수의 주소값을 인자로 전달

square()와 square의 차이?

→ 함수의 호출 / 함수의 주소값

void square(int x){
	cout << x * x << ' ';
}

vector<int> v{1,2,3,4};

for_each(v.begin(), v.end(), square);
// 1 4 9 16
//cout << square 을 할 경우 square의 주소값 출력

 

lambda expression의 사용

익명 함수

함수에 이름을 부여하지 않고, 한번 사용하고 버리는 함수 구현에 사용

vector<int> v{1, 2, 3, 4};

for_each(v.begin(), v.end()), 
	[](int x){
	cout << x * x << ' ';
	}) // lambda

//1 4 9 16
반응형

'Language > C++' 카테고리의 다른 글

16.예외처리등 기타  (0) 2023.12.25
15.STL Containers  (0) 2023.12.25
13.제네릭 프로그래밍  (0) 2023.12.25
12.연산자 오버로딩  (1) 2023.12.25
11.다형성  (1) 2023.12.25

댓글