Ответы на теоретические вопросы по ПМ.01
1. Порождающие паттерны проектирования
Паттерн проектирования — это часто встречающееся решение определённой проблемы при проектировании архитектуры программ.
Описания паттернов обычно очень формальны и чаще всего состоят из таких пунктов: 
•	проблема, которую решает паттерн; 
•	мотивации к решению проблемы способом, который предлагает 
•	паттерн; 
•	структуры классов, составляющих решение; 
•	примера на одном из языков программирования; 
•	особенностей реализации в различных контекстах; 
•	связей с другими паттернами.
Порождающие паттерны беспокоятся о гибком создании объектов без внесения в программу лишних зависимостей.
Фабричный метод — это порождающий паттерн проектирования, который определяет общий интерфейс для создания объектов в суперклассе, позволяя подклассам изменять тип создаваемых объектов. 
Абстрактная фабрика — это порождающий паттерн проектирования, который позволяет создавать семейства связанных объектов, не привязываясь к конкретным классам создаваемых объектов.
Строитель — это порождающий паттерн проектирования, который позволяет создавать сложные объекты пошагово. Строитель даёт возможность использовать один и тот же код строительства для получения разных представлений объектов.
Прототип — это порождающий паттерн проектирования, который позволяет копировать объекты, не вдаваясь в подробности их реализации.
Одиночка — это порождающий паттерн проектирования, который гарантирует, что у класса есть только один экземпляр, и предоставляет к нему глобальную точку доступа.
2. Оценка сложности алгоритма
Оценка сложности алгоритма определяет, как растет время выполнения алгоритма с увеличением размера входных данных. Основные обозначения: - O(1) - константное время (не зависит от размера входных данных) - O(log n) - логарифмическая сложность - O(n) - линейная сложность - O(n log n) - линейно-логарифмическая сложность - O(n²) - квадратичная сложность - O(2ⁿ) - экспоненциальная сложность
Оценивается: - Временная сложность - время выполнения - Пространственная сложность - объем используемой памяти
3. Особенности организации взаимодействия низкоуровневого системного ПО с памятью: Режимы адресации
Взаимодействие низкоуровневого системного ПО с памятью имеет существенные особенности, о которых стоит упомянуть. Одним из ключевых аспектов является режим адресации. Рассмотрим основные режимы адресации, используемые в системном программировании:
Прямой адресацией
   - В этом режиме адрес памяти указывается непосредственно в инструкции. Прямой доступ к памяти упрощает управление, но ограничивает количество доступных адресов.
Косвенной адресацией
   - Адреса указываются не напрямую, а через указатель, который может находиться в регистре или по заданному адресу. Этот способ позволяет работать с более крупными объемами данных.
Регистровой адресацией
   - Операнды находятся в регистрах процессора. Это обеспечивает высокую скорость доступа, так как операции выполняются напрямую над регистрами.
Фрагментарной адресацией
   - В этом режиме память делится на сегменты. Каждому сегменту присваивается базовый адрес, и доступ к данным происходит через смещение от этого адреса. Это упрощает управление памятью и обеспечивает защиту.
Страничной адресацией
   - Память делится на страницы фиксированного размера, что позволяет эффективно использовать виртуальную память. Эта схема упрощает перераспределение памяти и управление ею.
Индексной адресацией
   - Используются индексы для обращения к массивам и структурам данных. Адрес вычисляется с учетом базового адреса и значения индекса, что упрощает работу с последовательностями.
Автоинкрементная автоуменьшенная адресация
   - Позволяет автоматически увеличивать или уменьшать адрес после доступа к памяти, что удобно для перебора массивов и структур данных.
Эти режимы адресации определяют, как система управляет доступом к памяти и как программы могут эффективно взаимодействовать с аппаратным обеспечением. Выбор режима адресации может оказывать значительное влияние на производительность и эффективное использование ресурсов.
4. Виды ошибок
•	Синтаксические ошибки - нарушения правил языка программирования
•	Семантические ошибки - логические ошибки, которые не нарушают синтаксис
•	Ошибки времени выполнения - возникают во время работы программы (деление на ноль, выход за границы массива)
•	Логические ошибки - программа работает, но результат не соответствует ожиданиям
•	Ошибки совместимости - возникают при взаимодействии с другими системами
•	Ошибки производительности - неэффективное использование ресурсов
•	Утечки памяти - неосвобождение выделенной памяти
-----------------------------------------------------------------------------------------------------------------------------
Ошибка в программировании (или так называемый баг) – это ситуация у разработчиков, при которой определенный код вследствие обработки выдает неверный результат
•	Синтаксические – нарушение правил языка.
•	Логические – неверный алгоритм.
•	Ошибки времени выполнения (exceptions) – деление на ноль, выход за границы массива.
•	Взаимодействия – подразумевается взаимодействие с аппаратным или программным окружением. Пример – ошибка при использовании веб-протоколов. Это приведет к тому, что облачный сервис не будет нормально функционировать;
•	Компиляционные – встречается при разработке на языках высокого уровня. Во время преобразований в машинный тип «что-то идет не так». Причиной служат синтаксические ошибки или сбои непосредственно в компиляторе;
•	Ресурсные – сбои вроде «переполнение буфера» или «нехватка памяти»;
•	Арифметические;
•	Среды выполнения.
5. Паттерны поведения
Поведенческие паттерны проектирования (англ. Behavioral patterns) — это шаблоны, которые определяют алгоритмы и способы реализации взаимодействия различных объектов и классов. Они описывают механизмы коммуникации между компонентами и помогают организовать более гибкую и расширяемую архитектуру
Итератор — это поведенческий паттерн проектирования, который даёт возможность последовательно обходить элементы составных объектов, не раскрывая их внутреннего представления. 
Наблюдатель — это поведенческий паттерн проектирования, который создаёт механизм подписки, позволяющий одним объектам следить и реагировать на события, происходящие в других объектах. 
Состояние — это поведенческий паттерн проектирования, который позволяет объектам менять поведение в зависимости от своего состояния. Извне создаётся впечатление, что изменился класс объекта. 
Стратегия — это поведенческий паттерн проектирования, который определяет семейство схожих алгоритмов и помещает каждый из них в собственный класс, после чего алгоритмы можно взаимозаменять прямо во время исполнения программы. Паттерн Стратегия предлагает определить семейство схожих алгоритмов, которые часто изменяются или расширяются, и вынести их в собственные классы, называемые стратегиями. Вместо того, чтобы изначальный класс сам выполнял тот или иной алгоритм, он будет играть роль контекста, ссылаясь на одну из стратегий и делегируя ей выполнение работы. Чтобы сменить алгоритм, вам будет достаточно подставить в контекст другой объект-стратегию. Важно, чтобы все стратегии имели общий интерфейс. Используя этот интерфейс, контекст будет независимым от конкретных классов стратегий. С другой стороны, вы сможете изменять и добавлять новые виды алгоритмов, не трогая код контекста. 
Посетитель — это поведенческий паттерн проектирования, который позволяет добавлять в программу новые операции, не изменяя классы объектов, над которыми эти операции могут выполняться. Паттерн Посетитель предлагает разместить новое поведение в отдельном классе, вместо того чтобы множить его сразу в нескольких классах. Объекты, с которыми должно было быть связано поведение, не будут выполнять его самостоятельно. Вместо этого вы будете передавать эти объекты в методы посетителя. 
Шаблонный метод — это поведенческий паттерн проектирования, который определяет скелет алгоритма, перекладывая ответственность за некоторые его шаги на подклассы. Паттерн позволяет подклассам переопределять шаги алгоритма, не меняя его общей структуры. Паттерн Шаблонный метод предлагает разбить алгоритм на последовательность шагов, описать эти шаги в отдельных методах и вызывать их в одном шаблонном методе друг за другом. Это позволит подклассам переопределять некоторые шаги алгоритма, оставляя без изменений его структуру и остальные шаги, которые для этого подкласса не так важны
6. Уровни тестирования
•	Модульное (Unit) тестирование - проверка отдельных компонентов программы
•	Интеграционное тестирование - проверка взаимодействия между компонентами
•	Системное тестирование - проверка всей системы на соответствие требованиям
•	Приемочное тестирование - проверка системы на соответствие бизнес-требованиям и готовность к выпуску
•	Альфа-тестирование - внутреннее тестирование перед выпуском
•	Бета-тестирование - внешнее тестирование перед выпуском
•	Регрессионное тестирование - проверка, что новые изменения не повредили существующую функциональность
Юнит-тестирование – это первый уровень тестирования программного обеспечения, который используется для проверки того, удовлетворяют ли программные модули заданным требованиям или нет.
Оно предполагает анализ каждого модуля или отдельного компонента программного приложения.
•	Интеграционное тестирование.
Если на первом уровне происходила проверка наличия ошибок в отдельных функциях, то на этом этапе осуществляется проверка самой системы в целом. При интеграционном тестировании тестируются отдельные компоненты или модули программного обеспечения в группе.
Его основная цель – выявление дефектов при взаимодействии между интегрированными компонентами.
•	Системное тестирование.
Третий уровень тестирования программного обеспечения – это системное тестирование, которое используется для проверки функциональных и нефункциональных требований к программному обеспечению.
Это сквозное тестирование, при котором система тестируется как единое целое. Другими словами – это полная проверка продукта, направленная на выявление нерационального использования ресурсов, отсутствия определенных функций, некорректных комбинаций данных, несовместимости с окружением и т. д.
•	Приемочное тестирование.
Существует несколько видов приемочного тестирования:
o	Приемочное пользовательское тестирование (UAT — User Acceptance Testing) – проводится конечным пользователем продукта с целью найти оставшиеся баги перед релизом ПО.
o	Эксплуатационное – выполняется пользователем или администратором в среде, имитирующей реальное рабочее окружение. На этом этапе проверяются функции резервного копирования, аварийное восстановление системы, безопасность.
o	На соответствие контракту – проверка ПО на соответствие спецификации или другим нормативным актам.
o	Альфа – эксплуатационное тестирование на стороне разработчика.
o	Бета – производится без участия разработчиков, на внешней стороне, небольшой группой пользователей перед релизом.
7. Декораторы
Декоратор — структурный паттерн, позволяющий динамически добавлять объектам новую функциональность, оборачивая их в объекты-декораторы
Декораторы – это обертка вокруг функций (или классов) в Python, которая меняет способ работы этой функции. Декоратор абстрагирует свой собственный функционал
def decorator(func):	
    def wrapper():
        print("Дополнительная функциональность")
        func()
    return wrapper

