class Algorithms {
public:
Algorithms lecture {
.author = "Р.А. Нестеров"
.year = "2026/27"
.course = "НИУ ВШЭ ПИ, 2 курс"
};
// 01. Сортировка подсчетом
void bucket_sort(std::vector<int>& vec);
void counting_sort(std::vector<int>& vec);
// 02. LSB-поразрядная сортировка и варианты ее реализации
void radix_sort(std::vector<int>& vec);
// 03. Домашняя работа set_3: применение библиотеки Google Benchmark
// для многостороннего бенчмаркинга алгоритмов
void fetch_new_tasks();
->07
07.00
алгоритмы сортировки на основе сравнений
[cb-сортировки]
классификация алгоритмов сортировки
void comparisons_lower_bound();
явная оценка высоты дерева решений cb-сортировки
void classify_sorting_algorithms();
ключевые параметры сравнения алгоритмов
void classify_sorting_algorithms();
ключевые параметры сравнения алгоритмов
void classify_sorting_algorithms();
ключевые параметры сравнения алгоритмов
#include <vector>
void insertion_sort(std::vector<int>& arr) {
int n = arr.size();
for (int i = 1; i < n; ++i) {
int key = arr[i];
int j = i - 1;
while (j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j];
j = j - 1;
}
arr[j + 1] = key;
}
}
#include <vector>
#include <algorithm>
#include <iterator>
template<typename Iter>
void quick_sort(Iter first, Iter last) {
if (std::distance(first, last) <= 1) return;
auto pivot_pos = partition(first, last);
quick_sort(first, pivot_pos);
quick_sort(std::next(pivot_pos), last);
}
| Алгоритм | Аналог в STL | IN-PLACE? | stable? | Худший случай | Примечание |
|---|---|---|---|---|---|
| selection_sort | — | ✅ | ❌ | $\mathrm{O}(n^2)$ | — |
| insertion_sort | — | ✅ | ✅ | $\mathrm{O}(n^2)$ | полезно для небольших массивов и тех, что уже упорядочены |
| shell_sort | — | ✅ | ❌ | $\mathrm{O}(n^{1.5})$ | — |
| merge_sort | std::stable_sort | ❌ | ✅ | $\mathrm{O}(n \log n)$ | устойчивый алгоритм с гарантированной сложностью |
| quick_sort | std::sort | ✅ | ❌ | $\mathrm{O}(n^2)$ | вероятностная гарантия оптимальной сложности |
| heap_sort | std::make_heap std::sort_heap | ✅ | ❌ | $\mathrm{O}(n \log n)$ | НЕустойчивый алгоритм с гарантированной сложностью |
*std::nth_element для поиска порядковой статистики
*std::partial_sort для выборки заданного числа наименьших элементов массива [in-place]
void classify_sorting_algorithms();
ключевые параметры сравнения алгоритмов
07.01
базовая схема алгоритма bucket_sort
для сортировки массива уникальных объектов
алгоритм counting_sort
для сортировки
массива объектов с повторениями
void bucket_sort(std::vector<int>& arr);
массив уникальных чисел в известном диапазоне
void bucket_sort(std::vector<int>& arr);
массив уникальных чисел в известном диапазоне
сложность $\Theta(n+m)$ — псевдолинейная
void bucket_sort(std::vector<int>& arr);
массив уникальных чисел в известном диапазоне
сложность $\Theta(n+m)$ — псевдолинейная
* клик по ответу покажет, верный ли он
07.02
поразрядная сортировка на основе массива очередей
экономичная [по памяти] поразрядная сортировка двоичных чисел: «двусторонний» массив
void radix_sort(std::vector<int>& arr);
массив чисел / строк в известном алфавите
void radix_sort(std::vector<int>& arr);
массив чисел / строк в известном алфавите
сложность $\mathrm{O}(\ell \cdot (n + B))$ — псевдолинейная
void radix_sort(std::vector<int>& arr);
двусторонний массив c «двойной буферизацией»
шаг 1 создаем дополнительный массив для хранения очередей
void radix_sort(std::vector<int>& arr);
двусторонний массив c «двойной буферизацией»
шаг 2 сортируем числа по третьему биту
void radix_sort(std::vector<int>& arr);
двусторонний массив c «двойной буферизацией»
шаг 2 сортируем числа по третьему биту
void radix_sort(std::vector<int>& arr);
двусторонний массив c «двойной буферизацией»
шаг 2 сортируем числа по третьему биту
void radix_sort(std::vector<int>& arr);
двусторонний массив c «двойной буферизацией»
шаг 3 очищаем исходный массив и сортируем по второму биту
void radix_sort(std::vector<int>& arr);
двусторонний массив c «двойной буферизацией»
шаг 3 очищаем исходный массив и сортируем по второму биту
void radix_sort(std::vector<int>& arr);
двусторонний массив c «двойной буферизацией»
шаг 3 очищаем исходный массив и сортируем по второму биту
void radix_sort(std::vector<int>& arr);
двусторонний массив c «двойной буферизацией»
шаг 3 очищаем исходный массив и сортируем по второму биту
void radix_sort(std::vector<int>& arr);
двусторонний массив c «двойной буферизацией»
шаг 4 очищаем дополнительный массив и сортируем по старшему биту
void radix_sort(std::vector<int>& arr);
двусторонний массив c «двойной буферизацией»
шаг 4 очищаем дополнительный массив и сортируем по старшему биту
void radix_sort(std::vector<int>& arr);
двусторонний массив c «двойной буферизацией»
шаг 5 очищаем исходный массив
void radix_sort(std::vector<int>& arr);
двусторонний массив c «двойной буферизацией»
шаг 6 копируем первую половину
void radix_sort(std::vector<int>& arr);
двусторонний массив c «двойной буферизацией»
шаг 7 копируем развернутую вторую половину
void radix_sort(std::vector<int>& arr);
двусторонний массив c «двойной буферизацией»
шаг 8 сортировка завершена
* клик по ответу покажет, верный ли он
07.03
задачи на сортировки и стохастические алгоритмы
часть k: бенчмаркинг алгоритмов с помощью
библиотеки Google Benchmark
void fetch_new_tasks();
сортировки · стохастические алгоритмы · бенчмаркинг и экспериментальный анализ
| ID | Баллы | Комментарий |
|---|---|---|
| p1_heap CORE | 5 | реализация пирамидальной сортировки |
| p2_counting CORE | 6 | реализация сортировки подсчетом |
| p3_radix256 CORE | 6 | реализация поразрядной сортировки с заданным основанием |
| p4_fractions CORE | 5 | применение библиотечной сортировки |
| p5_freivalds CORE | 7 | случайный алгоритм проверки матричного умножения |
| p6_queens CORE | 7 | случайный алгоритм расстановки ферзей на шахматной доске |
| k1_mersertion CORE | 10 + 10 | бенчмаркинг гибридной сортировки с помощью Google Benchmark |
| k2_3circles CORE | 7 + 8 | исследование сходимости метода Монте-Карло |
#include <iostream>
#include <vector>
#include <numeric>
#include <algorithm>
#include <random>
#include <chrono>
constexpr size_t kN = 128;
void bubble_sort(std::vector<int>& arr) {
for (size_t i = 0; i < arr.size() - 1; ++i) {
for (size_t j = 0; j < arr.size() - i - 1; ++j) {
if (arr[j] > arr[j + 1]) std::swap(arr[j], arr[j + 1]);
}
}
}
int main() {
using clock = std::chrono::high_resolution_clock;
using nanos = std::chrono::nanoseconds;
std::vector<int> arr(kN);
std::iota(arr.begin(), arr.end(), 1);
std::mt19937 g(42);
std::shuffle(arr.begin(), arr.end(), g);
auto start = clock::now();
bubble_sort(arr);
auto end = clock::now();
auto dur = std::chrono::duration_cast<nanos>(end - start).count();
std::cout << "время сортировки: " << dur << " нс\n";
return 0;
}
#include <benchmark/benchmark.h>
#include <vector>
#include <algorithm>
void HybridSort(std::vector<int>& arr, size_t threshold) {
std::sort(arr.begin(), arr.end());
}
static void BM_Example(benchmark::State& state) {
// 1. Извлекаем параметры из сгенерированной сетки
const size_t kN = state.range(0);
const size_t kThreshold = state.range(1);
// Инициализация исходных данных
std::vector<int> source(kN, 42);
// 2. Основной измеряемый цикл фреймворка
for (auto _ : state) {
state.PauseTiming(); // Пауза таймера
std::vector<int> target = source;
state.ResumeTiming(); // Включаем таймер
HybridSort(target, kThreshold);
// Защита от оптимизаций компилятора
benchmark::DoNotOptimize(target.data());
benchmark::ClobberMemory();
}
}
// 3. Возможности задания диапазонов аргументов фреймворка:
// Вариант А: Простая линейная сетка параметров (DenseRange)
// Запустит бенчмарк для порогов: 4, 8, 12, 16
// BENCHMARK(BM_HybridSortExample)->DenseRange(4, 16, 4);
// Вариант Б: Двумерная матрица параметров (ArgsProduct)
// Протестирует комбинации ВСЕХ размеров N и ВСЕХ порогов
BENCHMARK(BM_Example)->ArgsProduct({
{128, 512},
benchmark::CreateDenseRange(4, 12, 4)
});
BENCHMARK_MAIN(); // Генерирует main() автоматически
// Лекция 07 завершена
// Резюме основных моментов
линейная сортировка
и вопросы ее применимости
LSB-поразрядная сортировка
и вопросы ее применимости / реализации
практические приемы проведения
экспериментального исследования производительности
--> на следующей лекции
--> бинарные деревья [поиска] — часть #1
--> обходы, итерация и основные операции
};
return 0;
07->