diff --git a/Graphs/pagerank.py b/Graphs/pagerank.py new file mode 100644 index 000000000000..59f15a99e6b2 --- /dev/null +++ b/Graphs/pagerank.py @@ -0,0 +1,72 @@ +''' +Author: https://github.com/bhushan-borole +''' +''' +The input graph for the algorithm is: + + A B C +A 0 1 1 +B 0 0 1 +C 1 0 0 + +''' + +graph = [[0, 1, 1], + [0, 0, 1], + [1, 0, 0]] + + +class Node: + def __init__(self, name): + self.name = name + self.inbound = [] + self.outbound = [] + + def add_inbound(self, node): + self.inbound.append(node) + + def add_outbound(self, node): + self.outbound.append(node) + + def __repr__(self): + return 'Node {}: Inbound: {} ; Outbound: {}'.format(self.name, + self.inbound, + self.outbound) + + +def page_rank(nodes, limit=3, d=0.85): + ranks = {} + for node in nodes: + ranks[node.name] = 1 + + outbounds = {} + for node in nodes: + outbounds[node.name] = len(node.outbound) + + for i in range(limit): + print("======= Iteration {} =======".format(i+1)) + for j, node in enumerate(nodes): + ranks[node.name] = (1 - d) + d * sum([ ranks[ib]/outbounds[ib] for ib in node.inbound ]) + print(ranks) + + +def main(): + names = list(input('Enter Names of the Nodes: ').split()) + + nodes = [Node(name) for name in names] + + for ri, row in enumerate(graph): + for ci, col in enumerate(row): + if col == 1: + nodes[ci].add_inbound(names[ri]) + nodes[ri].add_outbound(names[ci]) + + print("======= Nodes =======") + for node in nodes: + print(node) + + page_rank(nodes) + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/README.md b/README.md index faebd313507a..9b61f1b63287 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ # The Algorithms - Python +[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.me/TheAlgorithms/100) + ### All algorithms implemented in Python (for education) diff --git a/compression/huffman.py b/compression/huffman.py new file mode 100644 index 000000000000..b6238b66e9fd --- /dev/null +++ b/compression/huffman.py @@ -0,0 +1,87 @@ +import sys + +class Letter: + def __init__(self, letter, freq): + self.letter = letter + self.freq = freq + self.bitstring = "" + + def __repr__(self): + return f'{self.letter}:{self.freq}' + + +class TreeNode: + def __init__(self, freq, left, right): + self.freq = freq + self.left = left + self.right = right + + +def parse_file(file_path): + """ + Read the file and build a dict of all letters and their + frequences, then convert the dict into a list of Letters. + """ + chars = {} + with open(file_path) as f: + while True: + c = f.read(1) + if not c: + break + chars[c] = chars[c] + 1 if c in chars.keys() else 1 + letters = [] + for char, freq in chars.items(): + letter = Letter(char, freq) + letters.append(letter) + letters.sort(key=lambda l: l.freq) + return letters + +def build_tree(letters): + """ + Run through the list of Letters and build the min heap + for the Huffman Tree. + """ + while len(letters) > 1: + left = letters.pop(0) + right = letters.pop(0) + total_freq = left.freq + right.freq + node = TreeNode(total_freq, left, right) + letters.append(node) + letters.sort(key=lambda l: l.freq) + return letters[0] + +def traverse_tree(root, bitstring): + """ + Recursively traverse the Huffman Tree to set each + Letter's bitstring, and return the list of Letters + """ + if type(root) is Letter: + root.bitstring = bitstring + return [root] + letters = [] + letters += traverse_tree(root.left, bitstring + "0") + letters += traverse_tree(root.right, bitstring + "1") + return letters + +def huffman(file_path): + """ + Parse the file, build the tree, then run through the file + again, using the list of Letters to find and print out the + bitstring for each letter. + """ + letters_list = parse_file(file_path) + root = build_tree(letters_list) + letters = traverse_tree(root, "") + print(f'Huffman Coding of {file_path}: ') + with open(file_path) as f: + while True: + c = f.read(1) + if not c: + break + le = list(filter(lambda l: l.letter == c, letters))[0] + print(le.bitstring, end=" ") + print() + +if __name__ == "__main__": + # pass the file path to the huffman function + huffman(sys.argv[1]) diff --git a/graphs/Directed and Undirected (Weighted) Graph.py b/graphs/Directed and Undirected (Weighted) Graph.py index 68977de8d311..a31a4a96d6d0 100644 --- a/graphs/Directed and Undirected (Weighted) Graph.py +++ b/graphs/Directed and Undirected (Weighted) Graph.py @@ -152,6 +152,7 @@ def cycle_nodes(self): parent = -2 indirect_parents = [] ss = s + on_the_way_back = False anticipating_nodes = set() while True: @@ -199,6 +200,7 @@ def has_cycle(self): parent = -2 indirect_parents = [] ss = s + on_the_way_back = False anticipating_nodes = set() while True: @@ -367,6 +369,7 @@ def cycle_nodes(self): parent = -2 indirect_parents = [] ss = s + on_the_way_back = False anticipating_nodes = set() while True: @@ -414,6 +417,7 @@ def has_cycle(self): parent = -2 indirect_parents = [] ss = s + on_the_way_back = False anticipating_nodes = set() while True: diff --git a/maths/BinaryExponentiation.py b/maths/BinaryExponentiation.py new file mode 100644 index 000000000000..2411cd58a76b --- /dev/null +++ b/maths/BinaryExponentiation.py @@ -0,0 +1,25 @@ +#Author : Junth Basnet +#Time Complexity : O(logn) + +def binary_exponentiation(a, n): + + if (n == 0): + return 1 + + elif (n % 2 == 1): + return binary_exponentiation(a, n - 1) * a + + else: + b = binary_exponentiation(a, n / 2) + return b * b + + +try: + base = int(input('Enter Base : ')) + power = int(input("Enter Power : ")) +except ValueError: + print ("Invalid literal for integer") + +result = binary_exponentiation(base, power) +print("{}^({}) : {}".format(base, power, result)) + diff --git a/maths/PrimeCheck.py b/maths/PrimeCheck.py index e0c51d77a038..8c5c181689dd 100644 --- a/maths/PrimeCheck.py +++ b/maths/PrimeCheck.py @@ -1,13 +1,54 @@ import math +import unittest + + def primeCheck(number): - if number % 2 == 0 and number > 2: + """ + A number is prime if it has exactly two dividers: 1 and itself. + """ + if number < 2: + # Negatives, 0 and 1 are not primes return False - return all(number % i for i in range(3, int(math.sqrt(number)) + 1, 2)) + if number < 4: + # 2 and 3 are primes + return True + if number % 2 == 0: + # Even values are not primes + return False + + # Except 2, all primes are odd. If any odd value divide + # the number, then that number is not prime. + odd_numbers = range(3, int(math.sqrt(number)) + 1, 2) + return not any(number % i == 0 for i in odd_numbers) + + +class Test(unittest.TestCase): + def test_primes(self): + self.assertTrue(primeCheck(2)) + self.assertTrue(primeCheck(3)) + self.assertTrue(primeCheck(5)) + self.assertTrue(primeCheck(7)) + self.assertTrue(primeCheck(11)) + self.assertTrue(primeCheck(13)) + self.assertTrue(primeCheck(17)) + self.assertTrue(primeCheck(19)) + self.assertTrue(primeCheck(23)) + self.assertTrue(primeCheck(29)) + + def test_not_primes(self): + self.assertFalse(primeCheck(-19), + "Negative numbers are not prime.") + self.assertFalse(primeCheck(0), + "Zero doesn't have any divider, primes must have two") + self.assertFalse(primeCheck(1), + "One just have 1 divider, primes must have two.") + self.assertFalse(primeCheck(2 * 2)) + self.assertFalse(primeCheck(2 * 3)) + self.assertFalse(primeCheck(3 * 3)) + self.assertFalse(primeCheck(3 * 5)) + self.assertFalse(primeCheck(3 * 5 * 7)) -def main(): - print(primeCheck(37)) - print(primeCheck(100)) - print(primeCheck(77)) if __name__ == '__main__': - main() + unittest.main() + diff --git a/other/sierpinski_triangle.py b/other/sierpinski_triangle.py index 6a06058fe03e..329a8ce5c43f 100644 --- a/other/sierpinski_triangle.py +++ b/other/sierpinski_triangle.py @@ -21,7 +21,7 @@ Usage: - $python sierpinski_triangle.py -Credits: This code was written by editing the code from http://www.lpb-riannetrujillo.com/blog/python-fractal/ +Credits: This code was written by editing the code from http://www.riannetrujillo.com/blog/python-fractal/ ''' import turtle @@ -64,4 +64,4 @@ def triangle(points,depth): depth-1) -triangle(points,int(sys.argv[1])) \ No newline at end of file +triangle(points,int(sys.argv[1])) diff --git a/project_euler/problem_02/sol4.py b/project_euler/problem_02/sol4.py new file mode 100644 index 000000000000..64bae65f49b4 --- /dev/null +++ b/project_euler/problem_02/sol4.py @@ -0,0 +1,13 @@ +import math +from decimal import * + +getcontext().prec = 100 +phi = (Decimal(5) ** Decimal(0.5) + 1) / Decimal(2) + +n = Decimal(int(input()) - 1) + +index = (math.floor(math.log(n * (phi + 2), phi) - 1) // 3) * 3 + 2 +num = round(phi ** Decimal(index + 1)) / (phi + 2) +sum = num // 2 + +print(int(sum)) diff --git a/searches/binary_search.py b/searches/binary_search.py index 7df45883c09a..1d5da96586cd 100644 --- a/searches/binary_search.py +++ b/searches/binary_search.py @@ -21,10 +21,10 @@ def binary_search(sorted_collection, item): """Pure implementation of binary search algorithm in Python - Be careful collection must be sorted, otherwise result will be + Be careful collection must be ascending sorted, otherwise result will be unpredictable - :param sorted_collection: some sorted collection with comparable items + :param sorted_collection: some ascending sorted collection with comparable items :param item: item value to search :return: index of found item or None if item is not found @@ -60,10 +60,10 @@ def binary_search(sorted_collection, item): def binary_search_std_lib(sorted_collection, item): """Pure implementation of binary search algorithm in Python using stdlib - Be careful collection must be sorted, otherwise result will be + Be careful collection must be ascending sorted, otherwise result will be unpredictable - :param sorted_collection: some sorted collection with comparable items + :param sorted_collection: some ascending sorted collection with comparable items :param item: item value to search :return: index of found item or None if item is not found @@ -89,11 +89,11 @@ def binary_search_by_recursion(sorted_collection, item, left, right): """Pure implementation of binary search algorithm in Python by recursion - Be careful collection must be sorted, otherwise result will be + Be careful collection must be ascending sorted, otherwise result will be unpredictable First recursion should be started with left=0 and right=(len(sorted_collection)-1) - :param sorted_collection: some sorted collection with comparable items + :param sorted_collection: some ascending sorted collection with comparable items :param item: item value to search :return: index of found item or None if item is not found @@ -123,11 +123,11 @@ def binary_search_by_recursion(sorted_collection, item, left, right): return binary_search_by_recursion(sorted_collection, item, midpoint+1, right) def __assert_sorted(collection): - """Check if collection is sorted, if not - raises :py:class:`ValueError` + """Check if collection is ascending sorted, if not - raises :py:class:`ValueError` :param collection: collection - :return: True if collection is sorted - :raise: :py:class:`ValueError` if collection is not sorted + :return: True if collection is ascending sorted + :raise: :py:class:`ValueError` if collection is not ascending sorted Examples: >>> __assert_sorted([0, 1, 2, 4]) @@ -136,10 +136,10 @@ def __assert_sorted(collection): >>> __assert_sorted([10, -1, 5]) Traceback (most recent call last): ... - ValueError: Collection must be sorted + ValueError: Collection must be ascending sorted """ if collection != sorted(collection): - raise ValueError('Collection must be sorted') + raise ValueError('Collection must be ascending sorted') return True @@ -150,7 +150,7 @@ def __assert_sorted(collection): try: __assert_sorted(collection) except ValueError: - sys.exit('Sequence must be sorted to apply binary search') + sys.exit('Sequence must be ascending sorted to apply binary search') target_input = raw_input('Enter a single number to be found in the list:\n') target = int(target_input) diff --git a/sorts/random_pivot_quick_sort.py b/sorts/random_pivot_quick_sort.py new file mode 100644 index 000000000000..fc8f90486ee6 --- /dev/null +++ b/sorts/random_pivot_quick_sort.py @@ -0,0 +1,33 @@ +""" +Picks the random index as the pivot +""" +import random + +def partition(A, left_index, right_index): + pivot = A[left_index] + i = left_index + 1 + for j in range(left_index + 1, right_index): + if A[j] < pivot: + A[j], A[i] = A[i], A[j] + i += 1 + A[left_index], A[i - 1] = A[i - 1], A[left_index] + return i - 1 + +def quick_sort_random(A, left, right): + if left < right: + pivot = random.randint(left, right - 1) + A[pivot], A[left] = A[left], A[pivot] #switches the pivot with the left most bound + pivot_index = partition(A, left, right) + quick_sort_random(A, left, pivot_index) #recursive quicksort to the left of the pivot point + quick_sort_random(A, pivot_index + 1, right) #recursive quicksort to the right of the pivot point + +def main(): + user_input = input('Enter numbers separated by a comma:\n').strip() + arr = [int(item) for item in user_input.split(',')] + + quick_sort_random(arr, 0, len(arr)) + + print(arr) + +if __name__ == "__main__": + main() \ No newline at end of file