Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ A repo for storing Python code and tracking learning progress. All programs are
└── data_structures
├── doubly_linked_list-interactive.py
├── doubly_linked_list.py
├── singly_linked_list-interactive.py
└── singly_linked_list.py
```

Expand Down
149 changes: 149 additions & 0 deletions data_structures/singly_linked_list-interactive.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
"""A singly linked list implementation with an interactive command-line menu."""


from dataclasses import dataclass
import os


@dataclass
class Node:
data: int
next: "Node | None" = None


class SinglyLinkedList:
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
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
self.tail.next = new_node
self.tail = new_node

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
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 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 = SinglyLinkedList(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: SinglyLinkedList) -> 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 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.\n - 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":
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 = SinglyLinkedList(numbers)
command_loop(linked_list)


if __name__ == "__main__":
main()
150 changes: 50 additions & 100 deletions data_structures/singly_linked_list.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
"""A singly linked list implementation with an interactive command-line menu."""
"""A singly linked list implementation."""


from dataclasses import dataclass
import os


@dataclass
Expand All @@ -15,15 +14,8 @@ class SinglyLinkedList:
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
current = new_node
self.tail = current
self.append(item)

def append(self, item: int) -> None:
new_node = Node(item)
Expand All @@ -35,114 +27,72 @@ def append(self, item: int) -> None:
self.tail.next = new_node
self.tail = new_node

def __len__(self) -> int:
size = 0
def remove(self, item: int) -> bool:
current = self.head
previous: Node | None = None
while current is not None:
size += 1
if current.data == item:
if previous is None:
self.head = current.next
else:
previous.next = current.next
if current is self.tail:
self.tail = previous
return True
previous = current
current = current.next
return size
return False

def print_list(self) -> None:
if self.head is None:
print("(empty)")
return
def sort_list(self) -> None:
values: list[int] = []
current = self.head
values: list[str] = []
while current is not None:
values.append(str(current.data))
values.append(current.data)
current = current.next
print(" ".join(values))
values.sort()
self.head = None
self.tail = None
for value in values:
self.append(value)

def remove(self, item: int) -> bool:
def fetch_list(self) -> str:
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
return True
return "(empty)"
values: list[str] = []
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 is self.tail:
self.tail = current
return True
while current is not None:
values.append(str(current.data))
current = current.next
return False
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 = SinglyLinkedList(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: SinglyLinkedList) -> 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 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.\n - 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":
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 = SinglyLinkedList(numbers)
command_loop(linked_list)
linked_list = SinglyLinkedList([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())


if __name__ == "__main__":
Expand Down
Loading