diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..cecaf8a Binary files /dev/null and b/.DS_Store differ diff --git a/Chapter01/chapter1.py b/Chapter01/chapter1.py new file mode 100644 index 0000000..9d9d1be --- /dev/null +++ b/Chapter01/chapter1.py @@ -0,0 +1,598 @@ +p = "Hello India" +q = 10 +r = 10.2 +print(type(p)) +print(type(q)) +print(type(r)) +print(type(12+31j)) + +############### + +var = 13.2 +print(type(var)) +#13.2 + +type (var) +# + +var = "Now the type is string" +print(type(var)) + +type(var) +# +var = 13.2 +print(var) +#13.2 + +############# +print(type(bool(22))) +print(type(True)) +print(type(False)) +''' +Output: + + + +''' + +bool(False) +print(bool(False)) +#False +va1 = 0 +print(bool(va1)) +#False + +va2 = 11 +print(bool(va2)) +#True + +va3 = -2.3 +print(bool(va3)) +#True + +#### Strings +str1 = 'Hello how are you' +str2 = "Hello how are you" +str3 = 'multiline'+'string'; +print(str1) +print(str2) +print(str3) + +f = 'data' +s = 'structure' +print(f + s) +#'datastructure' +print('Data ' + 'structure') +#Data structure + + +st = 'data.' +print(st * 3) +#'data.data.data.' +print(3 * st) +#'data.data.data.' + +###### Range ###### + +print(list(range(10))) +print(range(10)) +print(list(range(10))) +print(range(1,10,2)) +print(list(range(1,10,2))) +print(list(range(20,10,-2))) + +#[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] +#range(0, 10) +#[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] +#range(1, 10, 2) +#[1, 3, 5, 7, 9] +#[20, 18, 16, 14, 12] + + +###### Lists ###### + +a = ['food', 'bus', 'apple', 'queen'] +print(a) +#['food', 'bus', 'apple', 'queen'] + + +mylist = [10, "India", "world", 8] +# accessing elements in list. +print(mylist[1]) +#India + + + +###### Ordered List ###### + +[10, 12, 31, 14] == [14, 10, 31, 12] +print([10, 12, 31, 14] == [14, 10, 31, 12]) +#False + + +###### Dynamic List ###### +b = ['data', 'and', 'book', 'structure', 'hello', 'st'] + +b += [32] +print(b) +#['data', 'and', 'book', 'structure', 'hello', 'st', 32] + + +b[2:3] = [] +print(b) +#['data', 'and', 'structure', 'hello', 'st', 32] + +del b[0] +print(b) +#['and', 'structure', 'hello', 'st', 32] + +a = [2.2, 'python', 31, 14, 'data', False, 33.59] +print(a) +#[2.2, 'python', 31, 14, 'data', False, 33.59] + + +a = ['data', 'structures', 'using', 'python', 'happy', 'learning'] +print(a[0]) +'data' +print(a[2]) +'using' +print(a[-1]) +'learning' +print(a[-5]) +'structures' + + +print(a[1:5]) +['structures', 'using'] + +print(a[-3:-1]) +['python', 'happy'] + +######### Mutable #### +a = ['data', 'and', 'book', 'structure', 'hello', 'st'] +print(a) +['data', 'and', 'book', 'structure', 'hello', 'st'] +a[1] = 1 +a[-1] = 120 +print(a) +['data', 1, 'book', 'structure', 'hello', 120] + +a = ['data', 'and', 'book', 'structure', 'hello', 'st'] + +print(a[2:5]) +['book', 'structure', 'hello'] +a[2:5] = [1, 2, 3, 4, 5] +print(a) +['data', 'and', 1, 2, 3, 4, 5, 'st'] + +######### Other operators #### + +a = ['data', 'structures', 'using', 'python', 'happy', 'learning'] +print('data' in a) +#True + +print(a) +#['data', 'structures', 'using', 'python', 'happy', 'learning'] + +a + ['New', 'elements'] +print(a) +#['data', 'structures', 'using', 'python', 'happy', 'learning', 'New', 'elements'] + +print(a * 2) +#['data', 'structures', 'using', 'python', 'happy', 'learning', 'New', 'elements', 'data', 'structures', 'using', 'python', 'happy', 'learning', 'New', 'elements'] + +print(len(a)) +#6 +print(min(a)) + + +############ Membership operators + +#using 'in' operator +mylist1=[100,20,30,40] +mylist2=[10,50,60,90] +if mylist1[1] in mylist2: + print("elements are overlapping") +else: + print("elements are not overlapping") + +#Output: +#elements are not overlapping + + +########## Program to illustrate 'not in' operator +val = 104 +mylist = [100, 210, 430, 840, 108] +if val not in mylist: + print("val is NOT present in mylist") +else: + print("val is present in mylist") + +#Output: +#val is NOT present in mylist + + + +############# Example program to demonstrate the use of 'is' operator +Firstlist = [] +Secondlist = [] +if Firstlist == Secondlist: + print("Both are equal") +else: + print("Both are not equal") +if Firstlist is Secondlist: + print("Both variables are pointing to the same object") +else: + print("Both variables are not pointing to the same object") +thirdList = Firstlist +if thirdList is Secondlist: + print("Both are pointing to the same object") +else: + print("Both are not pointing to the same object") +''' +Output: +Both are equal +Both variables are not pointing to the same object +Both are pointing to the same object +''' + + + +####### Example program to demonstrate the use of 'is not' operator +Firstlist = [] +Secondlist = [] +if Firstlist is not Secondlist: + print("Both Firstlist and Secondlist variables are the same object") +else: + print("Both Firstlist and Secondlist variables are not the same object") + +#Output: +# Both Firstlist and Secondlist variables are the same object + + + +############## Logical Operators + +#### Example program to demonstrate the use of 'and' operator +a = 32 +b = 132 +if a > 0 and b > 0: + print("Both a and b are greater than zero") +else: + print("At least one variable is less than 0") + +#Output: +#Both a and b are greater than zero + + + +######### Example program to demonstrate the use of 'or' operator +a = 32 +b = -32 +if a > 0 or b > 0: + print("At least one variable is greater than zero") +else: + print("Both variables are less than 0") + +#Output: +#At least one variable is greater than zero + + +########## Example program to demonstrate the use of 'or' operator +a = 32 +if not a: + print("Boolean value of a is False") +else: + print("Boolean value of a is True") + +#Output: +#Boolean value of a is True + + + + +########## Tuple ########### + +tupleName = ("entry1" , "entry2" , "entry3") +myTuple = ("Shyam", 23 , True , "male") +print(len((4,5, 'hello'))) + +print((4,5)+(10,20)) +print((2,1)*3) +print(3 in ('hi', 'xyz',3)) +for p in (6,7,8): + print(p) + +x = ('hello', 'world', 'india') +print(x[1]) +print(x[-2]) +print(x[1:]) + + +######### Dictionaries ######### +my_dict = { + '1': 'Data', + '2': 'Structure', + '3': 'python', + '4': 'programming', + '5': 'language' +} + + +############ + +person = {} +print(type(person)) +# + +person['name'] = 'ABC' +person['lastname'] = 'XYZ' +person['age'] = 31 +person['address'] = ['Jaipur'] + +print(person) +#{'name': 'ABC', 'lastname': 'XYZ', 'age': 31, 'address': ['Jaipur']} + +print(person['name']) +#'ABC' + + +print('name' in person) +#True +print('fname' not in person) +#True +print(len(person)) +#4 + +mydict = {'a': 1, 'b': 2, 'c': 3} +print(mydict) +#{'a': 1, 'b': 2, 'c': 3} +mydict.clear() +print(mydict) +#{} + +''' +mydict.get('b') +print(mydict) +#2 +mydict.get('z') +print(mydict) +#None + +print(list(mydict.items())) +#[('a', 1), ('b', 2), ('c', 3)] + +print(list(mydict.keys())) +#['a', 'b', 'c'] + +print(list(mydict.values())) +#[1, 2, 3] + +print(mydict.pop('b')) +#2 +print(mydict) +#{'a': 1, 'c': 3} +mydict = {'a': 1,'b': 2,'c': 3} +print(mydict.popitem()) +#('c', 3) +print(mydict) +#{'a': 1, 'b': 2} +d1 = {'a': 10, 'b': 20, 'c': 30} +d2 = {'b': 200, 'd': 400} + +print(d1.update(d2)) +print(d1) +#{'a': 10, 'b': 200, 'c': 30, 'd': 400} +''' + + +############## SETS ############# + +x1 = set(['and', 'python', 'data', 'structure']) +print(x1) +#{'and', 'python', 'data', 'structure'} +print(type(x1)) +# + +x2 = {'and', 'python', 'data', 'structure'} +print(x2) +#{'and', 'python', 'data', 'structure'} +x = {'data', 'structure', 'and', 'python'} +print(len(x)) +#4 +print('structure' in x) +#True +x1 = {'data', 'structure'} +x2 = {'python', 'java', 'c', 'data'} + +######### Union of two sets, x1 and x2. +x3 = x1 | x2 +print(x3) +{'java', 'structure', 'c', 'python', 'data'} + +print(x1.union(x2)) +{'java', 'structure', 'c', 'python', 'data'} + + +########## Intersection of sets +print(x1.intersection(x2)) +#{'data'} +print(x1 & x2) +#{'data'} + + +########## Difference of sets + +print(x1.difference(x2)) +#{'structure'} +print(x1 - x2) +#{'structure'} + + +######### Symmetric difference ########## +print(x1.symmetric_difference(x2)) +#{'structure', 'python', 'c', 'java'} + +print(x1 ^ x2) +#{'structure', 'python', 'c', 'java'} + +####### subset ###### + +print(x1.issubset(x2)) +#False +print(x1 <= x2) +#False + +########## Immutable Sets ######### + +x = frozenset(['data', 'structure', 'and', 'python']) +print(x) +#frozenset({'and', 'python', 'data', 'structure'}) +##### Error in the below code #### +''' +a11 = set(['data']) +a21 = set(['structure']) +a31 = set(['python']) +x1 = {a11, a21, a31} +''' + +a1 = frozenset(['data']) +a2 = frozenset(['structure']) +a3 = frozenset(['python']) +x = {a1, a2, a3} +print(x) + + + +######## Named Tuples ######## + +from collections import namedtuple +Book = namedtuple ('Book', ['name', 'ISBN', 'quantity']) +Book1 = Book('Hands on Data Structures', '9781788995573', '50') +# Accessing data items +print('Using index ISBN:' + Book1[1]) +#Using index ISBN: 9781788995573 +print('Using key ISBN:' + Book1.ISBN) +#Using key ISBN: 9781788995573 + + +######## Deque ############ + +from collections import deque +s = deque() # Creates an empty deque +print(s) +my_queue = deque([1, 2, 'Name']) +print(my_queue) +#deque([1, 2, 'Name']) +my_queue.append('age') +print(my_queue) +my_queue.appendleft('age') +print(my_queue) +my_queue.pop() +print(my_queue) +my_queue.popleft() +print(my_queue) + + +########## Ordered Dictionaries ######## + +from collections import OrderedDict +od = OrderedDict({'my': 2, 'name ': 4, 'is': 2, 'Mohan' :5}) +od['hello'] = 4 +print(od) +#([('my', 2), ('name', 4), ('is', 2), ('Mohan', 5), ('hello', 4)]) + + +############ Default Dictionary ######## + +from collections import defaultdict +dd = defaultdict(int) +words = str.split('data python data data structure data python') +for word in words: + dd[word] +=1 + +print(dd) +#defaultdict(, {'data': 4, 'python': 2, 'structure': 1}) + + + + +############ ChainMap Object ############## + +from collections import ChainMap +dict1 = {"data": 1, "structure": 2} +dict2 = {"python": 3, "language": 4} +chain = ChainMap(dict1, dict2) + +print(chain) +#ChainMap({'data': 1, 'structure': 2}, {'python': 3, 'language': 4}) +print(list(chain.keys())) +#['python', 'language', 'data', 'structure'] +print(list(chain.values())) +#[3, 4, 1, 2] +print(chain["data"]) +#1 +print(chain["language"]) +#4 + + +################ Counter Objects ########### + +from collections import Counter +inventory = Counter('hello') +print(inventory) +Counter({'l': 2, 'h': 1, 'e': 1, 'o': 1}) + + + +############### UserDict ############# +''' +from collections import UserDict +class MyDict(UserDict): + def push(self, key, value): + raise RuntimeError("Cannot insert") + +d = MyDict({'ab':1, 'bc': 2, 'cd': 3}) +d.push('b', 2) + +Traceback (most recent call last): + File "", line 12, in +File "", line 6, in push +RuntimeError: Cannot insert +''' + +######### UserList ########### +''' +from collections import UserList +class MyList(UserList): + def push(self, key): + raise RuntimeError("Cannot insert in the list") + +d = MyList([11, 12, 13]) +d.push(2) + +Traceback (most recent call last): + Traceback (most recent call last): + File "", line 1, in + File "", line 3, in push +RuntimeError: Cannot insert in the list +''' + +######### UserString ########## + +# create a custom append function for string +from collections import UserString +class MyString(UserString): + def append(self, value): + self.data += value + +s1 = MyString("data") +print("Original:", s1) +#Original: data + +s1.append('h') +print("After append: ", s1) +#After append: datah + + + diff --git a/Chapter02/binary_search.py b/Chapter02/binary_search.py new file mode 100644 index 0000000..4ca8711 --- /dev/null +++ b/Chapter02/binary_search.py @@ -0,0 +1,16 @@ +def binary_search(arr, low, high, key): + while low <= high: + mid = int(low + (high - low)/2) + if arr[mid] == key: + return mid + elif arr[mid] < key: + low = mid + 1 + else: + high = mid - 1 + return -1 + + +arr = [ 2, 3, 4, 2, 10, 40] +x = 10 +result = binary_search(arr, 0, len(arr)-1, x) +print(result) diff --git a/Chapter02/linear_search.py b/Chapter02/linear_search.py new file mode 100644 index 0000000..a66c676 --- /dev/null +++ b/Chapter02/linear_search.py @@ -0,0 +1,13 @@ +# Linear search program to search an element, return the index position of the #array + +def linear_search(input_list, element): + for index, value in enumerate(input_list): + if value == element: + return index + + return -1 + + +input_list = [3, 4, 1, 6, 14] +element = 4 +print("Index position for the element x is:", linear_search(input_list,element)) diff --git a/Chapter02/matrix_chain.py b/Chapter02/matrix_chain.py new file mode 100644 index 0000000..55b6eed --- /dev/null +++ b/Chapter02/matrix_chain.py @@ -0,0 +1,14 @@ +import sys + +def matrix_chain(mat, i, j): + if i == j: + return 0 + minimum_computations = sys.maxsize + for k in range(i, j): + count = (matrix_chain(mat, i, k) + matrix_chain(mat, k+1, j)+ mat[i-1] * mat[k] * mat[j]) + if count < minimum_computations: + minimum_computations = count + return minimum_computations + +matrix_sizes = [20, 30, 45, 50] +print("Minimum multiplications are", matrix_chain(matrix_sizes , 1, len(matrix_sizes)-1)) diff --git a/Chapter02/merge_sort.py b/Chapter02/merge_sort.py new file mode 100644 index 0000000..d724aca --- /dev/null +++ b/Chapter02/merge_sort.py @@ -0,0 +1,37 @@ +def merge_sort(unsorted_list): + if len(unsorted_list) == 1: + return unsorted_list + mid_point = int(len(unsorted_list)/2) + first_half = unsorted_list[:mid_point] + second_half = unsorted_list[mid_point:] + + half_a = merge_sort(first_half) + half_b = merge_sort(second_half) + + return merge(half_a, half_b) + + +def merge(first_sublist, second_sublist): + i = j = 0 + merged_list = [] + while i < len(first_sublist) and j < len(second_sublist): + if first_sublist[i] < second_sublist[j]: + merged_list.append(first_sublist[i]) + i += 1 + else: + merged_list.append(second_sublist[j]) + j += 1 + + while i < len(first_sublist): + merged_list.append(first_sublist[i]) + i += 1 + + while j < len(second_sublist): + merged_list.append(second_sublist[j]) + j += 1 + return merged_list + + +a= [11, 12, 7, 41, 61, 13, 16, 14] +print(merge_sort(a)) + diff --git a/Chapter03/Fibonacci_series.py b/Chapter03/Fibonacci_series.py new file mode 100644 index 0000000..99590f2 --- /dev/null +++ b/Chapter03/Fibonacci_series.py @@ -0,0 +1,8 @@ +def fib(n): + if n <= 1: + return 1 + else: + return fib(n-1) + fib(n-2) + +for i in range(5): + print(fib(i)) diff --git a/Chapter03/MatrixChain_multiplication.py b/Chapter03/MatrixChain_multiplication.py new file mode 100644 index 0000000..3c14e70 --- /dev/null +++ b/Chapter03/MatrixChain_multiplication.py @@ -0,0 +1,14 @@ +import sys +def MatrixChain(mat, i, j): + if i == j: + return 0 + minimum_computations = sys.maxsize + for k in range(i, j): + count = (MatrixChain(mat, i, k) + MatrixChain(mat, k+1, j)+ mat[i-1] * mat[k] * mat[j]) + if count < minimum_computations: + minimum_computations = count + return minimum_computations + + +matrix_sizes = [20, 30, 45, 50] +print("Minimum multiplications are", MatrixChain(matrix_sizes , 1, len(matrix_sizes)-1)) diff --git a/Chapter03/binary_search.py b/Chapter03/binary_search.py new file mode 100644 index 0000000..09a6444 --- /dev/null +++ b/Chapter03/binary_search.py @@ -0,0 +1,18 @@ +def binary_search(arr, start, end, key): + while start <= end: + mid = start + (end - start)//2 + if arr[mid] == key: + return mid + elif arr[mid] < key: + start = mid + 1 + else: + end = mid - 1 + return -1 + + +arr = [ 4, 6, 9, 13, 14, 18, 21, 24, 38] +x = 13 +result = binary_search(arr, 0, len(arr)-1, x) +print(result) + + diff --git a/Chapter03/dijkstra.py b/Chapter03/dijkstra.py new file mode 100644 index 0000000..29cab7a --- /dev/null +++ b/Chapter03/dijkstra.py @@ -0,0 +1,80 @@ + +def get_shortest_distance(table, vertex): + shortest_distance = table[vertex][DISTANCE] + return shortest_distance + +def set_shortest_distance(table, vertex, new_distance): + table[vertex][DISTANCE] = new_distance + +def set_previous_node(table, vertex, previous_node): + table[vertex][PREVIOUS_NODE] = previous_node + +def get_distance(graph, first_vertex, second_vertex): + return graph[first_vertex][second_vertex] + +def get_next_node(table, visited_nodes): + unvisited_nodes = list(set(table.keys()).difference(set(visited_nodes))) + assumed_min = table[unvisited_nodes[0]][DISTANCE] + min_vertex = unvisited_nodes[0] + for node in unvisited_nodes: + if table[node][DISTANCE] < assumed_min: + assumed_min = table[node][DISTANCE] + min_vertex = node + return min_vertex + +def find_shortest_path(graph, table, origin): + visited_nodes = [] + current_node = origin + starting_node = origin + while True: + adjacent_nodes = graph[current_node] + if set(adjacent_nodes).issubset(set(visited_nodes)): + # Nothing here to do. All adjacent nodes have been visited. + pass + else: + unvisited_nodes = set(adjacent_nodes).difference(set(visited_nodes)) + for vertex in unvisited_nodes: + distance_from_starting_node = get_shortest_distance(table, vertex) + if distance_from_starting_node == INFINITY and current_node == starting_node: + total_distance = get_distance(graph, vertex, current_node) + else: + total_distance = get_shortest_distance (table, + current_node) + get_distance(graph, current_node, vertex) + if total_distance < distance_from_starting_node: + set_shortest_distance(table, vertex, total_distance) + set_previous_node(table, vertex, current_node) + visited_nodes.append(current_node) + #print(visited_nodes) + if len(visited_nodes) == len(table.keys()): + break + current_node = get_next_node(table,visited_nodes) + return(table) + +graph = dict() +graph['A'] = {'B': 5, 'D': 9, 'E': 2} +graph['B'] = {'A': 5, 'C': 2} +graph['C'] = {'B': 2, 'D': 3} +graph['D'] = {'A': 9, 'F': 2, 'C': 3} +graph['E'] = {'A': 2, 'F': 3} +graph['F'] = {'E': 3, 'D': 2} + +table = dict() +table = { + 'A': [0, None], + 'B': [float("inf"), None], + 'C': [float("inf"), None], + 'D': [float("inf"), None], + 'E': [float("inf"), None], + 'F': [float("inf"), None], +} + + +DISTANCE = 0 +PREVIOUS_NODE = 1 +INFINITY = float('inf') + +shortest_distance_table = find_shortest_path(graph, table, 'A') + + +for k in sorted(shortest_distance_table): + print("{} - {}".format(k,shortest_distance_table[k])) diff --git a/Chapter03/dyna_fib.py b/Chapter03/dyna_fib.py new file mode 100644 index 0000000..9c81b91 --- /dev/null +++ b/Chapter03/dyna_fib.py @@ -0,0 +1,17 @@ +def dyna_fib(n): + if n == 0: + return 0 + if n == 1: + return 1 + if lookup[n] is not None: + return lookup[n] + + lookup[n] = dyna_fib(n-1) + dyna_fib(n-2) + return lookup[n] + + +lookup = [None]*(1000) + + +for i in range(6): + print(dyna_fib(i)) diff --git a/Chapter03/factorial.py b/Chapter03/factorial.py new file mode 100644 index 0000000..861221a --- /dev/null +++ b/Chapter03/factorial.py @@ -0,0 +1,10 @@ +def factorial(n): + # test for a base case + if n == 0: + return 1 + else: + return n*factorial(n-1) # Do the calculation and a recursive call + + + +print(factorial(4)) diff --git a/Chapter03/merge_sort.py b/Chapter03/merge_sort.py new file mode 100644 index 0000000..d678a03 --- /dev/null +++ b/Chapter03/merge_sort.py @@ -0,0 +1,35 @@ +def merge_sort(unsorted_list): + if len(unsorted_list) == 1: + return unsorted_list + mid_point = int(len(unsorted_list)/2) + first_half = unsorted_list[:mid_point] + second_half = unsorted_list[mid_point:] + + half_a = merge_sort(first_half) + half_b = merge_sort(second_half) + + return merge(half_a, half_b) + + + +def merge(first_sublist, second_sublist): + i = j = 0 + merged_list = [] + while i < len(first_sublist) and j < len(second_sublist): + if first_sublist[i] < second_sublist[j]: + merged_list.append(first_sublist[i]) + i += 1 + else: + merged_list.append(second_sublist[j]) + j += 1 + while i < len(first_sublist): + merged_list.append(first_sublist[i]) + i += 1 + while j < len(second_sublist): + merged_list.append(second_sublist[j]) + j += 1 + return merged_list + + +a= [11, 12, 7, 41, 61, 13, 16, 14] +print(merge_sort(a)) diff --git a/Chapter04/CircularList.py b/Chapter04/CircularList.py new file mode 100644 index 0000000..e179121 --- /dev/null +++ b/Chapter04/CircularList.py @@ -0,0 +1,104 @@ +class Node: + """ A Circular linked node. """ + def __init__(self, data=None): + self.data = data + self.next = None + + + + +class CircularList: + def __init__ (self): + self.tail = None + self.head = None + self.size = 0 + + def append(self, data): + node = Node(data) + if self.tail: + self.tail.next = node + self.tail = node + node.next = self.head + else: + self.head = node + self.tail = node + self.tail.next = self.tail + self.size += 1 + + def delete(self, data): + current = self.head + prev = self.head + flag = False + while prev == current or prev != self.tail: + if current.data == data: + if current == self.head: + #item to be deleted is head node + self.head = current.next + self.tail.next = self.head + elif current == self.tail: + #item to be deleted is tail node + self.tail = prev + prev.next = self.head + else: + #item to be deleted is an intermediate node + prev.next = current.next + self.size -= 1 + return + prev = current + current = current.next + if flag is False: + print("Item not present in the list") + + + def iter(self): + current = self.head + while current: + val = current.data + current = current.next + yield val + + + +words = CircularList() +words.append('eggs') +words.append('ham') +words.append('spam') + + +counter = 0 +for word in words.iter(): + print(word) + counter += 1 + if counter > 2: + break + + + +words.append('foo') +words.append('bar') +words.append('bim') +words.append('baz') +words.append('quux') +words.append('duux') + + + +print("Done iterating. Now we try to delete something that isn't there.") +words.delete('socks') +print('back to iterating') +counter = 0 +for item in words.iter(): + print(item) + counter += 1 + if counter > 2: + break + +print('Let us delete something that is there.') +words.delete('foo') +print('back to iterating') +counter = 0 +for item in words.iter(): + print(item) + counter += 1 + if counter > 2: + break diff --git a/Chapter04/SinglyLinkedList.py b/Chapter04/SinglyLinkedList.py new file mode 100644 index 0000000..01647cf --- /dev/null +++ b/Chapter04/SinglyLinkedList.py @@ -0,0 +1,34 @@ +class Node: + """ A singly-linked node. """ + def __init__(self, data=None): + self.data = data + self.next = None + + +class SinglyLinkedList: + def __init__ (self): + self.head = None + self.size = 0 + + def append(self, data): + # Encapsulate the data in a Node + node = Node(data) + if self.head is None: + self.head = node + else: + current = self.head + while current.next: + current = current.next + current.next = node + + + +words = SinglyLinkedList() +words.append('egg') +words.append('ham') +words.append('spam') + +current = words.head +while current: + print(current.data) + current = current.next diff --git a/Chapter04/append_at_any_location_singly_linkedlist.py b/Chapter04/append_at_any_location_singly_linkedlist.py new file mode 100644 index 0000000..c2e1f2f --- /dev/null +++ b/Chapter04/append_at_any_location_singly_linkedlist.py @@ -0,0 +1,70 @@ +class Node: + """ A singly-linked node. """ + def __init__(self, data=None): + self.data = data + self.next = None + + +class SinglyLinkedList: + def __init__ (self): + self.tail = None + self.head = None + self.size = 0 + + def append(self, data): + # Encapsulate the data in a Node + node = Node(data) + if self.head is None: + self.head = node + else: + current = self.head + while current.next: + current = current.next + current.next = node + + def append_at_a_location(self, data, index): + current = self.head + prev = self.head + node = Node(data) + count = 1 + while current: + if count == 1: + node.next = current + self.head = node + print(count) + return + elif index == index: + node.next = current + prev.next = node + return + count += 1 + prev = current + current = current.next + if count < index: + print("The list has less number of elements") + + + + + +words = SinglyLinkedList() +words.append('egg') +words.append('ham') +words.append('spam') + +current = words.head +while current: + print(current.data) + current = current.next + + + +words.append_at_a_location('new', 2) + +current = words.head +while current: + print(current.data) + current = current.next + + + diff --git a/Chapter04/delete_operation_doubly_linkedlist.py b/Chapter04/delete_operation_doubly_linkedlist.py new file mode 100644 index 0000000..8bdf96d --- /dev/null +++ b/Chapter04/delete_operation_doubly_linkedlist.py @@ -0,0 +1,80 @@ +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 + self.tail = None + self.count = 0 + + def append(self, data): + #Append an item to the list. + new_node = Node(data, None, None) + if self.head is None: + self.head = new_node + self.tail = self.head + else: + new_node.prev = self.tail + self.tail.next = new_node + self.tail = new_node + self.count += 1 + + + + def delete(self, data): + # Delete a node from the list. + current = self.head + node_deleted = False + if current is None: #List is empty + print("List is empty") + elif current.data == data: #Item to be deleted is found at starting of list + self.head.prev = None + node_deleted = True + self.head = current.next + + elif self.tail.data == data: #Item to be deleted is found at the end of list. + self.tail = self.tail.prev + self.tail.next = None + node_deleted = True + + else: + while current: #search item to be deleted, and delete that node + if current.data == data: + current.prev.next = current.next + current.next.prev = current.prev + node_deleted = True + current = current.next + if node_deleted == False: #Item to be deleted is not found in the list + print("Item not found") + if node_deleted: + self.count -= 1 + + + + +#Code to create for a doubly linked list +words = DoublyLinkedList() +words.append('egg') +words.append('ham') +words.append('spam') +current = words.head +while current: + print(current.data) + current = current.next + + +words.delete('ham') +current = words.head +while current: + print(current.data) + current = current.next + + +words.delete('spam') +current = words.head +while current: + print(current.data) + current = current.next diff --git a/Chapter04/delete_operation_singly_linkedlist.py b/Chapter04/delete_operation_singly_linkedlist.py new file mode 100644 index 0000000..c181c0c --- /dev/null +++ b/Chapter04/delete_operation_singly_linkedlist.py @@ -0,0 +1,86 @@ +class Node: + """ A singly-linked node. """ + def __init__(self, data=None): + self.data = data + self.next = None + +class SinglyLinkedList: + def __init__ (self): + self.head = None + self.size = 0 + + def append(self, data): + # Encapsulate the data in a Node + node = Node(data) + if self.head is None: + self.head = node + else: + current = self.head + while current.next: + current = current.next + current.next = node + + def delete_first_node (self): + current = self.head + if self.head is None: + print("No data element to delete") + elif current == self.head: + self.head = current.next + + + def delete_last_node (self): + current = self.head + prev = self.head + while current: + if current.next is None: + prev.next = current.next + self.size -= 1 + prev = current + current = current.next + + + def delete(self, data): + current = self.head + prev = self.head + while current: + if current.data == data: + if current == self.head: + self.head = current.next + else: + prev.next = current.next + self.size -= 1 + return + prev = current + current = current.next + + +words = SinglyLinkedList() +words.append('egg') +words.append('ham') +words.append('spam') + +words.delete_first_node() + +current = words.head +while current: + print(current.data) + current = current.next + + + +words.delete_last_node() + +current = words.head +while current: + print(current.data) + current = current.next + + + +words.delete('ham') +current = words.head +while current: + print(current.data) + current = current.next + + diff --git a/Chapter04/doubly_linked_list.py b/Chapter04/doubly_linked_list.py new file mode 100644 index 0000000..4eb2f94 --- /dev/null +++ b/Chapter04/doubly_linked_list.py @@ -0,0 +1,116 @@ +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 + self.tail = None + self.count = 0 + + def append(self, data): + #Append an item at the end of the list. + new_node = Node(data, None, None) + if self.head is None: + self.head = new_node + self.tail = self.head + else: + new_node.prev = self.tail + self.tail.next = new_node + self.tail = new_node + self.count += 1 + + + def append_at_start(self, data): + # Append an item at beginning to the list. + new_node = Node(data, None, None) + if self.head is None: + self.head = new_node + self.tail = self.head + else: + new_node.next = self.head + self.head.prev = new_node + self.head = new_node + self.count += 1 + + def append_at_a_location(self, data): + current = self.head + prev = self.head + new_node = Node(data, None, None) + while current: + if current.data == data: + new_node.prev = prev + new_node.next = current + prev.next = new_node + current.prev = new_node + self.count += 1 + prev = current + current = current.next + + def iter(self): + current = self.head + while current: + val = current.data + current = current.next + yield val + + + def contains(self, data): + for node_data in self.iter(): + if data == node_data: + print(" Data item is present in the list. ") + return + print(" Data item is not present in the list. ") + return + + + + +words = DoublyLinkedList() +words.append('egg') +words.append('ham') +words.append('spam') + +print("Items in doubly linked list before append") +current = words.head +while current: + print(current.data) + current = current.next + +words.append_at_start('book') + +print("Items in doubly linked list after append") +current = words.head +while current: + print(current.data) + current = current.next + + +words.append('book') + +print("Items in doubly linked list after adding element at end.") +current = words.head +while current: + print(current.data) + current = current.next + + + +words.append_at_a_location('ham') +print("Doubly linked list after adding an element after word \"ham\" in the list.") +current = words.head +while current: + print(current.data) + current = current.next + + +words = DoublyLinkedList() +words.append('egg') +words.append('ham') +words.append('spam') + + +words.contains("ham") +words.contains("ham2") diff --git a/Chapter04/faster_append_singly_linked_list.py b/Chapter04/faster_append_singly_linked_list.py new file mode 100644 index 0000000..1d0b25b --- /dev/null +++ b/Chapter04/faster_append_singly_linked_list.py @@ -0,0 +1,32 @@ +class Node: + """ A singly-linked node. """ + def __init__(self, data=None): + self.data = data + self.next = None + + +class SinglyLinkedList: + def __init__ (self): + self.tail = None + self.head = None + self.size = 0 + + def append(self, data): + node = Node(data) + if self.tail: + self.tail.next = node + self.tail = node + else: + self.head = node + self.tail = node + + +words = SinglyLinkedList() +words.append('egg') +words.append('ham') +words.append('spam') + +current = words.head +while current: + print(current.data) + current = current.next diff --git a/Chapter04/list_traversal_singly_linklist.py b/Chapter04/list_traversal_singly_linklist.py new file mode 100644 index 0000000..5b6d259 --- /dev/null +++ b/Chapter04/list_traversal_singly_linklist.py @@ -0,0 +1,38 @@ +class Node: + """ A singly-linked node. """ + def __init__(self, data=None): + self.data = data + self.next = None + + +class SinglyLinkedList: + def __init__ (self): + self.head = None + self.size = 0 + + def append(self, data): + # Encapsulate the data in a Node + node = Node(data) + if self.head is None: + self.head = node + else: + current = self.head + while current.next: + current = current.next + current.next = node + + def iter(self): + current = self.head + while current: + val = current.data + current = current.next + yield val + + +words = SinglyLinkedList() +words.append('egg') +words.append('ham') +words.append('spam') + +for word in words.iter(): + print(word) diff --git a/Chapter05/.DS_Store b/Chapter05/.DS_Store new file mode 100644 index 0000000..fd3fa0c Binary files /dev/null and b/Chapter05/.DS_Store differ diff --git a/Chapter05/Linked_list_based_queue.py b/Chapter05/Linked_list_based_queue.py new file mode 100644 index 0000000..ee479df --- /dev/null +++ b/Chapter05/Linked_list_based_queue.py @@ -0,0 +1,50 @@ +class Node(object): + def __init__(self, data=None, next=None, prev=None): + self.data = data + self.next = next + self.prev = prev + + +class Queue: + def __init__(self): + self.head = None + self.tail = None + self.count = 0 + + def enqueue(self, data): + new_node = Node(data, None, None) + if self.head == None: + self.head = new_node + self.tail = self.head + else: + new_node.prev = self.tail + self.tail.next = new_node + self.tail = new_node + + self.count += 1 + + + def dequeue(self): + if self.count == 1: + self.count -= 1 + self.head = None + self.tail = None + elif self.count > 1: + self.head = self.head.next + self.head.prev = None + elif self.count <1: + print("Queue is empty") + self.count -= 1 + + + +q= Queue() +q.enqueue(4) +q.enqueue('dog') +q.enqueue('True') + +print(q.count) + +q.dequeue() + +print(q.count) diff --git a/Chapter05/List_based_queue.py b/Chapter05/List_based_queue.py new file mode 100644 index 0000000..bf1a9ce --- /dev/null +++ b/Chapter05/List_based_queue.py @@ -0,0 +1,44 @@ +class ListQueue: + def __init__(self): + self.items = [] + self.front = self.rear = 0 + self.size = 3 # maximum capacity of the queue + + def enqueue(self, data): + if self.size == self.rear: + print("\nQueue is full") + else: + self.items.append(data) + self.rear += 1 + + + + def dequeue(self): + if self.front == self.rear: + print("Queue is empty") + else: + data = self.items.pop(0) # delete the item from front end of the queue + self.rear -= 1 + return data + + + +q = ListQueue() +q.enqueue(20) +q.enqueue(30) +q.enqueue(40) +q.enqueue(50) +print(q.items) +#Queue is full +#[20, 30, 40] + + +data = q.dequeue() +print(data) +print(q.items) +#20 +#[30, 40] + + +a = q.size1() +print(a) diff --git a/Chapter05/Queue_application.py b/Chapter05/Queue_application.py new file mode 100644 index 0000000..3526aad --- /dev/null +++ b/Chapter05/Queue_application.py @@ -0,0 +1,98 @@ +from random import randint + + + +class Node(object): + """ A Doubly-linked lists' node. """ + def __init__(self, data=None, next=None, prev=None): + self.data = data + self.next = next + self.prev = prev + + +class Queue(object): + """ A doubly-linked list. """ + def __init__(self): + self.head = None + self.tail = None + self.count = 0 + + def enqueue(self, data): + """ Append an item to the list. """ + + new_node = Node(data, None, None) + if self.head is None: + self.head = new_node + self.tail = self.head + else: + new_node.prev = self.tail + self.tail.next = new_node + self.tail = new_node + + self.count += 1 + + def dequeue(self): + """ Remove elements from the front of the list""" + current = self.head + if self.count == 1: + self.count -= 1 + self.head = None + self.tail = None + elif self.count > 1: + self.head = self.head.next + self.head.prev = None + self.count -= 1 + return current + + + +queue = Queue() + +import time +start_time = time.time() +for i in range(100000): + queue.enqueue(i) +for i in range(100000): + queue.dequeue() +print("--- %s seconds ---" % (time.time() - start_time)) + + +class Track: + + def __init__(self, title=None): + self.title = title + self.length = randint(5, 10) + + + +track1 = Track("white whistle") +track2 = Track("butter butter") +print(track1.length) +print(track2.length) + +import time +class MediaPlayerQueue(Queue): + + + def add_track(self, track): + self.enqueue(track) + + def play(self): + while self.count > 0: + current_track_node = self.dequeue() + print("Now playing {}".format(current_track_node.data.title)) + time.sleep(current_track_node.data.length) + +track1 = Track("white whistle") +track2 = Track("butter butter") +track3 = Track("Oh black star") +track4 = Track("Watch that chicken") +track5 = Track("Don't go") + +media_player = MediaPlayerQueue() +media_player.add_track(track1) +media_player.add_track(track2) +media_player.add_track(track3) +media_player.add_track(track4) +media_player.add_track(track5) +media_player.play() diff --git a/Chapter05/Stack.py b/Chapter05/Stack.py new file mode 100644 index 0000000..3e01863 --- /dev/null +++ b/Chapter05/Stack.py @@ -0,0 +1,67 @@ +class Node: + def __init__(self, data=None): + self.data = data + self.next = None + + + +class Stack: + def __init__(self): + self.top = None + self.size = 0 + + def push(self, data): + # create a new node + node = Node(data) + if self.top: + node.next = self.top + self.top = node + else: + self.top = node + self.size += 1 + + + + def pop(self): + if self.top: + data = self.top.data + self.size -= 1 + if self.top.next: #check if there is more than one node. + self.top = self.top.next + else: + self.top = None + return data + else: + print("Stack is empty") + + + def peek(self): + if self.top: + return self.top.data + else: + print("Stack is empty") + + + +words = Stack() +words.push('egg') +words.push('ham') +words.push('spam') + +#print the stack elements. +current = words.top +while current: + print(current.data) + current = current.next + + +words.pop() + +current = words.top +while current: + print(current.data) + current = current.next + + +words.peek() + diff --git a/Chapter05/Stack_application.py b/Chapter05/Stack_application.py new file mode 100644 index 0000000..afc3006 --- /dev/null +++ b/Chapter05/Stack_application.py @@ -0,0 +1,68 @@ +class Node: + def __init__(self, data=None): + self.data = data + self.next = None + + + +class stack: + def __init__(self): + self.top = None + self.size = 0 + + def push(self, data): + # create a new node + node = Node(data) + if self.top: + node.next = self.top + self.top = node + else: + self.top = node + self.size += 1 + + + + def pop(self): + if self.top: + data = self.top.data + self.size -= 1 + if self.top.next: #check if there is more than one node. + self.top = self.top.next + else: + self.top = None + return data + else: + print("Stack is empty") + + + def peek(self): + if self.top: + return self.top.data + else: + print("Stack is empty") + + + +words = stack() +words.push('4') +words.push('5') +words.push('6') +words.push('7') + +#print the stack elements. +current = words.top +while current: + print(current.data) + current = current.next + + +words.pop() + +current = words.top +while current: + print(current.data) + current = current.next + + +words.peek() + diff --git a/Chapter05/Stack_based_queue.py b/Chapter05/Stack_based_queue.py new file mode 100644 index 0000000..5591d47 --- /dev/null +++ b/Chapter05/Stack_based_queue.py @@ -0,0 +1,31 @@ +class Queue: + def __init__(self): + self.Stack1 = [] + self.Stack2 = [] + + def enqueue(self, data): + self.Stack1.append(data) + + + + def dequeue(self): + if not self.Stack2: + while self.Stack1: + self.Stack2.append(self.Stack1.pop()) + if not self.Stack2: + print("No element to dequeue") + return + return self.Stack2.pop() + + +queue = Queue() +queue.enqueue(5) +queue.enqueue(6) +queue.enqueue(7) +print(queue.Stack1) + +queue.dequeue() +print(queue.Stack1) +print(queue.Stack2) +queue.dequeue() +print(queue.Stack2) diff --git a/Chapter05/Stack_using_array.py b/Chapter05/Stack_using_array.py new file mode 100644 index 0000000..20ad138 --- /dev/null +++ b/Chapter05/Stack_using_array.py @@ -0,0 +1,51 @@ +size = 3 +data = [0]*(size) #Initialize the stack +top = -1 + +def push(x): + global top + if top >= size-1: + print("Stack Overflow") + else: + top = top + 1 + data[top] = x + + +def pop(): + global top + if top == -1: + print("Stack Underflow") + else: + top = top-1 + data[top] = 0 + return data[top+1] + + +def peek(): + global top + if top == -1: + print("Stack is empty") + else: + print(data[top]) + + + + +push('egg') +push('ham') +push('spam') +push('new') +push('new2') + +print(data[0 : top + 1]) + +print(data[0 : top + 1]) +pop() +pop() +pop() +pop() +print(data[0:top+1]) + +peek() + +print(data[0:top+1]) diff --git a/Chapter06/binary_search_tree.py b/Chapter06/binary_search_tree.py new file mode 100644 index 0000000..c9ebdbd --- /dev/null +++ b/Chapter06/binary_search_tree.py @@ -0,0 +1,166 @@ +class Node: + def __init__(self, data): + self.data = data + self.right_child = None + self.left_child = None + +class Tree: + def __init__(self): + self.root_node = None + + def insert(self, data): + node = Node(data) + if self.root_node is None: + self.root_node = node + return self.root_node + else: + current = self.root_node + parent = None + while True: + parent = current + if node.data < parent.data: + current = current.left_child + if current is None: + parent.left_child = node + return self.root_node + else: + current = current.right_child + if current is None: + parent.right_child = node + return self.root_node + + def inorder(self, root_node): + current = root_node + if current is None: + return + self.inorder(current.left_child) + print(current.data) + self.inorder(current.right_child) + + + def get_node_with_parent(self, data): + parent = None + current = self.root_node + if current is None: + return (parent, None) + while True: + if current.data == data: + return (parent, current) + elif current.data > data: + parent = current + current = current.left_child + else: + parent = current + current = current.right_child + return (parent, current) + + + def remove(self, data): + parent, node = self.get_node_with_parent(data) + + if parent is None and node is None: + return False + + # Get children count + children_count = 0 + + if node.left_child and node.right_child: + children_count = 2 + elif (node.left_child is None) and (node.right_child is None): + children_count = 0 + else: + children_count = 1 + + if children_count == 0: + if parent: + if parent.right_child is node: + parent.right_child = None + else: + parent.left_child = None + else: + self.root_node = None + elif children_count == 1: + next_node = None + if node.left_child: + next_node = node.left_child + else: + next_node = node.right_child + + if parent: + if parent.left_child is node: + parent.left_child = next_node + else: + parent.right_child = next_node + else: + self.root_node = next_node + else: + parent_of_leftmost_node = node + leftmost_node = node.right_child + while leftmost_node.left_child: + parent_of_leftmost_node = leftmost_node + leftmost_node = leftmost_node.left_child + node.data = leftmost_node.data + + if parent_of_leftmost_node.left_child == leftmost_node: + parent_of_leftmost_node.left_child = leftmost_node.right_child + else: + parent_of_leftmost_node.right_child = leftmost_node.right_child + + + + def search(self, data): + current = self.root_node + while True: + if current is None: + print("Item not found") + return None + elif current.data is data: + print("Item found", data) + return data + elif current.data > data: + current = current.left_child + else: + current = current.right_child + + + def find_min(self): + current = self.root_node + while current.left_child: + current = current.left_child + return current.data + + + def find_max(self): + current = self.root_node + while current.right_child: + current = current.right_child + return current.data + + + +tree = Tree() +r = tree.insert(5) +r = tree.insert(2) +r = tree.insert(7) +r = tree.insert(9) +r = tree.insert(1) + +tree.inorder(r) + + + +tree.search(9) + + +tree.remove(9) +tree.search(9) + +tree = Tree() +tree.insert(5) +tree.insert(2) +tree.insert(7) +tree.insert(9) +tree.insert(1) + +print(tree.find_min()) +print(tree.find_max()) diff --git a/Chapter06/level_order_traversal.py b/Chapter06/level_order_traversal.py new file mode 100644 index 0000000..e14a551 --- /dev/null +++ b/Chapter06/level_order_traversal.py @@ -0,0 +1,35 @@ +from collections import deque + +class Node: + def __init__(self, data): + self.data = data + self.right_child = None + self.left_child = None + + +n1 = Node("root node") +n2 = Node("left child node") +n3 = Node("right child node") +n4 = Node("left grandchild node") + +n1.left_child = n2 +n1.right_child = n3 +n2.left_child = n4 + + + +def level_order_traversal(root_node): + list_of_nodes = [] + traversal_queue = deque([root_node]) + while len(traversal_queue) > 0: + node = traversal_queue.popleft() + list_of_nodes.append(node.data) + if node.left_child: + traversal_queue.append(node.left_child) + if node.right_child: + traversal_queue.append(node.right_child) + return list_of_nodes + + + +print(level_order_traversal(n1)) diff --git a/Chapter06/reverse_polish_expression.py b/Chapter06/reverse_polish_expression.py new file mode 100644 index 0000000..e01080d --- /dev/null +++ b/Chapter06/reverse_polish_expression.py @@ -0,0 +1,46 @@ + +class Stack: + def __init__(self): + self.elements = [] + + def push(self, item): + self.elements.append(item) + + def pop(self): + return self.elements.pop() + + +class TreeNode: + def __init__(self, data=None): + self.data = data + self.right = None + self.left = None + +def calc(node): + if node.data == "+": + return calc(node.left) + calc(node.right) + elif node.data == "-": + return calc(node.left) - calc(node.right) + elif node.data == "*": + return calc(node.left) * calc(node.right) + elif node.data == "/": + return calc(node.left) / calc(node.right) + else: + return node.data + +expr = "4 5 + 5 3 - *".split() + +stack = Stack() + +for term in expr: + if term in "+-*/": + node = TreeNode(term) + node.right = stack.pop() + node.left = stack.pop() + else: + node = TreeNode(int(term)) + stack.push(node) + +root = stack.pop() +result = calc(root) +print(result) diff --git a/Chapter06/tree_traversal.py b/Chapter06/tree_traversal.py new file mode 100644 index 0000000..7314801 --- /dev/null +++ b/Chapter06/tree_traversal.py @@ -0,0 +1,53 @@ +class Node: + def __init__(self, data): + self.data = data + self.right_child = None + self.left_child = None + + +n1 = Node("root node") +n2 = Node("left child node") +n3 = Node("right child node") +n4 = Node("left grandchild node") +n1.left_child = n2 +n1.right_child = n3 +n2.left_child = n4 + +current = n1 +while current: + print(current.data) + current = current.left_child + +print("\n" ) + +def inorder(root_node): + current = root_node + if current is None: + return + inorder(current.left_child) + print(current.data) + inorder(current.right_child) + +def preorder(root_node): + current = root_node + if current is None: + return + print(current.data) + preorder(current.left_child) + preorder(current.right_child) + + +def postorder(root_node): + current = root_node + if current is None: + return + postorder(current.left_child) + postorder(current.right_child) + print(current.data) + + +inorder(n1) +print("\n" ) +preorder(n1) +print("\n" ) +postorder(n1) diff --git a/Chapter07/.DS_Store b/Chapter07/.DS_Store new file mode 100644 index 0000000..2167c40 Binary files /dev/null and b/Chapter07/.DS_Store differ diff --git a/Chapter07/heap.py b/Chapter07/heap.py new file mode 100644 index 0000000..ee0aa33 --- /dev/null +++ b/Chapter07/heap.py @@ -0,0 +1,72 @@ +class MinHeap: + def __init__(self): + self.heap = [0] + self.size = 0 + + def arrange(self, k): + while k // 2 > 0: + if self.heap[k] < self.heap[k//2]: + self.heap[k], self.heap[k//2] = self.heap[k//2], self.heap[k] + k //= 2 + + def insert(self, item): + self.heap.append(item) + self.size += 1 + self.arrange(self.size) + + def sink(self, k): + while k * 2 <= self.size: + mc = self.minchild(k) + if self.heap[k] > self.heap[mc]: + self.heap[k], self.heap[mc] = self.heap[mc], self.heap[k] + k = mc + + def minchild(self, k): + if k * 2 + 1 > self.size: + return k * 2 + elif self.heap[k*2] < self.heap[k*2+1]: + return k * 2 + else: + return k * 2 + 1 + + def delete_at_root(self): + item = self.heap[1] + self.heap[1] = self.heap[self.size] + self.size -= 1 + self.heap.pop() + self.sink(1) + return item + + + def delete_at_location(self, location): + item = self.heap[location] + self.heap[location] = self.heap[self.size] + self.size -= 1 + self.heap.pop() + self.sink(location) + return item + + + +h = MinHeap() +for i in ( 4, 8, 7, 2, 9, 10, 5, 1, 3, 6): + h.insert(i) +print(h.heap) + +n = h.delete_at_root() +print(n) +print(h.heap) + +h = MinHeap() +for i in (4, 8, 7, 2, 9, 10, 5, 1, 3, 6): + h.insert(i) +print(h.heap) + +n = h.delete_at_location(2) +print(n) +print(h.heap) + + + + + diff --git a/Chapter07/heap_sort.py b/Chapter07/heap_sort.py new file mode 100644 index 0000000..39f7a92 --- /dev/null +++ b/Chapter07/heap_sort.py @@ -0,0 +1,82 @@ +class MinHeap: + def __init__(self): + self.heap = [0] + self.size = 0 + + def arrange(self, k): + while k // 2 > 0: + if self.heap[k] < self.heap[k//2]: + self.heap[k], self.heap[k//2] = self.heap[k//2], self.heap[k] + k //= 2 + + def insert(self, item): + self.heap.append(item) + self.size += 1 + self.arrange(self.size) + + def sink(self, k): + while k * 2 <= self.size: + mc = self.minchild(k) + if self.heap[k] > self.heap[mc]: + self.heap[k], self.heap[mc] = self.heap[mc], self.heap[k] + k = mc + + def minchild(self, k): + if k * 2 + 1 > self.size: + return k * 2 + elif self.heap[k*2] < self.heap[k*2+1]: + return k * 2 + else: + return k * 2 + 1 + + def delete_at_root(self): + item = self.heap[1] + self.heap[1] = self.heap[self.size] + self.size -= 1 + self.heap.pop() + self.sink(1) + return item + + + def delete_at_location(self, location): + item = self.heap[location] + self.heap[location] = self.heap[self.size] + self.size -= 1 + self.heap.pop() + self.sink(location) + return item + + def heap_sort(self): + sorted_list = [] + for node in range(self.size): + n = self.pop() + sorted_list.append(n) + return sorted_list + + + +h = MinHeap() +for i in ( 4, 8, 7, 2, 9, 10, 5, 1, 3, 6): + h.insert(i) +print(h.heap) + + +h = MinHeap() +unsorted_list = [4, 8, 7, 2, 9, 10, 5, 1, 3, 6] +for i in unsorted_list: + h.insert(i) +print("Unsorted list: {}".format(unsorted_list)) + + + + + +h = MinHeap() +unsorted_list = [4, 8, 7, 2, 9, 10, 5, 1, 3, 6] +for i in unsorted_list: + h.insert(i) +print("Unsorted list: {}".format(unsorted_list)) + +print("Sorted list: {}".format(h.heap_sort())) + + diff --git a/Chapter07/priorityQueue.py b/Chapter07/priorityQueue.py new file mode 100644 index 0000000..6508c2f --- /dev/null +++ b/Chapter07/priorityQueue.py @@ -0,0 +1,57 @@ +# class for Node with data and priority +class Node: + def __init__(self, info, priority): + self.info = info + self.priority = priority + +# class for Priority queue +class PriorityQueue: + def __init__(self): + self.queue = [] + + def size(self): + return (len(self.queue)) + + def show(self): + for x in self.queue: + print(str(x.info)+ " - "+ str(x.priority)) + + + def insert(self, node): + if len(self.queue) == 0: + # add the new node + self.queue.append(node) + else: + # traverse the queue to find the right place for new node + for x in range(0, len(self.queue)): + # if the priority of new node is greater + if node.priority >= self.queue[x].priority: + # if we have traversed the complete queue + if x == (len(self.queue)-1): + # add new node at the end + self.queue.insert(x+1, node) + else: + continue + else: + self.queue.insert(x, node) + return True + + def delete(self): + # remove the first node from the queue + x = self.queue.pop(0) + print("Deleted data with the given priority-", x.info, x.priority) + return x + + + +p = PriorityQueue() +p.insert(Node("Cat", 13)) +p.insert(Node("Bat", 2)) +p.insert(Node("Rat", 1)) +p.insert(Node("Ant", 26)) +p.insert(Node("Lion", 25)) +p.show() + + +p.delete() +p.show() diff --git a/Chapter07/priorityQueueHeap.py b/Chapter07/priorityQueueHeap.py new file mode 100644 index 0000000..ff47587 --- /dev/null +++ b/Chapter07/priorityQueueHeap.py @@ -0,0 +1,59 @@ +class PriorityQueueHeap: + def __init__(self): + self.heap = [()] + self.size = 0 + + def arrange(self, k): + while k // 2 > 0: + if self.heap[k][0] < self.heap[k//2][0]: + self.heap[k], self.heap[k//2] = self.heap[k//2], self.heap[k] + k //= 2 + + def insert(self,priority, item): + self.heap.append((priority, item)) + self.size += 1 + self.arrange(self.size) + + def sink(self, k): + while k * 2 <= self.size: + mc = self.minchild(k) + if self.heap[k][0] > self.heap[mc][0]: + self.heap[k], self.heap[mc] = self.heap[mc], self.heap[k] + k = mc + + def minchild(self, k): + if k * 2 + 1 > self.size: + return k * 2 + elif self.heap[k*2][0] < self.heap[k*2+1][0]: + return k * 2 + else: + return k * 2 + 1 + + def delete_at_root(self): + item = self.heap[1][1] + self.heap[1] = self.heap[self.size] + self.size -= 1 + self.heap.pop() + self.sink(1) + return item + + + +h = PriorityQueueHeap() +h.insert(2, "Bat") +h.insert(13,"Cat") +h.insert(18, "Rat") +h.insert(26, "Ant") +h.insert(3, "Lion") +h.insert(4, "Bear") + +h.heap + + +for i in range(h.size): + n = h.delete_at_root() + print(n) + print(h.heap) + + + diff --git a/Chapter08/.DS_Store b/Chapter08/.DS_Store new file mode 100644 index 0000000..3bfb2fc Binary files /dev/null and b/Chapter08/.DS_Store differ diff --git a/Chapter08/hashing.py b/Chapter08/hashing.py new file mode 100644 index 0000000..3b49cf3 --- /dev/null +++ b/Chapter08/hashing.py @@ -0,0 +1,10 @@ +def hash(data): + counter = 1 + sum = 0 + for d in data: + sum += counter * ord(d) + return sum % 256 + +items = ['foo', 'bar', 'bim', 'baz', 'quux', 'duux', 'gnn'] +for item in items: + print("{}: {}".format(item, hash(item))) diff --git a/Chapter08/hashtable.py b/Chapter08/hashtable.py new file mode 100644 index 0000000..d6f986a --- /dev/null +++ b/Chapter08/hashtable.py @@ -0,0 +1,184 @@ +class HashItem: + def __init__(self, key, value): + self.key = key + self.value = value + + +class HashTable: + def __init__(self): + self.size = 256 + self.slots = [None for i in range(self.size)] + self.count = 0 + self.MAXLOADFACTOR = 0.65 + self.prime_num = 5 + + def check_growth(self): + loadfactor = self.count / self.size + if loadfactor > self.MAXLOADFACTOR: + print("Load factor before growing the hash table", self.count / self.size ) + self.growth() + print("Load factor after growing the hash table", self.count / self.size ) + + + def growth(self): + New_Hash_Table = HashTable() + New_Hash_Table.size = 2 * self.size + New_Hash_Table.slots = [None for i in range(New_Hash_Table.size)] + + for i in range(self.size): + if self.slots[i] != None: + New_Hash_Table.put(self.slots[i].key, self.slots[i].value) + + self.size = New_Hash_Table.size + self.slots = New_Hash_Table.slots + + + def _hash(self, key): + mult = 1 + hv = 0 + for ch in key: + hv += mult * ord(ch) + mult += 1 + return hv % self.size + + def put(self, key, value): + item = HashItem(key, value) + h = self._hash(key) + + while self.slots[h] != None: + if self.slots[h].key == key: + break + h = (h + 1) % self.size + if self.slots[h] == None: + self.count += 1 + self.slots[h] = item + self.check_growth() + + def get(self, key): + h = self._hash(key) + while self.slots[h] != None: + if self.slots[h].key == key: + return self.slots[h].value + h = (h+ 1) % self.size + return None + + def put_quadratic(self, key, value): + item = HashItem(key, value) + h = self._hash(key) + j = 1 + while self.slots[h] != None: + if self.slots[h].key == key: + break + h = (h + j*j) % self.size + j = j+1 + if self.slots[h] == None: + self.count += 1 + self.slots[h] = item + self.check_growth() + + + def get_quadratic(self, key): + h = self._hash(key) + j = 1 + while self.slots[h] != None: + if self.slots[h].key == key: + return self.slots[h].value + h = (h+ j*j) % self.size + j = j + 1 + return None + + + def h2(self, key): + mult = 1 + hv = 0 + for ch in key: + hv += mult * ord(ch) + mult += 1 + return hv + + + def put_double_hashing(self, key, value): + item = HashItem(key, value) + h = self._hash(key) + j = 1 + while self.slots[h] != None: + if self.slots[h].key == key: + break + h = (h + j * (self.prime_num - (self.h2(key) % self.prime_num))) % self.size + j = j+1 + if self.slots[h] == None: + self.count += 1 + self.slots[h] = item + self.check_growth() + + def get_double_hashing(self, key): + h = self._hash(key) + j = 1 + while self.slots[h] != None: + if self.slots[h].key == key: + return self.slots[h].value + h = (h + j * (self.prime_num - (self.h2(key) % self.prime_num))) % self.size + j = j + 1 + return None + + + + + def __setitem__(self, key, value): + self.put(key, value) + + def __getitem__(self, key): + return self.get(key) + + + +ht = HashTable() +ht.put_quadratic(“good”, “eggs”) +ht.put_quadratic(“ad”, “packt”) +ht.put_quadratic(“ga”, “books”) +v = ht.get_quadratic(“ga”) +print(v) + + +ht = HashTable() +ht.put("good", "eggs") +ht.put("better", "ham") +ht.put("best", "spam") +ht.put("ad", "do not") +ht.put("ga", "collide") +ht.put(“awd”, “do not”) +ht.put(“add”, “do not”) +ht.checkGrow() + +for key in ("good", "better", "best", "worst", "ad", "ga"): + v = ht.get(key) + print(v) + + +ht = HashTable() +ht.put_double_hashing(“good”, “eggs”) +ht.put_double_hashing(“better”, “spam”) +ht.put_double_hashing(“best”, “cool”) +ht.put_double_hashing(“ad”, “donot”) +ht.put_double_hashing(“ga”, “collide”) +ht.put_double_hashing(“awd”, “hello”) +ht.put_double_hashing(“addition”, “ok”) +for key in (“good”, “better”, “best”, “worst”, “ad”, “ga”): +v = ht.get_double_hashing(key) +print(v) +print(“The number of elements is: {}”.format(ht.count)) + + +ht = HashTable() +ht["good"] = "eggs" +ht["better"] = "ham" +ht["best"] = "spam" +ht["ad"] = "do not" +ht["ga"] = "collide" +ht["data"] = "value" + +for key in ("good", "better", "best", "worst", "ad", "ga"): + v = ht[key] + print(v) + +print("The number of elements is: {}".format(ht.count)) diff --git a/Chapter08/hashtable_chaining.py b/Chapter08/hashtable_chaining.py new file mode 100644 index 0000000..0f0d006 --- /dev/null +++ b/Chapter08/hashtable_chaining.py @@ -0,0 +1,102 @@ +class HashItem: + def __init__(self, key, value): + self.key = key + self.value = value + +class Node: + def __init__(self, key=None, value=None): + self.key = key + self.value = value + self.next = None + + +class SinglyLinkedList: + def __init__ (self): + self.tail = None + self.head = None + + def append(self, key, value): + node = Node(key, value) + if self.tail: + self.tail.next = node + self.tail = node + else: + self.head = node + self.tail = node + + def traverse(self): + current = self.head + while current: + print("\"", current.key, "--", current.value, "\"") + current = current.next + + def search(self, key): + current = self.head + while current: + if current.key == key: + print("\"Record found:", current.key, "-", current.value, "\"") + return True + current = current.next + return False + + + +class HashTableChaining: + def __init__(self): + self.size = 6 + self.slots = [None for i in range(self.size)] + for x in range(self.size) : + self.slots[x] = SinglyLinkedList() + + + def _hash(self, key): + mult = 1 + hv = 0 + for ch in key: + hv += mult * ord(ch) + mult += 1 + return hv % self.size + + def put(self, key, value): + #self.resize() + node = Node(key, value) + h = self._hash(key) + self.slots[h].append(key, value) + + + def get(self, key): + h = self._hash(key) + v = self.slots[h].search(key) + + + def printHashTable(self) : + print("Hash table is :- \n") + print("Index \t\tValues\n") + for x in range(self.size) : + print(x,end="\t\n") + self.slots[x].traverse() + + + + +ht = HashTableChaining() +ht.put("good", "eggs") +ht.put("better", "ham") +ht.put("best", "spam") +ht.put("ad", "do not") +ht.put("ga", "collide") +ht.put("awd", "do not") + + + + +v = ht.get("ad") +print(v) + + +for key in ("good", "better", "best", "worst", "ad", "ga"): + v = ht.get(key) + print(v) + + +ht.printHashTable() diff --git a/Chapter09/breadth_first_search.py b/Chapter09/breadth_first_search.py new file mode 100644 index 0000000..28165c9 --- /dev/null +++ b/Chapter09/breadth_first_search.py @@ -0,0 +1,33 @@ +graph = dict() +graph['A'] = ['B', 'G', 'D'] +graph['B'] = ['A', 'F', 'E'] +graph['C'] = ['F', 'H'] +graph['D'] = ['F', 'A'] +graph['E'] = ['B', 'G'] +graph['F'] = ['B', 'D', 'C'] +graph['G'] = ['A', 'E'] +graph['H'] = ['C'] + + +from collections import deque + +def breadth_first_search(graph, root): + visited_vertices = list() + graph_queue = deque([root]) + visited_vertices.append(root) + node = root + + while len(graph_queue) > 0: + node = graph_queue.popleft() + adj_nodes = graph[node] + + remaining_elements = set(adj_nodes).difference(set(visited_vertices)) + if len(remaining_elements) > 0: + for elem in sorted(remaining_elements): + visited_vertices.append(elem) + graph_queue.append(elem) + + return visited_vertices + + +print(breadth_first_search(graph, 'A')) diff --git a/Chapter09/depth_first_search.py b/Chapter09/depth_first_search.py new file mode 100644 index 0000000..1894b2a --- /dev/null +++ b/Chapter09/depth_first_search.py @@ -0,0 +1,36 @@ +graph = dict() +graph['A'] = ['B', 'S'] +graph['B'] = ['A'] +graph['S'] = ['A','G','C'] +graph['D'] = ['C'] +graph['G'] = ['S','F','H'] +graph['H'] = ['G','E'] +graph['E'] = ['C','H'] +graph['F'] = ['C','G'] +graph['C'] = ['D','S','E','F'] + +def depth_first_search(graph, root): + visited_vertices = list() + graph_stack = list() + graph_stack.append(root) + node = root + while graph_stack: + if node not in visited_vertices: + visited_vertices.append(node) + adj_nodes = graph[node] + if set(adj_nodes).issubset(set(visited_vertices)): + graph_stack.pop() + if len(graph_stack) > 0: + node = graph_stack[-1] + continue + else: + remaining_elements = set(adj_nodes).difference(set(visited_vertices)) + + first_adj_node = sorted(remaining_elements)[0] + graph_stack.append(first_adj_node) + node = first_adj_node + return visited_vertices + + + +print(depth_first_search(graph, 'A')) diff --git a/Chapter09/graph.py b/Chapter09/graph.py new file mode 100644 index 0000000..58cc88b --- /dev/null +++ b/Chapter09/graph.py @@ -0,0 +1,31 @@ +graph = dict() +graph['A'] = ['B', 'C'] +graph['B'] = ['E','C', 'A'] +graph['C'] = ['A', 'B', 'E','F'] +graph['E'] = ['B', 'C'] +graph['F'] = ['C'] + +matrix_elements = sorted(graph.keys()) +cols = rows = len(matrix_elements) + +adjacency_matrix = [[0 for x in range(rows)] for y in range(cols)] + +edges_list = [] + + +for key in matrix_elements: + for neighbor in graph[key]: + edges_list.append((key,neighbor)) + + +print(edges_list) + + + +for edge in edges_list: + index_of_first_vertex = matrix_elements.index(edge[0]) + index_of_second_vertex = matrix_elements.index(edge[1]) + adjacency_matrix[index_of_first_vertex][index_of_second_vertex] = 1 + + +print(adjacency_matrix) diff --git a/Chapter10/.DS_Store b/Chapter10/.DS_Store new file mode 100644 index 0000000..eb64c3e Binary files /dev/null and b/Chapter10/.DS_Store differ diff --git a/Chapter10/Unordered_linear_search.py b/Chapter10/Unordered_linear_search.py new file mode 100644 index 0000000..0d400b4 --- /dev/null +++ b/Chapter10/Unordered_linear_search.py @@ -0,0 +1,33 @@ + +def search(unordered_list, term): + for i, item in enumerate(unordered_list): + if term == unordered_list[i]: + return i + return None + + + +list1 = [60, 1, 88, 10, 11, 600] + +search_term = 10 +index_position = search(list1, search_term) +print(index_position) + + + +list2 = ['packt', 'publish', 'data'] +search_term2 = 'data' +index_position2 = search(list2, search_term2) +print(index_position2) + + +if index_position is None: + print("{} not found".format(search_term)) +else: + print("{} found at position {}".format(search_term, index_position)) + + +if index_position2 is None: + print("{} not found".format(search_term2)) +else: + print("{} found at position {}".format(search_term2, index_position2)) diff --git a/Chapter10/binary_search_iterative.py b/Chapter10/binary_search_iterative.py new file mode 100644 index 0000000..c20a523 --- /dev/null +++ b/Chapter10/binary_search_iterative.py @@ -0,0 +1,44 @@ +def binary_search_iterative(ordered_list, term): + + size_of_list = len(ordered_list) - 1 + index_of_first_element = 0 + index_of_last_element = size_of_list + while index_of_first_element <= index_of_last_element: + mid_point = (index_of_first_element + index_of_last_element)/2 + if ordered_list[mid_point] == term: + return mid_point + if term > ordered_list[mid_point]: + index_of_first_element = mid_point + 1 + else: + index_of_last_element = mid_point - 1 + if index_of_first_element > index_of_last_element: + return None + +store = [1, 4, 5, 12, 43, 54, 60, 77] +a = binary_search_iterative(store, 2) +print("Index position of value 2 is", a) + + +print(binary_search_iterative(store, 7)) + +print(binary_search_iterative(store, 60)) + + +list1 = [10, 30, 100, 120, 500] + +search_term = 10 +index_position1 = binary_search_iterative(list1, search_term) +if index_position1 is None: + print("The data item {} is not found".format(search_term)) +else: + print("The data item {} is found at position {}".format(search_term, index_position1)) + + +list2 = ['book','data','packt', 'structure'] + +search_term2 = 'structure' +index_position2 = binary_search_iterative(list2, search_term2) +if index_position2 is None: + print("The data item {} is not found".format(search_term2)) +else: + print("The data item {} is found at position {}".format(search_term2, index_position2)) diff --git a/Chapter10/binary_search_recursive.py b/Chapter10/binary_search_recursive.py new file mode 100644 index 0000000..8e6d7b2 --- /dev/null +++ b/Chapter10/binary_search_recursive.py @@ -0,0 +1,36 @@ +def binary_search_recursive(ordered_list, first_element_index, last_element_index, term): + if (last_element_index < first_element_index): + return None + else: + mid_point = first_element_index + ((last_element_index - first_element_index) // 2) + + if ordered_list[mid_point] > term: + return binary_search_recursive(ordered_list, first_element_index, mid_point-1,term) + elif ordered_list[mid_point] < term: + return binary_search_recursive(ordered_list, mid_point+1, last_element_index, term) + else: + return mid_point + + + + + + +list1 = [10, 30, 100, 120, 500] + +search_term = 10 +index_position1 = binary_search_recursive(list1, 0, len(list1)-1, search_term) +if index_position1 is None: + print("The data item {} is not found".format(search_term)) +else: + print("The data item {} is found at position {}".format(search_term, index_position1)) + + +list2 = ['book','data','packt', 'structure'] + +search_term2 = 'data' +index_position2 = binary_search_recursive(list2, 0, len(list1)-1, search_term2) +if index_position2 is None: + print("The data item {} is not found".format(search_term2)) +else: + print("The data item {} is found at position {}".format(search_term2, index_position2)) diff --git a/Chapter10/exponential_search.py b/Chapter10/exponential_search.py new file mode 100644 index 0000000..da87ab8 --- /dev/null +++ b/Chapter10/exponential_search.py @@ -0,0 +1,28 @@ +def binary_search_recursive(ordered_list, first_element_index, last_element_index, term): + if (last_element_index < first_element_index): + return None + else: + mid_point = first_element_index + ((last_element_index - first_element_index) // 2) + if ordered_list[mid_point] > term: + return binary_search_recursive (ordered_list, first_element_index, mid_point-1, term) + elif ordered_list[mid_point] < term: + return binary_search_recursive (ordered_list, mid_point+1, last_element_index, term) + else: + return mid_point + + + + + +def exponential_search(A, search_value): + if (A[0] == search_value): + return 0 + index = 1 + while index < len(A) and A[index] < search_value: + index *= 2 + return binary_search_recursive(A, index // 2, min(index, len(A) - 1), search_value) + + + + +print(exponential_search([1,2,3,4,5,6,7,8,9,10,11,12,34,40],34)) diff --git a/Chapter10/interpolation_search.py b/Chapter10/interpolation_search.py new file mode 100644 index 0000000..16b80f8 --- /dev/null +++ b/Chapter10/interpolation_search.py @@ -0,0 +1,29 @@ + +def nearest_mid(input_list, low_index, upper_index, search_value): + mid = low_index + (( upper_index - low_index)/(input_list[upper_index] - input_list[low_index])) * (search_value - input_list[low_index]) + return int(mid) + + +def interpolation_search(ordered_list, search_value): + low_index = 0 + upper_index = len(ordered_list) - 1 + while low_index <= upper_index: + mid_point = nearest_mid(ordered_list, low_index, upper_index, search_value) + if mid_point > upper_index or mid_point < low_index: + return None + if ordered_list[mid_point] == search_value: + return mid_point + if search_value > ordered_list[mid_point]: + low_index = mid_point + 1 + else: + upper_index = mid_point - 1 + if low_index > upper_index: + return None + + + +list1 = [44, 60, 75, 100, 120, 230, 250] +a = interpolation_search(list1, 120) +print("Index position of value 2 is ", a) + +print(nearest_mid(list1, 0, 6, 120)) diff --git a/Chapter10/jump_search.py b/Chapter10/jump_search.py new file mode 100644 index 0000000..3393126 --- /dev/null +++ b/Chapter10/jump_search.py @@ -0,0 +1,43 @@ +def search_ordered(ordered_list, term): + print("Entering Linear Search") + ordered_list_size = len(ordered_list) + for i in range(ordered_list_size): + if term == ordered_list[i]: + return i + elif ordered_list[i] > term: + return -1 + return -1 + + + +def jump_search(ordered_list, item): + import math + print("Entering Jump Search") + list_size = len(ordered_list) + block_size = int(math.sqrt(list_size)) + i = 0 + while i != len(ordered_list)-1 and ordered_list[i] <= item: + print("Block under consideration - {}".format(ordered_list[i: i+block_size])) + if i+ block_size > len(ordered_list): + block_size = len(ordered_list) - i + block_list = ordered_list[i: i+block_size] + j = search_ordered(block_list, item) + if j == -1: + print("Element not found") + return + return i + j + if ordered_list[i + block_size -1] == item: + return i+block_size-1 + elif ordered_list[i + block_size - 1] > item: + block_array = ordered_list[i: i + block_size - 1] + j = search_ordered(block_array, item) + if j == -1: + print("Element not found") + return + return i + j + i += block_size + + + +print(jump_search([1,2,3,4,5,6,7,8,9, 10, 11], 8)) + diff --git a/Chapter10/search_ordered_list.py b/Chapter10/search_ordered_list.py new file mode 100644 index 0000000..ee829e0 --- /dev/null +++ b/Chapter10/search_ordered_list.py @@ -0,0 +1,33 @@ + +def search_ordered(ordered_list, term): + ordered_list_size = len(ordered_list) + for i in range(ordered_list_size): + if term == ordered_list[i]: + return i + elif ordered_list[i] > term: + return None + + return None + + + +list1 = [2, 3, 4, 6, 7] + +search_term = 6 +index_position1 = search_ordered(list1, search_term) + +if index_position1 is None: + print("{} not found".format(search_term)) +else: + print("{} found at position {}".format(search_term, index_position1)) + + + +list2 = ['book','data','packt', 'structure'] + +search_term2 = 'structure' +index_position2 = search_ordered(list2, search_term2) +if index_position2 is None: + print("{} not found".format(search_term2)) +else: + print("{} found at position {}".format(search_term2, index_position2)) diff --git a/Chapter11/.DS_Store b/Chapter11/.DS_Store new file mode 100644 index 0000000..7bdd748 Binary files /dev/null and b/Chapter11/.DS_Store differ diff --git a/Chapter11/Insertion_sort.py b/Chapter11/Insertion_sort.py new file mode 100644 index 0000000..b4b1305 --- /dev/null +++ b/Chapter11/Insertion_sort.py @@ -0,0 +1,19 @@ + +def insertion_sort(unsorted_list): + for index in range(1, len(unsorted_list)): + search_index = index + insert_value = unsorted_list[index] + while search_index > 0 and unsorted_list[search_index-1] > insert_value : + unsorted_list[search_index] = unsorted_list[search_index-1] + search_index -= 1 + unsorted_list[search_index] = insert_value + + + + + + +my_list = [5, 1, 100, 2, 10] +print("Original ist", my_list) +insertion_sort(my_list) +print("Sorted list", my_list) diff --git a/Chapter11/Quick_sort.py b/Chapter11/Quick_sort.py new file mode 100644 index 0000000..96efa57 --- /dev/null +++ b/Chapter11/Quick_sort.py @@ -0,0 +1,35 @@ +def partition(unsorted_array, first_index, last_index): + pivot = unsorted_array[first_index] + pivot_index = first_index + index_of_last_element = last_index + less_than_pivot_index = index_of_last_element + greater_than_pivot_index = first_index + 1 + while True: + while unsorted_array[greater_than_pivot_index] < pivot and greater_than_pivot_index < last_index: + greater_than_pivot_index += 1 + while unsorted_array[less_than_pivot_index] > pivot and less_than_pivot_index >= first_index: + less_than_pivot_index -= 1 + if greater_than_pivot_index < less_than_pivot_index: + temp = unsorted_array[greater_than_pivot_index] + unsorted_array[greater_than_pivot_index] = unsorted_array[less_than_pivot_index] + unsorted_array[less_than_pivot_index] = temp + else: + break + unsorted_array[pivot_index] = unsorted_array[less_than_pivot_index] + unsorted_array[less_than_pivot_index] = pivot + return less_than_pivot_index + + +def quick_sort(unsorted_array, first, last): + if last - first <= 0: + return + else: + partition_point = partition(unsorted_array, first, last) + quick_sort(unsorted_array, first, partition_point-1) + quick_sort(unsorted_array, partition_point+1, last) + + +my_array = [43, 3, 77, 89, 4, 20] +print(my_array) +quick_sort(my_array, 0, 5) +print(my_array) diff --git a/Chapter11/Selection_Sort.py b/Chapter11/Selection_Sort.py new file mode 100644 index 0000000..fae399b --- /dev/null +++ b/Chapter11/Selection_Sort.py @@ -0,0 +1,21 @@ +def selection_sort(unsorted_list): + size_of_list = len(unsorted_list) + for i in range(size_of_list): + small = i + for j in range(i+1, size_of_list): + if unsorted_list[j] < unsorted_list[small]: + small = j + temp = unsorted_list[i] + unsorted_list[i] = unsorted_list[small] + unsorted_list[small] = temp + + + + +a_list = [3, 2, 35, 4, 32, 94, 5, 7] + +print("List before sorting", a_list) + +selection_sort(a_list) + +print("List after sorting", a_list) diff --git a/Chapter11/Tim_sort.py b/Chapter11/Tim_sort.py new file mode 100644 index 0000000..f42cfb8 --- /dev/null +++ b/Chapter11/Tim_sort.py @@ -0,0 +1,48 @@ +def Insertion_Sort(unsorted_list): + for index in range(1, len(unsorted_list)): + search_index = index + insert_value = unsorted_list[index] + while search_index > 0 and unsorted_list[search_index-1] > insert_value : + unsorted_list[search_index] = unsorted_list[search_index-1] + search_index -= 1 + unsorted_list[search_index] = insert_value + return unsorted_list + + + +def Merge(first_sublist, second_sublist): + i = j = 0 + merged_list = [] + while i < len(first_sublist) and j < len(second_sublist): + if first_sublist[i] < second_sublist[j]: + merged_list.append(first_sublist[i]) + i += 1 + else: + merged_list.append(second_sublist[j]) + j += 1 + while i < len(first_sublist): + merged_list.append(first_sublist[i]) + i += 1 + while j < len(second_sublist): + merged_list.append(second_sublist[j]) + j += 1 + return merged_list + + +def Tim_Sort(arr, run): + for x in range(0, len(arr), run): + arr[x : x + run] = Insertion_Sort(arr[x : x + run]) + runSize = run + + while runSize < len(arr): + for x in range(0, len(arr), 2 * runSize): + arr[x : x + 2 * runSize] = Merge(arr[x : x + runSize], arr[x + runSize: x + 2 * runSize]) + + runSize = runSize * 2 + +arr = [4, 6, 3, 9, 2, 8, 7, 5] +run = 2 + + +Tim_Sort(arr, run) +print(arr) diff --git a/Chapter11/bubble_sort.py b/Chapter11/bubble_sort.py new file mode 100644 index 0000000..58e2f81 --- /dev/null +++ b/Chapter11/bubble_sort.py @@ -0,0 +1,29 @@ +unordered_list = [5, 2] + +temp = unordered_list[0] +unordered_list[0] = unordered_list[1] +unordered_list[1] = temp + +print(unordered_list) + + + +def bubble_sort(unordered_list): + iteration_number = len(unordered_list)-1 + for i in range(iteration_number,0,-1): + for j in range(i): + if unordered_list[j] > unordered_list[j+1]: + temp = unordered_list[j] + unordered_list[j] = unordered_list[j+1] + unordered_list[j+1] = temp + + + + +my_list = [4,3,2,1] +bubble_sort(my_list) +print(my_list) + +my_list = [1,12,3,4] +bubble_sort(my_list) +print(my_list) diff --git a/Chapter12/.DS_Store b/Chapter12/.DS_Store new file mode 100644 index 0000000..af1f624 Binary files /dev/null and b/Chapter12/.DS_Store differ diff --git a/Chapter12/deterministic_selection.py b/Chapter12/deterministic_selection.py new file mode 100644 index 0000000..0d5336d --- /dev/null +++ b/Chapter12/deterministic_selection.py @@ -0,0 +1,85 @@ +def partition(unsorted_array, first_index, last_index): + if first_index == last_index: + return first_index + else: + nearest_median = median_of_medians(unsorted_array[first_index:last_index]) + + index_of_nearest_median = get_index_of_nearest_median(unsorted_array, first_index, + last_index, nearest_median) + swap(unsorted_array, first_index, index_of_nearest_median) + + pivot = unsorted_array[first_index] + pivot_index = first_index + index_of_last_element = last_index + less_than_pivot_index = index_of_last_element + greater_than_pivot_index = first_index + 1 + + ## This while loop is used to correctly place pivot element at its correct position + while 1: + while unsorted_array[greater_than_pivot_index] < pivot and greater_than_pivot_index < last_index: + greater_than_pivot_index += 1 + while unsorted_array[less_than_pivot_index] > pivot and less_than_pivot_index >= first_index: + less_than_pivot_index -= 1 + + if greater_than_pivot_index < less_than_pivot_index: + temp = unsorted_array[greater_than_pivot_index] + unsorted_array[greater_than_pivot_index] = unsorted_array[less_than_pivot_index] + unsorted_array[less_than_pivot_index] = temp + else: + break + + unsorted_array[pivot_index]=unsorted_array[less_than_pivot_index] + unsorted_array[less_than_pivot_index]=pivot + return less_than_pivot_index + + +def median_of_medians(elems): + + sublists = [elems[j:j+5] for j in range(0, len(elems), 5)] + medians = [] + for sublist in sublists: + medians.append(sorted(sublist)[int(len(sublist)/2)]) + + if len(medians) <= 5: + return sorted(medians)[int(len(medians)/2)] + else: + return median_of_medians(medians) + + + +def get_index_of_nearest_median(array_list, first, second, median): + if first == second: + return first + else: + return first + array_list[first:second].index(median) + + + + +def swap(array_list, first, index_of_nearest_median): + temp = array_list[first] + array_list[first] = array_list[index_of_nearest_median] + array_list[index_of_nearest_median] = temp + + + + +def deterministic_select(array_list, left, right, k): + + split = partition(array_list, left, right) + if split == k: + return array_list[split] + elif split < k: + return deterministic_select(array_list, split + 1, right, k) + else: + return deterministic_select(array_list, left, split-1, k) + + + + +stored = [3,1,10,4,6, 5] +print(deterministic_select(stored, 0, 5, 2)) + + + + diff --git a/Chapter12/randomized_search.py b/Chapter12/randomized_search.py new file mode 100644 index 0000000..a8bf324 --- /dev/null +++ b/Chapter12/randomized_search.py @@ -0,0 +1,63 @@ +def partition(unsorted_array, first_index, last_index): + + pivot = unsorted_array[first_index] + pivot_index = first_index + index_of_last_element = last_index + + less_than_pivot_index = index_of_last_element + greater_than_pivot_index = first_index + 1 + + while True: + + while unsorted_array[greater_than_pivot_index] < pivot and greater_than_pivot_index < last_index: + greater_than_pivot_index += 1 + while unsorted_array[less_than_pivot_index] > pivot and less_than_pivot_index >= first_index: + less_than_pivot_index -= 1 + + if greater_than_pivot_index < less_than_pivot_index: + temp = unsorted_array[greater_than_pivot_index] + unsorted_array[greater_than_pivot_index] = unsorted_array[less_than_pivot_index] + unsorted_array[less_than_pivot_index] = temp + else: + break + + unsorted_array[pivot_index] = unsorted_array[less_than_pivot_index] + unsorted_array[less_than_pivot_index] = pivot + + return less_than_pivot_index + + +def quick_select(array_list, start, end, k): + split = partition(array_list, start, end) + if split == k: + return array_list[split] + elif split < k: + return quick_select(array_list, split + 1, end, k) + else: + return quick_select(array_list, start, split-1, k) + + + + +list1 = [3,1,10, 4, 6, 5] + +print("The 2nd smallest element is", quick_select(list1, 0, 5, 1)) + +print("The 3nd smallest element is", quick_select(list1, 0, 5, 2)) + + + + +stored = [3,1,10,4,6,5] +print(stored) +print(quick_select(stored, 0, 5, 0)) +stored = [3,1,10,4,6, 5] +print(quick_select(stored, 0, 5, 1)) +stored = [3,1,10,4,6, 5] +print(quick_select(stored, 0, 5, 2)) +stored = [3,1,10,4,6, 5] +print(quick_select(stored, 0, 5, 3)) +stored = [3,1,10,4,6, 5] +print(quick_select(stored, 0, 5, 4)) +stored = [3,1,10,4,6, 5] +print(quick_select(stored, 0, 5, 5)) diff --git a/Chapter13/.DS_Store b/Chapter13/.DS_Store new file mode 100644 index 0000000..a8320f1 Binary files /dev/null and b/Chapter13/.DS_Store differ diff --git a/Chapter13/Boyer_Moore_String_Matching.py b/Chapter13/Boyer_Moore_String_Matching.py new file mode 100644 index 0000000..a25803b --- /dev/null +++ b/Chapter13/Boyer_Moore_String_Matching.py @@ -0,0 +1,46 @@ +text = "acbaacacababacacac" +pattern = "acacac" + + +matched_indexes = [] + +i=0 +flag = True +while i<=len(text)-len(pattern): + for j in range(len(pattern)-1, -1, -1): #reverse searching + if pattern[j] != text[i+j]: + flag = False #indicates there is a mismatch + if j == len(pattern)-1: #if good-suffix is not present, we test bad character + if text[i+j] in pattern[0:j]: + i=i+j-pattern[0:j].rfind(text[i+j]) + #i+j is index of bad character, this line is used for jumping pattern to match + #bad character of text with same character in pattern + else: + i=i+j+1 #if bad character is not present, jump pattern next to it + else: + k=1 + while text[i+j+k:i+len(pattern)] not in pattern[0:len(pattern)-1]: + #used for finding sub part of a good-suffix + k=k+1 + if len(text[i+j+k:i+len(pattern)]) != 1: #good-suffix should not be of one character + gsshift=i+j+k-pattern[0:len(pattern)-1].rfind(text[i+j+k:i+len(pattern)]) + #jumps pattern to a position where good-suffix of pattern matches with good-suffix of text + else: + #gsshift=i+len(pattern) + gsshift=0 #when good-suffix heuristic is not applicable, + #we prefer bad character heuristic + if text[i+j] in pattern[0:j]: + bcshift=i+j-pattern[0:j].rfind(text[i+j]) + #i+j is index of bad character, this line is used for jumping pattern to match bad character + #of text with same character in pattern + else: + bcshift=i+j+1 + i=max((bcshift, gsshift)) + break + if flag: #if pattern is found then normal iteration + matched_indexes.append(i) + i = i+1 + else: #again set flag to True so new string in text can be examined + flag = True + +print ("Pattern found at", matched_indexes) diff --git a/Chapter13/Brute_force_string_matching.py b/Chapter13/Brute_force_string_matching.py new file mode 100644 index 0000000..bc614e5 --- /dev/null +++ b/Chapter13/Brute_force_string_matching.py @@ -0,0 +1,27 @@ +def brute_force(text, pattern): + l1 = len(text) # The length of the text string + l2 = len(pattern) # The length of the pattern + i = 0 + j = 0 # looping variables are set to 0 + flag = False # If the pattern doesn't appear at all, then set this to false and execute the last if statement + while i < l1: # iterating from the 0th index of text + j = 0 + count = 0 + # Count stores the length upto which the pattern and the text have matched + while j < l2: + if i+j < l1 and text[i+j] == pattern[j]: + # statement to check if a match has occurred or not + count += 1 # Count is incremented if a character is matched + j += 1 + if count == l2: # it shows a matching of pattern in the text + print("\nPattern occurs at index", i) + # print the starting index of the successful match + flag = True + # flag is True as we wish to continue looking for more matching of pattern in the text. + i += 1 + if not flag: + # If the pattern doesn't occurs at all, means no match of pattern in the text string + print('\nPattern is not at all present in the array') + + +brute_force('acbcabccababcaacbcac','acbcac') # function call diff --git a/Chapter13/KMP.py b/Chapter13/KMP.py new file mode 100644 index 0000000..26ec373 --- /dev/null +++ b/Chapter13/KMP.py @@ -0,0 +1,35 @@ +def pfun(pattern): # function to generate prefix function for the given pattern + n = len(pattern) # length of the pattern + prefix_fun = [0]*(n) # initialize all elements of the list to 0 + k = 0 + for q in range(2,n): + while k>0 and pattern[k+1] != pattern[q]: + k = prefix_fun[k] + if pattern[k+1] == pattern[q]: # If the kth element of the pattern is equal to the qth element + k += 1 # update k accordingly + prefix_fun[q] = k + return prefix_fun # return the prefix function + + +def KMP_Matcher(text,pattern): # KMP matcher function + m = len(text) + n = len(pattern) + flag = False + text = '-' + text # append dummy character to make it 1-based indexing + pattern = '-' + pattern # append dummy character to the pattern also + prefix_fun = pfun(pattern) # generate prefix function for the pattern + q = 0 + for i in range(1,m+1): + while q>0 and pattern[q+1] != text[i]: # while pattern and text are not equal, decrement the value of q if it is > 0 + q = prefix_fun[q] + if pattern[q+1] == text[i]: # if pattern and text are equal, update value of q + q += 1 + if q == n: # if q is equal to the length of the pattern, it means that the pattern has been found. + print("Pattern occours with shift",i-n) # print the index, where first match occours. + flag = True + q = prefix_fun[q] + if not flag: + print('\nNo match found') + + +KMP_Matcher('aabaacaadaabaaba','aabaa') # function call, with two parameters,text and pattern diff --git a/Chapter13/Rabin_Karp_String_Matching.py b/Chapter13/Rabin_Karp_String_Matching.py new file mode 100644 index 0000000..dda066f --- /dev/null +++ b/Chapter13/Rabin_Karp_String_Matching.py @@ -0,0 +1,46 @@ +def generate_hash(text, pattern): + ord_text = [ord(i) for i in text] # stores unicode value of each character in text + ord_pattern = [ord(j) for j in pattern] # stores unicode value of each character in pattern + len_text = len(text) # stores length of the text + len_pattern = len(pattern) # stores length of the pattern + len_hash_array = len_text - len_pattern + 1 # stores the length of new array that will contain the hash values of text + hash_text = [0]*(len_hash_array) # Initialize all the values in the array to 0. + hash_pattern = sum(ord_pattern) + for i in range(0,len_hash_array): # step size of the loop will be the size of the pattern + if i == 0: # Base condition + hash_text[i] = sum(ord_text[:len_pattern]) # initial value of hash function + else: + hash_text[i] = ((hash_text[i-1] - ord_text[i-1]) + ord_text[i+len_pattern-1]) # calculating next hash value using previous value + return [hash_text, hash_pattern] # return the hash values + + + +def Rabin_Karp_Matcher(text, pattern): + text = str(text) # convert text into string format + pattern = str(pattern) # convert pattern into string format + hash_text, hash_pattern = generate_hash(text, pattern) # generate hash values using generate_hash function + len_text = len(text) # length of text + len_pattern = len(pattern) # length of pattern + flag = False # checks if pattern is present atleast once or not at all + for i in range(len(hash_text)): + if hash_text[i] == hash_pattern: # if the hash value matches + count = 0 # count stores the total characters upto which both are similar + for j in range(len_pattern): + if pattern[j] == text[i+j]: # checking equality for each character + count += 1 # if value is equal, then update the count value + else: + break + if count == len_pattern: # if count is equal to length of pattern, it means match has been found + flag = True # update flag accordingly + print('Pattern occours at index',i) + if not flag: # if pattern doesn't match even once, then this if statement is executed + print('Pattern is not at all present in the text') + + +Rabin_Karp_Matcher("101110000011010010101101","10112") + +# Works for numeric +Rabin_Karp_Matcher("101110000011010010101101","1011") + +# Works for alphabets +Rabin_Karp_Matcher("ABBACCADABBACCEDF","ACCE") diff --git a/Chapter13/example_suffix_prefix.py b/Chapter13/example_suffix_prefix.py new file mode 100644 index 0000000..42d2741 --- /dev/null +++ b/Chapter13/example_suffix_prefix.py @@ -0,0 +1,6 @@ +string = "this is data structures book by packt publisher" +suffix = "publisher" +prefix = "this" +print(string.endswith(suffix)) #Check if string contains given suffix. + +print(string.startswith(prefix)) #Check if string starts with given prefix. diff --git a/README.md b/README.md index 138e58f..94bd315 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,9 @@ -# Data-Structures-and-Algorithms-with-Python-Third-Edition-published-by-Packt -Data Structures and Algorithms with Python – Third Edition + + + +# Hands-On Data-Structures-and-Algorithms-with-Python-Third-Edition-published-by-Packt +Hands-On Data Structures and Algorithms with Python – Third Edition +### Download a free PDF + + If you have already purchased a print or Kindle version of this book, you can get a DRM-free PDF version at no cost.
Simply click on the link to claim your free PDF.
+

