순열 알고리즘 (Permutation Algorithm)

  • is_permutation 두 컨테이너의 원소들이 (순서 상관없이) 일치하면 true, 그렇지 않으면 false를 반환.

    • 두번째가 첫번째의 순열이면 true.

// since C++11 until C++20
template< class ForwardIt1, class ForwardIt2 >
bool is_permutation( ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2 );

template< class ForwardIt1, class ForwardIt2, class BinaryPredicate >
bool is_permutation( ForwardIt1 first1, ForwardIt1 last1,
                     ForwardIt2 first2, BinaryPredicate p );

// since C++20
template< class ForwardIt1, class ForwardIt2 >
constexpr bool is_permutation( ForwardIt1 first1, ForwardIt1 last1,
                               ForwardIt2 first2 );

template< class ForwardIt1, class ForwardIt2, class BinaryPredicate >
constexpr bool is_permutation( ForwardIt1 first1, ForwardIt1 last1,
                               ForwardIt2 first2, BinaryPredicate p );

template< class ForwardIt1, class ForwardIt2 >
constexpr bool is_permutation( ForwardIt1 first1, ForwardIt1 last1,
                               ForwardIt2 first2, ForwardIt2 last2 );

template< class ForwardIt1, class ForwardIt2, class BinaryPredicate >
constexpr bool is_permutation( ForwardIt1 first1, ForwardIt1 last1,
                               ForwardIt2 first2, ForwardIt2 last2,
                               BinaryPredicate p );

// since C++14 until C++20
template< class ForwardIt1, class ForwardIt2 >
bool is_permutation( ForwardIt1 first1, ForwardIt1 last1,
                     ForwardIt2 first2, ForwardIt2 last2 );

template< class ForwardIt1, class ForwardIt2, class BinaryPredicate >
bool is_permutation( ForwardIt1 first1, ForwardIt1 last1,
                     ForwardIt2 first2, ForwardIt2 last2,
                     BinaryPredicate p );

// ----------------------------------------------------------------------------------
#include <iostream>
#include <algorithm>
using namespace std;

template<typename Os, typename V>
Os& operator<< (Os& os, V const& v) {
    os << "{ ";
    for (auto const& e : v) os << e << ' ';
    return os << "}";
}

int main() {
    static constexpr auto v1 = {1,2,3,4,5};
    static constexpr auto v2 = {3,5,4,1,2};
    static constexpr auto v3 = {3,5,4,1,1};

    cout << v2 << " is a permutation of " << v1 << ": " << boolalpha
         << is_permutation(v1.begin(), v1.end(), v2.begin()) << endl
         << v3 << " is a permutation of " << v1 << ": " << boolalpha
         << is_permutation(v1.begin(), v1.end(), v3.begin()) << endl;

    return 0;
}

/*
$ g++ test.cpp -std=c++14
$ ./a.out
{ 3 5 4 1 2 } is a permutation of { 1 2 3 4 5 }: true
{ 3 5 4 1 1 } is a permutation of { 1 2 3 4 5 }: false
 */
  • next_permutation 주어진 범위 내 원소들을 다음 순서로 섞은 뒤 true 반환, 다음 순서가 없으면 false 반환.

    • 사전순으로 정렬되었다고 가정하고, 다음 순서는 사전순으로 다음에 오는 것을 의미.

    • 시간 복잡도: O(N / 2), 범위의 크기 = N

// until C++20
template< class BidirIt >
bool next_permutation( BidirIt first, BidirIt last );

template< class BidirIt, class Compare >
bool next_permutation( BidirIt first, BidirIt last, Compare comp );

// since C++20
template< class BidirIt >
constexpr bool next_permutation( BidirIt first, BidirIt last );

template< class BidirIt, class Compare >
constexpr bool next_permutation( BidirIt first, BidirIt last, Compare comp );

// ----------------------------------------------------------------------------------
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

int main() {
    string s = "aba";
    sort(s.begin(), s.end());
    do {
        cout << s << endl;
    } while(next_permutation(s.begin(), s.end()));
    return 0;
}

/*
$ g++ test.cpp -std=c++11
$ ./a.out
aab
aba
baa
 */
  • prev_permutation 주어진 범위 내 원소들을 이전 순서로 섞고 true 반환, 이전 순서가 없으면 false 반환.

    • 이전 순서가 없다는 것은 원소들이 사전순으로 정렬되어 있다는 의미.

    • 시간 복잡도: O(N / 2), 범위의 크기 = N

// until C++20
template< class BidirIt >
bool prev_permutation( BidirIt first, BidirIt last );

template< class BidirIt, class Compare >
bool prev_permutation( BidirIt first, BidirIt last, Compare comp );

// since C++20
template< class BidirIt >
constexpr bool prev_permutation( BidirIt first, BidirIt last );

template< class BidirIt, class Compare >
constexpr bool prev_permutation( BidirIt first, BidirIt last, Compare comp );

// ----------------------------------------------------------------------------------
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

int main() {
    string s = "abcd";
    sort(s.begin(), s.end(), greater<char>());
    do {
        cout << s << endl;
    } while(prev_permutation(s.begin(), s.end()));
    return 0;
}

