目录
1.std::min_element与std::max_element
4.boost.xxx_[min|max]_yyy[min|max]_element
2.boost::algorithm::clamp_range
本文主要总结boost库中实用的三个组件:foreach、minmax、algorithm。
一、foreach
C++11引入了auto for循环,它虽然比老式的 for 循环更加简洁,更清晰地表明了代码编写者的意图,使用它不容易犯遍历不全或越界的错误。但有些时候我们使用的编译器不一定支持 C++ 的这个新特性,所以也就无法享受这一便利。
Boost的 foreach 库使用宏弥补了这个遗憾,它提供类似形式的序列遍历功能,简便好用,不需要使用麻烦的迭代器,也不需要定义新的函数对象,而且它还具有 C ++ 标准所没有的反向遍历的能力。
foreach库提供两个宏 BOOST_FOREACH 和BOOST_REVERSE_FOREACH,分别来实现对序列的正向遍历和反向遍历。使用foreach时要注意一点,它遍历序列有一个前提:假设序列是稳定的,也就是说在循环中不能改变序列的长度,也不能增减序列的元素,否则会导致遍历使用的迭代器失效,发生未定义错误。
如果在遍历时需要使用元素或者修改元素,则需要用引用的形式。auto 关键字可以加const或 & 来修饰,用来推导常量或引用类型,通常用 auto & 的形式最好,因为它可以避免无谓的拷贝。
#include <boost/foreach.hpp>
#include <boost/array.hpp>
void TestForeach()
{
boost::array<int, 3> _array{ 1,2,3 };
std::cout << "正向遍历:";
BOOST_FOREACH(auto& i, _array)
{
std::cout << i << ",";//正向遍历:1, 2, 3,
}
std::cout << std::endl << "反向遍历:";
BOOST_REVERSE_FOREACH(auto& i, _array)
{
std::cout << i << ",";//反向遍历:3, 2, 1,
}
}
BOOST_FOREACH 支持所有标准容器、原始数组、 C 字符串及元素是迭代器的std::pair。此外,BOOST_FOREACH 还支持 Boost 库内的大部分容器类型。(C++标准的for循环不支持元素是迭代器的std::pair序列。)
std::pair<int*, int*> _pair(_array.begin(), _array.end());//注意_pair里的元素是迭代器
BOOST_FOREACH(auto i, _pair)
{
std::cout << i << " ";
}
//for不支持
//for(auto i:_pair)
//{
// std::cout << i << " ";
//}
BOOST_FOREACH 是宏,这的确有时会带来问题。当变量声明是一个“含有逗号的”模板类型时,它就会失效(因为预处理器不能识别模板的"<>"),解决方法有:
- 使用auto关键字来自动推导变量类型;
- 使用boost.utility库中的BOOST_IDENTITY_TYPE宏。
#include <boost/unordered_map.hpp>
#include <boost/utility.hpp>
boost::unordered_map<int, std::string> map;
map.insert(std::pair(1, "one"));
map.insert(std::pair(2, "two"));
BOOST_FOREACH(auto i, map)//注意使用auto
{
std::cout << i.first << ":" << i.second << " ";
}
BOOST_FOREACH(BOOST_IDENTITY_TYPE((std::pair<int, std::string>)) i, map)
{
std::cout << i.first << ":" << i.second << " ";
}
二、minmax
minmax库是对 C++ 标准库中的算法 std::min/max 和 std::min_element/max_element的增强,可在一次处理中同时获得最大值和最小值,在执行效率上有很大提高,它们已经被收入C++标准。
(一)boost.minmax
1.std::min与std::max
std::cout << "100和101的最小值:" << std::min(100, 101) << std::endl;
std::cout << "100和101的最大值:" << std::max(100, 101) << std::endl;
2.boost::minmax
boost::minmax返回的是一个包含两个元素的tuple类型,第一个元素是最小值,第二个元素是最大值。
#include <boost/algorithm/minmax.hpp>
boost::tuple<const int&, const int&> tuple = boost::minmax(100, 101);
std::cout << "100和101的最小值:" << tuple.get<0>() << std::endl;
std::cout << "100和101的最大值:" << tuple.get<1>() << std::endl;
3.std::minmax(推荐)
std::minmax不仅兼容了boost::minmax,还支持初始化列表参数。需要注意的是std::minmax返回的类型是std::pair,而不是tuple。
std::pair< const int&, const int&> pair = std::minmax(100, 101);
std::cout << "100和101的最小值:" << pair.first << std::endl;
std::cout << "100和101的最大值:" << std::get<1>(pair) << std::endl;
std::pair< const int&, const int&> pair = std::minmax({ 100,101,102 });
(二)boost.minmax_element
minmax_element 并不是一个算法,而是一个算法族,包括 first_min_element、last_min_element、first_min_first_max _element等—系列类似的算 法。minmax_element 是其中最基本、最常用的算法。
【tips:begin()函数】
1.标准容器的begin()返回迭代器。迭代器中的元素是指针,指针指向第一个元素。对迭代器加*,即获得该迭代器所指的元素;对迭代器加*,再加&,就是该元素的地址。
2.boost容器begin()返回指针。指针指向第一个元素,类似标准容器的data()。
std::array<int, 3> array1{ 1,2,3 }; //标准库 printf("%p\n", array1.data()); //00000010E4CFEE58 printf("%p\n", &*array1.begin()); //00000010E4CFEE58 printf("%p\n", &*(array1.end() - 1));//00000010E4CFEE60 printf("%p\n", &array1[0]); //00000010E4CFEE58 printf("%p\n", &array1[1]); //00000010E4CFEE5C printf("%p\n", &*std::begin(array1));//00000010E4CFEE58 boost::array<int, 8> _array{ 1,2,1,8,3,4,5,8 };//boost::array printf("%p\n", _array.begin()); //00000082D5D4F108 printf("%p\n", &_array[0]); //00000082D5D4F108
3.C++11 标准库新增加的std::begin() 和std::end() 函数和 std::vector 容器包含的 begin() 和 end() 成员函数不同,标准库提供的这 2 个函数的操作对象,既可以是容器,还可以是普通数组。当操作对象是容器时,它和容器包含的 begin() 和 end() 成员函数的功能完全相同;如果操作对象是普通数组,则 begin() 函数返回的是指向数组第一个元素的指针,同样 end() 返回指向数组中最后一个元素之后一个位置的指针(注意不是最后一个元素)。
int a[3] = { 1,2,3 }; std::begin(a);//返回int* std::vector<int> vector{ 1,1,3,2,1,3,3,1 }; std::begin(vector);//返回iterator
1.std::min_element与std::max_element
当序列中元素有重复时,std::min_element返回序列中第一个最小的,std::max_element返回序列中第一个最大的。
std::vector<int> vector{1,1,3,2,1,3,3,1};
auto minPointer = std::min_element(vector.begin(), vector.end());
std::cout << "vector中的最小元素:" << *minPointer << std::endl;//1
auto maxPointer = std::max_element(vector.begin(), vector.end());
std::cout << "vector中的最大元素:" << *maxPointer << std::endl;//3
2.std::minmax_element
当序列中元素有重复时,std::minmax_element返回元素中第一个最小的,最后一个最大的。
std::vector<int> vector{1,1,3,2,1,3,3,1};
auto _pair = std::minmax_element(vector.begin(), vector.end());
std::cout << "vector中的最小元素:" << *_pair.first << std::endl;//1
std::cout << "vector中的最大元素:" << *std::get<1>(_pair) << std::endl;//3
printf("%p\n", vector.begin()._Ptr); //00000174B39EBD90
printf("%p\n", &*vector.begin()); //00000174B39EBD90
printf("%p\n", (vector.end()-1)._Ptr);//00000174B39EBDAC
printf("%p\n", _pair.first._Ptr); //00000174B39EBD90
printf("%p\n", _pair.second._Ptr); //00000174B39EBDA8
3.boost::minmax_element
当序列中(不论是标准库的还是boost库的容器)元素有重复时,boost::minmax_element返回元素中第一个最小的,第一个最大的。
注意:std::minmax_element与boost::minmax_element返回的迭代器不同。
#include <boost/algorithm/minmax_element.hpp>
boost::array<int, 8> _array{ 1,2,1,8,3,4,5,8 };
std::pair<int*, int*> _pair1 = boost::minmax_element(_array.begin(), _array.end());
std::cout << "_array中的最小元素:" << *_pair1.first << std::endl;
std::cout << "_array中的最大元素:" << *std::get<1>(_pair1) << std::endl;
printf("%p\n", _array.begin()); //00000082D5D4F108
printf("%p\n", &_array[0]); //00000082D5D4F108
printf("%p\n", _pair1.first); //00000082D5D4F108
printf("%p\n", _pair1.second); //00000082D5D4F114
4.boost.xxx_[min|max]_yyy[min|max]_element
minmax_element ( ) 函数的其他同族函数用于序列中存在相同元素的情况,它们可以找到第一个或最后一个最大值或最小值,形式为xxx_[min|max]_yyy[min|max]_element( ),其中的 xxx 和 yyy 可以是 first 或 last 。
boost::array<int, 8> _array{ 1,2,1,8,3,4,5,8 };
std::pair<int*, int*> _pair2 = boost::last_min_first_max_element(_array.begin(), _array.end());
std::cout << "_array中的最后一个最小元素:" << *_pair2.first << std::endl;
std::cout << "_array中的第一个最大元素:" << *std::get<1>(_pair2) << std::endl;
printf("%p\n", _pair2.first); //00000082D5D4F110
printf("%p\n", _pair2.second); //00000082D5D4F114
三、algorithm
(一)clamp
1.boost::algorithm::clamp
顾名思义 , clamp 用来判断一个值是否 " 夹 " 在另外一对值之间,其常用声明如下 :
template<typename T>
T const& clamp (const T& val,const T& lo,const T& hi);
函数的参数 lo 和 hi 确定了一个闭区间,其算法的逻辑如下:
- 如果 val 在区间内,那么返回 val。
- 如果 val 在区间左边 (val < lo ),那么返回 lo。
- 如果 val 在区间右边 ( hi < val ),那么返回 hi。
2.boost::algorithm::clamp_range
clamp_range可以对一组元素执行clamp算法,遵循clamp算法逻辑,然后把结果写入一个输出迭代器中。
#include <boost/algorithm/clamp.hpp>
void TestClamp()
{
int value1 = boost::algorithm::clamp(3, 1, 5);
std::cout << "3在[1,5]之间,输出:" << value1 << std::endl;//3
int value2 = boost::algorithm::clamp(3, 4, 6);
std::cout << "3在[4,6]左边,输出:" << value2 << std::endl;//4
int value3 = boost::algorithm::clamp(3, 0, 2);
std::cout << "3在[0,2]右边,输出:" << value3 << std::endl;//2
std::vector<int> vector{ 2,4,6,8,10 };
boost::algorithm::clamp_range(vector, std::ostream_iterator<int>(std::cout, ","),0,5);//2 4 5 5 5
}
(二)hex
hex算法用来执行ASCII字符( "0~9"、"A~F"和"a~f")与十六进制字符串的编码和解码,包含两个互逆的操作:hex/hex_lower 和 unhex 。
ASCII码一览表,ASCII码对照表 (biancheng.net)
ASCII字符串到16进制在线转换工具 - Coding.Tools
#include <boost/algorithm/hex.hpp>
void StudyAlgorithm::TestHex()
{
//ASCII码123转为十六进制字符串313233
boost::algorithm::hex("123", std::ostream_iterator<char>(std::cout));//313233
//解码
boost::algorithm::unhex("313233", std::ostream_iterator<char>(std::cout));//123
//ASCII码123转为十六进制字符串2B2D2A2F,并保存到字符串中
std::string value;
boost::algorithm::hex("+-*/", std::back_inserter(value));
std::cout << value;//2B2D2A2F
//小写
boost::algorithm::hex_lower("+-*/", std::back_inserter(value));
std::cout << value;//2b2d2a2f
}