linux cpp标准库,cpp_标准库算法demo

本文深入探讨C++标准库中的算法应用,包括计数、迭代器操作、排序算法、查找算法等,并通过实例展示如何高效利用这些算法进行容器操作。

// Copyright (c) 2020 by cpp 实战笔记

//

// g++ algo.cpp -std=c++11 -o a.out;./a.out

// g++ algo.cpp -std=c++14 -o a.out;./a.out

// g++ algo.cpp -std=c++14 -I../common -o a.out;./a.out

#include

#include

#include

#include

#include

#include

using namespace std;

// C++ 里的算法,指的是工作在容器上的一些泛型函数

void case1()

{

// vector 容器 定义及初始化

vector v = {1,3,1,7,5};

// count 计算容器中元素的数量,begin() 和end() 指定容器范围 ,每个元素计数1

auto n1 = std::count(

begin(v), end(v), 1

);

// 等价于手写循环实现统计。

int n2 = 0;

for(auto x : v) {

if (x == 1) {

n2++;

}

}

assert(n1 == n2);

// count_if 计算满足一定条件的元素的数量,

// begin(), end() 指定 容器范围,第三个参数可以传递lambda 函数 定义 条件函数

auto n = std::count_if(

begin(v), end(v),

[](auto x) {

return x > 2;

}

);

assert(n == 3);

}

// 算法操作容器,但实际上它看到的并不是容器,而是指向起始位置和结束位置的迭代器,

// 算法只能通过迭代器去“间接”访问容器以及元素,算法的能力是由迭代器决定的。

// 这是泛型编程的理念,与面向对象正好相反,分离了数据和操作。算法可以不关心容器的内部结构,

// 以一致的方式去操作元素,适用范围更广,用起来也更灵活。

void case2()

{

vector v = {1,2,3,4,5};

auto iter1 = v.begin(); // 成员函数的迭代器 开头

auto iter2 = v.end(); // 成员函数的迭代器 结尾

auto iter3 = std::begin(v); // 全局函数获取迭代器 获取开头,自动类型推导

auto iter4 = std::end(v); // // 全局函数获取迭代器 获取结尾,自动类型推导

// 建议使用更加通用的全局函数 begin()、end(),虽然效果是一样的,但写起来比较方便,看起来也更清楚

//(另外还有 cbegin()、cend() 函数,返回的是常量迭代器)

assert(iter1 == iter3);

assert(iter2 == iter4);

}

// 迭代器计算相关的函数

void case3()

{

array arr = {0,1,2,3,4}; // array静态数组容器

auto b = begin(arr); // 全局函数获取迭代器,首端

auto e = end(arr); // 全局函数获取迭代器,末端

assert(distance(b, e) == 5); // distance 计算迭代器的距离

auto p = next(b); // next 获取迭代器"下一个" 位置

assert(distance(b, p) == 1); // 迭代器距离

assert(distance(p, b) == -1); // distance 可以反向计算迭代器距离。

advance(p, 2); // advance 使迭代器前进 2 个位置。

assert(*p == 3);

assert(p == prev(e, 2)); // prev 计算迭代器 的前 2 个位置。

}

// 常用 的函数式 编程相关的函数

void case4()

{

#if 1

vector v = {3,5,1,7,10};

// range for 循环方式

for(const auto& x : v) {

cout << x << ",";

}

#endif

cout << endl;

#if 1

// 定义一个打印功能的lambda 函数

auto print = [](const auto& x)

{

cout << x << ",";

};

// for_each 算法的价值就体现在,把要做的事情分成了两部分,也就是两个函数:一

// 个遍历容器元素,另一个操纵容器元素,而且名字的含义更明确,代码也有更好的封装。

// 建议你尽量多用 for_each 来替代 for,因为它能 够促使我们更多地以“函数式编程”来思考,

// 使用 lambda 来封装逻辑,得到更干净、更安全的代码。

// for_each 算法 对容器内的每个函数执行同样的操作

for_each(cbegin(v), cend(v), print);

#endif

cout << endl;

#if 1

// for_each 可以直接传递 lambda 函数的方式

for_each(

cbegin(v), cend(v),

[](const auto& x)

{

cout << x << ",";

}

);

#endif

cout << endl;

}

void case5()