/*
$ g++ test.cpp -std=c++11
$ ./a.out
dcba
dcab
dbca
dbac
dacb
dabc
cdba
cdab
cbda
cbad
cadb
cabd
bdca
bdac
bcda
bcad
badc
bacd
adcb
adbc
acdb
acbd
abdc
abcd
 */

 

이진 탐색 알고리즘 (Binary Search Algorithm)

  • 시간 복잡도: O(log2(N)), 범위의 크기 = N

  • 이미 정렬된 상태에서 수행해야 하며, 비교자 함수를 별도로 지정할 수 있음.

  • lower_bound 특정 값보다 크거나 같은 원소들 중 가장 작은 값(하한)의 iterator를 반환.

// until C++20
template< class ForwardIt, class T >
ForwardIt lower_bound( ForwardIt first, ForwardIt last, const T& value );

template< class ForwardIt, class T, class Compare >
ForwardIt lower_bound( ForwardIt first, ForwardIt last, const T& value, Compare comp );

// since C++20
template< class ForwardIt, class T >
constexpr ForwardIt lower_bound( ForwardIt first, ForwardIt last, const T& value );

template< class ForwardIt, class T, class Compare >
constexpr ForwardIt lower_bound( ForwardIt first, ForwardIt last,
                                 const T& value, Compare comp );

// ----------------------------------------------------------------------------------
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

struct PriceInfo { double price; };

int main() {
    const vector<int> data = { 1, 2, 4, 5, 5, 6 };
    for (int i = 0; i < 8; ++i) {
        // Search for first element x such that i ≤ x
        auto lower = lower_bound(data.begin(), data.end(), i);

        cout << i << " ≤ ";
        lower != data.end()
            ? cout << *lower << " at index " << distance(data.begin(), lower)
            : cout << "[not found]";
        cout << endl;
    }

    vector<PriceInfo> prices = { {100.0}, {101.5}, {102.5}, {102.5}, {107.3} };
    for(double to_find: {102.5, 110.2}) {
        auto prc_info = lower_bound(prices.begin(), prices.end(), to_find,
                                    [](const PriceInfo& info, double value){
                                        return info.price < value;
                                    });
        prc_info != prices.end()
            ? cout << prc_info->price << " at index " << prc_info - prices.begin()
            : cout << to_find << " not found";
        cout << endl;
    }

    return 0;
}

/*
$ g++ test.cpp -std=c++11
$ ./a.out
0 ≤ 1 at index 0
1 ≤ 1 at index 0
2 ≤ 2 at index 1
3 ≤ 4 at index 2
4 ≤ 4 at index 2
5 ≤ 5 at index 3
6 ≤ 6 at index 5
7 ≤ [not found]
102.5 at index 2
110.2 not found
 */
  • upper_bound 특정 값보다 큰 원소들 중 가장 작은 값(상한)의 iterator를 반환.

// until C++20
template< class ForwardIt, class T >
ForwardIt upper_bound( ForwardIt first, ForwardIt last, const T& value );

template< class ForwardIt, class T, class Compare >
ForwardIt upper_bound( ForwardIt first, ForwardIt last, const T& value,
                       Compare comp );

// since C++20
template< class ForwardIt, class T >
constexpr ForwardIt upper_bound( ForwardIt first, ForwardIt last, const T& value );

template< class ForwardIt, class T, class Compare >
constexpr ForwardIt upper_bound( ForwardIt first, ForwardIt last, const T& value,
                                 Compare comp );

// ----------------------------------------------------------------------------------
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

struct PriceInfo { double price; };

int main() {
    const vector<int> data = { 1, 2, 4, 5, 5, 6 };
    for (int i = 0; i < 7; ++i) {
        // Search first element that is greater than i
        auto upper = upper_bound(data.begin(), data.end(), i);

        cout << i << " < ";
        upper != data.end()
            ? cout << *upper << " at index " << distance(data.begin(), upper)
            : cout << "not found";
        cout << endl;
    }

    vector<PriceInfo> prices = { {100.0}, {101.5}, {102.5}, {107.3}, {109.8} };
    for(double to_find: {102.5, 110.2}) {
        auto prc_info = upper_bound(prices.begin(), prices.end(), to_find,
                                    [](double value, const PriceInfo& info){
                                        return value < info.price;
                                    });
        prc_info != prices.end()
            ? cout << prc_info->price << " at index " << prc_info - prices.begin()
            : cout << to_find << " not found";
        cout << endl;
    }

    return 0;
}

/*
$ g++ test.cpp -std=c++11
$ ./a.out
0 < 1 at index 0
1 < 2 at index 1
2 < 4 at index 2
3 < 4 at index 2
4 < 5 at index 3
5 < 6 at index 5
6 < not found
107.3 at index 3
110.2 not found
 */
  • binary_search 범위 내 특정 값과 일치하는 원소의 iterator를 반환.

// until C++20
template< class ForwardIt, class T >
bool binary_search( ForwardIt first, ForwardIt last, const T& value );

template< class ForwardIt, class T, class Compare >
bool binary_search( ForwardIt first, ForwardIt last, const T& value, Compare comp );

// since C++20
template< class ForwardIt, class T >
constexpr bool binary_search( ForwardIt first, ForwardIt last, const T& value );

