SovranCode
Modern C++ Lesson 34
Course contents50 available · 0 planned

Get a program running

01 · C++ Introduction: What Is C++?02 · How to Install a C++ Compiler and Set Up Your Editor03 · C++ Hello World: Your First Program Explained04 · How to Compile and Run C++ Programs05 · C++ Debugging: Warnings and Breakpoints

Work with values and input

06 · C++ Variables: Initialization and Scope07 · C++ Data Types: int, double and Type Conversion08 · C++ const, constexpr and auto Explained09 · C++ Operators: Arithmetic, Comparison and Logic10 · C++ User Input: cin, getline and Validation

Control flow and functions

11 · C++ Conditions: if, else if and else12 · C++ Switch Statement: Cases, break and default13 · C++ For Loop: Syntax and Examples14 · C++ While and Do-While Loops: Examples15 · C++ Functions: Parameters and Return Values

Strings and sequences

16 · C++ Strings: std::string with Examples17 · C++ Vector: std::vector with Examples18 · C++ Arrays: std::array and Bounds Checking19 · C++ Range-Based For Loop and Iterators20 · C++ Vector Practice: Build a Data Summary

Model data with classes

21 · C++ Structs and enum class Explained22 · C++ Classes and Objects: Encapsulation23 · C++ Constructors and Member Initialization24 · C++ Const Member Functions and Composition25 · C++ Copying Objects and the Rule of Zero

Lifetime and resource ownership

26 · C++ Object Lifetime, Destructors and RAII27 · C++ Pointers and References: nullptr and Borrowing28 · C++ unique_ptr: Smart Pointers and Ownership29 · C++ Move Semantics: std::move vs Copying30 · C++ string_view and span: Avoid Dangling Views

Containers and algorithms

31 · C++ map vs unordered_map: Lookup and Examples32 · C++ set, queue and stack: When to Use Each33 · C++ Lambda Expressions and STL Algorithms34 · C++ sort and binary_search: Rules and Complexity35 · C++20 Ranges: Views, filter and transform

Errors, files, and interfaces

36 · C++ optional and variant Explained37 · C++ Exceptions: try, catch and Safe Cleanup38 · C++ File Handling: Read and Write Text Files39 · C++ Input Parsing and Data Validation40 · C++ Polymorphism: Virtual Functions and Interfaces

Generic programming and quality

41 · C++ Templates: Function and Class Examples42 · C++20 Concepts and Template Constraints43 · C++ Unit Testing: Normal and Boundary Cases44 · C++ Sanitizers: Find Memory and Undefined Behavior Bugs45 · C++ Performance: Benchmark Before Optimizing

Build and deliver a complete application

46 · C++ Header Files and Translation Units47 · C++ CMake Tutorial: Build an Executable48 · C++ Dependencies and CTest: Automated Tests49 · C++ Multithreading: Threads and Data Races50 · C++ Command-Line Applications: Help and Release Checks
Modern C++50 available · 0 planned

Get a program running

01 · C++ Introduction: What Is C++?02 · How to Install a C++ Compiler and Set Up Your Editor03 · C++ Hello World: Your First Program Explained04 · How to Compile and Run C++ Programs05 · C++ Debugging: Warnings and Breakpoints

Work with values and input

06 · C++ Variables: Initialization and Scope07 · C++ Data Types: int, double and Type Conversion08 · C++ const, constexpr and auto Explained09 · C++ Operators: Arithmetic, Comparison and Logic10 · C++ User Input: cin, getline and Validation

Control flow and functions

11 · C++ Conditions: if, else if and else12 · C++ Switch Statement: Cases, break and default13 · C++ For Loop: Syntax and Examples14 · C++ While and Do-While Loops: Examples15 · C++ Functions: Parameters and Return Values

Strings and sequences

16 · C++ Strings: std::string with Examples17 · C++ Vector: std::vector with Examples18 · C++ Arrays: std::array and Bounds Checking19 · C++ Range-Based For Loop and Iterators20 · C++ Vector Practice: Build a Data Summary

Model data with classes

21 · C++ Structs and enum class Explained22 · C++ Classes and Objects: Encapsulation23 · C++ Constructors and Member Initialization24 · C++ Const Member Functions and Composition25 · C++ Copying Objects and the Rule of Zero

Lifetime and resource ownership

26 · C++ Object Lifetime, Destructors and RAII27 · C++ Pointers and References: nullptr and Borrowing28 · C++ unique_ptr: Smart Pointers and Ownership29 · C++ Move Semantics: std::move vs Copying30 · C++ string_view and span: Avoid Dangling Views

Containers and algorithms

31 · C++ map vs unordered_map: Lookup and Examples32 · C++ set, queue and stack: When to Use Each33 · C++ Lambda Expressions and STL Algorithms34 · C++ sort and binary_search: Rules and Complexity35 · C++20 Ranges: Views, filter and transform

Errors, files, and interfaces

36 · C++ optional and variant Explained37 · C++ Exceptions: try, catch and Safe Cleanup38 · C++ File Handling: Read and Write Text Files39 · C++ Input Parsing and Data Validation40 · C++ Polymorphism: Virtual Functions and Interfaces

Generic programming and quality

41 · C++ Templates: Function and Class Examples42 · C++20 Concepts and Template Constraints43 · C++ Unit Testing: Normal and Boundary Cases44 · C++ Sanitizers: Find Memory and Undefined Behavior Bugs45 · C++ Performance: Benchmark Before Optimizing

Build and deliver a complete application

46 · C++ Header Files and Translation Units47 · C++ CMake Tutorial: Build an Executable48 · C++ Dependencies and CTest: Automated Tests49 · C++ Multithreading: Threads and Data Races50 · C++ Command-Line Applications: Help and Release Checks
PREVIOUS LESSONC++ Lambda Expressions and STL Algorithms
NEXT LESSONC++20 Ranges: Views, filter and transform
C++ foundations · Lesson 34 About 46 min with practice

C++ sort and binary_search: Rules and Complexity

Learn C++ sort, binary_search and lower_bound with clear examples, safe missing-result checks, duplicate values and simple complexity explanations.

Before you begin

Know vectors, iterators, find and small lambdas. We start with ascending integers before sorting records by a field.

What you will learn

  • Sort a vector using the normal ascending order.
  • Explain why binary search needs a compatible ordered range.
  • Use lower_bound and check whether a match exists.
  • Write a strict comparison for a record field.
  • Compare one-off search with sorting before repeated searches.

Sorting puts values into a useful order

Imagine a list of page numbers: seven, two, five and two. A plain search can inspect them one by one. A sorted list puts the smaller numbers first, which can make later tasks easier. std::sort changes the order of elements in a range. For ordinary integers without a custom comparison, the result is ascending order. Repeated values remain present; sorting is not the same as removing duplicates.

In this lesson, begin and end describe the whole vector. The boundary end is not included. After sorting, our four values become two, two, five and seven. The vector still has four elements. If arrival order matters to another part of your program, make a copy and sort that copy instead. Do not silently replace meaningful input order just because sorted output looks neater on screen.

A comparison tells an algorithm which value should come before another. The default integer comparison is less-than. Later we use a small lambda to compare a field inside a record. Start with the plain integer version and write the expected order by hand. Understanding that small result matters more than memorizing a complicated comparison expression before you know what it is meant to promise.

The unsorted values seven, two, five and two become two, two, five and seven after sorting. Binary search then looks for five in the ordered range, preserving both copies of two.
The example sorts in ascending order before searching with the matching default order. Keep duplicate values, check range boundaries, and never treat an arbitrary unsorted range as valid binary-search input.
C++ PRACTICE RUNNER

Sort first, then ask whether a value exists

binary_search reports a bool. It does not return the matching element's iterator.

#include <algorithm>
#include <iostream>
#include <vector>
int main() {
    std::vector<int> values{7, 2, 5, 2};
    std::sort(values.begin(), values.end());
    std::cout << "Sorted:";
    for (int value : values) std::cout << ' ' << value;
    std::cout << '\n' << std::boolalpha;
    std::cout << "Has 5: " << std::binary_search(values.begin(), values.end(), 5) << '\n';
    std::cout << "Has 4: " << std::binary_search(values.begin(), values.end(), 4) << '\n';
}
TERMINAL OUTPUT
Predict the output, edit the source, then select Run code.

