C++中的策略模式进阶

1、非修改序列算法

这些算法不会改变它们所操作的容器中的元素。

1.1 find 和 find_if
  • find(begin, end, value):查找第一个等于 value 的元素,返回迭代器(未找到返回 end)。
  • find_if(begin, end, predicate):查找第一个满足谓词的元素。
  • find_end(begin, end, sub_begin, sub_end):查找子序列最后一次出现的位置。
vector<int> nums = {1, 3, 5, 7, 9}; // 查找值为5的元素 auto it = find(nums.begin(), nums.end(), 5); if (it != nums.end()) { cout << "found: " << *it << endl; // 输出:5 } // 查找第一个大于6的元素 auto it2 = find_if(nums.begin(), nums.end(), [](int x) { return x > 6; }); cout << "first >6: " << *it2 << endl; // 输出:7 // 查找子序列 vector<int> sub = {3, 5}; auto it3 = find_end(nums.begin(), nums.end(), sub.begin(), sub.end()); if (it3 != nums.end()) { cout << "subsequence starts at index: " << it3 - nums.begin() << endl; // 输出:1 } 
1.2 count 和 count_if
  • count(begin, end, value):统计等于 value 的元素个数。
  • count_if(begin, end, predicate):统计满足谓词(predicate)的元素个数。
std::vector<int> vec = {1, 2, 3, 2, 4, 2}; int cnt = std::count(vec.begin(), vec.end(), 2); // 计数2的个数,结果为3 int even_cnt = std::count_if(vec.begin(), vec.end(), [](int x) { return x % 2 == 0; }); // 偶数个数,结果为4 
1.3 for_each

对范围内的每个元素应用一个函数