template< class ForwardIt, class T, class Compare >
constexpr bool binary_search( ForwardIt first, ForwardIt last, const T& value,
                              Compare comp );

// ----------------------------------------------------------------------------------
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    vector<int> haystack {1, 3, 4, 5, 9};
    vector<int> needles {1, 2, 3};

    for (auto needle : needles) {
        cout << "Searching for " << needle << endl;
        if (binary_search(haystack.begin(), haystack.end(), needle)) {
            cout << "Found " << needle << endl;
        } else {
            cout << "no dice!" << endl;
        }
    }

    return 0;
}

/*
$ g++ test.cpp -std=c++11
$ ./a.out
Searching for 1
Found 1
Searching for 2
no dice!
Searching for 3
Found 3
 */
  • equal_range 범위 내 특정 값과 일치하는 원소들의 부분 범위([lower_bound, upper_bound)) 반환.

// until C++20
template< class ForwardIt, class T >
std::pair<ForwardIt,ForwardIt> equal_range( ForwardIt first, ForwardIt last,
                                            const T& value );

template< class ForwardIt, class T, class Compare >
std::pair<ForwardIt,ForwardIt> 
    equal_range( ForwardIt first, ForwardIt last, const T& value, Compare comp );

// since C++20
template< class ForwardIt, class T >
constexpr std::pair<ForwardIt,ForwardIt> 
              equal_range( ForwardIt first, ForwardIt last, const T& value );

template< class ForwardIt, class T, class Compare >
constexpr std::pair<ForwardIt,ForwardIt> 
              equal_range( ForwardIt first, ForwardIt last,
                           const T& value, Compare comp );

// ----------------------------------------------------------------------------------
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

struct S {
    int number;
    char name;
    // note: name is ignored by this comparison operator
    bool operator< ( const S& s ) const { return number < s.number; }
};

int main() {
    // note: not ordered, only partitioned w.r.t. S defined below
    vector<S> vec = { {1,'A'}, {2,'B'}, {2,'C'}, {2,'D'}, {4,'G'}, {3,'F'} };

    S value = {2, '?'};

    auto p = equal_range(vec.begin(), vec.end(), value);
    for ( auto i = p.first; i != p.second; ++i )
        cout << i->name << ' ';
    cout << endl;

    // heterogeneous comparison:
    struct Comp {
        bool operator() ( const S& s, int i ) const { return s.number < i; }
        bool operator() ( int i, const S& s ) const { return i < s.number; }
    };

    auto p2 = equal_range(vec.begin(),vec.end(), 2, Comp{});
    for ( auto i = p2.first; i != p2.second; ++i )
        cout << i->name << ' ';
    cout << endl;

    return 0;
}

/*
$ g++ test.cpp -std=c++11
$ ./a.out
B C D
B C D
 */

 

파티셔닝 알고리즘 (Partitioning Algorithm)

  • partition 범위 내 원소들을 주어진 함수에 의해 두 그룹으로 나눔.

    • partition_copy 두 그룹으로 나뉘어진 원소들을 복사. (원본 유지)

// until C++11
template< class BidirIt, class UnaryPredicate >
BidirIt partition( BidirIt first, BidirIt last, UnaryPredicate p );

// since C++11 until C++20
template< class ForwardIt, class UnaryPredicate >
ForwardIt partition( ForwardIt first, ForwardIt last, UnaryPredicate p );

template< class InputIt, class OutputIt1, class OutputIt2, class UnaryPredicate >
std::pair<OutputIt1, OutputIt2>
     partition_copy( InputIt first, InputIt last,
                     OutputIt1 d_first_true, OutputIt2 d_first_false,
                     UnaryPredicate p );

// since C++20
template< class ForwardIt, class UnaryPredicate >
constexpr ForwardIt partition( ForwardIt first, ForwardIt last, UnaryPredicate p );

template< class InputIt, class OutputIt1, class OutputIt2, class UnaryPredicate >
constexpr std::pair<OutputIt1, OutputIt2>
               partition_copy( InputIt first, InputIt last,
                               OutputIt1 d_first_true, OutputIt2 d_first_false,
                               UnaryPredicate p );

// since C++17
template< class ExecutionPolicy, class ForwardIt, class UnaryPredicate >
ForwardIt partition( ExecutionPolicy&& policy, 
                     ForwardIt first, ForwardIt last, UnaryPredicate p );

template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class ForwardIt3,
          class UnaryPredicate >
std::pair<ForwardIt2, ForwardIt3>
     partition_copy( ExecutionPolicy&& policy, ForwardIt1 first, ForwardIt1 last,
                     ForwardIt2 d_first_true, ForwardIt3 d_first_false,
                     UnaryPredicate p );

// ----------------------------------------------------------------------------------
#include <iostream>
#include <vector>
#include <forward_list>
#include <algorithm>
#include <iterator>
using namespace std;

template <class ForwardIt>
 void quicksort(ForwardIt first, ForwardIt last) {
    if(first == last) return;
    auto pivot = *next(first, distance(first,last)/2);
    ForwardIt middle1 = partition(
            first, last, [pivot](const auto& em){ return em < pivot; });
    ForwardIt middle2 = partition(
            middle1, last, [pivot](const auto& em){ return !(pivot < em); });
    quicksort(first, middle1);
    quicksort(middle2, last);
}