@decorator
def hello():
    print("Hello!")

hello()
Декораторы функций — вызываемые объекты, которые принимают другую функцию в качестве аргумента. Декораторы функций могут производить операции с функцией и возвращают либо саму функцию, либо другую заменяющую её функцию или вызываемый объект
Пример:
@timer
def slow_function():
    # функция будет измерять время своего выполнения
    pass
8. Структура проекта Android-приложения
•	AndroidManifest.xml - основной конфигурационный файл
•	res/ - ресурсы приложения:
–	drawable/ - изображения
–	layout/ - макеты интерфейса
–	values/ - строки, цвета, стили
–	mipmap/ - иконки приложения
•	java/ - исходный код на Java/Kotlin
•	build.gradle - файлы конфигурации сборки
•	assets/ - дополнительные файлы ресурсов
Основные компоненты: - Activity - экран приложения - Fragment - часть пользовательского интерфейса - Service - фоновые процессы - ContentProvider - управление доступом к данным - BroadcastReceiver - обработка системных событий
---------------------------------------------------------------------------------------------------------------------------------
Проект Android может состоять из различных модулей. По умолчанию, когда мы создаем проект, создается один модуль - app. Модуль имеет три подпапки:
•	manifests: хранит файл манифеста AndroidManifest.xml, который описывает конфигурацию приложения иопределяет каждый из компонентов данного приложения.
•	java: хранит файлы кода на языке java, которые структурированы по отдельным пакетам. Так, в папке com.example.helloapp (название которого было указано на этапе создания проекта) имеется по умолчанию файл MainActivity.java с кодом на языке Java, который представляет класс MainActivity, запускаемый по умолчанию при старте приложения
•	res: содержит используемые в приложении ресурсы. Все ресурсы разбиты на подпапки. 
o	папка drawable предназначена для хранения изображений, используемых в приложении. 
o	папка layout предназначена для хранения файлов, определяющих графический интерфейс. По умолчанию здесь есть файл activity_main.xml, который определяет интерфейс для класса MainActivity в виде xml 
o	папки mipmap содержат файлы изображений, которые предназначены для создания иконки приложения при различных разрешениях экрана. 
o	папка values хранит различные xml-файлы, содержащие коллекции ресурсов - различных данных, которые применяются в приложении. По умолчанию здесь есть два файла и одна папка: 
	файл colors.xml хранит описание цветов, используемых в приложении 
	файл strings.xml содержит строковые ресурсы, используемые в приложении 
	папки themes хранит две темы приложения - для светлую (дневную) и темную (ночную)
