Где-то в Medium я нашел Google Interview University (взгляните!) И решил последовать некоторым из предоставленных советов; начав с создания собственной реализации базовых структур данных.
Что такое динамический массив?
С точки зрения непрофессионала, динамический массив похож на массив, но с той разницей, что его размер может динамически изменяться во время выполнения.
Элементы массива занимают непрерывный блок памяти, и после создания его размер не может быть изменен. Динамический массив может после заполнения массива выделить больший кусок памяти, скопировать содержимое из исходного массива в это новое пространство и продолжить заполнение доступных слотов.
В бэкэнде динамические массивы выделяют заранее определенный объем памяти при создании, который затем увеличивается в определенном размере, когда это необходимо. Эти параметры, начальный размер и фактор роста являются центральными с точки зрения производительности. Если исходный размер и фактор роста малы, вы будете часто перераспределять память, что плохо; с другой стороны, если они имеют более высокое значение, у вас, вероятно, будет много неиспользуемой памяти, и операция изменения размера может занять больше времени. Здесь очевиден компромисс.
Примеры динамических массивов в распространенных языках: ArrayList
в Java и C #, Vector
в C ++, List<>
в .NET, list
в Python и другие.
Реализация
Я начал писать динамический массив целых чисел на C. При этом я заметил, что было бы лучше написать массив класса, который управлял бы структурой данных, поэтому я переключился на C ++. И, поскольку мы уже на C ++, я решил создать класс шаблона, чтобы мы могли управлять динамическим массивом любого типа :).
Это мой класс Array; здесь важными методами являются Array
(конструктор), push
, pop
, set
, get
и resize
. Используемые атрибуты: m_size
, текущий размер массива, m_capacity
, текущая емкость массива иm_data
, указатель на данные массива. Я также объявил некоторые утилитарные методы, такие как size()
, capacity()
& print()
.
Конструктор
Устанавливает размер и емкость. Здесь я использовал заранее определенное значение начальной емкости. Размер равен нулю, так как при создании в массиве нет данных. Также выделяется место для массива.
Деструктор
Освобождает выделенную память m_data
.
Толкать
Помещает значение в верхнюю часть массива. Перед отправкой убедитесь, что в массиве есть свободное место! В противном случае может возникнуть ошибка сегментации.
Поп
Возвращает значение в верхней части массива и удаляет его из массива, уменьшая его размер на единицу.
Установленный
Устанавливает значение в массиве для данного индекса. Если индекс больше текущей емкости, размер массива изменяется и заполняется нулями, пока индекс не будет достигнут.
Изменить размер
Как следует из названия, он изменяет размер массива, заставляя его увеличиваться в определенном размере. Для этого я использовал функцию realloc
. Вы тоже можете использовать malloc/memcpy
. Если realloc
успешно, m_data
указывает на вспомогательный указатель tmp.
Тестирование
Это небольшой пример того, как использовать структуру данных, создавая массив целых чисел и управляя им.
И результат…
Код
Я оставлю полную реализацию в моем Github, не стесняйтесь комментировать или предлагать изменения, если вы видите что-то не так :)