수색…


소개

set 는 요소가 정렬되고 고유 한 컨테이너 유형입니다. multiset 은 유사하지만 multiset 의 경우 여러 요소가 동일한 값을 가질 수 있습니다.

비고

이러한 예제에는 C ++의 다양한 스타일이 사용되었습니다. C ++ 98 컴파일러를 사용하는 경우주의하십시오. 이 코드 중 일부는 사용하지 못할 수도 있습니다.

세트에 값 삽입

세 가지 다른 삽입 방법을 세트와 함께 사용할 수 있습니다.

  • 첫째, 값의 간단한 삽입. 이 메소드는 호출자가 삽입이 실제로 발생했는지 여부를 확인할 수있는 쌍을 리턴합니다.
  • 둘째, 값이 삽입 될 위치에 대한 힌트를 제공하여 삽입합니다. 이 경우 삽입 시간을 최적화하는 것이 목적이지만 값을 삽입해야하는 위치를 아는 것이 일반적인 경우는 아닙니다. 이 경우 조심하십시오. 힌트를주는 방법은 컴파일러 버전에 따라 다릅니다 .
  • 마지막으로 시작 및 끝 포인터를 제공하여 값 범위를 삽입 할 수 있습니다. 시작 부분은 삽입에 포함되고 끝 부분은 제외됩니다.
#include <iostream>
#include <set>

int main ()
{
  std::set<int> sut;
  std::set<int>::iterator it;
  std::pair<std::set<int>::iterator,bool> ret;

  // Basic insert
  sut.insert(7);
  sut.insert(5);
  sut.insert(12);
  
  ret = sut.insert(23);
  if (ret.second==true)
    std::cout << "# 23 has been inserted!" << std::endl;
    
  ret = sut.insert(23); // since it's a set and 23 is already present in it, this insert should fail
  if (ret.second==false)
    std::cout << "# 23 already present in set!" << std::endl;
 
  // Insert with hint for optimization
  it = sut.end();
  // This case is optimized for C++11 and above
  // For earlier version, point to the element preceding your insertion
  sut.insert(it, 30); 

  // inserting a range of values
  std::set<int> sut2;
  sut2.insert(20);
  sut2.insert(30);
  sut2.insert(45);
  std::set<int>::iterator itStart = sut2.begin();
  std::set<int>::iterator itEnd = sut2.end();
  
  sut.insert (itStart, itEnd); // second iterator is excluded from insertion

  std::cout << std::endl << "Set under test contains:" << std::endl;
  for (it = sut.begin(); it != sut.end(); ++it)
  {
    std::cout << *it << std::endl;
  }

  return 0;
}

출력은 다음과 같습니다.

# 23 has been inserted!                                                                                                                                                                                                                                                                                                   
# 23 already present in set!                                                                                                                                                                                                                                                                                              
                                                                                                                                                                                                                                                                                                                          
Set under test contains:                                                                                                                                                                                                                                                                                                  
5                                                                                                                                                                                                                                                                                                                         
7                                                                                                                                                                                                                                                                                                                         
12                                                                                                                                                                                                                                                                                                                        
20                                                                                                                                                                                                                                                                                                                        
23                                                                                                                                                                                                                                                                                                                        
30                                                                                                                                                                                                                                                                                                                        
45   

멀티 세트에 값 삽입하기

세트의 모든 삽입 메소드는 멀티 세트에도 적용됩니다. 그럼에도 불구하고 initializer_list를 제공하는 또 다른 가능성이 존재합니다 :

auto il = { 7, 5, 12 };
std::multiset<int> msut;
msut.insert(il);

세트의 기본 정렬 변경하기

setmultiset 에는 기본 비교 방법이 있지만 경우에 따라 과부하가 필요할 수 있습니다.

문자열 값을 집합에 저장한다고 가정 해 봅시다. 그러나 문자열에 숫자 값만 포함되어 있습니다. 기본적으로 정렬은 사전 식 문자열 비교이므로 순서가 숫자 정렬과 일치하지 않습니다. int 값에 해당하는 것과 동일한 정렬을 적용하려면 compare 메서드를 오버로드 할 수있는 functor가 필요합니다.

#include <iostream>
#include <set>
#include <stdlib.h> 

struct custom_compare final
{
    bool operator() (const std::string& left, const std::string& right) const
    {
        int nLeft = atoi(left.c_str());
        int nRight = atoi(right.c_str());
        return nLeft < nRight;
    }
};