•	Gradle Scripts содержит ряд скриптов, которые используются при построении приложения
9. Архитектура системных программ
Включает:
•	Ядро ОС — управление ресурсами.
•	Драйверы устройств — взаимодействие с железом.
•	Системные утилиты — обслуживание системы.
Архитектура программного обеспечения — это план или структура, которая описывает, как система организована, как разные её части (компоненты) взаимодействуют между собой и с внешними системами. 
Некоторые причины важности архитектуры:
•	Упрощение работы команды. Чёткая архитектура позволяет разработчикам легко понимать, как устроено приложение.
•	Развитие проекта. Хорошо спроектированная система легко масштабируется и адаптируется к новым требованиям.
•	Снижение сложности. Чем сложнее проект, тем важнее подход к проектированию.
•	Оптимизация взаимодействия. Модули программы работают слаженно, а изменения в одной части не ломают остальные.
Некоторые виды архитектуры:
•	Монолитная. Вся система — это единое целое, где все части тесно связаны. 
•	Микросервисная. Система разбивается на небольшие независимые сервисы, которые взаимодействуют друг с другом.
•	Клиент-серверная. Приложение делится на клиентскую и серверную части.
•	Событийно-ориентированная. Компоненты взаимодействуют через события.
•	Слоистая. Программа организована в виде слоёв, например, презентационный слой, бизнес-логика и база данных.
Основные принципы: - Модульность - Абстракция аппаратуры - Уровни привилегий - Минимизация зависимостей - Оптимизация производительности
10. Стратегии проектирования тестовых наборов данных
Проектирование тестовых данных — это процесс создания входных значений, которые будут использоваться для проверки корректности работы программы. Правильно подобранные тестовые данные помогают выявить ошибки, проверить граничные условия и убедиться в надежности кода.
1. Эквивалентное разделение (Equivalence Partitioning)
•	Суть: Разделение входных данных на классы эквивалентности, где все значения внутри одного класса обрабатываются программой одинаково. Тестируется по одному представителю из каждого класса.
•	Плюсы: Сокращает количество тестов. Покрывает все возможные сценарии.
2. Анализ граничных значений (Boundary Value Analysis)
•	Суть: Тестирование значений на границах классов эквивалентности, так как ошибки часто возникают именно там.
•	Плюсы: Выявляет ошибки в условиях (<=, <, >=, >).
3. Попарное тестирование (Pairwise Testing)
•	Суть: Тестирование всех возможных пар входных параметров вместо полного перебора. Основано на том, что большинство ошибок вызывается взаимодействием двух параметров.
•	Плюсы: Экономит время при сохранении хорошего покрытия.
4. Генерация случайных данных (Random Testing)
•	Суть: Использование случайных значений для тестирования, особенно полезно при нагрузочном тестировании.
•	Плюсы: Может выявить неочевидные ошибки. Полезно для тестирования устойчивости.
•	Минусы: Нет гарантии покрытия всех сценариев.
5. Тестирование на основе состояний (State Transition Testing)
•	Суть: Тестирование переходов между состояниями системы.
•	Плюсы: Полезно для систем с четкими состояниями (например, банкоматы, UI-потоки).
6. Тестирование на основе бизнес-правил (Domain Testing)
•	Суть: Использование данных, соответствующих бизнес-логике приложения.
•	Плюсы: Проверяет реальные сценарии использования.
Выбор стратегии зависит от контекста:
•	Эквивалентное разделение и граничные значения — для проверки валидации.
•	Попарное тестирование — для комбинаций параметров.
•	Случайные данные — для нагрузочного тестирования.
•	Тестирование состояний — для конечных автоматов.
•	Оптимальный подход — комбинация нескольких методов для максимального покрытия.
11. ООП: Наследование
Наследование в объектно-ориентированном программировании — это концепция, согласно которой одни классы, называемые родительскими, могут лежать в основе других — дочерних. При этом, дочерние классы перенимают свойства и поведение своего родителя.
Особенности: - Дочерний класс наследует атрибуты и методы родительского класса - Возможность переопределения методов родительского класса - Расширение функциональности базового класса - Повторное использование кода
Типы наследования: - Одиночное - наследование от одного класса - Множественное - наследование от нескольких классов (поддерживается не во всех языках) - Многоуровневое - класс наследуется от класса, который наследуется от другого класса - Иерархическое - несколько классов наследуются от одного базового класса
12. Ошибки. Виды ошибок. Стратегии работы с ошибками
Виды ошибок: - Синтаксические - Логические - Времени выполнения
Стратегии обработки: - Обработка исключений - try/catch/finally - Коды возврата и проверка ошибок - функции возвращают коды ошибок - Логирование - запись информации об ошибках - Защитное программирование - проверка входных данных - Повторные попытки - при временных ошибках - Откат изменений - возврат к предыдущему состоянию - Пользовательские уведомления - информирование пользователя
--------------------------------------------------------------------------------------------------------------------------------------
Ошибка в программировании (или так называемый баг) – это ситуация у разработчиков, при которой определенный код вследствие обработки выдает неверный результат
Виды ошибок:
•	Синтаксические – нарушение правил языка.
•	Логические – неверный алгоритм.
•	Ошибки времени выполнения (exceptions) – деление на ноль, выход за границы массива.
•	Взаимодействия – подразумевается взаимодействие с аппаратным или программным окружением. Пример – ошибка при использовании веб-протоколов. Это приведет к тому, что облачный сервис не будет нормально функционировать;
•	Компиляционные – встречается при разработке на языках высокого уровня. Во время преобразований в машинный тип «что-то идет не так». Причиной служат синтаксические ошибки или сбои непосредственно в компиляторе;
•	Ресурсные – сбои вроде «переполнение буфера» или «нехватка памяти»;
•	Арифметические;
•	Среды выполнения.
Стратегии работы с ошибками:
•	Использование отладчиков
o	   Отладчик позволяет пошагово проходить код и отслеживать значения переменных. Это помогает легче находить проблемные участки.
•	Логирование
o	   Запись информации о работе программы в лог-файл помогает анализировать поведение приложения и выявлять проблемы.
•	Обработка исключений
o	Используйте конструкции try-catch для перехвата и обработки исключений, чтобы избежать аварийного завершения программы.
•	Тестирование
o	Пишите юнит-тесты для важных функций. Регулярное тестирование позволяет обнаруживать ошибки на раннем этапе.
•	Ревью кода
o	Привлечение коллег для проверки кода помогает выявить ошибки, которые могли быть пропущены.
•	Использование статического анализа
o	Инструменты статического анализа кода помогают находить потенциальные ошибки без выполнения программы.
•	Документация
o	Пишите понятную документацию и комментарии к коду, чтобы другие разработчики могли быстрее понять логику и структуру программы.
13. Автоматизация разработки технической документации
Инструменты и подходы: - Генераторы документации из кода (Javadoc, Doxygen, Sphinx) - Системы управления документацией (Confluence, GitBook) - Маркдаун и другие языки разметки - Инструменты для создания диаграмм (PlantUML, Mermaid) - Автоматическая генерация API-документации (Swagger, Postman) - Системы непрерывной интеграции для автоматического обновления документации - Шаблоны документов для стандартизации
-----------------------------------------------------------------------------------------------------------------------------------
•	Сервисы с искусственным интеллектом;
•	Облачные сервисы;
•	Программы для создания и управления справочной документацией;
o	HelpNDoc - программа для создания справочной документации с функциями управления контентом и пользователями.
o	Doxygen - инструмент для генерации документации из комментариев исходного кода.
o	Sphinx - система создания документации на основе reStructuredText и LaTeX.
o	MkDocs - простой и быстрый генератор документации, основанный на Markdown.
o	javadoc - инструмент для создания документации Java из комментариев в исходном коде.
o	pydoc - встроенная в Python утилита для генерации документации.
o	RoboHelp - программа для создания интерактивной справочной документации.
o	Adobe Robotic - инструмент для автоматического создания и обновления документации.
o	Microsoft Word - текстовый редактор, который можно использовать для создания справочной документации.
•	Способы автоматизации использования стилей;
o	Использование шаблонов: Создание и использование шаблонов с уже настроенными стилями и форматированием может помочь сэкономить время при создании новых документов.
o	Использование автоматических генераторов стилей: Существуют инструменты, которые могут автоматически генерировать стили на основе содержимого документа. Это может включать в себя форматирование кода, создание оглавлений, таблиц и т.д.
o	Интеграция с инструментами контроля версий: Интеграция инструментов контроля версий, таких как Git, с текстовыми редакторами, такими как Visual Studio Code, может обеспечить автоматическую проверку стиля и форматирования при коммите изменений.
o	Использование регулярных выражений: Использование регулярных выражений может помочь автоматизировать процесс форматирования текста, например, форматирование кода или создание заголовков.
o	Использование плагинов и расширений: Многие текстовые редакторы имеют плагины и расширения, которые могут помочь с автоматизацией стилей. Например, в Visual Studio Code есть плагины для автоматического форматирования кода и другие функции, связанные со стилями.
•	Markdown-разметка;
•	Макросы;
•	Текстовые редакторы на любой вкус.
14. Обмен данными через именованные каналы
Именованные каналы (Named Pipes) - механизм межпроцессного взаимодействия, позволяющий процессам обмениваться данными: - Представляют собой файловые объекты в файловой системе - Обеспечивают двунаправленную связь между процессами - Могут использоваться для взаимодействия между процессами на разных компьютерах - Поддерживают передачу данных в виде потока байтов - Работают по принципу FIFO (First In, First Out)
Применение: - Клиент-серверное взаимодействие - Передача данных между компонентами приложения - Обмен сообщениями между службами
15. Жизненный цикл активностей мобильного приложения
Основные этапы жизненного цикла активности в Android: - onCreate() - создание активности и инициализация UI - onStart() - активность становится видимой для пользователя - onResume() - активность переходит на передний план и может взаимодействовать с пользователем - onPause() - другая активность становится активной, текущая теряет фокус - onStop() - активность становится невидимой для пользователя - onRestart() - вызывается после onStop() перед повторным показом активности - onDestroy() - активность уничтожается
Переходы между состояниями могут быть вызваны действиями пользователя или системными событиями.
16. Понятие и разница между терминами «ошибка», «дефект», «сбой»
•	Ошибка (Error) - действие человека, которое приводит к неправильному результату (ошибка разработчика при написании кода)
•	Дефект (Defect/Bug) - недостаток в программе, который может привести к неправильной работе (результат ошибки)
•	Сбой (Failure) - неспособность системы выполнить требуемую функцию в определенных условиях (внешнее проявление дефекта)
Цепочка: ошибка разработчика → дефект в коде → сбой при работе программы.
17. Контейнеры компоновки макетов: ConstraintLayout
ConstraintLayout - современный и гибкий контейнер компоновки для Android: - Позволяет создавать сложные макеты без вложенности элементов - Основан на ограничениях (constraints), определяющих положение элементов относительно друг друга и родителя - Улучшает производительность за счет плоской иерархии представлений - Поддерживает процентные ограничения и цепочки элементов - Имеет визуальный редактор в Android Studio
Основные типы ограничений: - Относительное позиционирование - Отступы - Выравнивание - Размеры (фиксированные, wrap_content, match_constraint) - Барьеры и направляющие
18. Примитивы синхронизации: Мьютексы
Мьютекс (Mutual Exclusion) - примитив синхронизации, обеспечивающий монопольный доступ к ресурсу: - Предотвращает одновременный доступ к общему ресурсу - Имеет два состояния: заблокирован (locked) и разблокирован (unlocked) - Поток, захвативший мьютекс, должен освободить его после использования ресурса - Если мьютекс заблокирован, другие потоки ожидают его освобождения - Помогает избежать состояния гонки (race condition)
Отличия от семафоров: - Мьютекс может быть освобожден только захватившим его потоком - Мьютекс имеет только два состояния (0/1), а семафор может иметь несколько разрешений
19. Алгоритмы на графах
Основные алгоритмы на графах: - Поиск в ширину (BFS) - обход графа по уровням (используется для поиска кратчайшего пути в невзвешенном графе) - Поиск в глубину (DFS) - обход графа с углублением в ветки (используется для топологической сортировки) - Алгоритм Дейкстры - поиск кратчайшего пути во взвешенном графе с неотрицательными весами - Алгоритм Беллмана-Форда - поиск кратчайшего пути во взвешенном графе (работает с отрицательными весами) - Алгоритм Флойда-Уоршелла - поиск кратчайших путей между всеми парами вершин - Алгоритм Крускала - построение минимального остовного дерева - Алгоритм Прима - построение минимального остовного дерева - Алгоритм Форда-Фалкерсона - нахождение максимального потока в сети
20. Парадигма “Разделяй и властвуй”
“Разделяй и властвуй” (Divide and Conquer) - алгоритмическая парадигма, состоящая из трех этапов: 1. Разделение - задача разбивается на несколько подзадач меньшего размера 2. Решение - подзадачи решаются рекурсивно 3. Комбинирование - решения подзадач объединяются для получения ответа на исходную задачу
Примеры алгоритмов: - Быстрая сортировка (QuickSort) - Сортировка слиянием (MergeSort) - Алгоритм Карацубы (быстрое умножение больших чисел) - Быстрое преобразование Фурье (FFT) - Двоичный поиск
Преимущества: - Эффективность для многих задач - Естественное распараллеливание - Простота понимания и реализации
Разберем алгоритм “Разделяй и властвуй”на примере.
Мы будем выполнять сортировку слиянием с помощью алгоритма «разделяй и властвуй».
1.	Пусть дан следующий массив:
761543
2. Делим его пополам:
 761 543
