Permutation And Numeric Algorithms

Permutations

std::prev_permutation and std::next_permutation return the previous smaller or next bigger permutation of the newly ordered range. If a smaller or bigger permutation is not available, the algorithms return false. Both algorithms need bidirectional iterators. Per default the predefined sorting criterion std::less is used. If you use your sorting criterion, it has to obey the strict weak ordering. If not, the program is undefined.

std::vector<int> myInts{1, 2, 3};
do{
  for (auto i: myInts) std::cout << i;
  std::cout << " ";
} while(std::next_permutation(myInts.begin(), myInts.end())); 
                                    // 123 132 213 231 312 321 

std::reverse(myInts.begin(), myInts.end());
do{
  for (auto i: myInts) std::cout << i;
  std::cout << " ";
} while(std::prev_permutation(myInts.begin(), myInts.end()));
                                    // 321 312 231 213 132 123

Min and Max

You can determine the minimum, the maximum and the minimum and maximum pair of a range with the algorithms std::min_elementstd::max_element and std::minmax_element. Each algorithm can be configured with a binary predicate.

int toInt(const std::string& s){
  std::stringstream buff;
  buff.str("");
  buff << s;
  int value;
  buff >> value;
  return value;
}

std::vector<std::string> myStrings{"94", "5", "39", "-4", "-49", "1001", "-77",
                                   "23", "0", "84", "59", "96", "6", "-94"};
auto str= std::minmax_element(myStrings.begin(), myStrings.end());
std::cout << *str.first << ":" << *str.second;              // -4:96

auto asInt= std::minmax_element(myStrings.begin(), myStrings.end(),
            [](std::string a, std::string b){ return toInt(a) < toInt(b); });
std::cout << *asInt.first << ":" << *asInt.second;          // -94:1001

Numeric

std::accumulate without callable uses the following strategy

result = init;
result += *(first+0);
result += *(first+1);
...

std::adjacent_difference without callable uses the following strategy:

*(result) = *first;
*(result+1) = *(first+1) - *(first);
*(result+2) = *(first+2) - *(first+1);
...

std::partial_sum without callable uses the following strategy:

*(result) = *first;
*(result+1) = *first + *(first+1);
*(result+2) = *first + *(first+1) + *(first+2)
...
std::array<int, 9> arr{1, 2, 3, 4, 5, 6, 7, 8, 9};
std::cout << std::accumulate(arr.begin(), arr.end(), 0);               // 45
std::cout << std::accumulate(arr.begin(), arr.end(), 1,
                             [](int a, int b){ return a*b; } );        // 362880
							 
std::vector<int> vec{1, 2, 3, 4, 5, 6, 7, 8, 9};
std::vector<int> myVec;
std::adjacent_difference(vec.begin(), vec.end(),
                 std::back_inserter(myVec), [](int a, int b){ return a*b; });
for (auto v: myVec) std::cout << v << " ";            // 1 2 6 12 20 30 42 56 72
std::cout << std::inner_product(vec.begin(), vec.end(), arr.begin(), 0);  // 285

myVec= {};
std::partial_sum(vec.begin(), vec.end(), std::back_inserter(myVec));
for (auto v: myVec) std::cout << v << " ";            // 1 3 6 10 15 21 28 36 45

std::vector<int> myLongVec(10);
std::iota(myLongVec.begin(), myLongVec.end(), 2000);
for (auto v: myLongVec) std::cout << v << " ";    
                            // 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009

binary heap

binary heap is a heap data structure that takes the form of a binary tree. Binary heaps are a common way of implementing priority queues.[1]:162–163 The binary heap was introduced by J. W. J. Williams in 1964, as a data structure for heapsort.[2]

A binary heap is defined as a binary tree with two additional constraints:[3]

  • Shape property: a binary heap is a complete binary tree; that is, all levels of the tree, except possibly the last one (deepest) are fully filled, and, if the last level of the tree is not complete, the nodes of that level are filled from left to right.
  • Heap property: the key stored in each node is either greater than or equal to (≥) or less than or equal to (≤) the keys in the node’s children, according to some total order.

