Структуры данных
На прошлой неделе мы изучили указатели. Теперь, используя их, мы будем умно организовывать данные. Группировка связанных данных с помощью struct, связанный список, стек и очередь — всё это мы увидим в живых диаграммах. Именно здесь раскрывается, почему указатели настолько важны.
Что вы узнаете на этом уроке
7.1 Что такое структура?
Под структурой данных (data structure) понимается способ удобно хранить данные и управлять ими. Одну мы уже знаем: массив. Но массив подходит не для всякой задачи.
Например, если вы хотите вставить элемент в середину массива, придётся сдвигать все остальные. Или размер массива задаётся заранее, и потом его непросто увеличить. Для разных задач лучше подходят разные структуры.
На этом уроке мы рассмотрим несколько: struct (группировка связанных данных), связанный список (легко растущий список), стек и очередь (списки с особым порядком). Большинство из них построены поверх указателей с прошлой недели.
7.2 struct: группировка данных
У одного ученика есть имя, возраст и оценка. Их можно хранить в трёх отдельных переменных, но они связаны между собой. struct как раз объединяет эти связанные поля в один новый тип.
К полям мы обращаемся через точку: student.yosh. Введите значения ниже и посмотрите, как заполняется struct:
7.3 Массив struct
struct, как и обычный тип, позволяет создать массив. struct Student sinf[3]; означает: полные данные трёх учеников в одном массиве. Теперь к каждому ученику мы обращаемся по индексу, а к каждому полю — через точку: sinf[1].baho.
Таблица ниже — это три struct учеников. Нажмите на строку и посмотрите, как к ней обращаться:
| # | ism | yosh | baho |
|---|
7.4 Связанный список
Теперь на помощь приходят указатели. Связанный список (linked list) состоит из узлов (node). Каждый узел хранит две вещи: своё значение и указатель на следующий узел. Так узлы соединяются в цепочку, а последний указывает на NULL (список закончился).
На диаграмме ниже каждый прямоугольник — это один узел: слева значение, справа стрелка к следующему. Зелёная голова указывает на первый узел:
7.5 Добавление и удаление
В этом сила связанного списка: чтобы добавить или удалить узел, не нужно сдвигать весь массив — мы лишь переподключаем несколько указателей. Добавление в начало особенно быстрое: новый узел указывает на старую голову, а голова — на новый узел.
Введите значение ниже и поработайте со списком. Новый узел вспыхивает зелёным:
7.6 Массив vs связанный список
Оба хранят данные последовательно, но у каждого есть сильные и слабые стороны. Выбор зависит от задачи:
| Свойство | Массив | Связанный список |
|---|---|---|
| Обращение по индексу | быстро (O(1)) | медленно (проход с начала) |
| Добавление в начало | медленно (нужно сдвигать) | быстро (O(1)) |
| Размер | задан заранее | растёт динамически |
| Память | компактно | в каждом узле есть надбавка на указатель |
Кратко: если вы часто обращаетесь по индексу, лучше массив. Если вы часто добавляете и удаляете в начале, а размер неизвестен, лучше связанный список.
7.7 Стек (LIFO)
Стек (stack) — это особый список, работающий только с одного конца. Добавление элемента называется push, удаление — pop, и оба происходят сверху. Правило: LIFO, то есть последний вошедший выходит первым. Как сложенные друг на друга тарелки.
Попробуйте ниже. Внимание: pop всегда берёт самый верхний:
Сделайте прогноз
В пустой стек мы сделали push 1, затем 2, затем 3. Если потом сделать один pop, что выйдет?
7.8 Очередь (FIFO)
Очередь (queue) похожа на стек, но с обратным правилом. Элемент добавляется с одного конца (enqueue), а берётся с другого (dequeue). Правило: FIFO, то есть первый вошедший выходит первым. Прямо как настоящая очередь в магазине.
Попробуйте ниже. Внимание: dequeue всегда берёт передний (вошедший первым):
7.9 Практика: какую структуру выбрать?
Выбор структуры зависит от характера задачи. Вот повседневные примеры:
- Нужно быстрое обращение по индексу (например таблица): массив
- Размер неизвестен, вы часто добавляете и удаляете: связанный список
- Отмена последнего действия (кнопка «назад»): стек (LIFO)
- Обслуживание по очереди (принтер, сообщения): очередь (FIFO)
- Хранить вместе несколько связанных полей: struct
7.10 Глубже advanced
Кратко познакомимся ещё с двумя мощными структурами. Их глубокое изучение — для следующих этапов, а сейчас получим общее представление.
Хеш-таблица
Хеш-таблица (hash table) — одна из самых быстрых структур для поиска. Она с помощью специальной функции напрямую превращает ключ (например имя) в место в памяти. Поэтому поиск элемента занимает почти один шаг (O(1)). Идеальна для словаря или телефонной книги.
Дерево
Дерево (tree) — ветвящаяся иерархическая структура. Каждый узел может иметь несколько «дочерних» узлов. Используется для папок в файловой системе, семейного древа или быстрого поиска (binary tree). Оно тоже, по сути, построено поверх узлов и указателей.
Словарь терминов
7.11 Тест знаний
16 вопросов. Чтобы завершить неделю, ответьте правильно как минимум на 11 из них.
Поздравляем! Неделя 7 завершена
Теперь вы умеете умно организовывать данные: вы познакомились со struct, связанным списком, стеком и очередью. Эти структуры лежат в сердце почти каждой серьёзной программы.
Следующая неделя: Рекурсия и файлы (функции, вызывающие сами себя, стек вызовов и работа с файлами).
Перейти к следующему модулю