C++ 標準庫 變序型算法

一 概述

  • C++ 標準庫中提供了很多算法,定義於頭文件 < algorithm >。本文主要探究以下用於 區間元素變序 的算法:
    • std::reverse 逆轉範圍中的元素順序
    • std::reverse_copy 創建一個範圍的逆向副本
    • std::rotate 旋轉範圍中的元素順序
    • std::rotate_copy 複製並旋轉元素範圍
    • std::next_permutation 產生某個元素範圍的按字典順序的下一個較大的排列
    • std::prev_permutation 產生某個元素範圍的按字典順序的下一個較小的排列
    • std::shuffle(C++11) 隨機重排範圍中的元素
    • std::random_shuffle(C++14棄用C++17移除) 隨機重排範圍中的元素
    • std::partition 將範圍中的元素分爲兩組
    • std::stable_partition 將元素分爲兩組,同時保留其相對順序
    • std::partition_copy 複製並將範圍中的元素分爲兩組

二 輔助函數

三 std::reverse

  • 定義
template< class BidirIt >
void reverse( BidirIt first, BidirIt last );(1)(C++20)
template< class BidirIt >
constexpr void reverse( BidirIt first, BidirIt last );(1)(C++20)
template< class ExecutionPolicy, class BidirIt >
void reverse( ExecutionPolicy&& policy, BidirIt first,
              BidirIt last );(2)(C++17)
if (1) {
  // std::reverse 逆轉範圍中的元素順序
  std::vector<int> vc;
  fill(vc, 1, 9);
  print("before reverse vc: ", vc);
  std::reverse(vc.begin(), vc.end());
  print(" after reverse vc: ", vc);
}
  • 結果
before reverse vc: 1 2 3 4 5 6 7 8 9
 after reverse vc: 9 8 7 6 5 4 3 2 1

四 std::reverse_copy

  • 定義
template< class BidirIt, class OutputIt >
OutputIt reverse_copy( BidirIt first, BidirIt last, OutputIt d_first );(1)(C++20)
template< class BidirIt, class OutputIt >
constexpr OutputIt reverse_copy( BidirIt first, BidirIt last, OutputIt d_first);(1)(C++20)
template< class ExecutionPolicy, class BidirIt, class ForwardIt >
ForwardIt reverse_copy( ExecutionPolicy&& policy, BidirIt first, BidirIt last,
                        ForwardIt d_first );(2)(C++17)
if (1) {
  // std::reverse_copy 創建一個範圍的逆向副本
  std::vector<int> vc1;
  fill(vc1, 1, 9);
  std::vector<int> vc2;
  print("before reverse_copy vc1: ", vc1);
   print("before reverse_copy vc2: ", vc2);
  std::reverse_copy(vc1.begin(), vc1.end(), std::back_inserter(vc2));
  print(" after reverse_copy vc1: ", vc1);
  print(" after reverse_copy vc2: ", vc2);
}
  • 結果
before reverse_copy vc1: 1 2 3 4 5 6 7 8 9
before reverse_copy vc2:
 after reverse_copy vc1: 1 2 3 4 5 6 7 8 9
 after reverse_copy vc2: 9 8 7 6 5 4 3 2 1

五 std::rotate

  • 定義
template< class ForwardIt >
void      rotate( ForwardIt first, ForwardIt n_first, ForwardIt last );(1)(C++11)
template< class ForwardIt >
ForwardIt rotate( ForwardIt first, ForwardIt n_first, 
                  ForwardIt last );(1)(C++11)(C++20)
template< class ForwardIt >
constexpr ForwardIt
          rotate( ForwardIt first, ForwardIt n_first, ForwardIt last );(1)(C++20)
template< class ExecutionPolicy, class ForwardIt >
ForwardIt rotate( ExecutionPolicy&& policy,
                  ForwardIt first, ForwardIt n_first, ForwardIt last );(2)(C++17)
  • 說明
    • std::rotate 交換範圍 [first, last) 中的元素,操作後滿足元素 n_first 成爲新範圍的首個元素,而 n_first - 1 成爲最後元素。
    • 前提條件是 [first, n_first) 和 [n_first, last) 爲合法範圍。
  • Demo
if (1) {
  // std::rotate 旋轉範圍中的元素順序
  std::vector<int> vc;
  fill(vc, 1, 9);
  print("before rotate vc: ", vc);
  std::rotate(vc.begin(), vc.begin() + 3, vc.end());
  print(" after rotate vc: ", vc);
}
  • 結果
before rotate vc: 1 2 3 4 5 6 7 8 9
 after rotate vc: 4 5 6 7 8 9 1 2 3

六 std::rotate_copy

  • 定義
