Стоимость инфраструктуры
В облачных средах вычислительные ресурсы измеряются в денежном эквиваленте. Неэффективный алгоритм напрямую влияет на эксплуатационные расходы.
Рассмотрим пример обработки запросов в веб-приложении.
Алгоритм с временной сложностью O(n) для обработки одного запроса при увеличении нагрузки в 10 раз потребует в 10 раз больше вычислительных ресурсов. Алгоритм с оптимизированной сложностью O(log n) при таком же росте нагрузки увеличит потребление ресурсов лишь на постоянную величину.
Важным аспектом является также потребление памяти. Алгоритмы, работающие in-place (без дополнительной памяти), предпочтительнее для обработки больших данных. Однако иногда расход памяти оправдан для достижения лучшего времени выполнения. Этот компромисс известен как trade-off между временем и памятью.
Масштабируемость системы
Масштабируемость — это способность системы справляться с ростом нагрузки. Алгоритмы с неоптимальной асимптотической сложностью становятся узким местом при горизонтальном масштабировании.
Например, алгоритм, требующий полной синхронизации всех узлов кластера для выполнения операции, имеет фундаментальное ограничение на масштабируемость.
В распределенных системах предпочтение отдается алгоритмам, которые:
Минимизируют коммуникацию между узлами
Допускают параллельное выполнение
Обладают свойством идемпотентности (многократное выполнение дает тот же результат)
Рассмотрим алгоритм согласованного хеширования (consistent hashing), используемый в распределенных кэшах и базах данных. Вместо перераспределения всех данных при изменении количества узлов кластера, этот алгоритм перемещает только O(1/n) данных, где n — количество узлов. Это обеспечивает предсказуемую производительность при масштабировании системы.
Практические рекомендации по выбору алгоритма
Профилирование перед оптимизацией: Используйте инструменты профилирования (такие как JProfiler, YourKit, Async Profiler) для идентификации реальных узких мест. Преждевременная оптимизация часто приводит к усложнению кода без значительного выигрыша в производительности.
Учет распределения данных: Эффективность алгоритмов может зависеть от характеристик данных. Хеш-таблицы обеспечивают среднее время O(1), но при плохом распределении хеш-функции могут деградировать до O(n). Деревья поиска гарантируют O(log n), но имеют большую константу.
Анализ частоты операций: Оптимизируйте операции, которые выполняются чаще всего. Если чтение происходит в 100 раз чаще, чем запись, имеет смысл использовать более сложные структуры данных для ускорения чтения, даже в ущерб производительности записи.
Учет аппаратных особенностей: Современные процессоры имеют многоуровневые кэши. Алгоритмы, обладающие локальностью ссылок (обращение к соседним элементам памяти), работают значительно быстрее из-за уменьшения промахов кэша.
Компромисс между разработкой и выполнением: Иногда простой алгоритм с чуть худшей асимптотической сложностью предпочтительнее сложного оптимизированного алгоритма, если он проще в реализации, отладке и поддержке.
#Java #для_новичков #beginner #algorithm
В облачных средах вычислительные ресурсы измеряются в денежном эквиваленте. Неэффективный алгоритм напрямую влияет на эксплуатационные расходы.
Рассмотрим пример обработки запросов в веб-приложении.
Алгоритм с временной сложностью O(n) для обработки одного запроса при увеличении нагрузки в 10 раз потребует в 10 раз больше вычислительных ресурсов. Алгоритм с оптимизированной сложностью O(log n) при таком же росте нагрузки увеличит потребление ресурсов лишь на постоянную величину.
Важным аспектом является также потребление памяти. Алгоритмы, работающие in-place (без дополнительной памяти), предпочтительнее для обработки больших данных. Однако иногда расход памяти оправдан для достижения лучшего времени выполнения. Этот компромисс известен как trade-off между временем и памятью.
Масштабируемость системы
Масштабируемость — это способность системы справляться с ростом нагрузки. Алгоритмы с неоптимальной асимптотической сложностью становятся узким местом при горизонтальном масштабировании.
Например, алгоритм, требующий полной синхронизации всех узлов кластера для выполнения операции, имеет фундаментальное ограничение на масштабируемость.
В распределенных системах предпочтение отдается алгоритмам, которые:
Минимизируют коммуникацию между узлами
Допускают параллельное выполнение
Обладают свойством идемпотентности (многократное выполнение дает тот же результат)
Рассмотрим алгоритм согласованного хеширования (consistent hashing), используемый в распределенных кэшах и базах данных. Вместо перераспределения всех данных при изменении количества узлов кластера, этот алгоритм перемещает только O(1/n) данных, где n — количество узлов. Это обеспечивает предсказуемую производительность при масштабировании системы.
Практические рекомендации по выбору алгоритма
Профилирование перед оптимизацией: Используйте инструменты профилирования (такие как JProfiler, YourKit, Async Profiler) для идентификации реальных узких мест. Преждевременная оптимизация часто приводит к усложнению кода без значительного выигрыша в производительности.
Учет распределения данных: Эффективность алгоритмов может зависеть от характеристик данных. Хеш-таблицы обеспечивают среднее время O(1), но при плохом распределении хеш-функции могут деградировать до O(n). Деревья поиска гарантируют O(log n), но имеют большую константу.
Анализ частоты операций: Оптимизируйте операции, которые выполняются чаще всего. Если чтение происходит в 100 раз чаще, чем запись, имеет смысл использовать более сложные структуры данных для ускорения чтения, даже в ущерб производительности записи.
Учет аппаратных особенностей: Современные процессоры имеют многоуровневые кэши. Алгоритмы, обладающие локальностью ссылок (обращение к соседним элементам памяти), работают значительно быстрее из-за уменьшения промахов кэша.
Компромисс между разработкой и выполнением: Иногда простой алгоритм с чуть худшей асимптотической сложностью предпочтительнее сложного оптимизированного алгоритма, если он проще в реализации, отладке и поддержке.
#Java #для_новичков #beginner #algorithm
👍4
OrderHub. Эволюция проекта из монолита к production-ready микросервису
1. Старт серии. Создаём основу для production-системы.
Я начинаю большой практический курс, в котором мы с нуля спроектируем и разработаем полноценную, отказоустойчивую микросервисную систему на современном Java-стеке.
Главная цель курса — дать вам не разрозненные знания, а целостный опыт разработчика: от написания кода до расследования инцидентов в работающей системе.
Сегодня:
🔹 Полный анонс курса: зачем это всё нужно и что вы получите в итоге.
🔹 Постановка бизнес-задачи и проектирование доменной модели.
🔹 Инициализация Spring Boot 3 проекта с правильной структурой пакетов.
🔹 Создание основных сущностей (Order, OrderItem) и REST API для работы с ними.
🔹 Закладываем фундамент для будущего масштабирования.
Исходный код проекта на GitHub очень ждет Ваших звезд.
Ссылка на Youtube
Ссылка на Рутьюб
Смотрите, ставьте лайки, подписывайтесь на каналы!✌️
1. Старт серии. Создаём основу для production-системы.
Я начинаю большой практический курс, в котором мы с нуля спроектируем и разработаем полноценную, отказоустойчивую микросервисную систему на современном Java-стеке.
Главная цель курса — дать вам не разрозненные знания, а целостный опыт разработчика: от написания кода до расследования инцидентов в работающей системе.
Сегодня:
🔹 Полный анонс курса: зачем это всё нужно и что вы получите в итоге.
🔹 Постановка бизнес-задачи и проектирование доменной модели.
🔹 Инициализация Spring Boot 3 проекта с правильной структурой пакетов.
🔹 Создание основных сущностей (Order, OrderItem) и REST API для работы с ними.
🔹 Закладываем фундамент для будущего масштабирования.
Исходный код проекта на GitHub очень ждет Ваших звезд.
Ссылка на Youtube
Ссылка на Рутьюб
Смотрите, ставьте лайки, подписывайтесь на каналы!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🔥1
Что выведет код?
#Tasks
import java.util.*;
public class Task080126 {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Comparator<Integer> comparator = (a, b) -> b - a;
int index = Collections.binarySearch(list, 1, comparator);
System.out.println(index);
}
}
#Tasks
👍1
👍1
Чем опасны mutable-ключи в HashMap? 🤓
Ответ:
Если изменить объект, используемый как ключ, его hashCode изменится. Map потеряет возможность найти элемент.
Поэтому ключи должны быть immutable или неизменяемыми на протяжении всего времени хранения.
#собеседование
Ответ:
Поэтому ключи должны быть immutable или неизменяемыми на протяжении всего времени хранения.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
История IT-технологий сегодня — 09 января
ℹ️ Кто родился в этот день
Не нашел(
🌐 Знаковые события
2007 — представлен первый iPhone.
#Biography #Birth_Date #Events #09Января
Не нашел(
2007 — представлен первый iPhone.
#Biography #Birth_Date #Events #09Января
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Раздел 7. Алгоритмы
Глава 1: Основы анализа алгоритмов
Временная сложность и Big O нотация: язык анализа алгоритмов
При анализе алгоритмов мы сталкиваемся с фундаментальной проблемой: измерение абсолютного времени выполнения зависит от множества внешних факторов — мощности процессора, объема памяти, оптимизаций компилятора, загрузки системы. Чтобы абстрагироваться от этих переменных и сосредоточиться на сути алгоритма, математики и информатики разработали асимптотический анализ — метод оценки роста потребления ресурсов при увеличении размера входных данных.
Асимптотическая сложность описывает, как время выполнения или потребление памяти алгоритма растет относительно размера входных данных (обычно обозначаемого как n). Ключевая идея: при достаточно больших n константные множители и младшие слагаемые становятся пренебрежимо малыми по сравнению с доминирующим членом функции.
Рассмотрим пример: два алгоритма со сложностями T₁(n) = 100n + 500 и T₂(n) = n² + 5. При малых n (например, n=10) первый алгоритм выполняется за 1500 условных единиц, второй — за 105 единиц. Однако при n=1000 первый требует 100500 единиц, а второй — уже 1000005 единиц. При n=10000 разрыв становится катастрофическим: 1 000 500 против 100 000 005.
Big O нотация: формализация верхней границы
Big O нотация (O-нотация) — это математический инструмент для описания верхней границы роста функции. Формально, функция f(n) = O(g(n)), если существуют положительные константы c и n₀ такие, что 0 ≤ f(n) ≤ c·g(n) для всех n ≥ n₀. На практике это означает, что f(n) растет не быстрее, чем g(n), с точностью до постоянного множителя.
Важное уточнение: Big O описывает худший случай выполнения алгоритма. Это консервативная оценка, гарантирующая, что алгоритм не будет работать медленнее указанной границы. Для полного понимания поведения алгоритма необходимо также рассматривать средний и лучший случаи.
Иерархия сложностей: от константной до экспоненциальной
O(1) — Константное время
Алгоритмы с константной сложностью выполняются за фиксированное время, независимо от размера входных данных.
Доступ к элементу массива по индексу — классический пример:
Характеристики:
Время выполнения постоянно
Идеальная масштабируемость
Редко достижима для нетривиальных задач
O(log n) — Логарифмическое время
Логарифмическая сложность возникает, когда на каждом шаге алгоритм уменьшает размер задачи в постоянное число раз.
Бинарный поиск в отсортированном массиве — канонический пример:
Математическая основа: если на каждом шаге мы делим задачу пополам, то максимальное количество шагов равно log₂n. При увеличении n в миллион раз количество операций увеличивается всего в 20 раз (log₂(1 000 000) ≈ 20).
#Java #для_новичков #beginner #algorithm #bigO
Глава 1: Основы анализа алгоритмов
Временная сложность и Big O нотация: язык анализа алгоритмов
При анализе алгоритмов мы сталкиваемся с фундаментальной проблемой: измерение абсолютного времени выполнения зависит от множества внешних факторов — мощности процессора, объема памяти, оптимизаций компилятора, загрузки системы. Чтобы абстрагироваться от этих переменных и сосредоточиться на сути алгоритма, математики и информатики разработали асимптотический анализ — метод оценки роста потребления ресурсов при увеличении размера входных данных.
Асимптотическая сложность описывает, как время выполнения или потребление памяти алгоритма растет относительно размера входных данных (обычно обозначаемого как n). Ключевая идея: при достаточно больших n константные множители и младшие слагаемые становятся пренебрежимо малыми по сравнению с доминирующим членом функции.
Рассмотрим пример: два алгоритма со сложностями T₁(n) = 100n + 500 и T₂(n) = n² + 5. При малых n (например, n=10) первый алгоритм выполняется за 1500 условных единиц, второй — за 105 единиц. Однако при n=1000 первый требует 100500 единиц, а второй — уже 1000005 единиц. При n=10000 разрыв становится катастрофическим: 1 000 500 против 100 000 005.
Big O нотация: формализация верхней границы
Big O нотация (O-нотация) — это математический инструмент для описания верхней границы роста функции. Формально, функция f(n) = O(g(n)), если существуют положительные константы c и n₀ такие, что 0 ≤ f(n) ≤ c·g(n) для всех n ≥ n₀. На практике это означает, что f(n) растет не быстрее, чем g(n), с точностью до постоянного множителя.
Важное уточнение: Big O описывает худший случай выполнения алгоритма. Это консервативная оценка, гарантирующая, что алгоритм не будет работать медленнее указанной границы. Для полного понимания поведения алгоритма необходимо также рассматривать средний и лучший случаи.
Иерархия сложностей: от константной до экспоненциальной
O(1) — Константное время
Алгоритмы с константной сложностью выполняются за фиксированное время, независимо от размера входных данных.
Доступ к элементу массива по индексу — классический пример:
public class ConstantTimeExample {
private int[] array;
public int getElement(int index) {
// Всегда выполняется за фиксированное время
return array[index];
}
public boolean isEven(int number) {
// Математическая операция также O(1)
return number % 2 == 0;
}
}Характеристики:
Время выполнения постоянно
Идеальная масштабируемость
Редко достижима для нетривиальных задач
O(log n) — Логарифмическое время
Логарифмическая сложность возникает, когда на каждом шаге алгоритм уменьшает размер задачи в постоянное число раз.
Бинарный поиск в отсортированном массиве — канонический пример:
public class BinarySearch {
public static int search(int[] sortedArray, int target) {
int left = 0;
int right = sortedArray.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2; // Избегаем переполнения
if (sortedArray[mid] == target) {
return mid;
} else if (sortedArray[mid] < target) {
left = mid + 1; // Отбрасываем левую половину
} else {
right = mid - 1; // Отбрасываем правую половину
}
}
return -1; // Элемент не найден
}
}Математическая основа: если на каждом шаге мы делим задачу пополам, то максимальное количество шагов равно log₂n. При увеличении n в миллион раз количество операций увеличивается всего в 20 раз (log₂(1 000 000) ≈ 20).
#Java #для_новичков #beginner #algorithm #bigO
🔥5👍1
O(n) — Линейное время
Линейная сложность означает прямо пропорциональную зависимость времени выполнения от размера входных данных.
Классический пример — поиск максимума в неотсортированном массиве:
Особенности:
Время выполнения растет пропорционально n
Часто является оптимальной сложностью для задач, требующих обработки каждого элемента
Алгоритмы с такой сложностью обычно хорошо масштабируются
O(n log n) — Линейно-логарифмическое время
Этот класс сложности часто встречается в эффективных алгоритмах сортировки, таких как MergeSort, HeapSort и QuickSort (в среднем случае). Алгоритм делит задачу на части (log n уровней деления), каждый из которых требует обработки всех n элементов.
Практическая значимость: O(n log n) часто является "естественной" нижней границей для задач, которые можно свести к задаче сортировки.
O(n²) — Квадратичное время
Квадратичная сложность характерна для алгоритмов с вложенными циклами, где каждый элемент обрабатывается с каждым другим элементом.
Классический пример — пузырьковая сортировка:
Проблема масштабирования: при увеличении n в 10 раз время выполнения увеличивается в 100 раз. Для n=1000 нужно примерно 500000 сравнений, для n=10000 — уже 50 миллионов.
O(2ⁿ) — Экспоненциальное время
Экспоненциальные алгоритмы становятся непрактичными даже для умеренных значений n. Они часто возникают при решении задач перебором, таких как задача коммивояжера (в наивной реализации) или вычисление чисел Фибоначчи через наивную рекурсию:
Критическая важность оптимизации: для n=50 наивный алгоритм требует порядка 2⁵⁰ ≈ 1.1×10¹⁵ операций, что на современном процессоре займет несколько дней. Алгоритм с динамическим программированием выполнит те же вычисления за 50 операций.
#Java #для_новичков #beginner #algorithm #bigO
Линейная сложность означает прямо пропорциональную зависимость времени выполнения от размера входных данных.
Классический пример — поиск максимума в неотсортированном массиве:
public class LinearTimeExample {
public static int findMax(int[] array) {
if (array.length == 0) {
throw new IllegalArgumentException("Array cannot be empty");
}
int max = array[0];
for (int i = 1; i < array.length; i++) {
if (array[i] > max) {
max = array[i];
}
}
return max;
}
}Особенности:
Время выполнения растет пропорционально n
Часто является оптимальной сложностью для задач, требующих обработки каждого элемента
Алгоритмы с такой сложностью обычно хорошо масштабируются
O(n log n) — Линейно-логарифмическое время
Этот класс сложности часто встречается в эффективных алгоритмах сортировки, таких как MergeSort, HeapSort и QuickSort (в среднем случае). Алгоритм делит задачу на части (log n уровней деления), каждый из которых требует обработки всех n элементов.
public class MergeSort {
public static void sort(int[] array) {
if (array.length <= 1) return;
int mid = array.length / 2;
int[] left = Arrays.copyOfRange(array, 0, mid);
int[] right = Arrays.copyOfRange(array, mid, array.length);
sort(left);
sort(right);
merge(array, left, right);
}
private static void merge(int[] result, int[] left, int[] right) {
int i = 0, j = 0, k = 0;
while (i < left.length && j < right.length) {
if (left[i] <= right[j]) {
result[k++] = left[i++];
} else {
result[k++] = right[j++];
}
}
while (i < left.length) result[k++] = left[i++];
while (j < right.length) result[k++] = right[j++];
}
}Практическая значимость: O(n log n) часто является "естественной" нижней границей для задач, которые можно свести к задаче сортировки.
O(n²) — Квадратичное время
Квадратичная сложность характерна для алгоритмов с вложенными циклами, где каждый элемент обрабатывается с каждым другим элементом.
Классический пример — пузырьковая сортировка:
public class BubbleSort {
public static void sort(int[] array) {
int n = array.length;
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (array[j] > array[j + 1]) {
// Обмен элементов
int temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
}
}
}
}Проблема масштабирования: при увеличении n в 10 раз время выполнения увеличивается в 100 раз. Для n=1000 нужно примерно 500000 сравнений, для n=10000 — уже 50 миллионов.
O(2ⁿ) — Экспоненциальное время
Экспоненциальные алгоритмы становятся непрактичными даже для умеренных значений n. Они часто возникают при решении задач перебором, таких как задача коммивояжера (в наивной реализации) или вычисление чисел Фибоначчи через наивную рекурсию:
public class ExponentialExample {
// Наивная рекурсивная реализация Фибоначчи: O(2ⁿ)
public static long fibonacciNaive(int n) {
if (n <= 1) return n;
return fibonacciNaive(n - 1) + fibonacciNaive(n - 2);
}
// Динамическое программирование: O(n)
public static long fibonacciDP(int n) {
if (n <= 1) return n;
long[] fib = new long[n + 1];
fib[0] = 0;
fib[1] = 1;
for (int i = 2; i <= n; i++) {
fib[i] = fib[i - 1] + fib[i - 2];
}
return fib[n];
}
}Критическая важность оптимизации: для n=50 наивный алгоритм требует порядка 2⁵⁰ ≈ 1.1×10¹⁵ операций, что на современном процессоре займет несколько дней. Алгоритм с динамическим программированием выполнит те же вычисления за 50 операций.
#Java #для_новичков #beginner #algorithm #bigO
🔥4👍2
Полный спектр асимптотических оценок
Ω (Omega) — нижняя граница
Если O-нотация описывает "не хуже чем", то Ω-нотация описывает "не лучше чем". Формально, f(n) = Ω(g(n)), если существуют положительные константы c и n₀ такие, что 0 ≤ c·g(n) ≤ f(n) для всех n ≥ n₀.
Пример: любой алгоритм сравнения для сортировки n элементов имеет нижнюю границу Ω(n log n) в модели сравнений. Это означает, что не существует алгоритма сортировки сравнением, который был бы асимптотически быстрее n log n.
Θ (Theta) — точная оценка
Θ-нотация объединяет O и Ω, описывая точный порядок роста. f(n) = Θ(g(n)), если f(n) = O(g(n)) и одновременно f(n) = Ω(g(n)). Это означает, что функция растет с той же скоростью, что и g(n), с точностью до постоянного множителя.
QuickSort: комплексный пример анализа
Быстрая сортировка (QuickSort) демонстрирует важность анализа разных сценариев выполнения.
Рассмотрим классическую реализацию:
Лучший случай: O(n log n)
Лучший случай происходит, когда опорный элемент каждый раз делит массив примерно пополам. Рекуррентное соотношение: T(n) = 2T(n/2) + O(n). По основной теореме о рекурренных соотношениях это дает T(n) = Θ(n log n).
Средний случай: Θ(n log n)
При случайных данных или рандомизированном выборе опорного элемента математическое ожидание времени выполнения составляет Θ(n log n). Доказательство основано на линейности математического ожидания и том факте, что каждый элемент сравнивается с O(log n) другими элементами в среднем.
Худший случай: O(n²)
Худший случай наступает, когда опорный элемент каждый раз является минимальным или максимальным (например, при уже отсортированном массиве и выборе последнего элемента как опорного). Рекуррентное соотношение: T(n) = T(n-1) + T(0) + O(n) = T(n-1) + O(n), что дает сумму арифметической прогрессии O(n²).
#Java #для_новичков #beginner #algorithm #bigO
Ω (Omega) — нижняя граница
Если O-нотация описывает "не хуже чем", то Ω-нотация описывает "не лучше чем". Формально, f(n) = Ω(g(n)), если существуют положительные константы c и n₀ такие, что 0 ≤ c·g(n) ≤ f(n) для всех n ≥ n₀.
Пример: любой алгоритм сравнения для сортировки n элементов имеет нижнюю границу Ω(n log n) в модели сравнений. Это означает, что не существует алгоритма сортировки сравнением, который был бы асимптотически быстрее n log n.
Θ (Theta) — точная оценка
Θ-нотация объединяет O и Ω, описывая точный порядок роста. f(n) = Θ(g(n)), если f(n) = O(g(n)) и одновременно f(n) = Ω(g(n)). Это означает, что функция растет с той же скоростью, что и g(n), с точностью до постоянного множителя.
QuickSort: комплексный пример анализа
Быстрая сортировка (QuickSort) демонстрирует важность анализа разных сценариев выполнения.
Рассмотрим классическую реализацию:
public class QuickSort {
public static void sort(int[] array) {
quickSort(array, 0, array.length - 1);
}
private static void quickSort(int[] array, int low, int high) {
if (low < high) {
// Разделение массива
int pivotIndex = partition(array, low, high);
// Рекурсивная сортировка частей
quickSort(array, low, pivotIndex - 1);
quickSort(array, pivotIndex + 1, high);
}
}
private static int partition(int[] array, int low, int high) {
int pivot = array[high]; // Выбор опорного элемента
int i = low - 1;
for (int j = low; j < high; j++) {
if (array[j] <= pivot) {
i++;
swap(array, i, j);
}
}
swap(array, i + 1, high);
return i + 1;
}
private static void swap(int[] array, int i, int j) {
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}Лучший случай: O(n log n)
Лучший случай происходит, когда опорный элемент каждый раз делит массив примерно пополам. Рекуррентное соотношение: T(n) = 2T(n/2) + O(n). По основной теореме о рекурренных соотношениях это дает T(n) = Θ(n log n).
Средний случай: Θ(n log n)
При случайных данных или рандомизированном выборе опорного элемента математическое ожидание времени выполнения составляет Θ(n log n). Доказательство основано на линейности математического ожидания и том факте, что каждый элемент сравнивается с O(log n) другими элементами в среднем.
Худший случай: O(n²)
Худший случай наступает, когда опорный элемент каждый раз является минимальным или максимальным (например, при уже отсортированном массиве и выборе последнего элемента как опорного). Рекуррентное соотношение: T(n) = T(n-1) + T(0) + O(n) = T(n-1) + O(n), что дает сумму арифметической прогрессии O(n²).
#Java #для_новичков #beginner #algorithm #bigO
👍5
Практические улучшения
На практике QuickSort модифицируют для избежания худшего случая:
Рандомизированный выбор опорного элемента
Выбор медианы трех элементов
При маленьких размерах подмассивов переход на сортировку вставками
Практическое значение асимптотического анализа
Понимание асимптотической сложности позволяет делать осознанный выбор алгоритмов:
Для небольших фиксированных n простой алгоритм O(n²) может быть лучше сложного O(n log n) из-за меньших констант
При обработке потоковых данных важна сложность по памяти, а не только по времени
В системах реального времени критичны гарантии худшего случая, а не среднего
Распространенные заблуждения
Миф: "O(100n) хуже чем O(n²)"
Реальность: O(100n) = O(n) — константы отбрасываются
Миф: "Big O описывает точное время выполнения"
Реальность: Big O описывает скорость роста, а не конкретные временные значения
Миф: "Алгоритм O(log n) всегда быстрее O(n)"
Реальность: При малых n константные факторы могут сделать O(n) быстрее
#Java #для_новичков #beginner #algorithm #bigO
На практике QuickSort модифицируют для избежания худшего случая:
Рандомизированный выбор опорного элемента
Выбор медианы трех элементов
При маленьких размерах подмассивов переход на сортировку вставками
public class OptimizedQuickSort {
private static final int INSERTION_THRESHOLD = 16;
public static void sort(int[] array) {
randomizedQuickSort(array, 0, array.length - 1);
}
private static void randomizedQuickSort(int[] array, int low, int high) {
// Для маленьких массивов используем сортировку вставками
if (high - low < INSERTION_THRESHOLD) {
insertionSort(array, low, high);
return;
}
// Рандомизированный выбор опорного элемента
int randomIndex = low + (int)(Math.random() * (high - low + 1));
swap(array, randomIndex, high);
int pivotIndex = partition(array, low, high);
randomizedQuickSort(array, low, pivotIndex - 1);
randomizedQuickSort(array, pivotIndex + 1, high);
}
}Практическое значение асимптотического анализа
Понимание асимптотической сложности позволяет делать осознанный выбор алгоритмов:
Для небольших фиксированных n простой алгоритм O(n²) может быть лучше сложного O(n log n) из-за меньших констант
При обработке потоковых данных важна сложность по памяти, а не только по времени
В системах реального времени критичны гарантии худшего случая, а не среднего
Распространенные заблуждения
Миф: "O(100n) хуже чем O(n²)"
Реальность: O(100n) = O(n) — константы отбрасываются
Миф: "Big O описывает точное время выполнения"
Реальность: Big O описывает скорость роста, а не конкретные временные значения
Миф: "Алгоритм O(log n) всегда быстрее O(n)"
Реальность: При малых n константные факторы могут сделать O(n) быстрее
#Java #для_новичков #beginner #algorithm #bigO
👍4
Что выведет код?
#Tasks
public class Task090126 {
public static void main(String[] args) {
int n = 10;
int count = 0;
for (int i = 1; i <= n; i++) {
for (int j = i; j <= n; j += i) {
count++;
}
}
System.out.println(count);
}
}#Tasks
👍3
👍3
Почему Stream нельзя переиспользовать? 🤓
Ответ:
Stream — одноразовый конвейер. После terminal-операции он считается закрытым.
Это сделано для предотвращения побочных эффектов и обеспечения ленивых вычислений.
Повторное использование нарушило бы контракт исполнения.
#собеседование
Ответ:
Это сделано для предотвращения побочных эффектов и обеспечения ленивых вычислений.
Повторное использование нарушило бы контракт исполнения.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5👍2
История IT-технологий сегодня — 10 января
ℹ️ Кто родился в этот день
Дональд Эрвин Кнут (англ. Donald Ervin Knuth, МФА: /kəˈnuːθ/ Шаблон:Respel; род. 10 января 1938 года, Милуоки, штат Висконсин) — американский учёный в области информатики, доктор философии (1963), эмерит-профессор Стэнфордского университета, член Американского философского общества (2012), преподаватель и идеолог программирования, автор 19 монографий (в том числе ряда классических книг по программированию) и более 160 статей, разработчик нескольких известных программных технологий. Является автором всемирно известной серии книг, посвящённой основным алгоритмам и методам вычислительной математики, а также создателем настольных издательских систем TeX и METAFONT, предназначенных для набора и вёрстки книг научно-технической тематики (в первую очередь — физико-математических).
🌐 Знаковые события
2001 — первый выход в свет Wikipedia как части «Нупедии». Через 5 дней Wikipedia становится самостоятельным сайтом.
#Biography #Birth_Date #Events #10Января
Дональд Эрвин Кнут (англ. Donald Ervin Knuth, МФА: /kəˈnuːθ/ Шаблон:Respel; род. 10 января 1938 года, Милуоки, штат Висконсин) — американский учёный в области информатики, доктор философии (1963), эмерит-профессор Стэнфордского университета, член Американского философского общества (2012), преподаватель и идеолог программирования, автор 19 монографий (в том числе ряда классических книг по программированию) и более 160 статей, разработчик нескольких известных программных технологий. Является автором всемирно известной серии книг, посвящённой основным алгоритмам и методам вычислительной математики, а также создателем настольных издательских систем TeX и METAFONT, предназначенных для набора и вёрстки книг научно-технической тематики (в первую очередь — физико-математических).
2001 — первый выход в свет Wikipedia как части «Нупедии». Через 5 дней Wikipedia становится самостоятельным сайтом.
#Biography #Birth_Date #Events #10Января
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
С 27.12 по 09.01
Предыдущий пост(с 20.12 по 26.12)
Воскресный мотивационный пост:
Вот и пришёл 2026 год 🎄
Запись встреч/видео:
Tree в Java. Самая сложная коллекция.
OrderHub. Эволюция проекта из монолита к production-ready микросервису
1. Старт серии. Создаём основу для production-системы
Обучающие статьи:
Java:
Глава 8. Дополнительные аспекты коллекций
Потокобезопасные коллекции и типичные ошибки
Практика
Раздел 7. Алгоритмы
Глава 1: Основы анализа алгоритмов
Временная сложность и Big O нотация: язык анализа алгоритмов
Глубокая архитектура и внутреннее устройство RabbitMQ
AMQP 1.0 vs AMQP 0-9-1: эволюция протокола
Введение: Современный стек для production
Паттерны использования и гарантии доставки в RabbitMQ
Полезные статьи и видео:
ПОДКЛЮЧЕНИЕ GPT GO на ГОД!
Моя первая статья на хабре
Field vs Constructor Injection в Java: ошибка объектного дизайна или вопрос синтаксиса?
Как и всегда, задачи можно найти под тегом - #Tasks, вопросы с собеседований - #собеседование
Предыдущий пост(с 20.12 по 26.12)
Воскресный мотивационный пост:
Вот и пришёл 2026 год 🎄
Запись встреч/видео:
Tree в Java. Самая сложная коллекция.
OrderHub. Эволюция проекта из монолита к production-ready микросервису
1. Старт серии. Создаём основу для production-системы
Обучающие статьи:
Java:
Глава 8. Дополнительные аспекты коллекций
Потокобезопасные коллекции и типичные ошибки
Практика
Раздел 7. Алгоритмы
Глава 1: Основы анализа алгоритмов
Временная сложность и Big O нотация: язык анализа алгоритмов
Глубокая архитектура и внутреннее устройство RabbitMQ
AMQP 1.0 vs AMQP 0-9-1: эволюция протокола
Введение: Современный стек для production
Паттерны использования и гарантии доставки в RabbitMQ
Полезные статьи и видео:
ПОДКЛЮЧЕНИЕ GPT GO на ГОД!
Моя первая статья на хабре
Field vs Constructor Injection в Java: ошибка объектного дизайна или вопрос синтаксиса?
Как и всегда, задачи можно найти под тегом - #Tasks, вопросы с собеседований - #собеседование
🔥2
Всем привет! 👌
А давайте завтра встретимся? И запишем видео как написать своего AI бота в телеге?☺️
В нагрузку покажу основные фишки нового обновления Telegram API v9.3.👏
Кто придет?🤨
А давайте завтра встретимся? И запишем видео как написать своего AI бота в телеге?
В нагрузку покажу основные фишки нового обновления Telegram API v9.3.
Кто придет?
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🔥1
История IT-технологий сегодня — 11 января
ℹ️ Кто родился в этот день
Мэтью «Мэтт» Чарльз Мулленвег (англ. Matthew Charles "Matt" Mullenweg; 11 января 1984 года, Хьюстон, Техас, США) — американский программист, предприниматель, менеджер и музыкант; создатель и основной разработчик распространяемой по лицензии GNU GPL системы управления содержимым сайта с открытым исходным кодом WordPress; основатель, владелец и руководитель девелоперской компании Automattic и некоммерческой организации WordPress Foundation, поддерживающей инфраструктуру WordPress; член совета директоров некоммерческого издания Grist; поддерживает ряд филантропических организаций, в частности Архив Интернета, Electronic Frontier Foundation, Фонд свободного программного обеспечения, Long Now Foundation и Innocence Project; участник и докладчик множества международных конференций.
🌐 Знаковые события
1700 — в России вместо византийского календаря введён юлианский календарь. После 31 декабря 7208 года наступило 1 января 1700 года. Начало года перенесёно на 1 января.
1787 — Уильям Гершель открыл Титанию и Оберон — спутники планеты Уран.
2011 — Прекращена общая поддержка операционной системы Windows XP Service Pack 3.
2022 — прекращена основная поддержка Windows Server 2016.
#Biography #Birth_Date #Events #11Января
Мэтью «Мэтт» Чарльз Мулленвег (англ. Matthew Charles "Matt" Mullenweg; 11 января 1984 года, Хьюстон, Техас, США) — американский программист, предприниматель, менеджер и музыкант; создатель и основной разработчик распространяемой по лицензии GNU GPL системы управления содержимым сайта с открытым исходным кодом WordPress; основатель, владелец и руководитель девелоперской компании Automattic и некоммерческой организации WordPress Foundation, поддерживающей инфраструктуру WordPress; член совета директоров некоммерческого издания Grist; поддерживает ряд филантропических организаций, в частности Архив Интернета, Electronic Frontier Foundation, Фонд свободного программного обеспечения, Long Now Foundation и Innocence Project; участник и докладчик множества международных конференций.
1700 — в России вместо византийского календаря введён юлианский календарь. После 31 декабря 7208 года наступило 1 января 1700 года. Начало года перенесёно на 1 января.
1787 — Уильям Гершель открыл Титанию и Оберон — спутники планеты Уран.
2011 — Прекращена общая поддержка операционной системы Windows XP Service Pack 3.
2022 — прекращена основная поддержка Windows Server 2016.
#Biography #Birth_Date #Events #11Января
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Telegram AI Bot. Версия Telegram API 9.3+
В этом видео мы разбираем реальное обновление Telegram Bot API, которое наконец делает стриминг ответов в Telegram нативным, без костылей и бесконечных EditMessageText.
Бота пишем самого простого, просто в целях демонстрации, не более.
Сама демонстрация работы в самом конце)
Показываю и объясняю на живом Java-проекте:
🔹Long Polling (без webhook и ngrok)
🔹Spring Boot + Spring AI
🔹Потоковые ответы от LLM
🔹Новый механизм sendMessageDraft
🔹Автоматическую работу по замене названий в forum topics
⚠️ sendMessageDraft работает только в темах форума
⚠️ В Java SDK метод sendMessageDraft ещё не реализован — показываю, как добавить вручную
Исходный код проекта на GitHub очень ждет Ваших звезд.
Ссылка на Youtube
Ссылка на Рутьюб
Смотрите, ставьте лайки, подписывайтесь на каналы!✌️
В этом видео мы разбираем реальное обновление Telegram Bot API, которое наконец делает стриминг ответов в Telegram нативным, без костылей и бесконечных EditMessageText.
Бота пишем самого простого, просто в целях демонстрации, не более.
Сама демонстрация работы в самом конце)
Показываю и объясняю на живом Java-проекте:
🔹Long Polling (без webhook и ngrok)
🔹Spring Boot + Spring AI
🔹Потоковые ответы от LLM
🔹Новый механизм sendMessageDraft
🔹Автоматическую работу по замене названий в forum topics
⚠️ sendMessageDraft работает только в темах форума
⚠️ В Java SDK метод sendMessageDraft ещё не реализован — показываю, как добавить вручную
Исходный код проекта на GitHub очень ждет Ваших звезд.
Ссылка на Youtube
Ссылка на Рутьюб
Смотрите, ставьте лайки, подписывайтесь на каналы!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥3 1