Heaps where the parent key is greater than or equal to (≥) the child keys are called max-heaps; those where it is less than or equal to (≤) are called min-heaps. Efficient (logarithmic time) algorithms are known for the two operations needed to implement a priority queue on a binary heap: inserting an element, and removing the smallest or largest element from a min-heap or max-heap, respectively. Binary heaps are also commonly employed in the heapsort sorting algorithm, which is an in-place algorithm because binary heaps can be implemented as an implicit data structure, storing keys in an array and using their relative positions within that array to represent child-parent relationships.

insert

  1. Add the element to the bottom level of the heap at the most left.
  2. Compare the added element with its parent; if they are in the correct order, stop.
  3. If not, swap the element with its parent and return to the previous step.
This image has an empty alt attribute; its file name is 2-18.pngThis image has an empty alt attribute; its file name is 3-10.pngThis image has an empty alt attribute; its file name is 4-4.png
Insert “15”

Remove

  1. Replace the root of the heap with the last element on the last level.
  2. Compare the new root with its children; if they are in the correct order, stop.
  3. If not, swap the element with one of its children and return to the previous step. (Swap with its smaller child in a min-heap and its larger child in a max-heap.)
This image has an empty alt attribute; its file name is 5-3.pngThis image has an empty alt attribute; its file name is 6-3.pngThis image has an empty alt attribute; its file name is 7-3.png
extract “11”

Heap in C++

You can create with std::make_heap a heap. You can push with std::push_heap new elements on the heap. On the contrary, you can pop the largest element with std::pop_heap from the heap. Both operations respect the heap characteristics. std::push_heap moves the last element of the range on the heap; std::pop_heap moves the biggest element of the heap to the last position in the range. You can check with std::is_heap if a range is a heap. You can determine with std::is_heap_until until which position the range is a heap. std::sort_heap sorts the heap.

std::vector<int> vec{4, 3, 2, 1, 5, 6, 7, 9, 10};
std::make_heap(vec.begin(), vec.end());
for (auto v: vec) std::cout << v << " ";                   // 10 9 7 4 5 6 2 3 1
std::cout << std::is_heap(vec.begin(), vec.end());         // true

vec.push_back(100);
std::cout << std::is_heap(vec.begin(), vec.end());         // false
std::cout << *std::is_heap_until(vec.begin(), vec.end());  // 100
for (auto v: vec) std::cout << v << " ";                   // 10 9 7 4 5 6 2 3 1 100

std::push_heap(vec.begin(), vec.end());
std::cout << std::is_heap(vec.begin(), vec.end());        // true
for (auto v: vec) std::cout << v << " ";                  // 100 10 7 4 9 6 2 3 1 5

std::pop_heap(vec.begin(), vec.end());
for (auto v: vec) std::cout << v << " ";                  // 10 9 7 4 5 6 2 3 1 100
std::cout << *std::is_heap_until(vec.begin(), vec.end()); // 100

vec.resize(vec.size()-1);
std::cout << std::is_heap(vec.begin(), vec.end());        // true
std::cout << vec.front() << std::endl;                    // 10

Sort, Binary Search, Merge Algorithms

Sort And Partial Sort

You can sort a range with std::sort or std::stable_sort or sort until a position with std::partial_sort. In addition std::partial_sort_copy copies the partially sorted range. With std::nth_element you can assign an element the sorted position in the range. You can check with std::is_sorted if a range is sorted. If you want to know until which position a range is sorted, use std::is_sorted_until.

std::string str{"RUdAjdDkaACsdfjwldXmnEiVSEZTiepfgOIkue"};
std::cout << std::is_sorted(str.begin(), str.end());        // false

std::partial_sort(str.begin(), str.begin()+30, str.end());
std::cout << str;           // AACDEEIORSTUVXZaddddeeffgiijjkwspnmluk

auto sortUntil= std::is_sorted_until(str.begin(), str.end());
std::cout << *sortUntil;                                   // s
for (auto charIt= str.begin(); charIt != sortUntil; ++charIt) 
    std::cout << *charIt;           // AACDEEIORSTUVXZaddddeeffgiijjkw

