diff --git a/data_structures/Graph/Graph.py b/data_structures/Graph/Graph.py new file mode 100644 index 000000000..0fa3f5593 --- /dev/null +++ b/data_structures/Graph/Graph.py @@ -0,0 +1,40 @@ +# Author: OMKAR PATHAK + +# We can use Python's dictionary for constructing the graph + +class AdjacencyList(object): + def __init__(self): + self.List = {} + + def addEdge(self, fromVertex, toVertex): + # check if vertex is already present + if fromVertex in self.List.keys(): + self.List[fromVertex].append(toVertex) + else: + self.List[fromVertex] = [toVertex] + + def printList(self): + for i in self.List: + print(i,'->',' -> '.join([str(j) for j in self.List[i]])) + +if __name__ == '__main__': + al = AdjacencyList() + al.addEdge(0, 1) + al.addEdge(0, 4) + al.addEdge(4, 1) + al.addEdge(4, 3) + al.addEdge(1, 0) + al.addEdge(1, 4) + al.addEdge(1, 3) + al.addEdge(1, 2) + al.addEdge(2, 3) + al.addEdge(3, 4) + + al.printList() + + # OUTPUT: + # 0 -> 1 -> 4 + # 1 -> 0 -> 4 -> 3 -> 2 + # 2 -> 3 + # 3 -> 4 + # 4 -> 1 -> 3 diff --git a/data_structures/Graph/P01_BreadthFirstSearch.py b/data_structures/Graph/P01_BreadthFirstSearch.py new file mode 100644 index 000000000..16b1b2007 --- /dev/null +++ b/data_structures/Graph/P01_BreadthFirstSearch.py @@ -0,0 +1,61 @@ +# Author: OMKAR PATHAK + +class Graph(): + def __init__(self): + self.vertex = {} + + # for printing the Graph vertexes + def printGraph(self): + for i in self.vertex.keys(): + print(i,' -> ', ' -> '.join([str(j) for j in self.vertex[i]])) + + # for adding the edge beween two vertexes + def addEdge(self, fromVertex, toVertex): + # check if vertex is already present, + if fromVertex in self.vertex.keys(): + self.vertex[fromVertex].append(toVertex) + else: + # else make a new vertex + self.vertex[fromVertex] = [toVertex] + + def BFS(self, startVertex): + # Take a list for stoting already visited vertexes + visited = [False] * len(self.vertex) + + # create a list to store all the vertexes for BFS + queue = [] + + # mark the source node as visited and enqueue it + visited[startVertex] = True + queue.append(startVertex) + + while queue: + startVertex = queue.pop(0) + print(startVertex, end = ' ') + + # mark all adjacent nodes as visited and print them + for i in self.vertex[startVertex]: + if visited[i] == False: + queue.append(i) + visited[i] = True + +if __name__ == '__main__': + g = Graph() + g.addEdge(0, 1) + g.addEdge(0, 2) + g.addEdge(1, 2) + g.addEdge(2, 0) + g.addEdge(2, 3) + g.addEdge(3, 3) + + g.printGraph() + print('BFS:') + g.BFS(2) + + # OUTPUT: + # 0  ->  1 -> 2 + # 1  ->  2 + # 2  ->  0 -> 3 + # 3  ->  3 + # BFS: + # 2 0 3 1 diff --git a/data_structures/Graph/P02_DepthFirstSearch.py b/data_structures/Graph/P02_DepthFirstSearch.py new file mode 100644 index 000000000..94ef3cb86 --- /dev/null +++ b/data_structures/Graph/P02_DepthFirstSearch.py @@ -0,0 +1,61 @@ +# Author: OMKAR PATHAK + +class Graph(): + def __init__(self): + self.vertex = {} + + # for printing the Graph vertexes + def printGraph(self): + print(self.vertex) + for i in self.vertex.keys(): + print(i,' -> ', ' -> '.join([str(j) for j in self.vertex[i]])) + + # for adding the edge beween two vertexes + def addEdge(self, fromVertex, toVertex): + # check if vertex is already present, + if fromVertex in self.vertex.keys(): + self.vertex[fromVertex].append(toVertex) + else: + # else make a new vertex + self.vertex[fromVertex] = [toVertex] + + def DFS(self): + # visited array for storing already visited nodes + visited = [False] * len(self.vertex) + + # call the recursive helper function + for i in range(len(self.vertex)): + if visited[i] == False: + self.DFSRec(i, visited) + + def DFSRec(self, startVertex, visited): + # mark start vertex as visited + visited[startVertex] = True + + print(startVertex, end = ' ') + + # Recur for all the vertexes that are adjacent to this node + for i in self.vertex.keys(): + if visited[i] == False: + self.DFSRec(i, visited) + +if __name__ == '__main__': + g = Graph() + g.addEdge(0, 1) + g.addEdge(0, 2) + g.addEdge(1, 2) + g.addEdge(2, 0) + g.addEdge(2, 3) + g.addEdge(3, 3) + + g.printGraph() + print('DFS:') + g.DFS() + + # OUTPUT: + # 0  ->  1 -> 2 + # 1  ->  2 + # 2  ->  0 -> 3 + # 3  ->  3 + # DFS: + # 0 1 2 3 diff --git a/data_structures/Stacks/Balanced_Parentheses.py b/data_structures/Stacks/Balanced_Parentheses.py new file mode 100644 index 000000000..6b7740380 --- /dev/null +++ b/data_structures/Stacks/Balanced_Parentheses.py @@ -0,0 +1,27 @@ +# Author: OMKAR PATHAK + +import Stack + +def parseParenthesis(string): + balanced = 1 + index = 0 + myStack = Stack.Stack(len(string)) + while (index < len(string)) and (balanced == 1): + check = string[index] + if check == '(': + myStack.push(check) + else: + if myStack.isEmpty(): + balanced = 0 + else: + myStack.pop() + index += 1 + + if balanced == 1 and myStack.isEmpty(): + return True + else: + return False + +if __name__ == '__main__': + print(parseParenthesis('((()))')) # True + print(parseParenthesis('((())')) # False diff --git a/data_structures/Stacks/Infix_To_Postfix_Conversion.py b/data_structures/Stacks/Infix_To_Postfix_Conversion.py new file mode 100644 index 000000000..e33926a3d --- /dev/null +++ b/data_structures/Stacks/Infix_To_Postfix_Conversion.py @@ -0,0 +1,48 @@ +# Author: OMKAR PATHAK + +import Stack + +def isOperand(char): + return (ord(char) >= ord('a') and ord(char) <= ord('z')) or (ord(char) >= ord('A') and ord(char) <= ord('Z')) + +def precedence(char): + if char == '+' or char == '-': + return 1 + elif char == '*' or char == '/': + return 2 + elif char == '^': + return 3 + else: + return -1 + +def infixToPostfix(myExp, myStack): + postFix = [] + for i in range(len(myExp)): + if (isOperand(myExp[i])): + postFix.append(myExp[i]) + elif(myExp[i] == '('): + myStack.push(myExp[i]) + elif(myExp[i] == ')'): + topOperator = myStack.pop() + while(not myStack.isEmpty() and topOperator != '('): + postFix.append(topOperator) + topOperator = myStack.pop() + else: + while (not myStack.isEmpty()) and (precedence(myExp[i]) <= precedence(myStack.peek())): + postFix.append(myStack.pop()) + myStack.push(myExp[i]) + + while(not myStack.isEmpty()): + postFix.append(myStack.pop()) + return ' '.join(postFix) + +if __name__ == '__main__': + myExp = 'a+b*(c^d-e)^(f+g*h)-i' + myExp = [i for i in myExp] + print('Infix:',' '.join(myExp)) + myStack = Stack.Stack(len(myExp)) + print('Postfix:',infixToPostfix(myExp, myStack)) + + # OUTPUT: + # Infix: a + b * ( c ^ d - e ) ^ ( f + g * h ) - i + # Postfix: a b c d ^ e - f g h * + ^ * + i - diff --git a/data_structures/Stacks/Stack.py b/data_structures/Stacks/Stack.py new file mode 100644 index 000000000..41bbdc9d2 --- /dev/null +++ b/data_structures/Stacks/Stack.py @@ -0,0 +1,50 @@ +# Author: OMKAR PATHAK + +class Stack(object): + def __init__(self, limit = 10): + self.stack = [] + self.limit = limit + + # for printing the stack contents + def __str__(self): + return ' '.join([str(i) for i in self.stack]) + + # for pushing an element on to the stack + def push(self, data): + if len(self.stack) >= self.limit: + print('Stack Overflow') + else: + self.stack.append(data) + + # for popping the uppermost element + def pop(self): + if len(self.stack) <= 0: + return -1 + else: + return self.stack.pop() + + # for peeking the top-most element of the stack + def peek(self): + if len(self.stack) <= 0: + return -1 + else: + return self.stack[len(self.stack) - 1] + + # to check if stack is empty + def isEmpty(self): + return self.stack == [] + + # for checking the size of stack + def size(self): + return len(self.stack) + +if __name__ == '__main__': + myStack = Stack() + for i in range(10): + myStack.push(i) + print(myStack) + myStack.pop() # popping the top element + print(myStack) + myStack.peek() # printing the top element + myStack.isEmpty() + myStack.size() diff --git a/sorts/bucket_sort.py b/sorts/bucket_sort.py new file mode 100644 index 000000000..e378d65f4 --- /dev/null +++ b/sorts/bucket_sort.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python +# Author: OMKAR PATHAK +# This program will illustrate how to implement bucket sort algorithm + +# Wikipedia says: Bucket sort, or bin sort, is a sorting algorithm that works by distributing the +# elements of an array into a number of buckets. Each bucket is then sorted individually, either using +# a different sorting algorithm, or by recursively applying the bucket sorting algorithm. It is a +# distribution sort, and is a cousin of radix sort in the most to least significant digit flavour. +# Bucket sort is a generalization of pigeonhole sort. Bucket sort can be implemented with comparisons +# and therefore can also be considered a comparison sort algorithm. The computational complexity estimates +# involve the number of buckets. + +# Time Complexity of Solution: +# Best Case O(n); Average Case O(n); Worst Case O(n) + +from P26_InsertionSort import insertionSort +import math + +DEFAULT_BUCKET_SIZE = 5 + +def bucketSort(myList, bucketSize=DEFAULT_BUCKET_SIZE): + if(len(myList) == 0): + print('You don\'t have any elements in array!') + + minValue = myList[0] + maxValue = myList[0] + + # For finding minimum and maximum values + for i in range(0, len(myList)): + if myList[i] < minValue: + minValue = myList[i] + elif myList[i] > maxValue: + maxValue = myList[i] + + # Initialize buckets + bucketCount = math.floor((maxValue - minValue) / bucketSize) + 1 + buckets = [] + for i in range(0, bucketCount): + buckets.append([]) + + # For putting values in buckets + for i in range(0, len(myList)): + buckets[math.floor((myList[i] - minValue) / bucketSize)].append(myList[i]) + + # Sort buckets and place back into input array + sortedArray = [] + for i in range(0, len(buckets)): + insertionSort(buckets[i]) + for j in range(0, len(buckets[i])): + sortedArray.append(buckets[i][j]) + + return sortedArray + +if __name__ == '__main__': + sortedArray = bucketSort([12, 23, 4, 5, 3, 2, 12, 81, 56, 95]) + print(sortedArray)