int main() {
    vector<int> v = {0,1,2,3,4,5,6,7,8,9};
    cout << "Original vector:\n    ";
    for(int elem : v) cout << elem << ' ';

    auto it = partition(v.begin(), v.end(), [](int i){return i % 2 == 0;});

    cout << endl << "Partitioned vector:\n    ";
    copy(begin(v), it, ostream_iterator<int>(cout, " "));
    cout << " * ";
    copy(it, end(v), ostream_iterator<int>(cout, " "));

    forward_list<int> fl = {1, 30, -4, 3, 5, -4, 1, 6, -8, 2, -5, 64, 1, 92};
    cout << endl << "Unsorted list:\n    ";
    for(int n : fl) cout << n << ' ';
    cout << endl;

    quicksort(begin(fl), end(fl));
    cout << "Sorted using quicksort:\n    ";
    for(int fi : fl) cout << fi << ' ';
    cout << endl;

    cout << "Call partition_copy():" << endl;

    int arr [10] = {1,2,3,4,5,6,7,8,9,10};
    int true_arr [5] = {0};
    int false_arr [5] = {0};

    cout << "Before: ";
    for (int n : arr) cout << n << " ";
    cout << endl;

    partition_copy(begin(arr), end(arr), begin(true_arr), begin(false_arr),
                   [] (int i) {return i > 5;});

    cout << "true_arr: ";
    for (int x : true_arr) cout << x << ' ';
    cout << endl;

    cout << "false_arr: ";
    for (int x : false_arr) cout << x << ' ';
    cout << endl;

    return 0;
}

/*
$ g++ test.cpp -std=c++14
$ ./a.out
Original vector:
    0 1 2 3 4 5 6 7 8 9
Partitioned vector:
    0 8 2 6 4  * 5 3 7 1 9
Unsorted list:
    1 30 -4 3 5 -4 1 6 -8 2 -5 64 1 92
Sorted using quicksort:
    -8 -5 -4 -4 1 1 1 2 3 5 6 30 64 92
Call partition_copy():
Before: 1 2 3 4 5 6 7 8 9 10
true_arr: 6 7 8 9 10
false_arr: 1 2 3 4 5
 */
  • is_partition 두 그룹이 주어진 함수에 의해 나뉘어져 있으면 true, 그렇지 않으면 false 반환.

// since C++11 until C++20
template< class InputIt, class UnaryPredicate >
bool is_partitioned( InputIt first, InputIt last, UnaryPredicate p );

// since C++20
template< class InputIt, class UnaryPredicate >
constexpr bool is_partitioned( InputIt first, InputIt last, UnaryPredicate p );

// since C++17
template< class ExecutionPolicy, class ForwardIt, class UnaryPredicate >
bool is_partitioned( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last,
                     UnaryPredicate p );

// ----------------------------------------------------------------------------------
#include <iostream>
#include <array>
#include <algorithm>
using namespace std;

int main() {
    array<int, 9> v = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

    auto is_even = [](int i){ return i % 2 == 0; };
    cout.setf(ios_base::boolalpha);
    cout << is_partitioned(v.begin(), v.end(), is_even) << ' ';

    partition(v.begin(), v.end(), is_even);
    cout << is_partitioned(v.begin(), v.end(), is_even) << ' ';

    reverse(v.begin(), v.end());
    cout << is_partitioned(v.cbegin(), v.cend(), is_even) << ' ';
    cout << is_partitioned(v.crbegin(), v.crend(), is_even) << endl;

    return 0;
}

/*
$ g++ test.cpp -std=c++11
$ ./a.out
false true false true
 */
  • stable_partition 상대적 순서를 유지한 상태로 두 그룹으로 나눔.

template< class BidirIt, class UnaryPredicate >
BidirIt stable_partition( BidirIt first, BidirIt last, UnaryPredicate p );

// since C++17
template< class ExecutionPolicy, class BidirIt, class UnaryPredicate >
BidirIt stable_partition( ExecutionPolicy&& policy, BidirIt first, BidirIt last,
                          UnaryPredicate p );

// ----------------------------------------------------------------------------------
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

int main() {
    vector<int> v{0, 0, 3, 0, 2, 4, 5, 0, 7};
    stable_partition(v.begin(), v.end(), [](int n){return n>0;});
    for (int n : v) cout << n << ' ';
    cout << endl;

    return 0;
}

/*
$ g++ test.cpp -std=c++11
$ ./a.out
3 2 4 5 7 0 0 0 0
 */
  • partition_point 두 그룹으로 나뉜 상태에서 첫번째 파티션이 끝나는 위치의 iterator를 반환.

// since C++11 until C++20
template< class ForwardIt, class UnaryPredicate >
ForwardIt partition_point( ForwardIt first, ForwardIt last, UnaryPredicate p );

// since C++20
template< class ForwardIt, class UnaryPredicate >
constexpr ForwardIt partition_point( ForwardIt first, ForwardIt last,
                                     UnaryPredicate p );

// ----------------------------------------------------------------------------------
#include <algorithm>
#include <array>
#include <iostream>
#include <iterator>
using namespace std;