Рекурсивно делим подмассивы пополам до тех пор, пока не останутся только отдельные элементы.
 7 6 1 5 4 3
2.	Объединяем и сортируем отдельные элементы. На этом этапе мы властвуем и объединяем:
67 45
167 345
134567
Сложность алгоритма: O(n log n)
Преимущества алгоритма
•	Сложность умножения двух матриц с помощью примитивного метода — O(n3). А вот сложность метода «разделяй и властвуй» (умножение матриц методом Штрассена) — O(n2.8074).
•	Идеально подходит для многоядерных систем.
•	Эффективно использует кэш-память.
Где применяется
•	Бинарный поиск.
•	Сортировка слиянием.
•	Быстрая сортировка. 
•	Умножение матриц методом Штрассена.
•	Алгоритм Карацубы.
21. Дескрипторы и псевдодескрипторы
Дескриптор - абстрактное целочисленное представление ресурса операционной системы: - Файловые дескрипторы - представляют открытые файлы - Дескрипторы сокетов - представляют сетевые соединения - Дескрипторы процессов - идентифицируют процессы - Дескрипторы окон - идентифицируют окна в графическом интерфейсе
HANDLE GetCurrentThread(VOID) – псевдодескриптор потока
Duplicate Handle() – можно получить дескриптор
HANDLE GetCurrentProcess(VOID) – псевдодескриптор процесса
Дескриптор нужен для управления процессом (заморозка, остановка, отключение), псевдодескриптор может быть использован внутри потока/процесса для управления им же внутри него
Псевдодескрипторы - специальные значения, которые выглядят как дескрипторы, но не являются прямыми ссылками на ресурсы: - STDIN (0), STDOUT (1), STDERR (2) - стандартные потоки ввода/вывода - Псевдодескрипторы в Win32 API (например, GetCurrentProcess()) - Псевдодескрипторы в графических подсистемах
22. ООП: Инкапсуляция
Инкапсуляция в программировании — это принцип, согласно которому внутреннее устройство сущностей нужно объединять в специальной «оболочке» и скрывать от вмешательств извне. Доступ к объектам возможен через специальные открытые методы, а напрямую обратиться к их содержимому нельзя.
Инкапсуляция - один из основных принципов ООП, заключающийся в скрытии внутренней реализации объекта и защите его данных: - Объединение данных и методов, работающих с этими данными, в одну единицу (класс) - Сокрытие внутреннего состояния объекта от внешнего мира - Доступ к данным осуществляется только через специальные методы (геттеры/сеттеры) - Реализуется с помощью модификаторов доступа (private, protected, public)
Преимущества: - Контроль доступа к данным - Защита от неправильного использования - Возможность изменения внутренней реализации без изменения внешнего интерфейса - Уменьшение связанности между компонентами системы
23. ООП: Классы и объекты
Класс — это тип данных, созданный пользователем. Он содержит разные свойства и методы, как, например, тип String или Int.
Объект — это экземпляр класса, или его копия, которая находится в памяти компьютера. Например, когда вы создаёте переменную типа String и присваиваете ей значение «Строка», то в памяти создаётся экземпляр класса String.
Взаимосвязь: - Класс - абстрактное понятие, объект - конкретная реализация - От одного класса можно создать множество объектов - Объекты одного класса имеют одинаковую структуру, но разные данные
По-другому можно сказать, что объекты — это сущности, у которых есть свойства и поведение. Обычно объекты являются экземплярами какого-нибудь класса. Например, в игре может быть класс Character («Персонаж»), а его экземплярами будут hero или npc.
24. Методы отладки
Отладка в программировании — это процесс поиска и исправления ошибок в компьютерной программе, выявленных в ходе разработки, тестирования или эксплуатации
•	Метод ручного тестирования. Это - самый простой и естественный способ данной группы. При обнаружении ошибки необходимо выполнить тестируемую программу вручную, используя тестовый набор, при работе с которым была обнаружена ошибка. Метод очень эффективен, но не применим для больших программ, программ со сложными вычислениями и в тех случаях, когда ошибка связана с неверным представлением программиста о выполнении некоторых операций. Данный метод часто используют как составную часть других методов отладки.
•	Метод индукции. Метод основан на тщательном анализе симптомов ошибки, которые могут проявляться как неверные результаты вычислений или как сообщение об ошибке
•	Метод дедукции. По методу дедукции вначале формируют множество причин, которые могли бы вызвать данное проявление ошибки. Затем анализируя причины, исключают те, которые противоречат имеющимся данным. Если все причины исключены, то следует выполнить дополнительное тестирование исследуемого фрагмента. В противном случае наиболее вероятную гипотезу пытаются доказать. Если гипотеза объясняет полученные признаки ошибки, то ошибка найдена, иначе - проверяют следующую причину
•	Метод обратного прослеживания. Для небольших программ эффективно применение метода обратного прослеживания. Начинают с точки вывода неправильного результата. Для этой точки строится гипотеза о значениях основных переменных, которые могли бы привести к получению имеющегося результата. Далее, исходя из этой гипотезы, делают предложения о значениях переменных в предыдущей точке. Процесс продолжают, пока не обнаружат причину ошибки.
25. Процесс. Взаимодействие с процессами
Процесс - экземпляр выполняющейся программы с выделенными ресурсами: - Имеет собственное адресное пространство - Содержит код, данные, стек, кучу - Имеет идентификатор процесса (PID) - Может создавать дочерние процессы
Методы взаимодействия с процессами: - Создание процессов - fork(), exec(), CreateProcess() - Завершение процессов - exit(), kill(), TerminateProcess() - Ожидание завершения - wait(), waitpid(), WaitForSingleObject() - Приоритеты процессов - nice(), SetPriorityClass() - Обмен данными между процессами (IPC): - Файлы и файловая система - Каналы (pipes) и именованные каналы - Сокеты - Разделяемая память - Сигналы - Очереди сообщений
-------------------------------------------------------------------------------------------------------------------------------------
Процесс – объект ядра, которому принадлежат системные ресурсы, используемые исполняемым приложением
У каждого процесса есть как минимум 1 поток – первичный, можно создать ещё потоки
У процесса есть:
- виртуальное адресное пространство
- некоторое количество страниц реальной памяти
- таблица для дескрипторов процесса и потоков
26. Структура консольного приложения
Структура консольного приложения может варьироваться в зависимости от языка программирования и специфики задачи, но в общем случае можно выделить несколько ключевых компонентов:
1.	Главная функция
- Это точка входа в приложение. В языках C, C++ это main(), в Python просто выполнение скрипта. Здесь начинается выполнение кода.
2.	Импорт библиотек или модулей
- Необходимо подключение стандартных или сторонних библиотек для выполнения задач. Например, в C# или Java это директивы using и import соответственно.
3.	Глобальные переменные и конфигурация
- Определение глобальных переменных, констант и начальных настроек, которые пригодятся в приложении.
4.	Определение функций или методов
- Основные функциональные блоки приложения, которые реализуют конкретные задачи. Функции могут быть разбиты на подзадачи и выполнены по мере необходимости.
5.	Обработка входных данных
- Код для чтения данных от пользователя через консоль, например, с использованием cin в C++, input() в Python или Console.ReadLine() в C#.
6.	Основная логика приложения
- Включает в себя алгоритмы обработки данных, бизнес-логику и взаимодействие с пользователем.
7.	Вывод результатов
- После обработки данных приложение должно предоставить пользователю результаты через консоль, используя команды вывода.
8.	Обработка ошибок
- Включает в себя механизмы для обработки возможных исключений или ошибок, которые могут возникнуть в процессе выполнения.
9.	Завершение приложения
- Код, который выполняется при завершении работы приложения, освобождающий ресурсы и подводящий итоги.
10.	Комментарии и документация
- Важно документировать код, добавляя комментарии для улучшения читаемости и понимания структуры приложения.
Типичные компоненты: - Парсеры командной строки - Модули обработки данных - Подсистема логирования - Интерфейс пользователя (текстовый) - Подключение к внешним ресурсам (файлы, сеть, БД)
27. Контейнеры компоновки макетов: LinearLayout
LinearLayout - это Макет, который упорядочивает другие представления либо по горизонтали в одном столбце,либо по вертикали в одной строке. В студии макет LinearLayout представлен двумя вариантами - Horizontal и Vertical. Макет LinearLayout выравнивает все дочерние объекты в одном направлении — вертикально или горизонтально.
 Направление задается при помощи атрибута ориентации android:orientation:
•	android:orientation="horizontal"
•	android:orientation="vertical"
Все дочерние элементы помещаются в стек один за другим, так что вертикальный список компонентов будет иметь только один дочерний элемент в ряду независимо от того, насколько широким он является. Горизонтальное расположение списка будет размещать элементы в одну строку с высотой, равной высоте самого высокого дочернего элемента списка
У разметки LinearLayout есть интересный атрибут android:layout_weight, который назначает индивидуальный вес для дочернего элемента. Этот атрибут определяет "важность" представления и позволяет этому элементу расширяться, чтобы заполнить любое оставшееся пространство в родительском представлении. Заданный по умолчанию вес является нулевым.
Преимущества: - Простота использования - Предсказуемое расположение элементов - Подходит для простых интерфейсов (списки, формы)
28. Организация сетевого взаимодействия
Организация сетевого взаимодействия включает: - Модель OSI - 7-уровневая модель сетевого взаимодействия - Стек протоколов TCP/IP - набор протоколов для Интернет-коммуникаций - Сокеты - программный интерфейс для сетевого взаимодействия - API для работы с сетью - библиотеки и фреймворки для сетевого программирования - HTTP/HTTPS - протоколы передачи гипертекста - WebSockets - протокол для двунаправленной связи - REST API - архитектурный стиль для взаимодействия компонентов - Сериализация/десериализация данных - преобразование объектов в формат для передачи (JSON, XML) - Асинхронное взаимодействие - неблокирующие операции ввода-вывода
29. Событийно-управляемое программирование
Событийно-ориентированное программирование, СОП, создание событийно-управляемых программ, event-driven programming - парадигма программирования, в которой выполнение программы определяется событиями - действиями пользователя (клавиатура, мышь), сообщениями других программ и потоков, событиями операционной системы (например, поступлением сетевого пакета).
Событийно-ориентированное программирование, как правило, применяется в следующих случаях:
•	построение пользовательских интерфейсов (в том числе графических);
•	создание серверных приложений;
•	моделирование сложных систем;
•	параллельные вычисления;
•	автоматические системы управления, SCADA;
•	программирование игр, в которых осуществляется управление множеством объектов.
private void button1_Click(object sender, EventArgs e)
        {
            MessageBox.Show("Была нажата кнопка");
        }