std::vector<int> vec{1, 0, 4, 3, 5};
auto vecIt= vec.begin();
while(vecIt != vec.end()){
  std::nth_element(vec.begin(), vecIt++, vec.end());
  std::cout << std::distance(vec.begin(), vecIt) << "-th ";
  for (auto v: vec) std::cout << v << "/";
}
// 1-th 01435/2-th 01435/3-th 10345/4-th 30145/5-th 10345
struct A{
    int v;
    bool operator<(const A& other){
        return this->v<other.v;
    }
};
int main(int argc, char *argv[])
{
    QCoreApplication a(argc,argv);
    QList<A> list{{8},{2},{3},{6},{5}};
    sort(list.begin(),list.end());
    for(const A& a:list){
        qDebug()<<a.v;
    }//2 3 5 6 8
    return a.exec();
}

Binary Search

Binary Search

The binary search algorithms use the fact that the ranges are already sorted. To search for an element, use std::binary_search. With std::lower_bound you get an iterator for the first element, being no smaller than the given value. With std::upper_bound you get an iterator back for the first element, which is bigger than the given value. std:::equal_range combines both algorithms.

binary_search : Searches the element val in the range
lower_bound : Returns the position of the first element of the range, being not smaller than val
upper_bound : Returns the position of the first element of the range, being bigger than val
equal_range  : Returns the pair std::lower_bound and std::upper_bound for the element val

bool isLessAbs(int a, int b){
  return abs(a) < abs(b);
}
vector<int> vec{-3, 0, -3, 2, -3, 5, -3, 7, -0, 6, -3, 5, 
                -6, 8, 9, 0, 8, 7, -7, 8, 9, -6, 3, -3, 2};

sort(vec.begin(), vec.end(), isLessAbs);
for (auto v: vec) cout << v << " "; 
     // 0 0 0 2 2 -3 -3 -3 -3 -3 3 -3 5 5 -6 -6 6 7 -7 7 8 8 8 9 9
cout << binary_search(vec.begin(), vec.end(), -5, isLessAbs); // true
cout << binary_search(vec.begin(), vec.end(), 5, isLessAbs);  // true

auto pair= equal_range(vec.begin(), vec.end(), 3, isLessAbs);
cout << distance(vec.begin(), pair.first);                    // 5
cout << distance(vec.begin(), pair.second)-1;                 // 11

for (auto threeIt= pair.first;threeIt != pair.second; ++threeIt) 
     cout << *threeIt << " ";              // -3 -3 -3 -3 -3 3 -3

Merge Operation

Merge operations empower you to merge sorted ranges in a new sorted range. The algorithm requires that the ranges and the algorithm use the same sorting criterion. If not, the program is undefined. Per default the predefined sorting criterion std::less is used. If you use your sorting criterion, it has to obey the strict weak ordering. If not, the program is undefined.

You can merge two sorted ranges with std::inplace_merge and std::merge. You can check with std::includes if one sorted range is in another sorted range. You can merge with std::set_differencestd::set_intersectionstd::set_symmetric_difference and std::set_union two sorted ranges in a new sorted range.

inplace_merge : Merges in place two sorted sub ranges [first, mid) and [mid, last)
merge : Merges two sorted ranges and copies the result to result
includes: Checks if all elements of the second range are in the first range
set_difference : Copies these elements of the first range to result, being not in the second range
set_intersection : Determines the intersection of the first with the second range and copies the result to result
set_symmetric_difference :  Determines the symmetric difference of the first with the second range and copies the result to result
set_union : Determines the union of the first with the second range and copies the result to result

std::vector<int> vec1{1, 1, 4, 3, 5, 8, 6, 7, 9, 2};
std::vector<int> vec2{1, 2, 3};

std::sort(vec1.begin(), vec1.end());
std::vector<int> vec(vec1);

vec1.reserve(vec1.size() + vec2.size());
vec1.insert(vec1.end(), vec2.begin(), vec2.end());
for (auto v: vec1) std::cout << v << " ";       // 1 1 2 3 4 5 6 7 8 9 1 2 3

std::inplace_merge(vec1.begin(), vec1.end()-vec2.size(), vec1.end());
for (auto v: vec1) std::cout << v << " ";       //  1 1 1 2 2 3 3 4 5 6 7 8 9

vec2.push_back(10);
for (auto v: vec) std::cout << v << " ";        // 1 1 2 3 4 5 6 7 8 9
for (auto v: vec2) std::cout << v << " ";       // 1 2 3 10