int main() {
    array<int, 9> v = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

    auto is_even = [](int i){ return i % 2 == 0; };
    partition(v.begin(), v.end(), is_even);

    auto p = partition_point(v.begin(), v.end(), is_even);

    cout << "Before partition:\n    ";
    copy(v.begin(), p, ostream_iterator<int>(cout, " "));
    cout << endl << "After partition:\n    ";
    copy(p, v.end(), ostream_iterator<int>(cout, " "));
    cout << endl;

    return 0;
}

/*
$ g++ test.cpp -std=c++11
$ ./a.out
Before partition:
    8 2 6 4
After partition:
    5 3 7 1 9
 */

 

STL: <algorithm> 헤더파일

  • STL 컨테이너의 원소를 탐색, 변경, 관리, 처리할 목적으로 제공되는 함수 집합.

  • 컨테이너 뿐만 아니라 일반 배열 구조(int[] 등)에도 적용 가능.

    • 2개의 인자 (first, last)를 이용해서 컨테이너의 범위를 지정하므로, 2개의 인자에 배열의 주소를 직접 주어도 됨.

    • 보통 주어진 범위는 [first, last) 로 지정됨. 마지막 위치는 제외.

  • 100 여가지 알고리즘을 제공하며, 대부분의 함수들은 C++11 부터 제공됨.

  • 알고리즘의 분류

    • 변경 불가 알고리즘: 원소 값을 변경하지 않음.

    • 변경 가능 알고리즘: 원소 값을 변경.

    • 파티셔닝 알고리즘: 원소들을 두 그룹으로 나눔.

    • 정렬 알고리즘: 원소의 순서를 변경.

    • 이진 탐색 알고리즘: 정렬된 상태에서 원소를 탐색.

    • 병합 알고리즘: 정렬된 상태의 원소들을 병합.

    • 집합 연산 관련 알고리즘: 집합 연산을 제공.

    • 힙 연산 관련 알고리즘: 최대 힙, 최소 힙을 탐색.

    • 최대, 최소 원소 탐색 알고리즘: 주어진 범위의 최댓값과 최솟값을 탐색.

    • 비교 알고리즘: 주어진 두 개의 범위가 동일한지 비교.

    • 순열 알고리즘: 순열 관련 알고리즘.

    • 수치 알고리즘: 부분 합 등 집계 수치 연산 제공.

    • 초기화되지 않은 메모리에 대한 연산

  • #include <algorithm>

 

변경 불가 알고리즘 (Non-modifying Sequence Algorithm)

  • all_of 범위 안의 모든 원소가 조건을 만족하는 경우 true를 반환, 그렇지 않으면 false를 반환.

    • 아래의 3번째 매개변수인 UnaryPredicate 는 범위에 적용될 함수 객체인데, 함수 포인터로 이해하면 될 듯. 미리 선언된 함수의 이름을 넘기거나, Lambda 식을 넘기면 됨.

    • any_of 범위 안의 원소 중 하나라도 조건을 만족하는 경우 true를 반환, 그렇지 않으면 false를 반환.

    • none_of 범위 안의 원소 중 어떤 것도 조건을 만족하지 않으면 true를 반환, 그렇지 않으면 false를 반환.

// since C++ 11
template< class InputIt, class UnaryPredicate >
bool all_of( InputIt first, InputIt last, UnaryPredicate p );

// until C++ 20
template< class InputIt, class UnaryPredicate >
constexpr bool all_of( InputIt first, InputIt last, UnaryPredicate p );

// until C++ 20
template< class ExecutionPolicy, class ForwardIt, class UnaryPredicate >
bool all_of( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last,
             UnaryPredicate p );

// ----------------------------------------------------------------------------------
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

bool isEven(int i) { return ~(i & 1); }

int main() {
    vector<int> v(10, 2);
    cout << "Lambda as the third parameter: ";
    cout << all_of(v.begin(), v.end(), [](int i){ return i % 2 == 0; }) << endl;

    cout << "Function name as the third parameter: ";
    cout << all_of(v.begin(), v.end(), isEven) << endl;

    return 0;
}

/*
$ g++ test.cpp -std=c++11
$ ./a.out
Lambda as the third parameter: 1
Function name as the third parameter: 1
 */
  • for_each 범위 안의 각각의 원소에 대해 전달된 함수를 호출.

    • 3번째 사용법을 살펴보면, 클래스(struct) 내 오버로딩된 함수(operator())를 넘겼을 때 최종 반환 결과가 객체임에 주의할 것.

    • for_each_n 첫번째 인자에서 두번째 인자로 주어진 개수만큼 전달된 함수를 호출. (C++17 부터 지원)

// until C++20
template< class InputIt, class UnaryFunction >
UnaryFunction for_each( InputIt first, InputIt last, UnaryFunction f );

// since C++20
template< class InputIt, class UnaryFunction >
constexpr UnaryFunction for_each( InputIt first, InputIt last, UnaryFunction f );

// since C++17
template< class ExecutionPolicy, class ForwardIt, class UnaryFunction2 >
void for_each( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last,
               UnaryFunction2 f );

// ----------------------------------------------------------------------------------
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

struct Sum {
    void operator()(int n) { sum += n; }
    int sum{0};
};