Примеры реализаций событийно-ориентированного программирования
•	Веб-серверы: Node.js, nginx, lighttpd
•	Прокси-серверы: Squid
Применение: - Графические пользовательские интерфейсы - Веб-приложения (JavaScript) - Мобильные приложения - Асинхронные серверы - Системы автоматизации
30. Система информационной безопасности системного ПО
Система информационной безопасности системного ПО включает: - Управление доступом - аутентификация, авторизация, разграничение прав - Защита памяти - предотвращение несанкционированного доступа к памяти процессов - Песочницы (Sandboxing) - изолированное выполнение программ - Шифрование данных - защита хранимых и передаваемых данных - Обнаружение вторжений - мониторинг подозрительной активности - Обновления безопасности - устранение уязвимостей - Аудит безопасности - логирование событий безопасности - Управление уязвимостями - выявление и устранение слабых мест - Защита от вредоносного ПО - антивирусные механизмы
31. Коллекции
Коллекции - структуры данных для хранения и управления наборами объектов:
Основные типы коллекций: - Списки (Lists) - упорядоченные коллекции с доступом по индексу - Множества (Sets) - коллекции уникальных элементов - Словари (Dictionaries/Maps) - пары ключ-значение - Очереди (Queues) - FIFO (First In, First Out) - Стеки (Stacks) - LIFO (Last In, First Out) - Деревья (Trees) - иерархические структуры - Графы (Graphs) - узлы и связи между ними
Характеристики: - Размер (фиксированный или динамический) - Производительность операций (вставка, удаление, поиск) - Упорядоченность элементов - Уникальность элементов - Потокобезопасность
32. Алгоритмы поиска
Основные алгоритмы поиска: - Линейный поиск - последовательный перебор элементов (O(n)) - Двоичный поиск - поиск в отсортированном массиве путем деления пополам (O(log n)) - Интерполяционный поиск - улучшение двоичного поиска для равномерно распределенных данных (O(log log n) в среднем) - Поиск по хэш-таблице - использование хэш-функции для доступа к элементам (O(1) в среднем) - Поиск в деревьях: - Поиск в бинарном дереве поиска (BST) - Поиск в AVL-дереве - Поиск в красно-черном дереве - Поиск в B-дереве - Поиск в графах: - Поиск в ширину (BFS) - Поиск в глубину (DFS)
----------------------------------------------------------------------------------------------------------------------------
•	Линейный поиск
•	Бинарный поиск
•	Интерполяционный
33. Верификация программного обеспечения
Верификация программного обеспечения — это проверка соответствия заявленным требованиям, проектной документации, техническим спецификациям и стандартам. Она необходима, чтобы убедиться, что создание продукта проходит правильно.
Процесс верификации включает следующие этапы:
1.	Проверка требований. Команда проекта подтверждает правильность всех пунктов в требованиях на основе данных, полученных от бизнеса.
2.	Проверка дизайна. Команда тестировщиков анализирует дизайн программного обеспечения, включая макеты и прототипы.
3.	Проверка логики кода. Команда проверяет код, чтобы убедиться в его полноте и согласованности.
Некоторые методы верификации:
•	Статический анализ кода. Подразумевает использование автоматизированных инструментов для анализа кода без его выполнения. Это позволяет обнаружить ошибки, потенциальные уязвимости и нарушения стандартов на ранних этапах разработки.
•	Формальная верификация. Включает математические методы для доказательства того, что система соответствует определённым требованиям. Этот метод чаще используется в критически важных приложениях, таких как авиационные системы, где ошибки могут быть катастрофическими.
•	Моделирование и прототипирование. Включает создание моделей и прототипов программного обеспечения на ранних стадиях разработки. Он позволяет обнаружить ошибки и несоответствия до того, как продукт будет полностью реализован.
Цель: выявление и устранение дефектов до выпуска продукта.
34. Методы тестирования
•	Тестирование методом «чёрного ящика»:
Методика тестирования без глубоких знаний о внутренней работе ПО называется «чёрным ящиком». Специалист не берёт во внимание архитектуру системы и не имеет доступа к исходному коду. Как правило, при выполнении теста с «чёрным ящиком» специалист работает с пользовательским интерфейсом системы, вводя данные и анализируя результат При этом тестировщик не знает, как и где обрабатываются эти данные.
•	Тестирование методом «белого ящика»:
Проверка «белого ящика» — это подробное исследование внутренней логики и структуры кода. Тестирование с использованием этого метода также называют тестированием стекла, или открытым тестированием. Зная, как работает код, эксперт изучает его изнутри и выясняет, какое устройство / блок кода ведёт себя некорректно.
•	Тестирование методом «серого ящика»:
Этот метод представляет собой что-то среднее между двумя предыдущими. При тестировании «серого ящика» специалист должен иметь представление о внутреннем устройстве ПО — но не слишком глубокое. Он ставит себя на место конечного пользователя, но проверяет функционал программы, опираясь на понимание её внутреннего устройства.
35. Методы оптимизации программного кода
1. Использование эффективных алгоритмов
Выбор правильного алгоритма является одним из ключевых факторов в оптимизации кода. При разработке программы следует выбирать алгоритмы с наилучшей временной сложностью и минимальным количеством операций.
2. Правильное использование циклов
Циклы являются одним из основных инструментов программирования. Однако, неправильное использование циклов может привести к значительным потерям производительности. При написании кода следует избегать вложенных циклов и по возможности использовать более эффективные альтернативы, такие как циклы с предусловием или циклы с постусловием.
3. Минимизация операций внутри циклов
Чем меньше операций выполняется внутри цикла, тем быстрее будет работать ваш код. Поэтому стоит стремиться к минимизации операций внутри циклов и выносить ненужные вычисления за пределы цикла.
4. Использование подходящих структур данных
Выбор правильной структуры данных может существенно повлиять на производительность вашего кода. Например, использование хеш-таблицы может значительно ускорить поиск элементов, в то время как список будет эффективнее при работе с последовательными данными.
5. Кэширование результатов вычислений
Если результат определенных вычислений остается неизменным на протяжении выполнения программы, то его можно закэшировать и использовать повторно вместо повторного вычисления. Это позволит сэкономить время и улучшить производительность кода.
6. Устранение избыточных операций
Анализируйте свой код на предмет избыточных операций, которые не влияют на результат работы программы. Избавление от таких операций поможет ускорить выполнение программы и сделает ее более эффективной.
7. Профилирование кода
Профилирование кода позволяет выявить места, где тратится больше всего времени при выполнении программы. Это помогает определить узкие места и сконцентрироваться на их оптимизации для повышения производительности.
В заключение, правильная оптимизация и улучшение производительности кода являются важными аспектами разработки программного продукта. Следуя приведенным методам, вы сможете создавать более эффективный и быстрый код, что положительно скажется на работе вашей программы 
36. Порядок разработки тестов. Аксиомы тестирования
Порядок разработки тестов: 1. Анализ требований и спецификаций 2. Разработка стратегии тестирования 3. Создание тестовых случаев 4. Подготовка тестовых данных 5. Настройка тестовой среды 6. Выполнение тестов 7. Анализ результатов 8. Отчетность о дефектах 9. Перетестирование исправлений
Аксиомы тестирования: - Невозможность полного тестирования - нельзя протестировать все возможные входные данные и сценарии - Скопление дефектов - большинство дефектов сконцентрировано в небольшой части кода - Парадокс пестицида - повторяющиеся тесты теряют эффективность со временем - Тестирование показывает наличие дефектов, но не их отсутствие - Раннее тестирование экономит ресурсы - Зависимость тестирования от контекста - разные системы требуют разных подходов - Отсутствие ошибок не гарантирует полезность продукта
37. Классификация типов мобильных приложений по способу разработки: сравнительная характеристика
Нативная разработка
Нативная разработка предполагает создание приложений для конкретной платформы (iOS или Android) с использованием официальных инструментов и языков программирования, предоставляемых разработчиками платформ.
Основные инструменты
•	iOS: язык программирования Swift или Objective-C, среда разработки Xcode.
•	Android: язык программирования Kotlin или Java, среда разработки Android Studio.
Преимущества нативной разработки
•	Высокая производительность. Нативные приложения имеют доступ к системным ресурсам и могут обеспечить максимальную производительность.
•	Пользовательский опыт. Приложения полностью соответствуют гайдлайнам платформы, что обеспечивает лучший пользовательский опыт.
•	Доступ к API и функциям устройства. Нативные приложения могут использовать все возможности устройства, включая камеру, датчики и другие аппаратные компоненты.
Недостатки нативной разработки
•	Высокие затраты. Разработка для каждой платформы требует отдельных команд разработчиков, что увеличивает затраты.
•	Длительное время разработки. Создание и поддержка двух отдельных версий приложения требует больше времени.
Кроссплатформенная разработка
Кроссплатформенная разработка позволяет создавать приложения для нескольких платформ с использованием одного кода. Это достигается с помощью специальных фреймворков и инструментов.
Основные инструменты
•	React Native: фреймворк от Facebook, использующий JavaScript и React.
•	Flutter: фреймворк от Google, использующий язык программирования Dart.
•	Xamarin: фреймворк от Microsoft, использующий C# и .NET.
Преимущества кроссплатформенной разработки
•	Снижение затрат. Использование единого кода для нескольких платформ позволяет сократить затраты на разработку и поддержку.
•	Сокращение времени разработки. Общее время разработки уменьшается за счет повторного использования кода.
•	Удобство для небольших команд. Кроссплатформенные решения особенно полезны для небольших команд, у которых нет ресурсов для создания отдельных приложений.
Недостатки кроссплатформенной разработки
•	Ограниченные возможности платформ. Кроссплатформенные приложения могут не иметь полного доступа к возможностям платформы.
•	Проблемы с производительностью. В некоторых случаях кроссплатформенные приложения могут уступать в производительности нативным.
Гибридные подходы
Гибридные приложения представляют собой веб-приложения, встроенные в нативные контейнеры. Они сочетают в себе элементы нативных и веб-приложений.
Преимущества гибридных подходов
•	Быстрая разработка. Гибридные приложения могут быть разработаны быстрее, чем нативные.
•	Многоразовый код. Большая часть кода может быть использована для нескольких платформ.
•	Упрощенная поддержка. Поддержка одного кода для всех платформ упрощает процесс обновлений и устранения ошибок.
Недостатки гибридных подходов
•	Ограниченная производительность. Гибридные приложения могут уступать в производительности нативным.
Ограниченные возможности. Доступ к функциям устройства может быть ограничен
38. Примитивы синхронизации: События
События (Events) - примитивы синхронизации, позволяющие одному потоку сигнализировать другим о наступлении определенного состояния: - Ручной сброс - событие остается в сигнальном состоянии до явного сброса - Автоматический сброс - событие автоматически сбрасывается после освобождения одного ожидающего потока - Начальное состояние - событие может быть создано в сигнальном или несигнальном состоянии
Операции: - Сигнализирование (Set) - перевод события в сигнальное состояние - Сброс (Reset) - перевод события в несигнальное состояние - Ожидание (Wait) - блокировка потока до наступления события - Проверка состояния - опрос текущего состояния события
Применение: - Уведомление о завершении операции - Синхронизация начала параллельных операций - Реализация шаблона “производитель-потребитель”
39. Принципы разработки интерфейса пользователя
Принципы разработки пользовательского интерфейса: - Простота - интерфейс должен быть интуитивно понятным - Согласованность - единообразие элементов и поведения - Обратная связь - информирование пользователя о результатах действий - Прощение ошибок - возможность отмены действий, предотвращение критических ошибок - Эффективность - минимизация количества действий для выполнения задачи - Доступность - учет потребностей пользователей с ограниченными возможностями - Эстетика - приятный внешний вид - Контроль пользователя - пользователь должен чувствовать контроль над системой - Гибкость - адаптация под разные устройства и предпочтения
Методологии: - User-Centered Design (UCD) - Material Design - Human Interface Guidelines (HIG) - Responsive Design
40. Определение потока. Создание и завершение потока
Поток (Thread) - наименьшая единица выполнения, которой операционная система может управлять отдельно: - Часть процесса, имеющая свой стек и набор регистров - Разделяет адресное пространство с другими потоками в том же процессе - Имеет свой идентификатор и приоритет
Создание потока – CreateThread(1,2,3,4,5,6)
1 – атрибуты защиты
2 – размер программного стека
3 – указывает на исполняемую функцию
4 – параметр, передающийся в поток
5 – флаги создания потока
6 – идентификатор потока
Завершение потока – ExitThread(код завершения) (в потоке) TerminateThread(дескриптор_потока, код  завершения) (можно вне потока)
41. Контейнеры компоновки макетов: FrameLayout
FrameLayout - простейший контейнер компоновки в Android: - Предназначен для отображения одного элемента, занимающего всю доступную область - Позволяет размещать элементы друг поверх друга (как слои) - Каждый элемент располагается относительно верхнего левого угла контейнера - Поддерживает позиционирование с помощью gravity (центр, верх, низ и т.д.) - Часто используется для фрагментов, наложения элементов и анимаций
Применение: - Контейнер для одиночного представления - Реализация переключения между представлениями - Создание наложений (оверлеев) - Контейнер для фрагментов - Основа для специализированных представлений (например, CardView)
42. Место тестирования и отладки в жизненном цикле программного обеспечения
Тестирование и отладка в жизненном цикле ПО:
1.	Планирование - разработка стратегии тестирования
2.	Анализ требований - создание тестовых случаев на основе требований
3.	Проектирование - верификация проектных решений
4.	Реализация:
–	Модульное тестирование в процессе разработки
–	Отладка выявленных проблем
–	Статический анализ кода
5.	Тестирование:
–	Интеграционное тестирование
–	Системное тестирование
–	Регрессионное тестирование
–	Отладка выявленных дефектов
6.	Развертывание:
–	Приемочное тестирование
–	Бета-тестирование
7.	Сопровождение:
–	Отладка проблем, обнаруженных в эксплуатации
–	Тестирование обновлений и исправлений
Непрерывная интеграция (CI) и непрерывная доставка (CD) обеспечивают автоматизацию тестирования на всех этапах.
Тестирование в программировании — это процесс проверки программного обеспечения, системы или приложения на соответствие определённым требованиям и оценки их качества.
Отладка – это этап разработки компьютерной программы, на котором обнаруживают, локализуют и устраняют ошибки
Тестирование помогает обнаружить дефекты в программном обеспечении, проверяя его работоспособность в разнообразных условиях и сценариях использования. Тестирование становится центральной частью каждого этапа жизненного цикла разработки программ. Тестированию подвергаются требования к программному продукту, алгоритмы, исходные коды, модули, программные сборки, функциональность программ и т. д.
Отладка начинается после того, как в процессе тестирования были обнаружены ошибки. Это процесс локализации, диагностирования и исправления обнаруженных ошибок или багов в коде. Отладка не только исправляет ошибки, но и способствует оптимизации и улучшению качества кода, благодаря чему увеличивается эффективность и производительность программы.
43. Технология структурного программирования
Технология структурного программирования - методология разработки, основанная на принципах: - Нисходящее проектирование - разбиение задачи на подзадачи - Модульность - разделение программы на независимые модули - Ограниченное использование операторов перехода (goto) - Стандартные управляющие структуры: - Последовательность (следование) - Ветвление (if-then-else) - Цикл (for, while)
Теорема Бома-Якопини: любой алгоритм можно реализовать, используя только три базовые управляющие структуры.
Преимущества: - Улучшение читаемости кода - Упрощение отладки и тестирования - Повышение надежности программ - Повторное использование кода
44. Состояния потока
Основные состояния потока: - Новый (New) - поток создан, но не запущен - Готовый к выполнению (Runnable) - поток готов к выполнению и ожидает процессорного времени - Выполняющийся (Running) - поток выполняется процессором - Заблокированный (Blocked) - поток ожидает ресурса (I/O, синхронизация) - Ожидающий (Waiting) - поток ожидает сигнала от другого потока - Спящий (Sleeping) - поток временно приостановлен - Завершенный (Terminated) - поток завершил выполнение
Переходы между состояниями: - Новый → Готовый: после вызова start() - Готовый → Выполняющийся: планировщик выбирает поток для выполнения - Выполняющийся → Заблокированный: ожидание ресурса - Заблокированный → Готовый: ресурс стал доступен - Выполняющийся → Ожидающий: вызов wait(), join() - Ожидающий → Готовый: получение сигнала notify(), notifyAll() - Выполняющийся → Спящий: вызов sleep() - Спящий → Готовый: истечение времени сна - Выполняющийся → Завершенный: завершение выполнения или исключение
45. Алгоритмы сортировки
Основные алгоритмы сортировки: - Пузырьковая сортировка (Bubble Sort) - O(n²), простая реализация, неэффективна для больших наборов
def bubble_sort(array):
    n = len(array) 
    for i in range(n):
        swapped = False # Оптимизация: проверка, произошёл ли обмен
        for j in range(0, n - i - 1):
            if array[j] > array[j + 1]:
                array[j], array[j + 1] = array[j + 1], array[j] # Обмен элементов
        swapped = True 
        if not swapped:
            break # Если обменов не было, массив уже отсортирован
    return array
 - Сортировка вставками (Insertion Sort) - O(n²), эффективна для почти отсортированных данных 