std::vector<int> res;
std::set_symmetric_difference(vec.begin(), vec.end(), vec2.begin(), vec2.end(), 
                              std::back_inserter(res));
for (auto v : res) std::cout << v << " ";       // 1 4 5 6 7 8 9 10

res= {};
std::set_union(vec.begin(), vec.end(), vec2.begin(), vec2.end(),
std::back_inserter(res));
for (auto v : res) std::cout << v << " ";       // 1 1 2 3 4 5 6 7 8 9 10

Modifying Algorithms

Copy Elements and Ranges

You can copy ranges forward with std::copy, backward with std::copy_backward and conditionally with std::copy_if. If you want to copy n elements, you can use std::copy_n.

std::vector<int> myVec{0, 1, 2, 3, 4, 5, 6, 7, 9};
std::vector<int> myVec2(10);

std::copy_if(myVec.begin(), myVec.end(), myVec2.begin()+3,
             [](int a){ return a%2; });
			 
for (auto v: myVec2) std::cout << v << " ";    // 0 0 0 1 3 5 7 9 00

std::string str{"abcdefghijklmnop"};
std::string str2{"---------------------"};

std::cout << str2;                             // ---------------------
std::copy_backward(str.begin(), str.end(), str2.end());
std::cout << str2;                             // -----abcdefghijklmnop
std::cout << str;                              // abcdefghijklmnop

std::copy_backward(str.begin(), str.begin() + 5, str.end());
std::cout << str;                              // abcdefghijkabcde

Replace Elements and Ranges

You have with std::replacestd::replace_ifstd::replace_copy and std::replace_copy_if four variations to replace elements in a range. The algorithms differ in two aspects. First, does the algorithm need a predicate? Second, does the algorithm copy the elements in the destination range?

std::string str{"Only for testing purpose."};
std::replace(str.begin(), str.end(), ' ', '1');
std::cout << str; // Only1for1testing1purpose.

std::replace_if(str.begin(), str.end(), [](char c){ return c == '1'; }, '2'); 
std::cout << str; // Only2for2testing2purpose.

std::string str2;
std::replace_copy(str.begin(), str.end(), std::back_inserter(str2), '2', '3');
std::cout << str2; // Only3for3testing3purpose.

std::string str3;
std::replace_copy_if(str2.begin(), str2.end(),
std::back_inserter(str3), [](char c){ return c == '3'; }, '4');
std::cout << str3; // Only4for4testing4purpose.

Remove Elements and Ranges

The four variations std::remove, std::remove_if, std::remove_copy and std::remove_copy_if support two kinds of operations. On one hand, remove elements with and without a predicate from a range. On the other hand, copy the result of your modification to a new range.

