Бо Карнс – разработчик и преподаватель расскажет о наиболее часто используемых и общих структурах данных. Специально для вас мы перевели его статью.
«Плохие программисты беспокоятся о коде. Хорошие программисты беспокоятся о структурах данных и их отношениях ». — Линус Торвальдс, создатель Linux
Структуры данных являются важной частью разработки программного обеспечения и одной из наиболее распространенных тем для вопросов на собеседованиях с разработчиками.
Хорошая новость в том, что они в основном являются просто специализированными форматами для организации и хранения данных.
Из этой статьи вы узнаете о 10 наиболее распространенных структурах данных.
Также сюда добавлены видеоролики (на английском языке) по каждой из структур, и код их реализации на JS. А чтобы вы немного попрактиковались, я добавил сюда задачи из бесплатной учебной программы freeCodeCamp.
Обратите внимание, что некоторые из этих структур данных включают временную сложность в нотации Big O.
Это не относится ко всем из них, поскольку временная сложность иногда основана на реализации. Если вы хотите узнать больше о нотации Big O, посмотрите видео от Briana Marie .
Несмотря на то, что для каждой структуры я привожу код реализации на JavaScript, вам вероятно, никогда не придется делать этого самостоятельно, только если вы не будете использовать низкоуровневый язык вроде С.
JavaScript (как и большинство языков высокого уровня) имеет встроенные реализации многих из этих структур данных.
Тем не менее, знание того, как реализовать эти структуры данных, даст вам огромное преимущество в поиске работы и может пригодиться, когда вы попытаетесь написать высокопроизводительный код.
Связные списки
Реализация на JavaScript
Временная сложность связного списка
╔═══════════╦═════════╦══════════════╗
║ Алгоритм ║В среднем║Худший случай ║
╠═══════════╬═════════╬══════════════╣
║ Space ║ O(n) ║ O(n) ║
║ Search ║ O(n) ║ O(n) ║
║ Insert ║ O(1) ║ O(1) ║
║ Delete ║ O(1) ║ O(1) ║
╚═══════════╩═════════╩══════════════╝
Задания с freeCodeCamp:
Стеки
Стек — это базовая структура данных, в которой вы можете только вставлять или удалять элементы в начале стека. Он напоминает стопку книг. Если вы хотите взглянуть на книгу в середине стека, вы сначала должны взять книги, лежащие сверху.
Стек считается LIFO (Last In First Out) — это означает, что последний элемент, который добавлен в стек, — это первый элемент, который из него выходит.
Существует три основных операции, которые могут выполняться в стеках: вставка элемента в стек (называемый «push»), удаление элемента из стека (называемое «pop») и отображение содержимого стека (иногда называемого «pip»).
Реализация на JavaScript
Временная сложность стека
╔═══════════╦═════════╦══════════════╗
║ Алгоритм ║В среднем║Худший случай ║
╠═══════════╬═════════╬══════════════╣
║ Space ║ O(n) ║ O(n) ║
║ Search ║ O(n) ║ O(n) ║
║ Insert ║ O(1) ║ O(1) ║
║ Delete ║ O(1) ║ O(1) ║
╚═══════════╩═════════╩══════════════╝
Задания с freeCodeCamp:
- Learn how a Stack Works
- Create a Stack Class Queues
Очереди
Вы можете думать об этой структуре, как об очереди людей в продуктовом магазине. Стоящий первым будет обслужен первым. Также как очередь.
Если рассматривать очередь с точки доступа к данным, то она является FIFO (First In First Out).
Это означает, что после добавления нового элемента все элементы, которые были добавлены до этого, должны быть удалены до того, как новый элемент будет удален.
В очереди есть только две основные операции: enqueue и dequeue. Enqueue означает вставить элемент в конец очереди, а dequeue означает удаление переднего элемента.
Реализация на JavaScript
Временная сложность очереди
╔═══════════╦═════════╦══════════════╗
║ Алгоритм ║В среднем║Худший случай ║
╠═══════════╬═════════╬══════════════╣
║ Space ║ O(n) ║ O(n) ║
║ Search ║ O(n) ║ O(n) ║
║ Insert ║ O(1) ║ O(1) ║
║ Delete ║ O(1) ║ O(1) ║
╚═══════════╩═════════╩══════════════╝
Задания с freeCodeCamp:
- Create a Queue Class
- Create a Priority Queue Class
- Create a Circular Queue
Множества
- Union (Объединение). Объединяет все элементы из двух разных множеств и возвращает результат, как новый набор (без дубликатов).
- Intersection (Пересечение). Если заданы два множества, эта функция вернет другое множество, содержащее элементы, которые имеются и в первом и во втором множестве.
- Difference (Разница). Вернет список элементов, которые находятся в одном множестве, но НЕ повторяются в другом.
- Subset(Подмножество) — возвращает булево значение, показывающее, содержит ли одно множество все элементы другого множества.
Реализация на JavaScript
Задания с freeCodeCamp:
Map
- Добавление пары в коллекцию
- Удаление пары из коллекции
- Изменение существующей пары
- Поиск значения, связанного с определенным ключом
Реализация на JavaScript
Задания с freeCodeCamp:
- Create a Map Data Structure
- Create an ES6 JavaScript Map
Хэш-таблицы
Хэш-таблица — это структура данных, реализующая интерфейс map, который позволяет хранить пары ключ / значение. Она использует хеш-функцию для вычисления индекса в массиве, по которым можно найти желаемое значение.
Хеш-функция обычно принимает строку и возвращает числовое значение. Хеш-функция всегда должна возвращать одинаковое число для одного и того же ввода. Когда два ввода хешируются с одним и тем же цифровым выходом, это коллизия. Суть в том, чтобы их было как можно меньше.
Поэтому, когда вы вводите пару ключ / значение в хеш-таблице, ключ проходит через хеш-функцию и превращается в число. Это числовое значение затем используется в качестве фактического ключа, в котором значение хранится.
Когда вы снова попытаетесь получить доступ к тому же ключу, хеширующая функция обработает ключ и вернет тот же числовой результат. Затем число будет использовано для поиска связанного значения.
Это обеспечивает очень эффективное время поиска O (1) в среднем.
Реализация на JavaScript
Временная сложность хэш-таблицы
╔═══════════╦═════════╦═══════════════╗
║ Алгоритм ║В среднем║Худший случай ║
╠═══════════╬═════════╬═══════════════╣
║ Space ║ O(n) ║ O(n) ║
║ Search ║ O(1) ║ O(n) ║
║ Insert ║ O(1) ║ O(n) ║
║ Delete ║ O(1) ║ O(n) ║
╚═══════════╩═════════╩═══════════════╝
Задания с freeCodeCamp:
Двоичное дерево поиска
Дерево — это структура данных, состоящая из узлов. Она имеет следующие характеристики:
- Каждое дерево имеет корневой узел (вверху).
- Корневой узел имеет ноль или более дочерних узлов.
- Каждый дочерний узел имеет ноль или более дочерних узлов и т. д.
Двоичное дерево поиска имеет + две характеристики:
- Каждый узел имеет до двух детей(потомков).
- Для каждого узла его левые потомки меньше текущего узла, что меньше, чем у правых потомков.
Двоичные деревья поиска позволяют быстро находить, добавлять и удалять элементы. Способ их настройки означает, что в среднем каждое сравнение позволяет операциям пропускать половину дерева, так что каждый поиск, вставка или удаление занимает время, пропорциональное логарифму количества элементов, хранящихся в дереве.
Реализация на JavaScript
Временная сложность двоичного поиска
╔═══════════╦══════════╦══════════════╗
║ Алгоритм ║В среднем ║Худший случай ║
╠═══════════╬══════════╬══════════════╣
║ Space ║ O(n) ║ O(n) ║
║ Search ║ O(log n) ║ O(n) ║
║ Insert ║ O(log n) ║ O(n) ║
║ Delete ║ O(log n) ║ O(n) ║
╚═══════════╩══════════╩══════════════╝
Задания с freeCodeCamp:
Префиксное дерево
Бор, луч или дерево префикса — это своего рода дерево поиска. Оно хранит данные в шагах, каждый из которых является его узлом. Префиксное дерево из-за быстрого поиска и функции автоматического дописания часто используют для хранения слов.
Каждый узел в префиксном дереве содержит одну букву слова. Вы следуете ветвям дерева, чтобы записать слово, по одной букве за раз. Шаги начинают расходиться, когда порядок букв отличается от других слов в дереве или, когда заканчивается слово.
Каждый узел содержит букву (данные) и логическое значение, указывающее, является ли узел последним узлом в слове.
Посмотрите на изображение, и вы можете создавать слова. Всегда начинайте с корневого узла вверху и двигайтесь вниз.
Показанное здесь дерево содержит слово ball, bat, doll, do, dork, dorm, send, sense.
Реализация на JavaScript
Задания с freeCodeCamp:
- Create a Trie Search Tree
Двоичная куча
Важен порядок между уровнями, но не узлами на одном уровне. На изображении вы можете видеть, что третий уровень минимальной кучи имеет значения 10, 6 и 12. Они расположены не по порядку.
Реализация на JavaScript
Временная сложность двоичной кучи
╔═══════════╦══════════╦═══════════════╗
║ Алгоритм ║В среднем ║ Худший случай ║
╠═══════════╬══════════╬═══════════════╣
║ Space ║ O(n) ║ O(n) ║
║ Search ║ O(n) ║ O(n) ║
║ Insert ║ O(1) ║ O(log n) ║
║ Delete ║ O(log n) ║ O(log n) ║
║ Peek ║ O(1) ║ O(1) ║
╚═══════════╩══════════╩═══════════════╝
Задания с freeCodeCamp:
Графы
Графы представляют собой совокупности узлов (также называемых вершинами) и связей (называемых ребрами) между ними. Графы также известны как сети.
Одним из примеров графов является социальная сеть. Узлы — это люди, а ребра — дружба.
Существует два основных типа графов: ориентированные и неориентированные. Второй тип — это графы без какого-либо направления на ребрах между узлами. Ориентированные графы, напротив, представляют собой графы с направлением на них.
Два частых способа представления графа — это список смежности и матрица смежности.
Список смежности может быть представлен как список, где левая сторона является узлом, а правая — списком всех других узлов, с которыми он соединен.
Матрица смежности представляет собой таблицу чисел, где каждая строка или столбец представляет собой другой узел на графе. На пересечении строки и столбца есть число, которое указывает на отношение. Нули означают, что нет ребер или отношений.
Единицы означают, что есть отношения. Числа выше единицы могут использоваться для отображения разных весов.
Алгоритмы обхода — это алгоритмы для перемещения или посещения узлов в графе. Основными типами алгоритмов обхода являются поиск в ширину и поиск в глубину. Одно из применений заключается в определении того, насколько близко узлы расположены по отношению к корневому узлу. Посмотрите, как реализовать поиск по ширине в JavaScript в приведенном ниже видео.
Реализация на JavaScript
Временная сложность списка смежности (граф)
╔═══════════════╦════════════╗
║ Алгоритм ║ Время ║
╠═══════════════╬════════════╣
║ Storage ║ O(|V|+|E|) ║
║ Add Vertex ║ O(1) ║
║ Add Edge ║ O(1) ║
║ Remove Vertex ║ O(|V|+|E|) ║
║ Remove Edge ║ O(|E|) ║
║ Query ║ O(|V|) ║
╚═══════════════╩════════════╝
Задания с freeCodeCamp:
Если хотите узнать больше:
Книга Grokking Algorithms — лучшая книга на эту тему, если вы новичок в структурах данных / алгоритмах и не обладаете базой компьютерных наук. Автор использует простые объяснения и юмор, рисованные иллюстрации (он является ведущим разработчиком в Etsy), чтобы объяснить некоторые структуры данных, представленные в этой статье.
Источник: https://proglib.io/p/data-structures/
Основные структуры данных. Матчасть. Азы
Все чаще замечаю, что современным самоучкам очень не хватает матчасти. Все знают языки, но мало основы, такие как типы данных или алгоритмы. Немного про типы данных.
Еще в далеком 1976 швейцарский ученый Никлаус Вирт написал книгу Алгоритмы + структуры данных = программы.
40+ лет спустя это уравнение все еще верно. И если вы самоучка и надолго в программировании пробегитесь по статье, можно по диагонали. Можно код кофе. В статье так же будут вопросы, которое вы можете услышать на интервью.
Что такое структура данных?
Структура данных — это контейнер, который хранит данные в определенном макете. Этот «макет» позволяет структуре данных быть эффективной в некоторых операциях и неэффективной в других.
Какие бывают?
Линейные, элементы образуют последовательность или линейный список, обход узлов линеен. Примеры: Массивы. Связанный список, стеки и очереди.
Нелинейные, если обход узлов нелинейный, а данные не последовательны. Пример: граф и деревья.
Основные структуры данных
- Массивы
- Стеки
- Очереди
- Связанные списки
- Графы
- Деревья
- Префиксные деревья
- Хэш таблицы
Массивы
Массив — это самая простая и широко используемая структура данных. Другие структуры данных, такие как стеки и очереди, являются производными от массивов. Изображение простого массива размера 4, содержащего элементы (1, 2, 3 и 4).
Каждому элементу данных присваивается положительное числовое значение (индекс), который соответствует позиции элемента в массиве. Большинство языков определяют начальный индекс массива как 0.
Бывают
Одномерные, как показано выше. Многомерные, массивы внутри массивов.
Основные операции
- Insert-вставляет элемент по заданному индексу
- Get-возвращает элемент по заданному индексу
- Delete-удаление элемента по заданному индексу
- Size-получить общее количество элементов в массиве
Вопросы
- Найти второй минимальный элемент массива
- Первые неповторяющиеся целые числа в массиве
- Объединить два отсортированных массива
- Изменение порядка положительных и отрицательных значений в массиве
Стеки
Стек — абстрактный тип данных, представляющий собой список элементов, организованных по принципу LIFO (англ. last in — first out, «последним пришёл — первым вышел»).
Это не массивы. Это очередь. Придумал Алан Тюринг.
Примером стека может быть куча книг, расположенных в вертикальном порядке. Для того, чтобы получить книгу, которая где-то посередине, вам нужно будет удалить все книги, размещенные на ней. Так работает метод LIFO (Last In First Out). Функция «Отменить» в приложениях работает по LIFO. Изображение стека, в три элемента (1, 2 и 3), где 3 находится наверху и будет удален первым.
Основные операции
- Push-вставляет элемент сверху
- Pop-возвращает верхний элемент после удаления из стека
- isEmpty-возвращает true, если стек пуст
- Top-возвращает верхний элемент без удаления из стека
Вопросы
- Реализовать очередь с помощью стека
- Сортировка значений в стеке
- Реализация двух стеков в массиве
- Реверс строки с помощью стека
Очереди
Подобно стекам, очередь — хранит элемент последовательным образом. Существенное отличие от стека – использование FIFO (First in First Out) вместо LIFO. Пример очереди – очередь людей.
Последний занял последним и будешь, а первый первым ее и покинет. Изображение очереди, в четыре элемента (1, 2, 3 и 4), где 1 находится наверху и будет удален первым
Основные операции
- Enqueue—) — вставляет элемент в конец очереди
- Dequeue () — удаляет элемент из начала очереди
- isEmpty () — возвращает значение true, если очередь пуста
- Top () — возвращает первый элемент очереди
Вопросы
- Реализовать cтек с помощью очереди
- Реверс первых N элементов очереди
- Генерация двоичных чисел от 1 до N с помощью очереди
Связанный список
Связанный список – массив где каждый элемент является отдельным объектом и состоит из двух элементов – данных и ссылки на следующий узел.
Принципиальным преимуществом перед массивом является структурная гибкость: порядок элементов связного списка может не совпадать с порядком расположения элементов данных в памяти компьютера, а порядок обхода списка всегда явно задаётся его внутренними связями.
Бывают
Однонаправленный, каждый узел хранит адрес или ссылку на следующий узел в списке и последний узел имеет следующий адрес или ссылку как NULL. 1->2->3->4->NULL
Двунаправленный, две ссылки, связанные с каждым узлом, одним из опорных пунктов на следующий узел и один к предыдущему узлу.
NULLNULL
Круговой, все узлы соединяются, образуя круг. В конце нет NULL. Циклический связанный список может быть одно-или двукратным циклическим связанным списком.
1->2->3->1 Самое частое, линейный однонаправленный список. Пример – файловая система.
Основные операции
- InsertAtEnd — Вставка заданного элемента в конец списка
- InsertAtHead — Вставка элемента в начало списка
- Delete — удаляет заданный элемент из списка
- DeleteAtHead — удаляет первый элемент списка
- Search — возвращает заданный элемент из списка
- isEmpty — возвращает True, если связанный список пуст
Вопросы
- Реверс связанного списка
- Определение цикла в связанном списке
- Возврат N элемента из конца в связанном списке
- Удаление дубликатов из связанного списка
Графы
Граф-это набор узлов (вершин), которые соединены друг с другом в виде сети ребрами (дугами).
Бывают
Ориентированный, ребра являются направленными, т.е. существует только одно доступное направление между двумя связными вершинами. Неориентированные, к каждому из ребер можно осуществлять переход в обоих направлениях. Смешанные
Встречаются в таких формах как
- Матрица смежности
- Список смежности
Общие алгоритмы обхода графа
- Поиск в ширину – обход по уровням
- Поиск в глубину – обход по вершинам
Вопросы
- Реализовать поиск по ширине и глубине
- Проверить является ли граф деревом или нет
- Посчитать количество ребер в графе
- Найти кратчайший путь между двумя вершинами
Деревья
Дерево-это иерархическая структура данных, состоящая из узлов (вершин) и ребер (дуг). Деревья по сути связанные графы без циклов. Древовидные структуры везде и всюду. Дерево скилов в играх знают все. Простое дерево Типы деревьев Бинарное дерево самое распространенное.
«Бинарное дерево — это иерархическая структура данных, в которой каждый узел имеет значение (оно же является в данном случае и ключом) и ссылки на левого и правого потомка. » — Procs
Три способа обхода дерева
- В прямом порядке (сверху вниз) — префиксная форма.
- В симметричном порядке (слева направо) — инфиксная форма.
- В обратном порядке (снизу вверх) — постфиксная форма.
Вопросы
- Найти высоту бинарного дерева
- Найти N наименьший элемент в двоичном дереве поиска
- Найти узлы на расстоянии N от корня
- Найти предков N узла в двоичном дереве
Trie ( префиксное деревое )
Разновидность дерева для строк, быстрый поиск. Словари. Т9. Вот как такое дерево хранит слова «top», «thus» и «their». Слова хранятся сверху вниз, зеленые цветные узлы «p», «s» и «r» указывают на конец «top», «thus « и «their» соответственно.
Вопросы
- Подсчитать общее количество слов
- Вывести все слова
- Сортировка элементов массива с префиксного дерева
- Создание словаря T9
Хэш таблицы
Хэширование — это процесс, используемый для уникальной идентификации объектов и хранения каждого объекта в заранее рассчитанном уникальном индексе (ключе). Объект хранится в виде пары «ключ-значение», а коллекция таких элементов называется «словарем». Каждый объект можно найти с помощью этого ключа.
По сути это массив, в котором ключ представлен в виде хеш-функции. Эффективность хеширования зависит от
- Функции хеширования
- Размера хэш-таблицы
- Метода борьбы с коллизиями
Пример сопоставления хеша в массиве. Индекс этого массива вычисляется через хэш-функцию.
Вопросы
- Найти симметричные пары в массиве
- Найти, если массив является подмножеством другого массива
- Описать открытое хеширование
Список ресурсов
Вместо заключения
Матчасть так же интересна, как и сами языки. Возможно, кто-то увидит знакомые ему базовые структуры и заинтересуется. Спасибо, что прочли. Надеюсь не зря потратили время =) PS: Прошу извинить, как оказалось, перевод статьи уже был тут и очень недавно, я проглядел.
Если интересно, вот она, спасибо Hokum, буду внимательнее.
Источник: https://habr.com/post/422259/
Базовые алгоритмические конструкции
Логическая структура любого алгоритма может быть представлена комбинацией трех базовых структур: следования (линейная структура), ветвления и цикла.
1. Базовая структура «следование» образуется последовательностью действий, следующих одно за другим. Это самый простой вид алгоритмов, его структура изображена на рисунке 11.3.
Базовая структура «ветвление» обеспечивает выбор одного из альтернативных путей работы алгоритма в зависимости от результата проверки условия (да или нет).
Структура «ветвление» существует в трёх основных вариантах: если-то-иначе (рисунок 11.5.а); если-то (рисунок 11.5.б); выбор-иначе (рисунок 11.5.в).
Базовая структура «цикл» обеспечивает многократное выполнение некоторой совокупности действий. Повторяющаяся совокупность действий называется – телом цикла.
Величина, с которой связано многократное выполнение тела цикла называется – параметром цикла. Параметр цикла имеет начальное и конечное значения.
- Существует три вида циклов:
- – цикл с заранее известным числом повторений (цикл с параметром);
- – цикл с предусловием (цикл «пока»);
- – цикл с постусловием (цикл «до»).
21. Система программирования – часть инструментального программного обеспечения, поддерживающая процесс программирования.
Системы программирования представляют собой единство средств статической (инструментальной) и динамической (исполнительной) поддержки.
В самом общем случае для создания и выполнения программы на выбранном языке программирования нужно иметь следующие компоненты.
1. Текстовый редактор. Так как текст программы записывается с помощью ключевых слов, обычно происходящих от английского языка, и набора стандартных символов для записи всевозможных операций, то сформировать этот текст можно в любом редакторе, получая в итоге текстовый файл с исходным текстом программы.
2. Транслятор. Исходный текст с помощью программы-транслятора переводится в машинный код и таким образом получается объектный модуль (ОМ) программы, т.е. файл с расширением .obj. Трансляторы делятся на компиляторы и интерпретаторы.
3. Компилятор — программа, которая весь ИМ целиком проверяет на ошибки и при их отсутствии, переводит его в машинные коды, получая тем самым ОМ. При нахождении ошибок на экране появляется соответствующее сообщение. После их исправления, транслятор запускается заново.
В общем случае работа компилятора (рисунок 11.16) состоит из четырех основных фаз:
1) лексического анализа, в процессе которого на основе исходного модуля опознаются различные символы и классифицируются как ключевые слова, числовые значения и т.д.;
- 2) синтаксического анализа, в процессе которого определяются синтаксические соотношения;
- 3) генерация объектного модуля программы;
- 4) оптимизация объектного модуля с целью повышения его эффективности.
- 22.
- Язык Си отличается от других языков программирования лаконичностью и сочетанием преимуществ языков программирования высокого и низкого уровней, является основным языком профессионального программирования.
- Алфавит языка программирования – фиксированный для данного языка набор символов, допустимых для построения конструкций программы.
- Алфавит языка С, C++ включает:
- ‒ строчные буквы латинского алфавита (a … z);
‒ прописные буквы латинского алфавита (A… Z);
‒ цифры (0 … 9 );
‒ специальные символы (. , ; + — * / = < > % & ! ( ) { } ^ | ? : [ ] ~ ' » # _ и пробел).
Константа –программный объект, принимающий фиксированное значение, не изменяющееся в процессе исполнения программы.
Переменная – программный объект, который может менять своё значение в процессе выполнения программы.
В C, С++ типы данных подразделяются на две группы: простые (скалярные) и составные (структурированные). К простым типам данных (таблица 12.2.1) относятся: целочисленный, вещественный и символьный типы. К структурированным типам данных относятся: строковый и файловый типы, массивы, структуры, перечисление.
Целочисленные переменные и константы могут быть знаковыми и беззнаковыми, для их различения используют модификаторы signed и unsigned соответственно. Модификатор signed может быть опущен, он подразумевается по умолчанию.
Целочисленные данные на языке С, С++ могут быть представлены в следующих системах счисления:
- ‒ десятичной (например, 123, 10, 55, 2160);
- ‒ восьмеричной (начинаются с ноля, например, 012, 0713, 01255);
- ‒ шестнадцатеричной (начинаются с 0x или 0X, например, 0x12, 0x7D, 0X1A4).
Таблица 12.2.1 – Скалярные типы данных
Идентификатор типа | Длина, байт | Диапазон значений |
Целые беззнаковые типы | ||
unsigned char | 0..255 | |
unsigned int | 0..65535 | |
unsigned short | 0..65535 | |
unsigned long | 0..4294967295 | |
Целые знаковые типы | ||
char | -128..127 | |
int | –32768…32767 | |
short | –32768…32767 | |
long | -2147483648…2147483647 | |
Вещественные типы | ||
float | ±(3.4E–38..3.4E+38) | |
double | ±(1.7E–308..1.7E+308) | |
long double | ±(3.4E–4932.. 3.4E+4932) |
23.
Операции определяют действия, производимые над операндами.
Опера́нд ‒ аргумент операции. Операндом в простейшем случае является константа или переменная.
Каждая операция имеет условное обозначение ‒ знак операции (символ или комбинация символов).
По количеству операндов, участвующих в операции, операции подразделяются на: унарные (один операнд), бинарные (два операнда) и тернарные(три операнда)..
- Синтаксис унарной операции имеет префиксный вид:
- Синтаксис бинарной операции:
Приоритет выполнения операций в С, С++ по убыванию: унарные операции; мультипликативные; аддитивные; сдвиг; , =; == или !=; &; |; ^; &&; ||; простое и составное высказывание.
Операции, объединённые в одну группу имеют одинаковый приоритет.
Унарные операции, операции присваивания и условная операция имеют ассоциативность «справа налево», т.е. первой будет выполняться операция, знак которой записан правее остальных.
Мультипликативные, аддитивные и поразрядные операции обладают свойством коммутативности. Это значит, что результат вычисления коммутативных операций равного приоритета, не зависит от порядка выполнения этих операций. Таким образом, при их выполнении компилятор оставляет за собой право проводить вычисления в любом порядке.
- Результат (выражение записанное на С,С++) имеет вид:
- (a+b) / (c – d)+e / (f * g).
- Математическое выражение
- Запись на С, С++
- 10*x + 3*sqrt(cos(x))
- (sin(2*x) – 1)/(pow(x,2) – 1)
fabs(x) + 2*sin(x)/cos(x)
24.
Выражение ‒ комбинация операндов и операций, задающая порядок вычисления некоторого значения. С целью задания желаемого порядка вычислений, в выражениях часто используют скобки.
- Математические выражения записываются по следующим правилам:
- ‒ запись ведётся в строчку;
- ‒ нельзя опускать знак умножения между сомножителями.
- Приоритет вычисления выражений: (), []; функции; операции.
Из стандартных функций в выражениях чаще других используются математические функции (таблица 12.3.3), содержащиеся в заголовочном файле math.h. При использовании стандартных функций аргумент обязательно заключается в круглые скобки. Основные математические функции С, С++
Математическая функция | Запись на языке С, С++ | Тип аргумента | Тип результата |
½ x½ | abs(x) | int | int |
fabs(x) | float, double, | double | |
sqrt(x) | int, double | double | |
xy | pow(x,y) | double | double |
10x | pow10(x) | int | double |
ex | exp(x) | int, double | double |
ln x | log(x) | int, double | double |
lg x | log10(x) | int, double | double |
sin x | sin(x) | double | double |
cos x | cos(x) | double | double |
tg x | tan(x) | double | double |
arcsin x | asin(x) | double | double |
arcos x | acos(x) | double | double |
arctg x | atan(x) | double | double |
Запись математических выражений:
Математическое выражение | Запись на С, С++ |
10*x + 3*sqrt(cos(x)) | |
(sin(2*x) – 1)/(pow(x,2) – 1) | |
fabs(x) + 2*sin(x)/cos(x) |
25. Программа — это упорядоченная последовательность команд, ведущая к получению результата, согласно алгоритму решения задачи.
- Команда выполняют определенные действия и называется операторомязыка программирования.
- Синтаксически программа состоит из:
- ‒ директив компилятора;
- ‒ описательной части;
- ‒ исполнительной части.
Директивы компиляторадают возможность использовать стандартные функции языка Си. Директива начинается с #includeв скобках указывается имя заголовочного файла (имя библиотека), который содержит необходимую стандартную функцию языка Си.
- Описательная частьсодержит: объявления констант, переменных и объявления функций.
- Объявления констант, переменных и функций необходимы для резервирования места в оперативной памяти компьютера, в момент выполнения программы.
- Синтаксис объявления константы:
- const ;
- Объявление простой переменной имеет следующий синтаксис:
- ;
- Исполнительная часть программы (раздел операторов) является основной частью программы и в общем случае имеет вид:
- Main()
- {
- return 0;}
Для форматного ввода-вывода данных скалярных типов и строк используются стандартные функции ввода/вывода, описанные в библиотеке stdio.h.
- Программа на С++ имеет вид:
- #include //включение заголовочного файла ввода-вывода
- const float pi =3.14; //описание константы π
- int R; /*описание переменных: целого типа,
- float Pi, L, S, V; вещественного типа*/
- main() //главная функция
- {
- cout R; //ввод значения гипотенузы в целом формате
- Pi=3.14; // присвоение значения переменной Pi
- L=2*Pi*R; // вычисление значений
- S= Pi*R*R;
V=4./3.*S*R;
- cout
Источник: https://poisk-ru.ru/s22183t3.html
Урок 19. Структурированные типы данных
Урок из серии: «Язык программирования Паскаль»
Все простые данные, которые рассматривались на предыдущих уроках, имели характерное свойства — неделимость.
Паскаль позволяет работать с более сложными по своей конструкции типами данных. Они называются типами данных пользователя и относятся к структурированным типам (от слова структура).
Отличаются они тем, что переменные структурного типа состоят не из одного элемента (как все стандартные типы — целые, вещественные, символьные и логические), а из нескольких элементов с одним общим именем.
Существует несколько методов структурирования, каждый из которых отличается способом обращения к отдельным компонентам, и способом обозначения компонентов, входящим в структурные данные. По способу организации и типу компонентов в сложных типах данных выделяют следующие разновидности:
- регулярный тип (массивы);
- комбинированный тип (записи);
- файловый тип (файлы);
- множественный тип (множества);
- строковый тип (строки).
Все структурированные типы данных требуют отдельного рассмотрения и будут подробно изучены нами в дальнейшем, а сегодня мы только их определим.
Массив (array). Он представляет собой заранее известное количество однотипных элементов, снабженных индексами. Массив может быть одномерным или многомерным.
Запись (record). Она включает в себя несколько полей, тип которых может отличаться друг от друга. Например, товар на складе описывается следующими величинами: наименование, количество, цена, наличие сертификата качества и т.д. В этом примере наименование – величина типа string, количество – integer, цена – real, наличие сертификата – boolean.
Запись представляет собой наиболее общий и гибкий структурированный тип данных, так как она может быть образована из неоднотипных компонентов и в ней явным образом выражена связь между элементами данных, характеризующими реальный объект.
Строка (string) – последовательность символов кодовой таблицы персонального компьютера. Количество символов в строке может изменяться от 0 до 255.
Множество (set) — это набор взаимосвязанных по какому-либо признаку или группе признаков элементов. Каждый элемент во множестве называется элементом множества. Множество должно состоять из порядковых элементов, и их число не должно превышать 255.
Файл (file) — последовательность однотипных компонентов, записанных на внешнем носителе под определенным именем. Тип этих компонентов может быть любой, за исключением типа — файла. Размер файла не объявляется.
- В этом уроке мы определили структурированные типы данных.
- В следующем уроке более подробно рассмотрим один из видов структурированных данных — массив.
- Следующий урок: «Описание массива»
Источник: https://gospodaretsva.com/urok-19-strukturirovannye-tipy-dannyx.html
3.2.1 Простые и структурированные типы данных. Структуры данных — записи, массивы, списки
Переменные
В ходе программирования обычно необходимо запоминать некоторое количество данных (промежуточные результаты, произошедшие события, входные данные, выходные данные и т.д.). Эти значения приходится держать в памяти.
Для этого объявляется место в памяти, которое используется для хранения данных и это объявленное место называется переменной.
Поскольку данные, которые хранятся, могут быть самыми разными, то при объявлении переменной, объявляется и тип данных, которые будут храниться в этой переменной (тип переменной).
Простые типы
У переменной простого типа под ключевым словом скрывается одно значение (зачастую читаемое как число) и к нему есть прямой доступ. Наиболее известные простые типы это: целое число со знаком, целое число без знака, дробное число (с запятой), символ, логическое значение. В различных языках они могут немного отличаться.
Структурированные типы
В случае структурированных типов под одним ключевым словом группируются несколько совместных значений, таких например как координаты точки или имя и фамилия человека. В таком виде набор данных разом легче передавать. В то же время использовать или изменять данные внутри структуры приходиться по одному.
Массивы
Массив это набор данных одинакового типа, у которых одно имя и которые отделяются друг от друга при помощи индекса. Массивы значительно облегчают обработку однотипных данных.
Простота обработки является результатом того, что в ходе выполнения программы можно просто менять индекс и таким образом проще обращаться к необходимой переменной.
Получение значения переменной из массива при помощи порядкового номера является для компьютера довольно быстрой задачей.
Массивы могут быть одномерными (ряд, строка), двумерными(таблица, матрица), трёхмерными(куб) и т.д.
- Пример (С#, Java)
- int[] mass = newint[10]; //создаётся массив для хранения десяти целых чисел
- mass[0]=1; //по индексу 0 записывается значение 1
Дополнительное чтение: http://enos.itcollege.ee/~jpoial/java/i200loeng4.html
Записи
Для хранения данных разных типов, которые вместе образуют некий связанный набор, используются записи. Например, запись человека формируется из следующих данных: имя(текст), фамилия(текст), пол(логическое значение, 0 — женщина, 1 — мужчина), вес(дробное число). Эти данные образуют одно целое при описании одного человека, однако, сами по себе очень разных типов.
- Пример (C#)
- structinimene {
- publicstring eesnimi;
- publicstring perenimi;
- publicbool sex;
- publicfloat weight;
- }
- С помощью этой записи мы можем создать переменную kasutaja(пользователь) и присвоить пользователю значения имени, фамилии, пола и веса:
- inimene kasutaja;
- kasutaja.eesnimi = «Jaan»;
- kasutaja.perenimi = «Mets»;
- kasutaja.sex = 1;
kasutaja.weight = 80.0;
Списки и деревья
В настоящее время часто для хранения данных используются списки (англ. List). Если каждый элемент списка указывает на следующий за ним элемент, то это связанный список, конец такого списка обозначается пустым элементом (null). Связанный список, где каждый элемент указывает только на следующий за ним, называется однонаправленным списком.
Связанный список, где каждый элемент указывает на следующий и предыдущий элементы, называется двунаправленным. Связанный список, где отсутствуют первый и последний элементы, и каждый элемент указывает на следующий, называется кольцевым списком. Длина связанного списка определяется количеством его элементов. Первый элемент списка это голова (англ.
Head) и остальные элементы — хвост (англ. Tail).
Стек (англ. Stack) это связанный список, в котором элемент добавленный последним — читается первым(англ. LIFO — Last In First Out (последним вошёл первым вышел)).
Очередь (англ. Queue) это связанный список, в котором элемент, добавленный первым — читается первым (англ. FIFO — First In First Out(первым вошёл, первым вышел)).
Дополнительное чтение: http://www.cs.tlu.ee/~inga/alg_andm/linked_list_C_2011.pdf
Дерево — это стрктура данных, в которой данные размещаются в виде дерева, состоит из вершин (англ. Node) и дуг (англ. Edges), которые соединяют вершины (указатели).
Вершины, которые соединены дугами с вершиной расположенной выше называются детьми (англ. Childs), а расположенная выше вершина в этом случае является родителем (англ. Parent). Самая верхняя вершина — это корень (англ. Root).
Вершину, у которой нет детей, называют листом (англ. Leaf).
Двигаясь от вершины к родителю, а оттуда к следующему родителю и т.д. достигаем корня. Предками называются все вершины находящиеся на пути от рассматриваемой вершины до корня. Высота дерева (англ. tree height) определяется самым длинным путём от листа к корню.
В случае упорядоченного дерева, корень и соединённые непосредственно с ним вершины определены, как вершины первого уровня (англ. First level nodes)(дети корня), а вершины соединённые напрямую с вершинами первого уровня — это вершины второго уровня (дети вершин первого уровня) и т.д.; также важным считается порядок детей слева на право.
Дополнительное чтение: http://www.cs.tlu.ee/~inga/alg_andm/tree_gen_2011.pdf
Двоичное дерево — это такое дерево, в котором у каждого родителя может быть один ребёнок, два ребёнка или совсем не быть детей и порядок детей важен.
Двоичное дерево поиска (англ. Binary search tree) — это двоичное дерево, которое упорядочено. Слева от вершины всегда находиться число меньшего размера и справа всегда большего.
При поиске по такому дереву искомое значение сравнивается с корнем и если искомое равно корню, то оно существует и найдено.
Если искомое значение не равно корню, то операция сравнения продолжается дальше, соответственно сравнивая искомое с набором вершин, находящихся справа или слева до тех пор, пока не доходят до листьев.
Если искомое значение равно значению одной из вершин, то искомый элемент найден и существует, однако если такой вершины не найдётся, то искомого элемента в данном дереве не существует. Такой способ поиска в разы быстрее, чем полный обход массива или связанного списка.
Б-дерево (англ. B tree) это дерево поиска, в котором количество детей у каждой вершины находится в промежутке от (t-1) до (2t-1), где t — это любая константа.
Б*-дерево — это Б-дерево, в котором вершины заполняются на 2/3, вначале заполняя две дочерние вершины путём перераспределения ключей и разбивая их после этого на 3 вершины.
За счёт этого Б-дерево позволяет сохранять глубину дерева меньше чем у бинарного дерева. Ограничивая заполнение, также есть возможность на промежуточных уровнях удерживать объем используемой памяти в чётко определённых пределах и в то же время можно сразу добавлять данные в подходящее место.
Дополнительное чтение: http://enos.itcollege.ee/~jpoial/algoritmid/puustruktuurid.html
Источник: https://www.e-ope.ee/_download/euni_repository/file/2530/arendus_vk.zip/321___________.html
Базовые конструкции алгоритмов. Типы данных: простые и структурированные
Метод структурнои̌ алгоритмизации одним ᴎɜ системных методов разработки алгоритмов. Он основан на визуальном представлении алгоритмов в виде последовательностей управляющих структурных фрагментов.
Важно заметить, что каждый алгоритм состоит ᴎɜ элементарных шагов, которые можно объединить в определенные алгоритмические конструкции: линейную (последовательную), разветвляющуюся, циклическую .
Понятие 1
Линейнои̌ называется конструкция алгоритма, реализованная в виде последовательности действий (шагов), причем каждое действие (шаг) выполняется только 1 раз, после каждого действия (шага) выполняется увеличение действия (шага) на 1 до тех пор, пока значение не станет больше конечного параметра алгоритма.
С помощью линейных алгоритмов представляют линейные процессы. Алгоритмы типа используют при описании обобщенного решения задач в виде последовательностей модулей.
Понятие 2
Разветвляющейся (ветвящейся) называют алгоритмическую конструкцию, обеспечивающую выбор между 2 вариантами решений в зависимости от значений входных данных.
Ветвления бывают двух типов: неполное (если—то) и полное (если—то—иначе). С помощью полного ветвления можно организовать 2 ветви в алгоритме (то или иначе), каждая ᴎɜ которых приведет к общей точке их слияния, алгоритм будет выполняться независимо от того, по какому пути пошло решение.
При наличии неполного ветвления предполагаются некоторые действия алгоритма лишь на однои̌ ветви (то), так как вторая отсутствует, одного ᴎɜ результатов проверки действия производить нет необходимости, управление сразу перейдет к точке слияния. Различают 4 базовые варианта структуры ветвления:
- Неполное ветвление типа ʼʼесли – тоʼʼ, при котором всœе действия будут выполняться истинности условия.
- Полное ветвление типа ʼʼесли – то – иначеʼʼ, при котором будут выполняться 2 действия в зависимости от истинности условия.
- Ветвление с выбором типа ʼʼтоʼʼ, при котором действие 1 будет выполняться при условии 1, действие 2 при условии 2 и т.д.
- Ветвление с выбором типа ʼʼиначеʼʼ, при котором при условии 1 будет выполняться действие 1, при условии 2 действие 2 и т.д., а иначе будут выполняться всœе другие действия.
Ни приведены блок-схемы разветвляющихся алгоритмов.
Понятие 3
Циклической (или циклом) называется конструкция алгоритма, в которой некоторая группа идущих подряд действий (шагов) выполняется несколько раз в зависимости от условия задачи и входных данных.
Понятие 4
Такую группу повторяющихся действий на каждом шагу цикла называют телом цикла.
В любой циклической конструкции содержатся элементы ветвящейся конструкции алгоритма.
Различают 3 типа циклических алгоритмов:
- цикл с параметром (арифметический цикл);
- цикл с предусловием;
- цикл с постусловием (последние два называют итерационными).
Арифметический цикл
Цикл с предусловием
Особенностью данного типа цикла при изначальнои̌ ложности значения условного выражения тело цикла не будет выполняться совсœем.
Цикл с постусловием
- В реальных задачах, как правило, присутствует любое количество циклов.
- Ни приведены блок-схемы циклических алгоритмов.
Типы данных: простые и структурированные
К реальным данным, которые обрабатываются программой, относят целые и вещественные числа, логические величины и символы. Они относятся к простым типам данных и называются базовыми.
Все обрабатываемые компьютером данные хранятся в ᴇᴦο ячейках памяти, каждая ᴎɜ которых имеет свой адрес.
В языках программирования существуют переменные, позволяющие не обращать внимание на адреса ячеек памяти и обращаться к ним с помощью имени (идентификатора).
Понятие 5
Переменная представляет собой именованный объект (ячейку памяти), изменяющий свое значение.
Имя переменнои̌ указывает на значение, а адрес и метод её хранения остаются скрытыми от про¬граммиста. Помимо имени и значения переменные имеют свой тип, помогающий опре¬делить какого типа информация находится в памяти.
Типом переменнои̌ задается:
- используемый метод записи информации в ячейки памяти;
- необходимый объем памяти её хранения.
Для каждого типа объем памяти определяется так, чтобы в нᴇᴦο можно было поместить любое значение ᴎɜ допустимо¬го диапазона значений данного типа.
Понятие 6
Переменные, которые присутствуют в программе на протяжении всœᴇᴦο периода её , называются статическими.
Понятие 7
Переменные, которые создаются и уничтожаются на разных этапах выполнения про¬граммы, называются динамическими.
Понятие 8
Остальные данные, значения которых не изменяются на протяжении всœᴇᴦο выполнения программы, называются константами или постоянными.
Константы так имеют тип. Их возможно ука¬зывать явно или с помощью идентификаторов.
Чтобы повысить производительность и качество нужно иметь данные, которые будут максимально приближены к реальным аналогам.
Понятие 9
Тип данных, который позволяет хранить вместе под одним именем несколько переменных, называется структурированным.
Любой язык программирования имеет свои структурированные типы. Рассмотрим одну ᴎɜ таких структур — массив.
Понятие 10
Массивом называют упорядоченную совокупность однотипных величин, которые имеют общее имя, порядковые номера у элементов (индексы).
Элементы массива хранятся в памяти компьютера по соседству в отличие от одиночных элементов. Массивы различают по количеству индексов элементов.
Одномерный массив характеризуется наличием у каждого элемента лишь одного индекса. Примерами одномерных массивов являются геометрическая и арифметическая последовательности, которые определяют конечные ряды чисел.
Понятие 11
Количество элементов массива называется размерностью.
У одномерного массива ᴇᴦο размерность записывают рядом с именем в круглых скобках.
Элементы одномерного массива вводятся поэлемен¬тно, в порядке, необходимом решения конкретнои̌ задачи. При необходимости ввода всœᴇᴦο массива элементы вводятся в порядке возрастания индексов.
Источник: http://referatwork.ru/info-lections-55/tech/view/1377_bazovye_konstrukcii_algoritmov_tipy_dannyh_prostye_i_strukturirovannye
Алгоритмы и структуры данных для начинающих: сложность алгоритмов
Вне зависимости от того, являетесь ли вы студентом или работающим программистом, и от того, в какой области вы работаете, знание алгоритмов и структур данных необходимо. Это важные строительные блоки для решения задач.
Конечно, вы наверняка пользовались списком или стеком, но знаете ли вы, как они работают? Если нет, то вы не можете быть уверены, что принимаете правильные решения относительно того, какой алгоритм использовать.
- Понимание алгоритмов и структур данных начинается с умения определять и сравнивать их сложность.
- Также смотрите другие материалы этой серии: бинарное дерево, стеки и очереди, динамический массив, связный список, сортировка и множества.
- Если не хочется копаться и разбираться, но есть потребность быстро понять основы оценки сложности, идите сюда.
Асимптотический анализ
Когда мы говорим об измерении сложности алгоритмов, мы подразумеваем анализ времени, которое потребуется для обработки очень большого набора данных. Такой анализ называют асимптотическим.
Сколько времени потребуется на обработку массива из десяти элементов? Тысячи? Десяти миллионов? Если алгоритм обрабатывает тысячу элементов за пять миллисекунд, что случится, если мы передадим в него миллион? Будет ли он выполняться пять минут или пять лет? Не стоит ли выяснить это раньше заказчика?
Все решают мелочи!
Порядок роста
Порядок роста описывает то, как сложность алгоритма растет с увеличением размера входных данных. Чаще всего он представлен в виде O-нотации (от нем.
«Ordnung» — порядок) : O(f(x)), где f(x) — формула, выражающая сложность алгоритма. В формуле может присутствовать переменная n, представляющая размер входных данных.
Ниже приводится список наиболее часто встречающихся порядков роста, но он ни в коем случае не полный.
Константный — O(1)
Порядок роста O(1) означает, что вычислительная сложность алгоритма не зависит от размера входных данных. Следует помнить, однако, что единица в формуле не значит, что алгоритм выполняется за одну операцию или требует очень мало времени. Он может потребовать и микросекунду, и год. Важно то, что это время не зависит от входных данных.
public int GetCount(int[] items)
{
return items.Length;
}
Линейный — O(n)
Порядок роста O(n) означает, что сложность алгоритма линейно растет с увеличением входного массива. Если линейный алгоритм обрабатывает один элемент пять миллисекунд, то мы можем ожидать, что тысячу элементов он обработает за пять секунд.
Такие алгоритмы легко узнать по наличию цикла по каждому элементу входного массива.
public long GetSum(int[] items)
{
long sum = 0;
foreach (int i in items)
{
sum += i;
}
return sum;
}
Логарифмический – O( log n)
Порядок роста O( log n) означает, что время выполнения алгоритма растет логарифмически с увеличением размера входного массива. (Прим. пер.
: в анализе алгоритмов по умолчанию используется логарифм по основанию 2). Большинство алгоритмов, работающих по принципу «деления пополам», имеют логарифмическую сложность.
Метод Contains бинарного дерева поиска (binary search tree) также имеет порядок роста O(log n).
Линеарифметический — O(n·log n)
Линеарифметический (или линейно-логарифмический) алгоритм имеет порядок роста O(n·log n). Некоторые алгоритмы типа «разделяй и властвуй» попадают в эту категорию. В следующих частях мы увидим два таких примера — сортировка слиянием и быстрая сортировка.
Квадратичный — O(n 2)
Время работы алгоритма с порядком роста O(n 2) зависит от квадрата размера входного массива. Несмотря на то, что такой ситуации иногда не избежать, квадратичная сложность — повод пересмотреть используемые алгоритмы или структуры данных. Проблема в том, что они плохо масштабируются.
Например, если массив из тысячи элементов потребует
1 000 000 операций, массив из миллиона элементов потребует 1 000 000 000 000 операций. Если одна операция требует миллисекунду для выполнения, квадратичный алгоритм будет обрабатывать миллион элементов 32 года.
Даже если он будет в сто раз быстрее, работа займет 84 дня.
Мы увидим пример алгоритма с квадратичной сложностью, когда будем изучать пузырьковую сортировку.
Наилучший, средний и наихудший случаи
Что мы имеем в виду, когда говорим, что порядок роста сложности алгоритма — O(n)? Это усредненный случай? Или наихудший? А может быть, наилучший?
Обычно имеется в виду наихудший случай, за исключением тех случаев, когда наихудший и средний сильно отличаются.
К примеру, мы увидим примеры алгоритмов, которые в среднем имеют порядок роста O(1), но периодически могут становиться O(n) (например, ArrayList.add).
В этом случае мы будем указывать, что алгоритм работает в среднем за константное время, и объяснять случаи, когда сложность возрастает.
Самое важное здесь то, что O(n) означает, что алгоритм потребует не более n шагов.
Что мы измеряем?
При измерении сложности алгоритмов и структур данных мы обычно говорим о двух вещах: количество операций, требуемых для завершения работы (вычислительная сложность), и объем ресурсов, в частности, памяти, который необходим алгоритму (пространственная сложность).
Алгоритм, который выполняется в десять раз быстрее, но использует в десять раз больше места, может вполне подходить для серверной машины с большим объемом памяти. Но на встроенных системах, где количество памяти ограничено, такой алгоритм использовать нельзя.
В этих статьях мы будем говорить о вычислительной сложности, но при рассмотрении алгоритмов сортировки затронем также вопрос ресурсов.
Операции, количество которых мы будем измерять, включают в себя:
- сравнения («больше», «меньше», «равно»);
- присваивания;
- выделение памяти.
То, какие операции мы учитываем, обычно ясно из контекста.
К примеру, при описании алгоритма поиска элемента в структуре данных мы почти наверняка имеем в виду операции сравнения. Поиск — это преимущественно процесс чтения, так что нет смысла делать присваивания или выделение памяти.
Когда мы говорим о сортировке, мы можем учитывать как сравнения, так и выделения и присваивания. В таких случаях мы будем явно указывать, какие операции мы рассматриваем.
Продолжение следует
На этом мы заканчиваем знакомство с анализом сложности алгоритмов. В следующий раз мы рассмотрим первую структуру данных — связный список.
Перевод статьи «Algorithms and Data Structures»
Источник: https://tproger.ru/translations/algorithms-and-data-structures/