[STL] set 정리 및 예제

2019. 7. 30. 00:32 기타/C++ STL

[STL] set 정리 및 예제


set 컨테이너는 연관 컨테이너 중 단순한 컨테이너로 key라 불리는 원소(value).의 집합으로 이루어진 컨테이너이다.

모든 연관 컨테이너는 노드 기반 컨테이너이며 균현 이진 트리로 구현되므로 균형 이진 트리의 모든 특징을 갖는다.



템플릿 형식 

 template<typename Key

, typename Pred=less<Key>

, typename Allocator=allocator<key>>

class set

 Key는 set 컨테이너 원소의 형식이며, Pred는 set의 정렬 기준인 조건자이다. 기본 조건자는 less 이다.



생성자 

 set s;

s는 빈 컨테이너이다. 

 set s(pred)

s는 빈 컨테이너로 정렬 기준은 pred 조건자를 사용한다 

 set s(s2)

s는 s2 컨테이너의 복사본이다. 

 set s(b,e)

s는 반복자 구간 [b,e)로 초기화된 원소를 갖는다. 

 set s(b,e, pred)

s는 반복자 구간 [b,e)로 초기화된 원소를 갖는다. 정렬 기준은 pred 조건자를 이용한다 



멤버 함수 

 p=s.begin()

p는 s의 첫 원소를 가리키는 반복자다 

 s.clear()

s의 모든 원소를 제거한다. 

 n=s.count(k)

원소 k의 개수를 반환한다 

 s.empty()

s가 비었는지 조사한다. 

 p=s.end()

p는 s의 끝을 표식하는 반복자다 

 pr=s.equal_range(k)

pr은 k 원소의 반복자 구간인 pair 객체다 

 q=s.erase(p)

p가 가리키는 원소를 제거한다. q는 다음 원소를 가리킨다. 

 q=s.erase(b,e)

 반복자 구간 [b,e)의 모든 원소를 제거한다. q는 다음 원소다 

 n=s.erase(k)

 k 원소를 모두 제거한다. n은 제거한 개수다.

 p=s.find()

p는 k 원소의 위치를 가리키는 반복자다 

 pr=s.insert(k)

 s 컨테이너에 k를 삽입한다. pr은 삽입한 원소를 가리키는 반복자와 성공 여부의 bool인 pair 객체이다. 

 q=s.insert(p,k)

p가 가리키는 위치부터 빠르게 k를 삽입한다. q는 삽입한 원소를 가리키는 반복자 

 s.insert(b,e)

반복자 구간 [b,e)의 원소를 삽입한다. 

 pred=s.key_comp()

pred는 s의 key 정렬 기준인 조건자다 (key_compare 타입) 

 p=s.lower_bound(k)

p는 k의 시작 구간을 가리키는 반복자다 

 n=s.max_size()

n는 s가 담을 수 있는 최대 원소의 개수다(메모리 크기) 

 p=s.rbegin()

p는 s의 역 순차열의 첫 원소를 가리키는 반복자다 

 p=s.rend()

p는 s의 역 순차열의 끝을 표식하는 반복자다 

 s.size()

s 원소의 개수다 

 s.swap(s2)

s와 s2를 swap한다. 

 p=s.upper_bound(k)

p는 k의 끝 구간을 가리키는 반복자다 

 pred=s.value_comp()

pred는 s의 value 정렬 기준인 조건자다 



연산자 

 s1 == s2

s1과 s2의 모든 원소가 같은가? (bool) 

 s1 != s2

s1과 s2의 모든 원소 중 하나라도 다른 원소가 있는가 

 s1 < s2

문자열 비교처럼 s2가 s1보다 큰가? 

 s1 > s2

문자열 비교처럼 s2가 s1 보다 작은가? 



멤버 형식 

 allocator_type

메모리 관리자 형식 

 const_iterator

const 반복자 형식 

 const_pointer

const value_type* 형식 

 const_reference

const value_type& 형식 

 const_reverse_iterator

const의 역 반복자 형식 

 difference_type

 두 반복자 차이의 형식 

 iterator

