std::sort
替代:std::vector<int> v{0,1,3,5,7,9,2,4,6,8};
// 手写冒泡排序
bool flag = true;
while(flag) {
flag = false;
for (int j = 0; j < (v.size() -1); j++) {
if (v[j+1] < v[j]) {
std::swap(v[j], v[j+1]);
flag = true;
}
}
}
for (int i : v) std::cout << i << " ";
std::cout << "\n";
// STL排序,简单又高效
std::vector<int> v2{0,1,3,5,7,9,2,4,6,8};
std::sort(v2.begin(), v2.end());
for (int i : v2) std::cout << i << " ";
std::min
这样简单的模板函数。下面我给你几个常用算法的简单版本示例,帮助理解它们的工作原理:std::min
template <typename T>
const T& min(const T& a, const T& b) {
return (a < b) ? a : b;
}
std::max
template <typename T>
const T& max(const T& a, const T& b) {
return (a > b) ? a : b;
}
std::swap
template <typename T>
void swap(T& a, T& b) {
T temp = a;
a = b;
b = temp;
}
std::find
template <typename Iterator, typename T>
Iterator find(Iterator begin, Iterator end, const T& value) {
for (Iterator it = begin; it != end; ++it) {
if (*it == value)
return it;
}
return end;
}
[begin, end)
找到第一个等于 value
的元素,返回它的迭代器;找不到则返回 end
。std::accumulate
template <typename Iterator, typename T>
T accumulate(Iterator begin, Iterator end, T init) {
for (Iterator it = begin; it != end; ++it) {
init = init + *it;
}
return init;
}
init
。std::copy
示例很棒,下面我帮你详细解释一下:std::copy
简单版实现template <typename IIter, typename OIter>
OIter copy(IIter first, IIter last, OIter res) {
for (; first != last; ++first, ++res)
*res = *first;
return res;
}
[first, last)
范围内的元素逐个复制到以 res
开始的目标位置。IIter first, last
:输入迭代器,指定要复制的范围。OIter res
:输出迭代器,指定复制目标起点。std::vector<int> src{1, 2, 3, 4, 5};
std::vector<int> dst(5);
copy(src.begin(), src.end(), dst.begin());
for (int x : dst)
std::cout << x << " "; // 输出: 1 2 3 4 5
std::copy
是最基本、常用的算法之一,广泛用于数组、容器数据搬运。
adjacent_pair
很清晰,就是遍历容器中相邻的元素对,然后对每对元素执行一个函数 f
。简单总结一下:adjacent_pair
函数模板解析template <typename FwIter, typename Func>
void adjacent_pair(FwIter first, FwIter last, Func f) {
if (first != last) {
FwIter trailer = first; // 指向前一个元素
++first; // 指向后一个元素
for (; first != last; ++first, ++trailer) {
f(*trailer, *first); // 对相邻元素调用函数
}
}
}
[first, last)
和一个函数 f
。trailer
指向第一个元素,first
指向第二个元素。f
被调用,参数是相邻两个元素。f
(n-1)
次,处理所有相邻的元素对。std::vector<int> v{1, 3, 6, 10};
adjacent_pair(v.begin(), v.end(), [](int a, int b) {
std::cout << "(" << a << ", " << b << ") ";
});
// 输出: (1, 3) (3, 6) (6, 10)
std::for_each
,但只针对相邻两元素。for_all_pairs
函数是用来遍历区间内的所有不重复的元素对,并对每对元素调用函数 f
。这是一个经典的双重循环模式。template <typename FwIter, typename Func>
void for_all_pairs(FwIter first, FwIter last, Func f)
{
if (first != last)
{
FwIter trailer = first; // 外层指针
++first; // 内层指针起点,总是在外层之后
for (; first != last; ++first, ++trailer)
for (FwIter it = first; it != last; ++it)
f(*trailer, *it);
}
}
trailer
指向当前第一个元素(左元素)first
指向比 trailer
位置往后一个的元素(右元素的起点)first
到 last
,生成所有和 trailer
配对的元素。(a,b)
出现一次,不出现 (b,a)
)。std::vector<int> v{1, 2, 3};
for_all_pairs(v.begin(), v.end(), [](int a, int b){
std::cout << "(" << a << ", " << b << ") ";
});
输出:
(1, 2) (1, 3) (2, 3)
copy_while
,它的功能是从输入区间 [first, last)
拷贝元素到输出迭代器 result
,直到遇到第一个不满足条件 p
的元素就停止。template<typename InIter, typename OutIter, typename Pred>
std::pair<InIter, OutIter>
copy_while(InIter first, InIter last, OutIter result, Pred p)
{
for (; first != last && p(*first); ++first, ++result)
*result = *first;
return std::make_pair(first, result);
}
first
是输入序列的开始迭代器。last
是输入序列的结束迭代器。result
是输出序列的开始迭代器。p
是一个一元谓词函数,判断元素是否满足某条件。first
到 last
,遍历元素。p(*first)
为 true
,就将元素复制到输出 result
。p(*first)
为 false
或到达结尾,停止循环。std::pair
:
first
指向第一个不满足条件的元素(或 last
,如果全部满足)。result
指向输出序列中下一个可写位置。std::vector<int> input{1, 2, 3, 4, 5, 6};
std::vector<int> output;
output.resize(input.size());
auto is_less_than_4 = [](int x) { return x < 4; };
auto result = copy_while(input.begin(), input.end(), output.begin(), is_less_than_4);
// 复制了1, 2, 3到output,result.first指向元素4的位置
copy_while
是 std::copy_if
的一个变种,只复制满足条件的连续前缀。split
函数模板,用来根据分隔符 t
将输入区间 [first, last)
拆分成多个子区间,并对每个子区间调用回调函数 f
。template <typename InIter, typename T, typename Func>
void split(InIter first, InIter last, const T &t, Func f)
{
while (true)
{
InIter found = std::find(first, last, t);
f(first, found);
if (found == last)
break;
first = ++found;
}
}
first
, last
:输入区间的迭代器。t
:分隔符元素。f
:函数对象或lambda,接受两个迭代器参数 [begin, end)
,表示拆分出的子区间。[first, last)
区间内查找第一个等于分隔符 t
的元素位置 found
。f(first, found)
,把当前子区间 [first, found)
传给回调函数。found
是最后一个元素,结束循环。first = found + 1
,继续拆分剩余区间。std::string s = "apple,banana,orange";
auto print_substr = [&](auto begin, auto end) {
std::cout << std::string(begin, end) << "\n";
};
split(s.begin(), s.end(), ',', print_substr);
输出:
apple
banana
orange
split
函数利用迭代器和回调函数完成分割,灵活且泛用。std::find
。f
,方便后续处理。adjacent_pair
,用于遍历一个区间内的元素,并对每对相邻元素调用一个给定的函数 f
。template <typename FwIter, typename Func>
void adjacent_pair(FwIter first, FwIter last, Func f)
{
if (first != last) // 如果区间非空
{
FwIter trailer = first; // 指向第一个元素
++first; // first 指向第二个元素
for (; first != last; ++first, ++trailer)
f(*trailer, *first); // 对相邻的两个元素调用函数 f
}
}
FwIter first, last
:输入迭代器,表示要遍历的区间 [first, last)
。Func f
:函数对象,接受两个参数,两个相邻元素的引用或值,类型大致是 void(const T&, const T&)
。trailer
指向第一个元素,first
指向第二个元素。first == last
:
f(*trailer, *first)
,即把当前元素和它后面的相邻元素传给回调函数。trailer
和 first
同时向后移动一位,保证下一次调用是下一个相邻对。假设你有一个整数序列,你想对每对相邻元素求和并打印:
std::vector<int> v = {1, 3, 5, 7};
adjacent_pair(v.begin(), v.end(), [](int a, int b){
std::cout << a << " + " << b << " = " << a + b << std::endl;
});
输出:
1 + 3 = 4
3 + 5 = 8
5 + 7 = 12
adjacent_pair
遍历序列的相邻元素对,依次执行 f
。adjacent_pair
函数的改写,用了“值拷贝”的方式保存上一个元素,而不是用迭代器 trailer
指向上一个元素。template <typename InIter, typename Func>
void adjacent_pair(InIter first, InIter last, Func f)
{
if (first != last)
{
???? trailer = *first; // What type is this?
++first;
for (; first != last; ++first)
{
f(trailer, *first);
trailer = *first;
}
}
}
trailer
的类型是什么?因为 trailer
是用来保存上一个元素的值,而不是迭代器,所以:
trailer
的类型应该和解引用迭代器 *first
返回的类型一致。decltype(*first)
,但注意它可能是引用类型(如 int&
),我们需要值类型。auto
自动推导时,auto trailer = *first;
会得到值类型(拷贝),这是最简单的写法。typename std::iterator_traits::value_type trailer = *first;
来显式写出类型。template <typename InIter, typename Func>
void adjacent_pair(InIter first, InIter last, Func f)
{
if (first != last)
{
auto trailer = *first; // 拷贝第一个元素的值
++first;
for (; first != last; ++first)
{
f(trailer, *first);
trailer = *first; // 更新上一个元素值
}
}
}
或者写得更明确点:
template <typename InIter, typename Func>
void adjacent_pair(InIter first, InIter last, Func f)
{
using ValueType = typename std::iterator_traits<InIter>::value_type;
if (first != last)
{
ValueType trailer = *first;
++first;
for (; first != last; ++first)
{
f(trailer, *first);
trailer = *first;
}
}
}
adjacent_pair
和之前版本的区别f
接受的是两个元素的引用或值,调用时写 f(*trailer, *first)
。f
直接用 trailer
和 *first
,这样避免了维护两个迭代器。trailer
类型就是迭代器指向元素的“值类型”,用 auto
即可,或用 std::iterator_traits
显式指定。template <typename InIter, typename Func>
void adjacent_pair(InIter first, InIter last, Func f)
{
if (first != last)
{
// 使用迭代器的值类型定义trailer,保存前一个元素的拷贝
typename std::iterator_traits<InIter>::value_type trailer = *first;
++first;
for (; first != last; ++first)
{
// 调用用户提供的函数f,传入相邻的两个元素
f(trailer, *first);
// 更新trailer为当前元素,准备下一轮比较
trailer = *first;
}
}
}
adjacent_pair
模板函数遍历 [first, last)
范围内的元素,针对所有相邻元素对调用 f
。trailer
保存前一个元素的拷贝,避免使用两个迭代器。trailer
初始化为第一个元素的值,然后从第二个元素开始遍历。f(trailer, *first)
,即处理相邻的两个元素。trailer
为当前元素的值,继续下一轮。trailer
是元素的拷贝,适合元素类型可拷贝的序列。std::vector<int> v = {1, 3, 6, 10};
adjacent_pair(v.begin(), v.end(), [](int a, int b) {
std::cout << a << " -> " << b << "\n";
});
输出:
1 -> 3
3 -> 6
6 -> 10
trailer
用来保存上一个元素的“值”。std::iterator_traits::value_type
明确写出 trailer
类型,便于泛型编程。std::iterator_traits::iterator_category
里,比如:
std::input_iterator_tag
std::forward_iterator_tag
std::bidirectional_iterator_tag
std::random_access_iterator_tag
// 适用于前向迭代器的实现
template <typename FWIter, typename Func>
void adjacent_pair_impl(FWIter first, FWIter last, Func f, std::forward_iterator_tag);
// 适用于输入迭代器的实现
template <typename InIter, typename Func>
void adjacent_pair_impl(InIter first, InIter last, Func f, std::input_iterator_tag);
// 主函数,调用对应版本
template <typename Iterator, typename Func>
void adjacent_pair(Iterator first, Iterator last, Func f)
{
return adjacent_pair_impl(first, last, f,
typename std::iterator_traits<Iterator>::iterator_category());
}
std::forward_iterator_tag()
。adjacent_pair_impl
重载版本。std::random_access_iterator_tag
,编译器也可以匹配接受基类 std::forward_iterator_tag
的函数(除非专门为随机访问迭代器写了更具体版本)。#include
#include
#include
// 针对前向迭代器的实现
template <typename FWIter, typename Func>
void adjacent_pair_impl(FWIter first, FWIter last, Func f, std::forward_iterator_tag)
{
std::cout << "Using forward iterator version\n";
// 实现逻辑...
}
// 针对输入迭代器的实现
template <typename InIter, typename Func>
void adjacent_pair_impl(InIter first, InIter last, Func f, std::input_iterator_tag)
{
std::cout << "Using input iterator version\n";
// 实现逻辑...
}
template <typename Iterator, typename Func>
void adjacent_pair(Iterator first, Iterator last, Func f)
{
adjacent_pair_impl(first, last, f, typename std::iterator_traits<Iterator>::iterator_category());
}
int main()
{
std::vector<int> v = {1, 2, 3};
adjacent_pair(v.begin(), v.end(), [](int a, int b){ std::cout << a << ", " << b << "\n"; });
// 对于只支持输入迭代器的类型,也会调用输入迭代器版本
}
iterator_category
告诉你迭代器类别。