int main ()
{
    std::set<std::string> sut({"1", "2", "5", "23", "6", "290"});
  
    std::cout << "### Default sort on std::set<std::string> :" << std::endl;
    for (auto &&data: sut)
        std::cout << data << std::endl;
  
    std::set<std::string, custom_compare> sut_custom({"1", "2", "5", "23", "6", "290"},
                                                     custom_compare{}); //< Compare object optional as its default constructible.
  
    std::cout << std::endl << "### Custom sort on set :" << std::endl;
    for (auto &&data : sut_custom)
        std::cout << data << std::endl;
  
    auto compare_via_lambda = [](auto &&lhs, auto &&rhs){ return lhs > rhs; };
    using set_via_lambda = std::set<std::string, decltype(compare_via_lambda)>;
    set_via_lambda sut_reverse_via_lambda({"1", "2", "5", "23", "6", "290"},
                                          compare_via_lambda);
  
    std::cout << std::endl << "### Lambda sort on set :" << std::endl;
    for (auto &&data : sut_reverse_via_lambda)
        std::cout << data << std::endl;

    return 0;
}

출력은 다음과 같습니다.

### Default sort on std::set<std::string> :
1
2
23
290
5
6
### Custom sort on set :
1
2
5
6
23
290  

### Lambda sort on set :
6
5
290
23
2
1

위의 예제에서 std::set 비교 연산을 추가하는 3 가지 다른 방법을 찾을 수 있으며, 각각은 자체 컨텍스트에서 유용합니다.

기본 정렬

이것은 키의 비교 연산자 (첫번째 템플릿 인자)를 사용할 것입니다. 종종이 키는 std::less<T> 함수에 대한 좋은 기본값을 제공합니다. 이 함수가 특수화되어 있지 않으면 객체의 operator< 사용합니다. 이는 다른 코드에서도 일부 코드를 사용하려고 할 때 특히 유용합니다. 전체 코드 기반의 일관성을 유지할 수 있기 때문입니다.

이 방법으로 코드를 작성하면 핵심 변경 사항이 API 일 때 코드를 업데이트하는 노력이 줄어 듭니다. 예를 들어 2 명의 멤버가 포함 된 클래스는 3 명의 멤버가 포함 된 클래스로 변경됩니다. 클래스의 operator< 를 업데이트하면 모든 항목이 업데이트됩니다.

예상대로 기본 정렬을 사용하는 것이 적절한 기본값입니다.

사용자 정의 정렬

비교 연산자로 개체를 통해 사용자 지정 정렬을 추가하면 기본 비교가 준수하지 않을 때 자주 사용됩니다. 위의 예에서 문자열은 정수를 나타 내기 때문입니다. 다른 경우에는 참조하는 객체를 기반으로하는 (스마트 한) 포인터를 비교하려는 경우 또는 비교를 위해 다른 제약 조건이 필요하기 때문에 (예 : std::pairfirst 값과 비교하는 경우) 자주 사용됩니다.

비교 연산자를 만들 때 안정된 정렬이어야합니다. 삽입 후 compare 연산자의 결과가 변경되면 정의되지 않은 동작이 발생합니다. 좋은 방법으로 비교 연산자는 상수 데이터 (const 멤버, const 함수 ...) 만 사용해야합니다.

위 예제에서와 같이 비교 연산자로 멤버가없는 클래스가 자주 발생합니다. 기본 생성자 및 복사 생성자가 생성됩니다. 기본 생성자를 사용하면 생성시 인스턴스를 생략 할 수 있으며 set이 compare 연산자의 복사본을 취할 때 복사 생성자가 필요합니다.

람다 정렬

Lambda 는 함수 객체를 작성하는 짧은 방법입니다. 이렇게하면 적은 수의 행에 compare 연산자를 작성하여 전체 코드를보다 쉽게 ​​읽을 수 있습니다.

람다 사용의 단점은 각 람다가 컴파일 할 때 특정 유형을 얻게된다는 것입니다. 따라서 동일한 컴파일 단위 (cpp 파일)의 각 컴파일에 대해 decltype(lambda) 이 여러 컴파일 단위 이상으로 다를 수 있습니다 (헤더 파일 ). 이런 이유 때문에, 헤더 파일 내에서 사용될 때 함수 객체를 비교 연산자로 사용하는 것이 좋습니다.

