C++参悟:stl中的比较最大最小操作

ops/2024/10/11 13:23:41/

stl中的比较最大最小操作

  • 一、概述
  • 二、最小值
  • 三、最大值
    • 1. max
    • 2. max_element
  • 四、混合
    • 1. minmax
    • 2. minmax_element

一、概述

记录这里C11中常用的最小值和最大值的比较函数,最好的参考资料其实就是 https://zh.cppreference.com

最重要的查看文档其实就看他的如何实现,这个就是使用的最常用的功能。因为STL用的很多基本上全是函数模板库,都是支持自定义函数函数器作为一个对比选项。

不带 _element 的函数一般用在两个值之间比较,如果很多值,还是用带_element ,这个是去遍历容器比较

就像min、max最后比较两个值,而且返回的是值,min_element、max_element比较容器,返回的是迭代器

二、最小值

1. min

1. 可能的实现

// 版本 1
template<class T> 
const T& min(const T& a, const T& b)
{return (b < a) ? b : a;
}// 版本 2
template<class T, class Compare> 
const T& min(const T& a, const T& b, Compare comp)
{return (comp(b, a)) ? b : a;
}// 版本 3
template<class T>
T min(std::initializer_list<T> ilist)
{return *std::min_element(ilist.begin(), ilist.end());
}// 版本 4
template<class T, class Compare>
T min(std::initializer_list<T> ilist, Compare comp)
{return *std::min_element(ilist.begin(), ilist.end(), comp);
}

从上面的实现其实就能看出来,这个是支持用函数器做自己的特定对比,也是可以通过重载 < 符号去实现对比功能.

而且输入值和输出的模板类型是一样的,

还有一些用的是 min_element 函数为实现,对了min_element的一个适配器。

  1. 例子

下面给一个对比最小值的例子

#include <algorithm>
#include <iostream>
#include <string_view>int main()
{int res_1 = std::min(1, 9999);	// res_1 = 1char res_2 = std::min('a', 'b');	// res_2 = 'a'string res_3 = std::min({"foo", "bar", "hello"}, [](const std::string s1, const std::string s2){return s1.size() < s2.size();}) ;	// res_3 = "foo"
}

min_element_67">2. min_element

看看这个的相关实现

// 版本一
template<class ForwardIt>
ForwardIt min_element(ForwardIt first, ForwardIt last)
{if (first == last)return last;ForwardIt smallest = first;++first;for (; first != last; ++first)if (*first < *smallest)smallest = first;return smallest;
}// 版本二
template<class ForwardIt, class Compare>
ForwardIt min_element(ForwardIt first, ForwardIt last, Compare comp)
{if (first == last)return last;ForwardIt smallest = first;++first;for (; first != last; ++first)if (comp(*first, *smallest))smallest = first;return smallest;
}

从函数的实现来看,外部的函数器的差距就在 一个是用得 ‘<’ ,另外一个用的 comp(*first, *smallest)对比,因为‘<’取决于语言定义或者我们程序员的重载实现的。 后面的其他函数max,minmax都是用的这样的。

这个参数的传入的其实就是迭代器,返回的也是迭代器也需要去解引取值之类的。

就像下面这种代码

std::vector<PointF> points{PointF{-1.43, 5.654}, PointF{2.453, 8.654} , PointF{10.453, -2.654}, PointF{14.453, -8.87}};auto x_minmax = std::minmax_element(points.begin(), points.end(), [](const PointF &p1, const PointF &p2){return p1.x() < p2.x();
}) ;

三、最大值

1. max

max和min是一样的定义方式,其实就是把那个大于小于改了一下

2. max_element

这个的实现也比较简单

// 版本一
template<class ForwardIt>
ForwardIt max_element(ForwardIt first, ForwardIt last)
{if (first == last)return last;ForwardIt largest = first;++first;for (; first != last; ++first)if (*largest < *first)largest = first;return largest;
}// 版本二
template<class ForwardIt, class Compare>
ForwardIt max_element(ForwardIt first, ForwardIt last, Compare comp)
{if (first == last)return last;ForwardIt largest = first;++first;for (; first != last; ++first)if (comp(*largest, *first))largest = first;return largest;
}

四、混合

1. minmax

实现的源码大差不差的如下,是不是比较巧妙和灵活,注意这个是返回的是值,而不是迭代器