int main() {
    vector<int> nums{3, 4, 2, 8, 15, 267};

    auto print = [](const int& n) { cout << " " << n; };

    cout << "before:";
    for_each(nums.cbegin(), nums.cend(), print);
    cout << endl;

    for_each(nums.begin(), nums.end(), [](int &n){ n++; });

    // calls Sum::operator() for each number
    Sum s = for_each(nums.begin(), nums.end(), Sum());

    cout << "after: ";
    for_each(nums.cbegin(), nums.cend(), print);
    cout << endl;

    cout << "sum: " << s.sum << endl;
    
    return 0;
}

/*
$ g++ test.cpp -std=c++11
$ ./a.out
before: 3 4 2 8 15 267
after:  4 5 3 9 16 268
sum: 305
 */
  • find 범위 안에서 3번째 인자로 주어진 과 일치하는 원소의 iterator를 반환.

    • find_if 조건과 일치하는 원소의 iterator 를 반환.

    • find_if_not 조건과 일치하지 않는 원소의 iterator 를 반환.

    • set이나 map처럼 연관 컨테이너에서는 find 함수보다 멤버 함수로 제공되는 find 함수를 쓰는 것이 더 효율적임. 멤버 함수는 연관 컨테이너가 정렬된 상태임을 활용하기 때문에 훨씬 빠르게 동작함.
// until C++20
template< class InputIt, class T >
InputIt find( InputIt first, InputIt last, const T& value );

// since C++20
template< class InputIt, class T >
constexpr InputIt find( InputIt first, InputIt last, const T& value );

// since C++17
template< class ExecutionPolicy, class ForwardIt, class T >
ForwardIt find( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last,
                const T& value );


// until C++20
template< class InputIt, class UnaryPredicate >
InputIt find_if( InputIt first, InputIt last, UnaryPredicate p );

// since C++20
template< class InputIt, class UnaryPredicate >
constexpr InputIt find_if( InputIt first, InputIt last, UnaryPredicate p );

// since C++17
template< class ExecutionPolicy, class ForwardIt, class UnaryPredicate >
ForwardIt find_if( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, 
                   UnaryPredicate p );

// find_if_not 은 find_if 과 인자가 동일
// ----------------------------------------------------------------------------------
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

int main() {
    int n1 = 3, n2 = 5;
    vector<int> v{0, 1, 2, 3, 4};

    auto result1 = find(begin(v), end(v), n1);
    auto result2 = find(begin(v), end(v), n2);

    if (result1 != end(v)) {
        cout << "v contains: " << n1 << endl;
    } else {
        cout << "v does not contain: " << n1 << endl;
    }

    if (result2 != end(v)) {
        cout << "v contains: " << n2 << endl;
    } else {
        cout << "v does not contain: " << n2 << endl;
    }

    auto result3 = find_if(v.begin(), v.end(), [](int i){ return i & 1; });
    if (result3 != end(v)) {
        cout << "odd number: " << *result3 << endl;
    }

    auto result4 = find_if_not(v.begin(), v.end(), [](int i){ return i & 1; });
    if (result4 != end(v)) {
        cout << "even number: " << *result4 << endl;
    }

    return 0;
}

/*
$ g++ test.cpp -std=c++11
$ ./a.out
v contains: 3
v does not contain: 5
odd number: 1
even number: 0
 */
  • adjacent_find 처음에 연속해서 나타나는 원소의 시작 위치의 iterator를 반환.

    • 3번째 인자로 비교자 함수를 greater<자료형> 으로 줄 경우, 끝에서 최초로 연속해서 나타나는 원소의 시작 위치를 반환.

// until C++20
template< class ForwardIt >
ForwardIt adjacent_find( ForwardIt first, ForwardIt last );

template< class ForwardIt, class BinaryPredicate>
ForwardIt adjacent_find( ForwardIt first, ForwardIt last, BinaryPredicate p );

// since C++20
template< class ForwardIt >
constexpr ForwardIt adjacent_find( ForwardIt first, ForwardIt last );

template< class ForwardIt, class BinaryPredicate>
constexpr ForwardIt adjacent_find( ForwardIt first, ForwardIt last,
                                   BinaryPredicate p );

// since C++17
template< class ExecutionPolicy, class ForwardIt >
ForwardIt adjacent_find( ExecutionPolicy&& policy,
                         ForwardIt first, ForwardIt last );

template< class ExecutionPolicy, class ForwardIt, class BinaryPredicate>
ForwardIt adjacent_find( ExecutionPolicy&& policy,
                         ForwardIt first, ForwardIt last, BinaryPredicate p );

// ----------------------------------------------------------------------------------
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;;

int main() {
    vector<int> v1{0, 1, 2, 3, 40, 40, 41, 41, 5};

    auto i1 = adjacent_find(v1.begin(), v1.end());

    if (i1 == v1.end()) {
        cout << "No matching adjacent elements\n";
    } else {
        cout << "The first adjacent pair of equal elements at: ";
        cout << distance(v1.begin(), i1) << endl;
    }

    auto i2 = adjacent_find(v1.begin(), v1.end(), greater<int>());
    if (i2 == v1.end()) {
        cout << "The entire vector is sorted in ascending order" << endl;
    } else {
        cout << "The last element in the non-decreasing subsequence is at: ";
        cout << distance(v1.begin(), i2) << endl;
    }

    return 0;
}