template< class ForwardIt, class OutputIt >
OutputIt rotate_copy( ForwardIt first, ForwardIt n_first,
                      ForwardIt last, OutputIt d_first );(1)(C++20)
template< class ForwardIt, class OutputIt >
constexpr OutputIt rotate_copy( ForwardIt first, ForwardIt n_first,
                                ForwardIt last, OutputIt d_first );(1)(C++20)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2 >
ForwardIt2 rotate_copy( ExecutionPolicy&& policy, ForwardIt1 first, ForwardIt1 n_first,
                        ForwardIt1 last, ForwardIt2 d_first );(2)(C++17)
  • Demo
if (1) {
  // std::rotate_copy 複製並旋轉元素範圍
  std::vector<int> vc1;
  fill(vc1, 1, 9);
  std::vector<int> vc2;
  print("before rotate_copy vc1: ", vc1);
  print("before rotate_copy vc2: ", vc2);
  std::rotate_copy(vc1.begin(), vc1.begin() + 3, vc1.end(), std::back_inserter(vc2));
  print(" after rotate_copy vc1: ", vc1);
  print(" after rotate_copy vc2: ", vc2);
}
  • 結果
before rotate_copy vc1: 1 2 3 4 5 6 7 8 9
before rotate_copy vc2:
 after rotate_copy vc1: 1 2 3 4 5 6 7 8 9
 after rotate_copy vc2: 4 5 6 7 8 9 1 2 3

七 std::next_permutation

  • 定義
template< class BidirIt >
bool next_permutation( BidirIt first, BidirIt last );(1)(C++20)
template< class BidirIt >
constexpr bool next_permutation( BidirIt first, BidirIt last );(1)(C++20)
template< class BidirIt, class Compare >
bool next_permutation( BidirIt first, BidirIt last, Compare comp );(2)(C++20)
template< class BidirIt, class Compare >
constexpr bool next_permutation( BidirIt first, BidirIt last, Compare comp );(2)(C++20)
  • Demo
if (1) {
  // std::next_permutation 產生某個元素範圍的按字典順序的下一個較大的排列
  std::vector<int> vc;
  fill(vc, 1, 3);
  print("before next_permutation vc: ", vc);
  while(std::next_permutation(vc.begin(), vc.end())){
    print(" after next_permutation vc: ", vc);
  }
}
  • 結果
before next_permutation vc: 1 2 3
 after next_permutation vc: 1 3 2
 after next_permutation vc: 2 1 3
 after next_permutation vc: 2 3 1
 after next_permutation vc: 3 1 2
 after next_permutation vc: 3 2 1

八 std::prev_permutation

  • 定義
template< class BidirIt >
bool prev_permutation( BidirIt first, BidirIt last);(1)(C++20)
template< class BidirIt >
constexpr bool prev_permutation( BidirIt first, BidirIt last);(1)(C++20)	
template< class BidirIt, class Compare >
bool prev_permutation( BidirIt first, BidirIt last, Compare comp);(2)(C++20)
template< class BidirIt, class Compare >
constexpr bool prev_permutation( BidirIt first, BidirIt last, 
                                 Compare comp);(2)(C++20)
  • Demo
if (1) {
  // std::prev_permutation 產生某個元素範圍的按字典順序的下一個較小的排列
  std::vector<int> vc{3,2,1};
  print("before prev_permutation vc: ", vc);
  while (std::prev_permutation(vc.begin(), vc.end())) {
    print(" after prev_permutation vc: ", vc);
  }
}
  • 結果
before prev_permutation vc: 3 2 1
 after prev_permutation vc: 3 1 2
 after prev_permutation vc: 2 3 1
 after prev_permutation vc: 2 1 3
 after prev_permutation vc: 1 3 2
 after prev_permutation vc: 1 2 3

九 std::shuffle(C++11)

  • 定義
template< class RandomIt, class URBG >
void shuffle( RandomIt first, RandomIt last, URBG&& g );(C++11)
  • g爲隨機數生成器,標準未欽定實現,所以即使你用準確相同的URBG ,也可能通過不同的標準庫實現得到不同結果。
  • Demo
if (1) {
  // std::shuffle(C++11) 隨機重排範圍中的元素
  std::vector<int> vc;
  fill(vc, 1, 9);
  print("before shuffle vc: ", vc);
  std::shuffle(vc.begin(), vc.end(), std::random_device());
  print(" after shuffle vc: ", vc);
}
  • 結果
before shuffle vc: 1 2 3 4 5 6 7 8 9
 after shuffle vc: 5 7 2 3 8 6 4 1 9

十 std::random_shuffle

  • 定義
