Лабы 2022-2023 / 2 сем / Baraeva_Elizaveta_lb2
.docМИНОБРНАУКИ РОССИИ
Санкт-Петербургский государственный
электротехнический университет
«ЛЭТИ» им. В. И. Ульянова (Ленина)
Кафедра МО ЭВМ
отчет
по лабораторной работе №2
по дисциплине «Информатика»
Тема: Алгоритмы и структуры данных в Python
Студентка гр. 2383 |
|
Бараева Е. Н. |
Преподаватель |
|
Иванов Д. В. |
Санкт-Петербург
2023
Цель работы.
Научиться создавать связные однонаправленные списки. Написать программу с созданием однонаправленного списка с методами для него.
Задание.
Вариант 1
Node
Класс, который описывает элемент списка.
Класс Node должен иметь 2 поля:
__data # данные, приватное поле
__next__ # ссылка на следующий элемент списка
Вам необходимо реализовать следующие методы в классе Node:
__init__(self, data, next) конструктор, у которого значения по умолчанию для аргумента next равно None.
get_data(self) метод возвращает значение поля __data.
__str__(self) перегрузка метода __str__. Описание того, как должен выглядеть результат вызова метода смотрите ниже в примере взаимодействия с Node.
Linked List
Класс, который описывает связный однонаправленный список.
Класс LinkedList должен иметь 2 поля:
__head__ # данные первого элемента списка
__length # количество элементов в списке
Вам необходимо реализовать конструктор:
__init__(self, head) конструктор, у которого значения по умолчанию для аргумента head равно None. Если значение переменной head равна None, метод должен создавать пустой список. Если значение head не равно None, необходимо создать список из одного элемента.
и следующие методы в классе LinkedList:
__len__(self) перегрузка метода __len__.
append(self, element) добавление элемента в конец списка. Метод должен создать объект класса Node, у которого значение поля __data будет равно element и добавить этот объект в конец списка.
__str__(self) перегрузка метода __str__. Описание того, как должен выглядеть результат вызова метода смотрите ниже в примере взаимодействия с LinkedList.
pop(self) удаление последнего элемента. Метод должен выбрасывать исключение IndexError с сообщением "LinkedList is empty!", если список пустой.
clear(self) очищение списка.
delete_on_end(self, n) удаление n-того элемента с конца списка. Метод должен выбрасывать исключение KeyError, с сообщением "<element> doesn't exist!", если количество элементов меньше n.
Вам не требуется реализовывать создание экземпляров ваших классов и вызов методов, это сделает проверяющая система.
В отчете вам требуется:
Указать, что такое связный список. Основные отличия связного списка от массива.
Указать сложность каждого метода.
Описать возможную реализацию бинарного поиска в связном списке. Чем отличается реализация алгоритма бинарного поиска для связного списка и для классического списка Python?
Выполнение работы.
Первым делом был создан класс Node, который описывает элемент списка. Затем были созданы поля __data (данные, приватное поле) и __next__ (ссылка на следующий элемент списка). Также у класса были созданы методы. __init__(self, data, next) – конструктор, у которого значения по умолчанию для аргумента next равно None. get_data(self) – метод, возвращающий значение поля __data. __str__(self) – метод, возвращающий форматную строку с элементом. После этого был создан класс LinkedList, который описывает связный однонаправленный список. В нем также были созданы 2 поля: __head__ (данные первого элемента списка), __length (количество элементов в списке). Затем было создано несколько методов. __len__(self) – метод, возвращающий значение поля __length. append(self, element) – метод, добавляющий элемент в конец списка. Если «голова» списка существует, то с помощью цикла while находится последний элемент списка и после него в конец добавляется новый элемент, иначе элемент добавляется как «голова» списка. В конце длина увеличивается на 1. __str__(self) – метод, возвращающий форматную строку со списком. pop(self) – метод, удаляющий последний элемент списка. Если длина 0, то метод «выбрасывает» исключение: IndexError("LinkedList is empty!"). Если список состоит только из «головы», то «голове» присваивается None. В других случаях цикл после того, как дойдет до последнего элемента, присвоит ему None. В конце длина уменьшается на 1. delete_on_end(self, n) – метод, удаляющий n-ый элемент с конца списка. Если n больше длины списка или меньше 1 или список пуст, то «выбрасывается» исключение KeyError("<element> doesn't exist!"), иначе обрабатывается несколько случаев: если нужно удалить «голову» списка, последний элемент списка, элемент не последний и не первый, если длина списка и n равны. В конце длина уменьшатся на 1. clear(self) – метод, очищающий список. С помощью цикла while удаляются все элементы списка.
1) Связный список – базовая динамическая структура данных, состоящая из узлов, содержащих данные и ссылки на следующий и/или предыдущий узел списка. Принципиальным преимуществом перед массивом является структурная гибкость: порядок элементов связного списка может не совпадать с порядком расположения элементов данных в памяти компьютера, а порядок обхода списка всегда явно задаётся его внутренними связями.
2) append(self, element) – O(1), pop(self) – O(n), delete_on_end(self, n) – O(n), clear(self) – O(n).
3) Бинарный поиск для связного списка будет неэффективен, нежели для массива, из-за невозможности обращения к элементу по индексу. Эффективнее в данном случае будет пройтись по списку, сравнивая каждый элемент списка с искомым элементом.
Разработанный программный код см. в приложении А.
Тестирование.
Результаты тестирования представлены в табл. 1.
Таблица 1 – Результаты тестирования
№ п/п |
Входные данные |
Выходные данные |
Комментарии |
1. |
node = Node(10) print(node) node.__next__ = Node(5, None) print(node) |
data: 10, next: None data: 10, next: 5 |
Проверка создания элемента списка. Верно. |
2. |
List = LinkedList() List.append(10) print(List) |
LinkedList[length = 1, [data: 10, next: None]] |
Проверка создания списка. Верно. |
3. |
List = LinkedList() List.append(10) List.append(6) List.append(-23) List.append(0) print(List) List.pop() print(List) List.delete_on_end(3) print(List) List.clear() print(List) |
LinkedList[length = 4, [data: 10, next: 6; data: 6, next: -23; data: -23, next: 0; data: 0, next: None]] LinkedList[length = 3, [data: 10, next: 6; data: 6, next: -23; data: -23, next: None]] LinkedList[length = 2, [data: 6, next: -23; data: -23, next: None]] LinkedList[] |
Проверка методов списка. Верно. |
Вывод.
Были изучены односвязные списки, а также написана программа с их реализацией. Были реализованы классы Node и NodeList, методы для работы с данными классами.
ПРИЛОЖЕНИЕ А ИСХОДНЫЙ КОД ПРОГРАММЫ
Название файла: main_lb2.py
class Node:
def __init__(self, data, next=None):
self.__data = data
self.__next__ = next
def get_data(self):
return self.__data
def __str__(self):
nxt = self.__next__.__data if self.__next__ else None
return f'data: {self.__data}, next: {nxt}'
class LinkedList:
def __init__(self, head=None):
self.__head__ = head
self.__length = 0
def __len__(self):
return self.__length
def append(self, element):
if self.__head__:
next = self.__head__
while next.__next__:
next = next.__next__
next.__next__ = Node(element)
else:
self.__head__ = Node(element)
self.__length += 1
def __str__(self):
if self.__length:
next = self.__head__
s = ''
while next.__next__:
s += f'data: {next.get_data()}, next: {next.__next__.get_data()}; '
next = next.__next__
s += f'data: {next.get_data()}, next: None'
return f'LinkedList[length = {self.__length}, [{s}]]'
else:
return 'LinkedList[]'
def pop(self):
if self.__length == 0:
raise IndexError("LinkedList is empty!")
if self.__head__.__next__ is None:
self.__head__ = None
else:
next = self.__head__
for i in range(self.__length - 2):
next = next.__next__
next.__next__ = None
self.__length -= 1
def delete_on_end(self, n):
next = self.__head__
if n > self.__length or self.__head__ is None or n < 1:
raise KeyError("<element> doesn't exist!")
elif self.__length == 1:
self.__head__ = None
elif self.__length == n:
self.__head__ = self.__head__.__next__
elif self.__length >= n:
for i in range(self.__length - n - 1):
next = next.__next__
next.__next__ = next.__next__.__next__
elif n == 1:
for i in range(self.__length - 2):
next = next.__next__
next.__next__ = None
self.__length -= 1
def clear(self):
while self.__length:
self.pop()