이 구조는 std::set 이 함수의 로컬 범위 내에서 대신 사용되는 경우 종종 발생하며 함수 객체는 함수 인수 또는 클래스 멤버로 사용될 때 선호됩니다.

다른 정렬 옵션

std::set 의 compare 연산자가 템플릿 인수이기 때문에 호출 가능한 모든 객체 를 compare 연산자로 사용할 수 있으며 위의 예제는 특정 경우에만 있습니다. 이러한 호출 가능한 객체의 유일한 제한은 다음과 같습니다.

  • 복사 가능해야합니다.
  • 키 유형의 2 개의 인수로 호출 가능해야합니다. (암시 적 변환은 허용되지만 성능을 해칠 수 있으므로 권장하지 않음)

set 및 multiset에서 값 검색

std::set 또는 std::multiset 에서 주어진 값을 검색하는 데는 여러 가지 방법이 있습니다.

키의 첫 번째 발생에 대한 반복자를 얻으려면 find() 함수를 사용할 수 있습니다. 키가 존재하지 않으면 end() 반환합니다.

  std::set<int> sut;
  sut.insert(10);
  sut.insert(15);
  sut.insert(22);
  sut.insert(3); // contains 3, 10, 15, 22    

  auto itS = sut.find(10); // the value is found, so *itS == 10
  itS = sut.find(555); // the value is not found, so itS == sut.end()   

  std::multiset<int> msut;
  sut.insert(10);
  sut.insert(15);
  sut.insert(22);
  sut.insert(15);
  sut.insert(3); // contains 3, 10, 15, 15, 22  

  auto itMS = msut.find(10);

또 다른 방법으로는 사용 count() 많은 대응하는 값이 발견 된 방법을 계산 함수 set / multiset (a 경우 set 의 반환 값은 단지 0 또는 1). 위와 같은 값을 사용하면 다음과 같이됩니다.

int result = sut.count(10); // result == 1
result = sut.count(555); // result == 0

result = msut.count(10); // result == 1
result = msut.count(15); // result == 2

std::multiset 의 경우 동일한 값을 갖는 여러 요소가있을 수 있습니다. 이 범위를 얻으려면 equal_range() 함수를 사용할 수 있습니다. iterator lower bound (포함)와 upper bound (exclusive)를 각각 갖는 std::pair 를 반환합니다. 키가 존재하지 않으면, 두 반복자는 가장 가까운 상위 값 (주어진 multiset 를 정렬하는 데 사용되는 비교 메소드를 기반으로 함)을 가리 킵니다.

auto eqr = msut.equal_range(15);
auto st = eqr.first; // point to first element '15'
auto en = eqr.second; // point to element '22'

eqr = msut.equal_range(9); // both eqr.first and eqr.second point to element '10'

세트에서 값 삭제하기

가장 확실한 방법은 set / multiset을 빈 것으로 재설정하고자하는 경우 clear 를 사용하는 것입니다.

  std::set<int> sut;
  sut.insert(10);
  sut.insert(15);
  sut.insert(22);
  sut.insert(3); 
  sut.clear(); //size of sut is 0

그런 다음 erase 방법을 사용할 수 있습니다. 삽입과 다소 비슷하게 보이는 몇 가지 가능성을 제공합니다.

std::set<int> sut;
std::set<int>::iterator it;
          
sut.insert(10);
sut.insert(15);
sut.insert(22);
sut.insert(3); 
sut.insert(30);
sut.insert(33);
sut.insert(45);
    
// Basic deletion
sut.erase(3);
    
// Using iterator
it = sut.find(22);
sut.erase(it);
          
// Deleting a range of values
it = sut.find(33);
sut.erase(it, sut.end());
    
std::cout << std::endl << "Set under test contains:" << std::endl;
for (it = sut.begin(); it != sut.end(); ++it)
{
  std::cout << *it << std::endl;
}

출력은 다음과 같습니다.

Set under test contains:                                                                                                                                                                                                                                                                                                  
10                                                                                                                                                                                                                                                                                                                        
15                                                                                                                                                                                                                                                                                                                        
30 

이러한 모든 방법은 multiset 에도 적용됩니다. multiset 에서 요소를 삭제하라는 메시지가 표시되고 여러 번 나타나면 해당 값이 모두 삭제됩니다 .



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow