diff --git a/README.md b/README.md index 851408c..6b3577f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Algos in Python +Algorithms in Python ====== Implementations of a few algorithms and datastructures for fun and profit! @@ -42,6 +42,8 @@ Completed - String Reverse - Parenthesis Matching - Infix to Postfix +- Modular exponentiation +- Modular multiplicative inverse Tests @@ -52,3 +54,5 @@ Tests python -m tests.heap_test python -m tests.unionfind_test python -m tests.singly_linked_list_test + python -m tests.modular_exponentiation_test + python -m tests.modular_multiplicative_inverse_test diff --git a/lists/queue.py b/lists/queue.py index a33fa83..e6883f1 100644 --- a/lists/queue.py +++ b/lists/queue.py @@ -1,6 +1,12 @@ +from collections import deque + + class Queue(object): + """Wrapper around collections.deque to provide the api consistent with + a Queue""" + def __init__(self): - self.items = [] + self.items = deque() def __str__(self): return ("Queue of size: %d" % len(self.items)) @@ -9,11 +15,10 @@ def isEmpty(self): return len(self.items) == 0 def enqueue(self, item): - self.items.insert(0, item) + self.items.append(item) def dequeue(self): - return self.items.pop() + return self.items.popleft() def size(self): return len(self.items) - diff --git a/misc/__init__.py b/misc/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/misc/modular_exponentiation.py b/misc/modular_exponentiation.py new file mode 100644 index 0000000..43c66ee --- /dev/null +++ b/misc/modular_exponentiation.py @@ -0,0 +1,22 @@ +""" +Problem: https://en.wikipedia.org/wiki/Modular_exponentiation +""" + +def modular_exponentiation(base, exp, mod): + if exp < 1: + raise ValueError("Exponentiation should be ve+ int") + if mod == 1: + return 0 + elif mod < 1: + raise ValueError("Modulus should be ve+ int") + #Initialize result to 1 + result = 1 + base %= mod + while exp > 0: + #multiply base to result if exp is odd + if exp % 2 == 1: + result = (result * base) % mod + #Double base and half exp + exp = exp >> 1 + base = (base ** 2) % mod + return result \ No newline at end of file diff --git a/misc/modular_multiplicative_inverse.py b/misc/modular_multiplicative_inverse.py new file mode 100644 index 0000000..36dd550 --- /dev/null +++ b/misc/modular_multiplicative_inverse.py @@ -0,0 +1,42 @@ +""" +Problem: https://en.wikipedia.org/wiki/Modular_multiplicative_inverse +""" +import GCD as gcd + +def modular_multiplicative_inv(a, m): + if m == 1: + return 0 + if m < 1: + raise ValueError('Modulus should be ve+ int > 0') + # check for co-prime condition + if gcd.greatest_common_divisor(a, m) != 1: + raise ValueError('a and m are not co-primes') + + # Make var "a" positive if it's negative + if a < 0: + a %= m + + # Initialise vars + m0 = m + x0 = 0 + x1 = 1 + + while a > 1: + # Calculate quotient q; store m into temp t + q = a / m + t = m + + # Calculate m as remainder(a, m); store temp t into a + m = a % m + a = t + + # Assign x0 into temp t; Calculate x0 and store temp t into x1 + t = x0 + x0 = x1 - q * x0 + x1 = t + + # If x1 is negative then add modulus m0 + if x1 < 0: + x1 += m0 + + return x1 \ No newline at end of file diff --git a/tests/modular_exponentiation_test.py b/tests/modular_exponentiation_test.py new file mode 100644 index 0000000..8ab9f68 --- /dev/null +++ b/tests/modular_exponentiation_test.py @@ -0,0 +1,16 @@ +import os, sys +import unittest +sys.path.append(os.path.join(os.getcwd(), os.path.pardir)) +from misc import modular_exponentiation as me + +class TestLCS(unittest.TestCase): + def test_modular_exponentiation(self): + self.assertEqual(me.modular_exponentiation(2, 10, 100), 24) + self.assertEqual(me.modular_exponentiation(2, 200, 10), 6) + self.assertEqual(me.modular_exponentiation(5, 20, 1), 0) + #self.assertEqual(me.modular_exponentiation(8, 1, 10), 8) + self.assertRaises(ValueError, me.modular_exponentiation, 12, -1, 10) + self.assertRaises(ValueError, me.modular_exponentiation, 12, 5, 0) + +if __name__ == "__main__": + unittest.main() \ No newline at end of file diff --git a/tests/modular_multiplicative_inverse_test.py b/tests/modular_multiplicative_inverse_test.py new file mode 100644 index 0000000..165eeaf --- /dev/null +++ b/tests/modular_multiplicative_inverse_test.py @@ -0,0 +1,16 @@ +import os, sys +import unittest +sys.path.append(os.path.join(os.getcwd(), os.path.pardir)) +from misc import modular_multiplicative_inverse as mmi + +class TestLCS(unittest.TestCase): + def test_modular_multiplicative_inverse(self): + self.assertEqual(mmi.modular_multiplicative_inv(10, 7), 5) + self.assertEqual(mmi.modular_multiplicative_inv(45, 13), 11) + self.assertEqual(mmi.modular_multiplicative_inv(52, 1), 0) + + self.assertRaises(ValueError, mmi.modular_multiplicative_inv, 12, -1) + self.assertRaises(ValueError, mmi.modular_multiplicative_inv, 12, 2) + +if __name__ == "__main__": + unittest.main() \ No newline at end of file diff --git a/trees/binarysearchtree.py b/trees/binarysearchtree.py index 14885c0..fb573e3 100644 --- a/trees/binarysearchtree.py +++ b/trees/binarysearchtree.py @@ -100,13 +100,13 @@ def insert(self, value): else: node = self.root while node and node.value != value: + if node.value == value: + return parent = node if node.value < value: node = node.right else: node = node.left - if node.value == value: - return if parent.value > value: parent.left = new_node else: