← Back to list

C++: полное руководство по бинарной сортировке

При бинарной сортировке, или сортировке с бинарными вставками, корректная позиция каждого элемента определяется двоичным поиском. Поэтому…

Андрей Шагин in NOP::Nuances of Programming · 2026-01-29 16:01 · 7 claps · 3.8 min read
#nuances-of-programming #c-plus-plus-language #cplusplus #binary-search #sorting-algorithms
Open on Medium ↗
Wiki topics: 💻 · Programming

C++: полное руководство по бинарной сортировке

При бинарной сортировке, или сортировке с бинарными вставками, корректная позиция каждого элемента определяется двоичным поиском. Поэтому на больших наборах данных такая сортировка эффективнее обычной сортировки вставками. Изучим ее реализацию и эффективное использование.

Базовая реализация

Вот простая реализация бинарной сортировки:

#include <vector>

template<typename T>
int binary_search(std::vector<T>& arr, int target, int low, int high) {
    while (low <= high) {
        int mid = low + (high - low) / 2;

        if (arr[mid] == target) {
            return mid;
        }
        if (arr[mid] < target) {
            low = mid + 1;
        } else {
            high = mid - 1;
        }
    }
    return low;
}

template<typename T>
void binary_sort(std::vector<T>& arr) {
    for (int i = 1; i < arr.size(); ++i) {
        T key = arr[i];
        int j = i - 1;

        // Место для вставки находится двоичным поиском
        int loc = binary_search(arr, key, 0, j);

        // Чтобы освободить место, элементы перемещаются
        while (j >= loc) {
            arr[j + 1] = arr[j];
            j--;
        }

        arr[j + 1] = key;
    }
}

Реальный пример: система учета учащихся

Вот практическое применение бинарной сортировки:

struct Student {
    std::string name;
    int id;
    float gpa;

    bool operator<(const Student& other) const {
        return id < other.id;
    }

    bool operator==(const Student& other) const {
        return id == other.id;
    }
};

class StudentDatabase {
private:
    std::vector<Student> students;

public:
    void add_student(const Student& student) {
        students.push_back(student);
        binary_sort(students);
    }

    Student* find_student(int id) {
        Student target{.id = id};
        int loc = binary_search(students, target, 0, students.size() - 1);

        if (loc < students.size() && students[loc].id == id) {
            return &students[loc];
        }
        return nullptr;
    }

    void print_sorted_students() const {
        for (const auto& student : students) {
            std::cout << "ID: " << student.id 
                      << ", Name: " << student.name 
                      << ", GPA: " << student.gpa << '\n';
        }
    }
};

// Пример использования
void manage_students() {
    StudentDatabase db;

    db.add_student({"Alice", 103, 3.8f});
    db.add_student({"Bob", 101, 3.5f});
    db.add_student({"Charlie", 102, 3.9f});

    db.print_sorted_students();
}

Оптимизированная бинарная сортировка для пользовательских объектов

Вот оптимизированная версия, здесь меньше перемещений в памяти:

template<typename T, typename Compare = std::less<T>>
class BinarySorter {
private:
    static int find_position(const std::vector<T>& arr, const T& target, 
                           int start, int end, Compare comp = Compare()) {
        while (start <= end) {
            int mid = start + (end - start) / 2;

            if (comp(arr[mid], target)) {
                start = mid + 1;
            } else if (comp(target, arr[mid])) {
                end = mid - 1;
            } else {
                return mid;
            }
        }
        return start;
    }

public:
    static void sort(std::vector<T>& arr, Compare comp = Compare()) {
        if (arr.size() <= 1) return;

        for (int i = 1; i < arr.size(); ++i) {
            T current = std::move(arr[i]);
            int pos = find_position(arr, current, 0, i - 1, comp);

            // Производительность повышается операциями перемещения
            for (int j = i; j > pos; --j) {
                arr[j] = std::move(arr[j - 1]);
            }
            arr[pos] = std::move(current);
        }
    }
};

// Пример с пользовательским компаратором
struct TimeStamp {
    int hour, minute, second;

    bool operator<(const TimeStamp& other) const {
        if (hour != other.hour) return hour < other.hour;
        if (minute != other.minute) return minute < other.minute;
        return second < other.second;
    }
};

void sort_timestamps() {
    std::vector<TimeStamp> times = {
        {14, 30, 0},
        {9, 15, 30},
        {14, 15, 45}
    };

    BinarySorter<TimeStamp>::sort(times);

    for (const auto& time : times) {
        std::cout << time.hour << ":" 
                  << time.minute << ":" 
                  << time.second << '\n';
    }
}

Реальное применение: обработка записей журнала

Вот как эффективно бинарная сортировка справляется с записями журнала:

class LogEntry {
public:
    std::chrono::system_clock::time_point timestamp;
    std::string message;
    int priority;

    bool operator<(const LogEntry& other) const {
        return timestamp < other.timestamp;
    }
};

class LogProcessor {
private:
    std::vector<LogEntry> log_entries;
    static constexpr size_t BATCH_SIZE = 1000;

public:
    void add_entry(const LogEntry& entry) {
        log_entries.push_back(entry);

        // Чтобы избежать постоянных пересортировок, выполняется пакетная сортировка
        if (log_entries.size() % BATCH_SIZE == 0) {
            process_batch();
        }
    }

    void process_batch() {
        binary_sort(log_entries);

        // Обрабатываются сортированные записи
        auto now = std::chrono::system_clock::now();
        auto one_hour_ago = now - std::chrono::hours(1);

        // Удаляются записи старше одного часа
        auto it = std::find_if(log_entries.begin(), log_entries.end(),
            [&](const LogEntry& entry) {
                return entry.timestamp >= one_hour_ago;
            });

        log_entries.erase(log_entries.begin(), it);
    }

    void print_recent_logs(int count = 10) const {
        int n = std::min(count, static_cast<int>(log_entries.size()));
        for (int i = log_entries.size() - n; i < log_entries.size(); ++i) {
            auto time_t = std::chrono::system_clock::to_time_t(
                log_entries[i].timestamp);
            std::cout << std::ctime(&time_t) << " - "
                     << log_entries[i].message << '\n';
        }
    }
};

Сравнение производительности

Вот тест производительности для сравнения бинарной сортировки с другими алгоритмами сортировки:

class SortBenchmark {
private:
    template<typename Func>
    static double measure_time(Func&& f) {
        auto start = std::chrono::high_resolution_clock::now();
        f();
        auto end = std::chrono::high_resolution_clock::now();

        return std::chrono::duration<double>(end - start).count();
    }

public:
    static void run_benchmark(int size) {
        std::vector<int> data(size);
        std::random_device rd;
        std::mt19937 gen(rd());
        std::uniform_int_distribution<> dis(1, 10000);

        // Генерируются случайные данные
        for (int& x : data) {
            x = dis(gen);
        }

        // Тестируется бинарная сортировка
        auto binary_time = measure_time([&] {
            auto binary_data = data;
            binary_sort(binary_data);
        });

        // Тестируется «std::sort»
        auto std_time = measure_time([&] {
            auto std_data = data;
            std::sort(std_data.begin(), std_data.end());
        });

        std::cout << "Array size: " << size << '\n'
                  << "Binary sort time: " << binary_time << "s\n"
                  << "std::sort time: " << std_time << "s\n";
    }
};

// Выполняются тесты производительности
void compare_sorts() {
    for (int size : {100, 1000, 10000}) {
        SortBenchmark::run_benchmark(size);
        std::cout << "-------------------\n";
    }
}

При выборе бинарной сортировки учитывайте, что она:

  1. Хороша для почти отсортированных данных.
  2. Эффективна для наборов данных малого и среднего размеров.
  3. Ею поддерживается стабильность: относительный порядок эквивалентных элементов сохраняется.
  4. На больших случайных наборах данных выполняется оптимальнее сортировки вставками, но хуже быстрой сортировки.

Не забывайте: хотя при бинарной сортировке меньше сравнений, чем при обычной сортировке вставками, в худшем случае ей по-прежнему требуется O(n²) перемещений. Для очень больших наборов данных воспользуйтесь std::sort или другими алгоритмами, такими как быстрая сортировка.

Читайте также:

Читайте нас в Telegram, VK и Дзен

Перевод статьи ryan: Binary Sort in C++: Complete Guide


메타데이터
post_id
d60c81774fc0
slug
c-полное-руководство-по-бинарной-сортировке-d60c81774fc0
url
https://medium.com/nuances-of-programming/c-%D0%BF%D0%BE%D0%BB%D0%BD%D0%BE%D0%B5-%D1%80%D1%83%D0%BA%D0%BE%D0%B2%D0%BE%D0%B4%D1%81%D1%82%D0%B2%D0%BE-%D0%BF%D0%BE-%D0%B1%D0%B8%D0%BD%D0%B0%D1%80%D0%BD%D0%BE%D0%B9-%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B5-d60c81774fc0
canonical_url
https://medium.com/nuances-of-programming/c-%D0%BF%D0%BE%D0%BB%D0%BD%D0%BE%D0%B5-%D1%80%D1%83%D0%BA%D0%BE%D0%B2%D0%BE%D0%B4%D1%81%D1%82%D0%B2%D0%BE-%D0%BF%D0%BE-%D0%B1%D0%B8%D0%BD%D0%B0%D1%80%D0%BD%D0%BE%D0%B9-%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B5-d60c81774fc0
author_url
https://medium.com/@helplearningrussian.overandout
status
ok
fetched_at
2026-09-04 19:23:03