C++ 最大值与最小值

在 C++ 中,比较两个或多个数据的大小、找出其中的最大值或最小值是很常见的操作。虽然我们可以自己写 if...else 语句或三元运算符来判断,但直接调用标准库提供的现成函数会让代码简洁直观得多。

与前面几节的 <cmath> 头文件不同,C++ 求最大值与最小值的函数定义在 <algorithm> 头文件中,常用的主要有 3 个:① std::max();② std::min();③ std::minmax()。

std::max() 与 std::min()

在 C++ 中,当我们只需要比较两个已知数据的大小时,可以在引入 <algorithm> 头文件后直接调用 std::max() 和 std::min(),分别用来获取最大值和最小值。

语法:

std::max(a, b)
std::min(a, b)

说明:

std::max(a, b) 会返回 a 和 b 中较大的值;std::min(a, b) 则会返回 a 和 b 中较小的值。它们不仅支持 int、double 等数值类型,还支持 char 字符和字符串按字典序比较大小。

小伙伴们要注意,比较字符串大小时需要先引入 <string> 头文件并传入 std::string 对象。千万不要直接传入 "apple"、"banana" 这样的双引号字符串字面量,否则比较的是内存地址而不是文本内容。

示例 1:比较两个数的大小

#include <algorithm>
#include <iostream>

int main() {
    int a = 15;
    int b = 28;
    std::cout << std::max(a, b) << '\n';    // 求较大值
    std::cout << std::min(a, b) << '\n';    // 求较小值

    double x = 3.14;
    double y = 2.71;
    std::cout << std::max(x, y) << '\n';    // 比较浮点数
    return 0;
}

运行结果如下。

28
15
3.14

分析:

std::max(a, b) 返回了较大的整数 28,std::min(a, b) 返回了较小的整数 15,对浮点数 x 和 y 也同样适用。

除了单纯比大小之外,这两个函数在实际开发中还经常用来给变量做 “保底” 或 “封顶”。比如游戏角色受到伤害扣血后,生命值 hp 最低只能扣到 0,不能变成负数。对于这个需求,下面 2 种方式是等价的。

int hp = 20 - 35;

// 方式 1(推荐)
hp = std::max(0, hp);

// 方式 2
if (hp < 0) {
    hp = 0;
}

其中,方式 1 通过 std::max(0, hp) 为生命值设置了下限:一旦 hp 小于 0,函数就会返回较大的 0,一行代码就能代替手写 if 判断。

std::clamp() 函数

在上面的扣血例子里,如果我们不仅要求生命值 hp 最低不能小于 0,还要求回血时最高不能超过满血上限 100,此时又应该怎么写呢?

从 C++17 标准开始,<algorithm> 头文件专门提供了 std::clamp(val, lo, hi) 函数,其中 clamp 是英文 “夹紧、固定” 的意思。当 val 小于下限 lo 时返回 lo,大于上限 hi 时返回 hi,处于区间内则原样返回 val。

比如直接写一句 hp = std::clamp(hp, 0, 100);,我们就能把 hp 限制在 0 ~ 100 之间,比嵌套写成 std::min(100, std::max(0, hp)) 好读得多。使用时只需要注意下限 lo 不能大于上限 hi 即可。

比较多个数与 std::minmax()

如果手头有 3 个、4 个甚至更多已知的变量,想要找出其中的最值,我们不需要一层套一层地写成 std::max(a, std::max(b, c)),<algorithm> 提供了更简便的多值比较写法。

1. 比较 3 个及以上的数

当需要同时比较多个同类型的数据时,我们只需要在参数位置写上一对花括号 {},把所有待比较的值放进去即可。

语法:

std::max({值1, 值2, 值3, ...})
std::min({值1, 值2, 值3, ...})

说明:

花括号 {} 内可以放入任意多个同类型的变量或常量,数据之间用英文逗号隔开,函数会自动找出并返回其中的最大值或最小值。

示例 2:比较多个数的大小

#include <algorithm>
#include <iostream>