{

vector v = {3,5,1,7,10,99,42};

auto print = [](const auto& x)

{

cout << x << ",";

};

// total sort 排序算法,全排序

std::sort(begin(v), end(v)); // 默认快拍

for_each(cbegin(v), cend(v), print);

cout << endl;

// top3 排序, partial_sort 可以完成top n 排序

std::partial_sort(

begin(v), next(begin(v), 3), end(v));

for_each(cbegin(v), cend(v), print);

cout << endl;

// best3 nth_element 选出 最好的 n 个元素,但不排序

std::nth_element(

begin(v), next(begin(v), 3), end(v));

for_each(cbegin(v), cend(v), print);

cout << endl;

// Median nth_element 可以求中位数

auto mid_iter =

next(begin(v), v.size()/2);

std::nth_element( begin(v), mid_iter, end(v));

for_each(cbegin(v), cend(v), print);

cout << "median is " << *mid_iter << endl;

// partition 找出所有大于9 的元素

auto pos = std::partition(

begin(v), end(v),

[](const auto& x)

{

return x > 9;

}

);

for_each(begin(v), pos, print);

cout << endl;

for_each(cbegin(v), cend(v), print);

cout << endl;

// min/max minmax_element 求出最大最小元素

auto value = std::minmax_element(

cbegin(v), cend(v)

);

cout << *value.first << ","

<< *value.second << endl;

// 以上排序算法最好在顺序容器 array/vector 上调用

}

void case6()

{

vector v = {3,5,1,7,10,99,42};

auto print = [](const auto& x)

{

cout << x << ",";

};

// total sort 先排序

std::sort(begin(v), end(v));

for_each(cbegin(v), cend(v), print);

cout << endl;

// 执行二分查找,确定元素是否存在

auto found = binary_search(

cbegin(v), cend(v), 7

);

cout << "found: " << found << endl;

decltype(cend(v)) pos; // 使用decltype,声明一个迭代器,

pos = std::lower_bound(

cbegin(v), cend(v), 7 // lower_bound, 找到第一个大于等于7 的元素的位置。

);

//assert(pos != cend(v));

//assert(*pos == 7);

found = (pos != cend(v)) && (*pos == 7); // 可能找不到需要做判断

assert(found); // 7 在容器里

pos = std::lower_bound(

cbegin(v), cend(v), 9 // lower_bound 找到第一个大于等于 9 的元素的位置。

);

//assert(pos != cend(v));

//cout << *pos << endl;

found = (pos != cend(v)) && (*pos == 9);

assert(!found);

// lower_bound 的返回值是一个迭代器,所以就要做一点判断工作,才能知道是否真的找到了。

// 判断的条件有两个,一个是迭代器是否有效,另一个是迭代器的值是不是要找的值。

// lower_bound 的查找条件是“大于等于”,而不是“等于”,所以它的真正含义是“大于等于值的第一个位置”。

// 相应的也就有“大于等于值的最后一个位置”,算法叫upper_bound,返回的是第一个“大于”值的元素

pos = std::upper_bound(

cbegin(v), cend(v), 9 // 找到第一个大于9 的位置。

);

// 返回的形式 begin < x <= lower_bound < upper_bound < end

//cout << *pos << endl;

// equal_range() 可以找出有序序列中所有和给定元素相等的元素。它的前两个参数是指定序列的两个正向迭代器,第三个参数是要查找的元素

// 算法会返回一个 pair 对象,first 指向的是不小于第三个参数的一个元素,second 指向大于第三个参数的一个元素

auto range = std::equal_range(

cbegin(v), cend(v), 9

);

//cout << *range.first << endl;

//cout << *range.second << endl;

for_each(

range.first, std::next(range.second), print

);

cout << endl;

}

void case7()

{

// 有序容器set、map 有等价的成员函数find/lower_bound/upper_bound,效果是一样的

multiset s = {3,5,1,7,7,7,10,99,42}; // multiset 允许重复

auto print = [](const auto& x)

{

cout << x << ",";

};

auto pos = s.find(7);

assert(pos != s.end()); // 二分查找返回迭代器,需要和end 比较才能确定是否找到。

auto lower_pos = s.lower_bound(7); // 获取区间的左端点

auto upper_pos = s.upper_bound(7); // 获取区间的右端点。

for_each(

lower_pos, upper_pos, print

);

cout << endl;

}

void case8()

{

vector v = {1,9,11,3,5,7};

decltype(v.end()) pos; // 声明一个迭代器,使用decltype

pos = std::find(

begin(v), end(v), 3 // find 查找算法,找到第一个出现的位置

);

assert(pos != end(v)); // 与end()比较才能知道是否找到

// find_if 查找算法,用lambda判断条件

pos = std::find_if(

begin(v), end(v),

[](auto x) {

return x % 2 == 0;

}

);

assert(pos == end(v));

array arr = {3,5};

// find_first_of 查找一个子区间

pos = std::find_first_of(

begin(v), end(v),

begin(arr), end(arr)

);

assert(pos != end(v));

}

int main()

{

case1();

case2();

case3();

case4();

case5();

case6();

case7();

case8();

using namespace std;

cout << "algorithm demo" << endl;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值