diff --git a/2_BubbleSort/2.py b/2_BubbleSort/2.py new file mode 100644 index 0000000..a6e01ca --- /dev/null +++ b/2_BubbleSort/2.py @@ -0,0 +1,84 @@ +# ### Bubble Sort Exercise + +# Modify [bubble_sort function](https://github.com/codebasics/data-structures-algorithms-python/blob/master/algorithms/2_BubbleSort/bubble_sort.py) such that it can sort following list of transactions happening in an electronic store, +# ``` +# elements = [ +# { 'name': 'mona', 'transaction_amount': 1000, 'device': 'iphone-10'}, +# { 'name': 'dhaval', 'transaction_amount': 400, 'device': 'google pixel'}, +# { 'name': 'kathy', 'transaction_amount': 200, 'device': 'vivo'}, +# { 'name': 'aamir', 'transaction_amount': 800, 'device': 'iphone-8'}, +# ] +# ``` +# bubble_sort function should take key from a transaction record and sort the list as per that key. For example, +# ``` +# bubble_sort(elements, key='transaction_amount') +# ``` +# This will sort elements by transaction_amount and your sorted list will look like, +# ``` +# elements = [ +# { 'name': 'kathy', 'transaction_amount': 200, 'device': 'vivo'}, +# { 'name': 'dhaval', 'transaction_amount': 400, 'device': 'google pixel'}, +# { 'name': 'aamir', 'transaction_amount': 800, 'device': 'iphone-8'}, +# { 'name': 'mona', 'transaction_amount': 1000, 'device': 'iphone-10'}, +# ] +# ``` +# But if you call it like this, +# ``` +# bubble_sort(elements, key='name') +# ``` +# output will be, +# ``` +# elements = [ +# { 'name': 'aamir', 'transaction_amount': 800, 'device': 'iphone-8'}, +# { 'name': 'dhaval', 'transaction_amount': 400, 'device': 'google pixel'}, +# { 'name': 'kathy', 'transaction_amount': 200, 'device': 'vivo'}, +# { 'name': 'mona', 'transaction_amount': 1000, 'device': 'iphone-10'}, +# ] +# ``` + +# base bubble_sort. you can use this to sort strings too +def bubble_sort(elements): + size = len(elements) + + for i in range(size-1): + swapped = False + for j in range(size-1-i): + if elements[j] > elements[j+1]: + tmp = elements[j] + elements[j] = elements[j+1] + elements[j+1] = tmp + swapped = True + + if not swapped: + break + +def bubble_sort_by_key(elements, key): + size = len(elements) + + for i in range(size-1): + swapped = False + for j in range(size-1-i): + if elements[j][key] > elements[j+1][key]: + tmp = elements[j] + elements[j] = elements[j+1] + elements[j+1] = tmp + swapped = True + + if not swapped: + break + + +elements = [5,9,2,1,67,34,88,34] +elements = [1,2,3,4,2] +elements = ["mona", "dhaval", "aamir", "tina", "chang"] + +bubble_sort(elements) +print(elements) + +elements2 = [ { 'name': 'kathy', 'transaction_amount': 200, 'device': 'vivo'}, + { 'name': 'dhaval', 'transaction_amount': 400, 'device': 'google pixel'}, + { 'name': 'aamir', 'transaction_amount': 800, 'device': 'iphone-8'}, + { 'name': 'mona', 'transaction_amount': 1000, 'device': 'iphone-10'}, + ] +bubble_sort_by_key(elements2,key='transaction_amount') +print(elements2) diff --git a/2_BubbleSort/bubble_sort.py b/2_BubbleSort/bubble_sort.py new file mode 100644 index 0000000..c39aa87 --- /dev/null +++ b/2_BubbleSort/bubble_sort.py @@ -0,0 +1,25 @@ + +# you can use this to sort strings too +def bubble_sort(elements): + size = len(elements) + + for i in range(size-1): + swapped = False + for j in range(size-1-i): + if elements[j] > elements[j+1]: + tmp = elements[j] + elements[j] = elements[j+1] + elements[j+1] = tmp + swapped = True + + if not swapped: + break + + +if __name__ == '__main__': + elements = [5,9,2,1,67,34,88,34] + elements = [1,2,3,4,2] + elements = ["mona", "dhaval", "aamir", "tina", "chang"] + + bubble_sort(elements) + print(elements) \ No newline at end of file diff --git a/2_BubbleSort/bubble_sort_exercise.md b/2_BubbleSort/bubble_sort_exercise.md new file mode 100644 index 0000000..e930890 --- /dev/null +++ b/2_BubbleSort/bubble_sort_exercise.md @@ -0,0 +1,40 @@ +### Bubble Sort Exercise + +Modify [bubble_sort function](https://github.com/codebasics/data-structures-algorithms-python/blob/master/algorithms/2_BubbleSort/bubble_sort.py) such that it can sort following list of transactions happening in an electronic store, +``` +elements = [ + { 'name': 'mona', 'transaction_amount': 1000, 'device': 'iphone-10'}, + { 'name': 'dhaval', 'transaction_amount': 400, 'device': 'google pixel'}, + { 'name': 'kathy', 'transaction_amount': 200, 'device': 'vivo'}, + { 'name': 'aamir', 'transaction_amount': 800, 'device': 'iphone-8'}, + ] +``` +bubble_sort function should take key from a transaction record and sort the list as per that key. For example, +``` +bubble_sort(elements, key='transaction_amount') +``` +This will sort elements by transaction_amount and your sorted list will look like, +``` +elements = [ + { 'name': 'kathy', 'transaction_amount': 200, 'device': 'vivo'}, + { 'name': 'dhaval', 'transaction_amount': 400, 'device': 'google pixel'}, + { 'name': 'aamir', 'transaction_amount': 800, 'device': 'iphone-8'}, + { 'name': 'mona', 'transaction_amount': 1000, 'device': 'iphone-10'}, + ] +``` +But if you call it like this, +``` +bubble_sort(elements, key='name') +``` +output will be, +``` +elements = [ + { 'name': 'aamir', 'transaction_amount': 800, 'device': 'iphone-8'}, + { 'name': 'dhaval', 'transaction_amount': 400, 'device': 'google pixel'}, + { 'name': 'kathy', 'transaction_amount': 200, 'device': 'vivo'}, + { 'name': 'mona', 'transaction_amount': 1000, 'device': 'iphone-10'}, + ] +``` + +[Solution](https://github.com/codebasics/data-structures-algorithms-python/blob/master/algorithms/2_BubbleSort/bubble_sort_exercise_solution.py) + diff --git a/Algorithms/1_BinarySearch/1.py b/Algorithms/1_BinarySearch/1.py new file mode 100644 index 0000000..860e313 --- /dev/null +++ b/Algorithms/1_BinarySearch/1.py @@ -0,0 +1,105 @@ +# ### Binary Search Exercise +# 1. When I try to find number 5 in below list using binary search, it doesn't work and returns me -1 index. Why is that? + +# ```numbers = [1,4,6,9,10,5,7]``` + +# This is because the array is not sorted in order from lowest to highest. +# Once it splits the first time, it starts looking in the [1,4,6] range and doesn't find 5 + +# 1. Find index of all the occurances of a number from sorted list + +# ``` +# numbers = [1,4,6,9,11,15,15,15,17,21,34,34,56] +# number_to_find = 15 +# ``` +# This should return 5,6,7 as indices containing number 15 in the array + +from util import time_it + +@time_it +def linear_search(numbers_list, number_to_find): + for index, element in enumerate(numbers_list): + if element == number_to_find: + return index + return -1 + +@time_it +def binary_search(numbers_list, number_to_find): + left_index = 0 + right_index = len(numbers_list) - 1 + mid_index = 0 + + while left_index <= right_index: + mid_index = (left_index + right_index) // 2 + mid_number = numbers_list[mid_index] + + if mid_number == number_to_find: + return mid_index + + if mid_number < number_to_find: + left_index = mid_index + 1 + else: + right_index = mid_index - 1 + + return -1 + +def binary_search_recursive(numbers_list, number_to_find, left_index, right_index): + if right_index < left_index: + return -1 + + mid_index = (left_index + right_index) // 2 + if mid_index >= len(numbers_list) or mid_index < 0: + return -1 + + mid_number = numbers_list[mid_index] + + if mid_number == number_to_find: + return mid_index + + if mid_number < number_to_find: + left_index = mid_index + 1 + else: + right_index = mid_index - 1 + + return binary_search_recursive(numbers_list, number_to_find, left_index, right_index) + +#this should run the binary search, find the index, and then recursively run the search on both the right and left side +def binary_search_multiple(numbers_list, number_to_find): + + index = binary_search(numbers_list,number_to_find) + result_indices = [index] + + # find all indices on the left + i = index - 1 + while i>=0: + if numbers_list[i] == numbers_list[index]: + result_indices.append(i) + else: + break + i = i-1 + + # find all indices on the right + i = index + 1 + while i elements[j+1]: + tmp = elements[j] + elements[j] = elements[j+1] + elements[j+1] = tmp + swapped = True + + if not swapped: + break + +def bubble_sort_by_key(elements, key): + size = len(elements) + + for i in range(size-1): + swapped = False + for j in range(size-1-i): + if elements[j][key] > elements[j+1][key]: + tmp = elements[j] + elements[j] = elements[j+1] + elements[j+1] = tmp + swapped = True + + if not swapped: + break + + +elements = [5,9,2,1,67,34,88,34] +elements = [1,2,3,4,2] +elements = ["mona", "dhaval", "aamir", "tina", "chang"] + +bubble_sort(elements) +print(elements) + +elements2 = [ { 'name': 'kathy', 'transaction_amount': 200, 'device': 'vivo'}, + { 'name': 'dhaval', 'transaction_amount': 400, 'device': 'google pixel'}, + { 'name': 'aamir', 'transaction_amount': 800, 'device': 'iphone-8'}, + { 'name': 'mona', 'transaction_amount': 1000, 'device': 'iphone-10'}, + ] +bubble_sort_by_key(elements2,key='transaction_amount') +print(elements2) diff --git a/Algorithms/1_BinarySearch/2_BubbleSort/bubble_sort.py b/Algorithms/1_BinarySearch/2_BubbleSort/bubble_sort.py new file mode 100644 index 0000000..c39aa87 --- /dev/null +++ b/Algorithms/1_BinarySearch/2_BubbleSort/bubble_sort.py @@ -0,0 +1,25 @@ + +# you can use this to sort strings too +def bubble_sort(elements): + size = len(elements) + + for i in range(size-1): + swapped = False + for j in range(size-1-i): + if elements[j] > elements[j+1]: + tmp = elements[j] + elements[j] = elements[j+1] + elements[j+1] = tmp + swapped = True + + if not swapped: + break + + +if __name__ == '__main__': + elements = [5,9,2,1,67,34,88,34] + elements = [1,2,3,4,2] + elements = ["mona", "dhaval", "aamir", "tina", "chang"] + + bubble_sort(elements) + print(elements) \ No newline at end of file diff --git a/Algorithms/1_BinarySearch/2_BubbleSort/bubble_sort_exercise.md b/Algorithms/1_BinarySearch/2_BubbleSort/bubble_sort_exercise.md new file mode 100644 index 0000000..e930890 --- /dev/null +++ b/Algorithms/1_BinarySearch/2_BubbleSort/bubble_sort_exercise.md @@ -0,0 +1,40 @@ +### Bubble Sort Exercise + +Modify [bubble_sort function](https://github.com/codebasics/data-structures-algorithms-python/blob/master/algorithms/2_BubbleSort/bubble_sort.py) such that it can sort following list of transactions happening in an electronic store, +``` +elements = [ + { 'name': 'mona', 'transaction_amount': 1000, 'device': 'iphone-10'}, + { 'name': 'dhaval', 'transaction_amount': 400, 'device': 'google pixel'}, + { 'name': 'kathy', 'transaction_amount': 200, 'device': 'vivo'}, + { 'name': 'aamir', 'transaction_amount': 800, 'device': 'iphone-8'}, + ] +``` +bubble_sort function should take key from a transaction record and sort the list as per that key. For example, +``` +bubble_sort(elements, key='transaction_amount') +``` +This will sort elements by transaction_amount and your sorted list will look like, +``` +elements = [ + { 'name': 'kathy', 'transaction_amount': 200, 'device': 'vivo'}, + { 'name': 'dhaval', 'transaction_amount': 400, 'device': 'google pixel'}, + { 'name': 'aamir', 'transaction_amount': 800, 'device': 'iphone-8'}, + { 'name': 'mona', 'transaction_amount': 1000, 'device': 'iphone-10'}, + ] +``` +But if you call it like this, +``` +bubble_sort(elements, key='name') +``` +output will be, +``` +elements = [ + { 'name': 'aamir', 'transaction_amount': 800, 'device': 'iphone-8'}, + { 'name': 'dhaval', 'transaction_amount': 400, 'device': 'google pixel'}, + { 'name': 'kathy', 'transaction_amount': 200, 'device': 'vivo'}, + { 'name': 'mona', 'transaction_amount': 1000, 'device': 'iphone-10'}, + ] +``` + +[Solution](https://github.com/codebasics/data-structures-algorithms-python/blob/master/algorithms/2_BubbleSort/bubble_sort_exercise_solution.py) + diff --git a/Algorithms/1_BinarySearch/__pycache__/util.cpython-311.pyc b/Algorithms/1_BinarySearch/__pycache__/util.cpython-311.pyc new file mode 100644 index 0000000..b8e29c5 Binary files /dev/null and b/Algorithms/1_BinarySearch/__pycache__/util.cpython-311.pyc differ diff --git a/Algorithms/1_BinarySearch/binary_search_exercise.md b/Algorithms/1_BinarySearch/binary_search_exercise.md new file mode 100644 index 0000000..fea2b2b --- /dev/null +++ b/Algorithms/1_BinarySearch/binary_search_exercise.md @@ -0,0 +1,14 @@ +### Binary Search Exercise +1. When I try to find number 5 in below list using binary search, it doesn't work and returns me -1 index. Why is that? + + ```numbers = [1,4,6,9,10,5,7]``` + +1. Find index of all the occurances of a number from sorted list + + ``` + numbers = [1,4,6,9,11,15,15,15,17,21,34,34,56] + number_to_find = 15 + ``` + This should return 5,6,7 as indices containing number 15 in the array + +[Solution](https://github.com/codebasics/data-structures-algorithms-python/blob/master/algorithms/1_BinarySearch/binary_search_exercise_solution.py) \ No newline at end of file diff --git a/Algorithms/1_BinarySearch/binarysearch.py b/Algorithms/1_BinarySearch/binarysearch.py new file mode 100644 index 0000000..88ffc26 --- /dev/null +++ b/Algorithms/1_BinarySearch/binarysearch.py @@ -0,0 +1,55 @@ +from util import time_it + +@time_it +def linear_search(numbers_list, number_to_find): + for index, element in enumerate(numbers_list): + if element == number_to_find: + return index + return -1 + +@time_it +def binary_search(numbers_list, number_to_find): + left_index = 0 + right_index = len(numbers_list) - 1 + mid_index = 0 + + while left_index <= right_index: + mid_index = (left_index + right_index) // 2 + mid_number = numbers_list[mid_index] + + if mid_number == number_to_find: + return mid_index + + if mid_number < number_to_find: + left_index = mid_index + 1 + else: + right_index = mid_index - 1 + + return -1 + +def binary_search_recursive(numbers_list, number_to_find, left_index, right_index): + if right_index < left_index: + return -1 + + mid_index = (left_index + right_index) // 2 + if mid_index >= len(numbers_list) or mid_index < 0: + return -1 + + mid_number = numbers_list[mid_index] + + if mid_number == number_to_find: + return mid_index + + if mid_number < number_to_find: + left_index = mid_index + 1 + else: + right_index = mid_index - 1 + + return binary_search_recursive(numbers_list, number_to_find, left_index, right_index) + +numbers_list = [12, 15, 17, 19, 21, 24, 45, 67] +number_to_find = 21 + +index = binary_search_recursive(numbers_list, number_to_find, 0, len(numbers_list)) +print(f"Number found at index {index} using binary search") + diff --git a/Algorithms/1_BinarySearch/util.py b/Algorithms/1_BinarySearch/util.py new file mode 100644 index 0000000..2a7d2d5 --- /dev/null +++ b/Algorithms/1_BinarySearch/util.py @@ -0,0 +1,9 @@ +import time +def time_it(func): + def wrapper(*args, **kwargs): + start = time.time() + result = func(*args,**kwargs) + end = time.time() + print(func.__name__ +" took " + str((end-start)*1000) + " mil sec") + return result + return wrapper \ No newline at end of file diff --git a/Data_Structures/10_Graph/graph.py b/Data_Structures/10_Graph/graph.py new file mode 100644 index 0000000..cf97332 --- /dev/null +++ b/Data_Structures/10_Graph/graph.py @@ -0,0 +1,84 @@ +class Graph: + def __init__(self, edges): + self.edges = edges + self.graph_dict = {} + for start, end in edges: + if start in self.graph_dict: + self.graph_dict[start].append(end) + else: + self.graph_dict[start] = [end] + print("Graph Dict:", self.graph_dict) + + def get_paths(self, start, end, path=[]): + path = path + [start] + + if start == end: + return [path] + + if start not in self.graph_dict: + return [] + + paths = [] + for node in self.graph_dict[start]: + if node not in path: + new_paths = self.get_paths(node, end, path) + for p in new_paths: + paths.append(p) + + return paths + + def get_shortest_path(self, start, end, path=[]): + path = path + [start] + + if start == end: + return path + + if start not in self.graph_dict: + return None + + shortest_path = None + for node in self.graph_dict[start]: + if node not in path: + sp = self.get_shortest_path(node, end, path) + if sp: + if shortest_path is None or len(sp) < len(shortest_path): + shortest_path = sp + + return shortest_path + +if __name__ == '__main__': + + routes = [ + ("Mumbai","Pune"), + ("Mumbai", "Surat"), + ("Surat", "Bangaluru"), + ("Pune","Hyderabad"), + ("Pune","Mysuru"), + ("Hyderabad","Bangaluru"), + ("Hyderabad", "Chennai"), + ("Mysuru", "Bangaluru"), + ("Chennai", "Bangaluru") + ] + + routes = [ + ("Mumbai", "Paris"), + ("Mumbai", "Dubai"), + ("Paris", "Dubai"), + ("Paris", "New York"), + ("Dubai", "New York"), + ("New York", "Toronto"), + ] + + route_graph = Graph(routes) + + start = "Mumbai" + end = "New York" + + print(f"All paths between: {start} and {end}: ",route_graph.get_paths(start,end)) + print(f"Shortest path between {start} and {end}: ", route_graph.get_shortest_path(start,end)) + + start = "Dubai" + end = "New York" + + print(f"All paths between: {start} and {end}: ",route_graph.get_paths(start,end)) + print(f"Shortest path between {start} and {end}: ", route_graph.get_shortest_path(start,end)) diff --git a/Data_Structures/2_Arrays/2-1.py b/Data_Structures/2_Arrays/2-1.py new file mode 100644 index 0000000..0a28cfd --- /dev/null +++ b/Data_Structures/2_Arrays/2-1.py @@ -0,0 +1,60 @@ +# # Exercise: Array DataStructure + +# 1. Let us say your expense for every month are listed below, +# 1. January - 2200 +# 2. February - 2350 +# 3. March - 2600 +# 4. April - 2130 +# 5. May - 2190 + +# Create a list to store these monthly expenses and using that find out, + +# 1. In Feb, how many dollars you spent extra compare to January? +# 2. Find out your total expense in first quarter (first three months) of the year. +# 3. Find out if you spent exactly 2000 dollars in any month +# 4. June month just finished and your expense is 1980 dollar. Add this item to our monthly expense list +# 5. You returned an item that you bought in a month of April and +# got a refund of 200$. Make a correction to your monthly expense list +# based on this + +expenses = [2200,2350,2600,2130,2190] + +# 1. In Feb, how many dollars you spent extra compare to January? + +extraSpend = expenses[1] - expenses[0] + +print(f"In February, you spent ${extraSpend} more than in January") + +# 2. Find out your total expense in first quarter (first three months) of the year. + +q1_expenses = sum(expenses[0:3]) + +print(f"In Q1, you spent ${q1_expenses}") + +# 3. Find out if you spent exactly 2000 dollars in any month + +print("Did I spent 2000$ in any month? ", 2000 in expenses) # False + +did_i_spend = False + +for e in expenses: + if e == 2000: + did_i_spend = True + +if did_i_spend == True: + print('You did spend exactly 2000 in a month') +else: + print('You did not spend exactly 2000 in a month') + +#4. June month just finished and your expense is 1980 dollar. Add this item to our monthly expense list + +expenses.append(1980) + +print(expenses) + +# 5. You returned an item that you bought in a month of April and +# # got a refund of 200$. Make a correction to your monthly expense list +# # based on this + +expenses[3] = expenses[3] - 200 +print(expenses) diff --git a/Data_Structures/2_Arrays/2-2.py b/Data_Structures/2_Arrays/2-2.py new file mode 100644 index 0000000..b7777d0 --- /dev/null +++ b/Data_Structures/2_Arrays/2-2.py @@ -0,0 +1,47 @@ +# 2. You have a list of your favourite marvel super heros. +# ``` +# heros=['spider man','thor','hulk','iron man','captain america'] +# ``` + +# Using this find out, + +# 1. Length of the list +# 2. Add 'black panther' at the end of this list +# 3. You realize that you need to add 'black panther' after 'hulk', +# so remove it from the list first and then add it after 'hulk' +# 4. Now you don't like thor and hulk because they get angry easily :) +# So you want to remove thor and hulk from list and replace them with doctor strange (because he is cool). +# Do that with one line of code. +# 5. Sort the heros list in alphabetical order (Hint. Use dir() functions to list down all functions available in list) + + +heros=['spider man','thor','hulk','iron man','captain america'] + +# 1. Length of the list +print("length of heros list:",len(heros)) + +# 2. Add 'black panther' at the end of this list + +heros.append('black panther') +print(heros) + +# 3. You realize that you need to add 'black panther' after 'hulk', +# so remove it from the list first and then add it after 'hulk' + +heros.remove('black panther') +heros.insert(3,'black panther') +print(heros) + +# 4. Now you don't like thor and hulk because they get angry easily :) +# So you want to remove thor and hulk from list and replace them with doctor strange (because he is cool). +# Do that with one line of code. + +heros[1:3] = ['doctor stranger'] +print(heros) + +# 5. Sort the heros list in alphabetical order (Hint. Use dir() functions to list down all functions available in list) + +heros.sort() +print(heros) + + diff --git a/Data_Structures/2_Arrays/2-3.py b/Data_Structures/2_Arrays/2-3.py new file mode 100644 index 0000000..b9d4f8c --- /dev/null +++ b/Data_Structures/2_Arrays/2-3.py @@ -0,0 +1,13 @@ +# 3. Create a list of all odd numbers between 1 and a max number. +# Max number is something you need to take from a user using input() function + +odd_numbers_list = [] + +max_number = int(input('What is the max number? ')) + +for i in range(0,max_number+1): + if i%2 != 0: + odd_numbers_list.append(i) + +print(odd_numbers_list) + diff --git a/Data_Structures/2_Arrays/2_arrays_exercise.md b/Data_Structures/2_Arrays/2_arrays_exercise.md new file mode 100644 index 0000000..81d65f4 --- /dev/null +++ b/Data_Structures/2_Arrays/2_arrays_exercise.md @@ -0,0 +1,45 @@ +# Exercise: Array DataStructure + +1. Let us say your expense for every month are listed below, + 1. January - 2200 + 2. February - 2350 + 3. March - 2600 + 4. April - 2130 + 5. May - 2190 + +Create a list to store these monthly expenses and using that find out, + + 1. In Feb, how many dollars you spent extra compare to January? + 2. Find out your total expense in first quarter (first three months) of the year. + 3. Find out if you spent exactly 2000 dollars in any month + 4. June month just finished and your expense is 1980 dollar. Add this item to our monthly expense list + 5. You returned an item that you bought in a month of April and + got a refund of 200$. Make a correction to your monthly expense list + based on this + +[Solution](https://github.com/codebasics/data-structures-algorithms-python/blob/master/data_structures/2_Arrays/Solution/1_expenses.py) + +2. You have a list of your favourite marvel super heros. +``` +heros=['spider man','thor','hulk','iron man','captain america'] +``` + +Using this find out, + + 1. Length of the list + 2. Add 'black panther' at the end of this list + 3. You realize that you need to add 'black panther' after 'hulk', + so remove it from the list first and then add it after 'hulk' + 4. Now you don't like thor and hulk because they get angry easily :) + So you want to remove thor and hulk from list and replace them with doctor strange (because he is cool). + Do that with one line of code. + 5. Sort the heros list in alphabetical order (Hint. Use dir() functions to list down all functions available in list) + +[Solution](https://github.com/codebasics/data-structures-algorithms-python/blob/master/data_structures/2_Arrays/Solution/2_marvel.py) + + +3. Create a list of all odd numbers between 1 and a max number. +Max number is something you need to take from a user using input() function + +[Solution](https://github.com/codebasics/data-structures-algorithms-python/blob/master/data_structures/2_Arrays/Solution/3_odd_even_numbers.py) + diff --git a/Data_Structures/3_LinkedList/3-1.py b/Data_Structures/3_LinkedList/3-1.py new file mode 100644 index 0000000..a175c6e --- /dev/null +++ b/Data_Structures/3_LinkedList/3-1.py @@ -0,0 +1,183 @@ +# 1. In [LinkedList class](https://github.com/codebasics/data-structures-algorithms-python/blob/master/data_structures/3_LinkedList/3_linked_list.py) that we implemented in our tutorial add following two methods, +# ``` +# def insert_after_value(self, data_after, data_to_insert): +# # Search for first occurance of data_after value in linked list +# # Now insert data_to_insert after data_after node + +# def remove_by_value(self, data): +# # Remove first node that contains data +# ``` +# Now make following calls, +# ``` +# ll = LinkedList() +# ll.insert_values(["banana","mango","grapes","orange"]) +# ll.print() +# ll.insert_after_value("mango","apple") # insert apple after mango +# ll.print() +# ll.remove_by_value("orange") # remove orange from linked list +# ll.print() +# ll.remove_by_value("figs") +# ll.print() +# ll.remove_by_value("banana") +# ll.remove_by_value("mango") +# ll.remove_by_value("apple") +# ll.remove_by_value("grapes") +# ll.print() +# ``` + +class Node: + def __init__(self, data=None, next=None): + self.data = data + self.next = next + +class LinkedList: + def __init__(self): + self.head = None + + def print(self): + if self.head is None: + print("Linked list is empty") + return + itr = self.head + llstr = '' + while itr: + llstr += str(itr.data)+' --> ' if itr.next else str(itr.data) + itr = itr.next + print(llstr) + + def get_length(self): + count = 0 + itr = self.head + while itr: + count+=1 + itr = itr.next + + return count + + def insert_at_begining(self, data): + node = Node(data, self.head) + self.head = node + + def insert_at_end(self, data): + if self.head is None: + self.head = Node(data, None) + return + + itr = self.head + + while itr.next: + itr = itr.next + + itr.next = Node(data, None) + + def insert_at(self, index, data): + if index<0 or index>self.get_length(): + raise Exception("Invalid Index") + + if index==0: + self.insert_at_begining(data) + return + + count = 0 + itr = self.head + while itr: + if count == index - 1: + node = Node(data, itr.next) + itr.next = node + break + + itr = itr.next + count += 1 + + def remove_at(self, index): + if index<0 or index>=self.get_length(): + raise Exception("Invalid Index") + + if index==0: + self.head = self.head.next + return + + count = 0 + itr = self.head + while itr: + if count == index - 1: + itr.next = itr.next.next + break + + itr = itr.next + count+=1 + + def insert_values(self, data_list): + self.head = None + for data in data_list: + self.insert_at_end(data) + + def insert_after_value(self, data_after, data_to_insert): + + if self.head is None: + return + + if self.head.data==data_after: + self.head.next = Node(data_to_insert,self.head.next) + return + + itr = self.head #the itr is the first value in the Linked List + + while itr.next: + if itr.data == data_after: # Search for first occurance of data_after value in linked list + # Now insert data_to_insert after data_after node + node2 = Node(data_to_insert,itr.next) + itr.next = node2 + return + itr = itr.next + + raise Exception("the data you're searching for doesn't exist") + ## if it doesn't find the value after going through the whole list, raise Exception + + def remove_by_value(self, data): + # Handle the case where the list is empty + if self.head is None: + print("The list is empty.") + return + + # Handle the case where the node to be removed is the head + if self.head.data == data: + self.head = self.head.next + return + + itr = self.head #the itr is the first value in the Linked List + prev = None + + while itr: + if itr.data == data: #if we find the data + prev.next = itr.next # Remove first node that contains data + prev = itr + itr = itr.next + + + + +# ll = LinkedList() +# ll.insert_values(["banana","mango","grapes","orange"]) +# ll.insert_at(1,"blueberry") +# ll.remove_at(2) +# ll.print() +# ll.insert_values([45,7,12,567,99]) +# ll.insert_at_end(67) +# ll.print() + +ll = LinkedList() +ll.insert_values(["banana","mango","grapes","orange"]) +ll.print() +ll.insert_after_value("mango","apple") # insert apple after mango +ll.print() +ll.remove_by_value("orange") # remove orange from linked list +ll.print() +ll.remove_by_value("figs") +ll.print() +ll.remove_by_value("banana") +ll.remove_by_value("mango") +ll.print() +ll.remove_by_value("apple") +ll.remove_by_value("grapes") +ll.print() \ No newline at end of file diff --git a/Data_Structures/3_LinkedList/3-2.py b/Data_Structures/3_LinkedList/3-2.py new file mode 100644 index 0000000..54745f7 --- /dev/null +++ b/Data_Structures/3_LinkedList/3-2.py @@ -0,0 +1,194 @@ +# 2. Implement doubly linked list. The only difference with regular linked list is that double linked has prev node reference as well. That way you can iterate in forward and backward direction. +# Your node class will look this this, +# ``` +# class Node: +# def __init__(self, data=None, next=None, prev=None): +# self.data = data +# self.next = next +# self.prev = prev +# ``` +# Add following new methods, +# ``` +# def print_forward(self): +# # This method prints list in forward direction. Use node.next + +# def print_backward(self): +# # Print linked list in reverse direction. Use node.prev for this. +# ``` +# Implement all other methods in [regular linked list class] +#(https://github.com/codebasics/data-structures-algorithms-python/blob/master/data_structures/3_LinkedList/3_linked_list.py) +# and make necessary changes for doubly linked list (you need to populate node.prev in all those methods) + +class Node: + def __init__(self, data=None, next=None, prev=None): + self.data = data + self.next = next + self.prev = prev + +class DoublyLinkedList: + def __init__(self): + self.head = None + + def insert_at_end(self, data): + if self.head is None: + self.head = Node(data) + return + + itr = self.head + + while itr.next: + itr = itr.next + + # When you find the end of the list, create a new node with data. + # Set the new node's 'next' to None (it's the end of the list) and 'prev' to itr (the current last node). + new_node = Node(data, None, itr) + itr.next = new_node + + def insert_values(self, data_list): + self.head = None + for data in data_list: + self.insert_at_end(data) + + def print_forward(self): # This method prints list in forward direction. Use node.next + if self.head is None: + print("Linked list is empty") + return + itr = self.head + llstr = '' + while itr: + llstr += str(itr.data)+' --> ' if itr.next else str(itr.data) + itr = itr.next + print(llstr) + + + def print_backward(self): # Print linked list in reverse direction. Use node.prev for this. + if self.head is None: + print("Linked list is empty") + return + + itr = self.head + while itr.next: + itr = itr.next + ## after this runs, we are at the end of the linked list + + llstr = '' + while itr: + llstr += str(itr.data)+' --> ' if itr.prev else str(itr.data) + itr = itr.prev + print(llstr) + + def get_length(self): + count = 0 + itr = self.head + while itr: + count+=1 + itr = itr.next + + return count + + def insert_at_begining(self, data): + if self.head == None: + node = Node(data, self.head,None) + self.head = node + else: + node = Node(data, self.head, None) + self.head.prev = node + self.head = node + + def insert_at(self, index, data): + if index<0 or index>self.get_length(): + raise Exception("Invalid Index") + + if index==0: + self.insert_at_begining(data) + return + + count = 0 + itr = self.head + while itr: + if count == index - 1: + node = Node(data, itr.next,itr.prev) + if node.next: + node.next.prev = node + itr.next = node + break + + itr = itr.next + count += 1 + + def remove_at(self, index): + if index<0 or index>=self.get_length(): + raise Exception("Invalid Index") + + if index==0: + self.head = self.head.next + self.head.prev - None + return + + count = 0 + itr = self.head + while itr: + if count == index: + itr.prev.next = itr.next + if itr.next: + itr.next.prev = itr.prev + break + + itr = itr.next + count+=1 + + def insert_values(self, data_list): + self.head = None + for data in data_list: + self.insert_at_end(data) + + def insert_after_value(self, data_after, data_to_insert): + + if self.head is None: + return + + if self.head.data==data_after: + self.head.next = Node(data_to_insert,self.head.next) + return + + itr = self.head #the itr is the first value in the Linked List + + while itr.next: + if itr.data == data_after: # Search for first occurance of data_after value in linked list + # Now insert data_to_insert after data_after node + node2 = Node(data_to_insert,itr.next) + itr.next = node2 + return + itr = itr.next + + raise Exception("the data you're searching for doesn't exist") + ## if it doesn't find the value after going through the whole list, raise Exception + + def remove_by_value(self, data): + # Handle the case where the list is empty + if self.head is None: + print("The list is empty.") + return + + # Handle the case where the node to be removed is the head + if self.head.data == data: + self.head = self.head.next + return + + itr = self.head #the itr is the first value in the Linked List + prev = None + + while itr: + if itr.data == data: #if we find the data + prev.next = itr.next # Remove first node that contains data + prev = itr + itr = itr.next + +dll = DoublyLinkedList() +dll.insert_values(["banana","mango","grapes","orange"]) +dll.print_forward() +dll.print_backward() +dll.insert_after_value("mango","apple") # insert apple after mango +dll.print_forward() +dll.remove_by_value("orange") # remove orange from linked list +dll.print_forward() \ No newline at end of file diff --git a/Data_Structures/3_LinkedList/3_linked_list_exercise.md b/Data_Structures/3_LinkedList/3_linked_list_exercise.md new file mode 100644 index 0000000..b2cea35 --- /dev/null +++ b/Data_Structures/3_LinkedList/3_linked_list_exercise.md @@ -0,0 +1,50 @@ +# Exercise: Linked List + +1. In [LinkedList class](https://github.com/codebasics/data-structures-algorithms-python/blob/master/data_structures/3_LinkedList/3_linked_list.py) that we implemented in our tutorial add following two methods, +``` +def insert_after_value(self, data_after, data_to_insert): + # Search for first occurance of data_after value in linked list + # Now insert data_to_insert after data_after node + +def remove_by_value(self, data): + # Remove first node that contains data +``` +Now make following calls, +``` + ll = LinkedList() + ll.insert_values(["banana","mango","grapes","orange"]) + ll.print() + ll.insert_after_value("mango","apple") # insert apple after mango + ll.print() + ll.remove_by_value("orange") # remove orange from linked list + ll.print() + ll.remove_by_value("figs") + ll.print() + ll.remove_by_value("banana") + ll.remove_by_value("mango") + ll.remove_by_value("apple") + ll.remove_by_value("grapes") + ll.print() +``` +[Solution](https://github.com/codebasics/data-structures-algorithms-python/blob/master/data_structures/3_LinkedList/Solution/singly_linked_list_exercise.py) + +2. Implement doubly linked list. The only difference with regular linked list is that double linked has prev node reference as well. That way you can iterate in forward and backward direction. +Your node class will look this this, +``` +class Node: + def __init__(self, data=None, next=None, prev=None): + self.data = data + self.next = next + self.prev = prev +``` +Add following new methods, +``` +def print_forward(self): + # This method prints list in forward direction. Use node.next + +def print_backward(self): + # Print linked list in reverse direction. Use node.prev for this. +``` +Implement all other methods in [regular linked list class](https://github.com/codebasics/data-structures-algorithms-python/blob/master/data_structures/3_LinkedList/3_linked_list.py) and make necessary changes for doubly linked list (you need to populate node.prev in all those methods) + +[Solution](https://github.com/codebasics/data-structures-algorithms-python/blob/master/data_structures/3_LinkedList/Solution/doubly_linked_list_exercise.py) \ No newline at end of file diff --git a/Data_Structures/4_HashTable/4-1.py b/Data_Structures/4_HashTable/4-1.py new file mode 100644 index 0000000..5910af4 --- /dev/null +++ b/Data_Structures/4_HashTable/4-1.py @@ -0,0 +1,52 @@ +# 1. [nyc_weather.csv](https://github.com/codebasics/data-structures-algorithms-python/blob/master/data_structures/4_HashTable_2_Collisions/Solution/nyc_weather.csv) +# contains new york city weather for first few days in the month of January. Write a program that can answer following, +# 1. What was the average temperature in first week of Jan +# 1. What was the maximum temperature in first 10 days of Jan + +# Figure out data structure that is best for this problem + +#for this problem, I will use an list since I just want the values + +with open("/Users/rohansaxena/Desktop/AI Engineer/Week 5&6 - Data Structures and Algorithms in Python/4_HashTable/nyc_weather.csv","r+") as f: + # create an array for temperatures + temp_array = [] + + #create an array + for line in f: # for each line in the csv + # Strip newline characters and then split the line by comma + tokens = line.strip('\n').split(",") + #Append the data from the second column wit the values + temp_array.append(tokens[1]) + + #I should have done a try, except loop here to skip the header instead of the process I did + + temp_array.remove('temperature(F)') #remove the header so we now just have the values + + #convert each value from a string into an int + for val in range(0,len(temp_array)): + temp_array[val] = int(temp_array[val]) + + # 1. What was the average temperature in first week of Jan + avg_temp = round(sum(temp_array[0:7]) / 7,2) + print(f"The Average Temp in first week of Jan was {avg_temp} F") + + #1. What was the maximum temperature in first 10 days of Jan + + max_temp = max(temp_array) + print(f"The Max Temp in first 10 days of Jan was {max_temp} F") + +#v2 + +# arr = [] + +# with open("/Users/rohansaxena/Desktop/AI Engineer/Week 5&6 - Data Structures and Algorithms in Python/4_HashTable/nyc_weather.csv","r") as f: +# for line in f: +# tokens = line.split(',') +# try: +# temperature = int(tokens[1]) +# arr.append(temperature) +# except: +# print("Invalid temperature.Ignore the row") +# print(arr) +# print(sum(arr[0:7])/len(arr[0:7])) +# print(max(arr[0:10])) diff --git a/Data_Structures/4_HashTable/4-2.py b/Data_Structures/4_HashTable/4-2.py new file mode 100644 index 0000000..99a98f3 --- /dev/null +++ b/Data_Structures/4_HashTable/4-2.py @@ -0,0 +1,31 @@ +# 2. [nyc_weather.csv](https://github.com/codebasics/data-structures-algorithms-python/blob/master/data_structures/4_HashTable_2_Collisions/Solution/nyc_weather.csv) +# contains new york city weather for first few days in the month of January. W +# rite a program that can answer following, +# 1. What was the temperature on Jan 9? +# 1. What was the temperature on Jan 4? + +# Figure out data structure that is best for this problem + +# for this problem, I will use a dictionary (hash table) because I want to store the key and the value + +with open("/Users/rohansaxena/Desktop/AI Engineer/Week 5&6 - Data Structures and Algorithms in Python/4_HashTable/nyc_weather.csv","r+") as f: + + #create a dictionary + dict = {} + + for line in f: # for each line in the csv + # Strip newline characters and then split the line by comma + tokens = line.strip('\n').split(",") + try: + dict[tokens[0]] = int(tokens[1]) + except: + print("Invalid temperature.Ignore the row") + + # 1. What was the temperature on Jan 9? + + print(dict['Jan 9']) + # 1. What was the temperature on Jan 4? + print(dict['Jan 4']) + + + diff --git a/Data_Structures/4_HashTable/4-3.py b/Data_Structures/4_HashTable/4-3.py new file mode 100644 index 0000000..74cd030 --- /dev/null +++ b/Data_Structures/4_HashTable/4-3.py @@ -0,0 +1,27 @@ +# 3. [poem.txt](https://github.com/codebasics/data-structures-algorithms-python/blob/master/data_structures/4_HashTable_2_Collisions/Solution/poem.txt) +# Contains famous poem "Road not taken" by poet Robert Frost. +# You have to read this file in python and print every word and its count as show below. +#Think about the best data structure that you can use to solve this problem and figure out why you selected that specific data structure. +# ``` +# 'diverged': 2, +# 'in': 3, +# 'I': 8 + +# I am selecting a dictionary (hash table) because I want to store key,value pairs (key being the word, value being the amount of instances) + +with open("/Users/rohansaxena/Desktop/AI Engineer/Week 5&6 - Data Structures and Algorithms in Python/4_HashTable/poem.txt","r+") as f: + #create a dictionary to store each word occurence + words_dict = {} + for line in f: # for each line in the file + tokens = line.split(' ') # split the line into an array each words + for token in tokens: # for each word in the array of works + token=token.replace('\n','') # replace \n with nothing + if token in words_dict: # if the token exists in the dictionary + words_dict[token]+=1 # increment it's value + else: #if not + words_dict[token]=1 #set it's value to 1 + print (words_dict) #print the completed words dict + + + + diff --git a/Data_Structures/4_HashTable/4-4.py b/Data_Structures/4_HashTable/4-4.py new file mode 100644 index 0000000..aa80ceb --- /dev/null +++ b/Data_Structures/4_HashTable/4-4.py @@ -0,0 +1,183 @@ +# 4. Implement hash table where collisions are handled using linear probing. +# We learnt about linear probing in the video tutorial. +# Take the hash table implementation that uses chaining and modify methods to use **linear probing**. +# Keep MAX size of arr in hashtable as 10. + +# default HashTable Class + +class HashTable: + def __init__(self): + self.MAX = 10 + self.arr = [None for i in range(self.MAX)] + + def get_hash(self, key): + hash = 0 + for char in key: + hash += ord(char) + return hash % self.MAX + + def __getitem__(self, index): + h = self.get_hash(index) + return self.arr[h] + + def __setitem__(self, key, val): + h = self.get_hash(key) + self.arr[h] = val + + +# HashTable Class using Chaining + +class HashTable2: + def __init__(self): + self.MAX = 10 + self.arr = [[] for i in range(self.MAX)] + + def get_hash(self, key): + hash = 0 + for char in key: + hash += ord(char) + return hash % self.MAX + + def __getitem__(self, key): + arr_index = self.get_hash(key) + for kv in self.arr[arr_index]: + if kv[0] == key: + return kv[1] + + def __setitem__(self, key, val): + h = self.get_hash(key) + found = False + for idx, element in enumerate(self.arr[h]): + if len(element)==2 and element[0] == key: + self.arr[h][idx] = (key,val) + found = True + if not found: + self.arr[h].append((key,val)) + + def __delitem__(self, key): + arr_index = self.get_hash(key) + for index, kv in enumerate(self.arr[arr_index]): + if kv[0] == key: + print("del",index) + del self.arr[arr_index][index] + +# Hash Table Class using probing (keep Max Size at 10) - Rohan's attempt + +# class HashTable3: +# def __init__(self): +# self.MAX = 10 +# self.arr = [None for i in range(self.MAX)] # you do NOT need each location to be an array of arrays since there is only 1 value per location + +# def get_hash(self, key): +# hash = 0 +# for char in key: +# hash += ord(char) +# return hash % self.MAX + +# #if the location is empyt, place the value in there +# #if the location isn't empty, place the value in the next location +# #if the location is the last value, go to the beginning of the list + +# #go to the beginning of the list, repeat the above logic + +# def __getitem__(self, index): #original method +# h = self.get_hash(index) +# return self.arr[h] + +# def __setitem__(self, key, val): +# h = self.get_hash(key) ##this gets you the hash value of your given key +# found = False +# if h not in self.arr: #if the hash value does not exist / does not have a value +# self.arr[h] = val #then place the value in there +# else: #this means that there is something at that given value +# if (h+1)Find stock price on March 9" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "302.0\n" + ] + } + ], + "source": [ + "for element in stock_prices:\n", + " if element[0] == 'march 9':\n", + " print(element[1])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "

Complexity of search using a list is O(n)

" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "

Process using python dictionary

" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "stock_prices = {}\n", + "with open(\"stock_prices.csv\",\"r\") as f:\n", + " for line in f:\n", + " tokens = line.split(',')\n", + " day = tokens[0]\n", + " price = float(tokens[1])\n", + " stock_prices[day] = price" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'march 6': 310.0,\n", + " 'march 7': 340.0,\n", + " 'march 8': 380.0,\n", + " 'march 9': 302.0,\n", + " 'march 10': 297.0,\n", + " 'march 11': 323.0}" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "stock_prices" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "

Find stock price on March 9

" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "302.0" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "stock_prices['march 9']" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "

Complexity of search using dictionary is O(1)

" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "

Implement Hash Table

" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [], + "source": [ + "def get_hash(key): ##key is a string that the user inputs\n", + " hash = 0\n", + " for char in key: ##for each charcter in the string\n", + " hash += ord(char) ## ord() converts each charcter in to Ascii, then adds that value to the total (hash)\n", + " return hash % 100 ## assuming a table with size 100, divides the total by 100, assigns the remainder as the place to store" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "9" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "get_hash('march 6')" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "class HashTable: \n", + " def __init__(self):\n", + " self.MAX = 100 ##this many elements in the array\n", + " self.arr = [None for i in range(self.MAX)] ##initializes the array with MAX elements using list comprehension\n", + " #the value in each element of the array is None\n", + " \n", + " def get_hash(self, key): ## this is the same function as above\n", + " hash = 0\n", + " for char in key:\n", + " hash += ord(char)\n", + " return hash % self.MAX\n", + " \n", + " def __getitem__(self, index):\n", + " h = self.get_hash(index) ##get the hash for the key we want\n", + " return self.arr[h] ##return the value located at the has we just pulled\n", + " \n", + " def __setitem__(self, key, val):\n", + " h = self.get_hash(key) #step 1, get the hash (key) of the inputted key\n", + " self.arr[h] = val ##in the hash table's array, set the value of the key we definited above to the value we inputted \n", + " \n", + " def __delitem__(self, key):\n", + " h = self.get_hash(key) ##get the hash for the key we want\n", + " self.arr[h] = None ##set the value located at the has we just pulled to None (deletes it) " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "t = HashTable()\n", + "t[\"march 6\"] = 310\n", + "t[\"march 7\"] = 420" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " 310,\n", + " 420,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None]" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "t.arr" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "t[\"dec 30\"] = 88" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "88" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "t[\"dec 30\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "del t[\"march 6\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " 420,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " 88,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None,\n", + " None]" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "t.arr" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.4" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Data_Structures/4_HashTable/4_hash_table_collision_handling.ipynb b/Data_Structures/4_HashTable/4_hash_table_collision_handling.ipynb new file mode 100644 index 0000000..a040b11 --- /dev/null +++ b/Data_Structures/4_HashTable/4_hash_table_collision_handling.ipynb @@ -0,0 +1,341 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 56, + "metadata": {}, + "outputs": [], + "source": [ + "class HashTable: \n", + " def __init__(self):\n", + " self.MAX = 10\n", + " self.arr = [None for i in range(self.MAX)]\n", + " \n", + " def get_hash(self, key):\n", + " hash = 0\n", + " for char in key:\n", + " hash += ord(char)\n", + " return hash % self.MAX\n", + " \n", + " def __getitem__(self, index):\n", + " h = self.get_hash(index)\n", + " return self.arr[h]\n", + " \n", + " def __setitem__(self, key, val):\n", + " h = self.get_hash(key)\n", + " self.arr[h] = val " + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "9" + ] + }, + "execution_count": 51, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "t = HashTable()\n", + "t.get_hash(\"march 6\")" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "9" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "t.get_hash(\"march 17\")" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": {}, + "outputs": [], + "source": [ + "t[\"march 6\"] = 120\n", + "t[\"march 8\"] = 67\n", + "t[\"march 9\"] = 4\n", + "t[\"march 17\"] = 459" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "459" + ] + }, + "execution_count": 55, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "t[\"march 6\"]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "

Hash Table Collision Handling Using Chaining

" + ] + }, + { + "cell_type": "code", + "execution_count": 86, + "metadata": {}, + "outputs": [], + "source": [ + "class HashTable: \n", + " def __init__(self):\n", + " self.MAX = 10\n", + " self.arr = [[] for i in range(self.MAX)]\n", + " \n", + " def get_hash(self, key):\n", + " hash = 0\n", + " for char in key:\n", + " hash += ord(char)\n", + " return hash % self.MAX\n", + " \n", + " def __getitem__(self, key):\n", + " arr_index = self.get_hash(key) ##this finds the array at the index we specify (it is an array of key,value pairs)\n", + " for kv in self.arr[arr_index]: ##iterate through each element of the array\n", + " if kv[0] == key: ##if the key matches what we are looking for\n", + " return kv[1] ##return the value at that key\n", + " \n", + " def __setitem__(self, key, val):\n", + " h = self.get_hash(key)\n", + " found = False\n", + " for idx, element in enumerate(self.arr[h]): \n", + " ##enumerate is used to iterate through the elements in your array ()\n", + " #self.arr[h] is the array stored at index h of the hash table\n", + " #idx is the index in the array, element is the key,value pair at that index\n", + " if len(element)==2 and element[0] == key: ##if this key,value pair exists (len 2) and the key is equal to ours\n", + " self.arr[h][idx] = (key,val) #then overwrite that key value pair\n", + " found = True #set this vairable found to True\n", + " if not found: ##if we dont find our key value pair\n", + " self.arr[h].append((key,val)) ##append the key value pair\n", + " \n", + " def __delitem__(self, key):\n", + " arr_index = self.get_hash(key)\n", + " for index, kv in enumerate(self.arr[arr_index]):\n", + " if kv[0] == key:\n", + " print(\"del\",index)\n", + " del self.arr[arr_index][index]\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 87, + "metadata": {}, + "outputs": [], + "source": [ + "t = HashTable()\n", + "t[\"march 6\"] = 310\n", + "t[\"march 7\"] = 420\n", + "t[\"march 8\"] = 67\n", + "t[\"march 17\"] = 63457" + ] + }, + { + "cell_type": "code", + "execution_count": 88, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "310" + ] + }, + "execution_count": 88, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "t[\"march 6\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 89, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "63457" + ] + }, + "execution_count": 89, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "t[\"march 17\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 90, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[[('march 7', 420)],\n", + " [('march 8', 67)],\n", + " [],\n", + " [],\n", + " [],\n", + " [],\n", + " [],\n", + " [],\n", + " [],\n", + " [('march 6', 310), ('march 17', 63457)]]" + ] + }, + "execution_count": 90, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "t.arr" + ] + }, + { + "cell_type": "code", + "execution_count": 91, + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "t[\"march 6\"] = 11" + ] + }, + { + "cell_type": "code", + "execution_count": 92, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[[('march 7', 420)],\n", + " [('march 8', 67)],\n", + " [],\n", + " [],\n", + " [],\n", + " [],\n", + " [],\n", + " [],\n", + " [],\n", + " [('march 6', 11), ('march 17', 63457)]]" + ] + }, + "execution_count": 92, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "t.arr" + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "310" + ] + }, + "execution_count": 68, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "t[\"march 6\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "del 0\n" + ] + } + ], + "source": [ + "del t[\"march 6\"]" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Data_Structures/4_HashTable/4_hash_table_exercise.md b/Data_Structures/4_HashTable/4_hash_table_exercise.md new file mode 100644 index 0000000..84849b4 --- /dev/null +++ b/Data_Structures/4_HashTable/4_hash_table_exercise.md @@ -0,0 +1,31 @@ +# Exercise: Hash Table + +1. [nyc_weather.csv](https://github.com/codebasics/data-structures-algorithms-python/blob/master/data_structures/4_HashTable_2_Collisions/Solution/nyc_weather.csv) contains new york city weather for first few days in the month of January. Write a program that can answer following, + 1. What was the average temperature in first week of Jan + 1. What was the maximum temperature in first 10 days of Jan + +Figure out data structure that is best for this problem + +[Solution](https://github.com/codebasics/data-structures-algorithms-python/blob/master/data_structures/4_HashTable_2_Collisions/Solution/weather_analysis.ipynb) + +2. [nyc_weather.csv](https://github.com/codebasics/data-structures-algorithms-python/blob/master/data_structures/4_HashTable_2_Collisions/Solution/nyc_weather.csv) contains new york city weather for first few days in the month of January. Write a program that can answer following, + 1. What was the temperature on Jan 9? + 1. What was the temperature on Jan 4? + +Figure out data structure that is best for this problem + +[Solution](https://github.com/codebasics/data-structures-algorithms-python/blob/master/data_structures/4_HashTable_2_Collisions/Solution/weather_analysis.ipynb) + +3. [poem.txt](https://github.com/codebasics/data-structures-algorithms-python/blob/master/data_structures/4_HashTable_2_Collisions/Solution/poem.txt) Contains famous poem "Road not taken" by poet Robert Frost. You have to read this file in python and print every word and its count as show below. Think about the best data structure that you can use to solve this problem and figure out why you selected that specific data structure. +``` + 'diverged': 2, + 'in': 3, + 'I': 8 +``` + +[Solution](https://github.com/codebasics/data-structures-algorithms-python/blob/master/data_structures/4_HashTable_2_Collisions/Solution/exercise_poem_find_word_occurances.ipynb) + +4. Implement hash table where collisions are handled using linear probing. We learnt about linear probing in the video tutorial. Take the hash table implementation that uses chaining and modify methods to use **linear probing**. Keep MAX size of arr in hashtable as 10. + +[Solution](https://github.com/codebasics/data-structures-algorithms-python/blob/master/data_structures/4_HashTable_2_Collisions/Solution/exercise_hash_table_linear_probing.ipynb) + diff --git a/Data_Structures/4_HashTable/exercise_hash_table_linear_probing.ipynb b/Data_Structures/4_HashTable/exercise_hash_table_linear_probing.ipynb new file mode 100644 index 0000000..3450b65 --- /dev/null +++ b/Data_Structures/4_HashTable/exercise_hash_table_linear_probing.ipynb @@ -0,0 +1,428 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "

Implement hash table collision handling using linear probing

" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "class HashTable: \n", + " def __init__(self):\n", + " self.MAX = 10 # I am keeping size very low to demonstrate linear probing easily but usually the size should be high\n", + " self.arr = [None for i in range(self.MAX)]\n", + " \n", + " def get_hash(self, key):\n", + " hash = 0\n", + " for char in key:\n", + " hash += ord(char)\n", + " return hash % self.MAX\n", + " \n", + " def __getitem__(self, key):\n", + " h = self.get_hash(key)\n", + " if self.arr[h] is None:\n", + " return\n", + " prob_range = self.get_prob_range(h)\n", + " for prob_index in prob_range:\n", + " element = self.arr[prob_index]\n", + " if element is None:\n", + " return\n", + " if element[0] == key:\n", + " return element[1]\n", + " \n", + " def __setitem__(self, key, val):\n", + " h = self.get_hash(key)\n", + " if self.arr[h] is None:\n", + " self.arr[h] = (key,val)\n", + " else:\n", + " new_h = self.find_slot(key, h)\n", + " self.arr[new_h] = (key,val)\n", + " print(self.arr)\n", + " \n", + " def get_prob_range(self, index):\n", + " return [*range(index, len(self.arr))] + [*range(0,index)]\n", + " \n", + " def find_slot(self, key, index):\n", + " prob_range = self.get_prob_range(index)\n", + " for prob_index in prob_range:\n", + " if self.arr[prob_index] is None:\n", + " return prob_index\n", + " if self.arr[prob_index][0] == key:\n", + " return prob_index\n", + " raise Exception(\"Hashmap full\")\n", + " \n", + " def __delitem__(self, key):\n", + " h = self.get_hash(key)\n", + " prob_range = self.get_prob_range(h)\n", + " for prob_index in prob_range:\n", + " if self.arr[prob_index] is None:\n", + " return # item not found so return. You can also throw exception\n", + " if self.arr[prob_index][0] == key:\n", + " self.arr[prob_index]=None\n", + " print(self.arr)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Function to show how *range(x,y) works. It returns a list of numbers in range(x,y)**" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[5, 6, 7, 0, 1, 2, 3]" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "[*range(5,8)] + [*range(0,4)]" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[None, None, None, None, None, None, None, None, None, ('march 6', 20)]\n", + "[('march 17', 88), None, None, None, None, None, None, None, None, ('march 6', 20)]\n" + ] + } + ], + "source": [ + "t = HashTable()\n", + "t[\"march 6\"] = 20\n", + "t[\"march 17\"] = 88" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[('march 17', 29), None, None, None, None, None, None, None, None, ('march 6', 20)]\n" + ] + } + ], + "source": [ + "t[\"march 17\"] = 29" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[('march 17', 29), ('nov 1', 1), None, None, None, None, None, None, None, ('march 6', 20)]\n" + ] + } + ], + "source": [ + "t[\"nov 1\"] = 1" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[('march 17', 29), ('nov 1', 1), None, None, None, None, None, ('march 33', 234), None, ('march 6', 20)]\n" + ] + } + ], + "source": [ + "t[\"march 33\"] = 234" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "t[\"dec 1\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "234" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "t[\"march 33\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[('march 17', 29), ('nov 1', 1), None, None, None, None, None, ('march 33', 999), None, ('march 6', 20)]\n" + ] + } + ], + "source": [ + "t[\"march 33\"] = 999" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "999" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "t[\"march 33\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[('march 17', 29), ('nov 1', 1), None, None, None, None, None, ('march 33', 999), ('april 1', 87), ('march 6', 20)]\n" + ] + } + ], + "source": [ + "t[\"april 1\"]=87" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[('march 17', 29), ('nov 1', 1), ('april 2', 123), None, None, None, None, ('march 33', 999), ('april 1', 87), ('march 6', 20)]\n" + ] + } + ], + "source": [ + "t[\"april 2\"]=123" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[('march 17', 29), ('nov 1', 1), ('april 2', 123), ('april 3', 234234), None, None, None, ('march 33', 999), ('april 1', 87), ('march 6', 20)]\n" + ] + } + ], + "source": [ + "t[\"april 3\"]=234234" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[('march 17', 29), ('nov 1', 1), ('april 2', 123), ('april 3', 234234), ('april 4', 91), None, None, ('march 33', 999), ('april 1', 87), ('march 6', 20)]\n" + ] + } + ], + "source": [ + "t[\"april 4\"]=91" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[('march 17', 29), ('nov 1', 1), ('april 2', 123), ('april 3', 234234), ('april 4', 91), ('May 22', 4), None, ('march 33', 999), ('april 1', 87), ('march 6', 20)]\n" + ] + } + ], + "source": [ + "t[\"May 22\"]=4" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[('march 17', 29), ('nov 1', 1), ('april 2', 123), ('april 3', 234234), ('april 4', 91), ('May 22', 4), ('May 7', 47), ('march 33', 999), ('april 1', 87), ('march 6', 20)]\n" + ] + } + ], + "source": [ + "t[\"May 7\"]=47" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "ename": "Exception", + "evalue": "Hashmap full", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mException\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[21], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mt\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mJan 1\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m0\u001b[39m\n", + "Cell \u001b[0;32mIn[2], line 29\u001b[0m, in \u001b[0;36mHashTable.__setitem__\u001b[0;34m(self, key, val)\u001b[0m\n\u001b[1;32m 27\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39marr[h] \u001b[38;5;241m=\u001b[39m (key,val)\n\u001b[1;32m 28\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m---> 29\u001b[0m new_h \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mfind_slot\u001b[49m\u001b[43m(\u001b[49m\u001b[43mkey\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mh\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 30\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39marr[new_h] \u001b[38;5;241m=\u001b[39m (key,val)\n\u001b[1;32m 31\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39marr)\n", + "Cell \u001b[0;32mIn[2], line 43\u001b[0m, in \u001b[0;36mHashTable.find_slot\u001b[0;34m(self, key, index)\u001b[0m\n\u001b[1;32m 41\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39marr[prob_index][\u001b[38;5;241m0\u001b[39m] \u001b[38;5;241m==\u001b[39m key:\n\u001b[1;32m 42\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m prob_index\n\u001b[0;32m---> 43\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mException\u001b[39;00m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mHashmap full\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n", + "\u001b[0;31mException\u001b[0m: Hashmap full" + ] + } + ], + "source": [ + "t[\"Jan 1\"]=0" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[('march 17', 29), ('nov 1', 1), None, ('april 3', 234234), ('april 4', 91), ('May 22', 4), ('May 7', 47), ('march 33', 999), ('april 1', 87), ('march 6', 20)]\n" + ] + } + ], + "source": [ + "del t[\"april 2\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[('march 17', 29), ('nov 1', 1), ('Jan 1', 0), ('april 3', 234234), ('april 4', 91), ('May 22', 4), ('May 7', 47), ('march 33', 999), ('april 1', 87), ('march 6', 20)]\n" + ] + } + ], + "source": [ + "t[\"Jan 1\"]=0" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.4" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Data_Structures/4_HashTable/nyc_weather.csv b/Data_Structures/4_HashTable/nyc_weather.csv new file mode 100644 index 0000000..0aef64a --- /dev/null +++ b/Data_Structures/4_HashTable/nyc_weather.csv @@ -0,0 +1,11 @@ +date,temperature(F) +Jan 1,27 +Jan 2,31 +Jan 3,23 +Jan 4,34 +Jan 5,37 +Jan 6,38 +Jan 7,29 +Jan 8,30 +Jan 9,35 +Jan 10,30 \ No newline at end of file diff --git a/Data_Structures/4_HashTable/poem.txt b/Data_Structures/4_HashTable/poem.txt new file mode 100644 index 0000000..e6b7466 --- /dev/null +++ b/Data_Structures/4_HashTable/poem.txt @@ -0,0 +1,23 @@ +Two roads diverged in a yellow wood, +And sorry I could not travel both +And be one traveler, long I stood +And looked down one as far as I could +To where it bent in the undergrowth; + +Then took the other, as just as fair, +And having perhaps the better claim, +Because it was grassy and wanted wear; +Though as for that the passing there +Had worn them really about the same, + +And both that morning equally lay +In leaves no step had trodden black. +Oh, I kept the first for another day! +Yet knowing how way leads on to way, +I doubted if I should ever come back. + +I shall be telling this with a sigh +Somewhere ages and ages hence: +Two roads diverged in a wood, and I— +I took the one less traveled by, +And that has made all the difference. \ No newline at end of file diff --git a/Data_Structures/4_HashTable/stock_prices.csv b/Data_Structures/4_HashTable/stock_prices.csv new file mode 100644 index 0000000..2337b02 --- /dev/null +++ b/Data_Structures/4_HashTable/stock_prices.csv @@ -0,0 +1,6 @@ +march 6,310 +march 7,340 +march 8,380 +march 9,302 +march 10,297 +march 11,323 \ No newline at end of file diff --git a/Data_Structures/5_Stack/5-1.py b/Data_Structures/5_Stack/5-1.py new file mode 100644 index 0000000..a968917 --- /dev/null +++ b/Data_Structures/5_Stack/5-1.py @@ -0,0 +1,76 @@ +# ## Data structure tutorial exercise: Stack +# 1. Write a function in python that can reverse a string using stack data structure. +# Use [Stack class](https://github.com/codebasics/data-structures-algorithms-python/blob/master/data_structures/5_Stack/5_stack.ipynb) from the tutorial. +# ``` +# reverse_string("We will conquere COVID-19") should return "91-DIVOC ereuqnoc lliw eW" +# ``` + +from collections import deque +stack = deque() + +class Stack: + def __init__(self): + self.container = deque() + + def push(self,val): + self.container.append(val) + + def pop(self): + return self.container.pop() + + def peek(self): + return self.container[-1] + + def is_empty(self): + return len(self.container)==0 + + def size(self): + return len(self.container) + + +# Rohan's Version -> using generic Python +# def reverse_string(str): +# reversed_str = '' +# for char in str: +# reversed_str = char + reversed_str +# return reversed_str + +def reverse_string(str): + s = Stack() + + # take each char in the inputted string and add it to the stack + + for char in str: + s.push(char) + + # now pop out each char and add to the output string + reversed_str = '' + for i in range(len(s.container)): + reversed_str = reversed_str + s.pop() + + return reversed_str + + +# Keys + # 1. Don't define the method within the Stack class. We want to apply it using the stack class + # 2. Use the stack methods + + +s = Stack() +s.push("https://www.cnn.com/") +s.pop() + +s.push(9) +s.push(34) +s.push(78) +s.push(12) + +print(s.peek()) + +s.pop() + +print(s.peek()) + +print(reverse_string("We will conquere COVID-19")) + +print(reverse_string("hello Rohan")) \ No newline at end of file diff --git a/Data_Structures/5_Stack/5-2.py b/Data_Structures/5_Stack/5-2.py new file mode 100644 index 0000000..e862589 --- /dev/null +++ b/Data_Structures/5_Stack/5-2.py @@ -0,0 +1,87 @@ +# 2. Write a function in python that checks if paranthesis in the string are balanced or not. +# Possible parantheses are "{}',"()" or "[]". +# Use [Stack class](https://github.com/codebasics/data-structures-algorithms-python/blob/master/data_structures/5_Stack/5_stack.ipynb) from the tutorial. +# ``` +# is_balanced("({a+b})") --> True +# is_balanced("))((a+b}{") --> False +# is_balanced("((a+b))") --> True +# is_balanced("))") --> False +# is_balanced("[a+b]*(x+2y)*{gg+kk}") --> True + +from collections import deque +stack = deque() + +class Stack: + def __init__(self): + self.container = deque() + + def push(self,val): + self.container.append(val) + + def pop(self): + return self.container.pop() + + def peek(self): + return self.container[-1] + + def is_empty(self): + return len(self.container)==0 + + def size(self): + return len(self.container) + + +#Idea 1 + # run through each char, add to the Stack if it's a [, ], {, }, (, or ) + # create a counter for {}s, []s, and ()s. Increment by 1 if a [, {, or ( is popped out. Decrement by 1 if a ], }, or ) is popped out. + + # if a ), ], or } shows up before a (, [, or { return false + +def is_balanced(str): + s = Stack() + + # run through each char, add to the Stack if it's a [, ], {, }, (, or ) + for char in str: + if char == '[' or char == ']' or char == '{' or char == '}' or char == '(' or char == ')': + s.push(char) + + # print(s.size()) + # for i in range(s.size()): + # print(s.pop()) + + # create a counter for {}s, []s, and ()s. Increment by 1 if a [, {, or ( is popped out. + #Decrement by 1 if a ], }, or ) is popped out. + sq_bracket_counter = 0 + crly_bracket_counter = 0 + parenthesis_counter = 0 + + for i in range(s.size()): + character = s.pop() + if character == "[": + sq_bracket_counter +=1 + elif character == "]": + sq_bracket_counter -=1 + if character == "{": + crly_bracket_counter +=1 + elif character == "}": + crly_bracket_counter -=1 + if character == "(": + parenthesis_counter +=1 + elif character == ")": + parenthesis_counter -=1 + + # if a ), ], or } shows up before a (, [, or { return false -> this will cause a counter to go positive + if sq_bracket_counter > 0 or crly_bracket_counter > 0 or parenthesis_counter > 0: + return False + + # Once done, check the final counts + + # if all 3 equal 0 at the end, return True. Else return false + if sq_bracket_counter == 0 and crly_bracket_counter == 0 and parenthesis_counter == 0: + return True + else: + return False + +print(is_balanced("[a+b]*(x+2y)*{gg+kk}")) + + \ No newline at end of file diff --git a/Data_Structures/5_Stack/5_stack_exercise.md b/Data_Structures/5_Stack/5_stack_exercise.md new file mode 100644 index 0000000..a91a62a --- /dev/null +++ b/Data_Structures/5_Stack/5_stack_exercise.md @@ -0,0 +1,18 @@ +## Data structure tutorial exercise: Stack +1. Write a function in python that can reverse a string using stack data structure. Use [Stack class](https://github.com/codebasics/data-structures-algorithms-python/blob/master/data_structures/5_Stack/5_stack.ipynb) from the tutorial. + ``` + reverse_string("We will conquere COVID-19") should return "91-DIVOC ereuqnoc lliw eW" + ``` + +[Solution](https://github.com/codebasics/data-structures-algorithms-python/blob/master/data_structures/5_Stack/Exercise/reverse_string.py) + +2. Write a function in python that checks if paranthesis in the string are balanced or not. Possible parantheses are "{}',"()" or "[]". Use [Stack class](https://github.com/codebasics/data-structures-algorithms-python/blob/master/data_structures/5_Stack/5_stack.ipynb) from the tutorial. + ``` + is_balanced("({a+b})") --> True + is_balanced("))((a+b}{") --> False + is_balanced("((a+b))") --> True + is_balanced("))") --> False + is_balanced("[a+b]*(x+2y)*{gg+kk}") --> True + ``` + +[Solution](https://github.com/codebasics/data-structures-algorithms-python/blob/master/data_structures/5_Stack/Exercise/balance_paran.py) \ No newline at end of file diff --git a/Data_Structures/6_Queue/6-1.py b/Data_Structures/6_Queue/6-1.py new file mode 100644 index 0000000..8809f9a --- /dev/null +++ b/Data_Structures/6_Queue/6-1.py @@ -0,0 +1,74 @@ +# ## Data structure tutorial exercise: Queue + +# For all exercises use [Queue class](https://github.com/codebasics/data-structures-algorithms-python/blob/master/data_structures/6_Queue/6_queue.ipynb) implemented in main tutorial. + +# 1. Design a food ordering system where your python program will run two threads, +# 1. Place Order: This thread will be placing an order and inserting that into a queue. This thread places new order every 0.5 second. (hint: use time.sleep(0.5) function) +# 1. Serve Order: This thread will server the order. All you need to do is pop the order out of the queue and print it. This thread serves an order every 2 seconds. Also start this thread 1 second after place order thread is started. + +# Use this video to get yourself familiar with [multithreading in python](https://www.youtube.com/watch?v=PJ4t2U15ACo&list=PLeo1K3hjS3uub3PRhdoCTY8BxMKSW7RjN&index=2&t=0s) + +# Pass following list as an argument to place order thread, +# ``` +# orders = ['pizza','samosa','pasta','biryani','burger'] +# ``` +# This problem is a producer,consumer problem where place_order thread is producing orders whereas server_order thread is consuming the food orders. +# Use Queue class implemented in a video tutorial. + +from collections import deque + +import time # so we can run a delay +import threading # so we can multithread + +class Queue: + + def __init__(self): + self.buffer = deque() + + def enqueue(self, val): + self.buffer.appendleft(val) + + def dequeue(self): + if self.is_empty(): + print("Queue is empty, waiting for orders...") + return None + return self.buffer.pop() + + def is_empty(self): + return len(self.buffer)==0 + + def size(self): + return len(self.buffer) + +def place_order(queue, orders): + for order in orders: + print(f"Placing order: {order}") + queue.enqueue(order) # Place the order in the queue + time.sleep(0.5) # Delay 0.5 seconds + +def serve_order(queue): + # Start this thread 1 second after place order thread is started. + time.sleep(1.0) + while True: + time.sleep(2.0) # Delay 2 seconds + order = queue.dequeue() + if order is None: + continue + print(f"Order served: {order}") + if queue.is_empty(): + break + +# Create a single Queue instance for both functions to use +order_queue = Queue() +orders = ['pizza', 'samosa', 'pasta', 'biryani', 'burger'] + +t1 = threading.Thread(target=place_order, args=(order_queue, orders)) +t2 = threading.Thread(target=serve_order, args=(order_queue,)) + +t1.start() +t2.start() + +t1.join() +t2.join() + +print("All orders have been placed and served.") diff --git a/Data_Structures/6_Queue/6-2.py b/Data_Structures/6_Queue/6-2.py new file mode 100644 index 0000000..81e31a6 --- /dev/null +++ b/Data_Structures/6_Queue/6-2.py @@ -0,0 +1,78 @@ +# 2. Write a program to print binary numbers from 1 to 10 using Queue. Use Queue class implemented in main tutorial. +# Binary sequence should look like, +# ``` +# 1 +# 10 +# 11 +# 100 +# 101 +# 110 +# 111 +# 1000 +# 1001 +# 1010 +# ``` +# Hint: Notice a pattern above. After 1 second and third number is 1+0 and 1+1. 4th and 5th number are second number (i.e. 10) + 0 and second number (i.e. 10) + 1. + +# You also need to add front() function in queue class that can return the front element in the queue. + +from collections import deque + +class Queue: + + def __init__(self): + self.buffer = deque() + + def enqueue(self, val): + self.buffer.appendleft(val) + + def dequeue(self): + return self.buffer.pop() + + def is_empty(self): + return len(self.buffer)==0 + + def size(self): + return len(self.buffer) + +# def front(self): +# return self.buffer[-1] + +# def produce_binary_numbers(n): +# numbers_queue = Queue() +# numbers_queue.enqueue("1") + +# for i in range(n): +# front = numbers_queue.front() +# print(" ", front) +# numbers_queue.enqueue(front + "0") +# numbers_queue.enqueue(front + "1") + +# numbers_queue.dequeue() + +# produce_binary_numbers(10) + +# Rohan's solution + +# q = Queue() + +# for i in range(1,11): +# q.enqueue(bin(i)) + +# while q.is_empty() == False: +# print(q.dequeue().replace('0b','')) + +#Rohan's solution V2 + +def produce_binary_numbers(n): + numbers_queue = Queue() + + for i in range(1,(n+1)): + numbers_queue.enqueue(bin(i)) + + while numbers_queue.is_empty() == False: + print(numbers_queue.dequeue().replace('0b','')) + +produce_binary_numbers(10) + + diff --git a/Data_Structures/6_Queue/6_queue_exercise.md b/Data_Structures/6_Queue/6_queue_exercise.md new file mode 100644 index 0000000..3c3fc2d --- /dev/null +++ b/Data_Structures/6_Queue/6_queue_exercise.md @@ -0,0 +1,38 @@ +## Data structure tutorial exercise: Queue + +For all exercises use [Queue class](https://github.com/codebasics/data-structures-algorithms-python/blob/master/data_structures/6_Queue/6_queue.ipynb) implemented in main tutorial. + +1. Design a food ordering system where your python program will run two threads, + 1. Place Order: This thread will be placing an order and inserting that into a queue. This thread places new order every 0.5 second. (hint: use time.sleep(0.5) function) + 1. Serve Order: This thread will server the order. All you need to do is pop the order out of the queue and print it. This thread serves an order every 2 seconds. Also start this thread 1 second after place order thread is started. + + Use this video to get yourself familiar with [multithreading in python](https://www.youtube.com/watch?v=PJ4t2U15ACo&list=PLeo1K3hjS3uub3PRhdoCTY8BxMKSW7RjN&index=2&t=0s) + + Pass following list as an argument to place order thread, + ``` + orders = ['pizza','samosa','pasta','biryani','burger'] + ``` + This problem is a producer,consumer problem where place_order thread is producing orders whereas server_order thread is consuming the food orders. + Use Queue class implemented in a video tutorial. + +[Solution](https://github.com/codebasics/data-structures-algorithms-python/blob/master/data_structures/6_Queue/Exercise/food_ordering_system.py) + +2. Write a program to print binary numbers from 1 to 10 using Queue. Use Queue class implemented in main tutorial. +Binary sequence should look like, +``` + 1 + 10 + 11 + 100 + 101 + 110 + 111 + 1000 + 1001 + 1010 +``` +Hint: Notice a pattern above. After 1 second and third number is 1+0 and 1+1. 4th and 5th number are second number (i.e. 10) + 0 and second number (i.e. 10) + 1. + +You also need to add front() function in queue class that can return the front element in the queue. + +[Solution](https://github.com/codebasics/data-structures-algorithms-python/blob/master/data_structures/6_Queue/Exercise/binary_numbers.py) diff --git a/Data_Structures/7_Tree/7-1.py b/Data_Structures/7_Tree/7-1.py new file mode 100644 index 0000000..d3949e5 --- /dev/null +++ b/Data_Structures/7_Tree/7-1.py @@ -0,0 +1,90 @@ +# #### Data structures exercise: General Tree + +# 1. Below is the management hierarchy of a company. + +# ![ss](management_both.PNG) + +# Extent [tree class](https://github.com/codebasics/data-structures-algorithms-python/blob/master/data_structures/7_Tree/7_tree.py) built in our +# main tutorial so that it takes **name** and **designation** in data part of TreeNode class. +# Now extend print_tree function such that it can print either name tree, designation tree or name and designation tree. As shown below, + +# ![](all_trees.png) + +# Here is how your main function should will look like, +# ``` +# if __name__ == '__main__': +# root_node = build_management_tree() +# root_node.print_tree("name") # prints only name hierarchy +# root_node.print_tree("designation") # prints only designation hierarchy +# root_node.print_tree("both") # prints both (name and designation) hierarchy + +#potentially delete the "data" field in the constructor + +class TreeNode: + def __init__(self, data, name, designation): + self.data = data + self.children = [] + self.parent = None + self.name = name + self.designation = designation + + def get_level(self): + level = 0 + p = self.parent + while p: + level += 1 + p = p.parent + + return level + + def print_tree(self, type): + if type == 'both': + value = self.name + f" ({self.designation})" + + elif type == 'designation': + value = self.designation + + else: + value = self.name + + spaces = ' ' * self.get_level() * 3 + prefix = spaces + "|__" if self.parent else "" + print(prefix + value) + + if self.children: + for child in self.children: + child.print_tree(type) + + def add_child(self, child): + child.parent = self + self.children.append(child) + +def build_management_tree(): + root = TreeNode("","Nilpul","CEO") + + cto = TreeNode("","Chinmay","CTO") + + infra_head = TreeNode("","Vishwa","Infrastructure Head") + + infra_head.add_child(TreeNode("","Dhaval","Cloud Manager")) + infra_head.add_child(TreeNode("","Abhijit","App Manager")) + + cto.add_child(infra_head) + + cto.add_child(TreeNode("","Aamir","Application Head")) + + hr_head = TreeNode("","Gels","HR Head") + + hr_head.add_child(TreeNode("","Peter","Recruitment Manager")) + hr_head.add_child(TreeNode("","Waqas","Policy Manager")) + + root.add_child(cto) + root.add_child(hr_head) + + return root + +root_node = build_management_tree() + +root_node.print_tree('both') +root_node.print_tree('designation') +root_node.print_tree('name') \ No newline at end of file diff --git a/Data_Structures/7_Tree/7-2.py b/Data_Structures/7_Tree/7-2.py new file mode 100644 index 0000000..cc0187d --- /dev/null +++ b/Data_Structures/7_Tree/7-2.py @@ -0,0 +1,101 @@ +# 2. Build below location tree using **TreeNode** class + +# ![](location_trees.png) + +# Now modify print_tree method to take tree level as input. And that should print tree only upto that level as shown below, + +# ![](location_trees_all.png) + +class TreeNode: + def __init__(self, data): + self.data = data + self.children = [] + self.parent = None + + def get_level(self): + level = 0 + p = self.parent + while p: + level += 1 + p = p.parent + + return level + + # original code + # def print_tree(self): + # spaces = ' ' * self.get_level() * 3 + # prefix = spaces + "|__" if self.parent else "" + # print(prefix + self.data) + # if self.children: + # for child in self.children: + # child.print_tree() + + def print_tree(self,level): + spaces = ' ' * self.get_level() * 3 + prefix = spaces + "|__" if self.parent else "" + print(prefix + self.data) + if self.children: + for child in self.children: + if child.get_level() <= level: + child.print_tree(level) + + # def print_tree(self, level): + # for i in range(level): + # spaces = ' ' * self.get_level() * 3 + # prefix = spaces + "|__" if self.parent else "" + # print(prefix + self.data) + # if self.children: + # for child in self.children: + # child.print_tree(level) + + # def print_tree(self, level): + # spaces = ' ' * self.get_level() * 3 + # prefix = spaces + "|__" if self.parent else "" + # print(prefix + self.data) + # if self.children: + # for i in range(level): + # self.children[i].print_tree(i) + + + def add_child(self, child): + child.parent = self + self.children.append(child) + +def build_country_tree(): + globe = TreeNode("Global") + + india = TreeNode("India") + gujarat = TreeNode("Gujarat") + karnataka = TreeNode("Karnataka") + + gujarat.add_child(TreeNode("Ahmedabad")) + gujarat.add_child(TreeNode("Baroda")) + + karnataka.add_child(TreeNode("Bangluru")) + karnataka.add_child(TreeNode("Mysore")) + + india.add_child(gujarat) + india.add_child(karnataka) + + usa = TreeNode("USA") + new_jersey = TreeNode("New Jersey") + california = TreeNode("California") + + new_jersey.add_child(TreeNode("Princeton")) + new_jersey.add_child(TreeNode("Trenton")) + + california.add_child(TreeNode("San Fransisco")) + california.add_child(TreeNode("Mountain View")) + california.add_child(TreeNode("Palo Alto")) + + usa.add_child(new_jersey) + usa.add_child(california) + + globe.add_child(india) + globe.add_child(usa) + + return globe + +root_node = build_country_tree() + +root_node.print_tree(3) \ No newline at end of file diff --git a/Data_Structures/7_Tree/7_tree_exercise.md b/Data_Structures/7_Tree/7_tree_exercise.md new file mode 100644 index 0000000..8c00808 --- /dev/null +++ b/Data_Structures/7_Tree/7_tree_exercise.md @@ -0,0 +1,34 @@ +#### Data structures exercise: General Tree + +1. Below is the management hierarchy of a company. + + ![ss](management_both.PNG) + +Extent [tree class](https://github.com/codebasics/data-structures-algorithms-python/blob/master/data_structures/7_Tree/7_tree.py) built in our +main tutorial so that it takes **name** and **designation** in data part of TreeNode class. +Now extend print_tree function such that it can print either name tree, designation tree or name and designation tree. As shown below, + + ![](all_trees.png) + +Here is how your main function should will look like, +``` +if __name__ == '__main__': + root_node = build_management_tree() + root_node.print_tree("name") # prints only name hierarchy + root_node.print_tree("designation") # prints only designation hierarchy + root_node.print_tree("both") # prints both (name and designation) hierarchy +``` + +[Solution](https://github.com/codebasics/data-structures-algorithms-python/blob/master/data_structures/7_Tree/Exercise/management_hierarchy.py) + +2. Build below location tree using **TreeNode** class + + ![](location_trees.png) + +Now modify print_tree method to take tree level as input. And that should print tree only upto that level as shown below, + + ![](location_trees_all.png) + +[Solution](https://github.com/codebasics/data-structures-algorithms-python/blob/master/data_structures/7_Tree/Exercise/location_hierarchy.py) + + diff --git a/Data_Structures/8_Binary_Tree_1/8.py b/Data_Structures/8_Binary_Tree_1/8.py new file mode 100644 index 0000000..e315137 --- /dev/null +++ b/Data_Structures/8_Binary_Tree_1/8.py @@ -0,0 +1,116 @@ +# ### Binary Tree Part 1 Exercise + +# Add following methods to [BinarySearchTreeNode class](https://github.com/codebasics/data-structures-algorithms-python/blob/master/data_structures/8_Binary_Tree_1/binary_tree_part_1.py) created in main video tutorial + +# 1. find_min(): finds minimum element in entire binary tree +# 2. find_max(): finds maximum element in entire binary tree +# 3. calculate_sum(): calcualtes sum of all elements +# 4. post_order_traversal(): performs post order traversal of a binary tree +# 5. pre_order_traversal(): perofrms pre order traversal of a binary tree + +class BinarySearchTreeNode: + def __init__(self, data): + self.data = data + self.left = None + self.right = None + + def add_child(self, data): + if data == self.data: + return # node already exist + + if data < self.data: + if self.left: + self.left.add_child(data) + else: + self.left = BinarySearchTreeNode(data) + else: + if self.right: + self.right.add_child(data) + else: + self.right = BinarySearchTreeNode(data) + + + def search(self, val): + if self.data == val: + return True + + if val < self.data: + if self.left: + return self.left.search(val) + else: + return False + + if val > self.data: + if self.right: + return self.right.search(val) + else: + return False + + def in_order_traversal(self): + elements = [] + if self.left: + elements += self.left.in_order_traversal() + + elements.append(self.data) + + if self.right: + elements += self.right.in_order_traversal() + + return elements + + def find_min(self): + if self.left: + return self.left.find_min() + else: + return self.data + + def find_max(self): + if self.right: + return self.right.find_max() + else: + return self.data + + def calcluate_sum(self): + sum = 0 + elements = self.in_order_traversal() + for i in elements: + sum += i + return sum + + def pre_order_traversal(self): + elements = [self.data] + if self.left: + elements += self.left.pre_order_traversal() + if self.right: + elements += self.right.pre_order_traversal() + return elements + + + def post_order_traversal(self): + elements = [] + if self.left: + elements += self.left.post_order_traversal() + if self.right: + elements += self.right.post_order_traversal() + + elements.append(self.data) + + return elements + +def build_tree(elements): + print("Building tree with these elements:",elements) + root = BinarySearchTreeNode(elements[0]) + + for i in range(1,len(elements)): + root.add_child(elements[i]) + + return root + +numbers_tree = build_tree([15, 12, 7, 14, 27, 20, 23, 88]) + +print(numbers_tree.find_min()) +print(numbers_tree.find_max()) +print(numbers_tree.calcluate_sum()) +print(numbers_tree.in_order_traversal()) +print(numbers_tree.post_order_traversal()) +print(numbers_tree.pre_order_traversal()) \ No newline at end of file diff --git a/Data_Structures/8_Binary_Tree_1/8_binary_tree_part_1_exercise.md b/Data_Structures/8_Binary_Tree_1/8_binary_tree_part_1_exercise.md new file mode 100644 index 0000000..d050129 --- /dev/null +++ b/Data_Structures/8_Binary_Tree_1/8_binary_tree_part_1_exercise.md @@ -0,0 +1,12 @@ +### Binary Tree Part 1 Exercise + +Add following methods to [BinarySearchTreeNode class](https://github.com/codebasics/data-structures-algorithms-python/blob/master/data_structures/8_Binary_Tree_1/binary_tree_part_1.py) created in main video tutorial + + 1. find_min(): finds minimum element in entire binary tree + 2. find_max(): finds maximum element in entire binary tree + 3. calculate_sum(): calcualtes sum of all elements + 4. post_order_traversal(): performs post order traversal of a binary tree + 5. pre_order_traversal(): perofrms pre order traversal of a binary tree + +[Solution](https://github.com/codebasics/data-structures-algorithms-python/blob/master/data_structures/8_Binary_Tree_1/Exercise/binary_tree_part_1_exercise.py) + diff --git a/Data_Structures/9_Binary_Tree_2/9.py b/Data_Structures/9_Binary_Tree_2/9.py new file mode 100644 index 0000000..447aa83 --- /dev/null +++ b/Data_Structures/9_Binary_Tree_2/9.py @@ -0,0 +1,172 @@ +# ### Binary Tree Part 2 Exercise + +# Modify delete method in class [BinarySearchTreeNode class](https://github.com/codebasics/data-structures-algorithms-python/blob/master/data_structures/9_Binary_Tree_2/binary_tree_part_2.py) +# to use min element from left subtree. You will remove lines marked with ---> and use max value from left subtree + +# ``` + # def delete(self, val): + # if val < self.data: + # if self.left: + # self.left = self.left.delete(val) + # elif val > self.data: + # if self.right: + # self.right = self.right.delete(val) + # else: + # if self.left is None and self.right is None: + # return None + # elif self.left is None: + # return self.right + # elif self.right is None: + # return self.right + + # ---> min_val = self.right.find_min() + # ---> self.data = min_val + # ---> self.right = self.right.delete(min_val) + + +class BinarySearchTreeNode: + def __init__(self, data): + self.data = data + self.left = None + self.right = None + + def add_child(self, data): + if data == self.data: + return # node already exist + + if data < self.data: + if self.left: + self.left.add_child(data) + else: + self.left = BinarySearchTreeNode(data) + else: + if self.right: + self.right.add_child(data) + else: + self.right = BinarySearchTreeNode(data) + + + def search(self, val): + if self.data == val: + return True + + if val < self.data: + if self.left: + return self.left.search(val) + else: + return False + + if val > self.data: + if self.right: + return self.right.search(val) + else: + return False + + def in_order_traversal(self): + elements = [] + if self.left: + elements += self.left.in_order_traversal() + + elements.append(self.data) + + if self.right: + elements += self.right.in_order_traversal() + + return elements + + def find_min(self): + if self.left: + return self.left.find_min() + else: + return self.data + + def find_max(self): + if self.right: + return self.right.find_max() + else: + return self.data + + def calcluate_sum(self): + sum = 0 + elements = self.in_order_traversal() + for i in elements: + sum += i + return sum + + def pre_order_traversal(self): + elements = [self.data] + if self.left: + elements += self.left.pre_order_traversal() + if self.right: + elements += self.right.pre_order_traversal() + return elements + + + def post_order_traversal(self): + elements = [] + if self.left: + elements += self.left.post_order_traversal() + if self.right: + elements += self.right.post_order_traversal() + + elements.append(self.data) + + return elements + + def delete(self, val): + if val < self.data: + if self.left: + self.left = self.left.delete(val) + elif val > self.data: + if self.right: + self.right = self.right.delete(val) + else: + if self.left is None and self.right is None: + return None + elif self.left is None: + return self.right + elif self.right is None: + return self.right + + min_val = self.right.find_min() + self.data = min_val + self.right = self.right.delete(min_val) + return self + + + def delete2(self, val): + if val < self.data: + if self.left: + self.left = self.left.delete(val) + elif val > self.data: + if self.right: + self.right = self.right.delete(val) + else: + if self.left is None and self.right is None: + return None + elif self.left is None: + return self.right + elif self.right is None: + return self.right + + max_val = self.left.find_max() + self.data = max_val + self.left = self.left.delete(max_val) + return self + +def build_tree(elements): + print("Building tree with these elements:",elements) + root = BinarySearchTreeNode(elements[0]) + + for i in range(1,len(elements)): + root.add_child(elements[i]) + + return root + +numbers_tree = build_tree([15, 12, 7, 14, 27, 20, 23, 88]) + +print(numbers_tree.in_order_traversal()) + +numbers_tree.delete2(23) + +print(numbers_tree.in_order_traversal()) diff --git a/Data_Structures/9_Binary_Tree_2/9_binary_tree_part_2_exercise.md b/Data_Structures/9_Binary_Tree_2/9_binary_tree_part_2_exercise.md new file mode 100644 index 0000000..95cb303 --- /dev/null +++ b/Data_Structures/9_Binary_Tree_2/9_binary_tree_part_2_exercise.md @@ -0,0 +1,28 @@ +### Binary Tree Part 2 Exercise + +Modify delete method in class [BinarySearchTreeNode class](https://github.com/codebasics/data-structures-algorithms-python/blob/master/data_structures/9_Binary_Tree_2/binary_tree_part_2.py) +to use min element from left subtree. You will remove lines marked with ---> and use max value from left subtree + +``` + def delete(self, val): + if val < self.data: + if self.left: + self.left = self.left.delete(val) + elif val > self.data: + if self.right: + self.right = self.right.delete(val) + else: + if self.left is None and self.right is None: + return None + elif self.left is None: + return self.right + elif self.right is None: + return self.right + + ---> min_val = self.right.find_min() + ---> self.data = min_val + ---> self.right = self.right.delete(min_val) +``` + +[Solution](https://github.com/codebasics/data-structures-algorithms-python/blob/master/data_structures/9_Binary_Tree_2/Exercise/binary_tree_part_2_exercise.py) +