반복자 형식 

 key_compare

키 (key) 조건자(비교) 형식 (set은 key 가 value이므로 value_compare와 같다

 key_type

키(key)의 형식 

 pointer

value_type* 형식 
 referencevalue_type& 형식 
 reverse_iterator역 반복자 형식 
 size_type첨자(index)나 원소의 개수 등의 형식 
 value_compare 원소 조건자 형식
 value_type원소의 형식 


연관 컨테이너는 정렬 기준이 있으므로 insert()에 의해 삽입된 원소는 자동 정렬된다.

set 에서 원소를 key라 하며 이 키를 비교하여 내부 원소를 정렬한다.

set은 모든 원소가 유일하다. 원소의 중복을 허용해야 한다면 multiset 을 사용해야 한다.


정렬 기준은 템플릿 매개변수에 지정할 수 있으며, 기본 정렬 기준은 less 조건자이다.

연관 컨테이너는 시퀀스 컨테이너가 제공하는 순서와 관련된 함수류인 push_back(), push_front(), pop_back(), pop_front()와 시작, 끝 원소의 참조 멤버 함수 fron(), back()을 제공하지 않는다.


연관 컨테이너는 균형 이진 트리를 사용하므로 찾기 연산 (find(), lower_bound(), upper_bound(), equal_range(), count())에 뛰어난 성능(로그 시간)을 보이며 insert() 멤버 함수를 이용한 삽입도 로그 시간 복잡도를 보인다.


연관 컨테이너는 양방향 반복자를 지원하며 멤버 변수 begin(), end(), rbegin(), rend()는 순차열의 시작과 끝을 가리키는 반복자를 반환한다.


#include <iostream>
#include <set>
#include <functional>
using namespace std;

int main(){

    set<int> s;

    pair<set<int>::iterator, bool> pr;
    pr = s.insert(50);    // insert 결과 pair 반환
    s.insert(40);
    s.insert(80);

    if (true == pr.second)
        cout << *pr.first << " 삽입 성공!" << endl;
    else
        cout << *pr.first << "가 이미 있습니다. 삽입 실패! " << endl;

    set<int>::iterator iter;
    for (iter = s.begin(); iter != s.end(); ++iter){
        cout << *iter << " ";
    }
    cout << endl;

    pr = s.insert(50);        // 중복 값 insert
    if (true == pr.second)
        cout << *pr.first << " 삽입 성공!" << endl;
    else
        cout << *pr.first << "가 이미 있습니다. 삽입 실패!" << endl;

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

    s.insert(pr.first, 60);        // 50 위치에 값 50 바로 삽입

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

    set<int, greater<int>> s2;        // 내림차순 정렬
    s2.insert(50);
    s2.insert(30);
    s2.insert(80);
    s2.insert(40);
    s2.insert(10);
    s2.insert(70);
    s2.insert(90);

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

    // key_compare, value_compare 확인
    cout << "key_compare less : " << typeid(s.key_comp()).name() << endl;
    cout << "key_compare greater : " << typeid(s2.key_comp()).name() << endl;

    cout << "value_compare less : " << typeid(s.value_comp()).name() << endl;
    cout << "value_compare greater : " << typeid(s2.value_comp()).name() << endl;

    return 0;
}



결과 :

50 삽입 성공!

40 50 80

50가 이미 있습니다. 삽입 실패!

40 50 80

40 50 60 80

90 80 70 50 40 30 10

key_compare less : struct std::less<int>

key_compare greater : struct std::greater<int>

value_compare less : struct std::less<int>

value_compare greater : struct std::greater<int> 



set 에는 원소를 insert() 하면 정렬 기준에 따라 정렬된 위치에 insert가 된다.

insert() 결과로 삽입 성공 여부 pair를 반환한다.


pair.first 는 값 위치의 iterator 이며, pair.second 는 삽입 성공 여부 bool 형이 지정된다.

set은 중복을 허용하지 않기 때문에 존재하는 값을 insert 하면 실패하게 된다.


key_comp()는 컨테이너의 key의 정렬 기준을 반환하고, value_comp()는 원소 값의 정렬 기준을 반환한다.

set 에서는 key가 value 이므로 같은 값을 반환함을 볼 수 있다.


#include <iostream>
#include <set>
#include <functional>
using namespace std;

int main(){

    set<int> s;

    s.insert(40);
    s.insert(30);
    s.insert(50);
    s.insert(80);
    s.insert(10);
    s.insert(90); 
    s.insert(70);

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

    // count는 해당 원소의 개수를 반환한다. set은 중복을 허용하지 않으므로 1 또는 0이다.
    cout << "원소 50의 개수 : " << s.count(50) << endl;
    cout << "원소 100의 개수 : " << s.count(100) << endl;

    // find는 해당 원소를 찾는다. 원소가 없으면 end() 를 반환한다.
    iter = s.find(30);
    if (iter != s.end())
        cout << *iter << "가 s에 있다" << endl;
    else
        cout << "30이 s에 없다." << endl;

    
    set<int>::iterator iter_lower;
    set<int>::iterator iter_upper;

    iter_lower = s.lower_bound(30);        // 30 원소의 첫번째
    iter_upper = s.upper_bound(30);        // 30 원소 마지막의 다음 원소
    cout << *iter_lower << endl;
    cout << *iter_upper << endl;

    iter_lower = s.lower_bound(55);
    iter_upper = s.upper_bound(55);
    
    // 55의 첫번째 원소와 다음원소를 가리키는 iter가 같으면 값이 없다
    if (iter_lower != iter_upper)        
        cout << "55가 s에 있다" << endl;
    else
        cout << "55가 s에 없다" << endl;


    // equal_range는 해당 원소의 범위를 pair로 반환한다.
    pair<set<int>::iterator, set<int>::iterator> iter_pair;
    
    iter_pair = s.equal_range(30);
    cout << *iter_pair.first << endl;
    cout << *iter_pair.second << endl;

    iter_pair = s.equal_range(55);
    if (iter_pair.first != iter_pair.second)
        cout << "55가 s에 있다 " << endl;
    else
        cout << "55가 s에 없다 " << endl;

    return 0;
}



결과 :

10 30 40 70 80 90

원소 50의 개수 : 1

원소 100의 개수 : 0

30가 s에 있다

30

40

55가 s에 없다

30

40

55가 s에 없다


count() 함수는 컨테이너의 해당 원소 갯수를 반환한다. set은 중복을 허용하지 않으므로 1 또는 0 이 반환된다.


find() 함수는 해당 원소의 iter 를 찾아서 반환한다. 해당 원소가 컨테이너에 없다면 end()에 해당하는 끝표시 위치를 반환한다.

연관 컨테이너는 key를 이용하여 노드를 찾을 때 == 연산을 사용하지 않는다. 연관 컨테이너는 정렬 기준에 의해 key가 정렬되어 있으므로 컨테이너의 정렬 기준 조건자를 이용해 찾기 연산을 수행한다.

ex > (!s.key_comp()(a,b) && !s.key_comp()(b,a)) 로 원소와 노드 값을 비교한다.


lower_bound()는 해당 원소 중 첫번째 위치를 반환하고 upper_bound()는 해당 원소 마지막 위치 다음 위치를 반환 한다

따라서 해당 원소의 구간은 [lower_bound(), upper_bound()) 가 된다

이 구간 pair 를 찾아주는 함수가 equal_range() 이다.



출처: https://hyeonstorage.tistory.com/327?category=614599 [개발이 하고 싶어요]

'기타 > C++ STL' 카테고리의 다른 글

[STL] multimap 정리 및 예제  (0) 2019.07.30
[STL] map 정리 및 예제  (0) 2019.07.30
[STL] multiset 정리 및 예제  (0) 2019.07.30
[STL] list 정리 및 예제  (0) 2019.07.30
[STL] deque 정리 및 예제  (0) 2019.07.30
[STL] vector 벡터 정리 및 예제  (0) 2019.07.30
[STL] not2 함수  (0) 2019.07.30
[STL] 역방향 반복자 (reverse_iterator)  (1) 2019.07.30