C++ MinMax Algorithms: std::min, max, minmax_element & clamp
이 글의 핵심
Use std::min, max, minmax, min_element, max_element, minmax_element, and C++17 std::clamp — two-value vs range APIs, iterators, and performance notes.
What are MinMax algorithms?
They find minimum and maximum values: overloads for two or more values, and range algorithms returning iterators. Why use them?
- Concise code vs manual branches
- Type-safe comparisons
- Range algorithms for position and min/max in one pass
Overview | API | Input | Returns | Time | |-----|--------|---------|------| |min(a,b)/max| 2 values | reference | O(1) | |minmax(a,b)| 2 values | pair | O(1) | |min_element/max_element| range | iterator | O(n) | |minmax_element| range | pair of iterators | O(n) | |clamp(v, lo, hi)| value + bounds | clamped value | O(1) |
std::min and std::max
Basic usage
#include <algorithm>
int a = 10, b = 20;
int smaller = std::min(a, b); // 10
int larger = std::max(a, b); // 20
// With initializer list (C++11)
int minimum = std::min({5, 2, 8, 1, 9}); // 1
int maximum = std::max({5, 2, 8, 1, 9}); // 9
Custom comparator
struct Person {
std::string name;
int age;
};
Person p1{"Alice", 30};
Person p2{"Bob", 25};
// Compare by age
auto younger = std::min(p1, p2, [](const Person& a, const Person& b) {
return a.age < b.age;
});
// younger is Bob (25)
std::minmax
Returns both min and max in one call:
#include <algorithm>
int a = 10, b = 20;
auto [minimum, maximum] = std::minmax(a, b); // C++17 structured binding
// minimum = 10, maximum = 20
// With initializer list
auto [min_val, max_val] = std::minmax({5, 2, 8, 1, 9});
// min_val = 1, max_val = 9
min_element and max_element
Return iterators to the first occurrence of min/max:
#include <algorithm>
#include <vector>
std::vector<int> numbers = {3, 1, 4, 1, 5};
auto min_it = std::min_element(numbers.begin(), numbers.end());
auto max_it = std::max_element(numbers.begin(), numbers.end());
std::cout << "Min: " << *min_it << " at index "
<< std::distance(numbers.begin(), min_it) << "\n"; // Min: 1 at index 1
std::cout << "Max: " << *max_it << " at index "
<< std::distance(numbers.begin(), max_it) << "\n"; // Max: 5 at index 4
Finding both in one pass
auto [min_it, max_it] = std::minmax_element(numbers.begin(), numbers.end());
// More efficient than two separate scans
std::clamp (C++17)
Bounds a value to [lo, hi]:
#include <algorithm>
int value = 150;
int clamped = std::clamp(value, 0, 100); // 100
// Equivalent to:
// std::min(std::max(value, 0), 100);
// Use cases
int health = std::clamp(damage, 0, maxHealth);
float volume = std::clamp(userInput, 0.0f, 1.0f);
Requires: lo <= hi, otherwise undefined behavior.
Real-world applications
1. Statistics calculation
#include <algorithm>
#include <vector>
#include <numeric>
struct Stats {
double min, max, mean, range;
};
Stats calculateStats(const std::vector<double>& data) {
if (data.empty()) {
return {0, 0, 0, 0};
}
auto [min_it, max_it] = std::minmax_element(data.begin(), data.end());
double min_val = *min_it;
double max_val = *max_it;
double sum = std::accumulate(data.begin(), data.end(), 0.0);
double mean = sum / data.size();
return {min_val, max_val, mean, max_val - min_val};
}
// Usage
std::vector<double> temps = {22.5, 18.3, 25.1, 20.0, 23.7};
auto stats = calculateStats(temps);
std::cout << "Range: " << stats.min << " - " << stats.max << "\n";
2. Image processing: normalize pixel values
#include <algorithm>
#include <vector>
void normalizeImage(std::vector<uint8_t>& pixels) {
if (pixels.empty()) return;
auto [min_it, max_it] = std::minmax_element(pixels.begin(), pixels.end());
uint8_t min_val = *min_it;
uint8_t max_val = *max_it;
if (min_val == max_val) return; // Avoid division by zero
for (auto& pixel : pixels) {
pixel = static_cast<uint8_t>(
255.0 * (pixel - min_val) / (max_val - min_val)
);
}
}
3. Game development: clamp player position
struct Player {
float x, y;
float speed = 5.0f;
void update(float dx, float dy, float worldWidth, float worldHeight) {
x += dx * speed;
y += dy * speed;
// Keep player in bounds
x = std::clamp(x, 0.0f, worldWidth);
y = std::clamp(y, 0.0f, worldHeight);
}
};
4. Audio processing: clip samples
#include <algorithm>
#include <vector>
void clipAudio(std::vector<float>& samples, float threshold = 1.0f) {
for (auto& sample : samples) {
sample = std::clamp(sample, -threshold, threshold);
}
}
// Usage
std::vector<float> audio = {0.5f, 1.5f, -2.0f, 0.8f};
clipAudio(audio);
// Result: {0.5f, 1.0f, -1.0f, 0.8f}
Performance comparison
Benchmark (GCC 13, -O3, 1M element vector):
| Operation | Time (μs) | Comparisons |
|---|---|---|
std::min(a, b) | 0.5 | 1 |
std::min_element | 850 | 1M |
std::max_element | 850 | 1M |
std::minmax_element | 1100 | 1.5M |
| Two separate scans | 1700 | 2M |
std::clamp | 0.8 | 2 |
Key insight: minmax_element is 35% faster than two separate scans. |
Common pitfalls
Pitfall 1: Dangling reference from min/max
// ❌ Dangling reference
const int& result = std::min(10, 20); // Temporaries destroyed
std::cout << result; // Undefined behavior
// ✅ Copy the value
int result = std::min(10, 20);
Pitfall 2: Empty range
std::vector<int> empty;
// ❌ Undefined behavior
auto min_it = std::min_element(empty.begin(), empty.end());
std::cout << *min_it; // Crash!
// ✅ Check first
if (!empty.empty()) {
auto min_it = std::min_element(empty.begin(), empty.end());
std::cout << *min_it;
}
Pitfall 3: Wrong clamp bounds
int value = 50;
// ❌ Undefined behavior: lo > hi
int result = std::clamp(value, 100, 0);
// ✅ Correct: lo <= hi
int result = std::clamp(value, 0, 100);
Pitfall 4: Modifying during min_element
std::vector<int> data = {3, 1, 4, 1, 5};
// ❌ Iterator invalidation
auto min_it = std::min_element(data.begin(), data.end());
data.push_back(0); // Invalidates min_it!
std::cout << *min_it; // Undefined behavior
// ✅ Use value or recompute
int min_val = *std::min_element(data.begin(), data.end());
data.push_back(0);
std::cout << min_val; // Safe
Parallel execution (C++17)
#include <algorithm>
#include <execution>
#include <vector>
std::vector<int> data(10'000'000);
// ... fill data ...
// Sequential
auto min_it = std::min_element(data.begin(), data.end());
// Parallel
auto min_it_par = std::min_element(std::execution::par,
data.begin(), data.end());
Benchmark (10M elements):
- Sequential: 28ms
- Parallel: 9ms (on 8-core CPU)
Summary
| Algorithm | Mutates | Returns | Time |
|---|---|---|---|
min(a,b) | No | const reference | O(1) |
max(a,b) | No | const reference | O(1) |
minmax(a,b) | No | pair of references | O(1) |
min_element | No | iterator | O(n) |
max_element | No | iterator | O(n) |
minmax_element | No | pair of iterators | O(n) |
clamp(v,lo,hi) | No | clamped value | O(1) |
Related posts
Keywords
std::min, std::max, minmax_element, clamp, min_element, max_element, STL, C++, algorithm, statistics, bounds checking
자주 묻는 질문 (FAQ)
Q. 이 내용을 실무에서 언제 쓰나요?
A. Use std::min, max, minmax, min_element, max_element, minmax_element, and C++17 std::clamp — two-value vs range APIs, ite… 실무에서는 위 본문의 예제와 선택 가이드를 참고해 적용하면 됩니다.
Q. 선행으로 읽으면 좋은 글은?
A. 각 글 하단의 이전 글 또는 관련 글 링크를 따라가면 순서대로 배울 수 있습니다. C++ 시리즈 목차에서 전체 흐름을 확인할 수 있습니다.
Q. 더 깊이 공부하려면?
A. cppreference와 해당 라이브러리 공식 문서를 참고하세요. 글 말미의 참고 자료 링크도 활용하면 좋습니다.
같이 보면 좋은 글 (내부 링크)
이 주제와 연결되는 다른 글입니다.
- C++ Algorithm Sort | ‘정렬 알고리즘’ 가이드
- C++ 알고리즘 | ‘STL algorithm’ 핵심 정리
- C++ Algorithm Search | ‘검색 알고리즘’ 가이드
이 글에서 다루는 키워드 (관련 검색어)
C++, Algorithm, min, max, STL 등으로 검색하시면 이 글이 도움이 됩니다.