int main() {
    int s1 = 85;
    int s2 = 92;
    int s3 = 78;
    int s4 = 96;

    int highest = std::max({s1, s2, s3, s4});    // 找出最高分
    int lowest = std::min({s1, s2, s3, s4});     // 找出最低分

    std::cout << highest << '\n';
    std::cout << lowest << '\n';
    return 0;
}

运行结果如下。

96
78

分析:

std::max({s1, s2, s3, s4}) 表示直接从花括号里的 4 个分数中找出最高分 96,而 std::min({s1, s2, s3, s4}) 则找出了最低分 78,比多层嵌套调用直观得多。

2. 同时获取最小值和最大值

在上面的例子中,为了同时拿到最高分和最低分,我们分别调用了一次 std::max() 和一次 std::min()。如果希望在一次函数调用中同时拿到最小值和最大值,我们可以使用 std::minmax() 函数。

语法:

std::minmax(a, b)
std::minmax({值1, 值2, 值3, ...})

说明:

std::minmax() 既可以接收两个参数,也可以接收花括号列表来比较多个值。调用后,它会把找出来的最小值和最大值打包成一个 std::pair 对象返回,其中第 1 个成员 .first 固定是最小值,第 2 个成员 .second 固定是最大值。

示例 3:找出最低温与最高温

#include <algorithm>
#include <iostream>

int main() {
    auto res = std::minmax({18, 26, 12, 23});    // 同时获取最小值和最大值

    std::cout << "最低温:" << res.first << '\n';
    std::cout << "最高温:" << res.second << '\n';
    return 0;
}

运行结果如下。

最低温:12
最高温:26

分析:

在这个例子中,std::minmax({18, 26, 12, 23}) 返回了一个 std::pair 对象 res。小伙伴们可以顺着函数名 minmax 中 “先 min 后 max” 的顺序来记:第 1 个成员 res.first 是最小值 12,第 2 个成员 res.second 是最大值 26。

提示 std::max() 和 std::min() 适合比较已知的几个变量。如果想在一个存放了大量元素的数组或 std::vector 容器中查找最值,我们可以调用 STL 算法中的 std::max_element() 和 std::min_element() 函数来实现。

比较不同类型的数值

初学者在使用 std::max() 和 std::min() 时,经常会遇到这样一个编译报错:明明传进去的是 int 整数 10 和 double 小数 12.5,直接写 std::max(10, 12.5) 时编译器却提示找不到匹配的函数。

这是因为 std::max() 和 std::min() 底层是通过函数模板实现的,要求传入的两个参数类型必须一致。如果一个是 int、另一个是 double,编译器就无法确定应该按哪种类型来推导返回值。

遇到这种情况时,我们只需要在函数名后面加上 <double> 显式指定比较类型,写成 std::max<double>(a, b) 即可。请看下面例子。

示例 4:比较不同类型的数值

#include <algorithm>
#include <iostream>

int main() {
    int a = 10;
    double b = 12.5;

    double res = std::max<double>(a, b);    // 统一按 double 类型比较
    std::cout << res << '\n';
    return 0;
}

运行结果如下。

12.5

分析:

std::max<double>(a, b) 在函数名后面显式加上了 <double>,告诉编译器统一按 double 类型来比较。这样编译器会先把 int 类型的 a 转为 double,再与 b 比较并算出较大值 12.5。

下面这种不指定类型的写法就是错误的,由于两个参数的类型不一致,编译时会直接报错。

double wrongVal = std::max(a, b);    // 参数类型不一致

平时除了 int 与 double 比较之外,拿普通 int 变量与容器 .size() 返回的 size_t 比较大小时,同样会遇到类型不匹配的问题。遇到这种情况,大家显式加上 <size_t> 或 <int> 指定类型就能解决。

上一篇:

下一篇:

给站长反馈

绿叶网正在不断完善中,小伙伴们如果发现任何问题,还望多多给站长反馈,谢谢!

邮箱:lvyenet@vip.qq.com

「绿叶网」服务号
绿叶网服务号放大
关注服务号,微信也能看教程。
绿叶网服务号