Файл: Динамические структуры данных. Списки (Основные понятия).pdf

ВУЗ: Не указан

Категория: Курсовая работа

Дисциплина: Не указана

Добавлен: 24.04.2023

Просмотров: 744

Скачиваний: 5

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

Стеком называется структура данных, в которой новый элемент всегда помещается в начало списка, и при чтении также берется из начала, реализуя алгоритм LIFO (Last In – Firs Out).

Схема представления стека приведено на рисунке 11.

Рисунок 11 – Стек

В основе стека лежит динамический список. С учетом того, что работа всегда ведется только с головным элементом, исчезает необходимость просмотра элементов стека.

Очередь – это структура данных, представляющая собой последовательность элементов, образованная в порядке их поступления. Данный вид структуры реализует алгоритм FIFO (First In – First Out).

Частный случай очереди – дек (двусторонняя очередь). Схема реализации очереди представлена на рисунке 12.

Рисунок 12 – Очередь

Очередь также реализуется на базе линейного списка. Важно учесть, что работа здесь ведется как с началом, так и с концом очередь, следовательно, необходимо хранить два указателя – на голову и на хвост списка [9].

2.3. Деревья

Ссылки могут использоваться не только для представления линейных списков, возможны и другие способы – например, структуры, состоящие из записей, связанных между собой системой ссылок. При этом каждая запись может содержать ссылки на несколько других записей. Подобное представление называется ориентированным графом [3].

Дерево – частный случай графа. Дерево обладает следующими свойствами:

  • подструктуры, связанные с некоторым узлом, не связаны между собой;
  • существует единственный узел, называемый корнем дерева;
  • из корня, путем просмотра конечного числа ребер, можно достичь любого узла дерева.

Схема представления дерева приведена на рисунке 13.

Рисунок 13 – Дерево

Здесь узел А – это корень дерева. Узлы Г, Д, Е, И, К, Л – листья дерева (терминальные узлы).

Частным случаем дерева, которое наиболее часто используется в программировании, является двоичное (бинарное) дерево. Каждый узел такого дерева имеет не более двух узлов-отростков (см. рисунок 14) [20].

Бинарное дерево называется полным, если присутствуют все листья одного уровня, и каждая внутренняя вершина имеет непустые правое и левое поддеревья. Дерево называется сбалансированным тогда и только тогда, когда высоты двух поддеревьев каждой из его вершин отличаются не более чем на единицу.


Существует несколько способов обхода дерева (просмотра всех его элементов):

  • обход в глубину – посетить корень дерева, обойти левое поддерево, обойти правое поддерево;
  • обход в ширину – данный метод основан на использовании очереди. Алгоритм обхода:

Рисунок 14 – Двоичное дерево

    • изъять из очереди очередную вершину. Поместить в очередь ее дочерние вершины по порядку;
    • если очередь пуста – конец обхода, иначе перейти к п.1 [11].

Таким образом, в рамках данной главы рассмотрены динамические структуры данных. Приведена их классификация по нескольким признакам. Отдельное внимание уделяется динамическим структурам данных – спискам и деревьям.

3. ПРАКТИЧЕСКАЯ ЧАСТЬ

3.1. Линейный односвязный список

Класс линейного односвязного списка должен содержать в себе указатель на первый элемент списка. В качестве элемента списка необходимо использовать структуру из двух полей:

  • значение элемента списка;
  • указатель на следующий элемент списка.

Таким образом, в разрабатываемом классе содержится всего один элемент – указатель на голову списка, а также необходимо предусмотреть методы:

  • конструктор;
  • деструктор;
  • добавление элемента в начало списка;
  • добавление элемента в конец списка;
  • удаление из списка последнего элемента;
  • поиск элемента по значению;
  • вывод содержимого списка на экран.

Элемент структуры описывается следующим образом:

public: struct Node //описание узла - элемента списка

{

int value; //значение

struct Node *next; //ссылка на следующий элемент

} *head;

В данной записи head – это и есть указатель на первый элемент списка.

Методы класса:

  • Spisok() – конструктор без параметров;
  • Spisok(int val) – конструктор с параметром;
  • ~Spisok() – деструктор;
  • void AddAtBegin(int val) – добавление элемента в начало списка;
  • void AddAtEnd(int val) – добавление элемента в конец списка;
  • void Delete() – удаление из списка последнего элемента;
  • int Search(int val) – поиск элемента по значению;
  • void Show() – вывод содержимого списка на экран.