template< class RandomIt >
void random_shuffle( RandomIt first, RandomIt last );(1)(C++14中棄用)(C++17中移除)	
template< class RandomIt, class RandomFunc >
void random_shuffle( RandomIt first, RandomIt last, RandomFunc& r );(2)(C++11)
template< class RandomIt, class RandomFunc >
void random_shuffle( RandomIt first, RandomIt last,
                     RandomFunc&& r );(2)(C++11)(C++14 中棄用)(C++17 中移除)
  • Demo
if (1) {
  // std::random_shuffle(C++14棄用C++17移除) 隨機重排範圍中的元素
  std::vector<int> vc;
  fill(vc, 1, 9);
  print("before random_shuffle vc: ", vc);
  std::random_shuffle(vc.begin(), vc.end());
  print(" after random_shuffle vc: ", vc);
}
  • 結果
before random_shuffle vc: 1 2 3 4 5 6 7 8 9
 after random_shuffle vc: 9 2 7 3 1 6 8 4 5

十一 std::partition

  • 定義
template< class BidirIt, class UnaryPredicate >
BidirIt partition( BidirIt first, BidirIt last, UnaryPredicate p );(1)(C++11)
template< class ForwardIt, class UnaryPredicate >
ForwardIt partition( ForwardIt first, ForwardIt last, UnaryPredicate p );(1)(C++11)(C++20)
template< class ForwardIt, class UnaryPredicate >
constexpr ForwardIt partition( ForwardIt first, ForwardIt last, UnaryPredicate p );(1)(C++20)
template< class ExecutionPolicy, class ForwardIt, class UnaryPredicate >
ForwardIt partition( ExecutionPolicy&& policy,
                     ForwardIt first, ForwardIt last, UnaryPredicate p );(2)(C++17)
if (1) {
  // std::partition 將範圍中的元素分爲兩組
  std::vector<int> vc;
  fill(vc, 1, 9);
  print("before partition vc: ", vc);
  std::partition(vc.begin(), vc.end(), even);
  print(" after partition vc: ", vc);
}
  • 結果
before partition vc: 1 2 3 4 5 6 7 8 9
 after partition vc: 8 2 6 4 5 3 7 1 9

十二 std::stable_partition

  • 定義
template< class BidirIt, class UnaryPredicate >
BidirIt stable_partition( BidirIt first, BidirIt last, UnaryPredicate p );(1)	
template< class ExecutionPolicy, class BidirIt, class UnaryPredicate >
BidirIt stable_partition( ExecutionPolicy&& policy, BidirIt first, BidirIt last, 
                          UnaryPredicate p );(2)(C++17)
if (1) {
  // std::stable_partition 將元素分爲兩組,同時保留其相對順序
  std::vector<int> vc;
  fill(vc, 1, 9);
  print("before stable_partition vc: ", vc);
  std::stable_partition(vc.begin(), vc.end(), even);
  print(" after stable_partition vc: ", vc);
}
  • 結果
before stable_partition vc: 1 2 3 4 5 6 7 8 9
 after stable_partition vc: 2 4 6 8 1 3 5 7 9

十三 std::partition_copy

  • 定義
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 );(1)(C++11)(C++20)
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 );(1)(C++20)
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 );(2)(C++17)
  • 說明
    • ExecutionPolicy 請參考此前文章 std::find std::execution。
    • 從範圍 [first, last) 複製元素到二個不同範圍,取決於謂詞 p 的返回值。複製滿足謂詞 p 的元素到始於 d_first_true 的範圍。複製剩餘元素到始於 d_first_false 的範圍。
    • 若輸入範圍與任一輸出範圍重疊,則行爲未定義。
  • Demo
if (1) {
  // std::partition_copy 複製並將範圍中的元素分爲兩組
  std::vector<int> vc;
  fill(vc, 1, 9);
  std::vector<int> vc_true;
  std::vector<int> vc_false;
  print("before partition_copy vc: ", vc);
  print("before partition_copy vc_true: ", vc_true);
  print("before partition_copy vc_false: ", vc_false);
  std::partition_copy(vc.begin(), vc.end(), std::back_inserter(vc_true), 
                      std::back_inserter(vc_false), even);
  print(" after partition_copy vc: ", vc);
  print(" after partition_copy vc_true: ", vc_true);
  print(" after partition_copy vc_false: ", vc_false);
}
  • 結果
before partition_copy vc: 1 2 3 4 5 6 7 8 9
before partition_copy vc_true:
before partition_copy vc_false:
 after partition_copy vc: 1 2 3 4 5 6 7 8 9
 after partition_copy vc_true: 2 4 6 8
 after partition_copy vc_false: 1 3 5 7 9

十四 github

  • 所有Demo 已上傳github cplusplus
  • mutating_algorithm.cpp

十五 參考

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章