Массив — это упорядоченная коллекция элементов одного типа, доступ к которым выполняется по индексу. Важно представлять массив прежде всего как способ хранить данные рядом в памяти; это дает быстрый доступ и хорошую работу с кэшем процессора.
Ключевые свойства
- Доступ по индексу: выбор элемента занимает постоянное время, обычно обозначается O(1).
- Память: в классическом представлении элементы лежат подряд, поэтому адрес элемента i вычисляется легко.
- Размер: в низкоуровневых языках (C, C++) массив фиксирован по размеру; в высокоуровневых часто есть динамические аналоги.
- Операции вставки/удаления в середине стоят дорого: требуют сдвига элементов, то есть O(n).
- При динамическом расширении (вектор, ArrayList) добавление в конец амортизированно O(1), но перераспределение памяти может происходить иногда.
Варианты в популярных языках
В разных языках под «массивом» понимают немного разное.
- C: массивы фиксированы, тесно связаны с указателями. Выделение и контроль памяти — на программисте.
- C++: есть статические массивы и std::vector — безопасный динамический массив с управлением памяти.
- Java: массивы фиксированы по длине, а ArrayList — динамический аналог поверх массива.
- Python: встроенный list — динамический массив, неравномерный по типу элементов; для чисел есть массивы в модуле array и numpy для быстрых вычислений.
- JavaScript: Array гибкий, служит и как массив, и как список; индексы могут быть «разреженными».
- Go: есть массивы фиксированного размера и срезы (slice) — удобный динамический интерфейс к массивам.
- Rust: [T; N] — статический массив, Vec — динамический вектор с гарантиями безопасности времени компиляции.
Простые примеры
Четкие примеры помогают понять практику.
// C: статический массив и доступ
int a[5] = {1, 2, 3, 4, 5};
int x = a[2]; // 3
a[0] = 10;
# Python: list — динамический массив
a = [1, 2, 3]
a.append(4) # [1, 2, 3, 4]
x = a[1] # 2
del a[0] # [2, 3, 4]
// JavaScript: массивы гибкие
let a = [1,2,3];
a.push(4);
let x = a[2]; // 3
Когда выбирать массив
Массив выгоден, если важен быстрый индексный доступ, компактность хранения и предсказуемость времени чтения. Он идеален для численных задач, буферов ввода/вывода и случаев, где заранее известен размер или можно использовать ресайзинг раз в несколько операций.
Когда не стоит
Если требуется частая вставка и удаление в середине коллекции, лучше выбрать связный список или специализированную структуру. Для ассоциативного доступа по ключу подходят хеш-таблицы и словари, а не массив.
Типичные ошибки и ловушки
- Переполнение буфера: выход за границы массива приводит к неопределенному поведению в низкоуровневых языках.
- Off-by-one — частая логическая ошибка при итерации.
- Ошибочное предположение о копировании: в некоторых языках присваивание массива копирует только ссылку, а не данные.
- Путать логический размер и емкость динамического массива.
Краткая шпаргалка
- Доступ по индексу — быстро, вставка в середину — дорого.
- Низкоуровневые массивы — контроль и риск; высокоуровневые — удобство и абстракции.
- Для численных вычислений выбирайте специализированные библиотеки, они используют массивы эффективно.
Массив — одна из тех структур, которая кажется простой, но решает множество задач. Понимание того, как он хранит данные и как ведут себя операции, даёт реальное преимущество при выборе подходящей структуры в проекте.