PascalABC.NET официальный канал
الذهاب إلى القناة على Telegram
Официальный канал языка и системы программирования PascalABC.NET
إظهار المزيد1 859
المشتركون
-124 ساعات
-117 أيام
-2630 أيام
أرشيف المشاركات
📚 Анализ больших текстов в PascalABC.NET, Использование словарей 📚
Сегодня расскажем, как PascalABC.NET позволяет легко анализировать большой текст и получать ценную статистику! Взяв для примера текст "Властелин колец", мы сможем узнать, какие слова разной длины встречаются наиболее часто.
Рассмотрим следующий код:
begin
var a := ReadAllText('LordOfTheRings.txt').ToLower.ToWords(AllDelimiters)
.Where(w -> w[1] in 'а'..'я');
for var i:=2 to 10 do
a.Where(w -> w.Length = i)
.EachCount
.OrderByDescending(kv -> kv.Value).Take(5).Println;
end.
👀 Что делает этот код?
🔹 Загружает текст из файла, приводит его к нижнему регистру и разбивает на слова, используя константу AllDelimiters как разделители.
🔹 Оставляет только те слова, которые начинаются с русских букв.
🔹 С помощью метода EachCount получает словарь частот слов заданной длины.
🔹 Сортирует слова по их длине (от 2 до 10 символов) и подсчитывает частоту каждого слова.
🔹 Выводит самые популярные слова для каждой длины, помогая понять, какие слова наиболее часто встречаются.
✨ Почему это удобно? Работа с текстом в PascalABC.NET позволяет:
🔹 Легко анализировать большие текстовые данные,
🔹 Использовать встроенные методы Where, EachCount, OrderByDescending, Println и многие другие для фильтрации и сортировки данных,
🔹 Проводить быстрый и наглядный анализ, который можно адаптировать под любой текст.
Попробуйте адаптировать этот пример под свои тексты и узнайте, как часто и какие слова встречаются!🔹 Лямбда-выражения в PascalABC.NET: преобразования, условия и проекции
Лямбда-выражения в PascalABC.NET дают возможность упростить и улучшить код. Важно понимать, что лямбда-выражения делятся на три основные группы: лямбда-преобразования, лямбда-условия и лямбда-проекции. Давайте разберем каждый вид с примерами.
1. Лямбда-преобразования
Лямбда-преобразование используется для преобразования данных. Оно может оставлять тип данных без изменений или переводить элементы в другой тип. Рассмотрим оба варианта:
Преобразование к тому же типу. В этом примере каждый элемент массива возводится в квадрат, оставаясь числом.
var a := Arr(1, 2, 3, 4, 5);
var squares := a.Select(x -> x * x); // Числа преобразуются в их квадраты
a := squares.ToArray; // Результат можно присвоить тому же массиву
Println(squares); // Вывод: [1, 4, 9, 16, 25]
Преобразование к другому типу. Следующий пример показывает перевод чисел в строки, представляя каждое число текстом:
var a := Arr(1, 2, 3, 4, 5);
var strValues := a.Select(x -> x.ToString); // Числа преобразуются в строки
Println(strValues); // Вывод: ['1', '2', '3', '4', '5']
В обоих случаях метод Select позволяет эффективно преобразовывать данные: в первом случае, чтобы получить квадраты чисел, во втором — текстовое представление чисел.
2. Лямбда-условия
Лямбда-условия применяются для фильтрации элементов по критерию. В примере ниже отбираются только четные числа:
var a := Arr(1, 2, 3, 4, 5, 6);
var evenNumbers := a.Where(x -> x mod 2 = 0); // Отбираются только чётные числа
Println(evenNumbers); // Вывод: [2, 4, 6]
Метод Where использует условие x -> x mod 2 = 0, чтобы выбрать только числа, делящиеся на 2 без остатка.
3. Лямбда-проекции
Лямбда-проекция применяется, когда нужно извлечь часть составного объекта. В примере ниже из массива кортежей извлекаются только названия фруктов:
var items := Arr(('apple', 1.5), ('banana', 1.2), ('cherry', 0.9));
var fruitNames := items.Select(x -> x[0]); // Извлекается только название фрукта
Println(fruitNames); // Вывод: ['apple', 'banana', 'cherry']
Метод Select создает проекцию x -> x[0], возвращая первую часть кортежа x.
Подводим итоги:
✦ Лямбда-преобразования помогают изменить значение элемента, сохраняя или меняя его тип.
✦ Лямбда-условия отбирают данные по критерию.
✦ Лямбда-проекции полезны для извлечения частей составных объектов.
Пользуйтесь этими возможностями, чтобы сделать ваш код лаконичнее и понятнее! 🚀Работа с форматом JSON
Дорогие подписчики! Сегодня мы расскажем о том, как легко и удобно работать с форматом JSON в PascalABC.NET с использованием библиотеки Newtonsoft.Json. JSON (JavaScript Object Notation) — это текстовый формат для представления структурированных данных на основе синтаксиса JavaScript. Он стал стандартом де-факто для обмена данными в веб-приложениях и широко используется благодаря своей простоте и удобству.
💻 Предлагаем вашему вниманию небольшой пример кода, который демонстрирует разбор сложной JSON-структуры и вывод ее содержимого в консоль с русскими названиями полей. Обратите внимание на легкость доступа к вложенным объектам и массивам:
uses Newtonsoft.Json.Linq;
begin
// Считываем содержимое JSON из файла
var jsonString := ReadAllText('data.json');
// Разбор JSON-строки в объект JObject
var jsonObject := JObject.Parse(jsonString);
// Доступ к верхнему уровню объекта "человек"
var person := jsonObject['человек'];
// Извлечение простых значений
var name := person['имя'].ToString;
var age := person['возраст'].ToObject&<integer>;
var isStudent := person['являетсяСтудентом'].ToObject&<boolean>;
// Доступ к вложенному объекту "контакты"
var contacts := person['контакты'];
var email := contacts['электроннаяПочта'].ToString;
var phone := contacts['телефон'].ToString;
// Доступ к массиву "хобби"
var hobbies := person['хобби'];
var hobbyList := hobbies.ToObject&<array of string>;
// Вывод извлеченных данных с ручным выравниванием
Println($'Имя: {name}');
Println($'Возраст: {age}');
Println($'Является студентом: {isStudent}');
Println($'Электронная почта: {email}');
Println($'Телефон: {phone}');
// Объединение элементов массива хобби в строку и вывод
Println($'Хобби: {hobbyList.JoinToString('', '')}');
end.
В этом примере форматированный вывод поможет вам легко читать данные, а использование русских названий для полей делает код более понятным. 🌟
Файл data.json имеет следующее содержимое:
{
"человек": {
"имя": "Иван",
"возраст": 30,
"являетсяСтудентом": false,
"контакты": {
"электроннаяПочта": "ivan@example.com",
"телефон": "123-456-7890"
},
"хобби": ["чтение", "путешествия", "плавание"]
}
}
🚀 Пробуйте работать с JSON в своих проектах на PascalABC.NET и делитесь своими впечатлениями в комментариях! Мы всегда рады услышать ваше мнение и поддержать новые идеи. 💬
#PascalABCNET #JSON #DataParsingПрисваивание и сравнение динамических массивов
Работа с массивами в PascalABC.NET имеет свои особенности, особенно если речь идёт о динамических массивах. В этой новости разберём, как правильно присваивать, копировать и сравнивать такие массивы.
🔹 Присваивание динамических массивов
Когда вы присваиваете один динамический массив другому через оператор :=, происходит ссылочное присваивание. Это означает, что обе переменные ссылаются на один и тот же массив в памяти. Любые изменения в одном массиве автоматически отразятся на другом.
Пример:
var a := new integer[5]; // Создаём массив
var b := a; // b ссылается на тот же массив,что и a
b[0] := 10; // Теперь и a[0], и b[0] равны 10
Чтобы создать независимую копию массива, следует использовать встроенную функцию Copy(a).
Пример:
var a := new integer[5]; // Создаём массив
var b := Copy(a); // b — это копия массива a
b[0] := 10; // Изменение b не затрагивает a
🔹 Сравнение массивов
✦ Прямое сравнение массивов через оператор = проверяет ссылки, а не содержимое массивов. Даже если два массива содержат одинаковые элементы, они будут считаться неравными, если ссылаются на разные объекты в памяти.
Пример
var a, b: array of integer;
a := new integer[5];
b := new integer[5];
if a = b then // это сравнение вернёт False
Println('Массивы равны')
else
Println('Массивы не равны');
✦ Для корректного сравнения содержимого массивов в PascalABC.NET нужно использовать метод ArrEqual, который проверяет, равны ли все элементы двух массивов.
Пример:
var a := new integer[5];
var b := new integer[5];
if a.ArrEqual(b) then // Проверяет равенство всех элементов массива
Println('Массивы равны')
else
Println('Массивы не равны');
🔹 Итоги:
✦ Для копирования массива используйте функцию Copy(a), чтобы избежать ссылочного присваивания.
✦ Для сравнения содержимого массивов используйте метод ArrEqual.
Это поможет вам избежать ошибок при работе с динамическими массивами и сделает ваш код более предсказуемым и надёжным! 🚀Операции с массивами
Операции + и * с массивами позволяют быстро и эффективно конструировать массивы, заполняя их значениями. Для непрерывного диапазона элементов помогает также конструкция Arr(1..3).
Задание - из реального урока в компьютерной школе, под контролем системы невидимой автоматической проверки.
Сортировка выбором - минимизация обменов
Алгоритм сортировки выбором является одним из самых простых для понимания, но его можно улучшить! В стандартной реализации количество обменов может быть избыточным, так как обмен выполняется всегда, даже если текущий элемент уже на своём месте.
В улучшенной версии сортировки выбором проверяется, найдено ли новое минимальное значение, и обмен выполняется только в случае необходимости. Это позволяет сократить число обменов, что особенно полезно для массивов, которые уже частично отсортированы.
Новый алгоритм выглядит так:
procedure SortByChoice(a: array of integer);
begin
var n := a.Length;
for var i := 0 to a.Length - 2 do
begin
var imin := i;
for var j := i + 1 to n - 1 do
if a[j] < a[imin] then
imin := j;
if imin <> i then
Swap(a[imin], a[i]);
end;
end;
🔥 Теперь алгоритм работает эффективнее за счёт уменьшения количества обменов! 🔥 Пробуйте и внедряйте это улучшение в свои программы! 🚀Copilot - задача о поиске двух первых минимумов в массиве
Два запроса - два отличных ответа!
begin
var arr := ArrRandomInteger(10);
var min1, min2 := (MaxInt, MaxInt);
foreach var x in arr do
if x < min1 then
(min1, min2) := (x, min1)
else if x < min2 then
min2 := x;
Println('Сгенерированный массив: ', arr);
Println('Первый минимум: ', min1);
Println('Второй минимум: ', min2);
end.
и
begin
var arr := ArrRandomInteger(10);
var min1 := arr.Min();
var min2 := arr.Where(x -> x <> min1).Min();
Println('Сгенерированный массив: ', arr);
Println('Первый минимум: ', min1);
Println('Второй минимум: ', min2);
end.Логирование в PascalABC.NET
✦ Устанавливаем пакет NLog командой nuget install NLog.
✦ Копируем dll в папку проекта
✦ Создаем конфигурационный файл nlog.config:
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<targets>
<target xsi:type="File" name="logfile" fileName="log.txt" />
</targets>
<rules>
<logger name="*" minlevel="Info" writeTo="logfile" />
</rules>
</nlog>
✦ Просим Copilot написать программу для логирования:
{$reference 'NLog.dll'}
uses NLog;
begin
// Инициализация логгера
LogManager.LoadConfiguration('nlog.config');
var log := LogManager.GetCurrentClassLogger;
// Запись логов
log.Info('Программа запущена');
try
var a := 10;
var b := 0;
var c := a div b; // Это вызовет исключение
except
on e: Exception do
log.Error('Ошибка: ' + e.Message);
end;
log.Info('Программа завершена');
end.
Вуаля!Вычисление средних оценок студентов
Дан словарь оценок студентов. Вычислить для каждого студента среднюю оценку. Результат записать в новый словарь.
Трансформация части элементов массива
На скриншоте показана программа, в которой преобразуется часть элементов массива, удовлетворяющая некоторому условию. Для задания условия используется лямбда с условной операцией.
Используй принцип локальности при описании переменных!
Сегодня напомним об одном важном принципе, который делает ваш код более чистым, понятным и безопасным — принципе локальности при описании переменных.
Принцип локальности подразумевает, что переменные должны объявляться как можно ближе к месту их использования, а не в самом начале программы или функции. Это помогает избежать путаницы и ошибок при работе с переменными, особенно в больших и сложных проектах.
🔹 Почему это важно?
✦ Читаемость: Когда переменные объявляются рядом с кодом, который их использует, легче понять, для чего они нужны.
✦ Минимизация ошибок: Переменные, объявленные локально, реже влияют на другие части программы, что уменьшает шанс на случайные ошибки.
✦ Упрощение отладки: Когда переменная используется только в одном небольшом блоке кода, легче отследить, как она изменяется и откуда берутся значения.
✦ Экономия памяти: Локальные переменные занимают память только в пределах своего блока, что делает код более эффективным.
Использование атрибутов Combinatorial, Values и RangeAttribute при Unit-тестировании
Атрибуты Combinatorial, Values и RangeAttribute позволяют легко задавать разные наборы данных для тестов.
🔹 Combinatorial
Этот атрибут помогает комбинировать несколько наборов данных, применяемых к параметрам теста.
🔹 Values
С помощью атрибута Values можно указать несколько значений для одного параметра теста. Когда тест запускается, он выполняется с каждым из заданных значений, что позволяет проверить работу функции сразу на множестве входных данных.
🔹 RangeAttribute
Атрибут RangeAttribute позволяет указать диапазон значений, которые будут использоваться для параметра теста.
Использование этих атрибутов особенно полезно для тестирования методов с числовыми параметрами, чтобы покрыть различные диапазоны входных данных.
🧪 Unit-тестирование в PascalABC.NET
Один из лучших способов убедиться, что ваш код работает корректно, — это Unit-тестирование. В PascalABC.NET вы можете использовать популярный инструмент для тестирования — NUnit, который интегрирован в модуль NUnitABC. Изображенную на скрине программу надо запустить, используя Ctrl-Shift-T.
Тестирование с помощью NUnit — это не просто проверка кода, а способ сделать ваш проект стабильным, качественным и лёгким в поддержке. Внедряйте Unit-тестирование в ваш рабочий процесс, и ваши приложения станут надёжнее! 🚀
😈 Вредные советы для программистов на PascalABC.NET 😈
🎃 Совет 1: Никогда не проверяй код на ошибки. Если программа откомпилировалась — значит, всё работает идеально! А баги? Это фантазии пользователей.
🎃 Совет 2: Прояви немного уважения к программистам прошлого — объявляй все переменные до beginа основной программы. Зачем их размещать в блоке begin-end? Пусть поиск места первого присваивания такой переменной станет увлекательным квестом!
🎃 Совет 3: Используй глобальные переменные как можно больше! Глобальные переменные очень удобны, т. к. к ним можно обращаться отовсюду! И чем больше глобальных переменных — тем веселее искать причину ошибок!
🎃 Совет 4: Никогда не пиши комментарии. Пусть будущее поколение программистов с удивлением гадает, зачем этот код вообще существует.
🎃 Совет 5: Лишние скобки? Не заморачивайся, всё равно PascalABC.NET их поймёт! А ещё лучше — перемешивай их везде, где можно. Чем больше скобок, тем надёжнее программа!
🎃 Совет 6: Пиши всё в одну строку! Пробелы и отступы — для слабаков. Пусть коллеги попробуют разобрать этот шедевр без форматирования! И так код будет быстрее компилироваться!
🎃 Совет 7: Обязательно используй названия переменных вида a, b, c. Чем короче имя — тем быстрее работаешь. А тот, кто разберётся, что такое x9, будет настоящим героем!
🎃 Совет 8: Никогда не обновляй PascalABC.NET! Работает старая версия 2010 года? Зачем тогда что-то менять? Современные фишки — это излишество.
🎃 Совет 9: Писать тесты? Забудь! Тесты — для слабаков. Настоящие программисты сразу выкатывают код в продакшен!
🎃 Совет 10: Используй магические числа вместо констант. Пусть твой код выглядит загадочно и мистически! Никто не должен догадаться, зачем ты использовал 42 в каждом цикле.
🎃 Совет 11: Если что-то не работает, то, скорее всего, глючит компилятор. Попробуйте поменять местами некоторые переменные и строки кода.
🎃 Совет 12: Не пользуйся стандартной библиотекой языка! Что может быть интереснее, чем написать собственный алгоритм сортировки или собственное бинарное дерево? В своём коде уж точно не будет ошибок, а вот в стандартных функциях - ещё неизвестно!
🎃 Совет 13: Смело сравнивай числа с плавающей точкой с помощью операции =. Раз есть такая операция, значит ей нужно пользоваться.
🎃 Совет 14: Зачем инициализировать переменные, если там и так нули? Я вот недавно не инициализировал, и там ноль был. Всё работало.
🎃 Совет 15: Нет времени думать, копируй код многократно! Повторение — мать учения!
🎃 Совет 16: Выравнивание и единый стиль не дают раскрыться вашей индивидуальности и креативности. Это притеснение свободы личности и самовыражения. Каждый должен оформлять код так, как ему нравится.
🎃 Совет 17: Экономь память. Используй одну переменную для разных целей!
🎃 Совет 18: Статический массив — лучшее решение. И вообще, выделение памяти — зло. array[1..256] хватит всем, а если не хватит, то потом поменяем на 512. В крайнем случае – на 1024.
🎃 Совет 19: Если что-то не работает — просто добавь больше if-else. Логика обязательно сложится, а если нет, добавь ещё несколько уровней условий!
🎃 Совет 20: Настоящие программисты программируют только на PascalABC.NET. В крайнем случае на C++. И обязательно ругают Python!
😎 Эти советы точно помогут вам стать супер-программистом и на голову превзойти всех конкурентов! Научившись применять эти рекомендации на PascalABC.NET, используйте их затем и для других языков — они универсальны!
Снежинка Коха
Сегодня поговорим о создании одного из самых известных фракталов — снежинки Коха.
uses Turtle;
procedure Koch(sz: real; n: integer);
begin
if n = 0 then
Forw(sz)
else begin
Koch(sz/3,n-1); Turn(-60);
Koch(sz/3,n-1); Turn(120);
Koch(sz/3,n-1); Turn(-60);
Koch(sz/3,n-1);
end;
end;
begin
Window.Title := 'Снежинка Коха';
Turn(90);
Forw(-10);
Down;
Koch(20,5);
end.
Программа построения снежинки Коха использует модуль Turtle. Алгоритм заключается в следующем:
Базовый случай: Если глубина рекурсии n=0, то рисуем отрезок длиной sz.
Рекурсивный случай: Если n>0:
✦ Разбиваем отрезок на три части.
✦ Рисуем первую треть отрезка и поворачиваем на 60° влево.
✦ Рисуем первую часть писка и поворачиваем на 120° вправо.
✦ Рисуем вторую часть пика и поворачиваем на 60° влево
✦ Рисуем последнюю треть отрезка.
Процесс повторяется для каждой стороны, добавляя всё больше деталей на каждом шаге.
#рекурсия #графикаБиблиотеки в PascalABC.NET
Вот слайд с сегодняшней лекции по библиотекам.
Библиотеки отличаются от модулей по нескольким параметрам.
🔍 Метод Ньютона: Быстрый способ нахождения корней уравнений
Метод Ньютона — популярный численный метод нахождения корней уравнений с квадратичной сходимостью.
Метод Ньютона используется для нахождения корня функции, исходя из начального приближения, и работает за счет последовательных касательных к графику функции. На каждой итерации приближение улучшается, что позволяет с большой точностью находить корни сложных уравнений. Метод Ньютона работает гораздо быстрее метода половинного деления.
Метод Ньютона особенно эффективен для задач, где производная функции не равна нулю в окрестности корня.
function f(x: real) := exp(x) - 4;
function df(x: real) := exp(x); // Производная f'(x) = exp(x)
function NewtonMethod(x, eps: real): real;
begin
while abs(f(x)) > eps do
x := x - f(x) / df(x);
Result := x;
end;
begin
var x := 0.5; // Начальное приближение
var eps := 0.00001;
var root := NewtonMethod(x, eps);
Println('Корень уравнения: ', root);
end.📝 Метод половинного деления: простой и эффективный способ нахождения корней уравнений
Один из классических численных методов — метод половинного деления. Этот метод позволяет находить корни нелинейных уравнений с высокой точностью. Его особенность заключается в том, что он работает на отрезке, где функция непрерывна и меняет знак, и последовательно делит этот отрезок пополам, приближаясь к решению.
Метод прост в реализации и гарантированно сойдется, если на выбранном интервале есть корень.
function f(x: real) := exp(x) - 4;
function BisectionMethod(a, b, eps: real): real;
begin
var fa := f(a); // Вычисляем f(a) один раз в начале
while Abs(b - a) > eps do
begin
var c := (a + b) / 2;
var fc := f(c);
if fc = 0 then
break;
if fa * fc < 0 then
b := c
else
(a, fa) := (c, fc);
end;
Result := (a + b) / 2;
end;
begin
var (a, b) := (0.0, 3.0);
var eps := 0.000001;
var root := BisectionMethod(a, b, eps);
Println('Корень уравнения:', root);
end.Реализация класса SortedMultiset
Перед вами - реализация класса мультимножества, реализованная ChatGPT. Идея использовать для реализации класс SortedDictionary с подсчетом количества дублей также принадлежит ChatGPT. Отличное решение!
Операции добавления, удаления, поиска и получения минимального/максимального элемента выполняются за O(log(n)) благодаря использованию сбалансированного дерева поиска, которое реализовано в SortedDictionary.
type
SortedMultiset<T> = class(IEnumerable<T>)
private
data: SortedDictionary<T, integer>; // Храним элемент и количество его вхождений
public
// Конструктор
constructor Create;
begin
data := new SortedDictionary<T, integer>();
end;
// Метод добавления элемента
procedure Add(x: T);
begin
if data.ContainsKey(x) then
data[x] := data[x] + 1 // Увеличиваем количество вхождений
else
data.Add(x, 1); // Добавляем новый элемент с количеством 1
end;
// Метод удаления элемента
function Remove(x: T): boolean;
begin
if data.ContainsKey(x) then
begin
if data[x] > 1 then
data[x] := data[x] - 1 // Уменьшаем количество вхождений
else
data.Remove(x); // Удаляем элемент, если это последнее вхождение
Result := true;
end
else
Result := false;
end;
// Метод получения количества вхождений элемента
function Count(x: T): integer;
begin
if data.ContainsKey(x) then
Result := data[x]
else
Result := 0;
end;
// Метод для получения минимального элемента
function Min: T;
begin
if data.Count = 0 then
raise new System.InvalidOperationException('Мультимножество пусто.');
Result := data.Keys.First(); // Первый элемент в отсортированном множестве
end;
// Метод для получения максимального элемента
function Max: T;
begin
if data.Count = 0 then
raise new System.InvalidOperationException('Мультимножество пусто.');
Result := data.Keys.Last(); // Последний элемент в отсортированном множестве
end;
// Метод для получения всех элементов множества
function GetElements: sequence of T;
begin
foreach var key in data.Keys do
for var i := 1 to data[key] do
yield key;
end;
// Реализация интерфейса IEnumerable<T>
function GetEnumerator: IEnumerator<T>;
begin
Result := GetElements().GetEnumerator();
end;
function System.Collections.IEnumerable.GetEnumerator: System.Collections.IEnumerator;
begin
Result := GetElements().GetEnumerator();
end;
// Метод для вывода множества
procedure Print;
begin
foreach var e in self do
Write(e, ' ');
Writeln;
end;
end;
// Пример использования
begin
var multiset := new SortedMultiset<integer>();
multiset.Add(5);
multiset.Add(3);
multiset.Add(5);
multiset.Add(2);
multiset.Print(); // Вывод: 2 3 5 5
multiset.Remove(5);
multiset.Print(); // Вывод: 2 3 5
Writeln('Min: ', multiset.Min); // Вывод: Min: 2
Writeln('Max: ', multiset.Max); // Вывод: Max: 5
Writeln('Количество 5: ', multiset.Count(5)); // Вывод: Количество 5: 1
multiset.Println;
end.Алгоритм выбора первых k максимумов
В данном алгоритме, частично сгенерированным ChatGpt, приведен алгоритм получения первых k максимумов в массиве. Используется минимальная куча, моделируемая SortedSet. Поскольку SortedSet удаляет дубли, то в конце приходится снова проходиться по массиву и отбирать все элементы, совпадающие с элементами кучи.
Асимптотическая сложность при этом остаётся равной O(n log(k)).
Алгоритм привлекает своей простотой
function GetTopKMaximums(arr: array of integer; k: integer): array of integer;
begin
var minHeap := new SortedSet<integer>(arr.Take(k));
for var i := k to arr.Length - 1 do
if arr[i] > minHeap.Min then
begin
minHeap.Remove(minHeap.Min);
minHeap.Add(arr[i]);
end;
// Преобразуем кучу в массив
Result := arr.Where(x -> x in minHeap).OrderDescending.ToArray
end;
begin
var arr := |3, 1, 4, 2, 5, 9, 7, 7, 6|;
var k := 4;
var topKMaxs := GetTopKMaximums(arr, k);
Print($'Первые {k} максимума(ов):', topKMaxs);
end.
#алгоритмы