def insertion(arr):
    for i in range(len(arr)):
       j = i - 1 
       key = arr[i]
       while arr[j] > key and j >= 0:
          arr[j + 1] = arr[j]
          j -= 1
       arr[j + 1] = key
    return arr
- Сортировка выбором (Selection Sort) - O(n²), минимальное количество обменов 
def selection_sort(arr):
    n = len(arr)
    for i in range(n):  # Находим минимальный элемент в оставшейся неотсортированной части массива
        min_idx = i
        for j in range(i + 1, n):
            if arr[j] < arr[min_idx]:
                min_idx = j
        # Меняем найденный минимальный элемент с первым элементом неотсортированной части
        arr[i], arr[min_idx] = arr[min_idx], arr[i]
    return arr  # Возвращаем отсортированный массив
- Быстрая сортировка (Quick Sort) - O(n log n) в среднем, разделяй и властвуй, рекурсивная 
def quicksort(nums):
    if len(nums) <= 1:
        return nums
    else:
        q = random.choice(nums)
        s_nums =[]
        m_nums =[]
        e_nums =[]
        for n in nums:
            if n < q:
                s_nums.append(n)
            elif n > q:
                m_nums.append(n)
            else:
                e_nums.append(n)
        return quicksort(s_nums) + e_nums + quicksort(m_nums)
- Сортировка слиянием (Merge Sort) - O(n log n), разделяй и властвуй, стабильная 
def merge_sort(arr): 
    if len(arr) > 1: 
        mid = len(arr)//2
        left = arr[:mid] 
        right = arr[mid:]
        merge_sort(left) 
        merge_sort(right) 
        i = j = k = 0
        while i < len(left) and j < len(right): 
            if left[i] < right[j]: 
                arr[k] = left[i] 
                i+=1
            else: 
                arr[k] = right[j] 
                j+=1
            k+=1
        while i < len(left): 
            arr[k] = left[i] 
            i+=1
            k+=1
        while j < len(right): 
            arr[k] = right[j] 
            j+=1
            k+=1