//版本一
template<class T> 
constexpr std::pair<const T&, const T&> minmax( const T& a, const T& b )
{return (b < a) ? std::pair<const T&, const T&>(b, a): std::pair<const T&, const T&>(a, b);
}//版本二
template<class T, class Compare> 
constexpr std::pair<const T&, const T&> minmax( const T& a, const T& b, Compare comp )
{return comp(b, a) ? std::pair<const T&, const T&>(b, a): std::pair<const T&, const T&>(a, b);
}//版本三
template< class T >
constexpr std::pair<T, T> minmax( std::initializer_list<T> ilist )
{auto p = std::minmax_element(ilist.begin(), ilist.end());return std::pair(*p.first, *p.second);
}// 版本四
template< class T, class Compare >
constexpr std::pair<T, T> minmax( std::initializer_list<T> ilist, Compare comp )
{auto p = std::minmax_element(ilist.begin(), ilist.end(), comp);return std::pair(*p.first, *p.second);
}

上面的first是小值,second是大值,所以看一下源码就记住了
看看例子

std::pair<int, int> bounds = std::minmax(3, -1);

2. minmax_element

和之前的min_element类似,返回的是一个std::pair<迭代器,迭代器>类型,要取值要自己去解引数据

//版本一
template<class ForwardIt>
std::pair<ForwardIt, ForwardIt> minmax_element(ForwardIt first, ForwardIt last)
{using value_type = typename std::iterator_traits<ForwardIt>::value_type;return std::minmax_element(first, last, std::less<value_type>());
}//版本二
template<class ForwardIt, class Compare>
std::pair<ForwardIt, ForwardIt> minmax_element(ForwardIt first, ForwardIt last, Compare comp)
{auto min = first, max = first;if (first == last || ++first == last)return {min, max};if (comp(*first, *min)) {min = first;} else {max = first;}while (++first != last) {auto i = first;if (++first == last) {if (comp(*i, *min)) min = i;else if (!(comp(*i, *max))) max = i;break;} else {if (comp(*first, *i)) {if (comp(*first, *min)) min = first;if (!(comp(*i, *max))) max = i;} else {if (comp(*i, *min)) min = i;if (!(comp(*first, *max))) max = first;}}}return {min, max};
}

例子如下:

std::vector<int> v {3, 1, 4, 1, 5, 9, 2, 6};
auto bounds = std::minmax_element(v.begin(), v.end());int min = *bounds.first;	// 1
int max = *bounds.second;	// 9

http://www.ppmy.cn/ops/92000.html

相关文章

Linux LVM 详解

Linux逻辑卷管理&#xff08;LVM&#xff0c;Logical Volume Manager&#xff09;是一种管理磁盘存储空间的工具。它提供了比传统分区方法更灵活和高效的磁盘管理方式。通过LVM&#xff0c;可以动态调整磁盘分区大小&#xff0c;轻松添加或移除磁盘&#xff0c;并实现快照等高级…

算法学习day30

一、最短无序连续子数组&#xff08;贪心&#xff09; 给你一个整数数组 nums &#xff0c;你需要找出一个 连续子数组 &#xff0c;如果对这个子数组进行升序排序&#xff0c;那么整个数组都会变为升序排序。请你找出符合题意的 最短 子数组&#xff0c;并输出它的长度。 输…

鸿蒙应用服务开发【自定义通知角标】

自定义通知角标 介绍 本示例主要展示了设定应用的桌面图标角标的功能&#xff0c;使用ohos.notificationManager接口&#xff0c;进行桌面角标的设置&#xff0c;通知的发送&#xff0c;获取等。 效果预览 使用说明 在主界面&#xff0c;可以看到当前应用的所有消息通知&am…

基于Qt实现图片查看器

一、简介 基于Qt实现的图片查看器。支持如下功能&#xff1a; 图像放大、缩小、拖动矩形标注框显示&#xff0c;在放大缩小时&#xff0c;标注框的线宽始终保持固定宽度。 二、源码 ImgViewWidget.hpp // ImgViewWidget.hpp #pragma once #include <QImage> #includ…

Java设计模式(适配器模式)

定义 将一个类的接口转换成客户希望的另一个接口。适配器模式让那些接口不兼容的类可以一起工作。 角色 目标抽象类&#xff08;Target&#xff09;&#xff1a;目标抽象类定义客户所需的接口&#xff08;在类适配器中&#xff0c;目标抽象类只能是接口&#xff09;。 适配器类…

Shell脚本-DNS域名解析格式化

Shell脚本-DNS域名解析格式化 大家好&#xff0c;我是秋意零。 今天&#xff0c;分享一个Shell脚本。大家不一定用的上&#xff0c;但可以参考&#xff1b;再一个是可以通过下列需求进行练手&#xff0c;初学者可以试试&#xff01; 脚本还有优化的地方&#xff08;懒得改了…

【Android】ContentProvider基本概念

ContentProvider Android权限机制详解 <manifest xmlns:android"http://schemas.android.com/apk/res/android"package"com.example.broadcasttest"> <uses-permission android:name"android.permission.RECEIVE_BOOT_COMPLETED" />…

计算机网络408考研 2014

1 计算机网络408考研2014年真题解析_哔哩哔哩_bilibili 1 111 1 11