Lecture 1 Abstract Data Types of Complexity Analysis of Big Oh Notation.pptx
yhrcxd8wpm
11 views
16 slides
Mar 04, 2025
Slide 1 of 16
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
About This Presentation
data structure in cs
Size: 110.53 KB
Language: en
Added: Mar 04, 2025
Slides: 16 pages
Slide Content
Abstract Data Types Complexity Analysis Big Oh Notation Data Structures and Algorithms
Abstract Data Types (ADTs) Definition: An ADT is a mathematical model for a certain class of data structures that have similar behavior. It provides a theoretical framework for understanding data types through their operations. Components : Data : The values that the ADT can hold. Operations : The functions or methods that can be performed on the data. These typically include: Creation and initialization Modification (insertion, deletion, updating) Accessing (retrieving data) Traversing (iterating through elements)
Abstract Data Types (ADTs) Encapsulation : ADTs encapsulate the data and the operations, exposing only the necessary parts through a defined interface. This helps in hiding the implementation details and promotes modularity.
Examples of ADTs: List : A collection of elements with a specific order. Operations include adding, removing, and accessing elements. Stack : A collection that follows Last In, First Out (LIFO) principle. Operations include push (add), pop (remove), and peek (access the top element). Queue : A collection that follows First In, First Out (FIFO) principle. Operations include enqueue (add), dequeue (remove), and peek (access the front element). Map/Dictionary : A collection of key-value pairs. Operations include adding, removing, and accessing values by keys.
Code Explanation: __ init __(self) : This is the constructor method that initializes the Stack object. It sets the self.items attribute to an empty list, which will hold the elements in the stack. is_empty (self) : This method checks if the stack is empty. It does this by returning the length of the self.items list, which will be if the stack is empty. push(self, item) : This method adds an item to the top of the stack. It does this by appending the item to the self.items list. This effectively adds the new item to the end of the list, which represents the top of the stack.
Code Explanation: pop(self) : This method removes and returns the top element from the stack. It first checks if the stack is empty using the is_empty () method. If the stack is empty, it prints a message "Stack is empty. Cannot pop." and returns None . If the stack is not empty, it removes and returns the last element from the self.items list, which represents the top of the stack. peek(self) : This method returns the top element of the stack without removing it. It first checks if the stack is empty using the is_empty () method. If the stack is empty, it returns None . If the stack is not empty, it returns the last element of the self.items list, which represents the top of the stack. size(self) : This method returns the number of elements in the stack. It does this by returning the length of the self.items list.
Complexity Analysis Definition: Complexity analysis is a method for determining the efficiency of algorithms. Types of Complexity: Time Complexity: Measures the amount of time an algorithm takes as a function of input size. Space Complexity: Measures the amount of memory an algorithm uses.
Example: Finding the maximum element in a list. def find_max ( lst ): max_val = lst [0] for num in lst : if num > max_val : max_val = num return max_val # Test cases print( find_max ([5, 2, 8, 1, 9])) # Output: 9 print( find_max ([-3, 0, -1, 4])) # Output: 4 print( find_max ([10])) # Output: 10 print( find_max ([])) # Output: IndexError : list index out of range
Explanation: Time Complexity: This code has a time complexity of π(π) because it goes through each element of the list once. Space Complexity: The space complexity is π(1), as it only uses a constant amount of extra space.
Big O Notation Definition: Big O notation provides an upper bound of an algorithm's runtime, showing its worst-case scenario in terms of time complexity. Common Big O Notations: O(1): Constant time. O(log n): Logarithmic time (e.g., binary search). O(n): Linear time. O(n log n): Linearithmic time (e.g., merge sort). O(n^2): Quadratic time (e.g., bubble sort).
Code Example of Different Complexities: O(1): Constant Time def print_first_item ( lst ): print( lst [0]) # Only accesses the first item, so it's constant time
O(log n): Logarithmic Time def binary_search ( lst , target): low, high = 0, len ( lst ) - 1 while low <= high: mid = (low + high) // 2 if lst [mid] == target: return mid elif lst [mid] < target: low = mid + 1 else: high = mid - 1 return -1 # Example usage sorted_list = [1, 3, 5, 7, 9, 11] target_value = 7 result = binary_search ( sorted_list , target_value ) if result != -1: print( f"Target found at index: {result}") else: print("Target not found.")
O(log n): Logarithmic Time A sorted list sorted_list is defined. A target_value to search for is specified. The binary_search function is called with the sorted list and target value, and the result is stored in the result variable. Finally, it checks if the result is not -1 (which would mean the target was found) and prints the index. If the result is -1 , it prints that the target was not found.
O(n): Linear Time def linear_search ( lst , target): for i , item in enumerate( lst ): if item == target: return i return -1 # Example usage my_list = [10, 20, 30, 40, 50] target_value = 30 result = linear_search ( my_list , target_value ) if result != -1: print( f"Target found at index: {result}") else: print("Target not found.")
Explanation: O(1) example only accesses the first element, so it doesnβt depend on list size. O(log n) example uses binary search, halving the search space each time. O(n) example performs a linear search, checking each element until it finds the target.