C++ 算法 移除區間元素

一 概述

  • C++ 標準庫中提供了很多算法,定義於頭文件 < algorithm >。本文主要探究以下用於 移除區間元素 的算法:
    • std::remove 移除滿足特定判別標準的元素
    • std::remove_if 移除滿足特定判別標準的元素
    • std::remove_copy 複製一個範圍的元素,忽略滿足特定判別標準的元素。
    • std::remove_copy_if 複製一個範圍的元素,忽略滿足特定判別標準的元素。
    • std::unique 移除範圍內的連續重複元素
    • std::unique_copy 創建某範圍的不含連續重複元素的副本

二 輔助函數

template <typename It1, typename It2>
void print2(const std::string& pre, const It1& beg, const It2& end) {
  std::cout << pre;
  std::copy(beg, end,
            std::ostream_iterator<int>(std::cout, " "));
  std::cout << std::endl;
}

三 std::remove

  • 定義
template< class ForwardIt, class T >
ForwardIt remove( ForwardIt first, ForwardIt last, const T& value );(1)(C++20)
template< class ForwardIt, class T >
constexpr ForwardIt remove( ForwardIt first, ForwardIt last, const T& value );(1)(C++20)
template< class ExecutionPolicy, class ForwardIt, class T >
ForwardIt remove( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, 
                  const T& value );(2)(C++17)
if (1) {
  // std::remove 移除滿足特定判別標準的元素
  std::vector<int> vc;
  fill(vc, 1, 9);
  print("before remove vc: ", vc);
  auto it = std::remove(vc.begin(), vc.end(), 1);
  print("after remove vc: ", vc);
  print2("after remove vc: ", vc.begin(), it);
}
  • 結果
before remove vc: 1 2 3 4 5 6 7 8 9
after remove vc: 2 3 4 5 6 7 8 9 9
after remove vc: 2 3 4 5 6 7 8 9
  • 說明
    • 移除滿足條件元素,後面的元素“移動賦值”。
    • 保持剩餘元素的相對順序,且不更改容器的物理大小。

四 std::remove_if

  • 定義
template< class ForwardIt, class UnaryPredicate >
ForwardIt remove_if( ForwardIt first, ForwardIt last, UnaryPredicate p );(1)(C++20)
template< class ForwardIt, class UnaryPredicate >
constexpr ForwardIt remove_if( ForwardIt first, ForwardIt last, UnaryPredicate p );(1)(C++20)
template< class ExecutionPolicy, class ForwardIt, class UnaryPredicate >
ForwardIt remove_if( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, 
                     UnaryPredicate p );(2)(C++17)
if (1) {
  // std::remove_if 移除滿足特定判別標準的元素
  std::vector<int> vc;
  fill(vc, 1, 9);
  print("before remove_if vc: ", vc);
  auto it = std::remove_if(vc.begin(), vc.end(), even);
  print("after remove_if vc: ", vc);
  print2("after remove_if vc: ", vc.begin(), it);
}
  • 結果
before remove_if vc: 1 2 3 4 5 6 7 8 9
after remove_if vc: 1 3 5 7 9 6 7 8 9
after remove_if vc: 1 3 5 7 9

五 std::remove_copy

  • 定義
template< class InputIt, class OutputIt, class T >
OutputIt remove_copy( InputIt first, InputIt last, OutputIt d_first, const T& value );(1)(C++20)
template< class InputIt, class OutputIt, class T >
constexpr OutputIt remove_copy( InputIt first, InputIt last, OutputIt d_first,
                                const T& value );(1)(C++20)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class T >
ForwardIt2 remove_copy( ExecutionPolicy&& policy, ForwardIt1 first, ForwardIt1 last,
                        ForwardIt2 d_first, const T& value );(2)(C++17)
  • Demo
if (1) {
  // std::remove_copy 複製一個範圍的元素,忽略滿足特定判別標準的元素
  std::vector<int> vc1;
  fill(vc1, 1, 9);
  std::vector<int> vc2;
  print("before remove_copy vc1: ", vc1);
  print("before remove_copy vc2: ", vc2);
  auto it = std::remove_copy(vc1.begin(), vc1.end(), std::back_inserter(vc2), 1);
  print("after remove_copy vc1: ", vc1);
  print("after remove_copy vc2: ", vc2);
}
  • 結果
before remove_copy vc1: 1 2 3 4 5 6 7 8 9
before remove_copy vc2:
after remove_copy vc1: 1 2 3 4 5 6 7 8 9
after remove_copy vc2: 2 3 4 5 6 7 8 9
  • 注意
    • 源與目標範圍不能重疊。

六 std::remove_copy_if

  • 定義
template< class InputIt, class OutputIt, class UnaryPredicate >
OutputIt remove_copy_if( InputIt first, InputIt last, OutputIt d_first, 
                         UnaryPredicate p );(1)(C++20)
template< class InputIt, class OutputIt, class UnaryPredicate >
constexpr OutputIt remove_copy_if( InputIt first, InputIt last, OutputIt d_first,
                                   UnaryPredicate p );(1)(C++20)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class UnaryPredicate >
ForwardIt2 remove_copy_if( ExecutionPolicy&& policy, ForwardIt1 first, ForwardIt1 last,
                           ForwardIt2 d_first, UnaryPredicate p );(2)(C++17)
  • Demo
if (1) {
  // std::remove_copy_if 複製一個範圍的元素,忽略滿足特定判別標準的元素
  std::vector<int> vc1;
  fill(vc1, 1, 9);
  std::vector<int> vc2;
  print("before remove_copy_if vc1: ", vc1);
  print("before remove_copy_if vc2: ", vc2);
  auto it =
      std::remove_copy_if(vc1.begin(), vc1.end(), std::back_inserter(vc2), even);
  print("after remove_copy_if vc1: ", vc1);
  print("after remove_copy_if vc2: ", vc2);
}
  • 結果
