Compare commits
5 Commits
3d7acb1d63
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 352aed3ea8 | |||
| 5b6672cf4c | |||
| 0457fdd1ec | |||
| 7e2afe34e0 | |||
| eb9bd9db1a |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,3 +2,4 @@ build
|
|||||||
.cache
|
.cache
|
||||||
subprojects/*
|
subprojects/*
|
||||||
!subprojects/*.wrap
|
!subprojects/*.wrap
|
||||||
|
.tmp
|
||||||
|
|||||||
@@ -1,5 +1,12 @@
|
|||||||
Рабочий проект по изучению и анализу разнообразных алгоритмов.
|
Весь этот проект - это сборка, растянутая во времени и пространстве, реализаций и модернизаций разнообразных алгоритмов.
|
||||||
|
Папка tmp - разный мусор/заметки/фигзнает, который когда-то будет разобран.
|
||||||
|
Особником стоит папка tasks. Это сборище задачь, которые мне показались интересными или просто что-то, что может показать применение рассмотренных алгоритмов.
|
||||||
|
|
||||||
|
Для запуска всего того что хочется, нужно просто воспользоваться bin/main.cpp
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="./cover.gif" width="512" alt="cover">
|
<img src="./cover.gif" width="512" alt="cover">
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
src - основные примеры с задачами и разными реализациями
|
||||||
|
utils - алгоритмы, которые используются как вспомогательные на всем проекте
|
||||||
|
|||||||
13
bin/main.cpp
13
bin/main.cpp
@@ -1,18 +1,9 @@
|
|||||||
#include <hack/logger/logger.hpp>
|
#include <hack/logger/logger.hpp>
|
||||||
#include "tasks/001.hpp"
|
#include "tasks/001.hpp"
|
||||||
|
#include "tasks/002.hpp"
|
||||||
// #include "sort/insertion.hpp"
|
|
||||||
|
|
||||||
auto main() -> int
|
auto main() -> int
|
||||||
{
|
{
|
||||||
// {
|
alg::tasks::run_002();
|
||||||
// std::vector<int> v { 5, 4, 1, 3, 6, 9, 7, 2, 8, 0, 10 };
|
|
||||||
// // alg::sort::insertion(v, 0, v.size() - 1);
|
|
||||||
// alg::sort::insertion(v);
|
|
||||||
// hack::log()(v);
|
|
||||||
// return 0;
|
|
||||||
// }
|
|
||||||
|
|
||||||
alg::tasks::run();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
29
run.sh
29
run.sh
@@ -1,29 +0,0 @@
|
|||||||
#!/bin/zsh
|
|
||||||
|
|
||||||
PROJECT_NAME=$(basename $PWD)
|
|
||||||
|
|
||||||
run() {
|
|
||||||
command meson compile -C build
|
|
||||||
cd build
|
|
||||||
./bin/$PROJECT_NAME
|
|
||||||
cd ..
|
|
||||||
}
|
|
||||||
|
|
||||||
# run test [name_test]
|
|
||||||
# example: run test pattrens
|
|
||||||
if [[ "$1" == "test" ]]; then
|
|
||||||
echo ""
|
|
||||||
meson test $2 -C build
|
|
||||||
echo ""
|
|
||||||
awk '/^-------------------------------------------------------------------------------/{flag=1} /===============================================================================/{flag=0} flag' ./build/meson-logs/testlog.txt
|
|
||||||
elif [[ "$1" == "tests" ]]; then
|
|
||||||
echo ""
|
|
||||||
meson test -C build
|
|
||||||
echo ""
|
|
||||||
# awk '/^-------------------------------------------------------------------------------/{flag=1} /===============================================================================/{flag=0} flag' ./build/meson-logs/testlog.txt
|
|
||||||
elif [[ -d "build" ]]; then
|
|
||||||
run
|
|
||||||
else
|
|
||||||
command meson setup build
|
|
||||||
run
|
|
||||||
fi
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
// находит все простые числа от 0 до n
|
|
||||||
// Решето Эратосфена
|
|
||||||
namespace alg
|
|
||||||
{
|
|
||||||
inline std::vector<int> find_primes(int n)
|
|
||||||
{
|
|
||||||
std::vector<int> r;
|
|
||||||
std::vector<bool> is_prime(n + 1, true);
|
|
||||||
|
|
||||||
// 0 и 1 не являются простыми числами
|
|
||||||
is_prime[0] = is_prime[1] = false;
|
|
||||||
|
|
||||||
// Исключаем все чётные числа, кроме 2
|
|
||||||
for (int i = 4; i <= n; i += 2) is_prime[i] = false;
|
|
||||||
|
|
||||||
// Перебираем только нечётные числа, начиная с 3
|
|
||||||
for (int p = 3; p * p <= n; p += 2)
|
|
||||||
if (is_prime[p])
|
|
||||||
for (int i = p * p; i <= n; i += 2 * p) is_prime[i] = false;
|
|
||||||
|
|
||||||
for (int p = 3; p <= n; p += 2)
|
|
||||||
if (is_prime[p]) r.push_back(p);
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
// Называется алгоритм Евклида
|
|
||||||
// Находит наибольший общий делитель
|
|
||||||
// см. Алгоритмический тренинг стр. 80
|
|
||||||
namespace alg
|
|
||||||
{
|
|
||||||
inline int gcd(int a, int b)
|
|
||||||
{
|
|
||||||
while (b != 0)
|
|
||||||
{
|
|
||||||
int r = a%b;
|
|
||||||
a = b;
|
|
||||||
b = r;
|
|
||||||
}
|
|
||||||
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
|
|
||||||
namespace alg::search
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
/*
|
|
||||||
Сортировка вставками.
|
|
||||||
Для небольших массивов стабильна и является самой быстрой. Её можно использовать
|
|
||||||
как вспомогательную при реализации других сортировок.
|
|
||||||
|
|
||||||
Сортировка стабильна, если равные элементы сохраняют свой первоначальный порядок относительно друг друга.
|
|
||||||
|
|
||||||
Смысл следующий: Считаем что элемент с индексом 0 является как бы массивом(1) с уже отсотрированным элементом.
|
|
||||||
И далее, каждый появляющийся элемент мы сравниваем с элементом из массива(1) и если он меньше, то перемещаем его дальше вглубь массива(1)
|
|
||||||
При удачном раскладе и небольших данных работает
|
|
||||||
|
|
||||||
В наихудшем случае сложность алгоритма = O(N^2). Т.к. нам нужно будет пробежаться по каждому элементу из масива массивов
|
|
||||||
|
|
||||||
ДОПИСАТЬ ТЕКСТ ДАЛЬШЕ ПРО НАИЛУЧШИЙ И СРЕДНИЙ СЛУЧАЙ
|
|
||||||
*/
|
|
||||||
namespace alg::sort
|
|
||||||
{
|
|
||||||
template<typename Item>
|
|
||||||
void insertion(std::vector<Item>& v, std::size_t left, std::size_t right)
|
|
||||||
{
|
|
||||||
for (std::size_t i = left + 1; i <= right; ++i)
|
|
||||||
{
|
|
||||||
Item e = v[i];
|
|
||||||
std::size_t j = i;
|
|
||||||
while (j > left && e < v[j - 1])
|
|
||||||
{
|
|
||||||
v[j] = v[j - 1];
|
|
||||||
--j;
|
|
||||||
}
|
|
||||||
v[j] = e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Item>
|
|
||||||
void insertion(std::vector<Item>& v)
|
|
||||||
{
|
|
||||||
insertion(v, 0, v.size() - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,18 +3,22 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <hack/logger/logger.hpp>
|
||||||
|
|
||||||
namespace alg::tasks
|
namespace alg::tasks
|
||||||
{
|
{
|
||||||
// Есть набор чисел, необходимо из них создать такую перестановку
|
// Есть набор чисел, необходимо из них создать такую перестановку
|
||||||
// при котором разности их величин будутминимально отличаться.
|
// при котором разности их величин будут минимально отличаться.
|
||||||
// Т.е. как бы максимально их уравнять
|
// Т.е. как бы максимально их уравнять.
|
||||||
inline void run()
|
// Проще говоря:
|
||||||
|
// Есть люди разного роста (от 150 см до 190 см) и нужно построить их в шеренгу, чтобы каждый следующий
|
||||||
|
// человек отличался по росту от предыдущего примерно одинаково.
|
||||||
|
inline void run_001()
|
||||||
{
|
{
|
||||||
// { x, y }
|
// { x, y }
|
||||||
// x - число
|
// x - число
|
||||||
// y - просто номер чтоб не потеряться когда увидим перестановку
|
// y - просто номер чтоб не потеряться когда увидим перестановку
|
||||||
std::vector<std::pair<int, int>> data { { 1, 0 }, { 2, 1 }, { 3, 2 }, { 4, 3 } };
|
std::vector<std::pair<int, int>> data { { 1, 0 }, { 2, 1 }, { 3, 2 }, { 4, 3 }, { 3, 4 }, { 1, 5 }, { 5, 6 }, { 3 , 7 }, { 1, 8 }, { 5, 9 }, { 4, 10 } };
|
||||||
|
|
||||||
std::sort(data.begin(), data.end());
|
std::sort(data.begin(), data.end());
|
||||||
auto n = data.size();
|
auto n = data.size();
|
||||||
@@ -25,7 +29,7 @@ namespace alg::tasks
|
|||||||
std::cout << data[i].second << ' ';
|
std::cout << data[i].second << ' ';
|
||||||
|
|
||||||
// потом нечетные в порядке убывания
|
// потом нечетные в порядке убывания
|
||||||
for (int i = n - 1- n % 2; i >= 1; i -=2)
|
for (int i = n - 1 - n % 2; i >= 1; i -= 2)
|
||||||
std::cout << data[i].second << ' ';
|
std::cout << data[i].second << ' ';
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
|
|
||||||
@@ -33,7 +37,7 @@ namespace alg::tasks
|
|||||||
for (std::size_t i = 0; i < n; i += 2)
|
for (std::size_t i = 0; i < n; i += 2)
|
||||||
std::cout << data[i].first << ' ';
|
std::cout << data[i].first << ' ';
|
||||||
|
|
||||||
for (int i = n - 1- n % 2; i >= 1; i -=2)
|
for (int i = n - 1- n % 2; i >= 1; i -= 2)
|
||||||
std::cout << data[i].first << ' ';
|
std::cout << data[i].first << ' ';
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
}
|
}
|
||||||
|
|||||||
79
src/tasks/002.hpp
Normal file
79
src/tasks/002.hpp
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <deque>
|
||||||
|
#include <iostream>
|
||||||
|
#include <hack/logger/logger.hpp>
|
||||||
|
|
||||||
|
namespace alg::tasks
|
||||||
|
{
|
||||||
|
// Рассмотрим последовательность целых чисел длины n.
|
||||||
|
// По ней двигается «окно» длины k: сначала в «окне» находятся
|
||||||
|
// первые k чисел, на следующем шаге в «окне» уже будут находиться
|
||||||
|
// k чисел, начиная со второго, и так далее до конца последовательности.
|
||||||
|
// Требуется для каждого положения «окна» определить минимум в нём.
|
||||||
|
/* пример:
|
||||||
|
7 3
|
||||||
|
1 3 2 4 5 3 1
|
||||||
|
|
||||||
|
Рассмотрим все доступные положения скользящего окна:
|
||||||
|
|1 3 2| 4 5 3 1 - min(1, 3, 2) = 1
|
||||||
|
1 |3 2 4| 5 3 1 - min(3, 2, 4) = 2
|
||||||
|
1 3 |2 4 5| 3 1 - min(2, 4, 5) = 2
|
||||||
|
1 3 2 |4 5 3| 1 - min(4, 5, 3) = 3
|
||||||
|
1 3 2 4 |5 3 1| - min(5, 3, 1) = 1
|
||||||
|
|
||||||
|
результат [1, 2, 2, 3, 1]
|
||||||
|
*/
|
||||||
|
inline void run_002()
|
||||||
|
{
|
||||||
|
// Ускоряем ввод/вывод для больших объёмов данных
|
||||||
|
std::ios_base::sync_with_stdio(false);
|
||||||
|
std::cin.tie(nullptr);
|
||||||
|
|
||||||
|
int n, k;
|
||||||
|
std::cin >> n >> k;
|
||||||
|
std::vector<int> a(n);
|
||||||
|
for (int i = 0; i < n; ++i) std::cin >> a[i];
|
||||||
|
|
||||||
|
// deque хранит индексы элементов текущих окон.
|
||||||
|
// Значения a[dq[0]], a[dq[1]], ... всегда идут в неубывающем порядке.
|
||||||
|
std::deque<int> dq;
|
||||||
|
|
||||||
|
for (int i = 0; i < n; ++i)
|
||||||
|
{
|
||||||
|
// 1. Удаляем индекс из начала, если он вышел за пределы окна
|
||||||
|
if (!dq.empty() && dq.front() == i - k) dq.pop_front();
|
||||||
|
|
||||||
|
// 2. Удаляем индексы с конца, если их значения >= текущего элемента.
|
||||||
|
// Они больше никогда не станут минимумом окна.
|
||||||
|
while (!dq.empty() && a[dq.back()] >= a[i]) dq.pop_back();
|
||||||
|
|
||||||
|
// 3. Добавляем текущий индекс
|
||||||
|
dq.push_back(i);
|
||||||
|
|
||||||
|
// 4. Если окно полностью сформировалось (прошли минимум k элементов),
|
||||||
|
// минимум всегда находится в начале deque.
|
||||||
|
if (i >= k - 1) std::cout << a[dq.front()] << '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Основное:
|
||||||
|
1. **`dq.front()`** всегда содержит индекс минимального элемента в текущем окне.
|
||||||
|
2. При сдвиге окна мы удаляем устаревший индекс слева (`i - k`).
|
||||||
|
3. Перед добавлением нового элемента мы "очищаем" хвост очереди от элементов, которые больше или равны новому.
|
||||||
|
Они бесполезны, так как новый элемент `a[i]` моложе (живёт дольше в окне) и не больше их, поэтому минимумом они стать не смогут.
|
||||||
|
4. Каждый элемент добавляется в `deque` ровно один раз и удаляется тоже не более одного
|
||||||
|
раза → **амортизированное время `O(1)` на шаг**, итого `O(n)` на всю последовательность.
|
||||||
|
|
||||||
|
Сложность:
|
||||||
|
- **Время:** `O(n)` (проход по массиву, каждое число добавляется/удаляется из `deque` максимум 1 раз)
|
||||||
|
- **Память:** `O(n)` для хранения массива + `O(k)` для `deque` (в худшем случае)
|
||||||
|
|
||||||
|
Примечание по вводу/выводу:
|
||||||
|
В коде использованы `ios_base::sync_with_stdio(false); cin.tie(nullptr);` и `'\n'` вместо `endl`.
|
||||||
|
Это критически важно для задач с `n > 10^5`, иначе программа может не уложиться в лимит времени из-за медленного I/O в C++.
|
||||||
|
*/
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "gcd.hpp"
|
|
||||||
#include "pow.hpp"
|
|
||||||
|
|
||||||
// Малая теорема Ферма: Если p - число простое и a - целое число, не делящееся на p, то при
|
|
||||||
// возведении a в степень p - 1, наибольший общий делитель между результатом и p будет равен 1
|
|
||||||
// Но там есть ньюансы, называются обманщиками Ферма. По этому тесты нужно проводить на нескольких числах a.
|
|
||||||
// По этому если тестов много (у нас по уолчанию 1000) то вероятность того что появятся обманщики Ферам 1/2^1000
|
|
||||||
// Проверяет число на простоту
|
|
||||||
namespace alg
|
|
||||||
{
|
|
||||||
inline bool is_prime(int a, int max_test = 1000)
|
|
||||||
{
|
|
||||||
// начинаем с 4 т.к. 2 и 3 простые числа
|
|
||||||
for (int i = 4; i < max_test; ++i)
|
|
||||||
if (gcd(pow(i, a - 1), a) == 1) return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
// Возведение в степень
|
|
||||||
namespace alg
|
|
||||||
{
|
|
||||||
inline int pow(double a, int n)
|
|
||||||
{
|
|
||||||
double result = 1.0;
|
|
||||||
bool is_negative = n < 0;
|
|
||||||
|
|
||||||
if (is_negative) n *= -1;
|
|
||||||
|
|
||||||
while (n > 0)
|
|
||||||
{
|
|
||||||
if (n & 1) result *= a;
|
|
||||||
a *= a;
|
|
||||||
n >>= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return is_negative ? 1.0 / result : result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
// Находит все простые множители заданного числа.
|
|
||||||
// Простое число - это число > 1, которое делится на 1 и на само себя.
|
|
||||||
namespace alg
|
|
||||||
{
|
|
||||||
inline std::vector<int> prime_factors_v1(int a)
|
|
||||||
{
|
|
||||||
std::vector<int> result;
|
|
||||||
int i = 2;
|
|
||||||
|
|
||||||
while (i < a)
|
|
||||||
{
|
|
||||||
while (a%i == 0)
|
|
||||||
{
|
|
||||||
result.push_back(i);
|
|
||||||
a /= i;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (a > 1) result.push_back(a);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline std::vector<int> prime_factors_v2(int a)
|
|
||||||
{
|
|
||||||
std::vector<int> result;
|
|
||||||
|
|
||||||
while(a%2 == 0)
|
|
||||||
{
|
|
||||||
result.push_back(2);
|
|
||||||
a = a/2;
|
|
||||||
}
|
|
||||||
|
|
||||||
int i = 3;
|
|
||||||
int max_faxtor = std::sqrt(a);
|
|
||||||
|
|
||||||
while (i <= max_faxtor)
|
|
||||||
{
|
|
||||||
while (a%i == 0)
|
|
||||||
{
|
|
||||||
result.push_back(i);
|
|
||||||
a /= i;
|
|
||||||
max_faxtor = std::sqrt(a);
|
|
||||||
}
|
|
||||||
i += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (a > 1) result.push_back(a);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <hack/logger/logger.hpp>
|
|
||||||
|
|
||||||
// Сортировка вставкой
|
|
||||||
// Эффективна на мелких массивах. Сложнгость O(N^2)
|
|
||||||
namespace alg
|
|
||||||
{
|
|
||||||
inline void merge(std::vector<int>& v, int left, int mid, int right, std::vector<int>& tmp)
|
|
||||||
{
|
|
||||||
for(int i = left, j = mid + 1; left <= right; ++left)
|
|
||||||
{
|
|
||||||
bool useRight = i > mid || (j <= right && tmp[j] < tmp[i]);
|
|
||||||
v[left] = tmp[(useRight ? j : i)++];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void merge_sort_helper(std::vector<int>& v, int left, int right, std::vector<int>& tmp)
|
|
||||||
{
|
|
||||||
if (left < right)
|
|
||||||
{
|
|
||||||
int mid = (left + right) / 2;
|
|
||||||
|
|
||||||
merge_sort_helper(tmp, left, mid, v);
|
|
||||||
merge_sort_helper(tmp, mid + 1, right, v);
|
|
||||||
|
|
||||||
merge(v, left, mid, right, tmp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void merge_sort(std::vector<int>& v)
|
|
||||||
{
|
|
||||||
std::vector<int> tmp(v);
|
|
||||||
merge_sort_helper(v, 0, v.size() - 1, tmp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <hack/logger/logger.hpp>
|
|
||||||
#include "insertion_sort.hpp"
|
|
||||||
|
|
||||||
// Сортировка вставкой
|
|
||||||
// Эффективна на мелких массивах. Сложнгость O(N^2)
|
|
||||||
namespace alg_v1
|
|
||||||
{
|
|
||||||
// Функция для слияния двух отсортированных половин массива
|
|
||||||
inline void merge(std::vector<int>& v, int start1, int end1, int start2, int end2)
|
|
||||||
{
|
|
||||||
auto fs = start1;
|
|
||||||
auto fe = end2;
|
|
||||||
|
|
||||||
int i = 1;
|
|
||||||
|
|
||||||
std::vector<int> tmp(v);
|
|
||||||
|
|
||||||
while (start1 <= end1 && (start2 <= end2))
|
|
||||||
{
|
|
||||||
if (v[start1] < v[start2])
|
|
||||||
{
|
|
||||||
tmp[i] = v[start1];
|
|
||||||
++start1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tmp[i] = v[start2];
|
|
||||||
++start2;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (start1 <= end1)
|
|
||||||
{
|
|
||||||
for (int j = start1; j < end1; ++j)
|
|
||||||
{
|
|
||||||
tmp[i] = v[j];
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (int j = start2; j < end2; ++j)
|
|
||||||
{
|
|
||||||
tmp[i] = v[j];
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
i = 1;
|
|
||||||
for (int j = fs; j < fe; ++j)
|
|
||||||
{
|
|
||||||
v[j] = tmp[i];
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void merge_sort_helper(int i, std::vector<int>& v, int first, int last)
|
|
||||||
{
|
|
||||||
if (first < last)
|
|
||||||
{
|
|
||||||
// Находим среднюю точку
|
|
||||||
int mid = (first + last) / 2;
|
|
||||||
|
|
||||||
hack::log()(i, " | first =", first, ", last =", last, ", mid =", mid);
|
|
||||||
|
|
||||||
// Сортируем первую и вторую половины
|
|
||||||
merge_sort_helper(1, v, first, mid);
|
|
||||||
merge_sort_helper(2, v, mid + 1, last);
|
|
||||||
|
|
||||||
// Сливаем отсортированные половины
|
|
||||||
merge(v, first, mid, mid + 1, last);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void merge_sort(std::vector<int>& v)
|
|
||||||
{
|
|
||||||
merge_sort_helper(0, v, 0, v.size() - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <hack/logger/logger.hpp>
|
|
||||||
#include "insertion_sort.hpp"
|
|
||||||
|
|
||||||
// Сортировка вставкой
|
|
||||||
// Эффективна на мелких массивах. Сложнгость O(N^2)
|
|
||||||
namespace alg_v2
|
|
||||||
{
|
|
||||||
inline void merge(std::vector<int>& v, int left, int mid, int right)
|
|
||||||
{
|
|
||||||
std::vector<int> l(v.begin() + left, v.begin() + mid + 1);
|
|
||||||
std::vector<int> r(v.begin() + mid + 1, v.begin() + right + 1);
|
|
||||||
|
|
||||||
int i = 0; // индекс для левой подсистемы
|
|
||||||
int j = 0; // индекс для правой подсистемы
|
|
||||||
int k = left; // индекс для A[p:r+1]
|
|
||||||
|
|
||||||
// Объединение двух отсортированных подсистем
|
|
||||||
while (i < l.size() && j < r.size())
|
|
||||||
{
|
|
||||||
if (l[i] <= r[j]) {
|
|
||||||
v[k] = l[i];
|
|
||||||
i++;
|
|
||||||
} else {
|
|
||||||
v[k] = r[j];
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
k++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Копирование оставшихся элементов левой подсистемы (если есть)
|
|
||||||
while (i < l.size())
|
|
||||||
{
|
|
||||||
v[k] = l[i];
|
|
||||||
i++;
|
|
||||||
k++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Копирование оставшихся элементов правой подсистемы (если есть)
|
|
||||||
while (j < r.size()) {
|
|
||||||
v[k] = r[j];
|
|
||||||
j++;
|
|
||||||
k++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void merge_sort_helper(std::vector<int>& v, int left, int right)
|
|
||||||
{
|
|
||||||
if (left < right)
|
|
||||||
{
|
|
||||||
int mid = (left + right) / 2;
|
|
||||||
|
|
||||||
merge_sort_helper(v, left, mid);
|
|
||||||
merge_sort_helper(v, mid + 1, right);
|
|
||||||
|
|
||||||
merge(v, left, mid, right);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void merge_sort(std::vector<int>& v)
|
|
||||||
{
|
|
||||||
merge_sort_helper(v, 0, v.size() - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user