目录
前言
STL容器一览
set和map如何降序构建
set和map如何插入自定义对象
multiset和multimap如何降序构建
multiset和multimap如何插入自定义对象
multi_系列如何equal_range
multiset
multimap
unorder_multiset
unorder_multimap
STL容器迭代器一览
迭代器性能一览
copy()
ostream_iterator
reverse_iterator
insert_iterator系列
for_each
set_union
remove_if
transform
list.remove
string.find
string.substr
算法组
tolower
toupper
next_permutation
unique
count_if
bitset:用于将整数转化为二进制
后续
前言
君子生非异也,善假与物也。本文着重于讲解在做leetcode和牛客题目时,会较为经常用到的容器、容器方法和通用算法,使我们在做题时,可以得心应手。在不断的学习方法中,我们实际上还能更进一步理解c++的各种编程思想。但是本文是基于你已经做了许多题目,已经有所实践的基础上。如果你连十道题都没做过,那你暂时无法体会本文所讲的内容或者说所讲内容的意义。
STL容器一览
set和map如何降序构建
set降序构建
#include <iostream>
#include <set>int main() {// 建立降序setstd::set<int, std::greater<int>> descendingSet;// 插入元素descendingSet.insert(5);descendingSet.insert(3);descendingSet.insert(7);descendingSet.insert(1);// 遍历输出for (int num : descendingSet) {std::cout << num << " ";}// 输出结果为:7 5 3 1return 0;
}
map降序构建
#include <iostream>
#include <map>int main() {// 建立降序mapstd::map<int, std::string, std::greater<int>> descendingMap;// 插入元素descendingMap.insert({10, "apple"});descendingMap.insert({5, "banana"});descendingMap.insert({15, "cherry"});// 遍历输出for (const auto& pair : descendingMap) {std::cout << pair.first << ": " << pair.second << std::endl;}// 输出结果为:// 15: cherry// 10: apple// 5: bananareturn 0;
}
set和map如何插入自定义对象
set插入自定义对象
#include <iostream>
#include <set>
#include <string>class Person {
public:std::string name;int age;Person(const std::string& n, int a) : name(n), age(a) {}
};// 自定义比较函数对象
struct PersonComparator {bool operator()(const Person& a, const Person& b) const {if (a.age!= b.age) {return a.age < b.age;}return a.name < b.name;}
};int main() {std::set<Person, PersonComparator> people;people.insert(Person("Alice", 25));people.insert(Person("Bob", 20));people.insert(Person("Charlie", 25));for (const auto& person : people) {std::cout << "Name: " << person.name << ", Age: " << person.age << std::endl;}return 0;
}
map插入自定义对象
#include <iostream>
#include <map>
#include <string>class StudentID {
public:int id;std::string school;StudentID(int i, const std::string& s) : id(i), school(s) {}
};// 自定义比较函数对象
struct StudentIDComparator {bool operator()(const StudentID& a, const StudentID& b) const {if (a.id!= b.id) {return a.id < b.id;}return a.school < b.school;}
};int main() {std::map<StudentID, std::string, StudentIDComparator> studentNames;studentNames[StudentID(1, "SchoolA")] = "Alice";studentNames[StudentID(2, "SchoolB")] = "Bob";studentNames[StudentID(1, "SchoolC")] = "Charlie";for (const auto& pair : studentNames) {std::cout << "ID: " << pair.first.id << ", School: " << pair.first.school<< ", Name: " << pair.second << std::endl;}return 0;
}
multiset和multimap如何降序构建
与set和map如何降序构建一致
multiset和multimap如何插入自定义对象
与set和map如何插入自定义对象一致
multi_系列如何equal_range
equal_range
返回一个std::pair
,其中.first
指向范围的起始位置,是一个迭代器,.second
指向范围的结束位置(最后一个匹配元素的下一个位置),是一个迭代器。如果没有找到与键 k
相等的元素,.first
和 .second
都等于 end(),即超尾迭代器。
multiset
#include <iostream>
#include <set>int main() {std::multiset<int> numbers;numbers.insert(5);numbers.insert(3);numbers.insert(5);numbers.insert(7);numbers.insert(5);auto range = numbers.equal_range(5);for (auto it = range.first; it!= range.second; ++it) {std::cout << *it << " ";}std::cout << std::endl;return 0;
}
multimap
#include <iostream>
#include <map>
#include <string>int main() {std::multimap<int, std::string> idNames;idNames.insert({1, "Alice"});idNames.insert({2, "Bob"});idNames.insert({1, "Charlie"});idNames.insert({3, "David"});auto range = idNames.equal_range(1);for (auto it = range.first; it!= range.second; ++it) {std::cout << "ID: " << it->first << ", Name: " << it->second << std::endl;}return 0;
}
unorder_multiset
#include <iostream>
#include <unordered_set>int main() {std::unordered_multiset<int> numbers;numbers.insert(5);numbers.insert(3);numbers.insert(5);numbers.insert(7);numbers.insert(5);auto range = numbers.equal_range(5);for (auto it = range.first; it != range.second; ++it) {std::cout << *it << " ";}std::cout << std::endl;return 0;
}
unorder_multimap
#include <iostream>
#include <unordered_map>
#include <string>int main() {std::unordered_multimap<int, std::string> idNames;idNames.insert({ 1, "Alice" });idNames.insert({ 2, "Bob" });idNames.insert({ 1, "Charlie" });idNames.insert({ 3, "David" });auto range = idNames.equal_range(1);for (auto it = range.first; it != range.second; ++it) {std::cout << "ID: " << it->first << ", Name: " << it->second << std::endl;}return 0;
}
STL容器迭代器一览
迭代器性能一览
copy()
- OutputIterator copy (InputIterator first, InputIterator last, OutputIterator result)
- copy()函数将覆盖目标容器中已有的数据,同时目标容器必须足够大,以便能够容纳被复制的元素。
// copy algorithm example
#include <iostream> // std::cout
#include <algorithm> // std::copy
#include <vector> // std::vectorint main () {int myints[]={10,20,30,40,50,60,70};std::vector<int> myvector (7);std::copy ( myints, myints+7, myvector.begin() );std::cout << "myvector contains:";for (std::vector<int>::iterator it = myvector.begin(); it!=myvector.end(); ++it)std::cout << ' ' << *it;std::cout << '\n';return 0;
}
ostream_iterator
- template< class T, class charT = char, class traits = std::char_traits<charT> >
ostream_iterator(std::ostream& os, const charT* delim);
:构造一个ostream_iterator
,将元素输出到指定的输出流os
,每个元素后跟着分隔符delim
std::ostream_iterator
是一个输出迭代器,只支持++
(前置和后置)、*
和=
操作符。- *out_iter++ = 15; //works like cout << 15 << " ";
- copy(istream_iterator<int,char>(cin),istream_iterator<int,char>(),dice.begin());
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>int main() {std::vector<int> vec = {1, 2, 3, 4, 5};// 使用 std::ostream_iterator 将 vector 元素输出到 std::cout,元素间以空格分隔std::copy(vec.begin(), vec.end(), std::ostream_iterator<int>(std::cout, " "));std::cout << std::endl;return 0;
}
reverse_iterator
rbegin和rend
- 前者返回一个指向超尾的反向迭代器
- 后者返回一个指向第一个元素的反向迭代器。
- *rbegin = *(end-1)
- *rend = *(begin -1)
insert_iterator系列
insert_iterator、back_insert_iterator和front_insert_iterator,这三个为插入迭代器。
- back_insert_iterator将元素插入到容器尾部
- front_insert_iterator将元素插入到容器的前端,不能用于vector这样头插效率极低的容器
- insert_iterator将元素插入到insert_iterator构造函数的参数指定的位置前面
- 这三个插入迭代器都是输出容器概念的模型
- back_insert_iterator<vector<int>>back_iter(dice);
- front_insert_iterator<vector<int>>front_iter(dice);
- insert_iterator<vector<int>>insert_iter(dice,dice.begin());
- 必须声明容器类型的原因是,迭代器必须使用合适的容器方法。back_insert_iterator的构造函数将假设传递给它的类型有一个push_back()方法。copy()是一个独立的函数,没有重新调整容器大小的权限。但前面的声明让back_iter能够使用方法vector<int>::push_back(),该方法有这样的权限。
for_each
- Function for_each (InputIterator first, InputIterator last, Function fn)
- for_each 本身不会修改数组元素,但它会对范围内的每个元素调用你提供的函数或函数对象,如果这个函数或函数对象对元素进行了修改操作,那么数组元素就会被修改。
#include <iostream>
#include <algorithm>
#include <array>// 定义一个函数,将传入的整数加倍
void doubleValue(int& num) {num *= 2;
}int main() {std::array<int, 5> arr = {1, 2, 3, 4, 5};// 使用 for_each 对数组每个元素应用 doubleValue 函数std::for_each(arr.begin(), arr.end(), doubleValue);// 输出修改后的数组for (int num : arr) {std::cout << num << " ";}std::cout << std::endl;return 0;
}
set_union
- set_union 是 C++ 标准库 <algorithm> 头文件中的一个算法,用于构造两个有序范围的并集。这里的 “有序” 至关重要,意味着输入的两个范围必须是已经排好序的(通常是升序),否则结果将是未定义的。
示例 1:使用默认比较(<)
#include <iostream>
#include <algorithm>
#include <vector>int main() {std::vector<int> v1 = {1, 2, 3, 5, 7};std::vector<int> v2 = {2, 4, 6, 7};std::vector<int> result(v1.size() + v2.size());auto it = std::set_union(v1.begin(), v1.end(), v2.begin(), v2.end(), result.begin());result.resize(std::distance(result.begin(), it));std::cout << "Union of the two vectors: ";for (int num : result) {std::cout << num << " ";}std::cout << std::endl;return 0;
}
示例 2:使用自定义比较函数
#include <iostream>
#include <algorithm>
#include <vector>// 自定义比较函数,用于降序比较
bool greaterThan(int a, int b) {return a > b;
}int main() {std::vector<int> v1 = {7, 5, 3, 2, 1};std::vector<int> v2 = {7, 6, 4, 2};std::vector<int> result(v1.size() + v2.size());auto it = std::set_union(v1.begin(), v1.end(), v2.begin(), v2.end(), result.begin(), greaterThan);result.resize(std::distance(result.begin(), it));std::cout << "Union of the two vectors in descending order: ";for (int num : result) {std::cout << num << " ";}std::cout << std::endl;return 0;
}
示例3:复习front_insert_iterator
#include <iostream>
#include <algorithm>
#include <iterator>
#include <vector>int main() {std::vector<int> v1 = { 1, 2, 3, 5, 7 };std::vector<int> v2 = { 2, 4, 6, 7 };std::vector<int> result;auto it = std::set_union(v1.begin(), v1.end(), v2.begin(), v2.end(), std::insert_iterator<std::vector<int>>(result, result.begin()));//result.resize(std::distance(result.begin(), it));std::cout << "Union of the two vectors: ";for (int num : result) {std::cout << num << " ";}std::cout << std::endl;return 0;
}
remove_if
- ForwardIt remove_if(ForwardIt first, ForwardIt last, UnaryPredicate p);
- 从指定范围内移除满足特定条件的元素。需要注意的是,它并不是真正从容器中删除元素,而是将不满足条件的元素 “向前移动”,覆盖满足条件的元素
- 返回一个指向新的逻辑结束位置的迭代器
- 要真正从容器中删除元素,通常需要结合容器的
erase
成员函数
示例 1:
#include <iostream>
#include <algorithm>
#include <vector>int main() {std::vector<int> numbers = { 1, 2, 3, 4, 5, 6 };auto newEnd = std::remove_if(numbers.begin(), numbers.end(), [](int num) {return num % 2 == 0;});numbers.erase(newEnd, numbers.end());std::cout << "Numbers after removing even numbers: ";for (int num : numbers) {std::cout << num << " ";}std::cout << std::endl;return 0;
}
示例 2:
#include <iostream>
#include <algorithm>
#include <list>// 函数对象
struct GreaterThanTen {bool operator()(int num) const {return num > 10;}
};int main() {std::list<int> lst = {5, 15, 8, 20, 3};lst.erase(std::remove_if(lst.begin(), lst.end(), GreaterThanTen()), lst.end());std::cout << "List after removing numbers greater than 10: ";for (int num : lst) {std::cout << num << " ";}std::cout << std::endl;return 0;
}
transform
- OutputIt transform(InputIt first, InputIt last, OutputIt d_first, UnaryOperation unary_op);
- OutputIt transform(InputIt1 first1, InputIt1 last1, InputIt2 first2, OutputIt d_first, BinaryOperation binary_op);
示例 1:单输入范围
#include <iostream>
#include <algorithm>
#include <vector>int main() {std::vector<int> numbers = {1, 2, 3, 4, 5};std::vector<int> squaredNumbers(numbers.size());std::transform(numbers.begin(), numbers.end(), squaredNumbers.begin(), [](int num) {return num * num;});std::cout << "Squared numbers: ";for (int num : squaredNumbers) {std::cout << num << " ";}std::cout << std::endl;return 0;
}
示例 2:双输入范围
#include <iostream>
#include <algorithm>
#include <vector>// 函数对象
struct AddNumbers {int operator()(int a, int b) const {return a + b;}
};int main() {std::vector<int> numbers1 = {1, 2, 3};std::vector<int> numbers2 = {4, 5, 6};std::vector<int> sumNumbers(numbers1.size());std::transform(numbers1.begin(), numbers1.end(), numbers2.begin(), sumNumbers.begin(), AddNumbers());std::cout << "Sum of corresponding numbers: ";for (int num : sumNumbers) {std::cout << num << " ";}std::cout << std::endl;return 0;
}
list.remove
- void remove (const value_type& val)
- void remove_if (Predicate pred)
- 调用该方法后,链表中所有值为val的元素都将被删除,同时链表的长度将被自动调整。
string.find
- size_t find (const string& str, size_t pos = 0) const;
- size_t find (const char* s, size_t pos = 0) const;
- 如果未找到,返回 std::string::npos
string.substr
- string substr (size_t pos = 0, size_t len = npos) const;
算法组
- 非修改式序列操作
- 修改式序列操作
- 排序和相关操作
- 通用数字运算
- 非修改式序列操作对区间中的每个元素进行操作。这些操作不修改容器的内容。例如,find()和for_each()就属于这一类。
- 修改式序列操作也对区间中的每个元素进行操作。然而,顾名思义,它们可以修改容器的内容。可以修改值,也可以修改值的排列顺序。transform()、random_shuffle()和copy()属于这一类。
- 排序和相关操作包括多个排序函数(包括sort())和其他各种函数,包括集合操作。
- 数字操作包括将区间的内容累积、计算两个容器的内部乘积、计算小计、计算相邻对象差的函数。通常,这些都是数组的操作特性,因此vector是最有可能使用这些操作的容器。
- sort()是就地算法:结果被存放在原始数据的位置上
- copy()函数将结果发送到另一个位置,所以它是复制算法
- transform()函数可以以这两种方式完成工作
- 有些算法有两个版本:就地版本和复制版本。
- STL的约定是,复制版本的名称将以copy结尾。
- template<class ForwardIterator,class T>
void replace(ForwardIterator first,ForwardIterator last,const T&old_value,const T&new_value); - template<class InputIterator,class OutputIterator,class T>OutputIterator replace_copy(InputIterator first,InputIterator last,OutputIterator result,const T&old_value,const T&new_value)
- 对于复制算法,统一的约定是:返回一个迭代器,该迭代器指向复制的最后一个值后面的一个位置。
- 有些函数有这样的版本,即根据将函数应用于容器元素得到的结果来执行操作。
- 这些版本的名称通常以_if结尾。
- 例如,如果将函数用于旧值时,返回的值为true,则replace_if()将把旧值替换为新的值。
- template<class ForwardIterator,class Predicate class T>void replace_if(ForwardIterator first,ForwardIterator last,Predicate pred,const T&new_value);
tolower
- 将给定的字符转换为小写形式。如果字符本身不是大写字母,函数将返回原字符。
- int tolower( int ch );
#include <iostream>
#include <cctype>int main() {char upperCase = 'A';char lowerCase = static_cast<char>(std::tolower(upperCase));std::cout << "The lowercase of " << upperCase << " is " << lowerCase << std::endl;char nonLetter = '1';char result = static_cast<char>(std::tolower(nonLetter));std::cout << "The result of converting " << nonLetter << " is " << result << std::endl;return 0;
}
toupper
- 将给定的字符转换为大写形式。如果字符本身不是小写字母,函数将返回原字符。
- int toupper( int ch );
#include <iostream>
#include <cctype>int main() {char lowerCase = 'b';char upperCase = static_cast<char>(std::toupper(lowerCase));std::cout << "The uppercase of " << lowerCase << " is " << upperCase << std::endl;char nonLetter = '@';char result = static_cast<char>(std::toupper(nonLetter));std::cout << "The result of converting " << nonLetter << " is " << result << std::endl;return 0;
}
next_permutation
- next_permutation()算法将区间内容转换为下一种排列方式。
- 对于字符串,排列按照字母递增的顺序进行。
- 如果成功,该算法返回true;如果区间已经处于最后的序列中,则该算法返回false。
- 要得到区间内容的所有排列组合,应从最初的顺序开始,为此程序使用了STL算法sort()。
- 注意,算法next_permutation()自动提供唯一的排列组合
// strgstl.cpp -- applying the STL to a string
#include <iostream>
#include <string>
#include <algorithm>int main()
{using namespace std;string letters;cout << "Enter the letter grouping (quit to quit): ";while (cin >> letters && letters != "quit"){cout << "Permutations of " << letters << endl;sort(letters.begin(), letters.end());cout << letters << endl;while (next_permutation(letters.begin(), letters.end()))cout << letters << endl;cout << "Enter next sequence (quit to quit): ";}cout << "Done.\n";// cin.get();// cin.get();return 0;
}
Enter the letter grouping (quit to quit): Permutations of awl
alw
awl
law
lwa
wal
wla
Enter next sequence (quit to quit): Permutations of all
all
lal
lla
Enter next sequence (quit to quit): Done.
unique
- 只能用于移除相邻的重复元素
- template <class ForwardIterator>
ForwardIterator unique (ForwardIterator first, ForwardIterator last); - template <class ForwardIterator, class BinaryPredicate>
ForwardIterator unique (ForwardIterator first, ForwardIterator last,
BinaryPredicate pred);
count_if
-
template <class InputIterator, class UnaryPredicate>typename iterator_traits<InputIterator>::difference_typecount_if (InputIterator first, InputIterator last, UnaryPredicate pred);
bitset:用于将整数转化为二进制
#include <iostream>
#include <bitset>int main() {int num = 13;std::cout << "Decimal: " << num << std::endl;std::cout << "Binary: " << std::bitset<8 * sizeof(int)>(num) << std::endl;return 0;
}
后续
正在努力撰写ing