std::vector<int> myVec{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
auto newIt= std::remove_if(myVec.begin(), myVec.end(), 
                          [](int a){ return a%2; });
for (auto v: myVec) std::cout << v << " ";   // 0 2 4 6 8 5 6 7 8 9
myVec.erase(newIt, myVec.end());
for (auto v: myVec) std::cout << v << " ";   // 0 2 4 6 8
std::string str{"Only for Testing Purpose."};
str.erase( std::remove_if(str.begin(), str.end(),
          [](char c){ return std::isupper(c); }, str.end() ) );
std::cout << str << std::endl;               // nly for esting urpose.

Fill and Create Ranges

You can fill a range with std::fill and std::fill_n; you can generate new elements with std::generate and std::generate_n.

int getNext(){
  static int next{0};
  return ++next;
}

std::vector<int> vec(10);
std::fill(vec.begin(), vec.end(), 2011);
for (auto v: vec) std::cout << v << " ";
                      // 2011 2011 2011 2011 2011 2011 2011 2011 2011 2011
					
std::generate_n(vec.begin(), 5, getNext);
for (auto v: vec) std::cout << v << " ";
                      // 1 2 3 4 5 2011 2011 2011 2011 2011

Move Ranges

std::move moves the ranges forward; std::move_backward moves the ranges backwards.

std::vector<int> myVec{0, 1, 2, 3, 4, 5, 6, 7, 9};
std::vector<int> myVec2(myVec.size());
std::move(myVec.begin(), myVec.end(), myVec2.begin());
for (auto v: myVec2) std::cout << v << " ";    // 0 1 2 3 4 5 6 7 9 0

std::string str{"abcdefghijklmnop"};
std::string str2{"---------------------"};
std::move_backward(str.begin(), str.end(), str2.end());
std::cout << str2;                             // -----abcdefghijklmnop

Swap Ranges

std::swap and std::swap_ranges can swap objects and ranges.

std::vector<int> myVec{0, 1, 2, 3, 4, 5, 6, 7, 9};
std::vector<int> myVec2(9);
std::swap(myVec, myVec2);
for (auto v: myVec) std::cout << v << " ";    // 0 0 0 0 0 0 0 0 0
for (auto v: myVec2) std::cout << v << " ";   // 0 1 2 3 4 5 6 7 9

std::string str{"abcdefghijklmnop"};
std::string str2{"---------------------"};
std::swap_ranges(str.begin(), str.begin()+5, str2.begin()+5);
std::cout << str << std::endl;                // -----fghijklmnop
std::cout << str2 << std::endl;               // -----abcde-----------

Transform Ranges

The std::transform algorithm applies a unary or binary callable to a range and copies the modified elements to the destination range.

std::string str{"abcdefghijklmnopqrstuvwxyz"};
std::transform(str.begin(), str.end(), str.begin(),
               [](char c){ return std::toupper(c); });
std::cout << str;         // ABCDEFGHIJKLMNOPQRSTUVWXYZ

std::vector<std::string> vecStr{"Only", "for", "testing", "purpose", "."};
std::vector<std::string> vecStr2(5, "-");
std::vector<std::string> vecRes;
std::transform(vecStr.begin(), vecStr.end(), 
               vecStr2.begin(), std::back_inserter(vecRes),
               [](std::string a, std::string b){ return std::string(b)+a+b; });
for (auto str: vecRes) std::cout << str << " ";  
                           // -Only- -for- -testing- -purpose- -.-

Reverse Ranges

std::reverse and std::reverse_copy invert the order of the elements in their range.

std::string str{"123456789"};
std::reverse(str.begin(), str.begin()+5);
std::cout << str;           // 543216789

Randomly Shuffle Ranges

You can randomly shuffle ranges with std::random_shuffle and std::shuffle.

using std::chrono::system_clock;
using std::default_random_engine;
std::vector<int> vec1{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
std::vector<int> vec2(vec1);

std::random_shuffle(vec1.begin(), vec1.end());
for (auto v: vec1) std::cout << v << " ";     // 4 3 7 8 0 5 2 1 6 9

unsigned seed= system_clock::now().time_since_epoch().count();
std::shuffle(vec2.begin(), vec2.end(), default_random_engine(seed));
for (auto v: vec2) std::cout << v << " ";     // 4 0 2 3 9 6 5 1 8 7

Remove Duplicates

With the algorithms std::unique and std::unique_copy you have more opportunities to remove adjacent duplicates. This can be done with and without a binary predicate.

std::vector<int> myVec{0, 0, 1, 1, 2, 2, 3, 4, 4, 5, 
                       3, 6, 7, 8, 1, 3, 3, 8, 8, 9};

myVec.erase(std::unique(myVec.begin(), myVec.end()), myVec.end());
for (auto v: myVec) std::cout << v << " ";     // 0 1 2 3 4 5 3 6 7 8 1 3 8 9 

std::vector<int> myVec2{1, 4, 3, 3, 3, 5, 7, 9, 2, 4, 1, 6, 8, 
                        0, 3, 5, 7, 8, 7, 3, 9, 2, 4, 2, 5, 7, 3};
std::vector<int> resVec;
resVec.reserve(myVec2.size());
std::unique_copy(myVec2.begin(), myVec2.end(), std::back_inserter(resVec),
                 [](int a, int b){ return (a%2) == (b%2); } );
for(auto v: myVec2) std::cout << v << " "; 
                      // 1 4 3 3 3 5 7 9 2 4 1 6 8 0 3 5 7 8 7 3 9 2 4 2 5 7 3
for(auto v: resVec) std::cout << v << " ";       // 1 4 3 2 1 6 3 8 7 2 5

Partition

std::partition and std::stable_partition partition a range and returns the partition point. With std::partition_point you can get the partition point of a partition. Afterwards you can check the partition with std::is_partitioned or copy it with std::partition_copy.

bool isOdd(int i){ return (i%2) == 1; }
vector<int> vec{1, 4, 3, 4, 5, 6, 7, 3, 4, 5, 6, 0, 4, 
                8, 4, 6, 6, 5, 8, 8, 3, 9, 3, 7, 6, 4, 8};

auto parPoint= partition(vec.begin(), vec.end(), isOdd);
for (auto v: vec) cout << v << " ";
                    // 1 7 3 3 5 9 7 3 3 5 5 0 4 8 4 6 6 6 8 8 4 6 4 4 6 4 8
					
for (auto v= vec.begin(); v != parPoint; ++v) cout << *v << " ";
                    // 1 7 3 3 5 9 7 3 3 5 5
for (auto v= parPoint; v != vec.end(); ++v) cout << *v << " ";
                    // 4 8 4 6 6 6 8 8 4 6 4 4 6 4 8
					
cout << is_partitioned(vec.begin(), vec.end(), isOdd);     // true
list<int> le;
list<int> ri;
partition_copy(vec.begin(), vec.end(), back_inserter(le), back_inserter(ri),
               [](int i) { return i < 5; });
for (auto v: le) cout << v << " ";    // 1 3 3 3 3 0 4 4 4 4 4 4
for (auto v: ri) cout << v << " ";    // 7 5 9 7 5 5 8 6 6 6 8 8 6 6 8

Non-Modifying Algorithms

#include <algorithm>

for_each

#include <algorithm>
...
template <typename T>
class ContInfo{
public:
  void operator()(T t){
    num++;
    sum+= t;
  }
  int getSum() const{ return sum; }
  int getSize() const{ return num; }
  double getMean() const{
    return static_cast<double>(sum)/static_cast<double>(num);
  }
private:
  T sum{0};
  int num{0};
};

std::vector<double> myVec{1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9};
auto vecInfo= std::for_each(myVec.begin(), myVec.end(), ContInfo<double>());

std::cout << vecInfo.getSum() << std::endl;    // 49
std::cout << vecInfo.getSize() << std::endl;   // 9
std::cout << vecInfo.getMean() << std::endl;   // 5.5

std::array<int, 100> myArr{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
auto arrInfo= std::for_each(myArr.begin(), myArr.end(), ContInfo<int>());

std::cout << arrInfo.getSum() << std::endl;    // 55
std::cout << arrInfo.getSize() << std::endl;   // 100
std::cout << arrInfo.getMean() << std::endl;   // 0.55

Search Elements

std::find, std::find_if, std::find_if_not, std::find_of, and std::adjacent_find

bool isVowel(char c){
  string myVowels{"aeiouäöü"};
  set<char> vowels(myVowels.begin(), myVowels.end());
  return (vowels.find(c) != vowels.end());
}

list<char> myCha{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'};
int cha[]= {'A', 'B', 'C'};

cout << *find(myCha.begin(), myCha.end(), 'g');             // g
cout << *find_if(myCha.begin(), myCha.end(), isVowel);      // a
cout << *find_if_not(myCha.begin(), myCha.end(), isVowel);  // b

auto iter= find_first_of(myCha.begin(), myCha.end(), cha, cha + 3);
if (iter == myCha.end()) cout << "None of A, B or C.";      // None of A, B or C.
auto iter2= find_first_of(myCha.begin(), myCha.end(), cha, cha+3, 
            [](char a, char b){ return toupper(a) == toupper(b); });

if (iter2 != myCha.end()) cout << *iter2;                   // a
auto iter3= adjacent_find(myCha.begin(), myCha.end());
if (iter3 == myCha.end()) cout << "No same adjacent chars."; 
                                        // No same adjacent chars.

auto iter4= adjacent_find(myCha.begin(), myCha.end(),
            [](char a, char b){ return isVowel(a) == isVowel(b); });
if (iter4 != myCha.end()) cout << *iter4;                   // b 
struct A{
    int v;
    bool operator==(A other){
        return other.v==v;
    }
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc,argv);
    QList<A> list{{1},{2}};
    auto it =std::find(list.begin(),list.end(),A{2});
    if(it==list.end())
        qDebug()<<"can not found it";
    else
        qDebug()<<(*it).v;
    return a.exec();
}
struct A{
    int v;
    bool operator==(A other){
        return other.v==v;
    }
};

struct comparator{
    bool operator()( A& a1, A& a2){
        qDebug()<<a1.v<<a2.v;
        return false;
    }
};


int main(int argc, char *argv[])
{
    QCoreApplication a(argc,argv);
    QList<A> list{{1},{2},{3},{4},{5}};
    auto it =std::adjacent_find(list.begin(),list.end(),comparator());//(1,2),(2,3),(3,4),(4,5)
    return a.exec();
}

Count Elements

std::count, and std::count_if

std::string str{"abcdabAAAaefaBqeaBCQEaadsfdewAAQAaafbd"};
std::cout << std::count(str.begin(), str.end(), 'a');              // 9
std::cout << std::count_if(str.begin(), str.end(),              
                           [](char a){ return std::isupper(a); }); // 12

Check Conditions on Ranges

std::all_of, std::any_of, and std::none_of

auto even= [](int i){ return i%2; };
std::vector<int> myVec{1, 2, 3, 4, 5, 6, 7, 8, 9};
std::cout << std::any_of(myVec.begin(), myVec.end(), even);  // true
std::cout << std::all_of(myVec.begin(), myVec.end(), even);  // false
std::cout << std::none_of(myVec.begin(), myVec.end(), even); // false

Compare Ranges

equal , mismatch

string str1{"Only For Testing Purpose."};
string str2{"only for testing purpose."};
cout << equal(str1.begin(), str1.end(), str2.begin());  // false
cout << equal(str1.begin(), str1.end(), str2.begin(),
              [](char c1, char c2){ return toupper(c1) == toupper(c2);} ); 
			                                          // true
str1= {"Only for testing Purpose."};
str2= {"Only for testing purpose."};
auto pair= mismatch(str1.begin(), str1.end(), str2.begin());
if (pair.first != str1.end()){
  cout << distance(str1.begin(), pair.first)
       << "at (" << *pair.first << "," << *pair.second << ")";  // 17 at (P,p)
}
auto pair2= mismatch(str1.begin(), str1.end(), str2.begin(),
                     [](char c1, char c2){ return toupper(c1) == toupper(c2); });
if (pair2.first == str1.end()){
  cout << "str1 and str2 are equal";  // str1 and str2 are equal
}

Search for Ranges within Ranges

search : Searches the second range in the first one and returns the position. Starts at the beginning

find_end : Searches the second range in the first one and returns the positions. Starts at the end

search_n : Searches count consecutive values in the first range:

std::array<int, 10> arr1{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
std::array<int, 5> arr2{3, 4, -5, 6, 7};

auto fwdIt= search(arr1.begin(), arr1.end(), arr2.begin(), arr2.end());
if (fwdIt == arr1.end()) std::cout << "arr2 not in arr1.";  // arr2 not in arr1.

auto fwdIt2= search(arr1.begin(), arr1.end(), arr2.begin(), arr2.end(),
                    [](int a, int b){ return std::abs(a) == std::abs(b); });
if (fwdIt2 != arr1.end()) std::cout << "arr2 at position "
                    << std::distance(arr1.begin(), fwdIt2) << " in arr1."; 
                                                  // arr2 at position 3 in arr1.

parallel Algorithms

#include <iostream>
#include <vector>
#include <execution>
#include <algorithm>
#include <stdlib.h>
#include<time.h>
#include<chrono>

int main(int argc,const char* argv[]){
    std::srand(time(nullptr));
    std::vector<double> values;
    for(int i=0;i<=9999999;i++){
        values.push_back(rand()%9999);
    }
    std::chrono::time_point<std::chrono::system_clock> tf=std::chrono::system_clock::now();
    std::for_each(std::execution::par_unseq,values.begin(),values.end(),[](double& el){el=el/12.0+120.0;});
    int res=std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now()-tf).count();
    std::cout<<res;


    return 0;
}

to use the execution library with Linux you have to install libtbb-dev and add -ltbb flag to the compiler