C++20 compiler runner: source and input are sent only when you press Run to this website's execution endpoint, not an external vendor. Local preview requires Docker and gcc:14; production requires a separately isolated execution service. Network is disabled; execution is limited to 3 seconds, compilation to 10 seconds, memory to 384 MB and output to 32 KB. Single-file programs only. Don't enter secrets. Edits reset on refresh; Copy your work to keep it.

Compare with the starter's expected output
Sorted: 2 2 5 7
Has 5: true
Has 4: false

After editing inputs, calculate a new prediction; this reference describes only the starter.

Why order matters to the search

A linear search such as find checks values until it finds a match or reaches the end. Binary search uses the order to narrow the possible area. If the middle value is below the target, an ascending range lets the search ignore the earlier part. Without the required ordering, that reasoning is not valid. We use a fully sorted range with the same comparison as a simple, sufficient rule for these examples.

Do not test binary_search on arbitrary unsorted data and memorize whatever result appears. Violating an algorithm's required range conditions is not a reliable way to learn its meaning. Repair the program before running it: either sort the range with the matching comparison, or use find when you do not want to change or copy the input. A result that happens to look right once does not establish the rule for other input.

The example first sorts, then asks about five and four. Five is present and four is missing. boolalpha makes the answers easy to read. Notice that binary_search does not tell you which of several equal values it found. If your next step needs an iterator, use a suitable algorithm such as lower_bound and check the result. Searching for presence and finding an insertion position are related but different questions.

  • Start with 7, 2, 5, 2.
  • sort changes the vector to 2, 2, 5, 7.
  • binary_search for 5 returns true.
  • binary_search for 4 returns false; no element is inserted.
C++ PRACTICE RUNNER

A lower bound is not always a match

The first element not less than four is five. Check equality as well as the end boundary.

#include <algorithm>
#include <iostream>
#include <vector>
int main() {
    const std::vector<int> values{2, 2, 5, 7};
    const int target{4};
    const auto position = std::lower_bound(values.begin(), values.end(), target);
    if (position != values.end() && *position == target)
        std::cout << "Found: " << *position << '\n';
    else std::cout << "Not found\n";
}
TERMINAL OUTPUT
Predict the output, edit the source, then select Run code.

C++20 compiler runner: source and input are sent only when you press Run to this website's execution endpoint, not an external vendor. Local preview requires Docker and gcc:14; production requires a separately isolated execution service. Network is disabled; execution is limited to 3 seconds, compilation to 10 seconds, memory to 384 MB and output to 32 KB. Single-file programs only. Don't enter secrets. Edits reset on refresh; Copy your work to keep it.

Compare with the starter's expected output
Not found

After editing inputs, calculate a new prediction; this reference describes only the starter.

Check both the boundary and the value

For an ascending integer range, lower_bound returns the first position whose value is not less than the target. That can be the target, a larger value, or end. In the example, four is absent, but five is the first value not less than four. Checking only that the iterator is not end would incorrectly report a match. The equality check answers the second question: is this actual value the one we requested?

The condition uses && so the equality test is reached only when the iterator is not end. This protects the dereference. Search for eight and the position is end; search for two and it is the first two. Duplicate values are allowed. The lab reports the first matching index, starting at zero. Explain the difference between an index and a one-based position before converting output for a human-facing interface.

An empty sorted vector is a valid search range. Its begin and end are equal, and lower_bound returns end without a matching element. There is no need to read front, back or index zero to handle that case. Keep the same checked condition for both empty and nonempty ranges. Good boundary handling often lets one small piece of code cover several cases without adding an unsafe special branch.

C++ PRACTICE RUNNER

Sort records by a clear field

Use <, not <=. This example gives every record a different priority, so no tie order is assumed.

#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
struct Task { std::string name; int priority; };
int main() {
    std::vector<Task> tasks{{"Write", 3}, {"Read", 1}, {"Build", 2}};
    std::sort(tasks.begin(), tasks.end(), [](const Task& a, const Task& b) {
        return a.priority < b.priority;
    });
    for (const auto& task : tasks) std::cout << task.name << '\n';
}
TERMINAL OUTPUT
Predict the output, edit the source, then select Run code.

C++20 compiler runner: source and input are sent only when you press Run to this website's execution endpoint, not an external vendor. Local preview requires Docker and gcc:14; production requires a separately isolated execution service. Network is disabled; execution is limited to 3 seconds, compilation to 10 seconds, memory to 384 MB and output to 32 KB. Single-file programs only. Don't enter secrets. Edits reset on refresh; Copy your work to keep it.

Compare with the starter's expected output
Read
Build
Write

After editing inputs, calculate a new prediction; this reference describes only the starter.

Keep the comparison strict and consistent

A sorting comparison must follow a consistent strict ordering. For this task, a.priority < b.priority says that a comes first only when its number is smaller. A value does not come before itself under this rule. Using <= would say that equal values come before each other, breaking the required rule. Do not run an invalid comparator to get an interesting demonstration; repair it before using the sorting algorithm.

std::sort does not promise to preserve the original order of equal-priority records. Use stable_sort when preserving that tie order is part of the requirement, or define another comparison field when a specific order is needed. For a large input, sort uses O(n log n) comparisons. On a vector, binary-search algorithms use logarithmic comparisons and efficient jumps. These names describe how work grows as the input grows, not exact timing on your computer.

Sorting has a cost and changes order. For one search in an unsorted sequence, a linear find can be the simpler plan. For many searches against mostly unchanged data, sorting once may be useful. Do not call sort again before every query without thinking about that cost. This lesson's lab deliberately sorts once and searches once to teach the contract; it does not claim that this is the fastest plan for one small request.

Report the sorted values and first matching index

Read a count from zero through eight, that many integer values in minus one hundred through one hundred, and one target in the same range. Use complete lines and validate before reporting. Sort the vector once. Print Sorted and its values, then use lower_bound to print Index with the first matching zero-based index, or Not found when the checked position is not an equal value.

Test duplicates, a target smaller than every value, a target between values, and a target larger than every value. Include empty data and a one-element match. Bad syntax, a missing target and an out-of-range required number must print Invalid input with status one. Keep duplicates in the sorted row. The goal is a correct, explainable search, not a surprising transcript from an algorithm used outside its rules.

LOCAL TERMINAL COMMANDS

Run the same program on your computer

Save one complete example as main.cpp. Choose your installed compiler and run only after a successful build. These are terminal commands, not C++ source. The in-page Run button needs the configured compiler sandbox.

macOS / Linux:
clang++ -std=c++20 -Wall -Wextra -Wpedantic main.cpp -o lesson
# Or use g++ with the same options.
./lesson

Windows Developer Command Prompt:
cl /std:c++20 /EHsc /W4 main.cpp /Fe:lesson.exe
lesson.exe
APPLY THE CONCEPT

Independent lab

Sort a bounded sequence and find the first matching zero-based index safely.

Acceptance checklist

  • Read count 0..8, that many values -100..100, then a target -100..100 on whole lines.
  • Reject invalid required input as Invalid input with status 1 before reporting.
  • Sort once in ascending order and print every value, including duplicates.
  • Use lower_bound with both end and equality checks.
  • Print the first matching Index or Not found; handle an empty range without indexing it.
Need a hint?
  1. Use the default ordering for both sort and lower_bound.
  2. A position before end can still point to a value larger than the target.
  3. Subtract begin from a checked vector iterator to obtain the zero-based index.
C++ PRACTICE RUNNER

Write and run your lab

Build your own solution before revealing the reference. Use the input field for normal, boundary and invalid cases; this runner executes your program but does not grade it.

#include <iostream>
#include <string>
#include <sstream>
#include <limits>

int main() {
    // Implement the acceptance checklist above.
    return 0;
}

TERMINAL OUTPUT
Predict the output, edit the source, then select Run code.

C++20 compiler runner: source and input are sent only when you press Run to this website's execution endpoint, not an external vendor. Local preview requires Docker and gcc:14; production requires a separately isolated execution service. Network is disabled; execution is limited to 3 seconds, compilation to 10 seconds, memory to 384 MB and output to 32 KB. Single-file programs only. Don't enter secrets. Edits reset on refresh; Copy your work to keep it.

Your lab evidence and notes

Record predictions, actual output, commands and the cause of each repair. Code is plain text: this scratchpad does not execute or grade C++.

Loading local notes…

Review your acceptance checklist and quiz explanations before marking this lesson complete. This is self-review, not a grade or certification.

Reveal the explained lab solution
C++ PRACTICE RUNNER

Reference lab solution

Compare the reference with your own reasoning. Running this solution does not grade or complete the lesson.

#include <iostream>
#include <sstream>
#include <string>
bool readInteger(int& value) {
    std::string line;
    if (!std::getline(std::cin, line)) return false;
    std::istringstream parser{line};
    if (!(parser >> value)) return false;
    parser >> std::ws;
    return parser.eof();
}
#include <algorithm>
#include <vector>
int main() {
    int count{};
    if (!readInteger(count) || count < 0 || count > 8) {
        std::cout << "Invalid input\n"; return 1;
    }
    std::vector<int> values;
    for (int i = 0; i < count; ++i) {
        int value{};
        if (!readInteger(value) || value < -100 || value > 100) {
            std::cout << "Invalid input\n"; return 1;
        }
        values.push_back(value);
    }
    int target{};
    if (!readInteger(target) || target < -100 || target > 100) {
        std::cout << "Invalid input\n"; return 1;
    }
    std::sort(values.begin(), values.end());
    std::cout << "Sorted:";
    for (int value : values) std::cout << ' ' << value;
    std::cout << '\n';
    const auto position = std::lower_bound(values.begin(), values.end(), target);
    if (position != values.end() && *position == target)
        std::cout << "Index: " << position - values.begin() << '\n';
    else std::cout << "Not found\n";
}
TERMINAL OUTPUT
Predict the output, edit the source, then select Run code.

C++20 compiler runner: source and input are sent only when you press Run to this website's execution endpoint, not an external vendor. Local preview requires Docker and gcc:14; production requires a separately isolated execution service. Network is disabled; execution is limited to 3 seconds, compilation to 10 seconds, memory to 384 MB and output to 32 KB. Single-file programs only. Don't enter secrets. Edits reset on refresh; Copy your work to keep it.

Expected output

Sorted: 2 2 5 7
Index: 0

All required input is validated before sort or output, so a bad target cannot produce a partial success report.

The sorted range satisfies the ascending lower_bound rule. Repeated targets are located at their first matching position.

The end check happens before dereferencing. Equality prevents an insertion position for a missing value from being mistaken for a match.

Review before moving on

Explain the lesson's objectives in your own words, compare your lab evidence with the acceptance checklist, and keep the first failing case alongside your repair. Completing a page is not proof that every C++ feature or input is supported.

  • Sort a vector using the normal ascending order.
  • Explain why binary search needs a compatible ordered range.
  • Use lower_bound and check whether a match exists.
  • Write a strict comparison for a record field.
  • Compare one-off search with sorting before repeated searches.

References and further reading

Original examples and exercises accompany these primary references. Tool-specific diagnostics and support depend on your installed version.

  • C++ draft: sorting requirements
  • C++ draft: lower_bound
  • C++ draft: binary search
KNOWLEDGE CHECK

Check your understanding

Answer all five questions, then review the explanations. Answers are not saved or synced; completion is a separate self-review choice.

01What happens to duplicates when sort runs?
02What is a safe simple rule before binary_search here?
03lower_bound for 4 points to 5. Is 4 present?
04Which priority comparison is appropriate here?
05Does std::sort preserve the input order of equal keys?
PREVIOUS LESSONC++ Lambda Expressions and STL Algorithms
NEXT LESSONC++20 Ranges: Views, filter and transform
ON THIS PAGELearning objectivesSorting puts values into a useful orderWhy order matters to the searchCheck both the boundary and the valueKeep the comparison strict and consistentReport the sorted values and first matching indexIndependent labReviewKnowledge checkReferences
Course overview