Массив — это структура данных, которая хранит набор элементов подряд в памяти и дает доступ к любому из них по целочисленному индексу (порядковому номеру). Индексы идут без пропусков от начального значения, поэтому обращение к элементу по его номеру занимает одинаковое время независимо от размера массива. Дальше разберем виды массивов, как устроен доступ по индексу и заполнение, чем массив отличается от списка и динамического массива, и какая сложность у основных операций.
Содержание
Что такое массив и зачем он нужен
Элементы массива лежат в памяти подряд, одинакового размера. Зная адрес начала и номер элемента, программа вычисляет адрес ячейки простой арифметикой, поэтому чтение и запись по индексу идут за постоянное время O(1) — ради этого массив и используют. У классического (статического) массива при этом два ограничения: фиксированный размер и один тип элементов. Именно они отличают его от более гибких списков Python и массивов JavaScript.
Виды массивов
Массивы различают по трем признакам.
По числу измерений (размерности):
- Одномерные — один индекс, элементы идут цепочкой. Такой массив по смыслу близок к вектору.
- Двумерные — два индекса (строка и столбец), по форме это матрица (таблица).
- Многомерные — три и более индексов. На практике выше трех измерений встречаются редко.
По изменяемости размера:
- Статические (фиксированные) — размер задан при создании и не меняется. Так устроены массивы в C, C++, обычные массивы в Java.
- Динамические — размер меняется во время работы программы: списки Python, массивы JavaScript, std::vector в C++, ArrayList в Java.
По типу элементов:
- Однородные — все элементы одного типа (числовой массив, массив строк). Классический вариант для статических массивов.
- Гетерогенные — элементы разного типа. Так работают список Python и массив JavaScript: в одной структуре можно держать число, строку и объект.
Отдельно стоят структуры, которые называют массивами по аналогии: ассоциативные массивы (доступ по ключу, а не по числовому индексу — словарь dict в Python, объект или Map в JavaScript) и разреженные массивы (хранят только непустые элементы). Строго говоря, это не массивы с непрерывной индексацией, а отдельные структуры данных.
Доступ по индексу
В большинстве языков индексация начинается с нуля: первый элемент имеет индекс 0, последний — на единицу меньше длины. Так устроены C, C++, Java, Python, JavaScript. Но есть исключения: в Pascal нижнюю границу можно задать произвольно, в Lua отсчет идет с единицы. Так что «индексация с нуля» — частое, но не универсальное правило.
Пример на Python (список — это динамический массив):
a = [10, 20, 30, 40, 50]
print(a[0]) # 10 (первый элемент)
print(a[2]) # 30 (третий по счету)
print(a[-1]) # 50 (последний, отрицательный индекс - от конца)
print(len(a)) # 5 (длина)
Двумерный массив в Python обычно представляют как список списков:
matrix = [
[1, 2, 3],
[4, 5, 6],
]
print(matrix[1][2]) # 6 (вторая строка, третий столбец)
Типичная ошибка — выход за границу массива. Разберем тройкой: неверный код, результат, исправление.
Неверно:
a = [10, 20, 30]
print(a[3]) # обращаемся к четвертому элементу, а их три
Результат:
IndexError: list index out of range
Исправление — проверять границу или пользоваться длиной:
a = [10, 20, 30]
i = 3
if 0 <= i < len(a):
print(a[i])
else:
print("нет такого индекса") # нет такого индекса
Важное отличие: Python, Java и JavaScript проверяют границы и сообщают об ошибке, а C и C++ границы не проверяют — выход за пределы массива ведет к неопределенному поведению (можно случайно прочитать или испортить чужую память). Это частая причина уязвимостей в C-коде.
Отличие от списка и динамического массива
Термины «массив» и «список» в разных языках означают разное, и это главный источник путаницы.
- В C и C++ массив — статический блок памяти фиксированного размера, а динамический аналог — отдельный контейнер (std::vector).
- В Python встроенного «массива» в узком смысле нет: тип list — это динамический массив, который растет и хранит разнотипные элементы. Компактный типизированный массив дают модуль array и библиотека NumPy (ndarray).
- В JavaScript тип Array — тоже динамический и гетерогенный, ближе к списку, чем к классическому массиву.
Динамический массив внутри — обычный массив с запасом емкости: когда место кончается, он выделяет блок побольше и копирует данные. Поэтому добавление в конец в среднем стоит O(1) (амортизированно), а отдельная операция расширения — O(n).
Статический массив в C для контраста
Классический статический массив удобно увидеть на C: размер задан на этапе компиляции, тип один, границы не проверяются.
#include <stdio.h>
int main(void) {
int a[5] = {10, 20, 30, 40, 50}; // размер 5 фиксирован
printf("%d\n", a[0]); // 10
printf("%d\n", a[2]); // 30
return 0;
}
Такой массив нельзя расширить: чтобы «добавить» элемент, нужен либо массив побольше заранее, либо динамическое выделение памяти через указатели. Поэтому в C для меняющихся коллекций берут динамическую память или контейнеры C++.
Заполнение массива данными
Способ заполнения зависит от задачи. Основные варианты на Python.
Заполнение одинаковым значением и по формуле:
zeros = [0] * 5
print(zeros) # [0, 0, 0, 0, 0]
squares = [i * i for i in range(1, 6)] # квадраты чисел 1..5
print(squares) # [1, 4, 9, 16, 25]
Заполнение случайными числами:
import random
nums = [random.randint(0, 10) for _ in range(5)]
print(nums) # напр. [3, 9, 0, 7, 2], меняется от запуска
Заполнение вводом с клавиатуры (n чисел в одной строке через пробел) и добавление в конец по одному:
data = [int(x) for x in input().split()] # ввод: 4 8 15 16 23
print(data) # [4, 8, 15, 16, 23]
result = []
for i in range(1, 4):
result.append(i * 10) # добавляем в конец
print(result) # [10, 20, 30]
В JavaScript массив наполняют методами push (в конец), unshift (в начало) и splice (вставка с нужной позиции):
const arr = [2, 3];
arr.push(4); // [2, 3, 4]
arr.unshift(1); // [1, 2, 3, 4]
console.log(arr); // [1, 2, 3, 4]
Сложность операций
Скорость операций зависит от их вида: доступ по индексу мгновенный, а вставка в середину требует сдвига элементов. В таблице — оценки, где n — число элементов.
| Операция | Массив (по индексу) | Комментарий |
|---|---|---|
| Доступ по индексу | O(1) | адрес вычисляется напрямую |
| Изменение элемента по индексу | O(1) | перезапись ячейки |
| Поиск по значению | O(n) | перебор в худшем случае |
| Добавление в конец (динамический) | O(1) амортизированно | иногда расширение за O(n) |
| Вставка/удаление в начало или середину | O(n) | нужен сдвиг остальных элементов |
| Обход всех элементов | O(n) | один проход по массиву |
Практический вывод: массив хорош, когда часто читаешь по индексу и добавляешь в конец, и хуже подходит для частых вставок и удалений в начале или середине — там уместнее связный список или другие структуры.
Выводы
- Массив — это набор элементов подряд в памяти с доступом по целочисленному индексу; чтение и запись по индексу идут за постоянное время O(1).
- Виды массивов различают по размерности (одномерные, двумерные, многомерные), по изменяемости размера (статические и динамические) и по типу элементов (однородные и гетерогенные).
- Индексация чаще всего начинается с нуля, но это не универсальное правило: в Pascal, Lua и ряде языков нижняя граница другая.
- «Массив» и «список» означают разное: в Python list — это динамический массив, типизированный дают array и NumPy, а в C массив статический и фиксированного размера.
- Массив выгоден для доступа по индексу и добавления в конец, но проигрывает на вставках и удалениях в начале или середине — там уместнее другие структуры данных.
Где применяется / связь с практикой
Массивы — базовый строительный блок почти любой программы: буфер данных, таблица, матрица пикселей, список записей из базы, вектор признаков в машинном обучении. Понимание доступа по индексу и стоимости операций напрямую влияет на скорость кода, поэтому массивы спрашивают на технических собеседованиях уже на джуниор-уровне.
Разобраться на практике удобнее всего на Python: списки, срезы, включения (comprehensions) и модуль array дают все виды массивов, а порог входа низкий. Системно пройти основы — от переменных и циклов до структур данных — можно на курсе Python для начинающих. Если хочется сначала посмотреть формат и уровень без оплаты, начните с бесплатных вебинаров — там разбирают реальные задачи и отвечают на вопросы.
Смежные темы: Все о векторах от А до Я, Программирование на C: описание языка, перспективы, основы разработки, Дерево в IT: описание и особенности.
FAQ
Чем массив отличается от списка в Python?
Тип list — это и есть динамический массив общего назначения: хранит разнотипные элементы и меняет размер. Отдельный «массив» дают модуль array и библиотека NumPy — они типизированные и компактнее, быстрее на однотипных числовых данных.
Почему индекс во многих языках начинается с нуля?
Индекс исторически означает смещение от начала массива: у первого элемента оно равно нулю. Так удобнее адресной арифметике в C, и традиция перешла в большинство современных языков. В Pascal или Lua отсчет может начинаться иначе.
Можно ли хранить в одном массиве значения разных типов?
Зависит от языка. В статических массивах C, C++ и Java — нет, тип фиксирован при объявлении. В списке Python и массиве JavaScript — да, они гетерогенные, но без необходимости типы лучше не смешивать: однородные данные обрабатывать проще и быстрее.