https://packt.link/free-ebook/9781801073448

\ No newline at end of file diff --git a/errata.md b/errata.md new file mode 100644 index 0000000..9cc9cd7 --- /dev/null +++ b/errata.md @@ -0,0 +1,52 @@ +# Errata, Corrections and Improvements +---------------------------------------------------- +If you find any mistakes in the third edition of Hands On Data Structures and Algorithms with Python book, or if you have suggestions for improvements, then please [raise an issue in this repository]([https://github.com/PacktPublishing/JavaScript-from-Beginner-to-Professional/issues](https://github.com/PacktPublishing/Hands-On-Data-Structures-and-Algorithms-with-Python-Third-Edition/issues)), or email to us. + +## Chapter 13, Page 403 - Fixing the reference to `ord` array + +There should be a reference calling to the `ord` array as `ord_text` in the `generate_hash` function. + +Incorrect code is: +``` +else: + hash_text[i] = ((hash_text[i-1] - ord_text[i-1]) + ord[i+len_pattern-1]) # calculating next hash value using previous value +``` +Correct code is: +``` +else: + hash_text[i] = ((hash_text[i-1] - ord_text[i-1]) + ord_text[i+len_pattern-1]) # calculating next hash value using previous value +``` + +## Chapter 3, Page 61 - Fixed the missing '/' in `binary search` code + +There should be `//` in place of `/` + +Incorrect code is: +```python +mid = start + (end - start)/2 +if arr[mid] == key: + return mid +``` +Correct code is: +```python +mid = start + (end - start)//2 +if arr[mid] == key: + return mid +``` + + +## Chapter 1, Page 23 - Fixed the missing outputs + +This is the actual dictionary +`mydict = {'a': 1, 'b': 2, 'c': 3}` + +|Function |Description |Example| +| :-------:| :-------: | :-------: | +| `mydict.pop()`| If a given key is present in the dictionary, then this function will remove the key and return the associated value. | `print(mydict.pop('b'))` should give you output `2` | +| `| | `print(mydict)` should give you output `{'a': 1, 'c': 3}` | +| `mydict.popitem()`| This method removes the last key-value pair added in the dictionary and returns it as a tuple. | `print(mydict.popitem())` should give you output `('c', 3)` | +| `| | `print(mydict)` should give you output `{'a': 1, 'b': 2}` | +| `mydict.update()`| Merges one dictionary with another. Firstly, it checks whether a key of the second dictionary is present in the fi rst dictionary; the corresponding value is then updated. If the key is not present in the fi rst dictionary, then the key-value pair is added. | It has two dictionaries as `d1 = {'a': 10, 'b': 20, 'c': 30}` and `d2 = {'b': 200, 'd': 400}`| +| | | `d1.update(d2)` should update values of `d2` on `d1` | +| | | `print(d1)` should give you `{'a': 10, 'b': 200, 'c': 30, 'd': 400}` | +