class Node: def __init__(self, data: int | float | list | dict | tuple | set): self.data = data self.next = None self.prev = None class DoublyLinkedList: def __init__(self): self.head = None def append(self, data): """Add a node with the given data to the end of the list.""" new_node = Node(data) if not self.head: self.head = new_node return curr = self.head while curr.next: curr = curr.next curr.next = new_node new_node.prev = curr def prepend(self, data): """Add a node with the given data to the beginning of the list.""" new_node = Node(data) if self.head: self.head.prev = new_node new_node.next = self.head self.head = new_node def insert_at_position(self, position, data): """Insert a node with the given data at the specified position (0-based).""" if position <= 0 or not self.head: self.prepend(data) return new_node = Node(data) curr = self.head index = 0 while curr.next and index < position - 1: curr = curr.next index += 1 new_node.next = curr.next new_node.prev = curr if curr.next: curr.next.prev = new_node curr.next = new_node def delete_value(self, value): """Remove the first node that contains the specified value.""" curr = self.head while curr: if curr.data == value: if curr.prev: curr.prev.next = curr.next else: self.head = curr.next if curr.next: curr.next.prev = curr.prev return True curr = curr.next return False def search(self, value): """Return True if a node with the specified value exists, otherwise False.""" curr = self.head while curr: if curr.data == value: return True curr = curr.next return False def print_list(self): """Print all elements in the list in order.""" elems = [] curr = self.head while curr: elems.append(str(curr.data)) curr = curr.next print(" <-> ".join(elems))