- Пирамидальная сортировка (Heap Sort) - O(n log n), использует бинарную кучу 
- Сортировка подсчетом (Counting Sort) - O(n+k), для целых чисел в ограниченном диапазоне 
- Поразрядная сортировка (Radix Sort) - O(nk), для чисел с фиксированным количеством разрядов 
- Сортировка Шелла (Shell Sort) - улучшенная сортировка вставками
46. Системное программное обеспечение: подходы к определению и классификации
Системное программное обеспечение - набор программ, обеспечивающих управление аппаратными ресурсами компьютера и предоставляющих платформу для работы прикладного ПО.
Подходы к определению: - Функциональный - ПО, выполняющее системные функции - Структурный - ПО, являющееся частью операционной системы или расширяющее её - По уровню абстракции - ПО, работающее на низком уровне абстракции (близко к аппаратуре)
Классификация: 1. Операционные системы: - Ядро ОС - Подсистемы ввода-вывода - Файловые системы - Подсистемы управления процессами и памятью
2.	Сервисные программы (утилиты):
–	Диагностические программы
–	Программы обслуживания дисков
–	Архиваторы
–	Антивирусы
3.	Инструментальное ПО:
–	Компиляторы и интерпретаторы
–	Отладчики
–	Профилировщики
–	Системы контроля версий
4.	Драйверы устройств:
–	Драйверы ввода-вывода
–	Сетевые драйверы
–	Драйверы графических устройств
5.	Системы управления базами данных
47. Использование интентов при разработке мобильного приложения
Интент (Intent) в Android - объект, представляющий намерение выполнить действие или сообщение для активации компонента:
Типы интентов: - Явные (Explicit) - точно указывают компонент для активации - Неявные (Implicit) - указывают действие без явного указания компонента
Компоненты интента: - Action - действие, которое нужно выполнить - Data - URI данных и их MIME-тип - Category - категория компонента, который должен обрабатывать интент - Extras - дополнительные данные в виде пар ключ-значение - Flags - флаги, влияющие на обработку интента
Применение: - Запуск активностей - Запуск служб - Передача данных между компонентами - Отправка широковещательных сообщений - Работа с системными функциями (звонки, отправка SMS, открытие веб-страниц) - Обмен данными между приложениями
Фильтры интентов позволяют компонентам определить, какие интенты они могут обрабатывать.
48. Примитивы синхронизации: Семафоры
Семафор - примитив синхронизации, предназначенный для контроля доступа к ресурсу: - Представляет собой счетчик с атомарными операциями - Обеспечивает синхронизацию между потоками или процессами - Может использоваться для ограничения доступа к ресурсу определенным числом потоков
Типы семафоров: - Двоичный семафор (Binary) - принимает значения 0 или 1 (аналогичен мьютексу) - Счетный семафор (Counting) - принимает произвольные неотрицательные значения
Операции: - P (wait, acquire) - уменьшает значение семафора на 1; если значение становится отрицательным, поток блокируется - V (signal, release) - увеличивает значение семафора на 1; если есть заблокированные потоки, один из них разблокируется
Применение: - Взаимное исключение (двоичный семафор) - Ограничение количества одновременных пользователей ресурса - Синхронизация выполнения потоков - Реализация шаблонов “производитель-потребитель” и “читатели-писатели”
49. Способы записи алгоритмов
Основные способы записи алгоритмов: - Словесное описание - пошаговое описание на естественном языке - Блок-схемы - графическое представление с использованием стандартных символов - Псевдокод - промежуточный между естественным языком и языком программирования - Программный код - запись на конкретном языке программирования - Математические формулы - для математических алгоритмов - Диаграммы активности UML - стандартизированное графическое представление - Диаграммы переходов состояний - для алгоритмов, основанных на состояниях - Таблицы решений - табличное представление для сложных условий
Каждый способ имеет свои преимущества и области применения: - Блок-схемы наглядны для простых алгоритмов - Псевдокод легко преобразуется в код на любом языке - Математические формулы компактны для математических алгоритмов
50. Концепция виртуальной памяти
Виртуальная память - метод управления памятью, который предоставляет процессам иллюзию большого непрерывного адресного пространства независимо от доступной физической памяти: - Процессы работают с виртуальными адресами, которые преобразуются в физические - Подкачка страниц (Paging) - технология, при которой адресное пространство делится на страницы фиксированного размера - Сегментация - деление адресного пространства на логические сегменты переменного размера
Компоненты: - MMU (Memory Management Unit) - аппаратный модуль для трансляции адресов - Таблица страниц - структура данных для отображения виртуальных адресов в физические - TLB (Translation Lookaside Buffer) - кэш для ускорения трансляции адресов - Файл подкачки (Swap file) - область на диске для выгрузки неиспользуемых страниц
Преимущества: - Изоляция процессов друг от друга - Использование больше памяти, чем физически доступно - Упрощение программирования (непрерывное адресное пространство) - Защита памяти - Эффективное использование физической памяти
Недостатки: - Накладные расходы на преобразование адресов - Возможность снижения производительности при интенсивной подкачке (thrashing)
51. ООП: Методы
Метод в ООП - функция, определенная внутри класса и описывающая поведение объектов этого класса: - Имеет доступ к атрибутам и другим методам класса - Может принимать параметры и возвращать значения - Инкапсулирует логику работы с данными объекта
Типы методов: - Методы экземпляра - работают с конкретным экземпляром класса - Статические методы (классовые) - принадлежат классу, а не экземпляру - Методы доступа - геттеры и сеттеры для атрибутов - Конструкторы - специальные методы для инициализации объектов - Деструкторы - методы для освобождения ресурсов - Перегруженные методы - методы с одинаковым именем, но разными параметрами - Переопределенные методы - методы, изменяющие поведение родительских методов
Характеристики: - Сигнатура - имя метода и его параметры - Модификаторы доступа - public, private, protected - Возвращаемое значение - тип данных, возвращаемый методом - Реализация - тело метода с алгоритмом
Методы в объектно-ориентированном программировании (ООП) — это функции внутри объекта или класса, которые позволяют взаимодействовать с ним или другой частью кода. 
Каждый метод в классе даёт объекту определённую способность или реакцию на внешние стимулы. 
Некоторые виды методов в ООП:
•	Статические методы. Для их вызова не требуется создание экземпляра класса. Например, если есть класс Calculator с методом add, его можно вызвать так: Calculator.add(5, 3).
•	Асинхронные методы. Позволяют программе продолжать выполнение, не ожидая завершения предыдущей задачи.
•	Конструкторы. Играют роль инициализаторов: при создании нового объекта конструктор автоматически вызывается для установки начального состояния объекта.
•	Деструкторы. Управляют тем, что происходит, когда объект больше не нужен. В языках программирования, таких как C++, деструкторы играют ключевую роль в управлении памятью, освобождая ресурсы, которые были выделены для объекта.
•	Абстрактные методы. Задают шаблон, который должен быть реализован во всех подклассах.
•	Виртуальные функции. Позволяют подклассам переопределять методы родительского класса. Это ключевой элемент полиморфизма в ООП, позволяющий объектам разных классов вызывать один и тот же метод, но выполнять его по-разному в зависимости от типа объекта.
52. Ввод-вывод высокого уровня на консоль
Ввод-вывод высокого уровня на консоль - программные средства для взаимодействия с пользователем через консоль:
Особенности: - Абстракция от низкоуровневых операций ввода-вывода - Буферизация данных для повышения производительности - Форматирование вывода - Преобразование типов данных - Обработка ошибок - Интернационализация
Стандартные потоки: - stdin (стандартный ввод) - получение данных от пользователя - stdout (стандартный вывод) - вывод обычных данных - stderr (стандартный поток ошибок) - вывод сообщений об ошибках
Примеры в разных языках: - C: printf(), scanf(), fprintf(), fscanf() - C++: std::cout, std::cin, std::cerr - Java: System.out.println(), System.in, Scanner - Python: print(), input(), форматированный вывод с f-строками - C#: Console.WriteLine(), Console.ReadLine()
Управление консолью: - Очистка экрана - Позиционирование курсора - Цветной текст - Специальные символы и ANSI-последовательности