/*
$ g++ test.cpp -std=c++11
$ ./a.out
The first adjacent pair of equal elements at: 4
The last element in the non-decreasing subsequence is at: 7
 */
  • find_end 주어진 순열이 탐색 범위에서 마지막으로 나타난 위치의 iterator를 반환.

    • 시간 복잡도: O(S * (N - S + 1)), N은 탐색 범위, S는 탐색 대상의 범위

    • 내부적으로 search() 함수를 사용함.

    • 주어진 순열이 포함되었는지 비교하는 함수는 BinaryPredicate p라는 마지막 인자로 넘겨서 커스텀 비교자를 구현할 수 있음.

// until C++20
template< class ForwardIt1, class ForwardIt2 >
ForwardIt1 find_end( ForwardIt1 first, ForwardIt1 last,
                     ForwardIt2 s_first, ForwardIt2 s_last );

template< class ForwardIt1, class ForwardIt2, class BinaryPredicate >
ForwardIt1 find_end( ForwardIt1 first, ForwardIt1 last,
                     ForwardIt2 s_first, ForwardIt2 s_last, BinaryPredicate p );

// since C++20
C++20)
template< class ForwardIt1, class ForwardIt2 >
constexpr ForwardIt1 find_end( ForwardIt1 first, ForwardIt1 last,
                               ForwardIt2 s_first, ForwardIt2 s_last );

template< class ForwardIt1, class ForwardIt2, class BinaryPredicate >
constexpr ForwardIt1 find_end( ForwardIt1 first, ForwardIt1 last,
                               ForwardIt2 s_first, ForwardIt2 s_last,
                               BinaryPredicate p );

// since C++17
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2 >
ForwardIt1 find_end( ExecutionPolicy&& policy, ForwardIt1 first, ForwardIt1 last,
                     ForwardIt2 s_first, ForwardIt2 s_last );

template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2,
          class BinaryPredicate >
ForwardIt1 find_end( ExecutionPolicy&& policy, ForwardIt1 first, ForwardIt1 last,
                     ForwardIt2 s_first, ForwardIt2 s_last, BinaryPredicate p );

// ----------------------------------------------------------------------------------
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    vector<int> v{1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4};
    vector<int>::iterator result;

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

    result = find_end(v.begin(), v.end(), t1.begin(), t1.end());
    if (result == v.end()) {
        cout << "sequence not found" << endl;
    } else {
        int dist = distance(v.begin(), result);
        cout << "last occurrence is at: " << dist << endl;
    }

    vector<int> t2{4, 5, 6};
    result = find_end(v.begin(), v.end(), t2.begin(), t2.end());
    if (result == v.end()) {
        cout << "sequence not found" << endl;
    } else {
        int dist = distance(v.begin(), result);
        cout << "last occurrence is at: " << dist << endl;
    }

    return 0;
}

/*
$ g++ test.cpp -std=c++11
./a.out
last occurrence is at: 8
sequence not found
 */
  • count 범위 안에 주어진 과 일치하는 원소의 개수를 반환

    • count_if 주어진 조건과 일치하는 원소의 개수를 반환.

// until C++20
template< class InputIt, class T >
typename iterator_traits<InputIt>::difference_type
    count( InputIt first, InputIt last, const T &value );

template< class InputIt, class UnaryPredicate >
typename iterator_traits<InputIt>::difference_type
    count_if( InputIt first, InputIt last, UnaryPredicate p );

// since C++20
template< class InputIt, class T >
constexpr typename iterator_traits<InputIt>::difference_type
              count( InputIt first, InputIt last, const T &value );

template< class InputIt, class UnaryPredicate >
constexpr typename iterator_traits<InputIt>::difference_type
              count_if( InputIt first, InputIt last, UnaryPredicate p );

// since C++17
template< class ExecutionPolicy, class ForwardIt, class T >
typename iterator_traits<ForwardIt>::difference_type
    count( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last,
           const T &value );

template< class ExecutionPolicy, class ForwardIt, class UnaryPredicate >
typename iterator_traits<ForwardIt>::difference_type
    count_if( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last,
              UnaryPredicate p );

// ----------------------------------------------------------------------------------
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    vector<int> v{ 1, 2, 3, 4, 4, 3, 7, 8, 9, 10 };

    // determine how many integers in a vector match a target value.
    int target1 = 3, target2 = 5;
    int num_items1 = count(v.begin(), v.end(), target1);
    int num_items2 = count(v.begin(), v.end(), target2);
    cout << "number: " << target1 << " count: " << num_items1 << endl;
    cout << "number: " << target2 << " count: " << num_items2 << endl;

    // use a lambda expression to count elements divisible by 3.
    int num_items3 = count_if(v.begin(), v.end(), [](int i){return i % 3 == 0;});
    cout << "number divisible by three: " << num_items3 << endl;

    return 0;
}

/*
$ g++ test.cpp -std=c++11
$ ./a.out
number: 3 count: 2
number: 5 count: 0
number divisible by three: 3
 */
  • search 범위 안에서 주어진 순열이 포함되는 첫번째 위치의 iterator를 반환.

    • 시간 복잡도: O(S * N), 범위의 크기 = N, 주어진 순열의 크기 = S