std::vector<int> vec = {1, 2, 3, 4, 5}; std::for_each(vec.begin(), vec.end(), [](int& x) { x *= 2; // 将每个元素乘以2 }); // 现在vec变为{2, 4, 6, 8, 10} 
1.4 equal 与 mismatch
  • equal(b1, e1, b2):判断两个范围 [b1,e1) 和 [b2, b2+(e1-b1)) 是否相等。
  • mismatch(b1, e1, b2):返回两个范围中第一个不相等元素的迭代器对(pair)。
vector<int> a = {1, 2, 3}; vector<int> b = {1, 2, 4}; vector<int> c = {1, 2, 3, 4}; // 比较a和b的前3个元素 bool is_equal = equal(a.begin(), a.end(), b.begin()); cout << "a == b? " << boolalpha << is_equal << endl; // 输出:false // 查找a和c的第一个不匹配元素 auto mis = mismatch(a.begin(), a.end(), c.begin()); if (mis.first != a.end()) { cout << "mismatch: " << *mis.first << " vs " << *mis.second << endl; // 无输出(a和c前3元素相等) } 
1.5 all_of, any_of, none_of

检查范围内元素是否全部、存在或没有满足条件的

std::vector<int> vec = {2, 4, 6, 8}; bool all_even = std::all_of(vec.begin(), vec.end(), [](int x) { return x % 2 == 0; }); // true bool any_odd = std::any_of(vec.begin(), vec.end(), [](int x) { return x % 2 != 0; }); // false bool none_negative = std::none_of(vec.begin(), vec.end(), [](int x) { return x < 0; }); // true 

2、修改序列算法

这些算法会修改它们所操作的容器中的元素。

2.1 copy 和 copy_if
  • copy(begin, end, dest):将 [begin, end) 中的元素复制到 dest 开始的位置。
  • copy_if(begin, end, dest, predicate):复制满足谓词的元素到 dest
vector<int> src = {1, 2, 3, 4, 5}; vector<int> dest(5); // 需预先分配足够空间 // 复制所有元素 copy(src.begin(), src.end(), dest.begin()); // dest: [1,2,3,4,5] // 复制偶数元素到新容器 vector<int> evens; copy_if(src.begin(), src.end(), back_inserter(evens), [](int x) { return x % 2 == 0; }); // evens: [2,4] 

注意back_inserter(dest) 会自动调用 push_back,无需提前分配空间。

2.2 transform

对范围内的每个元素应用一个函数,并将结果存储在另一个范围内

vector<int> nums = {1, 2, 3}; vector<int> squares(3); // 计算平方(单参数转换) transform(nums.begin(), nums.end(), squares.begin(), [](int x) { return x * x; }); // squares: [1,4,9] // 两容器元素相加(双参数转换) vector<int> a = {1, 2, 3}; vector<int> b = {4, 5, 6}; vector<int> sum(3); transform(a.begin(), a.end(), b.begin(), sum.begin(), [](int x, int y) { return x + y; }); // sum: [5,7,9] 
2.3 replace、replace_if与 replace_copy
  • replace(begin, end, old_val, new_val):将所有 old_val 替换为 new_val
  • replace_if(begin, end, predicate, new_val):替换满足谓词的元素。
  • replace_copy(begin, end, dest, old_val, new_val):复制时替换元素(不修改原容器)。
vector<int> nums = {1, 2, 3, 2, 5}; // 替换所有2为20 replace(nums.begin(), nums.end(), 2, 20); // nums: [1,20,3,20,5] // 替换大于10的元素为0 replace_if(nums.begin(), nums.end(), [](int x) { return x > 10; }, 0); // nums: [1,0,3,0,5] // 复制时替换3为300(原容器不变) vector<int> res; replace_copy(nums.begin(), nums.end(), back_inserter(res), 3, 300); // res: [1,0,300,0,5] 
2.4 remove、remove_if 与 erase
  • remove(begin, end, value):将等于 value 的元素 “移动” 到容器末尾,返回新的逻辑尾迭代器(不实际删除元素,需配合 erase)。
  • remove_if(begin, end, predicate):移动满足谓词的元素到末尾。
vector<int> nums = {1, 2, 3, 2, 4}; // 逻辑删除所有2(移动到末尾) auto new_end = remove(nums.begin(), nums.end(), 2); // nums: [1,3,4,2,2] // 物理删除(真正移除元素) nums.erase(new_end, nums.end()); // nums: [1,3,4] // 结合lambda删除偶数 nums = {1, 2, 3, 4, 5}; nums.erase(remove_if(nums.begin(), nums.end(), [](int x) { return x % 2 == 0; }), nums.end()); // nums: [1,3,5] 
2.5 unique

移除范围内连续的重复元素,返回新的逻辑结尾迭代器。通常与erase结合使用。

std::vector<int> vec = {1, 1, 2, 2, 3, 3, 3, 4, 5}; auto last = std::unique(vec.begin(), vec.end()); vec.erase(last, vec.end()); // vec变为{1, 2, 3, 4, 5} 
2.6 reverse

反转范围内的元素顺序

std::vector<int> vec = {1, 2, 3, 4, 5}; std::reverse(vec.begin(), vec.end()); // vec变为{5, 4, 3, 2, 1} 
2.7 rotate

旋转范围内的元素,使中间元素成为新的第一个元素

std::vector<int> vec = {1, 2, 3, 4, 5}; std::rotate(vec.begin(), vec.begin() + 2, vec.end()); // 以3为起点旋转,vec变为{3, 4, 5, 1, 2} 
2.8 shuffle

随机重排范围内的元素(需要C++11或更高版本)

#include <random> #include <algorithm> std::vector<int> vec = {1, 2, 3, 4, 5}; std::random_device rd; std::mt19937 g(rd()); std::shuffle(vec.begin(), vec.end(), g); // 随机打乱vec中的元素 

3、排序和相关算法

3.1 sort、stable_sort 与 partial_sort
  • sort(begin, end):对元素进行快速排序(不稳定,平均时间复杂度 O (n log n))。
  • stable_sort(begin, end):稳定排序(相等元素相对位置不变)。
  • partial_sort(begin, mid, end):部分排序,使 [begin, mid) 为整个范围中最小的元素并排序。
std::vector<int> vec = {5, 3, 1, 4, 2}; std::sort(vec.begin(), vec.end()); // 默认升序,vec变为{1, 2, 3, 4, 5} std::sort(vec.begin(), vec.end(), std::greater<int>()); // 降序,vec变为{5, 4, 3, 2, 1} std::sort(vec.begin(), vec.end(), [](int a, int b) { return a < b; }); // 升序,自定义比较 std::vector<std::pair<int, int>> vec = {{1, 2}, {2, 1}, {1, 1}, {2, 2}}; std::stable_sort(vec.begin(), vec.end(), [](const auto& a, const auto& b) { return a.first < b.first; // 按first排序,保持相等元素的相对顺序 }); std::vector<int> vec = {5, 3, 1, 4, 2, 6}; // 将最小的3个元素放在前面并排序 std::partial_sort(vec.begin(), vec.begin() + 3, vec.end()); // 现在vec前三个元素是1, 2, 3,后面是未排序的4, 5, 6 
3.2 nth_element

重新排列范围,使得指定位置的元素等于排序后的元素,并且左边的元素都不大于它,右边的元素都不小于它

std::vector<int> vec = {5, 3, 1, 4, 2, 6}; // 找到第三小的元素(索引2) std::nth_element(vec.begin(), vec.begin() + 2, vec.end()); // 现在vec[2]是3,它左边的元素<=3,右边的>=3 
3.3 binary_search、lower_bound、upper_bound

需在已排序的容器上使用

  • binary_search(begin, end, value):判断 value 是否存在(返回 bool)。
  • lower_bound(begin, end, value):返回第一个不小于 value 的元素迭代器。
  • upper_bound(begin, end, value):返回第一个大于 value 的元素迭代器。
vector<int> sorted = {1, 3, 3, 5, 7}; // 必须先排序 // 判断3是否存在 bool exists = binary_search(sorted.begin(), sorted.end(), 3); // true // 查找第一个>=3的元素 auto lb = lower_bound(sorted.begin(), sorted.end(), 3); cout << "lower_bound index: " << lb - sorted.begin() << endl; // 输出:1 // 查找第一个>3的元素 auto ub = upper_bound(sorted.begin(), sorted.end(), 3); cout << "upper_bound index: " << ub - sorted.begin() << endl; // 输出:3 
3.4 merge

合并两个已排序的范围到新容器(保持排序)

vector<int> a = {1, 3, 5}; vector<int> b = {2, 4, 6}; vector<int> merged(a.size() + b.size()); // 合并a和b(均需已排序) merge(a.begin(), a.end(), b.begin(), b.end(), merged.begin()); // merged: [1,2,3,4,5,6] 

4、堆算法

STL提供了将范围作为堆来操作的算法,包括make_heappush_heappop_heapsort_heap等。

std::vector<int> vec = {4, 1, 3, 2, 5}; std::make_heap(vec.begin(), vec.end()); // 构建最大堆,vec变为{5, 4, 3, 2, 1} vec.push_back(6); std::push_heap(vec.begin(), vec.end()); // 将新元素加入堆,vec变为{6, 4, 5, 2, 1, 3} std::pop_heap(vec.begin(), vec.end()); // 将最大元素移到末尾,vec变为{5, 4, 3, 2, 1, 6} int max_val = vec.back(); // 获取最大元素6 vec.pop_back(); // 移除最大元素 std::sort_heap(vec.begin(), vec.end()); // 将堆排序为升序序列,vec变为{1, 2, 3, 4, 5} 

5、最小/最大值算法

5.1 min 和 max

返回两个值或初始化列表中的最小/最大值

int a = 5, b = 3; int min_val = std::min(a, b); // 3 int max_val = std::max(a, b); // 5 auto min_of_list = std::min({4, 2, 8, 5, 1}); // 1 auto max_of_list = std::max({4, 2, 8, 5, 1}); // 8 
5.2 min_element 和 max_element

返回范围内的最小/最大元素的迭代器

std::vector<int> vec = {3, 1, 4, 2, 5}; auto min_it = std::min_element(vec.begin(), vec.end()); // 指向1 auto max_it = std::max_element(vec.begin(), vec.end()); // 指向5 
5.3 minmax_element (C++11)

同时返回范围内的最小和最大元素的迭代器

std::vector<int> vec = {3, 1, 4, 2, 5}; auto minmax = std::minmax_element(vec.begin(), vec.end()); // minmax.first指向1,minmax.second指向5 

6、数值算法(在<numeric>中)

6.1 accumulate

计算范围内元素的累加和(或自定义操作)

#include <numeric> std::vector<int> vec = {1, 2, 3, 4, 5}; int sum = std::accumulate(vec.begin(), vec.end(), 0); // 和,初始值为0,结果为15 int product = std::accumulate(vec.begin(), vec.end(), 1, std::multiplies<int>()); // 乘积,初始值为1,结果为120 
6.2 inner_product

计算两个范围的内积(或自定义操作)

std::vector<int> a = {1, 2, 3}; std::vector<int> b = {4, 5, 6}; int dot = std::inner_product(a.begin(), a.end(), b.begin(), 0); // 1*4 + 2*5 + 3*6 = 32 
6.3 iota

用连续递增的值填充范围

std::vector<int> vec(5); std::iota(vec.begin(), vec.end(), 10); // 填充为10, 11, 12, 13, 14 
6.4 partial_sum

计算部分和,将结果存储在目标范围内

std::vector<int> src = {1, 2, 3, 4, 5}; std::vector<int> dst(src.size()); std::partial_sum(src.begin(), src.end(), dst.begin()); // dst变为{1, 3, 6, 10, 15} 
6.5 adjacent_difference

计算相邻元素的差值,将结果存储在目标范围内

std::vector<int> src = {1, 2, 3, 4, 5}; std::vector<int> dst(src.size()); std::adjacent_difference(src.begin(), src.end(), dst.begin()); // dst变为{1, 1, 1, 1, 1} 

7、其他

7.1 generate

用生成函数填充范围

std::vector<int> vec(5); int n = 0; std::generate(vec.begin(), vec.end(), [&n]() { return n++; }); // 填充为0, 1, 2, 3, 4 
7.2 generate_n

用生成函数填充范围的开始n个元素

std::vector<int> vec(5); int n = 10; std::generate_n(vec.begin(), 3, [&n]() { return n++; }); // 前三个元素为10, 11, 12,后两个保持不变 
7.3 includes

检查一个排序范围是否包含另一个排序范围的所有元素

std::vector<int> vec1 = {1, 2, 3, 4, 5}; std::vector<int> vec2 = {2, 4}; bool includes = std::includes(vec1.begin(), vec1.end(), vec2.begin(), vec2.end()); // true 
7.3 set_union, set_intersection, set_difference, set_symmetric_difference

执行集合操作:并集、交集、差集和对称差集

std::vector<int> v1 = {1, 2, 3, 4, 5}; std::vector<int> v2 = {3, 4, 5, 6, 7}; std::vector<int> result; // 并集 std::set_union(v1.begin(), v1.end(), v2.begin(), v2.end(), std::back_inserter(result)); // result为{1, 2, 3, 4, 5, 6, 7} // 交集 result.clear(); std::set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), std::back_inserter(result)); // result为{3, 4, 5} // 差集 (v1 - v2) result.clear(); std::set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), std::back_inserter(result)); // result为{1, 2} // 对称差集 (v1 ∪ v2 - v1 ∩ v2) result.clear(); std::set_symmetric_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), std::back_inserter(result)); // result为{1, 2, 6, 7} 

8、常见问题

  1. sort 与 stable_sort 的区别?
    • sort 采用快速排序(实际是 introsort 算法),不稳定(相等元素的相对位置可能改变),平均时间复杂度 O (n log n)。
    • stable_sort 采用归并排序,稳定(相等元素相对位置不变),时间复杂度 O (n log n),但空间开销略大。
  2. 为什么 remove 算法需要配合 erase 使用?
    remove 算法的原理是 “覆盖” 要删除的元素,将保留的元素移到前面,返回新的逻辑尾迭代器,但不修改容器的实际大小erase 则通过迭代器范围真正删除元素,修改容器大小。因此需结合使用:container.erase(remove(...), container.end())
  3. 哪些算法需要容器是已排序的?
    二分查找系列(binary_searchlower_boundupper_bound)、集合算法(set_intersectionset_union 等)、merge 等,这些算法依赖有序性实现高效操作(如二分查找 O (log n))。

Read more

【踩坑记录】使用 Layui 框架时解决 Unity WebGL 渲染在 Tab 切换时黑屏问题

【踩坑记录】使用 Layui 框架时解决 Unity WebGL 渲染在 Tab 切换时黑屏问题

【踩坑记录】使用 Layui 框架时解决 Unity WebGL 渲染在 Tab 切换时黑屏问题 在开发 Web 应用时,尤其是集成了 Unity WebGL 内容的页面,遇到一个问题:当 Unity WebGL 渲染内容嵌入到一个 Tab 中时,切换 Tab 后画面会变黑,直到用户点击黑屏区域,才会恢复显示。 这个问题通常是因为 Unity 渲染在 Tab 切换时被暂停或未能获得焦点所致。 在本文中,我们将介绍如何在使用 Layui 框架时,通过监听 Tab 切换事件并强制 Unity WebGL 渲染恢复,来解决这一问题。 1. 问题描述 当 Unity WebGL 内容嵌入到页面中的多个

By Ne0inhk
Spring Boot携手Leaflet,点亮省级旅游口号WebGIS可视化之路

Spring Boot携手Leaflet,点亮省级旅游口号WebGIS可视化之路

目录 前言 一、旅游口号信息管理 1、写在前面的 2、空间属性关联 二、SpringBoot后台实现 1、系统调用时序图 2、Mapper数据查询实现 3、控制层接口实现 三、Leaflet集成实现WebGIS 1、省级数据展示及可视化 2、东北三省旅游口号 3、长三角城市群口号 4、珠三角旅游口号 5、西北地区旅游口号 四、总结 前言         在当今数字化浪潮汹涌澎湃的时代,地理信息系统(GIS)技术正以前所未有的速度改变着我们对世界的认知与探索方式。它不仅为科学研究提供了强大的工具,更在旅游、城市规划、环境保护等诸多领域展现出巨大的应用潜力。而当我们将目光聚焦于旅游行业,一个充满活力与创新的领域,GIS技术的应用更是如鱼得水,为旅游体验的提升和旅        游管理的优化带来了全新的机遇。         省级旅游口号作为各地旅游宣传的重要名片,承载着地域文化的精髓与旅游资源的亮点,是吸引游客、塑造旅游品牌形象的关键要素。然而,传统的旅游口号宣传方式往往局限于文字、

By Ne0inhk
Claude Code免费使用教程,前端必看!

Claude Code免费使用教程,前端必看!

目前claude有两种使用方式,一种是官方购买渠道(太贵了,用不起,扎心。。。),还一种就是通过api方式,就是下面我讲的通过any-router提供的api调通就行~相当于中转站,主要是免费啊,谁能说不香! 1.注册LinuxDo账户 目前AnyRouter取消了github登录方式,只能通过LinuxDo账户登录,或者edu的邮箱登录,这里选择使用LinuxDo登录。 linux do官方网址:https://linux.do/   linux do邀请码:2E917F23-D9BF-44FE-BCBD-AE6AB3B1FC17 提示:如果Linuxdo邀请码失效,注册页面填写邀请码的那个输入框下面有邀请码链接,如图: 申请理由稍微写写,别全打逗号啥的,认真写下很快就过了。   2.any Router登录使用 上面linux do账号注册完毕就可以,登录any router了 any router网址:https://anyrouter.top/register?aff=iVs0    (貌似目前需要挂绿色软件才能登录上去) 一定要复制上面的网址(别删

By Ne0inhk
【Linux篇章】再续传输层协议TCP:用技术隐喻重构网络世界的底层逻辑,用算法演绎‘网络因果律’的终极推演(通俗理解TCP协议,这一篇就够了)!

【Linux篇章】再续传输层协议TCP:用技术隐喻重构网络世界的底层逻辑,用算法演绎‘网络因果律’的终极推演(通俗理解TCP协议,这一篇就够了)!

📌本篇摘要 * 本篇将根据TCP协议报文的格式来对TCP更深入的了解,学习它的三次握手,四次挥手,滑动窗口等等,到最后能更加深入理解之前写TCP通信的时候,底层到底是如何进行的,读完本篇将会对之前TCP网络通信编程有更深入的认识。 🏠欢迎拜访🏠:点击进入博主主页 📌本篇主题📌:再续TCP协议 📅制作日期📅:2025.12.20 🧭隶属专栏🧭:点击进入所属Linux专栏 一.TCP协议格式 -TCP 全称为 传输控制协议(Transmission Control Protocol). 人如其名, 要对数据的传输进行一个详细的控制。 下面看TCP报文的格式: 下面我们来一个个介绍下这些字段及作用: 1. 🔍十六位窗口大小 * 这里我们知道对于tcp来说,如果接收缓冲区满了,再发送机会被丢弃,因此发送前需要知道对的的接收缓冲区的剩余长度。 * 按量按需发送,必须知道对方的接受缓冲区中剩余空间的大小,因此每次发送的tcp报文都要带有自己剩余接收缓冲区的长度! 2.🔍4位首部长度 * 首先我们要知道tcp光报头就至少20字节(不包含

By Ne0inhk