From e8afae31c18224ba20e2d64094303eacde7b2828 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Wahr=C3=A9us?= Date: Sun, 7 Jun 2026 11:11:21 +0200 Subject: [PATCH 1/2] Added non-interactive DLL --- .../doubly_linked_list-interactive.py | 171 ++++++++++++++++ data_structures/doubly_linked_list.py | 182 ++++++------------ 2 files changed, 234 insertions(+), 119 deletions(-) create mode 100644 data_structures/doubly_linked_list-interactive.py diff --git a/data_structures/doubly_linked_list-interactive.py b/data_structures/doubly_linked_list-interactive.py new file mode 100644 index 0000000..901367f --- /dev/null +++ b/data_structures/doubly_linked_list-interactive.py @@ -0,0 +1,171 @@ +"""A doubly linked list implementation with an interactive command-line menu.""" + + +from dataclasses import dataclass +import os + + +@dataclass +class Node: + data: int + prev: "Node | None" = None + next: "Node | None" = None + + +class DoublyLinkedList: + def __init__(self, items: list[int]) -> None: + self.head: Node | None = None + self.tail: Node | None = None + current: Node | None = None + for item in items: + new_node = Node(item) + if current is None: + self.head = new_node + else: + current.next = new_node + new_node.prev = current + current = new_node + self.tail = current + + def append(self, item: int) -> None: + new_node = Node(item) + if self.head is None: + self.head = new_node + self.tail = new_node + return + assert self.tail is not None + new_node.prev = self.tail + self.tail.next = new_node + self.tail = new_node + + def fetch_reversed_list(self) -> str: + if self.head is None: + return "(empty)" + current = self.tail + values: list[str] = [] + while current is not None: + values.append(str(current.data)) + current = current.prev + return " ".join(values) + + def __len__(self) -> int: + size = 0 + current = self.head + while current is not None: + size += 1 + current = current.next + return size + + def print_list(self) -> None: + if self.head is None: + print("(empty)") + return + current = self.head + values: list[str] = [] + while current is not None: + values.append(str(current.data)) + current = current.next + print(" ".join(values)) + + def remove(self, item: int) -> bool: + if self.head is None: + return False + if self.head.data == item: + self.head = self.head.next + if self.head is None: + self.tail = None + else: + self.head.prev = None + return True + current = self.head + while current.next is not None: + if current.next.data == item: + removed_node = current.next + current.next = removed_node.next + if removed_node.next is not None: + removed_node.next.prev = current + if removed_node is self.tail: + self.tail = current + return True + current = current.next + return False + + def sort_list(self) -> None: + values: list[int] = [] + current = self.head + while current is not None: + values.append(current.data) + current = current.next + values.sort() + sorted_list = DoublyLinkedList(values) + self.head = sorted_list.head + self.tail = sorted_list.tail + + +def clear_screen() -> None: + os.system("cls" if os.name == "nt" else "clear") + + +def command_loop(linked_list: DoublyLinkedList) -> None: + clear_screen() + while True: + print("Current list: ", end="") + linked_list.print_list() + print("____________________") + command = input( + "Command options:\n" + " 1 append item\n" + " 2 remove item\n" + " 3 count items\n" + " 4 sort list\n" + " 5 print reverse\n" + " 6 exit\n" + "____________________\n" + "Command: ") + + if command == "1": + try: + item = int(input("\nEnter item to append: ")) + linked_list.append(item) + except ValueError: + input(" - Please enter a valid integer. Press Enter to continue.") + + elif command == "2": + try: + item = int(input("\nEnter item to remove: ")) + removed = linked_list.remove(item) + if not removed: + input(" - No matching item found.\n - Press Enter to continue.") + except ValueError: + input(" - Please enter a valid integer.\n - Press Enter to continue.") + + elif command == "3": + size = len(linked_list) + word = "item" if size == 1 else "items" + input(f"\n - The list contains {size} {word}.\n - Press Enter to continue.") + + elif command == "4": + linked_list.sort_list() + + elif command == "5": + reversed_list = linked_list.fetch_reversed_list() + input(f"\n - Reversed list: {reversed_list}\n - Press Enter to continue.") + + elif command == "6": + print("\n - Goodbye!\n") + break + + else: + input(" - Invalid command.\n - Press Enter to continue.") + + clear_screen() + + +def main() -> None: + numbers = [4, 2, 7, 1, 9, 6, 5, 8, 3] + linked_list = DoublyLinkedList(numbers) + command_loop(linked_list) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/data_structures/doubly_linked_list.py b/data_structures/doubly_linked_list.py index 901367f..f5c3693 100644 --- a/data_structures/doubly_linked_list.py +++ b/data_structures/doubly_linked_list.py @@ -1,8 +1,7 @@ -"""A doubly linked list implementation with an interactive command-line menu.""" +"""A doubly linked list implementation.""" from dataclasses import dataclass -import os @dataclass @@ -16,16 +15,8 @@ class DoublyLinkedList: def __init__(self, items: list[int]) -> None: self.head: Node | None = None self.tail: Node | None = None - current: Node | None = None for item in items: - new_node = Node(item) - if current is None: - self.head = new_node - else: - current.next = new_node - new_node.prev = current - current = new_node - self.tail = current + self.append(item) def append(self, item: int) -> None: new_node = Node(item) @@ -33,138 +24,91 @@ def append(self, item: int) -> None: self.head = new_node self.tail = new_node return + assert self.tail is not None new_node.prev = self.tail self.tail.next = new_node self.tail = new_node - def fetch_reversed_list(self) -> str: - if self.head is None: - return "(empty)" - current = self.tail - values: list[str] = [] + def remove(self, item: int) -> bool: + current = self.head while current is not None: - values.append(str(current.data)) - current = current.prev - return " ".join(values) + if current.data == item: + if current.prev is not None: + current.prev.next = current.next + else: + self.head = current.next + if current.next is not None: + current.next.prev = current.prev + else: + self.tail = current.prev + return True + current = current.next + return False - def __len__(self) -> int: - size = 0 + def sort_list(self) -> None: + values: list[int] = [] current = self.head while current is not None: - size += 1 + values.append(current.data) current = current.next - return size + values.sort() + self.head = None + self.tail = None + for value in values: + self.append(value) - def print_list(self) -> None: + def fetch_list(self) -> str: if self.head is None: - print("(empty)") - return - current = self.head + return "(empty)" values: list[str] = [] + current = self.head while current is not None: values.append(str(current.data)) current = current.next - print(" ".join(values)) + return " ".join(values) - def remove(self, item: int) -> bool: - if self.head is None: - return False - if self.head.data == item: - self.head = self.head.next - if self.head is None: - self.tail = None - else: - self.head.prev = None - return True - current = self.head - while current.next is not None: - if current.next.data == item: - removed_node = current.next - current.next = removed_node.next - if removed_node.next is not None: - removed_node.next.prev = current - if removed_node is self.tail: - self.tail = current - return True - current = current.next - return False + def fetch_reversed_list(self) -> str: + if self.tail is None: + return "(empty)" + values: list[str] = [] + current = self.tail + while current is not None: + values.append(str(current.data)) + current = current.prev + return " ".join(values) - def sort_list(self) -> None: - values: list[int] = [] + def size(self) -> int: + size = 0 current = self.head while current is not None: - values.append(current.data) + size += 1 current = current.next - values.sort() - sorted_list = DoublyLinkedList(values) - self.head = sorted_list.head - self.tail = sorted_list.tail - - -def clear_screen() -> None: - os.system("cls" if os.name == "nt" else "clear") - - -def command_loop(linked_list: DoublyLinkedList) -> None: - clear_screen() - while True: - print("Current list: ", end="") - linked_list.print_list() - print("____________________") - command = input( - "Command options:\n" - " 1 append item\n" - " 2 remove item\n" - " 3 count items\n" - " 4 sort list\n" - " 5 print reverse\n" - " 6 exit\n" - "____________________\n" - "Command: ") - - if command == "1": - try: - item = int(input("\nEnter item to append: ")) - linked_list.append(item) - except ValueError: - input(" - Please enter a valid integer. Press Enter to continue.") - - elif command == "2": - try: - item = int(input("\nEnter item to remove: ")) - removed = linked_list.remove(item) - if not removed: - input(" - No matching item found.\n - Press Enter to continue.") - except ValueError: - input(" - Please enter a valid integer.\n - Press Enter to continue.") - - elif command == "3": - size = len(linked_list) - word = "item" if size == 1 else "items" - input(f"\n - The list contains {size} {word}.\n - Press Enter to continue.") - - elif command == "4": - linked_list.sort_list() - - elif command == "5": - reversed_list = linked_list.fetch_reversed_list() - input(f"\n - Reversed list: {reversed_list}\n - Press Enter to continue.") - - elif command == "6": - print("\n - Goodbye!\n") - break - - else: - input(" - Invalid command.\n - Press Enter to continue.") - - clear_screen() + return size def main() -> None: - numbers = [4, 2, 7, 1, 9, 6, 5, 8, 3] - linked_list = DoublyLinkedList(numbers) - command_loop(linked_list) + linked_list = DoublyLinkedList([4, 2, 7, 1, 9, 6, 5, 8, 3]) + + print("Original list:") + print(linked_list.fetch_list()) + + linked_list.append(10) + print("\nAfter appending 10:") + print(linked_list.fetch_list()) + + linked_list.remove(7) + print("\nAfter removing 7:") + print(linked_list.fetch_list()) + + print(f"\nLength:\n{linked_list.size()}") + + linked_list.sort_list() + print("\nSorted list:") + print(linked_list.fetch_list()) + + print("\nReversed list:") + print(linked_list.fetch_reversed_list()) if __name__ == "__main__": From 1ac6307b03209e7343351a95b381f3eba9c5d9b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Wahr=C3=A9us?= Date: Sun, 7 Jun 2026 11:15:02 +0200 Subject: [PATCH 2/2] Added non-interactive DLL --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 4b7160f..a97f639 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ A repo for storing Python code and tracking learning progress. All programs are │ ├── taskgroup_error_handling.py │ └── worker_pipeline.py └── data_structures + ├── doubly_linked_list-interactive.py ├── doubly_linked_list.py └── singly_linked_list.py ```