diff --git a/Data_Structure/README.md b/Data_Structure/README.md new file mode 100644 index 0000000..e69de29 diff --git a/Data_Structure/requirements.txt b/Data_Structure/requirements.txt new file mode 100644 index 0000000..803dc01 --- /dev/null +++ b/Data_Structure/requirements.txt @@ -0,0 +1,4 @@ + +pytest +mypy +flake8 diff --git a/Data_Structure/src/__init__.py b/Data_Structure/src/__init__.py new file mode 100644 index 0000000..9911e26 --- /dev/null +++ b/Data_Structure/src/__init__.py @@ -0,0 +1,4 @@ + +from .stack_reverse import reverse_string +from .queue_with_stacks import QueueWithStacks +from .linked_list_max import LinkedList diff --git a/Data_Structure/src/__pycache__/__init__.cpython-312.pyc b/Data_Structure/src/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..67420fe Binary files /dev/null and b/Data_Structure/src/__pycache__/__init__.cpython-312.pyc differ diff --git a/Data_Structure/src/__pycache__/linked_list_max.cpython-312.pyc b/Data_Structure/src/__pycache__/linked_list_max.cpython-312.pyc new file mode 100644 index 0000000..9d6070d Binary files /dev/null and b/Data_Structure/src/__pycache__/linked_list_max.cpython-312.pyc differ diff --git a/Data_Structure/src/__pycache__/queue_with_stacks.cpython-312.pyc b/Data_Structure/src/__pycache__/queue_with_stacks.cpython-312.pyc new file mode 100644 index 0000000..5f6556f Binary files /dev/null and b/Data_Structure/src/__pycache__/queue_with_stacks.cpython-312.pyc differ diff --git a/Data_Structure/src/__pycache__/stack_reverse.cpython-312.pyc b/Data_Structure/src/__pycache__/stack_reverse.cpython-312.pyc new file mode 100644 index 0000000..aa20b14 Binary files /dev/null and b/Data_Structure/src/__pycache__/stack_reverse.cpython-312.pyc differ diff --git a/Data_Structure/src/linked_list_max.py b/Data_Structure/src/linked_list_max.py new file mode 100644 index 0000000..996aaed --- /dev/null +++ b/Data_Structure/src/linked_list_max.py @@ -0,0 +1,86 @@ +class Node: + """Represents a node in the LinkedList.""" + + def __init__(self, data): + """ + Initialize a node with data and a reference to the next node. + + Args: + data (int or float): The data to be stored in the node. + """ + self.data = data + self.next = None + +class LinkedList: + """LinkedList class to manage the linked list operations.""" + + def __init__(self): + """Initialize an empty LinkedList.""" + self.head = None + + def append(self, value): + """ + Append a new node with the given value to the end of the list. + + Args: + value (int or float): The value to be added to the list. + """ + new_node = Node(value) + if not self.head: + self.head = new_node + else: + current = self.head + while current.next: + current = current.next + current.next = new_node + + def find_max(self): + """ + Find the maximum value in the linked list. + + Returns: + int or float: The maximum value in the linked list. + + Raises: + ValueError: If the list is empty. + """ + if not self.head: + raise ValueError("The linked list is empty.") + + max_value = self.head.data + current = self.head.next + + while current: + if current.data > max_value: + max_value = current.data + current = current.next + + return max_value + + def print_list(self): + """ + Print all the values in the linked list. + + Returns: + list: A list of all values in the linked list. + """ + values = [] + current = self.head + while current: + values.append(current.data) + current = current.next + return values + + +if __name__ == "__main__": + ll = LinkedList() + ll.append(5) + ll.append(10) + ll.append(25) + ll.append(65) + + # Print all items in the linked list + print("LinkedList items:", ll.print_list()) # Output: LinkedList items: [3, 1, 4, 2] + + # Find and print the maximum value + print("Maximum Value in LinkedList:", ll.find_max()) # Output: Maximum Value in LinkedList: 4 diff --git a/Data_Structure/src/queue_with_stacks.py b/Data_Structure/src/queue_with_stacks.py new file mode 100644 index 0000000..2aaca5e --- /dev/null +++ b/Data_Structure/src/queue_with_stacks.py @@ -0,0 +1,71 @@ +class QueueWithStacks: + def __init__(self): + """ + This class implements a queue using two stacks. The enqueue operation is performed on stack1, + and the dequeue operation is performed on stack2. When stack2 is empty, elements are transferred + from stack1 to stack2 to ensure the correct order of elements. + """ + # Initialize two stacks: stack1 for enqueue operations, stack2 for dequeue operations + self.stack1 = [] + self.stack2 = [] + + def enqueue(self, x: int): + """ + Adds an element to the back of the queue. + + Parameters: + x (int): The element to be added to the queue. + + Returns: + None: This method does not return any value. It modifies the queue by adding the given element. + """ + # Push the element onto stack1 + self.stack1.append(x) + + def dequeue(self) -> int: + """ + Removes and returns the front element of the queue. + + The dequeue operation is performed on stack2. If stack2 is empty, elements are transferred + from stack1 to stack2 to ensure the correct order of elements. + + Raises: + IndexError: If both stacks are empty, indicating that the queue is empty. + + Returns: + int: The element at the front of the queue. + """ + # If both stacks are empty, raise an IndexError + if not self.stack1 and not self.stack2: + raise IndexError("Dequeue from an empty queue") + + # If stack2 is empty, transfer elements from stack1 to stack2 + if not self.stack2: + while self.stack1: + self.stack2.append(self.stack1.pop()) + + # Pop the element from stack2 (which is the front of the queue) + return self.stack2.pop() + + def __str__(self): + """ + Returns a string representation of the queue's current state. + + If stack2 is not empty, it represents the front of the queue in reverse order. + Otherwise, stack1 represents the back of the queue. + + Returns: + str: A string representation of the queue. + """ + if not self.stack2: + return str(self.stack1) + return str(self.stack2[::-1] + self.stack1) + +# Example usage: +if __name__ == "__main__": + q = QueueWithStacks() + q.enqueue("Lesson1") + q.enqueue("Lesson2") + q.enqueue("Lesson3") + print(q.dequeue()) # Output: 1 + print(q.dequeue()) # Output: 2 diff --git a/Data_Structure/src/stack_reverse.py b/Data_Structure/src/stack_reverse.py new file mode 100644 index 0000000..6867d36 --- /dev/null +++ b/Data_Structure/src/stack_reverse.py @@ -0,0 +1,85 @@ +class Stack: + + """ + A class representing a stack data structure. + + Attributes: + stack (list): A list to store the elements of the stack. + + Methods: + push(item): Adds an item to the top of the stack. + pop(): Removes and returns the top item from the stack. + is_empty(): Checks if the stack is empty. + """ + def __init__(self): + """ + Initializes an empty list to represent the stack. + """ + self.stack = [] + + def push(self, item): + """ + Adds an item to the top of the stack. + + Parameters: + item (any): The item to be added to the stack. + """ + self.stack.append(item) + + def pop(self): + """ + Removes and returns the top item from the stack. + + Returns: + any: The top item from the stack, or None if the stack is empty. + """ + return self.stack.pop() if not self.is_empty() else None + + def is_empty(self): + """ + Checks if the stack is empty. + + Returns: + bool: True if the stack is empty, False otherwise. + """ + return len(self.stack) == 0 + + +def reverse_string(s: str) -> str: + """ + Reverses a given string using a stack. + + Parameters: + s (str): The input string to be reversed. + + Returns: + str: The reversed string. + + Raises: + ValueError: If the input is not a string. + """ + # Check if the input is a string, raise an error if not + if not isinstance(s, str): + raise ValueError("Input must be a string") + + # Initialize a stack object to store characters + stack = Stack() + + # Iterate over each character in the string + for char in s: + # Push each character onto the stack + stack.push(char) + + # Initialize an empty string to store the reversed string + reversed_str = "" + + # While the stack is not empty + while not stack.is_empty(): + # Pop characters from the stack and append to the reversed string + reversed_str += stack.pop() + + # Return the reversed string + return reversed_str + + +print(reverse_string("Wellcome To My Data Structure Class Let's Have Fun Together!")) diff --git a/Data_Structure/tests/__init__.py b/Data_Structure/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Data_Structure/tests/__pycache__/__init__.cpython-312.pyc b/Data_Structure/tests/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..3b811ed Binary files /dev/null and b/Data_Structure/tests/__pycache__/__init__.cpython-312.pyc differ diff --git a/Data_Structure/tests/__pycache__/test_linked_list_max.cpython-312-pytest-8.3.2.pyc b/Data_Structure/tests/__pycache__/test_linked_list_max.cpython-312-pytest-8.3.2.pyc new file mode 100644 index 0000000..84f74b2 Binary files /dev/null and b/Data_Structure/tests/__pycache__/test_linked_list_max.cpython-312-pytest-8.3.2.pyc differ diff --git a/Data_Structure/tests/__pycache__/test_queue_with_stacks.cpython-312-pytest-8.3.2.pyc b/Data_Structure/tests/__pycache__/test_queue_with_stacks.cpython-312-pytest-8.3.2.pyc new file mode 100644 index 0000000..673ba32 Binary files /dev/null and b/Data_Structure/tests/__pycache__/test_queue_with_stacks.cpython-312-pytest-8.3.2.pyc differ diff --git a/Data_Structure/tests/__pycache__/test_stack_reverse.cpython-312-pytest-8.3.2.pyc b/Data_Structure/tests/__pycache__/test_stack_reverse.cpython-312-pytest-8.3.2.pyc new file mode 100644 index 0000000..8598a86 Binary files /dev/null and b/Data_Structure/tests/__pycache__/test_stack_reverse.cpython-312-pytest-8.3.2.pyc differ diff --git a/Data_Structure/tests/test_linked_list_max.py b/Data_Structure/tests/test_linked_list_max.py new file mode 100644 index 0000000..9628ebb --- /dev/null +++ b/Data_Structure/tests/test_linked_list_max.py @@ -0,0 +1,49 @@ +from src.linked_list_max import LinkedList + +def test_linked_list_find_max(): + """ + This function tests the find_max method of a LinkedList class. + + The LinkedList class is assumed to have the following methods: + - append(value): Adds a new node with the given value to the end of the list. + - find_max(): Returns the maximum value in the list. If the list is empty, raises a ValueError. + + Raises: + AssertionError: If the find_max method does not return the expected maximum value + or does not raise a ValueError for an empty list. + """ + + # Create and populate a LinkedList + ll = LinkedList() + ll.append(5) + ll.append(10) + ll.append(25) + ll.append(65) + + # Print appended items + def print_list(linked_list): + items = [] + current_node = linked_list.head + while current_node: + items.append(current_node.data) + current_node = current_node.next + return items + + print(f"LinkedList items: {print_list(ll)}") + + # Find and print the maximum value + max_value = ll.find_max() + print(f"Maximum Value in LinkedList: {max_value}") # Display maximum value + assert max_value == 65, f"Expected 65 but got {max_value}" + + # Test find_max with an empty LinkedList + try: + empty_ll = LinkedList() + empty_ll.find_max() + assert False, "Did not raise ValueError for empty linked list" + except ValueError as e: + print(f"Error for empty LinkedList: {e}") # Display error message + +if __name__ == "__main__": + test_linked_list_find_max() + print("All LinkedList find_max tests passed!") diff --git a/Data_Structure/tests/test_queue_with_stacks.py b/Data_Structure/tests/test_queue_with_stacks.py new file mode 100644 index 0000000..aec2387 --- /dev/null +++ b/Data_Structure/tests/test_queue_with_stacks.py @@ -0,0 +1,94 @@ +from src.queue_with_stacks import QueueWithStacks + +class QueueWithStacks: + def __init__(self): + """ + This class implements a queue using two stacks. The enqueue operation is performed on stack1, + and the dequeue operation is performed on stack2. When stack2 is empty, elements are transferred + from stack1 to stack2 to ensure the correct order of elements. + """ + self.stack1 = [] # enqueue operations + self.stack2 = [] # dequeue operations + + def enqueue(self, x: int): + """ + Adds an element to the back of the queue. + + Parameters: + x (int): The element to be added to the queue. + """ + self.stack1.append(x) + + def dequeue(self) -> int: + """ + Removes and returns the front element of the queue. + + Raises: + IndexError: If both stacks are empty, indicating that the queue is empty. + + Returns: + int: The element at the front of the queue. + """ + if not self.stack1 and not self.stack2: + raise IndexError("Dequeue from an empty queue") + + if not self.stack2: + while self.stack1: + self.stack2.append(self.stack1.pop()) + + return self.stack2.pop() + + def __str__(self): + """ + Returns a string representation of the queue's current state. + """ + if not self.stack2: + return str(self.stack1) + return str(self.stack2[::-1] + self.stack1) + + +def test_queue_with_stacks(): + """ + This function tests the functionality of a Queue implemented using two Stacks. + + The QueueWithStacks class has two methods: + - enqueue(value): Adds an element to the end of the queue. + - dequeue(): Removes and returns the element at the front of the queue. + + Raises: + IndexError: If the dequeue method is called on an empty queue. + """ + q = QueueWithStacks() + q.enqueue("Lesson1") + q.enqueue("Lesson2") + + # Test first dequeue + first_out = q.dequeue() + print(f"Dequeued: {first_out} | Queue state: {q}") + assert first_out == "Lesson1" + + # Test second and third dequeues + q.enqueue("Lesson3") + print(f"Queue after enqueueing 3-Lessons: {q}") + + second_out = q.dequeue() + print(f"Dequeued: {second_out} | Queue state: {q}") + assert second_out == "Lesson2" + + third_out = q.dequeue() + print(f"Dequeued: {third_out} | Queue state: {q}") + assert third_out == "Lesson3" + + # Test dequeue on an empty queue + try: + empty_queue = QueueWithStacks() + empty_queue.dequeue() + assert False, "Did not raise IndexError for empty queue" + except IndexError: + print("IndexError raised as expected for empty queue") + assert True + + +if __name__ == "__main__": + test_queue_with_stacks() + print("All QueueWithStacks tests passed!") diff --git a/Data_Structure/tests/test_stack_reverse.py b/Data_Structure/tests/test_stack_reverse.py new file mode 100644 index 0000000..528fb83 --- /dev/null +++ b/Data_Structure/tests/test_stack_reverse.py @@ -0,0 +1,37 @@ +from src.stack_reverse import reverse_string + +def test_reverse_string(): + """ + This function tests the reverse_string function from the src.stack_reverse module. + + It tests the reverse_string function with various inputs and asserts that the + expected output matches the actual output. It also tests the function's behavior when + given a non-string input. + + Raises: + AssertionError: If any of the test cases fail. + ValueError: If the reverse_string function raises a ValueError for a non-string input. + """ + + # Test cases with assertions and print statements + s = "Wellcome To My Data Structure Class Let's Have Fun Together!" + reversed_s = reverse_string(s) + print(f"Original String: {s}, Reversed String: {reversed_s}") # Display output + assert reversed_s == "!rehtegoT nuF evaH s'teL ssalC erutcurtS ataD yM oT emoclleW" + + assert reverse_string("") == "" + assert reverse_string("a") == "a" + assert reverse_string("madam") == "madam" + assert reverse_string("wuodrose") == "esordouw" + + # Test with non-string input + try: + reverse_string(12345) + assert False, "Did not raise ValueError for non-string input" + except ValueError: + print("ValueError raised as expected for non-string input") # Display output + assert True + +if __name__ == "__main__": + test_reverse_string() + print("All reverse_string tests passed!")