// until C++20
template< class ForwardIt1, class ForwardIt2 >
ForwardIt1 search( ForwardIt1 first, ForwardIt1 last,
                   ForwardIt2 s_first, ForwardIt2 s_last );

template< class ForwardIt1, class ForwardIt2, class BinaryPredicate >
ForwardIt1 search( ForwardIt1 first, ForwardIt1 last,
                   ForwardIt2 s_first, ForwardIt2 s_last, BinaryPredicate p );

// since C++20
template< class ForwardIt1, class ForwardIt2 >
constexpr ForwardIt1 search( ForwardIt1 first, ForwardIt1 last,
                             ForwardIt2 s_first, ForwardIt2 s_last );

template< class ForwardIt1, class ForwardIt2, class BinaryPredicate >
constexpr ForwardIt1 search( ForwardIt1 first, ForwardIt1 last,
                             ForwardIt2 s_first, ForwardIt2 s_last,
                             BinaryPredicate p );


template<class ForwardIt, class Searcher>
constexpr ForwardIt search( ForwardIt first, ForwardIt last,
                            const Searcher& searcher );

// since C++17
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2 >
ForwardIt1 search( ExecutionPolicy&& policy, ForwardIt1 first, ForwardIt1 last,
                   ForwardIt2 s_first, ForwardIt2 s_last );

template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2,
          class BinaryPredicate >
ForwardIt1 search( ExecutionPolicy&& policy, ForwardIt1 first, ForwardIt1 last,
                   ForwardIt2 s_first, ForwardIt2 s_last, BinaryPredicate p );

// since C++17 until C++20
template<class ForwardIt, class Searcher>
ForwardIt search( ForwardIt first, ForwardIt last, const Searcher& searcher );

// ----------------------------------------------------------------------------------
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <functional>
using namespace std;

template <typename Container>
bool in_quote(const Container& cont, const string& s) {
    return search(cont.begin(), cont.end(), s.begin(), s.end()) != cont.end();
}

int main() {
    string str = "why waste time learning, when ignorance is instantaneous?";
    // str.find() can be used as well
    cout << boolalpha << in_quote(str, "learning") << endl;
    cout << in_quote(str, "lemming")  << endl;

    vector<char> vec(str.begin(), str.end());
    cout << boolalpha << in_quote(vec, "learning") << endl;
    cout << in_quote(vec, "lemming")  << endl;

    // The C++17 overload demo:
    string in = "Lorem ipsum dolor sit amet, consectetur adipiscing elit,"
        " sed do eiusmod tempor incididunt ut labore et dolore magna aliqua";
    string needle = "pisci";
    auto it = search(in.begin(), in.end(), boyer_moore_searcher(needle.begin(), needle.end()));
    if(it != in.end()) {
        cout << "The string " << needle << " found at offset ";
        cout << it - in.begin() << endl;
    } else {
        cout << "The string " << needle << " not found" << endl;
    }

    return 0;
}

/*
$ g++ test.cpp -std=c++17
$ ./a.out
true
false
true
false
The string pisci found at offset 43
 */
  • search_n 범위 안에서 주어진 순열을 count번 반복한 순열의 위치(iterator)를 반환.

    • 시간 복잡도: O(N), 범위의 크기 = N

// until C++20
template< class ForwardIt, class Size, class T >
ForwardIt search_n( ForwardIt first, ForwardIt last, Size count, const T& value );

template< class ForwardIt, class Size, class T, class BinaryPredicate >
ForwardIt search_n( ForwardIt first, ForwardIt last, Size count, const T& value, 
                     BinaryPredicate p );

// since C++20
template< class ForwardIt, class Size, class T >
constexpr ForwardIt search_n( ForwardIt first, ForwardIt last, Size count,
                              const T& value );

template< class ForwardIt, class Size, class T, class BinaryPredicate >
constexpr ForwardIt search_n( ForwardIt first, ForwardIt last, Size count,
                              const T& value, BinaryPredicate p );

// since C++17
template< class ExecutionPolicy, class ForwardIt, class Size, class T >
ForwardIt search_n( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last,
                    Size count, const T& value );

template< class ExecutionPolicy, class ForwardIt, class Size, class T,
          class BinaryPredicate >
ForwardIt search_n( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last,
                    Size count, const T& value, BinaryPredicate p );

// ----------------------------------------------------------------------------------
#include <iostream>
#include <algorithm>
#include <iterator>
using namespace std;

template <class Container, class Size, class T>
bool consecutive_values(const Container& c, Size count, const T& v) {
  return search_n(begin(c),end(c),count,v) != end(c);
}

int main() {
   const char sequence[] = "1001010100010101001010101";

   cout << boolalpha;
   cout << "Has 4 consecutive zeros: " << consecutive_values(sequence,4,'0') << endl;
   cout << "Has 3 consecutive zeros: " << consecutive_values(sequence,3,'0') << endl;

   return 0;
}

/*
$ g++ test.cpp -std=c++11
$ ./a.out
Has 4 consecutive zeros: false
Has 3 consecutive zeros: true
 */
  • mismatch 범위 안에서 주어진 순열과 처음으로 일치하지 않는 위치의 iterator를 반환

 

+ Recent posts