Блок-схемы методов представлены на рисунках 15-21.


Рисунок 15 – Блок-схема конструктора

Рисунок 16 – Блок-схема деструктора

Рисунок 17 - Блок-схема метода добавления элемента в конец списка

Рисунок 18 - Блок-схема метода добавления элемента в начало списка

Рисунок 19 - Блок-схема метода удаления элемента из конца списка

Рисунок 20 - Блок-схема метода поиска элемента по значению

Рисунок 21 - Блок-схема метода вывода списка на экран

Для тестирования методов класса было создано приложение, исходный код которого надохится в приложении 1. Результаты тестирования программы представлены на рисунках 22-36.

Рисунок 22 – Окно запуска приложения

Рисунок 23 – Попытка просмотра пустого списка

Рисунок 24 – Попытка удаления из пустого списка

Рисунок 25 – Добавление элемента в начало списка

Рисунок 26 – Результат добавления элемента в начало списка

Рисунок 27 – Просмотр содержимого списка

Рисунок 28 – Добавление элемента в конец списка

Рисунок 29 – Результат добавления элемента в конец списка

Рисунок 30 – Просмотр содержимого списка

Рисунок 31 – Удаление последнего элемента

Рисунок 32 – Просмотр содержимого списка после удаления


Рисунок 33 – Поиск отсутствующего элемента

Рисунок 34 – Результат поиска отсутствующего элемента

Рисунок 35 – Поиск существующего элемента

Рисунок 36 – Результат поиска существующего элемента

3.2. Циклический двусвязный список

Класс циклического двусвязного списка должен содержать в себе указатель на первый элемент списка. В качестве элемента списка необходимо использовать структуру из трех полей:

  • значение элемента списка;
  • указатель на следующий элемент списка;
  • указатель на предыдущий элемент списка.

Таким образом, в разрабатываемом классе содержится всего один элемент – указатель на голову списка, а также необходимо предусмотреть методы:

  • конструктор;
  • деструктор;
  • добавление элемента в начало списка;
  • добавление элемента в конец списка;
  • удаление из списка последнего элемента;
  • поиск элемента по значению;
  • вывод содержимого списка на экран.

Элемент структуры описывается следующим образом:

public: struct Node //описание узла - элемента списка

{

int value; //значение

struct Node *next; //ссылка на следующий элемент

struct Node *back; //ссылка на предыдущий элемент

} *head;

В данной записи head – это и есть указатель на первый элемент списка.

Методы класса:

  • Spisok() – конструктор без параметров;
  • Spisok(int val) – конструктор с параметром;
  • ~Spisok() – деструктор;
  • void AddAtBegin(int val) – добавление элемента в начало списка;
  • void AddAtEnd(int val) – добавление элемента в конец списка;
  • void Delete() – удаление из списка последнего элемента;
  • int Search(int val) – поиск элемента по значению;
  • void Show() – вывод содержимого списка на экран.

Блок-схемы данных методов представлены на рисунках 37-

Рисунок 37 – Блок-схема конструктора

Рисунок 38 – Блок-схема деструктора

Рисунок 39 – Блок-схема метода добавления элемента в начало списка


Рисунок 40 – Блок-схема метода добавления элемента в конец списка

Рисунок 41 – Блок-схема метода удаления элемента из конца списка

Рисунок 42 – Блок-схема метода поиска элемента по значению

Рисунок 43 – Блок-схема метода вывода списка на экран

Для тестирования методов класса было создано приложение, исходный код которого надохится в приложении 2. Результаты тестирования программы представлены на рисунках 44-58.

Рисунок 44 – Окно запуска приложения

Рисунок 45 – Попытка просмотра пустого списка

Рисунок 46 – Попытка удаления из пустого списка

Рисунок 47 – Добавление элемента в начало списка

Рисунок 48 – Результат добавления элемента в начало списка

Рисунок 49 – Просмотр содержимого списка

Рисунок 50 – Добавление элемента в конец списка

Рисунок 51 – Результат добавления элемента в конец списка

Рисунок 52 – Просмотр содержимого списка

Рисунок 53 – Удаление последнего элемента

Рисунок 54 – Просмотр содержимого списка после удаления

Рисунок 55 – Поиск отсутствующего элемента

Рисунок 56 – Результат поиска отсутствующего элемента

Рисунок 57 – Поиск существующего элемента