before remove_copy_if vc1: 1 2 3 4 5 6 7 8 9
before remove_copy_if vc2:
after remove_copy_if vc1: 1 2 3 4 5 6 7 8 9
after remove_copy_if vc2: 1 3 5 7 9
  • 注意
    • 源與目標範圍不能重疊。

七 std::unique

  • 定義
template< class ForwardIt >
ForwardIt unique( ForwardIt first, ForwardIt last );(1)(C++20)
template< class ForwardIt >
constexpr ForwardIt unique( ForwardIt first, ForwardIt last );(1)(C++20)
template< class ExecutionPolicy, class ForwardIt >
ForwardIt unique( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last );(2)(C++17)
template< class ForwardIt, class BinaryPredicate >
ForwardIt unique( ForwardIt first, ForwardIt last, BinaryPredicate p );(3)(C++20)
template< class ForwardIt, class BinaryPredicate >
constexpr ForwardIt unique( ForwardIt first, ForwardIt last, BinaryPredicate p );(3)(C++20)
template< class ExecutionPolicy, class ForwardIt, class BinaryPredicate >
ForwardIt unique( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, 
                  BinaryPredicate p );(4)(C++17)
  • Demo
if (1) {
  // std::unique 移除範圍內的連續重複元素
  std::vector<int> vc{1,2,2,2,3,3,4,5,6,7,8,9};
  print("before unique vc: ", vc);
  auto it = std::unique(vc.begin(), vc.end());
  print("after unique vc: ", vc);
  print2("after unique vc: ", vc.begin(), it);
}
if (1) {
  // std::unique
  std::vector<int> vc{1, 2, 2, 2, 3, 3, 4, 5, 6, 7, 8, 9};
  print("before unique vc: ", vc);
  auto it = std::unique(vc.begin(), vc.end(), my_equal);
  print("after unique vc: ", vc);
  print2("after unique vc: ", vc.begin(), it);
}
  • 結果
before unique vc: 1 2 2 2 3 3 4 5 6 7 8 9
after unique vc: 1 2 3 4 5 6 7 8 9 7 8 9
after unique vc: 1 2 3 4 5 6 7 8 9

before unique vc: 1 2 2 2 3 3 4 5 6 7 8 9
after unique vc: 1 2 3 4 5 6 7 8 9 7 8 9
after unique vc: 1 2 3 4 5 6 7 8 9
  • 說明
    • 通過用覆寫要被擦除的元素的方式遷移範圍中的元素進行移除。保持剩餘元素的相對順序,且不更改容器的物理大小。
    • 另一個unique的詳細例子請參考此前文章 std::vector 去重。

八 std::unique_copy

  • 定義
template< class InputIt, class OutputIt >
OutputIt unique_copy( InputIt first, InputIt last, OutputIt d_first );(1)(C++20)
template< class InputIt, class OutputIt >
constexpr OutputIt unique_copy( InputIt first, InputIt last, OutputIt d_first );(1)(C++20)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2 >
ForwardIt2 unique_copy( ExecutionPolicy&& policy, ForwardIt1 first, ForwardIt1 last,
                        ForwardIt2 d_first );(2)(C++17)	
template< class InputIt, class OutputIt, class BinaryPredicate >
OutputIt unique_copy( InputIt first, InputIt last,
                      OutputIt d_first, BinaryPredicate p );(3)(C++20)
template< class InputIt, class OutputIt, class BinaryPredicate >
constexpr OutputIt unique_copy( InputIt first, InputIt last,
                                OutputIt d_first, BinaryPredicate p );(3)(C++20)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class BinaryPredicate >
ForwardIt2 unique_copy( ExecutionPolicy&& policy, ForwardIt1 first, ForwardIt1 last,
                        ForwardIt2 d_first, BinaryPredicate p );(4)(C++17)
  • Demo
if(1){
// std::unique_copy 創建某範圍的不含連續重複元素的副本
  std::vector<int> vc1{1, 2, 2, 2, 3, 3, 4, 5, 6, 7, 8, 9};
  std::vector<int> vc2;
  print("before unique_copy vc1: ", vc1);
  print("before unique_copy vc2: ", vc2);
  auto it =
      std::unique_copy(vc1.begin(), vc1.end(), std::back_inserter(vc2));
  print("after unique_copy vc1: ", vc1);
  print("after unique_copy vc2: ", vc2);
}
if (1) {
  // std::unique_copy
  std::vector<int> vc1{1, 2, 2, 2, 3, 3, 4, 5, 6, 7, 8, 9};
  std::vector<int> vc2;
  print("before unique_copy vc1: ", vc1);
  print("before unique_copy vc2: ", vc2);
  auto it =
      std::unique_copy(vc1.begin(), vc1.end(), std::back_inserter(vc2), my_equal);
  print("after unique_copy vc1: ", vc1);
  print("after unique_copy vc2: ", vc2);
}
  • 結果
before unique_copy vc1: 1 2 2 2 3 3 4 5 6 7 8 9
before unique_copy vc2:
after unique_copy vc1: 1 2 2 2 3 3 4 5 6 7 8 9
after unique_copy vc2: 1 2 3 4 5 6 7 8 9

before unique_copy vc1: 1 2 2 2 3 3 4 5 6 7 8 9
before unique_copy vc2:
after unique_copy vc1: 1 2 2 2 3 3 4 5 6 7 8 9
after unique_copy vc2: 1 2 3 4 5 6 7 8 9

九 github

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

十 參考

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