作者:王一哲
日期:2023年8月24日
C++ algorithm 函式庫中有許多好用的工具,例如排序用的 sort、反轉資料用的 reverse,在 APCS 及 能力競賽中都能使用 algorithm 函式庫,善用這些工具可以少寫很多程式碼。接下來的的程式碼中都省略了以下幾行
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
語法為
all_of(起點位址, 終點位址, 條件);
測試範圍包含起點位址,不包含終點位址,如果範圍中所有的元素皆符合條件或是範圍中沒有任何元素回傳 1,如果有任何一個元素不符合條件回傳 0。例如以下的程式碼
bool isPositive (int n) {
return n > 0;
}
int main() {
vector<int> a = {1, 3, 5, -2, -4, -6};
cout << all_of(a.begin(), a.end(), isPositive) << endl; // 印出 0
cout << all_of(a.begin(), a.end(), [](int x){return x > 0;}) << endl; // 印出 0
vector<int> b = {1, 3, 5, 2, 4, 6};
cout << all_of(b.begin(), b.end(), [](int x){return x > 0;}) << endl; // 印出 1
vector<int> c;
cout << all_of(c.begin(), c.end(), [](int x){return x > 0;}) << endl; // 印出 1
return 0;
}
語法為
any_of(起點位址, 終點位址, 條件);
測試範圍包含起點位址,不包含終點位址,如果範圍中任何一個元素符合條件回傳 1,如果所有元素皆不符合條件或是範圍中沒有任何元素回傳 0。例如以下的程式碼
bool isPositive (int n) {
return n > 0;
}
int main() {
vector<int> a = {1, 3, 5, -2, -4, -6};
cout << any_of(a.begin(), a.end(), isPositive) << endl; // 印出 1
cout << any_of(a.begin(), a.end(), [](int x){return x > 0;}) << endl; // 印出 1
vector<int> b = {-1, -3, -5, -2, -4, -6};
cout << any_of(b.begin(), b.end(), [](int x){return x > 0;}) << endl; // 印出 0
vector<int> c;
cout << any_of(c.begin(), c.end(), [](int x){return x > 0;}) << endl; // 印出 0
return 0;
}
語法為
none_of(起點位址, 終點位址, 條件);
測試範圍包含起點位址,不包含終點位址,如果範圍中沒有任何一個元素符合條件或是範圍中沒有任何元素回傳 1,如果所有元素皆符合條件回傳 0。例如以下的程式碼
bool isPositive (int n) {
return n > 0;
}
int main() {
vector<int> a = {1, 3, 5, -2, -4, -6};
cout << none_of(a.begin(), a.end(), isPositive) << endl; // 印出 0
cout << none_of(a.begin(), a.end(), [](int x){return x > 0;}) << endl; // 印出 0
vector<int> b = {-1, -3, -5, -2, -4, -6};
cout << none_of(b.begin(), b.end(), [](int x){return x > 0;}) << endl; // 印出 1
vector<int> c;
cout << none_of(c.begin(), c.end(), [](int x){return x > 0;}) << endl; // 印出 1
return 0;
}
語法為
for_each(起點位址, 終點位址, 自訂函式);
範圍包含起點位址,不包含終點位址。例如以下的程式碼,編譯後執行會印出 1 3 5 2 4 6。
void myfunc (int n) {
cout << n << " ";
}
int main() {
vector<int> a = {1, 3, 5, 2, 4, 6};
for_each(a.begin(), a.end(), myfunc);
cout << endl;
for_each(a.begin(), a.end(), [](int x){cout << x << " ";});
cout << endl;
return 0;
}
語法為
find(起點位址, 終點位址, 指定的元素);
範圍包含起點位址,不包含終點位址。如果有找到指定的元素,會回傳對應的迭代器,如果範圍中有好幾個指定的元素,只會回傳第一個;如果沒有找到指定的元素,會回傳終點位址對應的迭代器。例如以下的程式碼。
vector<int> a = {1, 2, 1, 2, 1, 2};
auto it = find(a.begin(), a.end(), 2);
cout << it - a.begin() << endl; // it - a.begin() 才會是索引值,印出 1
if (find(a.begin(), a.end(), -1) == a.end())
cout << "-1 is not in a." << endl; // -1 不在 a 之中
語法為
find_if(起點位址, 終點位址, 條件);
範圍包含起點位址,不包含終點位址。如果有找到符合條件的元素,會回傳對應的迭代器,如果範圍中有好幾個符合條件的元素,只會回傳第一個;如果沒有找到符合條件的元素,會回傳終點位址對應的迭代器。例如以下的程式碼。
bool isEven (int n) {
return n%2 == 0;
}
int main() {
vector<int> a = {1, 3, 5, 2, 4, 6};
auto it = find_if(a.begin(), a.end(), isEven);
cout << it - a.begin() << endl; // it - a.begin() 才會是索引值,印出 3
auto it2 = find_if(a.begin(), a.end(), [](int x){return x%2 == 0;});
cout << it2 - a.begin() << endl; // it2 - a.begin() 才會是索引值,印出 3
vector<int> b = {1, 3, 5, 7, 9, 11};
auto it3 = find_if(b.begin(), b.end(), isEven);
cout << it3 - b.begin() << endl; // it3 - b.begin() 才會是索引值,印出 6,b 當中所有的元素都是奇數
auto it4 = find_if(b.begin(), b.end(), [](int x){return x%2 == 0;});
cout << it4 - b.begin() << endl; // it4 - b.begin() 才會是索引值,印出 6,b 當中所有的元素都是奇數
return 0;
}
語法為
find_if_not(起點位址, 終點位址, 條件);
範圍包含起點位址,不包含終點位址。如果有找到不符合條件的元素,會回傳對應的迭代器,如果範圍中有好幾個不符合條件的元素,只會回傳第一個;如果沒有找到不符合條件的元素,會回傳終點位址對應的迭代器。例如以下的程式碼。
bool isEven (int n) {
return n%2 == 0;
}
int main() {
vector<int> a = {1, 3, 5, 2, 4, 6};
auto it = find_if_not(a.begin(), a.end(), isEven);
cout << it - a.begin() << endl; // it - a.begin() 才會是索引值,印出 0
auto it2 = find_if_not(a.begin(), a.end(), [](int x){return x%2 == 0;});
cout << it2 - a.begin() << endl; // it2 - a.begin() 才會是索引值,印出 0
vector<int> b = {2, 4, 6, 8, 10, 12};
auto it3 = find_if_not(b.begin(), b.end(), isEven);
cout << it3 - b.begin() << endl; // it3 - b.begin() 才會是索引值,印出 6,b 當中所有的元素都是偶數
auto it4 = find_if_not(b.begin(), b.end(), [](int x){return x%2 == 0;});
cout << it4 - b.begin() << endl; // it4 - b.begin() 才會是索引值,印出 6,b 當中所有的元素都是偶數
return 0;
}
語法為
find_end(起點位址, 終點位址, 子序列起點位址, 子序列終點位址);
範圍包含起點位址,不包含終點位址。如果有找到子序列,會回傳對應的迭代器,如果範圍中有好幾個子序列,只會回傳最後一個;如果沒有找到子序列,會回傳終點位址對應的迭代器。例如以下的程式碼。
vector<int> a = {1, 3, 5, 2, 4, 6, 1, 3, 5, 2, 4, 6}, b = {5, 2, 4}, c = {-1, -2, -3};
auto it = find_end(a.begin(), a.end(), b.begin(), b.end());
cout << it - a.begin() << endl; // it - a.begin() 才會是索引值,印出 8
auto it2 = find_end(a.begin(), a.end(), c.begin(), c.end());
cout << it2 - a.begin() << endl; // it2 - a.begin() 才會是索引值,印出 12
語法為
find_first_of(起點位址, 終點位址, 起點位址1, 終點位址2);
範圍包含起點位址,不包含終點位址。如果有找到範圍2中任何一個元素,會回傳對應的迭代器,如果範圍1中有好幾個範圍2中任何一個元素,只會回傳第一個;如果沒有找到範圍2中任何一個元素,會回傳終點位址對應的迭代器。例如以下的程式碼。
vector<int> a = {1, 3, 5, 2, 4, 6, 1, 3, 5, 2, 4, 6}, b = {2, 5, 4}, c = {-1, -2, -3};
auto it = find_first_of(a.begin(), a.end(), b.begin(), b.end());
cout << it - a.begin() << endl; // it - a.begin() 才會是索引值,印出 2
auto it2 = find_first_of(a.begin(), a.end(), c.begin(), c.end());
cout << it2 - a.begin() << endl; // it2 - a.begin() 才會是索引值,印出 12
語法為
adjancet_find(起點位址, 終點位址);
範圍包含起點位址,不包含終點位址。如果有找到兩個相鄰且相同的元素,會回傳第一個元素對應的迭代器,如果範圍中有好幾組兩個相鄰且相同的元素,只會回傳第一組;如果沒有找到兩個相鄰且相同的元素,會回傳終點位址對應的迭代器。例如以下的程式碼。
vector<int> a = {1, 3, 5, 2, 2, 1, 3, 5, 3, 3, 4, 6};
auto it = adjacent_find(a.begin(), a.end());
cout << "a[" << it - a.begin() << "] = " << *it << endl; // 印出 a[3] = 2
auto it2 = adjacent_find(++it, a.end());
cout << "a[" << it2 - a.begin() << "] = " << *it2 << endl; // 印出 a[8] = 3
vector<int> b = {1, 3, 5, 2, 4, 6};
auto it3 = adjacent_find(b.begin(), b.end());
cout << it3 - b.begin() << endl; // 印出 6
語法為
count(起點位址, 終點位址, 指定的元素);
範圍包含起點位址,不包含終點位址,回傳值格式為 int。例如以下的程式碼。
vector<int> a = {1, 3, 5, 2, 4, 6, 1, 1, 2, 2, 2, 3};
cout << count(a.begin(), a.end(), 1) << endl; // 印出 3
cout << count(a.begin(), a.end(), -1) << endl; // 印出 0
語法為
count_if(起點位址, 終點位址, 條件);
範圍包含起點位址,不包含終點位址,回傳值格式為 int。例如以下的程式碼。
bool isEven (int n) {
return n%2 == 0;
}
int main() {
vector<int> a = {1, 3, 5, 2, 4, 6, 8};
cout << count_if(a.begin(), a.end(), isEven) << endl; // 印出 4
cout << count_if(a.begin(), a.end(), [](int x){return x%2 == 0;}) << endl; // 印出 4
cout << count_if(a.begin(), a.end(), [](int x){return x < 0;}) << endl; // 印出 0
return 0;
}
語法為
mismatch(起點位址, 終點位址, 起點位址2, 終點位址2);
範圍包含起點位址,不包含終點位址,回傳值格式為兩個迭代器的 pair。例如以下的程式碼。
vector<int> a = {1, 3, 5, 2, 4, 6}, b = {1, 2, 5, 2, 3, 6};
auto it = mismatch(a.begin(), a.end(), b.begin(), b.end());
cout << "The first mismatching elements are " << *it.first << " and " << *it.second << endl; // 印出 The first mismatching elements are 3 and 2
it = mismatch(++(it.first), a.end(), ++(it.second), b.end());
cout << "The second mismatching elements are " << *it.first << " and " << *it.second << endl; // 印出 The first mismatching elements are 4 and 3
語法為
equal(起點位址, 終點位址, 起點位址2, 終點位址2);
範圍包含起點位址,不包含終點位址,回傳值格式為 1 或 0。例如以下的程式碼。
vector<int> a = {1, 3, 5, 2, 4, 6}, b = {2, 4, 6};
cout << equal(a.begin(), a.end(), b.begin(), b.end()) << endl; // 印出 0
cout << equal(a.begin()+3, a.end(), b.begin(), b.end()) << endl; // 印出 1
語法為
is_permutation(起點位址, 終點位址, 起點位址2, 終點位址2);
範圍包含起點位址,不包含終點位址,回傳值格式為 1 或 0。例如以下的程式碼。
vector<int> a = {1, 3, 5, 2, 4, 6}, b = {2, 6, 4};
cout << is_permutation(a.begin(), a.end(), b.begin(), b.end()) << endl; // 印出 0
cout << is_permutation(a.begin()+3, a.end(), b.begin(), b.end()) << endl; // 印出 1
語法為
search(起點位址, 終點位址, 子序列起點位址, 子序列終點位址);
範圍包含起點位址,不包含終點位址。如果有找到子序列,會回傳對應的迭代器,如果範圍中有好幾個子序列,只會回傳第一個;如果沒有找到子序列,會回傳終點位址對應的迭代器。例如以下的程式碼。
vector<int> a = {1, 3, 5, 2, 4, 6, 1, 3, 5}, b = {3, 5}, c = {2, 6};
auto it = search(a.begin(), a.end(), b.begin(), b.end());
if (it != a.end()) {
cout << "{3, 5} is found in a[" << it - a.begin() << "]" << endl; // 印出 1
} else {
cout << "{3, 5} is not found in a." << endl;
}
auto it2 = search(a.begin(), a.end(), c.begin(), c.end());
if (it2 != a.end()) {
cout << "{2, 6} is found in a[" << it2 - a.begin() << "]" << endl;
} else {
cout << "{2, 6} is not found in a." << endl; // 印出 {2, 6} is not found in a.
}
語法為
search_n(起點位址, 終點位址, 數量, 特定元素);
範圍包含起點位址,不包含終點位址。如果有找到連續且指定數量的特定元素,會回傳第一個元素對應的迭代器;如果沒有找到連續且指定數量的特定元素,會回傳終點位址對應的迭代器。例如以下的程式碼。
vector<int> a = {1, 3, 3, 5, 5, 5, 7, 7, 7, 7};
auto it = search_n(a.begin(), a.end(), 2, 3);
if (it != a.end()) {
cout << "Two 3s are found in a[" << it - a.begin() << "]" << endl; // 印出 1
} else {
cout << "Two 3s are not found in a." << endl;
}
auto it2 = search_n(a.begin(), a.end(), 4, 5);
if (it2 != a.end()) {
cout << "Four 5s are found in a[" << it2 - a.begin() << "]" << endl;
} else {
cout << "Four 5s are not found in a." << endl; // 印出 Four 5s are not found in a.
}
vector<int> b = {1, 3, 5, 7, 3, 5, 7, 5, 7, 7};
auto it3 = search_n(b.begin(), b.end(), 2, 3);
cout << it3 - b.begin() << endl; // 印出 10
語法為
copy(起點位址, 終點位址, 存放資料起點位址);
範圍包含起點位址,不包含終點位址。例如以下的程式碼。
vector<int> a = {1, 2, 3, 4, 5, 6}, b (6);
copy(a.begin()+2, a.end()-1, b.begin()); // b 的長度為 6,只複製了 3 個元素
for(auto it = b.begin(); it != b.end(); it++)
cout << *it << " \n"[it == b.end()-1]; // 印出 3 4 5 0 0 0
vector<int> c (a.begin()+2, a.end()-1); // 也可以在建立 vector 時複製資料
for(auto it = c.begin(); it != c.end(); it++)
cout << *it << " \n"[it == c.end()-1]; // 印出 3 4 5
語法為
copy_n(起點位址, 數量, 存放資料起點位址);
範圍包含起點位址,不包含終點位址,存放資料的容器長度要大於、等於複製資料的數量。例如以下的程式碼。
vector<int> a = {1, 2, 3, 4, 5, 6}, b (6), c (6);
copy_n(a.begin()+2, 3, b.begin());
for(auto it = b.begin(); it != b.end(); it++)
cout << *it << " \n"[it == b.end()-1]; // 印出 3 4 5 0 0 0
copy_n(a.begin(), 6, c.begin());
for(auto it = c.begin(); it != c.end(); it++)
cout << *it << " \n"[it == c.end()-1]; // 印出 1 2 3 4 5 6
語法為
copy_if(起點位址, 終點位址, 存放資料起點位址, 條件);
範圍包含起點位址,不包含終點位址,存放資料的容器長度要大於、等於複製資料的數量。例如以下的程式碼。
vector<int> a = {1, 2, 3, 4, 5, 6}, b (6), c (6);
copy_if(a.begin(), a.end(), b.begin(), [](int x){return x%2 == 0;});
for(auto it = b.begin(); it != b.end(); it++)
cout << *it << " \n"[it == b.end()-1]; // 印出 2 4 6 0 0 0
copy_if(a.begin(), a.end(), c.begin(), [](int x){return x%2 == 1;});
for(auto it = c.begin(); it != c.end(); it++)
cout << *it << " \n"[it == c.end()-1]; // 印出 1 3 5 0 0 0
語法為
copy_backward(起點位址, 終點位址, 存放資料終點位址);
範圍包含起點位址,不包含終點位址,存放資料的容器長度要大於、等於複製資料的數量,填入的資料仍然按照原來的順序。例如以下的程式碼。
vector<int> a = {1, 2, 3, 4, 5, 6}, b (8);
copy_backward(a.begin(), a.end(), b.end());
for(auto it = b.begin(); it != b.end(); it++)
cout << *it << " \n"[it == b.end()-1]; // 印出 0 0 1 2 3 4 5 6
語法為
move(起點位址, 終點位址, 存放資料起點位址);
存放資料容器名稱 = move(來源資料容器名稱);
範圍包含起點位址,不包含終點位址,存放資料的容器長度要大於、等於複製資料的數量。例如以下的程式碼,在說明書中像是第2行程式碼會清空 a 的內容,但是我測試時 a 仍然保有原來的內容。
vector<int> a = {1, 2, 3, 4, 5, 6}, b (6);
move(a.begin(), a.end(), b.begin());
cout << "a" << endl;
for(auto it = a.begin(); it != a.end(); it++)
cout << *it << " \n"[it == a.end()-1]; // 印出 1 2 3 4 5 6
cout << "b" << endl;
for(auto it = b.begin(); it != b.end(); it++)
cout << *it << " \n"[it == b.end()-1]; // 印出 1 2 3 4 5 6
b = move(a);
cout << "a" << endl;
for(auto it = a.begin(); it != a.end(); it++)
cout << *it << " \n"[it == a.end()-1]; // 沒有印出任何內容
cout << "b" << endl;
for(auto it = b.begin(); it != b.end(); it++)
cout << *it << " \n"[it == b.end()-1]; // 印出 1 2 3 4 5 6
語法為
move_backward(起點位址, 終點位址, 存放資料終點位址);
範圍包含起點位址,不包含終點位址,存放資料的容器長度要大於、等於複製資料的數量,填入的資料仍然按照原來的順序。例如以下的程式碼,在說明書中像是第2行程式碼會清除 a[1]、a[2]、a[3],但是我測試時 a 仍然保有原來的內容。
vector<int> a = {1, 2, 3, 4, 5, 6}, b (6);
move_backward(a.begin()+1, a.begin()+4, b.end());
cout << "a" << endl;
for(auto it = a.begin(); it != a.end(); it++)
cout << *it << " \n"[it == a.end()-1]; // 印出 1 2 3 4 5 6
cout << "b" << endl;
for(auto it = b.begin(); it != b.end(); it++)
cout << *it << " \n"[it == b.end()-1]; // 印出 0 0 0 2 3 4
語法為
swap(容器1, 容器2);
例如以下的程式碼。
int a = 1, b = -1;
swap(a, b);
cout << "a = " << a << ", b = " << b << endl; // 印出 a = -1, b = 1
vector<int> c = {1, 2, 3}, d = {4, 5, 6};
swap(c, d);
for(auto it = c.begin(); it != c.end(); it++)
cout << *it << " \n"[it == c.end()-1]; // 印出 4 5 6
for(auto it = d.begin(); it != d.end(); it++)
cout << *it << " \n"[it == d.end()-1]; // 印出 1 2 3
語法為
swap_ranges(容器1起點位址, 容器1終點位址, 容器2起點位址, 容器2終點位址);
例如以下的程式碼。
vector<int> a = {1, 2, 3, 4, 5, 6}, b = {6, 5, 4, 3, 2, 1};
swap_ranges(a.begin()+1, a.begin()+4, b.begin());
cout << "a" << endl;
for(auto it = a.begin(); it != a.end(); it++)
cout << *it << " \n"[it == a.end()-1]; // 印出 1 6 5 4 5 6
cout << "b" << endl;
for(auto it = b.begin(); it != b.end(); it++)
cout << *it << " \n"[it == b.end()-1]; // 印出 2 3 4 3 2 1
語法為
iter_swap(迭代器1, 迭代器2);
例如以下的程式碼。
vector<int> a = {1, 2, 3, 4, 5, 6}, b = {6, 5, 4, 3, 2, 1};
iter_swap(a.begin()+1, b.begin()+2);
cout << "a" << endl;
for(auto it = a.begin(); it != a.end(); it++)
cout << *it << " \n"[it == a.end()-1]; // 印出 1 4 3 4 5 6
cout << "b" << endl;
for(auto it = b.begin(); it != b.end(); it++)
cout << *it << " \n"[it == b.end()-1]; // 印出 6 5 2 3 2 1
語法為
transform(容器1起點位址, 容器1終點位址, 目標起點位址, 函式);
transform(容器1起點位址, 容器1終點位址, 容器2起點位址, 目標起點位址, 函式);
例如以下的程式碼。
vector<int> a = {1, 2, 3, 4, 5, 6}, b (6);
transform(a.begin(), a.end(), b.begin(), [](int x){return ++x;});
cout << "Plus one" << endl;
cout << "a: ";
for(auto it = a.begin(); it != a.end(); it++)
cout << *it << " \n"[it == a.end()-1]; // 印出 a: 1 2 3 4 5 6
cout << "b: ";
for(auto it = b.begin(); it != b.end(); it++)
cout << *it << " \n"[it == b.end()-1]; // 印出 b: 2 3 4 5 6 7
transform(a.begin(), a.end(), b.begin(), a.begin(), plus<int>());
cout << "Plus b to a" << endl;
cout << "a: ";
for(auto it = a.begin(); it != a.end(); it++)
cout << *it << " \n"[it == a.end()-1]; // 印出 a: 3 5 7 9 11 13
cout << "b: ";
for(auto it = b.begin(); it != b.end(); it++)
cout << *it << " \n"[it == b.end()-1]; // 印出 b: 2 3 4 5 6 7
語法為
replace(起點位址, 終點位址, 被取代的元素, 新的元素);
例如以下的程式碼。
vector<int> a = {1, 3, 2, 4, 3, 6};
replace(a.begin(), a.end(), 3, -3);
for(auto it = a.begin(); it != a.end(); it++)
cout << *it << " \n"[it == a.end()-1]; // 印出 a: 1 -3 2 4 -3 6
語法為
replace_if(起點位址, 終點位址, 條件, 新的元素);
例如以下的程式碼。
vector<int> a = {1, 2, 3, 4, 5, 6};
replace_if(a.begin(), a.end(), [](int x){return x%2 == 0;}, 0);
for(auto it = a.begin(); it != a.end(); it++)
cout << *it << " \n"[it == a.end()-1]; // 印出 1 0 3 0 5 0
語法為
replace_copy(容器1起點位址, 容器1終點位址, 容器2起點位址, 被取代的元素, 新的元素);
例如以下的程式碼。
vector<int> a = {1, 3, 2, 4, 3, 6}, b (6);
replace_copy(a.begin(), a.end(), b.begin(), 3, -3);
for(auto it = a.begin(); it != a.end(); it++)
cout << *it << " \n"[it == a.end()-1]; // 印出 1 3 2 4 3 6
for(auto it = b.begin(); it != b.end(); it++)
cout << *it << " \n"[it == b.end()-1]; // 印出 1 -3 2 4 -3 6
語法為
replace_copy_if(容器1起點位址, 容器1終點位址, 容器2起點位址, 條件, 新的元素);
例如以下的程式碼。
vector<int> a = {1, 2, 3, 4, 5, 6}, b (6);
replace_copy_if(a.begin(), a.end(), b.begin(), [](int x){return x%2 == 0;}, 0);
for(auto it = a.begin(); it != a.end(); it++)
cout << *it << " \n"[it == a.end()-1]; // 印出 1 2 3 4 5 6
for(auto it = b.begin(); it != b.end(); it++)
cout << *it << " \n"[it == b.end()-1]; // 印出 1 0 3 0 5 0
語法為
fill(起點位址, 終點位址, 填入的元素);
例如以下的程式碼。
vector<int> a (6);
fill(a.begin()+1, a.begin()+4, -1);
for(auto it = a.begin(); it != a.end(); it++)
cout << *it << " \n"[it == a.end()-1]; // 印出 0 -1 -1 -1 0 0
語法為
fill_n(起點位址, 數量, 填入的元素);
例如以下的程式碼。
vector<int> a (6);
fill_n(a.begin()+1, 3, -1);
for(auto it = a.begin(); it != a.end(); it++)
cout << *it << " \n"[it == a.end()-1]; // 印出 0 -1 -1 -1 0 0
語法為
generate(起點位址, 終點位址, 自訂函式);
例如以下的程式碼。
#include <iostream>
#include <algorithm>
#include <vector>
#include <ctime>
#include <cstdlib>
using namespace std;
int main() {
srand(time(NULL));
vector<int> a (6);
generate(a.begin(), a.end(), [](){return rand()%10;});
for(auto it = a.begin(); it != a.end(); it++)
cout << *it << " \n"[it == a.end()-1]; // 隨機印出 6 個 0 ~ 9 的整數
return 0;
}
語法為
generate_n(起點位址, 數量, 自訂函式);
例如以下的程式碼。
#include <iostream>
#include <algorithm>
#include <vector>
#include <ctime>
#include <cstdlib>
using namespace std;
int main() {
srand(time(NULL));
vector<int> a (6);
generate_n(a.begin(), 6, [](){return rand()%10;});
for(auto it = a.begin(); it != a.end(); it++)
cout << *it << " \n"[it == a.end()-1]; // 隨機印出 6 個 0 ~ 9 的整數
return 0;
}
語法為
remove(起點位址, 終點位址, 要移除的元素);
回傳值為範圍中沒有被移除的元素終點位址,例如以下的程式碼。
vector<int> a = {1, 3, 2, 4, 3, 6};
auto itEnd = remove(a.begin(), a.end(), 3);
for(auto it = a.begin(); it != itEnd; it++)
cout << *it << " \n"[it == itEnd-1]; // 印出 1 2 4 6
語法為
remove_if(起點位址, 終點位址, 條件);
回傳值為範圍中沒有被移除的元素終點位址,例如以下的程式碼。
vector<int> a = {1, 2, 3, 4, 5, 6};
auto itEnd = remove_if(a.begin(), a.end(), [](int x){return x%2 == 0;});
for(auto it = a.begin(); it != itEnd; it++)
cout << *it << " \n"[it == itEnd-1]; // 印出 1 3 5
語法為
remove_copy(容器1起點位址, 容器1終點位址, 容器2起點位址, 要移除的元素);
例如以下的程式碼。
vector<int> a = {1, 3, 2, 4, 3, 6}, b (6);
remove_copy(a.begin(), a.end(), b.begin(), 3);
for(auto it = a.begin(); it != a.end(); it++)
cout << *it << " \n"[it == a.end()-1]; // 印出 1 3 2 4 3 6
for(auto it = b.begin(); it != b.end(); it++)
cout << *it << " \n"[it == b.end()-1]; // 印出 1 2 4 6 0 0
語法為
remove_copy_if(容器1起點位址, 容器1終點位址, 容器2起點位址, 條件);
例如以下的程式碼。
vector<int> a = {1, 2, 3, 4, 5, 6}, b (6);
remove_copy_if(a.begin(), a.end(), b.begin(), [](int x){return x%2 == 0;});
for(auto it = a.begin(); it != a.end(); it++)
cout << *it << " \n"[it == a.end()-1]; // 印出 1 2 3 4 5 6
for(auto it = b.begin(); it != b.end(); it++)
cout << *it << " \n"[it == b.end()-1]; // 印出 1 3 5 0 0 0
語法為
remove_copy_if(容器1起點位址, 容器1終點位址, 容器2起點位址, 條件);
例如以下的程式碼。
vector<int> a = {1, 2, 3, 4, 5, 6}, b (6);
remove_copy_if(a.begin(), a.end(), b.begin(), [](int x){return x%2 == 0;});
for(auto it = a.begin(); it != a.end(); it++)
cout << *it << " \n"[it == a.end()-1]; // 印出 1 2 3 4 5 6
for(auto it = b.begin(); it != b.end(); it++)
cout << *it << " \n"[it == b.end()-1]; // 印出 1 3 5 0 0 0
語法為
unique(起點位址, 終點位址);
回傳值為留下的資料終點位址,例如以下的程式碼。
vector<int> a = {1, 2, 2, 3, 3, 2};
auto itEnd = unique(a.begin(), a.end());
a.resize(itEnd - a.begin());
for(auto it = a.begin(); it != a.end(); it++)
cout << *it << " \n"[it == a.end()-1]; // 印出 1 2 3 2
語法為
unique_copy(容器1起點位址, 容器1終點位址, 容器2起點位址);
回傳值為容器2填入資料的終點位址,例如以下的程式碼。
vector<int> a = {1, 2, 2, 3, 3, 2}, b (6);
auto itEnd = unique_copy(a.begin(), a.end(), b.begin());
for(auto it = a.begin(); it != a.end(); it++)
cout << *it << " \n"[it == a.end()-1]; // 印出 1 2 2 3 3 2
b.resize(itEnd - b.begin());
for(auto it = b.begin(); it != b.end(); it++)
cout << *it << " \n"[it == b.end()-1]; // 印出 1 2 3 2
語法為
reverse(起點位址, 終點位址);
沒有回傳值,例如以下的程式碼。
vector<int> a = {1, 2, 3, 4, 5, 6};
reverse(a.begin(), a.end());
for(auto it = a.begin(); it != a.end(); it++)
cout << *it << " \n"[it == a.end()-1]; // 印出 6 5 4 3 2 1
語法為
reverse_copy(容器1起點位址, 容器1終點位址, 容器2起點位址);
不會改變容器1的內容。例如以下的程式碼。
vector<int> a = {1, 2, 3, 4, 5, 6}, b (6);
reverse_copy(a.begin(), a.end(), b.begin());
for(auto it = a.begin(); it != a.end(); it++)
cout << *it << " \n"[it == a.end()-1]; // 印出 1 2 3 4 5 6
for(auto it = b.begin(); it != b.end(); it++)
cout << *it << " \n"[it == b.end()-1]; // 印出 6 5 4 3 2 1
語法為
rotate(起點位址, 新的起點位址, 終點位址);
例如以下的程式碼。
vector<int> a = {1, 2, 3, 4, 5, 6};
rotate(a.begin(), a.begin()+3, a.end());
for(auto it = a.begin(); it != a.end(); it++)
cout << *it << " \n"[it == a.end()-1]; // 印出 4 5 6 1 2 3
語法為
rotate_copy(起點位址, 新的起點位址, 終點位址, 容器2起點位址);
例如以下的程式碼。
vector<int> a = {1, 2, 3, 4, 5, 6}, b (6);
rotate_copy(a.begin(), a.begin()+3, a.end(), b.begin());
for(auto it = a.begin(); it != a.end(); it++)
cout << *it << " \n"[it == a.end()-1]; // 印出 1 2 3 4 5 6
for(auto it = b.begin(); it != b.end(); it++)
cout << *it << " \n"[it == b.end()-1]; // 印出 4 5 6 1 2 3
語法為
random_shuffle(起點位址, 終點位址);
可以使用內建的 rand 函式,並搭配 srant(time(NULL)),例如以下的程式碼。
#include <iostream>
#include <algorithm>
#include <vector>
#include <ctime>
#include <cstdlib>
using namespace std;
int main() {
srand(time(NULL));
vector<int> a = {1, 2, 3, 4, 5, 6};
random_shuffle(a.begin(), a.end());
for(auto it = a.begin(); it != a.end(); it++)
cout << *it << " \n"[it == a.end()-1]; // 1 ~ 6 隨機排列
return 0;
}
語法為
shuffle(起點位址, 終點位址, default_random_engine(seed));
使用 random 函式庫的 default_random_engine 函式,並搭配 chrono 函式庫的工具産生亂數種子,例如以下的程式碼。
#include <iostream>
#include <algorithm>
#include <vector>
#include <random>
#include <chrono>
using namespace std;
int main() {
unsigned int seed = chrono::system_clock::now().time_since_epoch().count();
vector<int> a = {1, 2, 3, 4, 5, 6};
shuffle(a.begin(), a.end(), default_random_engine(seed));
for(auto it = a.begin(); it != a.end(); it++)
cout << *it << " \n"[it == a.end()-1]; // 1 ~ 6 隨機排列
return 0;
}
語法為
is_partitioned(起點位址, 終點位址, 條件);
如果所有元素都符合條件回傳 1,如果有任何一個元素不符合條件回傳0,例如以下的程式碼。
vector<int> a = {0, 2, 4, 5, 6, 8}, b = {0, 2, 4, 6, 8, 10};
cout << is_partitioned(a.begin(), a.end(), [](int x){return x%2 == 0;}) << endl; // 印出 0
cout << is_partitioned(b.begin(), b.end(), [](int x){return x%2 == 0;}) << endl; // 印出 1
語法為
partition(起點位址, 終點位址, 條件);
回傳值為分區位址對應的迭代器,例如以下的程式碼。
vector<int> a = {1, 2, 3, 4, 5, 6};
auto bound = partition(a.begin(), a.end(), [](int x){return x%2 == 0;});
for(auto it = a.begin(); it != bound; it++) cout << *it << " "; // 印出 6 2 4
cout << endl;
for(auto it = bound; it != a.end(); it++) cout << *it << " "; // 印出 3 5 1
cout << endl;
語法為
stable_partition(起點位址, 終點位址, 條件);
回傳值為分區位址對應的迭代器,例如以下的程式碼。
vector<int> a = {1, 2, 3, 4, 5, 6};
auto bound = stable_partition(a.begin(), a.end(), [](int x){return x%2 == 0;});
for(auto it = a.begin(); it != bound; it++) cout << *it << " "; // 印出 2 4 6
cout << endl;
for(auto it = bound; it != a.end(); it++) cout << *it << " "; // 印出 1 3 5
cout << endl;
語法為
partition_copy(起點位址, 終點位址, 容器2起點位址, 容器3起點位址, 條件);
例如以下的程式碼。
vector<int> a = {1, 2, 3, 4, 5, 6}, b (3), c(3);
partition_copy(a.begin(), a.end(), b.begin(), c.begin(), [](int x){return x%2 == 0;});
for(auto it = a.begin(); it != a.end(); it++)
cout << *it << " \n"[it == a.end()-1]; // 印出 1 2 3 4 5 6
for(auto it = b.begin(); it != b.end(); it++)
cout << *it << " \n"[it == b.end()-1]; // 印出 2 4 6
for(auto it = c.begin(); it != c.end(); it++)
cout << *it << " \n"[it == c.end()-1]; // 印出 1 3 5
語法為
partition_point(起點位址, 終點位址, 條件);
回傳值為分區位址對應的迭代器,例如以下的程式碼。
vector<int> a = {1, 2, 3, 4, 5, 6}, b;
partition(a.begin(), a.end(), [](int x){return x%2 == 0;});
auto bound = partition_point(a.begin(), a.end(), [](int x){return x%2 == 0;});
b.assign(a.begin(), bound);
for(auto it = a.begin(); it != a.end(); it++)
cout << *it << " \n"[it == a.end()-1]; // 印出 6 2 4 3 5 1
for(auto it = b.begin(); it != b.end(); it++)
cout << *it << " \n"[it == b.end()-1]; // 印出 6 2 4
語法為
sort(起點位址, 終點位址, 比較式);
比較式預設值為由小到大排序,也可以引用內建函式 greater 由大到小排序,或是依照自訂函式排序,例如以下的程式碼。
vector<int> a = {1, 3, 5, 2, 4, 6};
sort(a.begin(), a.end());
for(auto it = a.begin(); it != a.end(); it++)
cout << *it << " \n"[it == a.end()-1]; // 印出 1 2 3 4 5 6
sort(a.begin(), a.end(), greater<>());
for(auto it = a.begin(); it != a.end(); it++)
cout << *it << " \n"[it == a.end()-1]; // 印出 6 5 4 3 2 1
語法為
stable_sort(起點位址, 終點位址, 比較式);
例如以下的程式碼。
vector<float> a = {2.5, 2.1, 2.3, 1.5, 1.1, 1.3};
stable_sort(a.begin(), a.end(), [](float x, float y){return int(x) < int(y);});
for(auto it = a.begin(); it != a.end(); it++)
cout << *it << " \n"[it == a.end()-1]; // 印出 1.5 1.1 1.3 2.5 2.1 2.3
語法為
partial_sort(起點位址, 中點位址, 終點位址, 比較式);
比較式預設值為由小到大排序,如果採用預設值,中點位址前會放入整個範圍中由小到大排序的元素,再由中點位址開始放入剩下的元素,如以下的程式碼。
vector<int> a = {1, 3, 5, 7, 9, 2, 4, 6, 8, 10};
partial_sort(a.begin(), a.begin()+5, a.end());
for(auto it = a.begin(); it != a.end(); it++)
cout << *it << " \n"[it == a.end()-1]; // 印出 1 2 3 4 5 9 7 6 8 10
語法為
partial_sort_copy(容器1起點位址, 容器1終點位址, 容器2起點位址, 容器2終點位址, 比較式);
比較式預設值為由小到大排序,不會改變容器1的內容,例如以下的程式碼。
vector<int> a = {1, 10, 2, 9, 3, 8, 4, 7, 5, 6}, b(5);
partial_sort_copy(a.begin(), a.begin()+5, b.begin(), b.end());
for(auto it = a.begin(); it != a.end(); it++)
cout << *it << " \n"[it == a.end()-1]; // 印出 1 10 2 9 3 8 4 7 5 6
for(auto it = b.begin(); it != b.end(); it++)
cout << *it << " \n"[it == b.end()-1]; // 印出 1 2 3 9 10
partial_sort_copy(a.begin(), a.begin()+5, b.begin(), b.end(), greater<>());
for(auto it = a.begin(); it != a.end(); it++)
cout << *it << " \n"[it == a.end()-1]; // 印出 1 10 2 9 3 8 4 7 5 6
for(auto it = b.begin(); it != b.end(); it++)
cout << *it << " \n"[it == b.end()-1]; // 印出 10 9 3 2 1
語法為
is_sorted(起點位址, 終點位址, 比較式);
比較式預設值為由小到大排序,如果已排序回傳 1,如果未排序回傳 0,例如以下的程式碼。
vector<int> a = {1, 3, 5, 6, 4, 2};
cout << is_sorted(a.begin(), a.end()) << endl; // 印出 0
cout << is_sorted(a.begin(), a.begin()+3) << endl; // 印出 1
cout << is_sorted(a.begin()+3, a.end(), greater<>()) << endl; // 印出 1
sort(a.begin(), a.end());
cout << is_sorted(a.begin(), a.end()) << endl; // 印出 1
語法為
is_sorted_until(起點位址, 終點位址);
如果所有元素都已經由小到大排序,回傳終點位址,例如以下的程式碼。
vector<int> a = {1, 3, 5, 6, 4, 2};
auto it = is_sorted_until(a.begin(), a.end());
cout << it - a.begin() << endl; // 印出 4
sort(a.begin(), a.end());
auto it2 = is_sorted_until(a.begin(), a.end());
cout << it2 - a.begin() << endl; // 印出 6
這些函式只能用在已經全部或部分排序的資料。
語法為
lower_bound(起點位址, 終點位址, 元素);
upper_bound(起點位址, 終點位址, 元素);
equal_range(起點位址, 終點位址, 元素);
lower_bound 回傳值為指定元素左側的位址,upper_bound 回傳值為指定元素右側的位址,equal_range 回傳值格式為 pair,同時包含 lower_bound 及 upper_bound,例如以下的程式碼。
vector<int> a = {1, 2, 3, 4, 5, 6};
auto it = lower_bound(a.begin(), a.end(), 3);
cout << it - a.begin() << endl; // 印出 2
auto it2 = upper_bound(a.begin(), a.end(), 3);
cout << it2 - a.begin() << endl; // 印出 3
auto bounds = equal_range(a.begin(), a.end(), 3);
cout << "lower_bound: " << bounds.first - a.begin() << " upper_bound: " << bounds.second - a.begin() << endl; // 印出 lower_bound: 2 upper_bound: 3
語法為
binary_search(起點位址, 終點位址, 元素);
如果找到指定元素回傳 1,如果沒有找到指定元素回傳 0,例如以下的程式碼。
vector<int> a = {1, 2, 3, 4, 5, 6};
cout << binary_search(a.begin(), a.end(), 3) << endl; // 印出 1
cout << binary_search(a.begin(), a.end(), -3) << endl; // 印出 0
語法為
merge(容器1起點位址, 容器1終點位址, 容器2起點位址, 容器2終點位址, 容器3起點位址);
例如以下的程式碼。
vector<int> a = {1, 3, 5, 7, 9}, b = {2, 4, 6, 8, 10}, c (10);
merge(a.begin(), a.end(), b.begin(), b.end(), c.begin());
for(auto it = c.begin(); it != c.end(); it++)
cout << *it << " \n"[it == c.end()-1]; // 印出 1 2 3 4 5 6 7 8 9 10
語法為
includes(容器1起點位址, 容器1終點位址, 容器2起點位址, 容器2終點位址);
如果是回傳 1,反之回傳 0,例如以下的程式碼。
vector<int> a = {1, 2, 3, 4, 5, 6}, b = {2, 3, 4}, c = {4, 3, 2};
cout << includes(a.begin(), a.end(), b.begin(), b.end()) << endl; // 印出 1
cout << includes(a.begin(), a.end(), c.begin(), c.end()) << endl; // 印出 0
語法為
set_union(容器1起點位址, 容器1終點位址, 容器2起點位址, 容器2終點位址, 容器3起點位址);
例如以下的程式碼。
vector<int> a = {1, 3, 3, 5, 5}, b = {2, 2, 4, 6, 6}, c (15);
auto itEnd = set_union(a.begin(), a.end(), b.begin(), b.end(), c.begin());
c.resize(itEnd - c.begin());
for(auto it = c.begin(); it != c.end(); it++)
cout << *it << " \n"[it == c.end()-1]; // 印出 1 2 2 3 3 4 5 5 6 6
語法為
set_intersection(容器1起點位址, 容器1終點位址, 容器2起點位址, 容器2終點位址, 容器3起點位址);
例如以下的程式碼。
vector<int> a = {1, 3, 3, 5, 5}, b = {1, 2, 3, 4, 5}, c (15);
auto itEnd = set_intersection(a.begin(), a.end(), b.begin(), b.end(), c.begin());
c.resize(itEnd - c.begin());
for(auto it = c.begin(); it != c.end(); it++)
cout << *it << " \n"[it == c.end()-1]; // 印出 1 3 5
語法為
set_difference(容器1起點位址, 容器1終點位址, 容器2起點位址, 容器2終點位址, 容器3起點位址);
將容器1的元素刪除容器2中也有的元素,剩下的元素存入容器3,例如以下的程式碼。
vector<int> a = {1, 2, 3, 4, 5}, b = {1, 3, 3, 5, 5}, c (15);
auto itEnd = set_difference(a.begin(), a.end(), b.begin(), b.end(), c.begin());
c.resize(itEnd - c.begin());
for(auto it = c.begin(); it != c.end(); it++)
cout << *it << " \n"[it == c.end()-1]; // 印出 2 4
語法為
set_symmetric_difference(容器1起點位址, 容器1終點位址, 容器2起點位址, 容器2終點位址, 容器3起點位址);
對稱差是將聯集扣掉交集,例如以下的程式碼。
vector<int> a = {1, 2, 3, 4, 5}, b = {2, 4, 6, 8, 10}, c (15);
auto itEnd = set_symmetric_difference(a.begin(), a.end(), b.begin(), b.end(), c.begin());
c.resize(itEnd - c.begin());
for(auto it = c.begin(); it != c.end(); it++)
cout << *it << " \n"[it == c.end()-1]; // 印出 1 3 5 6 8 10
語法為
min({元素1, 元素2, 元素3, ...});
max({元素1, 元素2, 元素3, ...});
minmax({元素1, 元素2, 元素3, ...});
例如以下的程式碼。
cout << "min = " << min({1, 2, 3, 4, 5}) << endl; // 印出 min = 1
cout << "max = " << max({1, 2, 3, 4, 5}) << endl; // 印出 max = 5
auto result = minmax({1, 2, 3, 4, 5});
cout << "min = " << result.first << ", max = " << result.second << endl; // 印出 min = 1, max = 5
語法為
min_element({元素1, 元素2, 元素3, ...});
max_element({元素1, 元素2, 元素3, ...});
minmax_element({元素1, 元素2, 元素3, ...});
min_element 及 max_element 回傳值為對應的迭代器,minmax_element 回傳值為迭代器的 pari,例如以下的程式碼。
vector<int> a = {1, 2, 3, 4, 5};
auto it1 = min_element(a.begin(), a.end());
cout << "The min element of a is a[" << it1 - a.begin() << "] = " << *it1 << endl; // 印出 The min element of a is a[0] = 1
auto it2 = max_element(a.begin(), a.end());
cout << "The max element of a is a[" << it2 - a.begin() << "] = " << *it2 << endl; // 印出 The max element of a is a[4] = 5
auto result = minmax_element(a.begin(), a.end());
cout << "min(a) = " << *(result.first) << ", max(a) = " << *(result.second) << endl; // 印出 min(a) = 1, max(a) = 5
以上是 algorithm 函式庫大部分的函式,其中我最常用到的函式為 sort、reverse、find、count、min、max,尤其是 sort,在競賽及檢定中經常用到,如果不使用 sort 就要當場寫氣泡排序或是快速排序,會浪費不少時間。
####### tags:C++
作者:王一哲日期:2023年7月29日
May 10, 2025作者:王一哲日期:2023年7月29日
May 9, 2025要先引入函式庫,函式庫的官方說明書在此 cplusplus.com std::deque。
May 3, 2025講義不是我寫的,原文連結為 Yui Huang 演算法學習筆記:C++ 基礎語法 我只是將自己寫的練習題程式碼記錄下來。 最後更新日期:2024年11月9日
Apr 29, 2025or
By clicking below, you agree to our terms of service.
New to HackMD? Sign up