├── .gitignore ├── .travis.yml ├── Algorithm_tests ├── cryptology_tests │ └── ceasar_test.py ├── dynamic_programming_tests │ ├── knapsack_tests │ │ └── knapsack_bottomup_test.py │ ├── sequence_alignment │ │ └── sequence_alignment_test.py │ └── weighted_interval_scheduling │ │ └── weighted_interval_scheduling_test.py ├── graphtheory_tests │ ├── BFS_test.py │ ├── DFS_test.py │ ├── Djikstra │ │ ├── djikstra_heap_test.py │ │ └── djikstra_naive_test.py │ ├── bellman_ford_test.py │ ├── kahn_topological_ordering_test.py │ ├── kruskal_unionfind_test.py │ ├── prims_algorithm_test.py │ ├── test_NN.py │ └── test_graph.txt ├── math_tests │ ├── intersection_test.py │ └── union_test.py ├── other_tests │ ├── test_binarysearch.py │ ├── test_intervalscheduling.py │ └── test_medianmaintenance.py └── sorting_tests │ └── test_sorting.py ├── Algorithms ├── cryptology │ ├── RSA_algorithm │ │ ├── RSA.py │ │ ├── __pycache__ │ │ │ └── euclid_gcd.cpython-37.pyc │ │ └── euclid_gcd.py │ ├── ceasar_shifting_cipher │ │ ├── __pycache__ │ │ │ └── ceasar_shift_cipher.cpython-37.pyc │ │ └── ceasar_shift_cipher.py │ ├── hill_cipher │ │ ├── __pycache__ │ │ │ ├── ceasar_shift_cipher.cpython-37.pyc │ │ │ └── euclid_gcd.cpython-37.pyc │ │ └── hill_cipher.py │ ├── one_time_pad │ │ └── one_time_pad.py │ └── vigenere_cipher │ │ └── vigenere.py ├── dynamic_programming │ ├── __pycache__ │ │ ├── sequence_alignment.cpython-37.pyc │ │ └── weighted_interval_scheduling.cpython-37.pyc │ ├── knapsack │ │ ├── __pycache__ │ │ │ ├── knapsack_bottomup.cpython-37.pyc │ │ │ └── knapsack_memoization_recursive_topdown.cpython-37.pyc │ │ ├── knapsack_bottomup.py │ │ ├── knapsack_memoization_recursive_topdown.py │ │ └── knapsack_naive_recursive.py │ ├── longest_increasing_subsequence.py │ ├── sequence_alignment.py │ └── weighted_interval_scheduling.py ├── graphtheory │ ├── bellman-ford │ │ ├── __pycache__ │ │ │ └── bellman_ford.cpython-37.pyc │ │ ├── bellman_ford.py │ │ └── data.txt │ ├── breadth-first-search │ │ ├── BFS_queue_iterative.py │ │ ├── __pycache__ │ │ │ └── BFS_queue_iterative.cpython-37.pyc │ │ └── exgraph.txt │ ├── depth-first-search │ │ ├── DFS_recursive.py │ │ ├── DFS_stack_iterative.py │ │ ├── __pycache__ │ │ │ ├── DFS_recursive.cpython-37.pyc │ │ │ └── DFS_stack_iterative.cpython-37.pyc │ │ └── exgraph.txt │ ├── dijkstra │ │ ├── __pycache__ │ │ │ ├── dijkstra.cpython-37.pyc │ │ │ └── heapdijkstra.cpython-37.pyc │ │ ├── dijkstra.py │ │ ├── dijkstraData.txt │ │ └── heapdijkstra.py │ ├── floyd-warshall │ │ ├── floyd-warshall.py │ │ └── test_graph.txt │ ├── kahns-toposort │ │ ├── __pycache__ │ │ │ └── kahn_topological_ordering.cpython-37.pyc │ │ ├── example.txt │ │ └── kahn_topological_ordering.py │ ├── kargers │ │ ├── kargermincut.py │ │ └── kargermincutdata.txt │ ├── kruskal │ │ ├── __pycache__ │ │ │ ├── DFS_stack_iterative.cpython-37.pyc │ │ │ ├── kruskal.cpython-37.pyc │ │ │ └── kruskal_unionfind.cpython-37.pyc │ │ ├── edges.txt │ │ ├── kruskal.py │ │ ├── kruskal_unionfind.py │ │ └── testedges.txt │ ├── nearest-neighbor-tsp │ │ ├── NearestNeighborTSP.py │ │ └── graph.txt │ └── prims │ │ ├── __pycache__ │ │ └── prim_heap.cpython-37.pyc │ │ ├── edges.txt │ │ ├── prim_heap.py │ │ └── prim_naive.py ├── math │ ├── euclid_gcd │ │ └── euclid_gcd.py │ ├── extended_euclidean_algorithm │ │ └── euclid_gcd.py │ ├── intersection_of_two_sets │ │ ├── __pycache__ │ │ │ └── intersection_of_two_sets.cpython-37.pyc │ │ └── intersection_of_two_sets.py │ ├── karatsuba │ │ └── karatsuba.py │ ├── pollard_p1 │ │ └── pollard_p1.py │ ├── prime_factorization │ │ └── primefactorization.py │ ├── sieve_of_eratosthenes │ │ └── sieve_eratosthenes.py │ └── union_of_two_sets │ │ ├── __pycache__ │ │ └── union_of_two_sets.cpython-37.pyc │ │ └── union_of_two_sets.py ├── numerical_methods │ ├── bisection.py │ └── fixpoint.py ├── other │ ├── Huffman │ │ ├── Huffman.py │ │ ├── compressed_file.bin │ │ ├── huffman.txt │ │ └── test.txt │ ├── Kadanes_algorithm.py │ ├── __pycache__ │ │ ├── interval_scheduling.cpython-38.pyc │ │ └── median_maintenance.cpython-38.pyc │ ├── binarysearch.py │ ├── counting_inversions.py │ ├── interval_scheduling.py │ └── median_maintenance.py └── sorting │ ├── __pycache__ │ ├── bubblesort.cpython-37.pyc │ ├── insertionsort.cpython-37.pyc │ ├── mergesort.cpython-37.pyc │ ├── quicksort.cpython-37.pyc │ ├── randomized_quicksort.cpython-37.pyc │ └── selectionsort.cpython-37.pyc │ ├── bubblesort.py │ ├── hopesort.py │ ├── insertionsort.py │ ├── mergesort.py │ ├── quicksort.py │ ├── randomized_quicksort.py │ └── selectionsort.py ├── LICENSE ├── README.md ├── requirements.txt └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | plot_complexity.py -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | 3 | # Default Python version is usually 2.7 4 | python: 3.7 5 | 6 | # Install ruby to get gem command 7 | before_install: 8 | - python --version 9 | - pip install -U pip 10 | - pip install -U pytest 11 | - pip install codecov 12 | - sudo apt-add-repository -y ppa:brightbox/ruby-ng 13 | - sudo apt-get -y update 14 | - sudo apt-get -y install ruby-full 15 | 16 | before_script: 17 | - gem install awesome_bot 18 | 19 | install: 20 | - pip3 install -r requirements.txt 21 | - pip3 install pytest 22 | - pip3 install pytest-cov 23 | - pip3 install codecov 24 | 25 | script: 26 | - awesome_bot README.md --allow-dupe --allow-redirect 27 | - pytest --cov=Algorithms/ 28 | 29 | # # Dynamic Programming Tests 30 | # - python Algorithm_tests/dynamic_programming_tests/knapsack_tests/knapsack_bottomup_test.py 31 | # - python Algorithm_tests/dynamic_programming_tests/sequence_alignment/sequence_alignment_test.py 32 | # - python Algorithm_tests/dynamic_programming_tests/weighted_interval_scheduling/weighted_interval_scheduling_test.py 33 | # 34 | # # Graph Theory Tests 35 | # - python Algorithm_tests/graphtheory_tests/bellman_ford_test.py 36 | # - python Algorithm_tests/graphtheory_tests/kahn_topological_ordering_test.py 37 | # - python Algorithm_tests/graphtheory_tests/Djikstra/djikstra_heap_test.py 38 | # - python Algorithm_tests/graphtheory_tests/Djikstra/djikstra_naive_test.py 39 | # - python Algorithm_tests/graphtheory_tests/kruskal_unionfind_test.py 40 | # - python Algorithm_tests/graphtheory_tests/prims_algorithm_test.py 41 | # - python Algorithm_tests/graphtheory_tests/BFS_test.py 42 | # - python Algorithm_tests/graphtheory_tests/DFS_test.py 43 | # 44 | # # Math tests 45 | # - python Algorithm_tests/other_tests/test_binarysearch.py 46 | # - python Algorithm_tests/math_tests/intersection_test.py 47 | # - python Algorithm_tests/math_tests/union_test.py 48 | # 49 | # # Cryptography tests 50 | # - python Algorithm_tests/cryptology_tests/ceasar_test.py 51 | # 52 | # # "Other" tests 53 | # - python Algorithm_tests/other_tests/test_medianmaintenance.py 54 | # - python Algorithm_tests/other_tests/test_intervalscheduling.py 55 | # 56 | # # Sorting tests 57 | # - python Algorithm_tests/sorting_tests/test_sorting.py 58 | 59 | after_success: 60 | - codecov 61 | -------------------------------------------------------------------------------- /Algorithm_tests/cryptology_tests/ceasar_test.py: -------------------------------------------------------------------------------- 1 | # Import folder where sorting algorithms 2 | import sys 3 | import unittest 4 | 5 | # For importing from different folders 6 | # OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from 7 | sys.path.append("Algorithms/cryptology/ceasar_shifting_cipher") 8 | 9 | # If run from local: 10 | # sys.path.append('../../Algorithms/cryptology/ceasar_shifting_cipher') 11 | 12 | from ceasar_shift_cipher import encrypt, decrypt 13 | 14 | # Note this is not robust.. but im trying to make it a habit to make some tests. 15 | # Some are better than nothing. But these are not complete at all. 16 | class test_ceasar_cipher(unittest.TestCase): 17 | def setUp(self): 18 | # test cases we wish to run 19 | self.message1 = "abc" 20 | self.shift1 = 3 21 | self.correct_encrypt1 = "def" 22 | 23 | self.message2 = "xyz " 24 | self.shift2 = 1 25 | self.correct_encrypt2 = "yz a" 26 | 27 | def test_encryption_message1(self): 28 | encrypted_message1 = encrypt(self.message1, self.shift1) 29 | self.assertEqual(encrypted_message1, self.correct_encrypt1) 30 | 31 | def test_decryption_message1(self): 32 | decrypted_message1 = decrypt(self.correct_encrypt1, self.shift1) 33 | self.assertEqual(decrypted_message1, self.message1) 34 | 35 | def test_encryption_message2(self): 36 | encrypted_message2 = encrypt(self.message2, self.shift2) 37 | self.assertEqual(encrypted_message2, self.correct_encrypt2) 38 | 39 | def test_decryption_message2(self): 40 | decrypted_message2 = decrypt(self.correct_encrypt2, self.shift2) 41 | self.assertEqual(decrypted_message2, self.message2) 42 | 43 | 44 | if __name__ == "__main__": 45 | print("Running ceasar cipher tests:") 46 | unittest.main() 47 | -------------------------------------------------------------------------------- /Algorithm_tests/dynamic_programming_tests/knapsack_tests/knapsack_bottomup_test.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import unittest 3 | 4 | # For importing from different folders 5 | # OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from 6 | sys.path.append("Algorithms/dynamic_programming/knapsack") 7 | 8 | # If run from local: 9 | # sys.path.append('../../../Algorithms/dynamic_programming/knapsack/') 10 | from knapsack_bottomup import knapsack 11 | 12 | 13 | class test_KnapSack(unittest.TestCase): 14 | def setUp(self): 15 | self.weights1, self.values1, self.capacity1 = [], [], 100 16 | self.n1 = len(self.weights1) 17 | self.correctvalue1, self.correctitems1 = 0, [] 18 | 19 | self.weights2, self.values2, self.capacity2 = [10], [50], 100 20 | self.n2 = len(self.weights2) 21 | self.correctvalue2, self.correctitems2 = 50, [0] 22 | 23 | self.weights3, self.values3, self.capacity3 = [10, 20, 30], [-10, -20, -30], 100 24 | self.n3 = len(self.weights2) 25 | self.correctvalue3, self.correctitems3 = 0, [] 26 | 27 | self.weights4, self.values4, self.capacity4 = ( 28 | [1, 2, 4, 2, 5], 29 | [5, 3, 5, 3, 2], 30 | 5, 31 | ) 32 | self.n4 = len(self.weights4) 33 | self.correctvalue4, self.correctitems4 = 11, [0, 1, 3] 34 | 35 | self.weights5, self.values5, self.capacity5 = [10, 10, 10], [30, 30, 30], 5 36 | self.n5 = len(self.weights5) 37 | self.correctvalue5, self.correctitems5 = 0, [] 38 | 39 | def test_noitems(self): 40 | total_value, items = knapsack( 41 | self.n1, self.capacity1, self.weights1, self.values1 42 | ) 43 | self.assertEqual(self.correctvalue1, total_value) 44 | self.assertEqual(self.correctitems1, items) 45 | 46 | def test_singleitem_value(self): 47 | total_value, items = knapsack( 48 | self.n2, self.capacity2, self.weights2, self.values2 49 | ) 50 | self.assertEqual(self.correctvalue2, total_value) 51 | self.assertEqual(self.correctitems2, items) 52 | 53 | def test_negativevalues(self): 54 | total_value, items = knapsack( 55 | self.n3, self.capacity3, self.weights3, self.values3 56 | ) 57 | self.assertEqual(self.correctvalue3, total_value) 58 | self.assertEqual(self.correctitems3, items) 59 | 60 | def test_simpleexample(self): 61 | total_value, items = knapsack( 62 | self.n4, self.capacity4, self.weights4, self.values4 63 | ) 64 | self.assertEqual(self.correctvalue4, total_value) 65 | self.assertEqual(self.correctitems4, items) 66 | 67 | def test_weight_too_heavy(self): 68 | total_value, items = knapsack( 69 | self.n5, self.capacity5, self.weights5, self.values5 70 | ) 71 | self.assertEqual(self.correctvalue5, total_value) 72 | self.assertEqual(self.correctitems5, items) 73 | 74 | 75 | if __name__ == "__main__": 76 | print("Running Knapsack tests:") 77 | unittest.main() 78 | -------------------------------------------------------------------------------- /Algorithm_tests/dynamic_programming_tests/sequence_alignment/sequence_alignment_test.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import unittest 3 | 4 | # For importing from different folders 5 | # OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from 6 | sys.path.append("Algorithms/dynamic_programming/") 7 | 8 | # If run from local: 9 | # sys.path.append('../../../Algorithms/dynamic_programming/') 10 | from sequence_alignment import SequenceAlignment 11 | 12 | 13 | class test_sequence_alignment(unittest.TestCase): 14 | def setUp(self): 15 | self.x1 = "ABC" 16 | self.y1 = "ADC" 17 | self.correct_editstep1 = 1 18 | 19 | self.x2 = "AB" 20 | self.y2 = "A" 21 | self.correct_editstep2 = 1 22 | 23 | self.x3 = "A" 24 | self.y3 = "" 25 | self.correct_editstep3 = 1 26 | 27 | self.x4 = "ABC" 28 | self.y4 = "ABCDE" 29 | self.correct_editstep4 = 2 30 | 31 | self.x5 = "ABCKL" 32 | self.y5 = "ADCE" 33 | self.correct_editstep5 = 3 34 | 35 | self.x6 = "A" * 10 36 | self.y6 = "" 37 | self.correct_editstep6 = 10 38 | 39 | self.x7 = "" 40 | self.y7 = "A" * 10 41 | self.correct_editstep7 = 10 42 | 43 | self.x8 = "TGACGTGC" 44 | self.y8 = "TCGACGTCA" 45 | self.correct_editstep8 = 3 46 | 47 | self.x9 = "XYZ" 48 | self.y9 = "XKZ" 49 | self.correct_solution9 = ["align_X", "align_K", "align_Z"] 50 | 51 | self.x10 = "XX" 52 | self.y10 = "" 53 | self.correct_solution10 = ["remove_X", "remove_X"] 54 | 55 | self.x11 = "" 56 | self.y11 = "XX" 57 | self.correct_solution11 = ["insert_X", "insert_X"] 58 | 59 | def test_simplecase(self): 60 | sequence_align = SequenceAlignment(self.x1, self.y1) 61 | editsteps, _ = sequence_align.alignment() 62 | self.assertEqual(self.correct_editstep1, editsteps) 63 | 64 | def test_remove(self): 65 | sequence_align = SequenceAlignment(self.x2, self.y2) 66 | editsteps, _ = sequence_align.alignment() 67 | self.assertEqual(self.correct_editstep2, editsteps) 68 | 69 | def test_remove_to_empty(self): 70 | sequence_align = SequenceAlignment(self.x3, self.y3) 71 | editsteps, _ = sequence_align.alignment() 72 | self.assertEqual(self.correct_editstep3, editsteps) 73 | 74 | def test_insert_elements(self): 75 | sequence_align = SequenceAlignment(self.x4, self.y4) 76 | editsteps, _ = sequence_align.alignment() 77 | self.assertEqual(self.correct_editstep4, editsteps) 78 | 79 | def test_remove_insert_align(self): 80 | sequence_align = SequenceAlignment(self.x5, self.y5) 81 | editsteps, _ = sequence_align.alignment() 82 | self.assertEqual(self.correct_editstep5, editsteps) 83 | 84 | def test_x_longer_than_y(self): 85 | sequence_align = SequenceAlignment(self.x6, self.y6) 86 | editsteps, _ = sequence_align.alignment() 87 | self.assertEqual(self.correct_editstep6, editsteps) 88 | 89 | def test_y_longer_than_x(self): 90 | sequence_align = SequenceAlignment(self.x7, self.y7) 91 | editsteps, _ = sequence_align.alignment() 92 | self.assertEqual(self.correct_editstep7, editsteps) 93 | 94 | def test_more_complicated_example(self): 95 | sequence_align = SequenceAlignment(self.x8, self.y8) 96 | editsteps, _ = sequence_align.alignment() 97 | self.assertEqual(self.correct_editstep8, editsteps) 98 | 99 | def test_findsolution_simplecase(self): 100 | sequence_align = SequenceAlignment(self.x9, self.y9) 101 | _, solution = sequence_align.alignment() 102 | self.assertEqual(self.correct_solution9, solution) 103 | 104 | def test_findsolution_empty_y(self): 105 | sequence_align = SequenceAlignment(self.x10, self.y10) 106 | _, solution = sequence_align.alignment() 107 | self.assertEqual(self.correct_solution10, solution) 108 | 109 | def test_findsolution_empty_x(self): 110 | sequence_align = SequenceAlignment(self.x11, self.y11) 111 | _, solution = sequence_align.alignment() 112 | self.assertEqual(self.correct_solution11, solution) 113 | 114 | 115 | if __name__ == "__main__": 116 | print("Running Sequence Alignment tests:") 117 | unittest.main() 118 | -------------------------------------------------------------------------------- /Algorithm_tests/dynamic_programming_tests/weighted_interval_scheduling/weighted_interval_scheduling_test.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import unittest 3 | 4 | # For importing from different folders 5 | # OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from 6 | sys.path.append("Algorithms/dynamic_programming/") 7 | 8 | # If run from local: 9 | # sys.path.append('../../../Algorithms/dynamic_programming/') 10 | from weighted_interval_scheduling import WeightedIntervalScheduling 11 | 12 | 13 | class test_weighted_interval_scheduling(unittest.TestCase): 14 | def setUp(self): 15 | self.I1 = [] 16 | self.correct_maxweight1 = 0 17 | self.correct_intervals1 = [] 18 | 19 | self.I2 = [(0, 3, 10)] 20 | self.correct_maxweight2 = 10 21 | self.correct_intervals2 = [(0, 3, 10)] 22 | 23 | self.I3 = [(0, 3, 5), (2, 5, 15), (4, 6, 5)] 24 | self.correct_maxweight3 = 15 25 | self.correct_intervals3 = [(2, 5, 15)] 26 | 27 | self.I4 = [(0, 3, 5), (3, 5, 15), (5, 7, 5)] 28 | self.correct_maxweight4 = 25 29 | self.correct_intervals4 = [(0, 3, 5), (3, 5, 15), (5, 7, 5)] 30 | 31 | self.I5 = [(0, 3, 5), (3, 5, -100), (5, 7, -50)] 32 | self.correct_maxweight5 = 5 33 | self.correct_intervals5 = [(0, 3, 5)] 34 | 35 | self.I6 = [(0, 50, 1), (0, 49, 1), (0, 48, 1), (15, 20, 10)] 36 | self.correct_maxweight6 = 10 37 | self.correct_intervals6 = [(15, 20, 10)] 38 | 39 | self.I7 = [(0, 50, 1), (0, 50, 1), (0, 50, 1), (0, 50, 1)] 40 | self.correct_maxweight7 = 1 41 | self.correct_intervals7 = [(0, 50, 1)] 42 | 43 | self.I8 = [(0, 50, 1), (0, 49, 1), (0, 48, 1), (0, 47, 1)] 44 | self.correct_maxweight8 = 1 45 | self.correct_intervals8 = [(0, 47, 1)] 46 | 47 | self.I9 = [(0, 50, 2), (0, 49, 1), (0, 48, 1), (0, 47, 1)] 48 | self.correct_maxweight9 = 2 49 | self.correct_intervals9 = [(0, 50, 2)] 50 | 51 | def test_empty_interval(self): 52 | weightedinterval = WeightedIntervalScheduling(self.I1) 53 | max_weight, best_intervals = weightedinterval.weighted_interval() 54 | self.assertEqual(self.correct_maxweight1, max_weight) 55 | self.assertEqual(self.correct_intervals1, best_intervals) 56 | 57 | def test_single_interval(self): 58 | weightedinterval = WeightedIntervalScheduling(self.I2) 59 | max_weight, best_intervals = weightedinterval.weighted_interval() 60 | self.assertEqual(self.correct_maxweight2, max_weight) 61 | self.assertEqual(self.correct_intervals2, best_intervals) 62 | 63 | def test_overlapping_intervals(self): 64 | weightedinterval = WeightedIntervalScheduling(self.I3) 65 | max_weight, best_intervals = weightedinterval.weighted_interval() 66 | self.assertEqual(self.correct_maxweight3, max_weight) 67 | self.assertEqual(self.correct_intervals3, best_intervals) 68 | 69 | def test_no_overlapping_intervals(self): 70 | weightedinterval = WeightedIntervalScheduling(self.I4) 71 | max_weight, best_intervals = weightedinterval.weighted_interval() 72 | self.assertEqual(self.correct_maxweight4, max_weight) 73 | self.assertEqual(self.correct_intervals4, best_intervals) 74 | 75 | def test_negative_weights(self): 76 | weightedinterval = WeightedIntervalScheduling(self.I5) 77 | max_weight, best_intervals = weightedinterval.weighted_interval() 78 | self.assertEqual(self.correct_maxweight5, max_weight) 79 | self.assertEqual(self.correct_intervals5, best_intervals) 80 | 81 | def test_interval_contained_in_all_intervals(self): 82 | weightedinterval = WeightedIntervalScheduling(self.I6) 83 | max_weight, best_intervals = weightedinterval.weighted_interval() 84 | self.assertEqual(self.correct_maxweight6, max_weight) 85 | self.assertEqual(self.correct_intervals6, best_intervals) 86 | 87 | def test_all_intervals_same(self): 88 | weightedinterval = WeightedIntervalScheduling(self.I7) 89 | max_weight, best_intervals = weightedinterval.weighted_interval() 90 | self.assertEqual(self.correct_maxweight7, max_weight) 91 | self.assertEqual(self.correct_intervals7, best_intervals) 92 | 93 | def test_earliest_finish_time(self): 94 | weightedinterval = WeightedIntervalScheduling(self.I8) 95 | max_weight, best_intervals = weightedinterval.weighted_interval() 96 | self.assertEqual(self.correct_maxweight8, max_weight) 97 | self.assertEqual(self.correct_intervals8, best_intervals) 98 | 99 | def test_earliest_finish_time_not_best(self): 100 | weightedinterval = WeightedIntervalScheduling(self.I9) 101 | max_weight, best_intervals = weightedinterval.weighted_interval() 102 | self.assertEqual(self.correct_maxweight9, max_weight) 103 | self.assertEqual(self.correct_intervals9, best_intervals) 104 | 105 | 106 | if __name__ == "__main__": 107 | print("Running Weighted Interval Scheduling tests:") 108 | unittest.main() 109 | -------------------------------------------------------------------------------- /Algorithm_tests/graphtheory_tests/BFS_test.py: -------------------------------------------------------------------------------- 1 | # Import folder where sorting algorithms 2 | import sys 3 | import unittest 4 | from collections import deque 5 | 6 | # For importing from different folders 7 | # OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from 8 | sys.path.append("Algorithms/graphtheory/breadth-first-search/") 9 | 10 | # If run from local: 11 | # sys.path.append('../../Algorithms/graphtheory/breadth-first-search/') 12 | from BFS_queue_iterative import BFS 13 | 14 | 15 | class test_BFS(unittest.TestCase): 16 | def setUp(self): 17 | self.G1 = {1: [2], 2: [1, 3], 3: [2]} 18 | self.correct_visited1 = [True] * 3 19 | self.correct_path1 = [1, 2, 3] 20 | 21 | self.G2 = {1: [2], 2: [1, 3, 4], 3: [2], 4: [2, 5], 5: [4]} 22 | self.correct_visited2 = [True] * 5 23 | 24 | self.G3 = {1: [2], 2: [1, 3, 4], 3: [2], 4: [2], 5: []} 25 | self.correct_visited3 = [True] * 4 + [False] 26 | 27 | self.G4 = {1: [2, 3, 4], 2: [1, 3, 4], 3: [1, 2, 4], 4: [1, 2, 3]} 28 | self.correct_visited4 = [True] * 4 29 | 30 | self.G5 = { 31 | 1: [2, 3, 4], 32 | 2: [1, 5], 33 | 3: [1, 7], 34 | 4: [1, 6], 35 | 5: [2], 36 | 6: [4], 37 | 7: [3], 38 | } 39 | self.correct_visited5 = [True] * 7 40 | 41 | def test_linear_graph(self): 42 | visited, path = BFS(self.G1, start_node=1) 43 | self.assertEqual(visited, self.correct_visited1) 44 | self.assertEqual(path, self.correct_path1) 45 | 46 | def test_simple_graph(self): 47 | visited, path = BFS(self.G2, start_node=1) 48 | self.assertTrue(path.index(3) < path.index(5)) 49 | self.assertEqual(visited, self.correct_visited2) 50 | 51 | def test_disconnected_graph(self): 52 | visited, path = BFS(self.G3, start_node=1) 53 | self.assertEqual(visited, self.correct_visited3) 54 | 55 | def test_complete_graph(self): 56 | visited, path = BFS(self.G4, start_node=1) 57 | self.assertEqual(visited, self.correct_visited4) 58 | 59 | def test_breadth_before_depth(self): 60 | visited, path = BFS(self.G5, start_node=1) 61 | self.assertEqual(visited, self.correct_visited5) 62 | 63 | # Make sure it goes breadth first 64 | self.assertTrue(path.index(2) < path.index(5)) 65 | self.assertTrue(path.index(2) < path.index(6)) 66 | self.assertTrue(path.index(2) < path.index(7)) 67 | self.assertTrue(path.index(3) < path.index(5)) 68 | self.assertTrue(path.index(3) < path.index(6)) 69 | self.assertTrue(path.index(3) < path.index(7)) 70 | self.assertTrue(path.index(4) < path.index(5)) 71 | self.assertTrue(path.index(4) < path.index(6)) 72 | self.assertTrue(path.index(4) < path.index(7)) 73 | 74 | 75 | if __name__ == "__main__": 76 | print("Running BFS/DFS tests:") 77 | unittest.main() 78 | -------------------------------------------------------------------------------- /Algorithm_tests/graphtheory_tests/DFS_test.py: -------------------------------------------------------------------------------- 1 | # Import folder where sorting algorithms 2 | import sys 3 | import unittest 4 | from collections import deque 5 | 6 | # For importing from different folders 7 | # OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from 8 | sys.path.append("Algorithms/graphtheory/depth-first-search/") 9 | 10 | # If run from local: 11 | # sys.path.append('../../Algorithms/graphtheory/depth-first-search/') 12 | from DFS_recursive import DFS as DFS_rec 13 | from DFS_stack_iterative import DFS as DFS_stack 14 | 15 | 16 | class test_DFS(unittest.TestCase): 17 | def setUp(self): 18 | self.G1 = {1: [2], 2: [1, 3], 3: [2]} 19 | self.correct_visited1 = [True] * 3 20 | self.correct_path1 = [1, 2, 3] 21 | self.DFS_recursive_visited1 = [False for i in range(1, len(self.G1) + 1)] 22 | 23 | self.G2 = {1: [2], 2: [1, 3, 4], 3: [2], 4: [2, 5], 5: [4]} 24 | self.correct_visited2 = [True] * 5 25 | self.DFS_recursive_visited2 = [False for i in range(1, len(self.G2) + 1)] 26 | 27 | self.G3 = {1: [2], 2: [1, 3, 4], 3: [2], 4: [2], 5: []} 28 | self.correct_visited3 = [True] * 4 + [False] 29 | self.DFS_recursive_visited3 = [False for i in range(1, len(self.G3) + 1)] 30 | 31 | self.G4 = {1: [2, 3, 4], 2: [1, 3, 4], 3: [1, 2, 4], 4: [1, 2, 3]} 32 | self.correct_visited4 = [True] * 4 33 | self.DFS_recursive_visited4 = [False for i in range(1, len(self.G4) + 1)] 34 | 35 | def test_linear_graph(self): 36 | visited, path = DFS_stack(self.G1, start_node=1) 37 | self.assertEqual(visited, self.correct_visited1) 38 | self.assertEqual(path, self.correct_path1) 39 | 40 | DFS_rec(self.G1, 1, self.DFS_recursive_visited1) 41 | self.assertEqual(self.DFS_recursive_visited1, self.correct_visited1) 42 | 43 | def test_simple_graph(self): 44 | visited, path = DFS_stack(self.G2, start_node=1) 45 | self.assertEqual(visited, self.correct_visited2) 46 | 47 | DFS_rec(self.G2, 1, self.DFS_recursive_visited2) 48 | self.assertEqual(self.DFS_recursive_visited2, self.correct_visited2) 49 | 50 | def test_disconnected_graph(self): 51 | visited, path = DFS_stack(self.G3, start_node=1) 52 | self.assertEqual(visited, self.correct_visited3) 53 | 54 | DFS_rec(self.G3, 1, self.DFS_recursive_visited3) 55 | self.assertEqual(self.DFS_recursive_visited3, self.correct_visited3) 56 | 57 | def test_complete_graph(self): 58 | visited, path = DFS_stack(self.G4, start_node=1) 59 | self.assertEqual(visited, self.correct_visited4) 60 | 61 | DFS_rec(self.G4, 1, self.DFS_recursive_visited4) 62 | self.assertEqual(self.DFS_recursive_visited4, self.correct_visited4) 63 | 64 | 65 | if __name__ == "__main__": 66 | print("Running BFS/DFS tests:") 67 | unittest.main() 68 | -------------------------------------------------------------------------------- /Algorithm_tests/graphtheory_tests/Djikstra/djikstra_heap_test.py: -------------------------------------------------------------------------------- 1 | # Import folder where sorting algorithms 2 | import sys 3 | import unittest 4 | 5 | # For importing from different folders 6 | # OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from 7 | sys.path.append("Algorithms/graphtheory/dijkstra/") 8 | 9 | # If run from local: 10 | # sys.path.append('../../../Algorithms/graphtheory/dijkstra/') 11 | 12 | from heapdijkstra import dijkstra 13 | 14 | 15 | class test_Dijkstra(unittest.TestCase): 16 | def setUp(self): 17 | self.G1 = {} 18 | self.correct_path1 = [] 19 | self.correct_dist1 = float("inf") 20 | 21 | self.G2 = {1: {2: 1, 4: 10}, 2: {3: 15}, 3: {6: 5}, 4: {5: 1}, 5: {6: 1}, 6: {}} 22 | self.correct_path2 = [1, 4, 5, 6] 23 | self.correct_dist2 = 12 24 | 25 | self.G3 = {1: {2: 1, 4: 10}, 2: {3: 15}, 3: {}, 4: {5: 1}, 5: {}, 6: {}} 26 | self.correct_path3 = [] 27 | self.correct_dist3 = float("inf") 28 | 29 | self.G4 = {1: {2: 1, 4: 10}, 2: {3: 15}, 3: {6: 5}, 4: {5: 1}, 5: {6: 1}, 6: {}} 30 | self.correct_path4 = [1, 4, 5] 31 | self.correct_dist4 = 11 32 | 33 | def test_emptygraph(self): 34 | path_to_take, distances = dijkstra(self.G1, 0, 1) 35 | self.assertEqual(distances[1], self.correct_dist1) 36 | self.assertEqual(path_to_take, self.correct_path1) 37 | 38 | def test_simplegraph(self): 39 | path_to_take, distances = dijkstra(self.G2, 1, 6) 40 | self.assertEqual(distances[6], self.correct_dist2) 41 | self.assertEqual(path_to_take, self.correct_path2) 42 | 43 | def test_no_path_exists(self): 44 | path_to_take, distances = dijkstra(self.G3, 1, 6) 45 | self.assertEqual(distances[6], self.correct_dist3) 46 | self.assertEqual(path_to_take, self.correct_path3) 47 | 48 | def test_not_endpoint(self): 49 | path_to_take, distances = dijkstra(self.G4, 1, 5) 50 | self.assertEqual(distances[5], self.correct_dist4) 51 | self.assertEqual(path_to_take, self.correct_path4) 52 | 53 | 54 | if __name__ == "__main__": 55 | print("Running Djikstra tests:") 56 | unittest.main() 57 | -------------------------------------------------------------------------------- /Algorithm_tests/graphtheory_tests/Djikstra/djikstra_naive_test.py: -------------------------------------------------------------------------------- 1 | # Import folder where sorting algorithms 2 | import sys 3 | import unittest 4 | 5 | # For importing from different folders 6 | # OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from 7 | sys.path.append("Algorithms/graphtheory/dijkstra/") 8 | 9 | # If run from local: 10 | # sys.path.append('../../../Algorithms/graphtheory/dijkstra/') 11 | 12 | from dijkstra import dijkstra 13 | 14 | 15 | class test_Dijkstra(unittest.TestCase): 16 | def setUp(self): 17 | self.G1 = {} 18 | self.correct_path1 = [] 19 | self.correct_dist1 = float("inf") 20 | 21 | self.G2 = {1: {2: 1, 4: 10}, 2: {3: 15}, 3: {6: 5}, 4: {5: 1}, 5: {6: 1}, 6: {}} 22 | self.correct_path2 = [1, 4, 5, 6] 23 | self.correct_dist2 = 12 24 | 25 | self.G3 = {1: {2: 1, 4: 10}, 2: {3: 15}, 3: {}, 4: {5: 1}, 5: {}, 6: {}} 26 | self.correct_path3 = [] 27 | self.correct_dist3 = float("inf") 28 | 29 | self.G4 = {1: {2: 1, 4: 10}, 2: {3: 15}, 3: {6: 5}, 4: {5: 1}, 5: {6: 1}, 6: {}} 30 | self.correct_path4 = [1, 4, 5] 31 | self.correct_dist4 = 11 32 | 33 | def test_emptygraph(self): 34 | path_to_take, distance = dijkstra(self.G1, 0, 1) 35 | self.assertEqual(distance, self.correct_dist1) 36 | self.assertEqual(path_to_take, self.correct_path1) 37 | 38 | def test_simplegraph(self): 39 | path_to_take, distance = dijkstra(self.G2, 1, 6) 40 | self.assertEqual(distance, self.correct_dist2) 41 | self.assertEqual(path_to_take, self.correct_path2) 42 | 43 | def test_no_path_exists(self): 44 | path_to_take, distance = dijkstra(self.G3, 1, 6) 45 | self.assertEqual(distance, self.correct_dist3) 46 | self.assertEqual(path_to_take, self.correct_path3) 47 | 48 | def test_not_endpoint(self): 49 | path_to_take, distance = dijkstra(self.G4, 1, 5) 50 | self.assertEqual(distance, self.correct_dist4) 51 | self.assertEqual(path_to_take, self.correct_path4) 52 | 53 | 54 | if __name__ == "__main__": 55 | print("Running Djikstra tests:") 56 | unittest.main() 57 | -------------------------------------------------------------------------------- /Algorithm_tests/graphtheory_tests/bellman_ford_test.py: -------------------------------------------------------------------------------- 1 | # Import folder where sorting algorithms 2 | import sys 3 | import unittest 4 | 5 | # For importing from different folders 6 | # OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from 7 | sys.path.append("Algorithms/graphtheory/bellman-ford") 8 | 9 | # If run from local: 10 | # sys.path.append('../../Algorithms/graphtheory/bellman-ford') 11 | 12 | from bellman_ford import bellman_ford 13 | 14 | 15 | class test_BellmanFord(unittest.TestCase): 16 | def test_negativecycle(self): 17 | # Because of negative cycles, we shall denote the shortest path for these 18 | # as -infinity. 19 | G = {1: {2: 5, 3: 20}, 2: {4: 10}, 3: {5: 10}, 4: {}, 5: {6: 5}, 6: {3: -20}} 20 | 21 | correct_shortest_dist = { 22 | 1: 0, 23 | 2: 5, 24 | 3: -float("inf"), 25 | 4: 15, 26 | 5: -float("inf"), 27 | 6: -float("inf"), 28 | } 29 | shortest_dist, _ = bellman_ford(G, 1) 30 | 31 | self.assertEqual(shortest_dist, correct_shortest_dist) 32 | 33 | def test_shortestdist(self): 34 | G = {1: {2: 100, 3: 5}, 2: {4: 20}, 3: {2: 10}, 4: {}} 35 | 36 | start_node = 1 37 | shortest_dist, _ = bellman_ford(G, start_node) 38 | 39 | # Test distance to starting node should be 0 40 | self.assertEqual(shortest_dist[start_node], 0) 41 | 42 | # Test shortest distances from graph 43 | self.assertEqual(shortest_dist[2], 15) 44 | self.assertEqual(shortest_dist[3], 5) 45 | self.assertEqual(shortest_dist[4], 35) 46 | 47 | def test_run_emptygraph(self): 48 | G = {} 49 | start_node = 1 50 | 51 | # Cant run an empty graph without returning error 52 | with self.assertRaises(ValueError): 53 | shortest_dist, _ = bellman_ford(G, start_node) 54 | 55 | 56 | if __name__ == "__main__": 57 | print("Running bellman ford tests:") 58 | unittest.main() 59 | -------------------------------------------------------------------------------- /Algorithm_tests/graphtheory_tests/kahn_topological_ordering_test.py: -------------------------------------------------------------------------------- 1 | # Import folder where sorting algorithms 2 | import sys 3 | import unittest 4 | 5 | # For importing from different folders 6 | # OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from 7 | sys.path.append("Algorithms/graphtheory/kahns-toposort/") 8 | 9 | # If run from local: 10 | # sys.path.append('../../Algorithms/graphtheory/kahns-toposort') 11 | 12 | from kahn_topological_ordering import topological_ordering 13 | from collections import defaultdict 14 | 15 | 16 | class test_TopologicalOrdering(unittest.TestCase): 17 | def setUp(self): 18 | self.G1 = {} 19 | self.degree_incoming1 = defaultdict(int, {}) 20 | self.correct_isDAG1 = False 21 | self.correct_path1 = [] 22 | 23 | self.G2 = {"1": ["2"], "2": ["3"], "3": ["4"], "4": ["5"], "5": []} 24 | self.degree_incoming2 = defaultdict(int, {"2": 1, "3": 1, "4": 1, "5": 1}) 25 | self.correct_isDAG2 = True 26 | self.correct_path2 = ["1", "2", "3", "4", "5"] 27 | 28 | self.G3 = { 29 | "1": ["2", "3", "4", "5"], 30 | "2": ["3", "4", "5"], 31 | "3": ["4", "5"], 32 | "4": ["5"], 33 | "5": [], 34 | } 35 | self.degree_incoming3 = defaultdict(int, {"2": 1, "3": 2, "4": 3, "5": 4}) 36 | self.correct_isDAG3 = True 37 | self.correct_path3 = ["1", "2", "3", "4", "5"] 38 | 39 | self.G4 = { 40 | "1": ["2", "3", "4", "5"], 41 | "2": ["3", "4", "5"], 42 | "3": ["2", "4", "5"], 43 | "4": ["5"], 44 | "5": [], 45 | } 46 | self.degree_incoming4 = defaultdict(int, {"2": 2, "3": 2, "4": 3, "5": 4}) 47 | self.correct_isDAG4 = False 48 | self.correct_path4 = [] 49 | 50 | def test_emptygraph(self): 51 | path_to_take, is_DAG = topological_ordering(self.G1, self.degree_incoming1) 52 | self.assertEqual(path_to_take, self.correct_path1) 53 | self.assertEqual(is_DAG, self.correct_isDAG1) 54 | 55 | def test_clear_ordering(self): 56 | path_to_take, is_DAG = topological_ordering(self.G2, self.degree_incoming2) 57 | self.assertEqual(path_to_take, self.correct_path2) 58 | self.assertEqual(is_DAG, self.correct_isDAG2) 59 | 60 | def test_more_complicated_graph(self): 61 | path_to_take, is_DAG = topological_ordering(self.G3, self.degree_incoming3) 62 | self.assertEqual(path_to_take, self.correct_path3) 63 | self.assertEqual(is_DAG, self.correct_isDAG3) 64 | 65 | def test_no_topological_ordering(self): 66 | path_to_take, is_DAG = topological_ordering(self.G4, self.degree_incoming4) 67 | self.assertEqual(path_to_take, self.correct_path4) 68 | self.assertEqual(is_DAG, self.correct_isDAG4) 69 | 70 | 71 | if __name__ == "__main__": 72 | print("Running Topological Ordering tests:") 73 | unittest.main() 74 | -------------------------------------------------------------------------------- /Algorithm_tests/graphtheory_tests/kruskal_unionfind_test.py: -------------------------------------------------------------------------------- 1 | # Import folder where sorting algorithms 2 | import sys 3 | import unittest 4 | from unionfind import unionfind 5 | 6 | # For importing from different folders 7 | # OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from 8 | sys.path.append("Algorithms/graphtheory/kruskal/") 9 | 10 | # If run from local: 11 | # sys.path.append('../../Algorithms/graphtheory/kruskal/') 12 | from kruskal_unionfind import kruskal 13 | 14 | 15 | class test_Kruskal(unittest.TestCase): 16 | def setUp(self): 17 | # self.G1 = {1:[(10, 2, 1)], 2:[(10, 1, 2), (10, 3, 2)], 3:[(10, 2, 3)]} 18 | self.G1 = [(10, 2, 1), (10, 1, 2), (10, 3, 2), (10, 2, 3)] 19 | self.num_nodes1 = 3 20 | self.correct_cost1 = 20 21 | self.correct_MST1 = [(1, 2, 10), (2, 3, 10)] 22 | 23 | self.G2 = [ 24 | (10, 2, 1), 25 | (10, 3, 1), 26 | (10, 1, 2), 27 | (100, 3, 2), 28 | (10, 1, 3), 29 | (100, 2, 3), 30 | ] 31 | self.num_nodes2 = 3 32 | self.correct_cost2 = 20 33 | self.correct_MST2 = [(1, 2, 10), (1, 3, 10)] 34 | 35 | self.G3 = [ 36 | (1, 2, 1), 37 | (1, 1, 2), 38 | (1, 3, 2), 39 | (1, 4, 3), 40 | (5, 5, 3), 41 | (1, 3, 4), 42 | (1, 5, 4), 43 | (5, 3, 5), 44 | (1, 4, 5), 45 | ] 46 | self.num_nodes3 = 5 47 | self.correct_cost3 = 4 48 | self.correct_MST3 = [(1, 2, 1), (2, 3, 1), (3, 4, 1), (4, 5, 1)] 49 | 50 | self.G4 = [(1, 2, 1), (1, 1, 2), (1, 4, 3), (1, 3, 4)] 51 | self.num_nodes4 = 4 52 | self.correct_cost4 = 2 53 | self.correct_MST4 = [(1, 2, 1), (3, 4, 1)] 54 | 55 | self.G5 = {} 56 | self.num_nodes5 = 0 57 | self.correct_cost5 = 0 58 | self.correct_MST5 = [] 59 | 60 | # Takes as input G which will have {node1: [(cost, to_node, node1), ...], node2:[(...)] } 61 | 62 | def test_linear_graph(self): 63 | MST, cost = kruskal(sorted(self.G1, key=lambda tup: tup[0]), self.num_nodes1) 64 | self.assertEqual(MST, self.correct_MST1) 65 | self.assertEqual(cost, self.correct_cost1) 66 | 67 | def test_triangle_graph(self): 68 | MST, cost = kruskal(sorted(self.G2, key=lambda tup: tup[0]), self.num_nodes2) 69 | self.assertEqual(MST, self.correct_MST2) 70 | self.assertEqual(cost, self.correct_cost2) 71 | 72 | def test_trickier_mst(self): 73 | MST, cost = kruskal(sorted(self.G3, key=lambda tup: tup[0]), self.num_nodes3) 74 | self.assertEqual(MST, self.correct_MST3) 75 | self.assertEqual(cost, self.correct_cost3) 76 | 77 | def test_disconnected_graph(self): 78 | MST, cost = kruskal(sorted(self.G4, key=lambda tup: tup[0]), self.num_nodes4) 79 | self.assertEqual(MST, self.correct_MST4) 80 | self.assertEqual(cost, self.correct_cost4) 81 | 82 | def test_empty_graph(self): 83 | MST, cost = kruskal(self.G5, self.num_nodes5) 84 | self.assertEqual(MST, self.correct_MST5) 85 | self.assertEqual(cost, self.correct_cost5) 86 | 87 | 88 | if __name__ == "__main__": 89 | print("Running Kruskal tests:") 90 | unittest.main() 91 | -------------------------------------------------------------------------------- /Algorithm_tests/graphtheory_tests/prims_algorithm_test.py: -------------------------------------------------------------------------------- 1 | # Import folder where sorting algorithms 2 | import sys 3 | import unittest 4 | 5 | # For importing from different folders 6 | # OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from 7 | sys.path.append("Algorithms/graphtheory/prims/") 8 | 9 | # If run from local: 10 | # sys.path.append('../../Algorithms/graphtheory/prims/') 11 | from prim_heap import prims_algo 12 | 13 | 14 | class test_primsHeap(unittest.TestCase): 15 | def setUp(self): 16 | # How I've decided to construct the graph is confusing, but the reason is because we're using a min heap and 17 | # want first element in the tuple to be the cost of the edge. However when I return the MST, we want it to be 18 | # returned as: from_node, to_node, edge_cost, rather than the reverse for constructing the graph. 19 | 20 | self.G1 = {1: [(10, 2, 1)], 2: [(10, 1, 2), (10, 3, 2)], 3: [(10, 2, 3)]} 21 | self.correct_cost1 = 20 22 | self.correct_MST1 = [(1, 2, 10), (2, 3, 10)] 23 | 24 | self.G2 = { 25 | 1: [(10, 2, 1), (10, 3, 1)], 26 | 2: [(10, 1, 2), (100, 3, 2)], 27 | 3: [(10, 1, 3), (100, 2, 3)], 28 | } 29 | self.correct_cost2 = 20 30 | self.correct_MST2 = [(1, 2, 10), (1, 3, 10)] 31 | 32 | self.G3 = { 33 | 1: [(1, 2, 1)], 34 | 2: [(1, 1, 2), (1, 3, 2)], 35 | 3: [(1, 4, 3), (5, 5, 3)], 36 | 4: [(1, 3, 4), (1, 5, 4)], 37 | 5: [(5, 3, 5), (1, 4, 5)], 38 | } 39 | self.correct_cost3 = 4 40 | self.correct_MST3 = [(1, 2, 1), (2, 3, 1), (3, 4, 1), (4, 5, 1)] 41 | 42 | self.G4 = {1: [(1, 2, 1)], 2: [(1, 1, 2)], 3: [(1, 4, 3)], 4: [(1, 3, 4)]} 43 | self.correct_cost4 = 1 44 | self.correct_MST4 = [(1, 2, 1)] 45 | 46 | self.G5 = {} 47 | self.correct_cost5 = 0 48 | self.correct_MST5 = [] 49 | 50 | # Takes as input G which will have {node1: [(cost, to_node, node1), ...], node2:[(...)] } 51 | 52 | def test_linear_graph(self): 53 | MST, cost = prims_algo(self.G1, start=1) 54 | self.assertEqual(MST, self.correct_MST1) 55 | self.assertEqual(cost, self.correct_cost1) 56 | 57 | def test_triangle_graph(self): 58 | MST, cost = prims_algo(self.G2, start=1) 59 | self.assertEqual(MST, self.correct_MST2) 60 | self.assertEqual(cost, self.correct_cost2) 61 | 62 | def test_trickier_mst(self): 63 | MST, cost = prims_algo(self.G3, start=1) 64 | self.assertEqual(MST, self.correct_MST3) 65 | self.assertEqual(cost, self.correct_cost3) 66 | 67 | def test_disconnected_graph(self): 68 | MST, cost = prims_algo(self.G4, start=1) 69 | self.assertEqual(MST, self.correct_MST4) 70 | self.assertEqual(cost, self.correct_cost4) 71 | 72 | def test_empty_graph(self): 73 | MST, cost = prims_algo(self.G5, start=1) 74 | self.assertEqual(MST, self.correct_MST5) 75 | self.assertEqual(cost, self.correct_cost5) 76 | 77 | 78 | if __name__ == "__main__": 79 | print("Running Prims Heap tests:") 80 | unittest.main() 81 | -------------------------------------------------------------------------------- /Algorithm_tests/graphtheory_tests/test_NN.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import sys 3 | 4 | # Import from different folder 5 | sys.path.append("Algorithms/graphtheory/nearest-neighbor-tsp/") 6 | 7 | import NearestNeighborTSP 8 | 9 | 10 | class TestNN(unittest.TestCase): 11 | def setUp(self): 12 | self.G1 = [[0,3,-1],[3,0,1],[-1,1,0]] 13 | self.correct_path1 = [0,1,2,0] 14 | 15 | # No possible solution for this one so its a dead end 16 | self.G2 = [[0, 2, -1,-1,-1], [2, 0,5,1,-1], [-1, 5, 0, -1, -1],[-1, 1, -1, 0, 3], [-1, -1, -1, 3, 0]] 17 | self.correct_path2 = [0,1,3,4] 18 | 19 | # No possible solution for this one so its a dead end 20 | self.G3 = [[0, 2, -1,-1,-1], [2, 0,5,1,-1], [-1, 5, 0, -1, -1],[-1, 1, -1, 0, -1], [-1, -1, -1, -1, 0]] 21 | self.correct_path3 = [0, 1, 3] 22 | 23 | # Multiple possible solutions 24 | self.G4 = [[0,1,1,1],[1,0,1,1],[1,1,0,1],[1,1,1,0]] 25 | self.correct_path4 = [0, 1, 2, 3, 0] 26 | 27 | 28 | # adjacency matrix of a graph for testing 29 | adjMatrix = [[0,2,5,-1,3],[2,0,2,4,-1],[5,2,0,5,5],[-1,4,5,0,2],[3,-1,5,2,0]] 30 | # correct rank of each node's neighbors 31 | correctNeighbors = [[1,4,2],[0,2,3],[1,0,3,4],[4,1,2],[3,0,2]] 32 | 33 | 34 | def test_0_rankNeighbors(self): 35 | for i in range(0,4): 36 | self.assertEqual(NearestNeighborTSP.rankNeighbors(i, self.adjMatrix), self.correctNeighbors[i], "Check if order is different.") 37 | 38 | 39 | def test_1_nnTSP(self): 40 | path=NearestNeighborTSP.nnTSP(self.adjMatrix) 41 | # Test if path is null 42 | self.assertIsNotNone(path,"Output is empty") 43 | # Test if path is not complete 44 | self.assertEqual(len(path),len(self.adjMatrix)+1,"Path in incomplete") 45 | 46 | 47 | def test_linear_graph(self): 48 | #print(NearestNeighbor.nnTSP(self.G2)) 49 | path = NearestNeighborTSP.nnTSP(self.G1) 50 | self.assertEqual(path,self.correct_path1) 51 | 52 | 53 | def test_simple_graph(self): 54 | path = NearestNeighborTSP.nnTSP(self.G2) 55 | self.assertEqual(path,self.correct_path2) 56 | 57 | 58 | def test_disconnected_graph(self): 59 | path = NearestNeighborTSP.nnTSP(self.G3) 60 | self.assertEqual(path, self.correct_path3) 61 | 62 | 63 | def test_complete_graph(self): 64 | path = NearestNeighborTSP.nnTSP(self.G4) 65 | self.assertEqual(path, self.correct_path4) 66 | 67 | if __name__ == '__main__': 68 | print("Running Nearest Neighbor TSP solver tests:") 69 | unittest.main() -------------------------------------------------------------------------------- /Algorithm_tests/graphtheory_tests/test_graph.txt: -------------------------------------------------------------------------------- 1 | 1 2,5 3,10 2 | 2 4,-5 3 | 3 4,15 -------------------------------------------------------------------------------- /Algorithm_tests/math_tests/intersection_test.py: -------------------------------------------------------------------------------- 1 | # Import folder where sorting algorithms 2 | import sys 3 | import unittest 4 | 5 | # For importing from different folders 6 | # OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from 7 | sys.path.append("Algorithms/math/intersection_of_two_sets") 8 | 9 | # If run from local: 10 | # sys.path.append('../../Algorithms/math/intersection_of_two_sets') 11 | 12 | from intersection_of_two_sets import intersection 13 | 14 | 15 | class test_intersection(unittest.TestCase): 16 | def setUp(self): 17 | # test cases we wish to run 18 | self.L1 = [1, 3, 5, 7, 9, 10] 19 | self.L2 = [2, 4, 6, 11, 12] 20 | self.L1L2_correct = [] 21 | 22 | self.L3 = [1, 3, 5, 10] 23 | self.L4 = [2, 4, 6, 10] 24 | self.L3L4_correct = [10] 25 | 26 | self.L5 = [1, 3, 5, 10] 27 | self.L6 = [1, 4, 6, 11] 28 | self.L5L6_correct = [1] 29 | 30 | self.L7 = [1, 2, 3, 4, 5, 6, 7] 31 | self.L8 = [1, 2, 3, 4, 5, 6, 7] 32 | self.L7L8_correct = [1, 2, 3, 4, 5, 6, 7] 33 | 34 | self.L9 = [] 35 | self.L10 = [] 36 | self.L9L10_correct = [] 37 | 38 | def test_intersection_none(self): 39 | L1L2_output = intersection(self.L1, self.L2) 40 | self.assertEqual(L1L2_output, self.L1L2_correct) 41 | 42 | def test_intersection_lastelement(self): 43 | L3L4_output = intersection(self.L3, self.L4) 44 | self.assertEqual(L3L4_output, self.L3L4_correct) 45 | 46 | def test_intersection_firstelement(self): 47 | L5L6_output = intersection(self.L5, self.L6) 48 | self.assertEqual(L5L6_output, self.L5L6_correct) 49 | 50 | def test_intersection_allequal(self): 51 | L7L8_output = intersection(self.L7, self.L8) 52 | self.assertEqual(L7L8_output, self.L7L8_correct) 53 | 54 | def test_intersection_both_empty(self): 55 | L9L10_output = intersection(self.L9, self.L10) 56 | self.assertEqual(L9L10_output, self.L9L10_correct) 57 | 58 | 59 | if __name__ == "__main__": 60 | print("Running sorting tests:") 61 | unittest.main() 62 | -------------------------------------------------------------------------------- /Algorithm_tests/math_tests/union_test.py: -------------------------------------------------------------------------------- 1 | # Import folder where sorting algorithms 2 | import sys 3 | import unittest 4 | 5 | # For importing from different folders 6 | # OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from 7 | sys.path.append("Algorithms/math/union_of_two_sets") 8 | 9 | # If run from local: 10 | # sys.path.append('../../Algorithms/math/union_of_two_sets') 11 | 12 | from union_of_two_sets import union 13 | 14 | 15 | class test_union(unittest.TestCase): 16 | def setUp(self): 17 | # test cases we wish to run 18 | self.L1 = [1, 3, 5, 7, 9, 10] 19 | self.L2 = [2, 4, 6, 11, 12] 20 | self.L1L2_correct = [1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12] 21 | 22 | self.L3 = [1, 3, 5, 10] 23 | self.L4 = [2, 4, 6, 10] 24 | self.L3L4_correct = [1, 2, 3, 4, 5, 6, 10] 25 | 26 | self.L5 = [1, 3, 5, 10] 27 | self.L6 = [1, 4, 6, 11] 28 | self.L5L6_correct = [1, 3, 4, 5, 6, 10, 11] 29 | 30 | self.L7 = [1, 2, 3, 4, 5, 6, 7] 31 | self.L8 = [1, 2, 3, 4, 5, 6, 7] 32 | self.L7L8_correct = [1, 2, 3, 4, 5, 6, 7] 33 | 34 | self.L9 = [] 35 | self.L10 = [] 36 | self.L9L10_correct = [] 37 | 38 | def test_union_all(self): 39 | L1L2_output = union(self.L1, self.L2) 40 | self.assertEqual(L1L2_output, self.L1L2_correct) 41 | 42 | def test_union_lastequal(self): 43 | L3L4_output = union(self.L3, self.L4) 44 | self.assertEqual(L3L4_output, self.L3L4_correct) 45 | 46 | def test_union_firstequal(self): 47 | L5L6_output = union(self.L5, self.L6) 48 | self.assertEqual(L5L6_output, self.L5L6_correct) 49 | 50 | def test_union_samelist(self): 51 | L7L8_output = union(self.L7, self.L8) 52 | self.assertEqual(L7L8_output, self.L7L8_correct) 53 | 54 | def test_union_both_empty(self): 55 | L9L10_output = union(self.L9, self.L10) 56 | self.assertEqual(L9L10_output, self.L9L10_correct) 57 | 58 | 59 | if __name__ == "__main__": 60 | print("Running sorting tests:") 61 | unittest.main() 62 | -------------------------------------------------------------------------------- /Algorithm_tests/other_tests/test_binarysearch.py: -------------------------------------------------------------------------------- 1 | # Import folder where sorting algorithms 2 | import sys 3 | import unittest 4 | 5 | # For importing from different folders 6 | # OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from 7 | sys.path.append("Algorithms/other") 8 | 9 | # If run from local: 10 | # sys.path.append('../../Algorithms/other') 11 | 12 | from binarysearch import binarysearch_iterative, binarysearch_recursive 13 | 14 | 15 | class test_binarysearch(unittest.TestCase): 16 | def setUp(self): 17 | # test cases we wish to run 18 | self.L1 = [1, 3, 5, 8, 10, 12] 19 | self.L1_target = 5 20 | self.L1_correct = True, 2 21 | 22 | self.L2 = [1, 3, 5, 8, 10, 12] 23 | self.L2_target = 6 24 | self.L2_correct = False, None 25 | 26 | self.L3 = [1, 1, 1, 1, 1, 1, 1, 1] 27 | self.L3_target = 1 28 | self.L3_correct = True, (0 + len(self.L3) - 1) // 2 29 | 30 | self.L4 = [1, 3, 6, 11, 16, 21, 25, 27] 31 | self.L4_target = 27 32 | self.L4_correct = True, len(self.L4) - 1 33 | 34 | self.L5 = [1, 3, 6, 11, 16, 21, 27] 35 | self.L5_target = 1 36 | self.L5_correct = True, 0 37 | 38 | self.L6 = [] 39 | self.L6_target = 10 40 | self.L6_correct = False, None 41 | 42 | self.L7 = [11, 12, 15, 19, 23, 41, 173, 298] 43 | self.L7_target = 12 44 | self.L7_correct = True, 1 45 | 46 | def test_binarysearch_basic(self): 47 | L1_result_iterative = binarysearch_iterative(self.L1, self.L1_target) 48 | L1_result_recursive = binarysearch_recursive( 49 | self.L1, self.L1_target, 0, len(self.L1) - 1 50 | ) 51 | 52 | self.assertEqual(L1_result_iterative, self.L1_correct) 53 | self.assertEqual(L1_result_recursive, self.L1_correct) 54 | 55 | def test_binarysearch_nonexistant(self): 56 | L2_result_iterative = binarysearch_iterative(self.L2, self.L2_target) 57 | L2_result_recursive = binarysearch_recursive( 58 | self.L2, self.L2_target, 0, len(self.L1) - 1 59 | ) 60 | 61 | self.assertEqual(L2_result_iterative, self.L2_correct) 62 | self.assertEqual(L2_result_recursive, self.L2_correct) 63 | 64 | def test_binarysearch_identical(self): 65 | L3_result_iterative = binarysearch_iterative(self.L3, self.L3_target) 66 | L3_result_recursive = binarysearch_recursive( 67 | self.L3, self.L3_target, 0, len(self.L3) - 1 68 | ) 69 | 70 | self.assertEqual(L3_result_iterative, self.L3_correct) 71 | self.assertEqual(L3_result_recursive, self.L3_correct) 72 | 73 | def test_binarysearch_lastvalue(self): 74 | L4_result_iterative = binarysearch_iterative(self.L4, self.L4_target) 75 | L4_result_recursive = binarysearch_recursive( 76 | self.L4, self.L4_target, 0, len(self.L4) - 1 77 | ) 78 | 79 | self.assertEqual(L4_result_iterative, self.L4_correct) 80 | self.assertEqual(L4_result_recursive, self.L4_correct) 81 | 82 | def test_binarysearch_firstvalue(self): 83 | L5_result_iterative = binarysearch_iterative(self.L5, self.L5_target) 84 | L5_result_recursive = binarysearch_recursive( 85 | self.L5, self.L5_target, 0, len(self.L5) - 1 86 | ) 87 | 88 | self.assertEqual(L5_result_iterative, self.L5_correct) 89 | self.assertEqual(L5_result_recursive, self.L5_correct) 90 | 91 | def test_binarysearch_empty(self): 92 | L6_result_iterative = binarysearch_iterative(self.L6, self.L6_target) 93 | L6_result_recursive = binarysearch_recursive( 94 | self.L6, self.L6_target, 0, len(self.L6) - 1 95 | ) 96 | 97 | self.assertEqual(L6_result_iterative, self.L6_correct) 98 | self.assertEqual(L6_result_recursive, self.L6_correct) 99 | 100 | def test_binarysearch_standard(self): 101 | L7_result_iterative = binarysearch_iterative(self.L7, self.L7_target) 102 | L7_result_recursive = binarysearch_recursive( 103 | self.L7, self.L7_target, 0, len(self.L7) - 1 104 | ) 105 | 106 | self.assertEqual(L7_result_iterative, self.L7_correct) 107 | self.assertEqual(L7_result_recursive, self.L7_correct) 108 | 109 | 110 | if __name__ == "__main__": 111 | print("Running sorting tests:") 112 | unittest.main() 113 | -------------------------------------------------------------------------------- /Algorithm_tests/other_tests/test_intervalscheduling.py: -------------------------------------------------------------------------------- 1 | # Import folder where sorting algorithms 2 | import sys 3 | import unittest 4 | 5 | # For importing from different folders 6 | # OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from 7 | sys.path.append("Algorithms/other") 8 | 9 | # If run from local: 10 | # sys.path.append('../../Algorithms/other') 11 | 12 | from interval_scheduling import interval_scheduling 13 | 14 | 15 | class test_intervalscheduling(unittest.TestCase): 16 | def setUp(self): 17 | # test cases we wish to run 18 | self.R1 = [(0, 5), (3, 6), (5, 10)] 19 | self.R1_correct = [(0, 5), (5, 10)] 20 | 21 | self.R2 = [] 22 | self.R2_correct = [] 23 | 24 | self.R3 = [(0, 3), (3, 6), (6, 9), (9, 10)] 25 | self.R3_correct = [(0, 3), (3, 6), (6, 9), (9, 10)] 26 | 27 | self.R4 = [(1, 3), (0, 2), (1, 4), (2, 5)] 28 | self.R4_correct = [(0, 2), (2, 5)] 29 | 30 | self.R5 = [(0, 3)] 31 | self.R5_correct = [(0, 3)] 32 | 33 | def test_intervalscheduling_basic(self): 34 | O = [] 35 | O = interval_scheduling(self.R1, O) 36 | self.assertEqual(O, self.R1_correct) 37 | 38 | def test_intervalscheduling_empty(self): 39 | O = [] 40 | O = interval_scheduling(self.R2, O) 41 | self.assertEqual(O, self.R2_correct) 42 | 43 | def test_intervalscheduling_take_all(self): 44 | O = [] 45 | O = interval_scheduling(self.R3, O) 46 | self.assertEqual(O, self.R3_correct) 47 | 48 | def test_intervalscheduling_unsorted(self): 49 | O = [] 50 | O = interval_scheduling(self.R4, O) 51 | self.assertEqual(O, self.R4_correct) 52 | 53 | def test_intervalscheduling_one_element(self): 54 | O = [] 55 | O = interval_scheduling(self.R5, O) 56 | self.assertEqual(O, self.R5_correct) 57 | 58 | 59 | if __name__ == "__main__": 60 | print("Running Interval Scheduling tests:") 61 | unittest.main() 62 | -------------------------------------------------------------------------------- /Algorithm_tests/other_tests/test_medianmaintenance.py: -------------------------------------------------------------------------------- 1 | # Import packages 2 | import sys 3 | import unittest 4 | 5 | # For importing from different folders 6 | # OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from 7 | sys.path.append("Algorithms/other") 8 | 9 | # If run from local: 10 | # sys.path.append('../../Algorithms/other') 11 | 12 | from median_maintenance import Maintain_Median 13 | 14 | 15 | class MyTestCase(unittest.TestCase): 16 | def setUp(self): 17 | self.data1 = [1, 3, 8, 5, 10] 18 | self.correct1 = 5 19 | 20 | self.data2 = [] 21 | self.correct2 = [] 22 | 23 | self.data3 = [10] 24 | self.correct3 = 10 25 | 26 | self.data4 = [1, 2, 3, 4] 27 | self.correct4 = 2.5 28 | 29 | self.data5 = [1, 10, 2, 9, 11, 4, 6, 5, 3, 8, 7] 30 | self.correct5 = 6 31 | 32 | def test_basic(self): 33 | maintain_median = Maintain_Median() 34 | median = maintain_median.main(self.data1) 35 | self.assertEqual(median, self.correct1) 36 | 37 | def test_empty(self): 38 | maintain_median = Maintain_Median() 39 | median = maintain_median.main(self.data2) 40 | self.assertEqual(median, self.correct2) 41 | 42 | def test_single(self): 43 | maintain_median = Maintain_Median() 44 | median = maintain_median.main(self.data3) 45 | self.assertEqual(median, self.correct3) 46 | 47 | def test_even(self): 48 | maintain_median = Maintain_Median() 49 | median = maintain_median.main(self.data4) 50 | self.assertEqual(median, self.correct4) 51 | 52 | def test_longer_example(self): 53 | maintain_median = Maintain_Median() 54 | median = maintain_median.main(self.data5) 55 | self.assertEqual(median, self.correct5) 56 | 57 | 58 | if __name__ == "__main__": 59 | unittest.main() 60 | -------------------------------------------------------------------------------- /Algorithm_tests/sorting_tests/test_sorting.py: -------------------------------------------------------------------------------- 1 | # Import folder where sorting algorithms 2 | import sys 3 | import unittest 4 | 5 | # For importing from different folders 6 | # OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from 7 | sys.path.append("Algorithms/sorting") 8 | 9 | # If run from local: 10 | # sys.path.append('../../Algorithms/sorting') 11 | 12 | from bubblesort import bubblesort 13 | from insertionsort import insertionsort 14 | from mergesort import merge_sort, merge 15 | from quicksort import quicksort_firstpivot, quicksort_lastpivot 16 | from randomized_quicksort import quicksort_randomized 17 | from selectionsort import selectionsort 18 | 19 | # Test cases we wish to run 20 | L1 = [1, 2, 3, 4, 5, 6, 7, 8, 9] 21 | L1_sorted = [1, 2, 3, 4, 5, 6, 7, 8, 9] 22 | 23 | L2 = [9, 8, 7, 6, 5, 4, 3, 2, 1] 24 | L2_sorted = [1, 2, 3, 4, 5, 6, 7, 8, 9] 25 | 26 | L3 = [1, 1, 1, 1, 1, 1, 1, 1, 1] 27 | L3_sorted = [1, 1, 1, 1, 1, 1, 1, 1, 1] 28 | 29 | L4 = [6, 7, 3, 5, 1, 3] 30 | L4_sorted = [1, 3, 3, 5, 6, 7] 31 | 32 | L5 = [] 33 | L5_sorted = [] 34 | 35 | L6 = [-1, -2, -3] 36 | L6_sorted = [-3, -2, -1] 37 | 38 | L7 = [-5, -7, -1, -3, -4] 39 | L7_sorted = [-7, -5, -4, -3, -1] 40 | 41 | 42 | class test_sorting(unittest.TestCase): 43 | def test_bubblesort(self): 44 | self.assertEqual(bubblesort(L1), L1_sorted) 45 | self.assertEqual(bubblesort(L2), L2_sorted) 46 | self.assertEqual(bubblesort(L3), L3_sorted) 47 | self.assertEqual(bubblesort(L4), L4_sorted) 48 | self.assertEqual(bubblesort(L5), L5_sorted) 49 | self.assertEqual(bubblesort(L6), L6_sorted) 50 | self.assertEqual(bubblesort(L7), L7_sorted) 51 | self.assertEqual(bubblesort(L7), L7_sorted) 52 | 53 | def test_insertionsort(self): 54 | self.assertEqual(insertionsort(L1), L1_sorted) 55 | self.assertEqual(insertionsort(L2), L2_sorted) 56 | self.assertEqual(insertionsort(L3), L3_sorted) 57 | self.assertEqual(insertionsort(L4), L4_sorted) 58 | self.assertEqual(insertionsort(L5), L5_sorted) 59 | self.assertEqual(insertionsort(L6), L6_sorted) 60 | self.assertEqual(insertionsort(L7), L7_sorted) 61 | 62 | def test_mergesort(self): 63 | self.assertEqual(merge_sort(L1), L1_sorted) 64 | self.assertEqual(merge_sort(L2), L2_sorted) 65 | self.assertEqual(merge_sort(L3), L3_sorted) 66 | self.assertEqual(merge_sort(L4), L4_sorted) 67 | self.assertEqual(merge_sort(L5), L5_sorted) 68 | self.assertEqual(merge_sort(L6), L6_sorted) 69 | self.assertEqual(merge_sort(L7), L7_sorted) 70 | 71 | def test_quicksort(self): 72 | self.assertEqual(quicksort_firstpivot(L1), L1_sorted) 73 | self.assertEqual(quicksort_firstpivot(L2), L2_sorted) 74 | self.assertEqual(quicksort_firstpivot(L3), L3_sorted) 75 | self.assertEqual(quicksort_firstpivot(L4), L4_sorted) 76 | self.assertEqual(quicksort_firstpivot(L5), L5_sorted) 77 | self.assertEqual(quicksort_firstpivot(L6), L6_sorted) 78 | self.assertEqual(quicksort_firstpivot(L7), L7_sorted) 79 | 80 | self.assertEqual(quicksort_lastpivot(L1), L1_sorted) 81 | self.assertEqual(quicksort_lastpivot(L2), L2_sorted) 82 | self.assertEqual(quicksort_lastpivot(L3), L3_sorted) 83 | self.assertEqual(quicksort_lastpivot(L4), L4_sorted) 84 | self.assertEqual(quicksort_lastpivot(L5), L5_sorted) 85 | self.assertEqual(quicksort_lastpivot(L6), L6_sorted) 86 | self.assertEqual(quicksort_lastpivot(L7), L7_sorted) 87 | 88 | def test_selectionsort(self): 89 | self.assertEqual(selectionsort(L1), L1_sorted) 90 | self.assertEqual(selectionsort(L2), L2_sorted) 91 | self.assertEqual(selectionsort(L3), L3_sorted) 92 | self.assertEqual(selectionsort(L4), L4_sorted) 93 | self.assertEqual(selectionsort(L5), L5_sorted) 94 | self.assertEqual(selectionsort(L6), L6_sorted) 95 | self.assertEqual(selectionsort(L7), L7_sorted) 96 | 97 | def test_quicksort_randomized(self): 98 | self.assertEqual(quicksort_randomized(L1), L1_sorted) 99 | self.assertEqual(quicksort_randomized(L2), L2_sorted) 100 | self.assertEqual(quicksort_randomized(L3), L3_sorted) 101 | self.assertEqual(quicksort_randomized(L4), L4_sorted) 102 | self.assertEqual(quicksort_randomized(L5), L5_sorted) 103 | self.assertEqual(quicksort_randomized(L6), L6_sorted) 104 | self.assertEqual(quicksort_randomized(L7), L7_sorted) 105 | 106 | 107 | if __name__ == "__main__": 108 | print("Running sorting tests:") 109 | unittest.main() 110 | -------------------------------------------------------------------------------- /Algorithms/cryptology/RSA_algorithm/RSA.py: -------------------------------------------------------------------------------- 1 | """ 2 | Purpose of the RSA cryptosystem is to have a secure way of transmitting data 3 | 4 | Programmed by Aladdin Persson 5 | * 2019-08-26 Initial programming 6 | 7 | """ 8 | 9 | from math import gcd 10 | from sympy import isprime 11 | import random 12 | from euclid_gcd import extended_euclidean 13 | 14 | 15 | def generate_pq(bits): 16 | # Randomly generate two primes p,q 17 | p = random.getrandbits(bits) 18 | q = random.getrandbits(bits) 19 | 20 | # Check if p,q is prime 21 | p_isprime = isprime(p) 22 | q_isprime = isprime(q) 23 | 24 | # Keep generating until both are primes 25 | while not (p_isprime and q_isprime): 26 | if not p_isprime: 27 | p = random.getrandbits(bits) 28 | if not q_isprime: 29 | q = random.getrandbits(bits) 30 | 31 | p_isprime = isprime(p) 32 | q_isprime = isprime(q) 33 | 34 | return p, q 35 | 36 | 37 | def generate_e(totient): 38 | # Generate e such that 1 < e < phi(n) 39 | # phi(n) in this case is totient 40 | 41 | while True: 42 | # Should be (2,totient) so if it is stuck in infinite loop then restart or replace 80000 -> totient 43 | # Reason why I want e to be a low value is to make encryption faster 44 | e = random.randint(2, 50000) 45 | 46 | if gcd(e, totient) == 1: 47 | return e 48 | 49 | 50 | def generate_d(e, totient): 51 | _, e_inverse, _ = extended_euclidean(e, totient) 52 | d = e_inverse % totient 53 | 54 | return d 55 | 56 | 57 | def generate_all_values(): 58 | num_bits = 1024 59 | p, q = generate_pq(num_bits) 60 | totient = (p - 1) * (q - 1) 61 | e = generate_e(totient) 62 | d = generate_d(e, totient) 63 | 64 | print("Generated value n: " + str(p * q)) 65 | print("Generated e and d: " + str(e) + " and " + str(d)) 66 | 67 | return p * q, e, d 68 | 69 | 70 | def encrypt(message, n, e): 71 | encrypted = "" 72 | for letter in message: 73 | pad = 3 - len(str(ord(letter))) 74 | 75 | if pad > 0: 76 | new_letter = "0" * pad + str(ord(letter)) 77 | else: 78 | new_letter = ord(letter) 79 | 80 | encrypted += str(new_letter) 81 | 82 | encrypted = pow(int(encrypted), e, n) 83 | return encrypted 84 | 85 | 86 | def decrypt(encrypted, n, d): 87 | decrypted_message = "" 88 | decrypted_code = str(pow(encrypted, d, n)) 89 | 90 | if len(decrypted_code) % 3 != 0: 91 | decrypted_code = "0" + decrypted_code 92 | 93 | while len(decrypted_code): 94 | decrypted_message += chr(int(decrypted_code[0:3])) 95 | decrypted_code = decrypted_code[3:] 96 | 97 | return decrypted_message 98 | 99 | 100 | def example(): 101 | # An example of a test case where we generate all necessary primes, encrypt and then decrypt the message. 102 | # Only to show how all parts of the code is working. This is not how it's going to be used in practice. 103 | hidden_message = "i really love peanuts" 104 | n, e, d = generate_all_values() 105 | encrypted_message = encrypt(hidden_message, n, e) 106 | decrypted_message = decrypt(encrypted_message, n, d) 107 | 108 | print("\n") 109 | print("Original message: " + hidden_message) 110 | print("Encrypted message: " + str(encrypted_message)) 111 | print("Decrypted message: " + decrypted_message) 112 | 113 | 114 | def main(): 115 | # Write the values of your RSA encryption (Note: Never give the 'd' to someone that doesn't want it) 116 | n = 354089397494626050014776605732143027269473328409397973403863001639624332101789181044818951483060155060788030618162673282176493895463414816015601230408140046833172059490430968956729878861381343553446553025440156523477822105773362480000716985478565013956749662865189691539813391686696182702224364834273144673717742246537383454469146642154754778836797926780437490677663302034284308892191362266103193070200405420180296005388479418941723827243187899338980201782128797489464650981164232057548015010630986959083998487019465357524040595865260220030689502065850060761344148196291328192760801074939658292752592564874822996765430361631210613041006858858506787439506504448316606509551260553919757840169593791152166515571202450662850988377002989153080277915454500432640601643512909764636398157415600050468972065216354878984114648007494687081718749734915103155014825420081658864982423629447913147575382146725524407739875786801876011026010419782863232303861065841801863420557617962438178979549855959377311548527613240676904989886382444381261628076009466895878852398923237601309285642954207693266358989851324012643315688180744573155217352955083176785543099571257338683938756048920161738393295253775030232399282686809347027784971441882883201432807953 117 | e = 9361 118 | # d = 119 | 120 | enc_or_dec = input( 121 | "Would you like to encrypt or decrypt a message (input: 'enc' or 'dec'): " 122 | ) 123 | 124 | if enc_or_dec.lower() == "enc": 125 | hidden_message = input("What is your hidden message?: ") 126 | print("Encrypted message: " + str(encrypt(hidden_message, n, e))) 127 | 128 | elif enc_or_dec.lower() == "dec": 129 | encrypted = input("What is your encrypted message?: ") 130 | print(encrypted) 131 | print("Decrypted message: " + str(decrypt(int(encrypted), n, d))) 132 | 133 | else: 134 | print("Not sure what you typed") 135 | 136 | 137 | main() 138 | -------------------------------------------------------------------------------- /Algorithms/cryptology/RSA_algorithm/__pycache__/euclid_gcd.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aladdinpersson/Algorithms-Collection-Python/266e5608b0c3558c3738ab749e27329010cd9fd6/Algorithms/cryptology/RSA_algorithm/__pycache__/euclid_gcd.cpython-37.pyc -------------------------------------------------------------------------------- /Algorithms/cryptology/RSA_algorithm/euclid_gcd.py: -------------------------------------------------------------------------------- 1 | """ 2 | 3 | 4 | """ 5 | 6 | import sys 7 | 8 | sys.setrecursionlimit(100000) 9 | 10 | 11 | def extended_euclidean(a, b): 12 | if a == 0: 13 | return (b, 0, 1) 14 | 15 | else: 16 | gcd, x, y = extended_euclidean(b % a, a) 17 | return (gcd, y - (b // a) * x, x) 18 | 19 | 20 | if __name__ == "__main__": 21 | print(extended_euclidean(5, -2772)) 22 | # print(extended_euclidean(13, 2640)) 23 | -------------------------------------------------------------------------------- /Algorithms/cryptology/ceasar_shifting_cipher/__pycache__/ceasar_shift_cipher.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aladdinpersson/Algorithms-Collection-Python/266e5608b0c3558c3738ab749e27329010cd9fd6/Algorithms/cryptology/ceasar_shifting_cipher/__pycache__/ceasar_shift_cipher.cpython-37.pyc -------------------------------------------------------------------------------- /Algorithms/cryptology/ceasar_shifting_cipher/ceasar_shift_cipher.py: -------------------------------------------------------------------------------- 1 | """ 2 | The Ceasar cipher is one of the simplest and one of the earliest known ciphers. 3 | It is a type of substitution cipher that 'shifts' a letter by a fixed amount in the alphabet. 4 | 5 | For example with a shift = 3: 6 | a -> d 7 | b -> e 8 | . 9 | . 10 | . 11 | z -> c 12 | 13 | Programmed by Aladdin Persson 14 | * 2019-11-07 Initial programming 15 | 16 | """ 17 | 18 | # This alphabet is of 27 letters since I included a space, but normally it is of 26 letters. 19 | # If you wish to include more letters you need to expand the alphabet used. For example you cannot use '!', '@' now. 20 | alphabet = "abcdefghijklmnopqrstuvwxyz " 21 | letter_to_index = dict(zip(alphabet, range(len(alphabet)))) 22 | index_to_letter = dict(zip(range(len(alphabet)), alphabet)) 23 | 24 | 25 | def encrypt(message, shift=3): 26 | cipher = "" 27 | 28 | for letter in message: 29 | number = (letter_to_index[letter] + shift) % len(letter_to_index) 30 | letter = index_to_letter[number] 31 | cipher += letter 32 | 33 | return cipher 34 | 35 | 36 | def decrypt(cipher, shift=3): 37 | decrypted = "" 38 | 39 | for letter in cipher: 40 | number = (letter_to_index[letter] - shift) % len(letter_to_index) 41 | letter = index_to_letter[number] 42 | decrypted += letter 43 | 44 | return decrypted 45 | 46 | 47 | # def main(): 48 | # message = 'attackatnoon' 49 | # cipher = encrypt(message, shift=3) 50 | # decrypted = decrypt(cipher, shift=3) 51 | # 52 | # print('Original message: ' + message) 53 | # print('Encrypted message: ' + cipher) 54 | # print('Decrypted message: ' + decrypted) 55 | # 56 | # main() 57 | -------------------------------------------------------------------------------- /Algorithms/cryptology/hill_cipher/__pycache__/ceasar_shift_cipher.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aladdinpersson/Algorithms-Collection-Python/266e5608b0c3558c3738ab749e27329010cd9fd6/Algorithms/cryptology/hill_cipher/__pycache__/ceasar_shift_cipher.cpython-37.pyc -------------------------------------------------------------------------------- /Algorithms/cryptology/hill_cipher/__pycache__/euclid_gcd.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aladdinpersson/Algorithms-Collection-Python/266e5608b0c3558c3738ab749e27329010cd9fd6/Algorithms/cryptology/hill_cipher/__pycache__/euclid_gcd.cpython-37.pyc -------------------------------------------------------------------------------- /Algorithms/cryptology/hill_cipher/hill_cipher.py: -------------------------------------------------------------------------------- 1 | """ 2 | Implementation of Hill Cipher! 3 | 4 | Important notation: 5 | K = Matrix which is our 'Secret Key' 6 | P = Vector of plaintext (that has been mapped to numbers) 7 | C = Vector of Ciphered text (in numbers) 8 | 9 | C = E(K,P) = K*P (mod X) -- X is length of alphabet used 10 | P = D(K,C) = inv(K)*C (mod X) -- X is length of alphabet used 11 | 12 | Programmed by Aladdin Persson 13 | * 2019-11-09 Initial programming 14 | """ 15 | 16 | import numpy as np 17 | from egcd import egcd # pip install egcd 18 | 19 | alphabet = "abcdefghijklmnopqrstuvwxyz" 20 | 21 | letter_to_index = dict(zip(alphabet, range(len(alphabet)))) 22 | index_to_letter = dict(zip(range(len(alphabet)), alphabet)) 23 | 24 | 25 | def matrix_mod_inv(matrix, modulus): 26 | """We find the matrix modulus inverse by 27 | Step 1) Find determinant 28 | Step 2) Find determinant value in a specific modulus (usually length of alphabet) 29 | Step 3) Take that det_inv times the det*inverted matrix (this will then be the adjoint) in mod 26 30 | """ 31 | 32 | det = int(np.round(np.linalg.det(matrix))) # Step 1) 33 | det_inv = egcd(det, modulus)[1] % modulus # Step 2) 34 | matrix_modulus_inv = ( 35 | det_inv * np.round(det * np.linalg.inv(matrix)).astype(int) % modulus 36 | ) # Step 3) 37 | 38 | return matrix_modulus_inv 39 | 40 | 41 | def encrypt(message, K): 42 | encrypted = "" 43 | message_in_numbers = [] 44 | 45 | for letter in message: 46 | message_in_numbers.append(letter_to_index[letter]) 47 | 48 | split_P = [ 49 | message_in_numbers[i : i + int(K.shape[0])] 50 | for i in range(0, len(message_in_numbers), int(K.shape[0])) 51 | ] 52 | 53 | for P in split_P: 54 | P = np.transpose(np.asarray(P))[:, np.newaxis] 55 | 56 | while P.shape[0] != K.shape[0]: 57 | P = np.append(P, letter_to_index[" "])[:, np.newaxis] 58 | 59 | numbers = np.dot(K, P) % len(alphabet) 60 | n = numbers.shape[0] # length of encrypted message (in numbers) 61 | 62 | # Map back to get encrypted text 63 | for idx in range(n): 64 | number = int(numbers[idx, 0]) 65 | encrypted += index_to_letter[number] 66 | 67 | return encrypted 68 | 69 | 70 | def decrypt(cipher, Kinv): 71 | decrypted = "" 72 | cipher_in_numbers = [] 73 | 74 | for letter in cipher: 75 | cipher_in_numbers.append(letter_to_index[letter]) 76 | 77 | split_C = [ 78 | cipher_in_numbers[i : i + int(Kinv.shape[0])] 79 | for i in range(0, len(cipher_in_numbers), int(Kinv.shape[0])) 80 | ] 81 | 82 | for C in split_C: 83 | C = np.transpose(np.asarray(C))[:, np.newaxis] 84 | numbers = np.dot(Kinv, C) % len(alphabet) 85 | n = numbers.shape[0] 86 | 87 | for idx in range(n): 88 | number = int(numbers[idx, 0]) 89 | decrypted += index_to_letter[number] 90 | 91 | return decrypted 92 | 93 | 94 | def main(): 95 | # message = 'my life is potato' 96 | message = "help" 97 | 98 | K = np.matrix([[3, 3], [2, 5]]) 99 | # K = np.matrix([[6, 24, 1], [13,16,10], [20,17,15]]) # for length of alphabet = 26 100 | # K = np.matrix([[3,10,20],[20,19,17], [23,78,17]]) # for length of alphabet = 27 101 | Kinv = matrix_mod_inv(K, len(alphabet)) 102 | 103 | encrypted_message = encrypt(message, K) 104 | decrypted_message = decrypt(encrypted_message, Kinv) 105 | 106 | print("Original message: " + message) 107 | print("Encrypted message: " + encrypted_message) 108 | print("Decrypted message: " + decrypted_message) 109 | 110 | 111 | main() 112 | -------------------------------------------------------------------------------- /Algorithms/cryptology/one_time_pad/one_time_pad.py: -------------------------------------------------------------------------------- 1 | """ 2 | Implementation of the famous one time pad / Vernam Cipher 3 | 4 | In practice we need a way to generate random keys which I havn't included. 5 | 6 | Programmed by Aladdin Persson 7 | * 2019-11-12 Initial programming 8 | 9 | """ 10 | 11 | 12 | def xor(s1, s2): 13 | xor_result = [] 14 | 15 | for i in range(min(len(s1), len(s2))): 16 | xor_result.append(int(s1[i]) ^ int(s2[i])) # xor 17 | 18 | return xor_result 19 | 20 | 21 | def encrypt(message, key): 22 | binary_message = "" 23 | binary_key = "" 24 | ciphered_text = "" 25 | 26 | for letter in message: 27 | binary_message += format(ord(letter), "b") 28 | 29 | for letter in key: 30 | binary_key += format(ord(letter), "b") 31 | 32 | cipher_binary = xor(binary_message, binary_key) 33 | 34 | return "".join(str(e) for e in cipher_binary) 35 | 36 | 37 | def decrypt(cipher_text, key): 38 | binary_key = "" 39 | decrypted_text = "" 40 | 41 | for letter in key: 42 | binary_key += format(ord(letter), "b") 43 | 44 | binary_message = xor(cipher_text, binary_key) 45 | 46 | for i in range(0, len(binary_message), 7): 47 | letter = "".join(str(e) for e in binary_message[i : i + 7]) 48 | decrypted_text += chr(int(letter, 2)) 49 | 50 | return decrypted_text 51 | 52 | 53 | def main(): 54 | message = "cheesecake" # 'secret' message 55 | key = "randomrandomrandom" #'random' key 56 | 57 | encrypted = encrypt(message, key) 58 | decrypted = decrypt(encrypted, key) 59 | 60 | print("Original message: " + str(message)) 61 | print("Encrypted message (in binary): " + str(encrypted)) 62 | print("Decrypted message: " + str(decrypted)) 63 | 64 | 65 | if __name__ == "__main__": 66 | main() 67 | -------------------------------------------------------------------------------- /Algorithms/cryptology/vigenere_cipher/vigenere.py: -------------------------------------------------------------------------------- 1 | """ 2 | Vigenère cipher is one of the simplest that employs a form of polyalphabetic substitution (each letter is assigned 3 | more than one substitute). 4 | 5 | It was first described in 1553 but took an entire three centuries to break it in 1863. 6 | 7 | Weakness: If someone finds key length then this can be broken. 8 | 9 | Programmed by Aladdin Persson 10 | * 2019-11-07 Initial programming 11 | 12 | """ 13 | 14 | 15 | alphabet = "abcdefghijklmnopqrstuvwxyz " 16 | 17 | letter_to_index = dict(zip(alphabet, range(len(alphabet)))) 18 | index_to_letter = dict(zip(range(len(alphabet)), alphabet)) 19 | 20 | 21 | def encrypt(message, key): 22 | encrypted = "" 23 | split_message = [ 24 | message[i : i + len(key)] for i in range(0, len(message), len(key)) 25 | ] 26 | 27 | for each_split in split_message: 28 | i = 0 29 | for letter in each_split: 30 | number = (letter_to_index[letter] + letter_to_index[key[i]]) % len(alphabet) 31 | encrypted += index_to_letter[number] 32 | i += 1 33 | 34 | return encrypted 35 | 36 | 37 | def decrypt(cipher, key): 38 | decrypted = "" 39 | split_encrypted = [ 40 | cipher[i : i + len(key)] for i in range(0, len(cipher), len(key)) 41 | ] 42 | 43 | for each_split in split_encrypted: 44 | i = 0 45 | for letter in each_split: 46 | number = (letter_to_index[letter] - letter_to_index[key[i]]) % len(alphabet) 47 | decrypted += index_to_letter[number] 48 | i += 1 49 | 50 | return decrypted 51 | 52 | 53 | def main(): 54 | message = "i loove peanuts" 55 | key = "banana" 56 | encrypted_message = encrypt(message, key) 57 | decrypted_message = decrypt(encrypted_message, key) 58 | 59 | print("Original message: " + message) 60 | print("Encrypted message: " + encrypted_message) 61 | print("Decrypted message: " + decrypted_message) 62 | 63 | 64 | main() 65 | -------------------------------------------------------------------------------- /Algorithms/dynamic_programming/__pycache__/sequence_alignment.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aladdinpersson/Algorithms-Collection-Python/266e5608b0c3558c3738ab749e27329010cd9fd6/Algorithms/dynamic_programming/__pycache__/sequence_alignment.cpython-37.pyc -------------------------------------------------------------------------------- /Algorithms/dynamic_programming/__pycache__/weighted_interval_scheduling.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aladdinpersson/Algorithms-Collection-Python/266e5608b0c3558c3738ab749e27329010cd9fd6/Algorithms/dynamic_programming/__pycache__/weighted_interval_scheduling.cpython-37.pyc -------------------------------------------------------------------------------- /Algorithms/dynamic_programming/knapsack/__pycache__/knapsack_bottomup.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aladdinpersson/Algorithms-Collection-Python/266e5608b0c3558c3738ab749e27329010cd9fd6/Algorithms/dynamic_programming/knapsack/__pycache__/knapsack_bottomup.cpython-37.pyc -------------------------------------------------------------------------------- /Algorithms/dynamic_programming/knapsack/__pycache__/knapsack_memoization_recursive_topdown.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aladdinpersson/Algorithms-Collection-Python/266e5608b0c3558c3738ab749e27329010cd9fd6/Algorithms/dynamic_programming/knapsack/__pycache__/knapsack_memoization_recursive_topdown.cpython-37.pyc -------------------------------------------------------------------------------- /Algorithms/dynamic_programming/knapsack/knapsack_bottomup.py: -------------------------------------------------------------------------------- 1 | """ 2 | Purpose is if having a bunch of items with a weight and corresponding value to each object. 3 | Which collection of objects should we choose such that we maximize the value restricted to 4 | a specific capacity of weight. Bottom up implementation of Knapsack (using loops) 5 | 6 | Time Complexity: O(nC), pseudo-polynomial 7 | 8 | Programmed by Aladdin Persson 9 | 2020-02-15 Initial programming 10 | """ 11 | 12 | 13 | def find_opt(i, c, M, values, items, weights): 14 | if i <= 0 or c <= 0: 15 | return items 16 | 17 | if (M[i - 1][c] >= (values[i - 1] + M[i - 1][c - weights[i - 1]])) or ( 18 | c - weights[i - 1] 19 | ) < 0: 20 | find_opt(i - 1, c, M, values, items, weights) 21 | 22 | else: 23 | items.append(i - 1) 24 | find_opt(i - 1, c - weights[i - 1], M, values, items, weights) 25 | 26 | 27 | def knapsack(n, C, weights, values): 28 | # Initialization of matrix of size (n*W) 29 | M = [[None for i in range(C + 1)] for j in range(len(values) + 1)] 30 | 31 | for c in range(C + 1): 32 | M[0][c] = 0 33 | 34 | for i in range(len(weights) + 1): 35 | M[i][0] = 0 36 | 37 | for i in range(1, n + 1): 38 | for c in range(1, C + 1): 39 | # If current weight exceeds capacity then we cannot take it 40 | if weights[i - 1] > c: 41 | M[i][c] = M[i - 1][c] 42 | 43 | # Else we can take it, then find what gives us the optimal value, either 44 | # taking it or not taking it and we consider what gives us max value of those 45 | else: 46 | M[i][c] = max(M[i - 1][c], values[i - 1] + M[i - 1][c - weights[i - 1]]) 47 | items = [] 48 | 49 | find_opt(n, C, M, values, items, weights) 50 | 51 | return M[n][C], items[::-1] 52 | 53 | 54 | # if __name__ == '__main__': 55 | # # Run small example 56 | # weights = [1,2,4,2,5] 57 | # values = [5,3,5,3,2] 58 | # n = len(weights) 59 | # capacity = 3 60 | # total_value, items = knapsack(n, capacity, weights, values) 61 | # print('Items at the end: ' + str(items)) 62 | # print('With total value: ' + str(total_value)) 63 | -------------------------------------------------------------------------------- /Algorithms/dynamic_programming/knapsack/knapsack_memoization_recursive_topdown.py: -------------------------------------------------------------------------------- 1 | # Memoization implementation Knapsack 2 | 3 | # Purpose is if having a bunch of items with a weight and corresponding value to each object. 4 | # Which collection of objects should we choose such that we maximize the value restricted to 5 | # a specific capacity of weight 6 | 7 | # Programmed by Aladdin Persson 8 | # 2019-02-28 Initial programming 9 | # 2019-03-04 Made code cleaner and included a tracking of which items to choose 10 | 11 | 12 | def knapsack(n, C, W, v, items, arr): 13 | # if n == 0 we cannot index further (since we look at n-1), further if we have no more capacity 14 | # then we cannot obtain more objects 15 | if n == 0 or C == 0: 16 | return 0, [] 17 | 18 | elif arr[n - 1][C - 1] != None: 19 | return arr[n - 1][C - 1], items 20 | 21 | # If the weight is higher than our capacity then we can't pick it 22 | elif W[n - 1] > C: 23 | result, items = knapsack(n - 1, C, W, v, items, arr) 24 | 25 | # Recursively search through all choices 26 | else: 27 | tmp1, items1 = knapsack(n - 1, C, W, v, items, arr) # exclude item 28 | tmp2, items2 = knapsack(n - 1, C - W[n - 1], W, v, items, arr) # include item 29 | 30 | items = items2 + [n - 1] if (tmp2 + v[n - 1] > tmp1) else items1 31 | 32 | result = max(tmp1, tmp2 + v[n - 1]) 33 | 34 | arr[n - 1][C - 1] = result 35 | 36 | return result, items 37 | 38 | 39 | if __name__ == "__main__": 40 | # Run a small example 41 | weight = [1, 2, 4, 2, 5] 42 | value = [5, 3, 5, 3, 2] 43 | num_objects = len(weight) 44 | capacity = 3 45 | 46 | arr = [[None for i in range(capacity)] for j in range(num_objects)] 47 | 48 | total_val_and_items = knapsack(num_objects, capacity, weight, value, []) 49 | print(total_val_and_items) 50 | -------------------------------------------------------------------------------- /Algorithms/dynamic_programming/knapsack/knapsack_naive_recursive.py: -------------------------------------------------------------------------------- 1 | # "Naive" Implementation of the knapsack problem 2 | 3 | # Purpose is if having a bunch of items with a weight and corresponding value to each object. 4 | # Which collection of objects should we choose such that we maximize the value restricted to 5 | # a specific capacity of weight? 6 | 7 | # Programmed by Aladdin Persson 8 | # 2019-02-28 Initial programming 9 | # 2019-03-04 Cleaned up code and included a tracking of which items to choose 10 | 11 | 12 | def knapsack(n, C, W, v, items): 13 | # if n == 0 we cannot index further (since we look at n-1), further if we have no more capacity 14 | # then we cannot obtain more objects 15 | if n == 0 or C == 0: 16 | return 0, [] 17 | 18 | # If the weight is higher than our capacity then we can't pick it 19 | elif W[n - 1] > C: 20 | result, items = knapsack(n - 1, C, W, v, items) 21 | 22 | # Recursively search through all choices 23 | else: 24 | tmp1, items1 = knapsack(n - 1, C, W, v, items) # exclude item 25 | tmp2, items2 = knapsack(n - 1, C - W[n - 1], W, v, items) # include item 26 | 27 | items = items2 + [n - 1] if (tmp2 + v[n - 1] > tmp1) else items1 28 | 29 | result = max(tmp1, tmp2 + v[n - 1]) 30 | 31 | return result, items 32 | 33 | 34 | if __name__ == "__main__": 35 | # Run small example 36 | weight = [1, 2, 4, 2, 5] 37 | value = [5, 3, 5, 3, 2] 38 | num_objects = len(weight) 39 | capacity = 3 40 | 41 | arr = [[None for i in range(capacity)] for j in range(num_objects)] 42 | 43 | total_val_and_items = knapsack(num_objects, capacity, weight, value, []) 44 | print(total_val_and_items) # items = [] 45 | -------------------------------------------------------------------------------- /Algorithms/dynamic_programming/longest_increasing_subsequence.py: -------------------------------------------------------------------------------- 1 | """ 2 | O(n^2) algorithm, can be faster and done in O(nlogn), but this works ok. 3 | To do: Create extensive test cases before adding to algorithm list. 4 | 5 | """ 6 | 7 | 8 | def longest_increasing_subsequence(nums): 9 | if len(nums) == 0: 10 | return 0 11 | 12 | OPT = [1 for i in range(len(nums))] 13 | 14 | for i in range(1, len(nums)): 15 | for j in range(0, i): 16 | if nums[j] < nums[i] and OPT[j] + 1 > OPT[i]: 17 | OPT[i] = OPT[j] + 1 18 | 19 | return max(OPT) 20 | 21 | 22 | if __name__ == "__main__": 23 | # test1 = [1,5,-2,10, 50, -10, 10, 1,2,3,4] 24 | test2 = [10, 1, 2, 11, 3, 5] 25 | # test3 = [10,9,8,5,3,2,1,2,3] 26 | # test4 = [1,5,2,3,4,5,6] 27 | test5 = [] 28 | 29 | print(test2) 30 | print(longest_increasing_subsequence(test2)) 31 | -------------------------------------------------------------------------------- /Algorithms/dynamic_programming/sequence_alignment.py: -------------------------------------------------------------------------------- 1 | """ 2 | Algorithm for solving sequence alignment 3 | Input strings x,y of len(x) = m, len(y) = n and find minimum number of 4 | edit steps and the specific steps to transform x into y. 5 | 6 | Time Complexity: O(nm) 7 | 8 | Video of algorithm explanation: https://youtu.be/bQ7kRW6zo9Y 9 | Video of code explanation: https://youtu.be/XmyxiSc3LKg 10 | 11 | Programmed by Aladdin Persson 12 | 2020-02-15 Initial coding 13 | 2020-02-16 Improved find_solution and made code cleaner 14 | 2020-03-13 There was an error in the code in function find_solution, 15 | I was working with list indexing as if it was a matrix. 16 | Should be working now. Extensive testing would be good. 17 | 18 | 2020-03-28 Cleaned up code by making SequenceAlignment into class 19 | """ 20 | 21 | 22 | class SequenceAlignment(object): 23 | def __init__(self, x, y): 24 | self.x = x 25 | self.y = y 26 | self.solution = [] 27 | 28 | delta = lambda self, x, y, i, j: 1 if x[i] != y[j] else 0 29 | 30 | def find_solution(self, OPT, m, n): 31 | if m == 0 and n == 0: 32 | return 33 | 34 | # We can only do insert if n != 0, align if there are element in both x, y, etc. 35 | insert = OPT[m][n - 1] + 1 if n != 0 else float("inf") 36 | align = ( 37 | OPT[m - 1][n - 1] + self.delta(self.x, self.y, m - 1, n - 1) 38 | if m != 0 and n != 0 39 | else float("inf") 40 | ) 41 | delete = OPT[m - 1][n] + 1 if m != 0 else float("inf") 42 | 43 | best_choice = min(insert, align, delete) 44 | 45 | if best_choice == insert: 46 | self.solution.append("insert_" + str(self.y[n - 1])) 47 | return self.find_solution(OPT, m, n - 1) 48 | 49 | elif best_choice == align: 50 | self.solution.append("align_" + str(self.y[n - 1])) 51 | return self.find_solution(OPT, m - 1, n - 1) 52 | 53 | elif best_choice == delete: 54 | self.solution.append("remove_" + str(self.x[m - 1])) 55 | return self.find_solution(OPT, m - 1, n) 56 | 57 | def alignment(self): 58 | n = len(self.y) 59 | m = len(self.x) 60 | OPT = [[0 for i in range(n + 1)] for j in range(m + 1)] 61 | 62 | for i in range(1, m + 1): 63 | OPT[i][0] = i 64 | 65 | for j in range(1, n + 1): 66 | OPT[0][j] = j 67 | 68 | for i in range(1, m + 1): 69 | for j in range(1, n + 1): 70 | OPT[i][j] = min( 71 | OPT[i - 1][j - 1] + self.delta(self.x, self.y, i - 1, j - 1), 72 | OPT[i - 1][j] + 1, 73 | OPT[i][j - 1] + 1, 74 | ) # align, delete, insert respectively 75 | 76 | self.find_solution(OPT, m, n) 77 | 78 | return (OPT[m][n], self.solution[::-1]) 79 | 80 | 81 | # if __name__ == '__main__': 82 | # x = 'TGACGTGC' 83 | # y = 'TCGACGTCA' 84 | # print('We we want to transform: ' + x + ' to: ' + y) 85 | # sqalign = SequenceAlignment(x, y) 86 | # min_edit, steps = sqalign.alignment() 87 | # print('Minimum amount of edit steps are: ' + str(min_edit)) 88 | # print('And the way to do it is: ' + str(steps)) 89 | -------------------------------------------------------------------------------- /Algorithms/dynamic_programming/weighted_interval_scheduling.py: -------------------------------------------------------------------------------- 1 | """ 2 | Weighted Interval Scheduling 3 | Explained YouTube video: https://www.youtube.com/watch?v=iIX1YvbLbvc 4 | Implementation walkthrough video: https://www.youtube.com/watch?v=dU-coYsd7zw 5 | 6 | Programmed by Aladdin Persson 7 | 2020-02-13 Initial programming 8 | 2020-03-28 Cleaned up code by making WeightedIntervalScheduling class 9 | 10 | Time complexity: O(nlogn) 11 | """ 12 | 13 | import bisect 14 | 15 | 16 | class WeightedIntervalScheduling(object): 17 | def __init__(self, I): 18 | self.I = sorted(I, key=lambda tup: tup[1]) # (key = lambda tup : tup[1]) 19 | self.OPT = [] 20 | self.solution = [] 21 | 22 | def previous_intervals(self): 23 | start = [task[0] for task in self.I] 24 | finish = [task[1] for task in self.I] 25 | p = [] 26 | 27 | for i in range(len(self.I)): 28 | # finds idx for which to input start[i] in finish times to still be sorted 29 | idx = bisect.bisect(finish, start[i]) - 1 30 | p.append(idx) 31 | 32 | return p 33 | 34 | def find_solution(self, j): 35 | if j == -1: 36 | return 37 | 38 | else: 39 | if (self.I[j][2] + self.compute_opt(self.p[j])) > self.compute_opt(j - 1): 40 | self.solution.append(self.I[j]) 41 | self.find_solution(self.p[j]) 42 | 43 | else: 44 | self.find_solution(j - 1) 45 | 46 | def compute_opt(self, j): 47 | if j == -1: 48 | return 0 49 | 50 | elif (0 <= j) and (j < len(self.OPT)): 51 | return self.OPT[j] 52 | 53 | else: 54 | return max( 55 | self.I[j][2] + self.compute_opt(self.p[j]), self.compute_opt(j - 1) 56 | ) 57 | 58 | def weighted_interval(self): 59 | if len(self.I) == 0: 60 | return 0, self.solution 61 | 62 | self.p = self.previous_intervals() 63 | 64 | for j in range(len(self.I)): 65 | opt_j = self.compute_opt(j) 66 | self.OPT.append(opt_j) 67 | 68 | self.find_solution(len(self.I) - 1) 69 | 70 | return self.OPT[-1], self.solution[::-1] 71 | 72 | 73 | # Small Example 74 | # if __name__ == '__main__': 75 | # # They are labeled as: (start, end, weight) 76 | # t1 = (0,3,3) 77 | # t2 = (1,4,2) 78 | # t3 = (0,5,4) 79 | # t4 = (3,6,1) 80 | # t5 = (4,7,2) 81 | # t6 = (3,9,5) 82 | # t7 = (5,10,2) 83 | # t8 = (8,10,1) 84 | # I = [t1,t2,t3,t4,t5,t6,t7,t8] 85 | # weightedinterval = WeightedIntervalScheduling(I) 86 | # max_weight, best_intervals = weightedinterval.weighted_interval() 87 | # print('Maximum weight: ' + str(max_weight)) 88 | # print('The best items to take are: ' + str(best_intervals)) 89 | -------------------------------------------------------------------------------- /Algorithms/graphtheory/bellman-ford/__pycache__/bellman_ford.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aladdinpersson/Algorithms-Collection-Python/266e5608b0c3558c3738ab749e27329010cd9fd6/Algorithms/graphtheory/bellman-ford/__pycache__/bellman_ford.cpython-37.pyc -------------------------------------------------------------------------------- /Algorithms/graphtheory/bellman-ford/bellman_ford.py: -------------------------------------------------------------------------------- 1 | """ 2 | Purpose is to find the shortest path between one source node to all other nodes using Bellman-Ford Algorithm. 3 | The difference between Dijkstra and this is that this can handle negative edges. We do pay for this as it is 4 | a lot slower than Dijkstra. 5 | 6 | Time Complexity: O(mn) 7 | 8 | Programmed by Aladdin Persson 9 | 2019-03-04 Initial programming 10 | """ 11 | 12 | 13 | def bellman_ford(G, start): 14 | """ 15 | :param G: {from_node1: {to_node1, cost1, to_node2, cost2}, from_node2: {etc}} 16 | :param start: node to start from 17 | """ 18 | 19 | if len(G) == 0: 20 | raise ValueError("There should be something in the graph") 21 | 22 | # step1: initialize by setting to infinity etc. 23 | shortest_distance = {} 24 | predecessor = {} 25 | infinity = float("inf") 26 | 27 | for node in G: 28 | shortest_distance[node] = infinity 29 | 30 | shortest_distance[start] = 0 31 | num_vertices = len(G) 32 | 33 | # step2: relax edges 34 | for _ in range(num_vertices - 1): 35 | for from_node in G: 36 | for to_node, weight in G[from_node].items(): 37 | if shortest_distance[from_node] + weight < shortest_distance[to_node]: 38 | shortest_distance[to_node] = shortest_distance[from_node] + weight 39 | predecessor[to_node] = from_node 40 | 41 | # step3: check neg. cycles 42 | for from_node in G: 43 | for to_node, weight in G[from_node].items(): 44 | if shortest_distance[from_node] + weight < shortest_distance[to_node]: 45 | shortest_distance[to_node] = -infinity 46 | 47 | return shortest_distance, predecessor 48 | 49 | 50 | # if __name__ == '__main__': 51 | # G = {1: {2: -10, 3: 20}, 52 | # 2: {4: 40}, 53 | # 3: {4: 5}, 54 | # 4: {}} 55 | # 56 | # print(f'Current graph is: {G}') 57 | # shortest, predecessor = bellman_ford(G, 1) 58 | # print(shortest) 59 | -------------------------------------------------------------------------------- /Algorithms/graphtheory/breadth-first-search/BFS_queue_iterative.py: -------------------------------------------------------------------------------- 1 | """ 2 | Programmed by Aladdin Persson 3 | 2019-02-17 Initial programming 4 | 2020-03-29 Cleaned up code, removed load graph, I think a small example is sufficient 5 | and instead only have the BFS function. 6 | """ 7 | 8 | from collections import deque 9 | 10 | 11 | def BFS(G, start_node=1): 12 | """ 13 | :param G: Graph with G = {from_node1:[to_node1, to_node2], from_node2: [to_node,] etc} 14 | :param start_node: starting node to run BFS from 15 | :return: returns visited boolean array and path in which order it visited them 16 | """ 17 | visited = [False for i in range(1, len(G) + 1)] 18 | 19 | Q = deque() 20 | Q.append(start_node) 21 | 22 | path = [] 23 | 24 | while Q: 25 | curr_node = Q.popleft() 26 | path.append(curr_node) 27 | 28 | if not visited[curr_node - 1]: 29 | visited[curr_node - 1] = True 30 | 31 | for connected_node in G[curr_node]: 32 | if not visited[connected_node - 1]: 33 | Q.append(connected_node) 34 | 35 | return visited, path 36 | 37 | 38 | # Small Example Run 39 | # if __name__ == '__main__': 40 | # G = {1:[2,3], 2:[1,4], 3:[1,4],4:[]} 41 | # visited, path = BFS(G) 42 | # 43 | # if all(visited) == True: 44 | # print("Return: This graph is connected!") 45 | 46 | # else: 47 | # print("Not all nodes were reachable, i.e the graph is not connected.") 48 | -------------------------------------------------------------------------------- /Algorithms/graphtheory/breadth-first-search/__pycache__/BFS_queue_iterative.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aladdinpersson/Algorithms-Collection-Python/266e5608b0c3558c3738ab749e27329010cd9fd6/Algorithms/graphtheory/breadth-first-search/__pycache__/BFS_queue_iterative.cpython-37.pyc -------------------------------------------------------------------------------- /Algorithms/graphtheory/breadth-first-search/exgraph.txt: -------------------------------------------------------------------------------- 1 | 1 37 79 164 155 32 87 39 113 15 18 78 175 140 200 4 160 97 191 100 91 20 69 198 196 2 | 2 123 134 10 141 13 12 43 47 3 177 101 179 77 182 117 116 36 103 51 154 162 128 30 3 | 3 48 123 134 109 41 17 159 49 136 16 130 141 29 176 2 190 66 153 157 70 114 65 173 104 194 54 4 | 4 91 171 118 125 158 76 107 18 73 140 42 193 127 100 84 121 60 81 99 80 150 55 1 35 23 93 5 | 5 193 156 102 118 175 39 124 119 19 99 160 75 20 112 37 23 145 135 146 73 35 6 | 6 155 56 52 120 131 160 124 119 14 196 144 25 75 76 166 35 87 26 20 32 23 7 | 7 156 185 178 79 27 52 144 107 78 22 71 26 31 15 56 76 112 39 8 113 93 8 | 8 185 155 171 178 108 64 164 53 140 25 100 133 9 52 191 46 20 150 144 39 62 131 42 119 127 31 7 9 | 9 91 155 8 160 107 132 195 26 20 133 39 76 100 78 122 127 38 156 191 196 115 10 | 10 190 184 154 49 2 182 173 170 161 47 189 101 153 50 30 109 177 148 179 16 163 116 13 90 185 11 | 11 123 134 163 41 12 28 130 13 101 83 77 109 114 21 82 88 74 24 94 48 33 12 | 12 161 109 169 21 24 36 65 50 2 101 159 148 54 192 88 47 11 142 43 70 182 177 179 189 194 33 13 | 13 161 141 157 44 83 90 181 41 2 176 10 29 116 134 182 170 165 173 190 159 47 82 111 142 72 154 110 21 103 130 11 33 138 152 14 | 14 91 156 58 122 62 113 107 73 137 25 19 40 6 139 150 46 37 76 39 127 15 | 15 149 58 68 52 39 67 121 191 1 45 100 18 118 174 40 85 196 122 42 193 119 139 26 127 145 135 57 38 7 16 | 16 48 10 36 187 43 3 114 173 111 142 129 88 189 117 128 147 141 194 180 106 167 179 66 74 136 51 59 17 | 17 48 123 134 36 163 3 44 117 167 161 152 95 170 83 180 77 65 72 109 47 43 88 159 197 28 194 181 49 18 | 18 193 149 56 62 15 160 67 191 140 52 178 96 107 132 1 145 89 198 4 26 73 151 126 34 115 19 | 19 156 80 178 164 108 84 71 174 40 62 113 22 89 45 91 126 195 144 5 14 172 20 | 20 185 122 171 56 8 52 73 191 67 126 9 119 1 89 79 107 96 31 75 55 5 6 34 23 21 | 21 188 187 12 173 180 197 138 167 63 111 95 13 192 116 94 114 105 49 177 51 130 90 11 50 66 157 176 22 | 22 156 27 32 131 7 56 53 81 149 23 100 146 115 26 175 121 96 75 57 39 119 71 132 19 150 140 93 23 | 23 91 122 124 22 200 195 145 5 69 125 55 68 156 20 58 191 4 57 149 6 24 | 24 123 134 161 163 169 72 116 167 30 33 77 162 143 159 187 63 184 130 28 50 153 12 148 11 53 25 | 25 193 185 79 108 8 158 87 73 81 115 39 64 178 132 27 68 127 84 14 52 200 97 6 93 26 | 26 193 58 27 108 52 144 160 18 84 81 22 75 139 166 15 107 198 131 7 9 133 6 27 | 27 156 139 144 166 112 100 26 174 31 42 75 158 122 81 22 7 58 73 89 115 39 25 200 69 169 28 | 28 134 188 24 184 159 29 72 114 152 116 169 173 141 17 111 61 192 90 11 177 179 77 33 66 83 136 29 | 29 48 134 188 13 47 88 3 82 92 28 194 50 192 189 123 199 177 147 43 106 148 197 77 103 129 181 30 | 30 165 123 10 24 41 187 47 168 92 148 197 101 50 2 179 111 130 77 153 199 70 31 | 31 27 171 56 131 146 139 191 89 20 108 38 71 75 69 196 149 97 8 86 98 7 32 | 32 156 149 171 62 22 185 35 124 56 38 158 97 53 121 160 1 191 58 89 127 87 120 39 99 84 60 151 174 6 33 | 33 48 161 109 141 24 187 47 88 168 183 110 103 95 116 28 12 11 13 83 134 63 34 | 34 37 122 171 118 76 131 166 137 40 46 97 87 80 164 127 18 62 52 20 139 35 | 35 79 164 125 32 107 137 75 121 85 55 69 45 193 132 4 5 200 135 76 139 198 6 36 | 36 165 188 17 106 88 16 177 110 147 154 159 179 136 41 50 141 66 162 152 168 184 12 43 72 180 190 77 2 170 61 122 37 | 37 193 149 39 121 191 115 146 52 127 79 198 58 125 38 34 1 76 89 164 97 86 178 108 87 84 124 98 174 195 14 5 57 196 186 38 | 38 193 37 86 32 76 107 73 85 127 100 46 89 31 57 96 158 99 160 45 15 9 39 | 39 193 37 122 102 8 158 32 87 85 81 200 60 5 27 155 1 58 150 15 113 76 84 22 25 151 139 100 14 145 9 7 40 | 40 91 156 122 79 118 125 52 175 87 15 81 166 132 121 19 14 160 34 78 71 41 | 41 36 169 184 116 163 106 189 11 104 61 30 123 129 111 3 47 49 154 161 152 13 153 65 92 183 177 162 95 54 70 108 42 | 42 178 79 27 53 171 164 102 52 87 113 15 191 131 91 62 193 8 122 89 56 4 127 145 112 43 | 43 165 161 12 70 199 54 17 190 16 153 141 36 47 44 194 110 82 189 2 148 183 29 130 94 170 51 61 59 44 | 44 188 163 169 17 13 43 114 173 142 154 103 129 181 105 157 148 182 101 110 66 176 49 45 | 45 156 80 149 58 178 53 108 68 56 125 15 93 75 135 174 198 81 166 113 100 19 89 35 97 38 46 | 46 193 58 86 122 155 8 175 160 99 127 67 14 150 144 126 146 34 131 55 38 196 47 | 47 123 10 109 41 17 12 43 116 59 33 13 2 187 165 88 117 29 30 176 147 180 101 130 194 50 94 152 70 48 | 48 180 128 188 197 105 51 94 190 116 29 183 114 153 33 16 49 3 63 184 17 141 168 179 162 11 66 83 193 49 | 49 48 123 10 186 141 41 168 3 148 142 179 21 136 109 44 117 17 103 187 74 50 | 50 165 123 10 188 36 169 24 187 12 65 29 167 47 21 134 130 111 168 77 116 138 106 66 30 51 | 51 165 48 109 141 163 159 92 190 143 2 21 138 43 59 192 117 16 184 104 169 52 | 52 37 178 8 6 15 200 133 80 102 96 40 119 164 166 127 151 20 42 7 26 76 18 73 99 78 25 132 139 191 150 34 53 | 53 156 122 102 193 137 133 42 62 45 64 60 78 160 132 155 56 144 131 196 178 125 8 32 113 22 98 121 198 24 54 | 54 123 187 12 43 168 65 129 130 147 95 41 61 59 141 3 138 114 199 66 110 55 | 55 68 56 125 113 73 78 200 46 131 85 107 89 185 60 84 4 35 99 171 71 20 23 56 | 56 193 122 53 108 45 55 18 125 86 171 79 6 85 133 80 140 96 31 107 20 32 87 120 42 73 84 22 112 196 7 57 | 57 79 155 158 76 84 22 75 121 85 191 100 97 15 37 102 69 38 64 195 145 23 58 | 58 15 146 107 193 140 84 144 86 14 150 26 60 46 166 80 87 139 195 126 45 37 27 102 62 32 175 39 124 23 93 188 59 | 59 186 163 187 47 168 92 143 147 157 54 51 61 199 43 103 63 184 16 188 197 60 | 60 58 86 178 53 171 125 39 144 146 73 124 4 93 32 99 158 132 80 91 96 75 174 55 196 61 | 61 188 116 41 114 183 28 77 54 36 163 187 147 179 65 63 190 43 186 59 189 62 | 62 193 185 79 53 171 102 146 84 198 14 58 137 8 166 175 32 113 18 115 196 42 200 132 121 19 112 133 172 34 63 | 63 48 24 116 183 111 167 21 162 90 181 147 105 106 101 33 123 153 184 128 168 61 59 64 | 64 91 149 122 53 8 120 113 124 119 25 132 131 193 121 144 68 185 108 175 107 57 65 | 65 186 17 12 114 82 3 66 159 167 197 50 101 176 94 54 134 41 165 157 194 180 77 103 74 61 66 | 66 188 36 116 3 65 183 72 180 77 16 136 177 82 159 28 95 48 50 187 21 44 54 176 67 | 67 91 156 102 68 175 131 144 15 18 146 119 20 200 46 112 139 75 80 86 137 68 | 68 122 171 55 78 175 96 75 71 93 118 195 115 67 79 45 158 15 120 155 193 87 146 81 25 64 23 69 | 69 91 108 125 131 81 75 85 174 145 89 27 200 35 156 1 98 86 23 191 127 31 57 70 | 70 165 123 163 153 12 43 168 3 114 82 148 190 129 74 176 47 110 181 41 30 71 | 71 193 79 171 68 124 98 120 73 75 93 151 108 89 155 19 96 22 119 7 125 85 127 40 55 140 31 72 | 72 109 169 24 116 17 114 182 190 141 186 192 28 104 13 66 165 162 36 159 77 110 129 130 181 73 | 73 91 80 27 160 4 20 100 56 193 60 38 18 25 172 76 14 55 52 149 96 78 71 195 127 5 112 97 93 74 | 74 88 104 197 111 130 95 11 138 123 77 159 65 179 94 165 70 141 16 153 136 83 49 75 | 75 91 79 27 171 68 158 87 81 22 119 71 166 57 60 35 160 69 175 26 193 45 127 67 126 89 20 5 31 198 6 76 | 76 37 178 175 120 122 57 52 34 4 156 98 115 133 131 171 149 85 38 174 39 73 99 14 140 35 135 172 9 7 6 77 | 77 24 116 17 72 190 110 36 173 143 94 65 29 61 154 2 161 90 66 159 28 128 117 11 50 138 74 30 78 | 78 156 80 53 164 68 131 144 107 73 195 55 175 1 126 7 149 171 81 91 52 124 40 9 79 | 79 80 37 158 40 75 108 198 25 62 42 7 86 57 102 122 145 175 71 1 35 164 68 118 56 144 200 139 20 112 135 172 163 80 | 80 91 144 100 118 45 78 139 112 149 98 113 87 195 124 85 73 119 19 79 99 58 56 52 146 81 4 60 137 67 126 145 97 34 134 81 | 81 86 27 120 39 131 40 132 25 69 96 26 127 108 75 68 135 98 80 115 149 78 22 4 45 172 82 | 82 161 186 109 153 43 159 114 101 104 70 29 197 192 116 148 65 152 184 13 154 92 110 130 11 147 66 176 83 | 83 17 13 153 88 111 90 117 95 11 33 147 28 109 199 48 74 167 182 154 101 84 | 84 149 58 86 178 171 62 175 113 26 135 96 198 39 19 57 144 37 118 32 56 119 4 98 25 200 150 55 85 | 85 156 80 185 155 102 56 158 39 76 15 69 38 150 175 118 137 71 35 120 57 55 135 86 | 86 58 84 120 81 112 37 60 46 185 193 38 125 118 175 149 99 108 126 133 102 79 56 144 67 69 31 109 87 | 87 80 149 58 118 25 75 126 115 68 178 37 200 32 40 164 56 42 193 107 1 39 113 145 89 172 6 34 93 88 | 88 36 116 12 47 165 168 29 83 159 154 74 148 92 176 180 33 110 194 167 17 114 173 16 11 89 | 89 37 27 102 32 42 18 99 71 151 19 55 75 98 131 69 45 31 38 195 87 20 135 115 90 | 90 163 116 13 173 28 110 190 77 129 117 130 10 179 92 134 194 21 63 83 157 94 152 199 91 | 91 126 14 75 135 107 80 102 67 160 158 144 23 64 155 4 198 40 9 73 69 193 185 149 164 42 78 60 98 19 1 165 92 | 92 161 109 163 187 88 186 141 51 117 197 59 173 192 82 29 143 116 41 30 111 148 129 90 194 152 170 93 | 93 68 99 71 60 45 150 145 98 25 87 122 178 185 7 144 4 22 73 58 112 94 | 94 48 163 65 173 182 154 77 21 117 11 147 74 189 43 114 47 177 192 104 90 95 | 95 123 141 169 17 168 114 179 21 33 165 167 177 41 103 83 199 129 182 188 74 66 157 152 54 176 96 | 96 171 164 68 56 52 18 73 84 81 124 22 71 60 126 150 20 97 38 149 158 196 115 97 | 97 185 149 37 178 122 108 118 32 131 1 31 140 73 34 45 25 80 133 57 96 98 | 98 80 171 164 158 120 76 99 81 71 37 91 151 144 172 140 150 160 121 84 53 139 89 69 31 133 93 99 | 99 80 86 178 122 118 125 52 193 32 174 46 113 98 93 89 150 102 76 100 124 4 60 55 5 38 196 100 | 100 80 185 149 27 8 113 131 15 73 99 22 4 200 45 102 172 57 164 38 39 1 112 9 101 | 101 165 10 188 109 141 163 187 12 168 82 65 148 180 47 167 2 162 169 192 30 179 11 44 83 170 63 102 | 102 91 86 79 53 171 155 67 113 39 137 158 196 166 120 42 89 58 5 119 85 62 52 146 99 121 100 57 103 | 103 161 188 186 184 153 159 167 189 2 168 13 29 104 142 33 65 197 117 148 44 95 181 59 49 104 | 104 134 188 186 141 184 41 187 168 114 82 148 192 194 154 74 3 190 161 105 163 72 103 94 170 51 105 | 105 165 48 161 116 159 104 21 129 63 44 169 106 142 190 181 143 179 157 173 188 199 176 106 | 106 36 163 169 184 41 159 29 197 111 16 179 162 105 138 148 50 165 63 173 109 107 | 107 91 58 56 125 158 87 191 133 9 38 122 164 175 135 4 35 14 7 185 78 18 146 151 26 64 126 55 20 112 198 172 108 | 108 86 178 79 164 37 25 195 144 120 198 26 56 19 132 69 193 115 45 172 97 155 8 81 71 166 139 174 64 31 41 109 | 109 10 47 116 12 128 51 167 180 179 33 123 101 142 92 143 199 154 3 72 82 141 17 168 114 173 183 148 189 11 181 106 83 152 49 86 110 | 110 165 186 36 163 169 43 88 168 33 138 147 13 167 189 184 134 72 90 188 82 77 44 54 70 111 | 111 41 92 114 162 188 129 187 170 152 83 142 74 157 16 13 138 186 106 63 184 28 21 50 30 192 112 | 112 193 80 86 27 137 174 67 5 79 198 132 127 42 131 100 73 107 56 135 62 7 93 113 | 113 156 80 149 171 102 62 39 133 84 87 198 1 53 64 55 172 122 100 42 14 160 99 124 137 45 19 145 7 114 | 114 48 104 136 16 61 72 181 128 82 88 138 109 129 70 192 3 153 65 95 44 111 28 21 11 94 54 115 | 115 185 37 27 108 68 62 87 120 76 81 22 25 151 139 191 140 9 89 96 18 116 | 116 48 188 109 24 157 61 41 181 128 66 88 63 152 189 168 90 105 72 77 10 13 47 82 173 92 142 28 180 2 21 117 50 33 136 164 117 | 117 17 47 92 16 179 2 103 90 194 189 192 94 143 170 162 83 116 129 184 77 138 152 51 49 118 | 118 193 156 80 86 155 68 196 145 40 4 97 79 5 99 87 149 174 34 137 166 131 15 160 84 121 85 119 | 119 80 178 102 52 160 124 84 185 6 22 67 174 8 121 133 5 75 64 15 150 71 151 145 20 120 | 120 185 86 171 108 102 68 200 193 126 64 160 32 150 6 115 98 81 56 191 76 124 71 139 85 195 135 121 | 121 156 185 37 32 15 146 22 119 4 98 151 57 62 126 53 139 40 102 35 118 64 135 133 122 | 122 156 146 23 99 196 46 14 56 53 175 164 20 68 39 195 126 97 40 34 64 79 27 155 113 76 131 15 42 107 166 151 9 93 36 123 | 123 165 194 50 70 95 11 153 30 24 17 49 47 54 2 189 147 199 3 188 197 186 109 41 29 129 130 128 74 136 63 156 124 | 124 193 80 125 32 146 99 23 5 60 113 120 191 6 58 64 119 71 37 78 96 137 125 | 125 37 86 56 4 133 69 178 132 53 172 45 60 151 40 198 55 35 107 99 124 71 137 127 23 126 | 126 91 58 86 122 155 87 120 146 78 200 121 19 80 20 137 75 96 107 18 156 46 135 127 | 127 37 178 32 52 131 160 81 4 25 191 125 38 71 15 8 42 75 46 174 73 14 69 112 172 9 34 128 | 128 48 134 161 109 116 187 114 183 16 179 189 130 181 142 123 138 2 136 77 152 63 129 | 129 165 184 41 153 114 148 111 177 16 180 44 29 123 54 173 72 92 70 199 105 90 117 95 157 130 | 130 186 169 24 3 154 189 21 136 72 82 74 190 11 47 13 173 54 181 43 123 90 128 50 138 30 176 131 | 131 193 53 76 78 22 69 97 118 178 122 140 81 34 164 8 100 127 67 31 6 42 146 200 195 26 64 46 55 89 112 132 | 132 185 149 53 171 108 125 18 81 60 25 139 191 178 64 52 9 62 22 40 164 35 112 133 | 133 86 53 56 125 8 52 113 76 107 119 195 97 156 98 121 62 140 26 175 9 134 | 134 153 11 17 182 165 197 138 173 24 28 104 128 29 2 167 152 183 3 162 154 186 13 65 142 110 90 50 33 157 80 135 | 135 91 171 164 107 84 81 45 5 35 112 120 15 151 85 76 79 178 121 126 89 136 | 136 165 36 187 3 114 173 190 130 128 66 74 152 123 154 116 28 49 153 16 169 137 | 137 156 185 53 155 102 118 62 166 175 200 151 112 113 14 124 80 146 35 125 34 85 67 126 145 172 138 | 138 134 186 153 114 111 142 110 179 21 128 130 117 197 169 77 13 74 51 180 50 106 54 139 | 139 80 58 27 164 132 121 108 115 140 31 79 98 15 160 52 26 171 39 195 120 67 14 35 196 34 140 | 140 185 58 56 8 175 131 144 18 4 166 98 139 1 195 22 156 71 76 178 115 97 133 141 | 141 109 104 184 2 143 188 51 49 33 197 48 176 95 159 148 101 154 13 170 190 36 43 3 92 72 16 28 167 180 147 74 54 178 142 | 142 161 109 169 12 183 111 163 187 162 180 16 165 116 184 138 44 13 49 134 143 177 103 128 181 105 192 143 | 143 165 161 109 141 24 184 168 92 142 154 180 51 147 179 176 183 189 59 159 167 77 117 105 152 144 | 144 91 80 58 178 27 53 164 108 8 158 60 79 67 155 78 140 7 86 26 174 84 98 64 19 46 145 6 93 145 | 145 178 79 155 118 18 151 69 39 113 42 119 93 80 144 87 15 137 23 158 166 5 57 172 146 | 146 149 58 37 122 62 60 68 107 31 67 172 195 121 131 102 185 174 124 126 80 22 137 46 5 147 | 147 123 186 36 47 183 29 182 197 16 167 110 143 168 83 82 141 63 94 54 59 157 170 61 148 | 148 10 188 186 141 163 12 43 88 82 109 192 70 161 30 129 24 92 49 177 29 104 197 154 101 103 162 181 106 44 176 149 | 149 156 80 200 146 15 185 87 91 100 45 37 178 18 32 64 132 97 84 150 113 86 118 76 73 81 78 22 31 96 23 161 150 | 150 149 58 8 175 120 39 99 119 166 98 200 85 14 4 46 96 84 22 93 52 151 | 151 125 52 160 71 166 98 137 145 122 171 119 193 175 32 121 107 115 18 39 89 135 196 152 | 152 134 161 36 116 41 17 82 111 28 128 157 13 92 47 143 117 109 90 95 136 170 153 | 153 165 48 123 134 10 186 138 187 103 82 70 163 129 188 170 173 24 83 167 41 43 3 114 154 180 74 136 63 30 154 | 154 134 10 109 141 36 41 88 159 82 104 143 148 197 44 13 94 130 162 177 153 167 77 2 83 136 170 155 | 155 91 185 53 164 108 145 171 200 6 122 8 9 85 57 1 137 126 102 118 46 68 158 39 144 160 71 172 156 | 156 7 53 113 45 14 193 122 40 67 19 121 22 118 78 5 137 166 149 32 85 178 27 158 76 126 140 69 133 9 23 123 157 | 157 184 116 13 3 65 111 90 105 187 147 152 134 59 95 186 197 44 170 129 21 158 | 158 91 193 79 27 102 68 32 75 156 107 185 144 4 57 39 155 98 171 85 25 175 60 145 38 96 159 | 159 188 141 36 24 13 12 88 103 105 179 177 17 3 182 51 82 28 161 154 106 65 183 72 143 77 66 74 160 | 160 91 185 53 32 120 155 6 9 18 127 171 118 113 119 151 26 46 195 200 73 98 75 139 40 1 5 198 38 161 | 161 165 10 24 173 142 182 162 92 13 152 33 82 189 43 143 128 103 186 105 12 188 184 41 17 159 148 104 180 77 194 170 149 162 | 162 134 161 188 186 36 24 173 182 111 142 72 154 101 48 148 2 179 106 63 41 117 163 | 163 177 92 10 148 101 44 169 59 110 188 17 51 90 186 94 11 24 70 106 182 41 153 187 104 142 190 61 79 164 | 164 185 37 122 175 139 144 91 35 19 96 98 78 155 1 108 198 42 135 79 195 8 52 87 131 107 166 132 100 34 116 165 | 165 30 105 36 101 167 183 43 50 70 189 181 190 161 123 136 51 143 129 153 110 134 169 13 47 88 65 142 72 95 106 74 91 166 | 166 156 58 27 102 118 62 52 191 140 164 40 122 151 108 75 174 137 196 150 34 200 45 26 145 6 167 | 167 165 134 109 24 17 153 187 88 168 65 182 177 154 16 194 141 103 50 147 63 110 101 179 143 21 95 83 168 | 168 36 169 116 88 48 70 30 33 101 104 109 110 143 181 167 54 199 49 59 95 177 180 103 50 147 63 169 | 169 163 50 184 12 176 106 41 194 173 168 110 142 44 95 130 24 165 182 72 177 197 28 101 138 105 136 51 27 170 | 170 10 186 141 17 13 153 111 117 157 92 161 152 147 104 179 154 43 101 36 199 171 | 171 34 60 68 31 20 42 62 4 120 71 32 135 113 175 84 102 132 96 98 75 155 56 8 158 76 160 78 151 139 55 184 172 | 172 185 108 125 113 146 73 98 174 100 155 81 79 76 127 87 137 107 19 62 145 173 | 173 134 10 161 169 13 153 109 162 44 21 88 182 3 190 179 136 90 16 116 94 92 28 77 129 130 105 106 174 | 174 27 118 175 76 144 15 146 99 119 166 45 32 19 172 191 60 108 37 69 112 127 175 | 175 86 122 79 171 164 68 62 84 140 5 40 196 46 174 150 67 58 76 193 158 107 78 22 137 75 151 85 195 64 1 133 176 | 176 141 169 13 47 88 3 65 183 177 143 148 82 105 130 66 181 44 21 182 95 70 177 | 177 10 36 163 169 159 29 148 190 12 199 167 176 180 2 192 168 142 41 179 129 154 28 21 95 66 94 178 | 178 149 76 19 52 127 108 45 156 60 198 99 37 144 7 97 145 84 119 42 191 53 125 8 87 131 18 25 132 195 140 135 93 141 179 | 179 10 109 36 159 173 177 49 117 12 48 101 189 2 138 128 95 106 28 167 16 143 162 90 105 74 170 199 30 61 180 | 180 48 109 17 88 142 177 16 65 194 36 153 116 161 66 143 141 129 47 168 21 101 181 138 181 | 181 165 188 184 116 13 168 114 182 130 128 44 103 148 63 29 142 180 17 109 72 105 176 70 182 | 182 134 10 161 163 169 184 13 159 173 183 147 189 162 181 12 72 167 94 199 192 2 95 44 83 176 183 | 183 165 48 134 188 186 63 33 147 43 61 109 142 159 66 41 128 182 176 190 184 143 189 184 | 184 48 10 141 169 24 143 41 161 181 36 129 197 104 186 182 28 106 157 103 199 82 183 111 142 110 117 63 51 59 171 185 | 185 193 140 8 97 7 121 160 155 85 172 91 100 164 132 25 120 20 62 137 115 149 86 32 158 107 146 119 64 55 93 10 186 | 186 161 104 199 162 148 110 138 183 153 103 192 82 130 123 59 49 147 134 65 170 163 184 187 92 197 111 72 157 61 37 187 | 187 24 153 186 92 189 54 33 59 21 167 163 101 136 50 197 16 104 128 192 30 47 111 142 66 157 61 49 188 | 188 48 123 50 104 36 101 148 66 161 44 28 21 162 116 183 103 159 181 61 29 141 163 153 111 110 190 95 105 59 58 189 | 189 165 123 10 161 116 41 187 43 29 182 197 16 110 179 143 12 183 103 199 109 130 128 194 117 94 61 190 | 190 165 48 10 141 13 43 3 173 183 104 177 72 36 77 188 90 136 51 163 70 130 105 61 191 | 191 193 37 178 8 32 120 15 42 107 18 124 166 132 174 20 52 57 31 115 127 1 69 9 23 192 | 192 186 187 12 114 82 92 29 148 104 182 177 72 28 101 21 117 94 51 111 142 193 | 193 26 112 191 62 195 25 91 39 71 158 131 46 5 38 37 185 18 118 124 56 156 58 86 53 108 68 175 87 120 15 42 73 99 4 75 151 64 35 48 194 | 194 123 169 43 88 65 29 104 16 167 180 90 189 161 199 47 92 3 12 17 117 195 | 195 193 80 58 122 164 108 68 160 146 78 139 23 120 178 133 73 175 37 131 9 19 89 140 57 196 | 196 122 53 102 118 62 175 15 166 31 9 37 6 99 151 56 139 46 1 96 60 197 | 197 48 123 134 141 184 187 82 65 92 106 148 147 199 29 17 30 189 186 74 169 154 21 103 138 157 59 198 | 198 91 37 178 79 164 108 125 62 113 18 84 45 26 112 35 107 160 53 1 75 199 | 199 123 186 109 184 43 168 29 182 197 177 189 129 194 95 83 170 54 105 90 179 30 59 200 | 200 149 155 52 87 120 39 160 137 27 79 131 100 25 55 23 126 84 166 150 62 67 1 69 35 201 | -------------------------------------------------------------------------------- /Algorithms/graphtheory/depth-first-search/DFS_recursive.py: -------------------------------------------------------------------------------- 1 | # Purpose of Depth first search is (mainly from my understanding) to find if a graph G is connected. 2 | # Identify all nodes that are reachable from a given starting node. 3 | 4 | # Programmed by Aladdin Persson 5 | # 2019-02-16 Initial programming 6 | 7 | 8 | def DFS(G, curr_node, visited): 9 | """ 10 | :param G: G = {from_node1:[to_node1, to_node2], from_node2: [to_node,] etc} 11 | :param curr_node: Node currently at, run from beginning this is the starting node 12 | :param visited: since it is recursive, visited is updated and needs to be sent in on recursive call 13 | :return: visited is initialized outside of DFS and updates this boolean array with which nodes has been visited 14 | """ 15 | if visited[curr_node - 1]: 16 | return 17 | 18 | visited[curr_node - 1] = True 19 | 20 | neighbours = G[curr_node] 21 | 22 | for next_node in neighbours: 23 | DFS(G, next_node, visited) 24 | 25 | 26 | # Small Eaxmple 27 | # if __name__ == '__main__': 28 | # G = {1: [2], 2: [1, 3, 4], 3: [2], 4: [2, 5], 5: [4]} 29 | # 30 | # visited = [False for i in range(1, len(G) + 1)] 31 | # start_node = 1 32 | # 33 | # DFS(G, start_node, visited) 34 | # 35 | # if any(visited) == False: 36 | # print("Result: This graph is connected!") 37 | -------------------------------------------------------------------------------- /Algorithms/graphtheory/depth-first-search/DFS_stack_iterative.py: -------------------------------------------------------------------------------- 1 | """ 2 | Depth first search has many applications,for example finding if a graph G is connected. 3 | Identify all nodes that are reachable from a given starting node. 4 | 5 | Programmed by Aladdin Persson 6 | 2019-02-17 Initial programming 7 | 2020-03-29 Cleaned up code, made test cases 8 | """ 9 | 10 | 11 | def DFS(G, start_node): 12 | """ 13 | :param G: Graph with G = {from_node1:[to_node1, to_node2], from_node2: [to_node,] etc} 14 | :param start_node: starting node to run BFS from 15 | :return: returns visited boolean array and path in which order it visited them 16 | """ 17 | visited = [False for i in range(1, len(G) + 1)] 18 | path = [start_node] 19 | stack = [] 20 | stack.append(start_node) 21 | 22 | while stack: 23 | v = stack.pop() 24 | if not visited[v - 1]: 25 | visited[v - 1] = True 26 | 27 | for connected_node in G[v]: 28 | if not visited[connected_node - 1]: 29 | stack.append(connected_node) 30 | path.append(connected_node) 31 | 32 | return visited, path 33 | 34 | 35 | # if __name__ == '__main__': 36 | # G = {1: [2, 3], 2: [1, 4], 3: [1, 4], 4: []} 37 | # start_node = 1 38 | # visited = DFS(G, start_node) 39 | # 40 | # if all(visited) == True: 41 | # print("Return: This graph is connected!") 42 | # else: 43 | # print("Not all nodes were reachable, i.e the graph is not connected.") 44 | -------------------------------------------------------------------------------- /Algorithms/graphtheory/depth-first-search/__pycache__/DFS_recursive.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aladdinpersson/Algorithms-Collection-Python/266e5608b0c3558c3738ab749e27329010cd9fd6/Algorithms/graphtheory/depth-first-search/__pycache__/DFS_recursive.cpython-37.pyc -------------------------------------------------------------------------------- /Algorithms/graphtheory/depth-first-search/__pycache__/DFS_stack_iterative.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aladdinpersson/Algorithms-Collection-Python/266e5608b0c3558c3738ab749e27329010cd9fd6/Algorithms/graphtheory/depth-first-search/__pycache__/DFS_stack_iterative.cpython-37.pyc -------------------------------------------------------------------------------- /Algorithms/graphtheory/dijkstra/__pycache__/dijkstra.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aladdinpersson/Algorithms-Collection-Python/266e5608b0c3558c3738ab749e27329010cd9fd6/Algorithms/graphtheory/dijkstra/__pycache__/dijkstra.cpython-37.pyc -------------------------------------------------------------------------------- /Algorithms/graphtheory/dijkstra/__pycache__/heapdijkstra.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aladdinpersson/Algorithms-Collection-Python/266e5608b0c3558c3738ab749e27329010cd9fd6/Algorithms/graphtheory/dijkstra/__pycache__/heapdijkstra.cpython-37.pyc -------------------------------------------------------------------------------- /Algorithms/graphtheory/dijkstra/dijkstra.py: -------------------------------------------------------------------------------- 1 | """ 2 | Dijkstra's algorithm for finding the shortest path in a graph, this implementation 3 | is a naive implementation, check my Heap implementation for a more efficient algorithm 4 | 5 | Programmed by Aladdin Persson 6 | 2019-01-28 Initial programming 7 | 2020-03-28 Cleaned up code 8 | """ 9 | 10 | 11 | def dijkstra(G, start, end): 12 | """ 13 | :param G: {from_node1: {to_node1:cost1, to_node2:cost2}, from_node2 : {.., etc.}, ...} 14 | :param start: starting node 15 | :param end: ending node where we want to find path to 16 | :return: path from starting node to end node and the cost to get between them 17 | """ 18 | 19 | if start not in G or end not in G: 20 | return [], float("inf") 21 | 22 | shortest_distance = {} 23 | predecessor = {} 24 | unseenNodes = G 25 | infinity = float("inf") 26 | path = [] 27 | 28 | for node in unseenNodes: 29 | shortest_distance[node] = infinity 30 | 31 | shortest_distance[start] = 0 32 | 33 | while unseenNodes: 34 | minNode = None 35 | 36 | for node in unseenNodes: 37 | if minNode is None: 38 | minNode = node 39 | elif shortest_distance[node] < shortest_distance[minNode]: 40 | minNode = node 41 | 42 | for childNode, weight in G[minNode].items(): 43 | if weight + shortest_distance[minNode] < shortest_distance[childNode]: 44 | shortest_distance[childNode] = weight + shortest_distance[minNode] 45 | predecessor[childNode] = minNode 46 | 47 | unseenNodes.pop(minNode) 48 | 49 | # Find path from start node s to end node t 50 | currentNode = end 51 | 52 | while currentNode != start: 53 | try: 54 | path.insert(0, currentNode) 55 | currentNode = predecessor[currentNode] 56 | except KeyError: 57 | return [], float("inf") 58 | 59 | path.insert(0, start) 60 | 61 | return path, shortest_distance[end] 62 | 63 | 64 | if __name__ == "__main__": 65 | G = {1: {2: 10, 3: 20}, 2: {4: 40}, 3: {4: 5}, 4: {}} 66 | 67 | print(f"Current graph is: {G}") 68 | path, shortest = dijkstra(G, 1, 4) 69 | 70 | print(path) 71 | print(shortest) 72 | -------------------------------------------------------------------------------- /Algorithms/graphtheory/dijkstra/heapdijkstra.py: -------------------------------------------------------------------------------- 1 | """ 2 | Dijkstra's algorithm for finding the shortest path. 3 | Improved version with the usage of heaps. 4 | 5 | Programmed by Aladdin Persson 6 | 2019-02-15 Initial coding 7 | 2020-03-28 Small code changes, fixed for edge cases not covered 8 | 9 | """ 10 | 11 | import heapq 12 | 13 | 14 | def make_graph(file): 15 | try: 16 | f = open(file, "r") 17 | except IOError: 18 | raise ("File does not exist!") 19 | 20 | line_list = f.readlines() 21 | 22 | # Kinda messy graph loading 23 | G = { 24 | int(line.split()[0]): { 25 | (int(tup.split(",")[0])): int(tup.split(",")[1]) 26 | for tup in line.split()[1:] 27 | if tup 28 | } 29 | for line in line_list 30 | if line 31 | } 32 | f.close() 33 | return G 34 | 35 | 36 | def dijkstra(G, start, end=None): 37 | if start not in G or (end != None and end not in G): 38 | return [], {end: float("inf")} 39 | 40 | distance, visited, history, heap, path = {}, {}, {}, [], [] 41 | 42 | for node in G.keys(): 43 | distance[node] = float("inf") 44 | visited[node] = False 45 | 46 | distance[start], visited[start] = 0, True 47 | heapq.heappush(heap, (0, start)) 48 | 49 | while heap: 50 | (d, node) = heapq.heappop(heap) 51 | visited[node] = True 52 | 53 | for child_node, weight in G[node].items(): 54 | if (not visited[child_node]) and (d + weight < distance[child_node]): 55 | history[child_node] = node 56 | distance[child_node] = d + weight 57 | heapq.heappush(heap, (distance[child_node], child_node)) 58 | 59 | if end != None: 60 | current_node = end 61 | 62 | while current_node != start: 63 | try: 64 | path.insert(0, current_node) 65 | current_node = history[current_node] 66 | 67 | except KeyError: 68 | return [], distance 69 | 70 | path.insert(0, start) 71 | 72 | return path, distance 73 | 74 | 75 | if __name__ == "__main__": 76 | # start, end = 1, 160 77 | # print(f'Goal is to find the path from node {start} to node {end}') 78 | # G = make_graph('dijkstraData.txt') 79 | 80 | G = {1: {2: 10, 3: 20}, 2: {4: 40}, 3: {4: 5}, 4: {}} 81 | start = 1 82 | end = 2 83 | 84 | path, dist = dijkstra(G, start, end) 85 | print(f"Path found: {path}") 86 | print(dist) 87 | -------------------------------------------------------------------------------- /Algorithms/graphtheory/floyd-warshall/floyd-warshall.py: -------------------------------------------------------------------------------- 1 | """ 2 | Purpose is to the find shortest path from all nodes to all other nodes, O(n^3). 3 | Can be used with negative weights, however to check if it has negative cycles, bellman ford should prob. be used first. 4 | 5 | Programmed by Aladdin Persson 6 | * 2019-03-08 Initial programming 7 | 8 | """ 9 | 10 | 11 | def load_graph(file_name): 12 | try: 13 | with open(file_name) as file: 14 | line_list = file.readlines() 15 | file.close() 16 | 17 | except IOError: 18 | raise IOError("File does not exist") 19 | 20 | G = { 21 | int(line.split()[0]): { 22 | (int(tup.split(",")[0])): int(tup.split(",")[1]) 23 | for tup in line.split()[1:] 24 | if tup 25 | } 26 | for line in line_list 27 | if line 28 | } 29 | 30 | # If we have path set path else make value infinity 31 | adjacency_matrix = [ 32 | [ 33 | G[i][j] if (i in G and j in G[i]) else float("inf") 34 | for j in range(1, len(G) + 1) 35 | ] 36 | for i in range(1, len(G) + 1) 37 | ] 38 | 39 | # Make diagonal values all 0 40 | for i in range(len(G)): 41 | adjacency_matrix[i][i] = 0 42 | 43 | # next will be matrix showing which path to take for the shortest path 44 | next = [ 45 | [j if adjacency_matrix[i][j] != float("inf") else None for j in range(len(G))] 46 | for i in range(len(G)) 47 | ] 48 | 49 | return adjacency_matrix, next 50 | 51 | 52 | def floyd_warshall(adj_matrix, next): 53 | n = len(adj_matrix) 54 | # make a copy of adj_matrix, dp will contain APSP (All-Path-Shortest-Path) solutions, 55 | APSP = adj_matrix.copy() 56 | 57 | # Can we get a better path by going through node k? 58 | for k in range(n): 59 | # Goal is to find path from i to j 60 | for i in range(n): 61 | for j in range(n): 62 | # if distance from i to k, then k to j is less than distance i to j 63 | if APSP[i][k] + APSP[k][j] < APSP[i][j]: 64 | APSP[i][j] = APSP[i][k] + APSP[k][j] 65 | next[i][j] = next[i][k] 66 | 67 | # return APSP (All-Path-Shortest-Path) matrix 68 | return APSP, next 69 | 70 | 71 | def construct_path_to_take(next, start, end): 72 | go_through = start 73 | path = [start] 74 | 75 | while next[go_through][end] != end: 76 | go_through = next[go_through][end] 77 | path.append(go_through) 78 | 79 | path.append(end) 80 | 81 | return path 82 | 83 | 84 | if __name__ == "__main__": 85 | adj_matrix, next = load_graph("test_graph.txt") 86 | APSP, next = floyd_warshall(adj_matrix, next) 87 | 88 | print(f"The shortest paths are {APSP}") 89 | print(f"The path to take is given by {next}") 90 | 91 | path_to_take = construct_path_to_take(next, 0, 3) 92 | print(path_to_take) 93 | -------------------------------------------------------------------------------- /Algorithms/graphtheory/floyd-warshall/test_graph.txt: -------------------------------------------------------------------------------- 1 | 1 2,5 3,10 2 | 2 4,-3 3 | 3 4,20 4 | 4 -------------------------------------------------------------------------------- /Algorithms/graphtheory/kahns-toposort/__pycache__/kahn_topological_ordering.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aladdinpersson/Algorithms-Collection-Python/266e5608b0c3558c3738ab749e27329010cd9fd6/Algorithms/graphtheory/kahns-toposort/__pycache__/kahn_topological_ordering.cpython-37.pyc -------------------------------------------------------------------------------- /Algorithms/graphtheory/kahns-toposort/example.txt: -------------------------------------------------------------------------------- 1 | Step C must be finished before step A can begin. 2 | Step C must be finished before step F can begin. 3 | Step A must be finished before step B can begin. 4 | Step A must be finished before step D can begin. 5 | Step B must be finished before step E can begin. 6 | Step D must be finished before step E can begin. 7 | Step F must be finished before step E can begin. -------------------------------------------------------------------------------- /Algorithms/graphtheory/kahns-toposort/kahn_topological_ordering.py: -------------------------------------------------------------------------------- 1 | """ 2 | Purpose of this algorithm is finding a path that is in topological ordering for a directed acyclic graph (DAG). 3 | If the graph is not a DAG and includes cycles it will return is_DAG = 'False' meaning it has cycles. 4 | 5 | Time Complexity: O(n + m), n = |V|, m = |E| 6 | 7 | Programmed by Aladdin Persson 8 | * 2019-03-17 Intitial programming 9 | * 2020-03-28 Removed load graph function, just having topological sort seems to make more sense 10 | The loading of the graph is so varying depending on input, doesn't make much sense to include it 11 | 12 | """ 13 | 14 | from collections import defaultdict, deque 15 | 16 | 17 | def topological_ordering(graph, degree_incoming): 18 | if len(graph) == 0: 19 | return [], False 20 | 21 | curr_accessible_nodes = deque() 22 | 23 | for node in graph: 24 | if degree_incoming[node] == 0: 25 | curr_accessible_nodes.append(node) 26 | 27 | path = [] 28 | 29 | while curr_accessible_nodes: 30 | node_topological = curr_accessible_nodes.popleft() 31 | path.append(node_topological) 32 | 33 | for connected_node in graph[node_topological]: 34 | degree_incoming[connected_node] -= 1 35 | 36 | if degree_incoming[connected_node] == 0: 37 | curr_accessible_nodes.append(connected_node) 38 | 39 | # Check if there are still incoming edges (meaning it will have cycles) 40 | is_DAG = True 41 | 42 | for val in degree_incoming.values(): 43 | if val != 0: 44 | is_DAG = False 45 | path = [] 46 | 47 | return path, is_DAG 48 | 49 | 50 | if __name__ == "__main__": 51 | G = {"A": ["B"], "B": ["C", "D"], "C": ["D"], "D": []} 52 | degree_incoming = defaultdict(int, {"B": 1, "C": 1, "D": 2}) 53 | 54 | print("The graph to check is : " + str(G)) 55 | print("Which has incoming edges: " + str(degree_incoming)) 56 | print("\n") 57 | path_to_take, is_DAG = topological_ordering(G, degree_incoming) 58 | print("The graph has a topological ordering <--> G is a DAG: " + str(is_DAG)) 59 | print(f'One path to take that is a topological ordering is {"".join(path_to_take)}') 60 | -------------------------------------------------------------------------------- /Algorithms/graphtheory/kargers/kargermincut.py: -------------------------------------------------------------------------------- 1 | # Purpose of Karger's algorithm is to compute the minimum cut of a connected graph. 2 | # If you have nodes connected to edges, where should the graph be cut so that we cut 3 | # the minimum amount of edges possible 4 | 5 | # Programmed by Aladdin Persson 6 | # 2019-01-25 Initial programming 7 | 8 | # Improvements to be made: 9 | # * Comment code better 10 | # * See if there is a datastructure to be used to make it faster 11 | 12 | import random, copy 13 | 14 | random.seed(1) 15 | 16 | 17 | def load_graph(): 18 | data = open("data.txt", "r") 19 | G = {} 20 | 21 | for line in data: 22 | lst = [int(x) for x in line.split()] 23 | G[lst[0]] = lst[1:] 24 | 25 | return G 26 | 27 | 28 | def get_random_edge(G): 29 | v1 = random.choice(list(G.keys())) 30 | v2 = random.choice(list(G[v1])) 31 | return v1, v2 32 | 33 | 34 | def karger_contraction(G): 35 | length = [] 36 | 37 | while len(G) > 2: 38 | v1, v2 = get_random_edge(G) 39 | G[v1].extend(G[v2]) 40 | 41 | for edge in G[v2]: 42 | G[edge].remove(v2) 43 | G[edge].append(v1) 44 | 45 | # self-connections 46 | while v1 in G[v1]: 47 | G[v1].remove(v1) 48 | 49 | del G[v2] 50 | 51 | for key in G.keys(): 52 | length.append(len(G[key])) 53 | 54 | return length[0] 55 | 56 | 57 | def main(): 58 | count = None 59 | G = load_graph() 60 | N = 100 61 | 62 | for i in range(N): 63 | data = copy.deepcopy(G) 64 | min_cut = karger_contraction(data) 65 | if count == None or min_cut < count: 66 | count = min_cut 67 | 68 | return count 69 | 70 | 71 | val = main() 72 | print(val) 73 | -------------------------------------------------------------------------------- /Algorithms/graphtheory/kargers/kargermincutdata.txt: -------------------------------------------------------------------------------- 1 | 1 37 79 164 155 32 87 39 113 15 18 78 175 140 200 4 160 97 191 100 91 20 69 198 196 2 | 2 123 134 10 141 13 12 43 47 3 177 101 179 77 182 117 116 36 103 51 154 162 128 30 3 | 3 48 123 134 109 41 17 159 49 136 16 130 141 29 176 2 190 66 153 157 70 114 65 173 104 194 54 4 | 4 91 171 118 125 158 76 107 18 73 140 42 193 127 100 84 121 60 81 99 80 150 55 1 35 23 93 5 | 5 193 156 102 118 175 39 124 119 19 99 160 75 20 112 37 23 145 135 146 73 35 6 | 6 155 56 52 120 131 160 124 119 14 196 144 25 75 76 166 35 87 26 20 32 23 7 | 7 156 185 178 79 27 52 144 107 78 22 71 26 31 15 56 76 112 39 8 113 93 8 | 8 185 155 171 178 108 64 164 53 140 25 100 133 9 52 191 46 20 150 144 39 62 131 42 119 127 31 7 9 | 9 91 155 8 160 107 132 195 26 20 133 39 76 100 78 122 127 38 156 191 196 115 10 | 10 190 184 154 49 2 182 173 170 161 47 189 101 153 50 30 109 177 148 179 16 163 116 13 90 185 11 | 11 123 134 163 41 12 28 130 13 101 83 77 109 114 21 82 88 74 24 94 48 33 12 | 12 161 109 169 21 24 36 65 50 2 101 159 148 54 192 88 47 11 142 43 70 182 177 179 189 194 33 13 | 13 161 141 157 44 83 90 181 41 2 176 10 29 116 134 182 170 165 173 190 159 47 82 111 142 72 154 110 21 103 130 11 33 138 152 14 | 14 91 156 58 122 62 113 107 73 137 25 19 40 6 139 150 46 37 76 39 127 15 | 15 149 58 68 52 39 67 121 191 1 45 100 18 118 174 40 85 196 122 42 193 119 139 26 127 145 135 57 38 7 16 | 16 48 10 36 187 43 3 114 173 111 142 129 88 189 117 128 147 141 194 180 106 167 179 66 74 136 51 59 17 | 17 48 123 134 36 163 3 44 117 167 161 152 95 170 83 180 77 65 72 109 47 43 88 159 197 28 194 181 49 18 | 18 193 149 56 62 15 160 67 191 140 52 178 96 107 132 1 145 89 198 4 26 73 151 126 34 115 19 | 19 156 80 178 164 108 84 71 174 40 62 113 22 89 45 91 126 195 144 5 14 172 20 | 20 185 122 171 56 8 52 73 191 67 126 9 119 1 89 79 107 96 31 75 55 5 6 34 23 21 | 21 188 187 12 173 180 197 138 167 63 111 95 13 192 116 94 114 105 49 177 51 130 90 11 50 66 157 176 22 | 22 156 27 32 131 7 56 53 81 149 23 100 146 115 26 175 121 96 75 57 39 119 71 132 19 150 140 93 23 | 23 91 122 124 22 200 195 145 5 69 125 55 68 156 20 58 191 4 57 149 6 24 | 24 123 134 161 163 169 72 116 167 30 33 77 162 143 159 187 63 184 130 28 50 153 12 148 11 53 25 | 25 193 185 79 108 8 158 87 73 81 115 39 64 178 132 27 68 127 84 14 52 200 97 6 93 26 | 26 193 58 27 108 52 144 160 18 84 81 22 75 139 166 15 107 198 131 7 9 133 6 27 | 27 156 139 144 166 112 100 26 174 31 42 75 158 122 81 22 7 58 73 89 115 39 25 200 69 169 28 | 28 134 188 24 184 159 29 72 114 152 116 169 173 141 17 111 61 192 90 11 177 179 77 33 66 83 136 29 | 29 48 134 188 13 47 88 3 82 92 28 194 50 192 189 123 199 177 147 43 106 148 197 77 103 129 181 30 | 30 165 123 10 24 41 187 47 168 92 148 197 101 50 2 179 111 130 77 153 199 70 31 | 31 27 171 56 131 146 139 191 89 20 108 38 71 75 69 196 149 97 8 86 98 7 32 | 32 156 149 171 62 22 185 35 124 56 38 158 97 53 121 160 1 191 58 89 127 87 120 39 99 84 60 151 174 6 33 | 33 48 161 109 141 24 187 47 88 168 183 110 103 95 116 28 12 11 13 83 134 63 34 | 34 37 122 171 118 76 131 166 137 40 46 97 87 80 164 127 18 62 52 20 139 35 | 35 79 164 125 32 107 137 75 121 85 55 69 45 193 132 4 5 200 135 76 139 198 6 36 | 36 165 188 17 106 88 16 177 110 147 154 159 179 136 41 50 141 66 162 152 168 184 12 43 72 180 190 77 2 170 61 122 37 | 37 193 149 39 121 191 115 146 52 127 79 198 58 125 38 34 1 76 89 164 97 86 178 108 87 84 124 98 174 195 14 5 57 196 186 38 | 38 193 37 86 32 76 107 73 85 127 100 46 89 31 57 96 158 99 160 45 15 9 39 | 39 193 37 122 102 8 158 32 87 85 81 200 60 5 27 155 1 58 150 15 113 76 84 22 25 151 139 100 14 145 9 7 40 | 40 91 156 122 79 118 125 52 175 87 15 81 166 132 121 19 14 160 34 78 71 41 | 41 36 169 184 116 163 106 189 11 104 61 30 123 129 111 3 47 49 154 161 152 13 153 65 92 183 177 162 95 54 70 108 42 | 42 178 79 27 53 171 164 102 52 87 113 15 191 131 91 62 193 8 122 89 56 4 127 145 112 43 | 43 165 161 12 70 199 54 17 190 16 153 141 36 47 44 194 110 82 189 2 148 183 29 130 94 170 51 61 59 44 | 44 188 163 169 17 13 43 114 173 142 154 103 129 181 105 157 148 182 101 110 66 176 49 45 | 45 156 80 149 58 178 53 108 68 56 125 15 93 75 135 174 198 81 166 113 100 19 89 35 97 38 46 | 46 193 58 86 122 155 8 175 160 99 127 67 14 150 144 126 146 34 131 55 38 196 47 | 47 123 10 109 41 17 12 43 116 59 33 13 2 187 165 88 117 29 30 176 147 180 101 130 194 50 94 152 70 48 | 48 180 128 188 197 105 51 94 190 116 29 183 114 153 33 16 49 3 63 184 17 141 168 179 162 11 66 83 193 49 | 49 48 123 10 186 141 41 168 3 148 142 179 21 136 109 44 117 17 103 187 74 50 | 50 165 123 10 188 36 169 24 187 12 65 29 167 47 21 134 130 111 168 77 116 138 106 66 30 51 | 51 165 48 109 141 163 159 92 190 143 2 21 138 43 59 192 117 16 184 104 169 52 | 52 37 178 8 6 15 200 133 80 102 96 40 119 164 166 127 151 20 42 7 26 76 18 73 99 78 25 132 139 191 150 34 53 | 53 156 122 102 193 137 133 42 62 45 64 60 78 160 132 155 56 144 131 196 178 125 8 32 113 22 98 121 198 24 54 | 54 123 187 12 43 168 65 129 130 147 95 41 61 59 141 3 138 114 199 66 110 55 | 55 68 56 125 113 73 78 200 46 131 85 107 89 185 60 84 4 35 99 171 71 20 23 56 | 56 193 122 53 108 45 55 18 125 86 171 79 6 85 133 80 140 96 31 107 20 32 87 120 42 73 84 22 112 196 7 57 | 57 79 155 158 76 84 22 75 121 85 191 100 97 15 37 102 69 38 64 195 145 23 58 | 58 15 146 107 193 140 84 144 86 14 150 26 60 46 166 80 87 139 195 126 45 37 27 102 62 32 175 39 124 23 93 188 59 | 59 186 163 187 47 168 92 143 147 157 54 51 61 199 43 103 63 184 16 188 197 60 | 60 58 86 178 53 171 125 39 144 146 73 124 4 93 32 99 158 132 80 91 96 75 174 55 196 61 | 61 188 116 41 114 183 28 77 54 36 163 187 147 179 65 63 190 43 186 59 189 62 | 62 193 185 79 53 171 102 146 84 198 14 58 137 8 166 175 32 113 18 115 196 42 200 132 121 19 112 133 172 34 63 | 63 48 24 116 183 111 167 21 162 90 181 147 105 106 101 33 123 153 184 128 168 61 59 64 | 64 91 149 122 53 8 120 113 124 119 25 132 131 193 121 144 68 185 108 175 107 57 65 | 65 186 17 12 114 82 3 66 159 167 197 50 101 176 94 54 134 41 165 157 194 180 77 103 74 61 66 | 66 188 36 116 3 65 183 72 180 77 16 136 177 82 159 28 95 48 50 187 21 44 54 176 67 | 67 91 156 102 68 175 131 144 15 18 146 119 20 200 46 112 139 75 80 86 137 68 | 68 122 171 55 78 175 96 75 71 93 118 195 115 67 79 45 158 15 120 155 193 87 146 81 25 64 23 69 | 69 91 108 125 131 81 75 85 174 145 89 27 200 35 156 1 98 86 23 191 127 31 57 70 | 70 165 123 163 153 12 43 168 3 114 82 148 190 129 74 176 47 110 181 41 30 71 | 71 193 79 171 68 124 98 120 73 75 93 151 108 89 155 19 96 22 119 7 125 85 127 40 55 140 31 72 | 72 109 169 24 116 17 114 182 190 141 186 192 28 104 13 66 165 162 36 159 77 110 129 130 181 73 | 73 91 80 27 160 4 20 100 56 193 60 38 18 25 172 76 14 55 52 149 96 78 71 195 127 5 112 97 93 74 | 74 88 104 197 111 130 95 11 138 123 77 159 65 179 94 165 70 141 16 153 136 83 49 75 | 75 91 79 27 171 68 158 87 81 22 119 71 166 57 60 35 160 69 175 26 193 45 127 67 126 89 20 5 31 198 6 76 | 76 37 178 175 120 122 57 52 34 4 156 98 115 133 131 171 149 85 38 174 39 73 99 14 140 35 135 172 9 7 6 77 | 77 24 116 17 72 190 110 36 173 143 94 65 29 61 154 2 161 90 66 159 28 128 117 11 50 138 74 30 78 | 78 156 80 53 164 68 131 144 107 73 195 55 175 1 126 7 149 171 81 91 52 124 40 9 79 | 79 80 37 158 40 75 108 198 25 62 42 7 86 57 102 122 145 175 71 1 35 164 68 118 56 144 200 139 20 112 135 172 163 80 | 80 91 144 100 118 45 78 139 112 149 98 113 87 195 124 85 73 119 19 79 99 58 56 52 146 81 4 60 137 67 126 145 97 34 134 81 | 81 86 27 120 39 131 40 132 25 69 96 26 127 108 75 68 135 98 80 115 149 78 22 4 45 172 82 | 82 161 186 109 153 43 159 114 101 104 70 29 197 192 116 148 65 152 184 13 154 92 110 130 11 147 66 176 83 | 83 17 13 153 88 111 90 117 95 11 33 147 28 109 199 48 74 167 182 154 101 84 | 84 149 58 86 178 171 62 175 113 26 135 96 198 39 19 57 144 37 118 32 56 119 4 98 25 200 150 55 85 | 85 156 80 185 155 102 56 158 39 76 15 69 38 150 175 118 137 71 35 120 57 55 135 86 | 86 58 84 120 81 112 37 60 46 185 193 38 125 118 175 149 99 108 126 133 102 79 56 144 67 69 31 109 87 | 87 80 149 58 118 25 75 126 115 68 178 37 200 32 40 164 56 42 193 107 1 39 113 145 89 172 6 34 93 88 | 88 36 116 12 47 165 168 29 83 159 154 74 148 92 176 180 33 110 194 167 17 114 173 16 11 89 | 89 37 27 102 32 42 18 99 71 151 19 55 75 98 131 69 45 31 38 195 87 20 135 115 90 | 90 163 116 13 173 28 110 190 77 129 117 130 10 179 92 134 194 21 63 83 157 94 152 199 91 | 91 126 14 75 135 107 80 102 67 160 158 144 23 64 155 4 198 40 9 73 69 193 185 149 164 42 78 60 98 19 1 165 92 | 92 161 109 163 187 88 186 141 51 117 197 59 173 192 82 29 143 116 41 30 111 148 129 90 194 152 170 93 | 93 68 99 71 60 45 150 145 98 25 87 122 178 185 7 144 4 22 73 58 112 94 | 94 48 163 65 173 182 154 77 21 117 11 147 74 189 43 114 47 177 192 104 90 95 | 95 123 141 169 17 168 114 179 21 33 165 167 177 41 103 83 199 129 182 188 74 66 157 152 54 176 96 | 96 171 164 68 56 52 18 73 84 81 124 22 71 60 126 150 20 97 38 149 158 196 115 97 | 97 185 149 37 178 122 108 118 32 131 1 31 140 73 34 45 25 80 133 57 96 98 | 98 80 171 164 158 120 76 99 81 71 37 91 151 144 172 140 150 160 121 84 53 139 89 69 31 133 93 99 | 99 80 86 178 122 118 125 52 193 32 174 46 113 98 93 89 150 102 76 100 124 4 60 55 5 38 196 100 | 100 80 185 149 27 8 113 131 15 73 99 22 4 200 45 102 172 57 164 38 39 1 112 9 101 | 101 165 10 188 109 141 163 187 12 168 82 65 148 180 47 167 2 162 169 192 30 179 11 44 83 170 63 102 | 102 91 86 79 53 171 155 67 113 39 137 158 196 166 120 42 89 58 5 119 85 62 52 146 99 121 100 57 103 | 103 161 188 186 184 153 159 167 189 2 168 13 29 104 142 33 65 197 117 148 44 95 181 59 49 104 | 104 134 188 186 141 184 41 187 168 114 82 148 192 194 154 74 3 190 161 105 163 72 103 94 170 51 105 | 105 165 48 161 116 159 104 21 129 63 44 169 106 142 190 181 143 179 157 173 188 199 176 106 | 106 36 163 169 184 41 159 29 197 111 16 179 162 105 138 148 50 165 63 173 109 107 | 107 91 58 56 125 158 87 191 133 9 38 122 164 175 135 4 35 14 7 185 78 18 146 151 26 64 126 55 20 112 198 172 108 | 108 86 178 79 164 37 25 195 144 120 198 26 56 19 132 69 193 115 45 172 97 155 8 81 71 166 139 174 64 31 41 109 | 109 10 47 116 12 128 51 167 180 179 33 123 101 142 92 143 199 154 3 72 82 141 17 168 114 173 183 148 189 11 181 106 83 152 49 86 110 | 110 165 186 36 163 169 43 88 168 33 138 147 13 167 189 184 134 72 90 188 82 77 44 54 70 111 | 111 41 92 114 162 188 129 187 170 152 83 142 74 157 16 13 138 186 106 63 184 28 21 50 30 192 112 | 112 193 80 86 27 137 174 67 5 79 198 132 127 42 131 100 73 107 56 135 62 7 93 113 | 113 156 80 149 171 102 62 39 133 84 87 198 1 53 64 55 172 122 100 42 14 160 99 124 137 45 19 145 7 114 | 114 48 104 136 16 61 72 181 128 82 88 138 109 129 70 192 3 153 65 95 44 111 28 21 11 94 54 115 | 115 185 37 27 108 68 62 87 120 76 81 22 25 151 139 191 140 9 89 96 18 116 | 116 48 188 109 24 157 61 41 181 128 66 88 63 152 189 168 90 105 72 77 10 13 47 82 173 92 142 28 180 2 21 117 50 33 136 164 117 | 117 17 47 92 16 179 2 103 90 194 189 192 94 143 170 162 83 116 129 184 77 138 152 51 49 118 | 118 193 156 80 86 155 68 196 145 40 4 97 79 5 99 87 149 174 34 137 166 131 15 160 84 121 85 119 | 119 80 178 102 52 160 124 84 185 6 22 67 174 8 121 133 5 75 64 15 150 71 151 145 20 120 | 120 185 86 171 108 102 68 200 193 126 64 160 32 150 6 115 98 81 56 191 76 124 71 139 85 195 135 121 | 121 156 185 37 32 15 146 22 119 4 98 151 57 62 126 53 139 40 102 35 118 64 135 133 122 | 122 156 146 23 99 196 46 14 56 53 175 164 20 68 39 195 126 97 40 34 64 79 27 155 113 76 131 15 42 107 166 151 9 93 36 123 | 123 165 194 50 70 95 11 153 30 24 17 49 47 54 2 189 147 199 3 188 197 186 109 41 29 129 130 128 74 136 63 156 124 | 124 193 80 125 32 146 99 23 5 60 113 120 191 6 58 64 119 71 37 78 96 137 125 | 125 37 86 56 4 133 69 178 132 53 172 45 60 151 40 198 55 35 107 99 124 71 137 127 23 126 | 126 91 58 86 122 155 87 120 146 78 200 121 19 80 20 137 75 96 107 18 156 46 135 127 | 127 37 178 32 52 131 160 81 4 25 191 125 38 71 15 8 42 75 46 174 73 14 69 112 172 9 34 128 | 128 48 134 161 109 116 187 114 183 16 179 189 130 181 142 123 138 2 136 77 152 63 129 | 129 165 184 41 153 114 148 111 177 16 180 44 29 123 54 173 72 92 70 199 105 90 117 95 157 130 | 130 186 169 24 3 154 189 21 136 72 82 74 190 11 47 13 173 54 181 43 123 90 128 50 138 30 176 131 | 131 193 53 76 78 22 69 97 118 178 122 140 81 34 164 8 100 127 67 31 6 42 146 200 195 26 64 46 55 89 112 132 | 132 185 149 53 171 108 125 18 81 60 25 139 191 178 64 52 9 62 22 40 164 35 112 133 | 133 86 53 56 125 8 52 113 76 107 119 195 97 156 98 121 62 140 26 175 9 134 | 134 153 11 17 182 165 197 138 173 24 28 104 128 29 2 167 152 183 3 162 154 186 13 65 142 110 90 50 33 157 80 135 | 135 91 171 164 107 84 81 45 5 35 112 120 15 151 85 76 79 178 121 126 89 136 | 136 165 36 187 3 114 173 190 130 128 66 74 152 123 154 116 28 49 153 16 169 137 | 137 156 185 53 155 102 118 62 166 175 200 151 112 113 14 124 80 146 35 125 34 85 67 126 145 172 138 | 138 134 186 153 114 111 142 110 179 21 128 130 117 197 169 77 13 74 51 180 50 106 54 139 | 139 80 58 27 164 132 121 108 115 140 31 79 98 15 160 52 26 171 39 195 120 67 14 35 196 34 140 | 140 185 58 56 8 175 131 144 18 4 166 98 139 1 195 22 156 71 76 178 115 97 133 141 | 141 109 104 184 2 143 188 51 49 33 197 48 176 95 159 148 101 154 13 170 190 36 43 3 92 72 16 28 167 180 147 74 54 178 142 | 142 161 109 169 12 183 111 163 187 162 180 16 165 116 184 138 44 13 49 134 143 177 103 128 181 105 192 143 | 143 165 161 109 141 24 184 168 92 142 154 180 51 147 179 176 183 189 59 159 167 77 117 105 152 144 | 144 91 80 58 178 27 53 164 108 8 158 60 79 67 155 78 140 7 86 26 174 84 98 64 19 46 145 6 93 145 | 145 178 79 155 118 18 151 69 39 113 42 119 93 80 144 87 15 137 23 158 166 5 57 172 146 | 146 149 58 37 122 62 60 68 107 31 67 172 195 121 131 102 185 174 124 126 80 22 137 46 5 147 | 147 123 186 36 47 183 29 182 197 16 167 110 143 168 83 82 141 63 94 54 59 157 170 61 148 | 148 10 188 186 141 163 12 43 88 82 109 192 70 161 30 129 24 92 49 177 29 104 197 154 101 103 162 181 106 44 176 149 | 149 156 80 200 146 15 185 87 91 100 45 37 178 18 32 64 132 97 84 150 113 86 118 76 73 81 78 22 31 96 23 161 150 | 150 149 58 8 175 120 39 99 119 166 98 200 85 14 4 46 96 84 22 93 52 151 | 151 125 52 160 71 166 98 137 145 122 171 119 193 175 32 121 107 115 18 39 89 135 196 152 | 152 134 161 36 116 41 17 82 111 28 128 157 13 92 47 143 117 109 90 95 136 170 153 | 153 165 48 123 134 10 186 138 187 103 82 70 163 129 188 170 173 24 83 167 41 43 3 114 154 180 74 136 63 30 154 | 154 134 10 109 141 36 41 88 159 82 104 143 148 197 44 13 94 130 162 177 153 167 77 2 83 136 170 155 | 155 91 185 53 164 108 145 171 200 6 122 8 9 85 57 1 137 126 102 118 46 68 158 39 144 160 71 172 156 | 156 7 53 113 45 14 193 122 40 67 19 121 22 118 78 5 137 166 149 32 85 178 27 158 76 126 140 69 133 9 23 123 157 | 157 184 116 13 3 65 111 90 105 187 147 152 134 59 95 186 197 44 170 129 21 158 | 158 91 193 79 27 102 68 32 75 156 107 185 144 4 57 39 155 98 171 85 25 175 60 145 38 96 159 | 159 188 141 36 24 13 12 88 103 105 179 177 17 3 182 51 82 28 161 154 106 65 183 72 143 77 66 74 160 | 160 91 185 53 32 120 155 6 9 18 127 171 118 113 119 151 26 46 195 200 73 98 75 139 40 1 5 198 38 161 | 161 165 10 24 173 142 182 162 92 13 152 33 82 189 43 143 128 103 186 105 12 188 184 41 17 159 148 104 180 77 194 170 149 162 | 162 134 161 188 186 36 24 173 182 111 142 72 154 101 48 148 2 179 106 63 41 117 163 | 163 177 92 10 148 101 44 169 59 110 188 17 51 90 186 94 11 24 70 106 182 41 153 187 104 142 190 61 79 164 | 164 185 37 122 175 139 144 91 35 19 96 98 78 155 1 108 198 42 135 79 195 8 52 87 131 107 166 132 100 34 116 165 | 165 30 105 36 101 167 183 43 50 70 189 181 190 161 123 136 51 143 129 153 110 134 169 13 47 88 65 142 72 95 106 74 91 166 | 166 156 58 27 102 118 62 52 191 140 164 40 122 151 108 75 174 137 196 150 34 200 45 26 145 6 167 | 167 165 134 109 24 17 153 187 88 168 65 182 177 154 16 194 141 103 50 147 63 110 101 179 143 21 95 83 168 | 168 36 169 116 88 48 70 30 33 101 104 109 110 143 181 167 54 199 49 59 95 177 180 103 50 147 63 169 | 169 163 50 184 12 176 106 41 194 173 168 110 142 44 95 130 24 165 182 72 177 197 28 101 138 105 136 51 27 170 | 170 10 186 141 17 13 153 111 117 157 92 161 152 147 104 179 154 43 101 36 199 171 | 171 34 60 68 31 20 42 62 4 120 71 32 135 113 175 84 102 132 96 98 75 155 56 8 158 76 160 78 151 139 55 184 172 | 172 185 108 125 113 146 73 98 174 100 155 81 79 76 127 87 137 107 19 62 145 173 | 173 134 10 161 169 13 153 109 162 44 21 88 182 3 190 179 136 90 16 116 94 92 28 77 129 130 105 106 174 | 174 27 118 175 76 144 15 146 99 119 166 45 32 19 172 191 60 108 37 69 112 127 175 | 175 86 122 79 171 164 68 62 84 140 5 40 196 46 174 150 67 58 76 193 158 107 78 22 137 75 151 85 195 64 1 133 176 | 176 141 169 13 47 88 3 65 183 177 143 148 82 105 130 66 181 44 21 182 95 70 177 | 177 10 36 163 169 159 29 148 190 12 199 167 176 180 2 192 168 142 41 179 129 154 28 21 95 66 94 178 | 178 149 76 19 52 127 108 45 156 60 198 99 37 144 7 97 145 84 119 42 191 53 125 8 87 131 18 25 132 195 140 135 93 141 179 | 179 10 109 36 159 173 177 49 117 12 48 101 189 2 138 128 95 106 28 167 16 143 162 90 105 74 170 199 30 61 180 | 180 48 109 17 88 142 177 16 65 194 36 153 116 161 66 143 141 129 47 168 21 101 181 138 181 | 181 165 188 184 116 13 168 114 182 130 128 44 103 148 63 29 142 180 17 109 72 105 176 70 182 | 182 134 10 161 163 169 184 13 159 173 183 147 189 162 181 12 72 167 94 199 192 2 95 44 83 176 183 | 183 165 48 134 188 186 63 33 147 43 61 109 142 159 66 41 128 182 176 190 184 143 189 184 | 184 48 10 141 169 24 143 41 161 181 36 129 197 104 186 182 28 106 157 103 199 82 183 111 142 110 117 63 51 59 171 185 | 185 193 140 8 97 7 121 160 155 85 172 91 100 164 132 25 120 20 62 137 115 149 86 32 158 107 146 119 64 55 93 10 186 | 186 161 104 199 162 148 110 138 183 153 103 192 82 130 123 59 49 147 134 65 170 163 184 187 92 197 111 72 157 61 37 187 | 187 24 153 186 92 189 54 33 59 21 167 163 101 136 50 197 16 104 128 192 30 47 111 142 66 157 61 49 188 | 188 48 123 50 104 36 101 148 66 161 44 28 21 162 116 183 103 159 181 61 29 141 163 153 111 110 190 95 105 59 58 189 | 189 165 123 10 161 116 41 187 43 29 182 197 16 110 179 143 12 183 103 199 109 130 128 194 117 94 61 190 | 190 165 48 10 141 13 43 3 173 183 104 177 72 36 77 188 90 136 51 163 70 130 105 61 191 | 191 193 37 178 8 32 120 15 42 107 18 124 166 132 174 20 52 57 31 115 127 1 69 9 23 192 | 192 186 187 12 114 82 92 29 148 104 182 177 72 28 101 21 117 94 51 111 142 193 | 193 26 112 191 62 195 25 91 39 71 158 131 46 5 38 37 185 18 118 124 56 156 58 86 53 108 68 175 87 120 15 42 73 99 4 75 151 64 35 48 194 | 194 123 169 43 88 65 29 104 16 167 180 90 189 161 199 47 92 3 12 17 117 195 | 195 193 80 58 122 164 108 68 160 146 78 139 23 120 178 133 73 175 37 131 9 19 89 140 57 196 | 196 122 53 102 118 62 175 15 166 31 9 37 6 99 151 56 139 46 1 96 60 197 | 197 48 123 134 141 184 187 82 65 92 106 148 147 199 29 17 30 189 186 74 169 154 21 103 138 157 59 198 | 198 91 37 178 79 164 108 125 62 113 18 84 45 26 112 35 107 160 53 1 75 199 | 199 123 186 109 184 43 168 29 182 197 177 189 129 194 95 83 170 54 105 90 179 30 59 200 | 200 149 155 52 87 120 39 160 137 27 79 131 100 25 55 23 126 84 166 150 62 67 1 69 35 201 | -------------------------------------------------------------------------------- /Algorithms/graphtheory/kruskal/__pycache__/DFS_stack_iterative.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aladdinpersson/Algorithms-Collection-Python/266e5608b0c3558c3738ab749e27329010cd9fd6/Algorithms/graphtheory/kruskal/__pycache__/DFS_stack_iterative.cpython-37.pyc -------------------------------------------------------------------------------- /Algorithms/graphtheory/kruskal/__pycache__/kruskal.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aladdinpersson/Algorithms-Collection-Python/266e5608b0c3558c3738ab749e27329010cd9fd6/Algorithms/graphtheory/kruskal/__pycache__/kruskal.cpython-37.pyc -------------------------------------------------------------------------------- /Algorithms/graphtheory/kruskal/__pycache__/kruskal_unionfind.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aladdinpersson/Algorithms-Collection-Python/266e5608b0c3558c3738ab749e27329010cd9fd6/Algorithms/graphtheory/kruskal/__pycache__/kruskal_unionfind.cpython-37.pyc -------------------------------------------------------------------------------- /Algorithms/graphtheory/kruskal/kruskal.py: -------------------------------------------------------------------------------- 1 | """ 2 | Kruskal's algorithm for finding minimal spanning tree (MST) of a graph. 3 | 4 | Aladdin Persson 5 | 2019-02-16 Initial programming 6 | 7 | """ 8 | 9 | import sys 10 | 11 | sys.path.append("../depth-first-search") 12 | from DFS_stack_iterative import DFS 13 | 14 | 15 | def load_graph(file="edges.txt"): 16 | G = [] 17 | 18 | try: 19 | f = open(file, "r") 20 | except IOError: 21 | raise ("File does not exist!") 22 | 23 | line_list = f.readlines() 24 | 25 | num_nodes, num_edges = map(int, line_list[0].split()) 26 | 27 | for line in line_list[1:]: 28 | G.append(tuple(map(int, line.split()))[::-1]) 29 | 30 | return sorted(G), num_nodes 31 | 32 | 33 | def kruskal(G, num_nodes): 34 | MST = [] 35 | tot_cost = 0 36 | temp_G = {key: [] for key in range(1, num_nodes + 1)} 37 | 38 | for each_set in G: 39 | temp_G[each_set[2]] += [each_set[1]] 40 | temp_G[each_set[1]] += [each_set[2]] 41 | 42 | visited, path = DFS(temp_G, each_set[2]) 43 | 44 | if len(set(path)) == len(path): 45 | tot_cost += each_set[0] 46 | 47 | if each_set[2] not in MST: 48 | MST.append(each_set[2]) 49 | 50 | if each_set[1] not in MST: 51 | MST.append(each_set[1]) 52 | else: 53 | temp_G[each_set[2]].pop() 54 | temp_G[each_set[1]].pop() 55 | 56 | return MST, tot_cost 57 | 58 | 59 | if __name__ == "__main__": 60 | print("---- Computing minimal spanning tree using Kruskal's Algorithm ----") 61 | print() 62 | 63 | G, num_nodes = load_graph() 64 | 65 | print(f"Our loaded graph is: {G}") 66 | MST, total_cost = kruskal(G) 67 | 68 | print(f"Our minimum spanning tree is: {MST}") 69 | print(f"Total cost is: {total_cost}") 70 | -------------------------------------------------------------------------------- /Algorithms/graphtheory/kruskal/kruskal_unionfind.py: -------------------------------------------------------------------------------- 1 | # Kruskal's algorithm for finding minimal spanning tree (MST) of a graph. Using Union find datastructure 2 | 3 | # Aladdin Persson 4 | # 2019-02-18 Initial programming 5 | 6 | from unionfind import unionfind 7 | 8 | 9 | def load_graph(file="edges.txt"): 10 | G = [] 11 | 12 | try: 13 | f = open(file, "r") 14 | except IOError: 15 | raise ("File does not exist!") 16 | 17 | line_list = f.readlines() 18 | 19 | num_nodes, num_edges = map(int, line_list[0].split()) 20 | 21 | for line in line_list[1:]: 22 | G.append(tuple(map(int, line.split()))[::-1]) 23 | 24 | return sorted(G), num_nodes 25 | 26 | 27 | def kruskal(G, num_nodes): 28 | uf = unionfind(num_nodes) 29 | tot_cost, MST = 0, [] 30 | 31 | for each_edge in G: 32 | cost, to_node, from_node = each_edge[0], each_edge[1], each_edge[2] 33 | 34 | if not uf.issame(from_node - 1, to_node - 1): 35 | tot_cost += cost 36 | uf.unite(from_node - 1, to_node - 1) 37 | MST.append((from_node, to_node, cost)) 38 | 39 | return MST, tot_cost 40 | 41 | 42 | if __name__ == "__main__": 43 | print("---- Computing minimal spanning tree using Kruskal's Algorithm ----") 44 | print() 45 | 46 | G, num_nodes = load_graph() 47 | 48 | print(f"Our loaded graph is: {G}") 49 | print() 50 | 51 | MST, total_cost = kruskal(G) 52 | 53 | print(f"Our minimum spanning tree is: {MST}") 54 | print(f"Total cost is: {total_cost}") 55 | -------------------------------------------------------------------------------- /Algorithms/graphtheory/kruskal/testedges.txt: -------------------------------------------------------------------------------- 1 | 7 8 2 | 1 2 20 3 | 1 3 10 4 | 2 4 50 5 | 3 5 25 6 | 3 6 70 7 | 5 6 100 8 | 5 7 150 9 | 6 5 100 -------------------------------------------------------------------------------- /Algorithms/graphtheory/nearest-neighbor-tsp/NearestNeighborTSP.py: -------------------------------------------------------------------------------- 1 | """ 2 | Author: Philip Andreadis 3 | e-mail: philip_andreadis@hotmail.com 4 | 5 | This script implements a simple heuristic solver for the Traveling Salesman Problem. 6 | It is not guaranteed that an optimal solution will be found. 7 | 8 | Format of input text file must be as follows: 9 | 1st line - number of nodes 10 | each next line is an edge and its respective weight 11 | 12 | The program is executed via command line with the graph in the txt format as input. 13 | 14 | """ 15 | 16 | import time 17 | import sys 18 | 19 | 20 | 21 | """ 22 | This function reads the text file and returns a 2d list which represents 23 | the adjacency matrix of the given graph 24 | """ 25 | def parseGraph(path): 26 | # Read number of vertices and create adjacency matrix 27 | f = open(path, "r") 28 | n = int(f.readline()) 29 | adjMatrix = [[-1 for i in range(n)] for j in range(n)] 30 | #Fill adjacency matrix with the correct edges 31 | for line in f: 32 | edge = line.split(" ") 33 | edge = list(map(int, edge)) 34 | adjMatrix[edge[0]][edge[1]] = edge[2] 35 | adjMatrix[edge[1]][edge[0]] = edge[2] 36 | for i in range(len(adjMatrix)): 37 | adjMatrix[i][i] = 0 38 | return adjMatrix 39 | 40 | 41 | 42 | """ 43 | Returns all the neighboring nodes of a node sorted based on the distance between them. 44 | """ 45 | def rankNeighbors(node,adj): 46 | sortednn = {} 47 | nList = [] 48 | for i in range(len(adj[node])): 49 | if adj[node][i]>0: 50 | sortednn[i] = adj[node][i] 51 | sortednn = {k: v for k, v in sorted(sortednn.items(), key=lambda item: item[1])} 52 | nList = list(sortednn.keys()) 53 | return nList 54 | 55 | 56 | """ 57 | Function implementing the logic of nearest neighbor TSP. 58 | Generate two lists a and b, placing the starting node in list a and the rest in list b. 59 | While b is not empty append to a the closest neighboring node of the last node in a and remove it from b. 60 | Repeat until a full path has been added to a and b is empty. 61 | Returns list a representing the shortest path of the graph. 62 | """ 63 | def nnTSP(adj): 64 | nodes = list(range(0, len(adj))) 65 | #print(nodes) 66 | weight = 0 67 | global length 68 | # Starting node is 0 69 | a = [] 70 | a.append(nodes[0]) 71 | b = nodes[1:] 72 | while b: 73 | # Take last placed node in a 74 | last = a[-1] 75 | # Find its nearest neighbor 76 | sortedNeighbors = rankNeighbors(last,adj) 77 | # If node being checked has no valid neighbors and the path is not complete a dead end is reached 78 | if (not sortedNeighbors) and len(a) 8 | 2019-02-16 Initial programming 9 | 2020-03-29 Changed few lines to be able to handle empty graphs, etc, and changed how MST is computed (now correctly) 10 | """ 11 | 12 | import heapq 13 | 14 | 15 | def load_graph(file="edges.txt"): 16 | try: 17 | f = open(file, "r") 18 | except IOError: 19 | raise ("File does not exist!") 20 | 21 | line_list = f.readlines() 22 | 23 | num_nodes, num_edges = line_list[0].split() 24 | 25 | # We want to have edge cost first because the min heap will be based on edge cost 26 | # concretely that's why we do [::-1], a bit confusing maybe 27 | G = { 28 | line: [ 29 | tuple(map(int, tup.split()))[::-1] 30 | for tup in line_list[1:] 31 | if (int(tup.split()[0]) == line or int(tup.split()[1]) == line) 32 | ] 33 | for line in range(1, int(num_nodes) + 1) 34 | } 35 | 36 | f.close() 37 | return G 38 | 39 | 40 | # Takes as input G which will have {node1: [(cost, to_node, node1), ...], node2:[(...)] } 41 | def prims_algo(G, start=1): 42 | if len(G) == 0: 43 | return [], 0 44 | 45 | unvisited_nodes = [i for i in range(1, len(G) + 1)] 46 | visited_nodes = [] 47 | tot_cost = 0 48 | 49 | unvisited_nodes.remove(start) 50 | visited_nodes.append(start) 51 | MST = [] 52 | 53 | heap = G[start] 54 | heapq.heapify(heap) 55 | 56 | while unvisited_nodes: 57 | if len(heap) == 0: 58 | # there is no MST because graph is disconnected then return MST of subgraph 59 | return MST, tot_cost 60 | 61 | (cost, n2, n1) = heapq.heappop(heap) 62 | new_node = None 63 | 64 | if n1 in unvisited_nodes and n2 in visited_nodes: 65 | new_node = n1 66 | MST.append((n2, n1, cost)) 67 | 68 | elif n1 in visited_nodes and n2 in unvisited_nodes: 69 | new_node = n2 70 | MST.append((n1, n2, cost)) 71 | 72 | if new_node != None: 73 | unvisited_nodes.remove(new_node) 74 | visited_nodes.append(new_node) 75 | tot_cost += cost 76 | 77 | for each in G[new_node]: 78 | heapq.heappush(heap, each) 79 | 80 | return MST, tot_cost 81 | 82 | 83 | if __name__ == "__main__": 84 | print("---- Computing minimal spanning tree using Prims Algorithm ---- \n") 85 | 86 | G = load_graph() 87 | MST, tot_cost = prims_algo(G) 88 | 89 | # print(f'The minimum spanning tree is: {MST}') 90 | print(f"Total cost of minimum spanning tree is {tot_cost}") 91 | -------------------------------------------------------------------------------- /Algorithms/graphtheory/prims/prim_naive.py: -------------------------------------------------------------------------------- 1 | # Prims algorithm for finding minimal spanning tree (MST) of a graph 2 | 3 | # With this straightforward implementation: O(m * n) where m = # edges, n = # vertices 4 | 5 | # Aladdin Persson 6 | # 2019-02-15 Initial programming 7 | 8 | # Improvement: Want to implement using heap datastructure 9 | 10 | 11 | def load_graph(path="edges.txt"): 12 | edge_list = [] 13 | 14 | with open(path) as f: 15 | lines = f.readlines() 16 | num_nodes, num_edges = [int(i) for i in lines[0].split()] 17 | 18 | for line in lines[1:]: 19 | node1, node2, edge_cost = [int(i) for i in line.split()] 20 | edge_list.append((node1, node2, edge_cost)) 21 | 22 | return edge_list, num_nodes, num_edges 23 | 24 | 25 | def prims_algo(edge_list, num_nodes): 26 | X = [] 27 | V = [i for i in range(1, num_nodes + 1)] 28 | E = [] 29 | total_cost = 0 30 | start = 1 31 | 32 | X.append(start) 33 | V.remove(start) 34 | 35 | while len(V) != 0: 36 | lowest_cost = float("inf") 37 | nodeX = None 38 | nodeV = None 39 | 40 | for edge in edge_list: 41 | if edge[0] in X and edge[1] in V: 42 | if edge[2] < lowest_cost: 43 | nodeX = edge[0] 44 | nodeV = edge[1] 45 | lowest_cost = edge[2] 46 | 47 | elif edge[1] in X and edge[0] in V: 48 | if edge[2] < lowest_cost: 49 | nodeX = edge[1] 50 | nodeV = edge[0] 51 | lowest_cost = edge[2] 52 | 53 | if nodeX != None: 54 | X.append(nodeV) 55 | V.remove(nodeV) 56 | E.append((nodeX, nodeV, lowest_cost)) 57 | total_cost += lowest_cost 58 | 59 | return E, total_cost 60 | 61 | 62 | if __name__ == "__main__": 63 | print("Computing minimal spanning tree using Prims Algorithm") 64 | 65 | edge_list, num_nodes, num_edges = load_graph() 66 | 67 | E, tot_cost = prims_algo(edge_list, num_nodes) 68 | -------------------------------------------------------------------------------- /Algorithms/math/euclid_gcd/euclid_gcd.py: -------------------------------------------------------------------------------- 1 | # "Euclidean algorithm is one of the oldest algorithms in common use". 2 | # The purpose is to find the greatest common divisor between two numbers a,b. 3 | 4 | # Example: gcd(21, 7) = 7 5 | 6 | # Programmed by Aladdin Persson 7 | # 2019-02-19 Initial programming 8 | 9 | 10 | def gcd_recursive(a, b): 11 | if b == 0: 12 | return a 13 | else: 14 | return gcd_recursive(b, a % b) 15 | 16 | 17 | def gcd_iterative(a, b): 18 | while b != 0: 19 | a, b = b, a % b 20 | 21 | return a 22 | 23 | 24 | if __name__ == "__main__": 25 | print(gcd_iterative(65, 14)) 26 | -------------------------------------------------------------------------------- /Algorithms/math/extended_euclidean_algorithm/euclid_gcd.py: -------------------------------------------------------------------------------- 1 | """ 2 | 3 | 4 | """ 5 | 6 | import sys 7 | 8 | sys.setrecursionlimit(100000) 9 | 10 | 11 | def extended_euclidean(a, b): 12 | if a == 0: 13 | return (b, 0, 1) 14 | 15 | else: 16 | gcd, x, y = extended_euclidean(b % a, a) 17 | return (gcd, y - (b // a) * x, x) 18 | 19 | 20 | if __name__ == "__main__": 21 | # print(extended_euclidean(5,-2772)) 22 | print(extended_euclidean(1635, 26)) 23 | -------------------------------------------------------------------------------- /Algorithms/math/intersection_of_two_sets/__pycache__/intersection_of_two_sets.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aladdinpersson/Algorithms-Collection-Python/266e5608b0c3558c3738ab749e27329010cd9fd6/Algorithms/math/intersection_of_two_sets/__pycache__/intersection_of_two_sets.cpython-37.pyc -------------------------------------------------------------------------------- /Algorithms/math/intersection_of_two_sets/intersection_of_two_sets.py: -------------------------------------------------------------------------------- 1 | """ 2 | Purpose is given two sets A,B find the intersection of them. I know there must be more efficients ways than what I, 3 | am doing here but havn't figured out how yet. 4 | 5 | Complexity: O(nlog(n)) + O(mlog(m)) + O(n+m) = O(max(n*log(n), m*log(m)) 6 | 7 | Programmed by Aladdin Persson 8 | * 2019-03-13 Initial programming 9 | 10 | """ 11 | 12 | 13 | def intersection(A, B): 14 | # n = length of A, m = length of B 15 | # O(nlog(n) + mlog(n)) cost for sorting 16 | A = sorted(A) 17 | B = sorted(B) 18 | 19 | i, j = 0, 0 20 | 21 | AB_intersection = [] 22 | 23 | # complexity O(n+m) 24 | while i < len(A) and j < len(B): 25 | if A[i] < B[j]: 26 | i += 1 27 | 28 | elif B[j] < A[i]: 29 | j += 1 30 | 31 | elif A[i] == B[j]: 32 | AB_intersection.append(A[i]) 33 | i += 1 34 | j += 1 35 | 36 | return AB_intersection 37 | 38 | 39 | if __name__ == "__main__": 40 | A = [1, 3, 5, 8, 12] 41 | B = [2, 3, 5, 10, 12] 42 | 43 | intersection_AB = intersection(A, B) 44 | print(intersection_AB) 45 | -------------------------------------------------------------------------------- /Algorithms/math/karatsuba/karatsuba.py: -------------------------------------------------------------------------------- 1 | # Purpose is to implement karatsuba multiplication, a way of computing 2 | # x * y which is faster than the normal method taught at school which has a time complexity of O(n^2) which 3 | # is very slow. This method produces a way which is much faster approx. O(n^(log2(3))) 4 | 5 | # import random to check if implementation is correct 6 | import random 7 | 8 | 9 | def karatsuba(x, y): 10 | # handle negative numbers multiplication 11 | if x < 0: 12 | return -1 * karatsuba(-x, y) 13 | if y < 0: 14 | return -1 * karatsuba(x, -y) 15 | 16 | # Base case (two numbers from 1-9 multiplication) 17 | if len(str(x)) == 1 or len(str(y)) == 1: 18 | return x * y 19 | 20 | n = max(len(str(x)), len(str(y))) 21 | 22 | # split about middle (can be done in multiple ways, found on github, thought was rly clever) 23 | a = x // 10 ** (n // 2) 24 | b = x % 10 ** (n // 2) 25 | c = y // 10 ** (n // 2) 26 | d = y % 10 ** (n // 2) 27 | 28 | # Compute the terms using recursion 29 | ac = karatsuba(a, c) 30 | bd = karatsuba(b, d) 31 | ad_bc = karatsuba(a + b, c + d) - ac - bd 32 | 33 | # calculate x * y 34 | product = ac * (10 ** (2 * (n // 2))) + ad_bc * (10 ** (n // 2)) + bd 35 | 36 | # return x * y 37 | return product 38 | 39 | 40 | # Following checks if implementation is correct 41 | # if __name__ == '__main__': 42 | # for _ in range(500): 43 | # a = random.randint(-100000, 100000) 44 | # b = random.randint(-100000, 100000) 45 | # karatsuba_result = karatsuba(a, b) 46 | # correct_result = a * b 47 | # 48 | # if karatsuba_result != correct_result: 49 | # print('mismatch for %s and %s' % (a, b)) 50 | # print(f'Correct result was {correct_result}') 51 | # print(f'Karatsuba method got it to {karatsuba_result}') 52 | # break 53 | 54 | 55 | # For Programming Assignment 1 56 | if __name__ == "__main__": 57 | x = 3141592653589793238462643383279502884197169399375105820974944592 58 | y = 2718281828459045235360287471352662497757247093699959574966967627 59 | 60 | print(karatsuba(x, y)) 61 | print(x * y) 62 | -------------------------------------------------------------------------------- /Algorithms/math/pollard_p1/pollard_p1.py: -------------------------------------------------------------------------------- 1 | """ 2 | Purpose is given a number write it only as a factorization of primes. 3 | 4 | Time complexity: 5 | 6 | Programmed by Aladdin Persson 7 | * 2019-08-22 Initial programming 8 | 9 | """ 10 | 11 | from math import gcd 12 | 13 | 14 | def pollard_p1(n): 15 | r = 2 16 | 17 | for i in range(2, 100): 18 | r = r ** i % n 19 | 20 | if gcd(r - 1, n) != 1: 21 | print("One factor found was: " + str(gcd(r - 1, n))) 22 | print("Number of iterations was: " + str(i)) 23 | return gcd(r - 1, n) 24 | 25 | print("No factorization was found") 26 | 27 | 28 | if __name__ == "__main__": 29 | pollard_p1(703425623) 30 | -------------------------------------------------------------------------------- /Algorithms/math/prime_factorization/primefactorization.py: -------------------------------------------------------------------------------- 1 | """ 2 | Purpose is given a number write it only as a factorization of primes. 3 | 4 | Time complexity: O(sqrt(n)) PSEUDO-POLYNOMIAL, actually exponential! 5 | 6 | Programmed by Aladdin Persson 7 | * 2019-03-18 Initial programming 8 | * 2019-08-19 Noticed a bug when using. Should be correct now, but I need to implement 9 | more robust tests to be certain that this is a correct implementation. 10 | 11 | """ 12 | 13 | 14 | def primefactorization(n): 15 | original_value = n 16 | values = [] 17 | 18 | for i in range(2, int(n ** 0.5) + 1): 19 | # Will not pass this if statement if i is not a prime number. 20 | # (This is because all numbers have a prime factorization) 21 | if n % i == 0: 22 | 23 | while n % i == 0: 24 | n /= i 25 | values.append(i) 26 | 27 | if len(values) != 0: 28 | values.append( 29 | int(n) 30 | ) # if we have found one factor <= sqrt(n), then there will be another factor. 31 | print(f"Prime factorization of {original_value} is: {values}") 32 | else: 33 | print( 34 | f"There is no prime factorization because the number {original_value} is a prime" 35 | ) 36 | 37 | 38 | if __name__ == "__main__": 39 | # primefactorization(2**2**6 + 1) 40 | primefactorization(123) 41 | -------------------------------------------------------------------------------- /Algorithms/math/sieve_of_eratosthenes/sieve_eratosthenes.py: -------------------------------------------------------------------------------- 1 | # Purpose of this is to find primes from [2,n] 2 | 3 | # Programmed by Aladdin Persson 4 | # 2019-02-27 Initial programming 5 | 6 | 7 | def eratosthenes(n): 8 | primes, sieve = [], [True] * (n + 1) 9 | sieve[0], sieve[1] = "Zero", "One" 10 | 11 | for num in range(2, n + 1): 12 | if sieve[num]: 13 | primes.append(num) 14 | 15 | # "Optimized" loop here because we dont have to go up 1,2,3,4 in this 16 | # we can jump num instead 17 | for i in range(num * num, n + 1, num): 18 | sieve[i] = False 19 | 20 | return primes 21 | 22 | 23 | if __name__ == "__main__": 24 | n = 10 ** 6 25 | primes = eratosthenes(n) 26 | print(primes) 27 | -------------------------------------------------------------------------------- /Algorithms/math/union_of_two_sets/__pycache__/union_of_two_sets.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aladdinpersson/Algorithms-Collection-Python/266e5608b0c3558c3738ab749e27329010cd9fd6/Algorithms/math/union_of_two_sets/__pycache__/union_of_two_sets.cpython-37.pyc -------------------------------------------------------------------------------- /Algorithms/math/union_of_two_sets/union_of_two_sets.py: -------------------------------------------------------------------------------- 1 | """ 2 | Purpose is given two sets A,B find the union of them. I know there must be more efficients ways than what I, 3 | am doing here but havn't figured out how yet. 4 | 5 | Complexity: O(nlog(n)) + O(mlog(m)) + O(n+m) = O(max(n*log(n), m*log(m)) 6 | 7 | Programmed by Aladdin Persson 8 | * 2019-03-13 Initial programming 9 | 10 | """ 11 | 12 | 13 | def union(A, B): 14 | # n = length of A, m = length of B 15 | # O(nlog(n) + mlog(n)) cost for sorting 16 | A = sorted(A) 17 | B = sorted(B) 18 | 19 | i, j = 0, 0 20 | 21 | AB_union = [] 22 | 23 | # complexity O(n+m) 24 | while i < len(A) and j < len(B): 25 | if A[i] < B[j]: 26 | AB_union.append(A[i]) 27 | i += 1 28 | 29 | elif B[j] < A[i]: 30 | AB_union.append(B[j]) 31 | j += 1 32 | 33 | elif A[i] == B[j]: 34 | AB_union.append(A[i]) 35 | i += 1 36 | j += 1 37 | 38 | AB_union.extend(A[i:]) 39 | AB_union.extend(B[j:]) 40 | 41 | return AB_union 42 | 43 | 44 | if __name__ == "__main__": 45 | A = [1, 3, 5, 8, 12] 46 | B = [2, 3, 5, 10, 12] 47 | 48 | AB_union = union(A, B) 49 | print(AB_union) 50 | -------------------------------------------------------------------------------- /Algorithms/numerical_methods/bisection.py: -------------------------------------------------------------------------------- 1 | """ 2 | # Purpose of the bisection method is to find an interval where there exists a root 3 | 4 | # Programmed by Aladdin Persson 5 | # 2019-10-07 Initial programming 6 | 7 | """ 8 | 9 | 10 | def function(x): 11 | # return (x**2 - 2) 12 | return x ** 2 + 2 * x - 1 13 | 14 | 15 | def bisection(a0, b0, eps, delta, maxit): 16 | # Initialize search bracket s.t a <= b 17 | alpha = min(a0, b0) 18 | beta = max(a0, b0) 19 | a = [] 20 | b = [] 21 | fa = function(alpha) 22 | fb = function(beta) 23 | 24 | if function(alpha) * function(beta) > 0: 25 | print("Needs to have one f(a) > 0 and f(b) < 0") 26 | exit() 27 | 28 | for j in range(maxit): 29 | a.append(alpha) 30 | b.append(beta) 31 | 32 | # Carefully compute the midpoint in an effort to avoid numerical roundoff errors 33 | midpoint = alpha + (beta - alpha) / 2 34 | fc = function(midpoint) 35 | 36 | # Check for small residual 37 | if abs(fc) <= eps: 38 | print("Very small function value -> we're close enough to a root") 39 | return alpha, beta 40 | 41 | # check for small bracket 42 | if abs(beta - alpha) <= delta: 43 | print("Interval is good enough --> We're close to root") 44 | return alpha, beta 45 | 46 | # Now we know we need to run more iterations 47 | if fa * fc < 0: 48 | beta = midpoint 49 | fb = fc 50 | else: 51 | alpha = midpoint 52 | fa = fc 53 | 54 | return alpha, beta 55 | 56 | 57 | def main(): 58 | a = 0 59 | b = 1 60 | # print(function(a)) 61 | # print(function(b)) 62 | alpha, beta = bisection(a, b, eps=1e-8, delta=1e-8, maxit=3) 63 | print("Bracket is (" + str(alpha) + ", " + str(beta) + ")") 64 | 65 | 66 | main() 67 | -------------------------------------------------------------------------------- /Algorithms/numerical_methods/fixpoint.py: -------------------------------------------------------------------------------- 1 | """ 2 | # Purpose of the fixpoint method is to solve equations of the form x = g(x) 3 | # Note that many equations can be rewritten in this form, to solve for example for roots. 4 | 5 | # Programmed by Aladdin Persson 6 | # 2019-10-07 Initial programming 7 | 8 | """ 9 | # Rewrite x^2 = 2 10 | def function(x): 11 | return (x + (2 / x)) / 2 12 | 13 | 14 | def fixpoint(x0, tol): 15 | x = x0 16 | y = function(x) 17 | 18 | while abs(x - y) > tol: 19 | x = y 20 | y = function(x) 21 | 22 | return y 23 | 24 | 25 | def main(): 26 | x0 = 2 27 | val = fixpoint(x0, tol=1e-8) 28 | print(val) 29 | 30 | 31 | main() 32 | -------------------------------------------------------------------------------- /Algorithms/other/Huffman/Huffman.py: -------------------------------------------------------------------------------- 1 | import heapq 2 | from bitarray import bitarray 3 | 4 | 5 | class Node(object): 6 | def __init__(self, ch, freq, left=None, right=None): 7 | self.ch = ch 8 | self.freq = freq 9 | self.left = left 10 | self.right = right 11 | 12 | def __lt__(self, other): 13 | return self.freq < other.freq 14 | 15 | 16 | def make_frequency_dict(file="huffman.txt"): 17 | freq = {} 18 | text = "" 19 | 20 | with open(file) as f: 21 | for line in f: 22 | text += line 23 | 24 | for char in line: 25 | if not char in freq: 26 | freq[char] = 0 27 | freq[char] += 1 28 | 29 | return freq, text 30 | 31 | 32 | def make_heap(freq): 33 | heap = [] 34 | for char in freq: 35 | node = Node(char, freq[char]) 36 | heapq.heappush(heap, node) 37 | 38 | return heap 39 | 40 | 41 | def build_tree(heap): 42 | # Create our binary tree 43 | 44 | while len(heap) > 1: 45 | nodeL = heapq.heappop(heap) 46 | nodeR = heapq.heappop(heap) 47 | tot_freq = nodeL.freq + nodeR.freq 48 | 49 | heapq.heappush(heap, Node("", tot_freq, nodeL, nodeR)) 50 | 51 | return heap 52 | 53 | 54 | def create_mapping(root, map={}, binarytext=""): 55 | # Create a mapping from each character to a binary string 56 | 57 | if root == None: 58 | return 59 | 60 | if root.left == None and root.right == None: 61 | # if we are a leaf 62 | map[root.ch] = binarytext 63 | 64 | left = create_mapping(root.left, map, binarytext + "0") 65 | right = create_mapping(root.right, map, binarytext + "1") 66 | 67 | return map 68 | 69 | 70 | def decode(binarystring, root): 71 | decoded_msg = "" 72 | curr_node = root 73 | 74 | i = 0 75 | 76 | while i <= len(binarystring): 77 | if curr_node.right == None and curr_node.left == None: 78 | decoded_msg += str(curr_node.ch) 79 | curr_node = root 80 | 81 | if i == len(binarystring): 82 | i += 1 83 | 84 | # If 1 walk right 85 | elif binarystring[i] == "1": 86 | curr_node = curr_node.right 87 | i += 1 88 | # If 0 walk left 89 | elif binarystring[i] == "0": 90 | curr_node = curr_node.left 91 | i += 1 92 | 93 | return decoded_msg 94 | 95 | 96 | def main(): 97 | freq, text = make_frequency_dict(file="Huffman.txt") 98 | # print(f"Our message that we wish to decompress using Huffman is: \n{text}") 99 | 100 | heap = make_heap(freq) 101 | tree = build_tree(heap) 102 | mapping = create_mapping(tree[0]) 103 | 104 | print(f"Our mapping is: \n{mapping}") 105 | 106 | # Get encoded message 107 | encoded = "" 108 | 109 | for letter in text: 110 | encoded += mapping[letter] 111 | 112 | print(f"Our encoded message is: \n{encoded}") 113 | 114 | out = bitarray(encoded) 115 | 116 | with open("compressed_file.bin", "wb") as f: 117 | out.tofile(f) 118 | 119 | # original_text = decode(encoded, tree[0]) 120 | 121 | 122 | if __name__ == "__main__": 123 | main() 124 | -------------------------------------------------------------------------------- /Algorithms/other/Huffman/compressed_file.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aladdinpersson/Algorithms-Collection-Python/266e5608b0c3558c3738ab749e27329010cd9fd6/Algorithms/other/Huffman/compressed_file.bin -------------------------------------------------------------------------------- /Algorithms/other/Huffman/test.txt: -------------------------------------------------------------------------------- 1 | aaabbbcdd -------------------------------------------------------------------------------- /Algorithms/other/Kadanes_algorithm.py: -------------------------------------------------------------------------------- 1 | """ 2 | Purpose of the Kadane's Algorithm is to the find the sum of the maximum 3 | contigous subarray of an array. Ex: [-2,1,-3,4,-1,2,1,-5,4] has [4,-1,2,1] 4 | with the largest sum = 6 5 | 6 | Programmed by Aladdin Persson 7 | # 2020-03-08 Initial programming 8 | 9 | """ 10 | 11 | 12 | def kadane_algorithm(array): 13 | max_current, max_global = array[0], array[0] 14 | 15 | for val in array[1:]: 16 | max_current = max(val, max_current + val) 17 | 18 | if max_current > max_global: 19 | max_global = max_current 20 | 21 | return max_global 22 | 23 | 24 | print(kadane_algorithm([-2, 1, -3, 4, -1, 2, 1, -5, 4])) 25 | -------------------------------------------------------------------------------- /Algorithms/other/__pycache__/interval_scheduling.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aladdinpersson/Algorithms-Collection-Python/266e5608b0c3558c3738ab749e27329010cd9fd6/Algorithms/other/__pycache__/interval_scheduling.cpython-38.pyc -------------------------------------------------------------------------------- /Algorithms/other/__pycache__/median_maintenance.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aladdinpersson/Algorithms-Collection-Python/266e5608b0c3558c3738ab749e27329010cd9fd6/Algorithms/other/__pycache__/median_maintenance.cpython-38.pyc -------------------------------------------------------------------------------- /Algorithms/other/binarysearch.py: -------------------------------------------------------------------------------- 1 | """ 2 | Purpose of this is to find a target element in an already sorted list L. 3 | We use the fact that it is already sorted and get a O(log(n)) search algorithm. 4 | 5 | Programmed by Aladdin Persson 6 | # 2019-03-12 Initial programming 7 | 8 | """ 9 | 10 | 11 | def binarysearch_iterative(L, target): 12 | low = 0 13 | high = len(L) - 1 14 | 15 | while low <= high: 16 | middle = (low + high) // 2 17 | 18 | if target == L[middle]: 19 | return True, middle 20 | 21 | elif target < L[middle]: 22 | high = middle - 1 23 | 24 | else: 25 | low = middle + 1 26 | 27 | return False, None 28 | 29 | 30 | def binarysearch_recursive(L, target, low, high): 31 | middle = (low + high) // 2 32 | 33 | if low > high: 34 | return False, None 35 | 36 | elif target == L[middle]: 37 | return True, middle 38 | 39 | elif target < L[middle]: 40 | return binarysearch_recursive(L, target, low, middle - 1) 41 | 42 | else: 43 | return binarysearch_recursive(L, target, middle + 1, high) 44 | 45 | 46 | if __name__ == "__main__": 47 | target = 1 48 | sorted_array = [1, 1, 1, 1, 1, 1, 1, 1] 49 | 50 | exists, idx = binarysearch_iterative(sorted_array, target) 51 | print(f"The target {target} exists in array: {exists}. The idx of it is: {idx}") 52 | 53 | exists, idx = binarysearch_recursive(sorted_array, target, 0, len(sorted_array) - 1) 54 | print(f"The target {target} exists in array: {exists}. The idx of it is: {idx}") 55 | -------------------------------------------------------------------------------- /Algorithms/other/counting_inversions.py: -------------------------------------------------------------------------------- 1 | def merge_sort(array): 2 | total_inversions = 0 3 | if len(array) <= 1: 4 | return (array, 0) 5 | 6 | midpoint = int(len(array) / 2) 7 | 8 | (left, left_inversions) = merge_sort(array[:midpoint]) 9 | (right, right_inversions) = merge_sort(array[midpoint:]) 10 | (merged_array, merge_inversions) = merge_and_count(left, right) 11 | 12 | return (merged_array, left_inversions + right_inversions + merge_inversions) 13 | 14 | 15 | def merge_and_count(left, right): 16 | count_inversions = 0 17 | result = [] 18 | left_pointer = right_pointer = 0 19 | left_len = len(left) 20 | right_len = len(right) 21 | 22 | while left_pointer < len(left) and right_pointer < len(right): 23 | if left[left_pointer] <= right[right_pointer]: 24 | result.append(left[left_pointer]) 25 | left_pointer += 1 26 | 27 | elif right[right_pointer] < left[left_pointer]: 28 | count_inversions += left_len - left_pointer 29 | result.append(right[right_pointer]) 30 | right_pointer += 1 31 | 32 | result.extend(left[left_pointer:]) 33 | result.extend(right[right_pointer:]) 34 | 35 | return (result, count_inversions) 36 | 37 | 38 | if __name__ == "__main__": 39 | array = [9, 2, 1, 5, 2, 3, 5, 1, 2, 32, 12, 11] 40 | print(array) 41 | 42 | result = merge_sort(array) 43 | print(result) 44 | -------------------------------------------------------------------------------- /Algorithms/other/interval_scheduling.py: -------------------------------------------------------------------------------- 1 | # Interval Scheduling, we have a set of requests R and we wish to choose 2 | # the maximum amount of non-overlapping intervals and output the optimal 3 | # solution as O. 4 | 5 | # Programmed by Aladdin Persson 6 | # 2020-01-25 Initial programming 7 | 8 | # Video: https://youtu.be/SmPxC8m0yIY 9 | 10 | 11 | def interval_scheduling(R, O): 12 | R.sort(key=lambda x: x[1]) # sort by finish times f1 <= f2 <= ... <= fn 13 | 14 | finish = 0 15 | 16 | for r in R: 17 | # remember r[0] start time of request r, r[1] finish time of request r 18 | if finish <= r[0]: 19 | finish = r[1] 20 | O.append(r) 21 | 22 | return O 23 | 24 | 25 | # def interval_scheduling_complicated_version(R, O): 26 | # while R: # keep going while R still has elements 27 | # (si, fi) = R[0] 28 | # O.append((si,fi)) 29 | # idx = 0 30 | # 31 | # while idx < len(R): 32 | # (sj, fj) = R[idx] 33 | # 34 | # if fi > sj: 35 | # R.remove(R[idx]) 36 | # idx -= 1 37 | # 38 | # idx += 1 39 | # return O 40 | 41 | if __name__ == "__main__": 42 | # run small example 43 | # request is: (start, end) 44 | r1 = (0, 3) 45 | r2 = (1, 3) 46 | r3 = (0, 5) 47 | r4 = (3, 6) 48 | r5 = (4, 7) 49 | r6 = (3, 9) 50 | r7 = (5, 10) 51 | r8 = (8, 10) 52 | 53 | R = [r1, r2, r3, r4, r5, r6, r7, r8] 54 | O = [] 55 | O = interval_scheduling(R, O) 56 | 57 | print("The intervals to choose are: " + str(O)) 58 | -------------------------------------------------------------------------------- /Algorithms/other/median_maintenance.py: -------------------------------------------------------------------------------- 1 | # Purpose of median_maintenance is given numbers, x then y, w, etc, maintain the median. 2 | 3 | # Programmed by Aladdin Persson 4 | # 2019-02-16 5 | 6 | # This is an optimized version using heap 7 | 8 | # note: heapq is a min-heap that is why we do -x, also we want all small values in the maxheap 9 | # and all large values in the minheap so that we can take the value on the top as our median 10 | 11 | # Improvements to be made: 12 | # * Do it without the use of globals 13 | # * Comment code 14 | 15 | import heapq 16 | 17 | 18 | class Maintain_Median(object): 19 | def __init__(self): 20 | self.maxheap = [] 21 | self.minheap = [] 22 | 23 | def medmain_insert(self, x): 24 | if len(self.maxheap) == 0: 25 | heapq.heappush(self.maxheap, -x) 26 | 27 | else: 28 | m = -self.maxheap[0] 29 | if x > m: 30 | heapq.heappush(self.minheap, x) 31 | 32 | if len(self.minheap) > len(self.maxheap): 33 | y = heapq.heappop(self.minheap) 34 | heapq.heappush(self.maxheap, -y) 35 | 36 | else: 37 | heapq.heappush(self.maxheap, -x) 38 | 39 | if len(self.maxheap) - len(self.minheap) > 1: 40 | y = -heapq.heappop(self.maxheap) 41 | heapq.heappush(self.minheap, y) 42 | 43 | return ( 44 | (-self.maxheap[0] + self.minheap[0]) / 2 45 | if len(self.maxheap) == len(self.minheap) 46 | else -self.maxheap[0] 47 | ) 48 | 49 | def main(self, data): 50 | if len(data) < 1: 51 | return data 52 | 53 | for x in data: 54 | median = self.medmain_insert(x) 55 | 56 | return median 57 | 58 | 59 | if __name__ == "__main__": 60 | data = [1, 3, 8, 5, 10] 61 | maintain_median = Maintain_Median() 62 | median = maintain_median.main(data) 63 | print(median) 64 | -------------------------------------------------------------------------------- /Algorithms/sorting/__pycache__/bubblesort.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aladdinpersson/Algorithms-Collection-Python/266e5608b0c3558c3738ab749e27329010cd9fd6/Algorithms/sorting/__pycache__/bubblesort.cpython-37.pyc -------------------------------------------------------------------------------- /Algorithms/sorting/__pycache__/insertionsort.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aladdinpersson/Algorithms-Collection-Python/266e5608b0c3558c3738ab749e27329010cd9fd6/Algorithms/sorting/__pycache__/insertionsort.cpython-37.pyc -------------------------------------------------------------------------------- /Algorithms/sorting/__pycache__/mergesort.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aladdinpersson/Algorithms-Collection-Python/266e5608b0c3558c3738ab749e27329010cd9fd6/Algorithms/sorting/__pycache__/mergesort.cpython-37.pyc -------------------------------------------------------------------------------- /Algorithms/sorting/__pycache__/quicksort.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aladdinpersson/Algorithms-Collection-Python/266e5608b0c3558c3738ab749e27329010cd9fd6/Algorithms/sorting/__pycache__/quicksort.cpython-37.pyc -------------------------------------------------------------------------------- /Algorithms/sorting/__pycache__/randomized_quicksort.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aladdinpersson/Algorithms-Collection-Python/266e5608b0c3558c3738ab749e27329010cd9fd6/Algorithms/sorting/__pycache__/randomized_quicksort.cpython-37.pyc -------------------------------------------------------------------------------- /Algorithms/sorting/__pycache__/selectionsort.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aladdinpersson/Algorithms-Collection-Python/266e5608b0c3558c3738ab749e27329010cd9fd6/Algorithms/sorting/__pycache__/selectionsort.cpython-37.pyc -------------------------------------------------------------------------------- /Algorithms/sorting/bubblesort.py: -------------------------------------------------------------------------------- 1 | """ 2 | Bubblesort sorting algorithm. This is not a very efficient sorting algorithm, T(n) = O(n^2). 3 | 4 | Programmed by Aladdin Persson 5 | * 2019-01-23 Initial code 6 | * 2019-03-05 Improved code by having swapped, while-loop and raise error 7 | 8 | """ 9 | 10 | 11 | def bubblesort(L): 12 | swapped = True 13 | 14 | while swapped: 15 | swapped = False 16 | 17 | for j in range(len(L) - 1): 18 | if L[j] > L[j + 1]: 19 | L[j], L[j + 1] = L[j + 1], L[j] 20 | swapped = True 21 | return L 22 | 23 | 24 | if __name__ == "__main__": 25 | unsorted = [5, 2, 4, 6, 1, 3] 26 | sorted = bubblesort(unsorted) 27 | print(sorted) 28 | -------------------------------------------------------------------------------- /Algorithms/sorting/hopesort.py: -------------------------------------------------------------------------------- 1 | """ 2 | Hopesort algorithm. If it works, then it works in constant time. 3 | Use at own risk :) 4 | 5 | Programmed by Aladdin Persson 6 | * 2019-03-08 Initial code 7 | 8 | """ 9 | 10 | 11 | def hopesort(L): 12 | # hope it is sorted 13 | return L 14 | 15 | 16 | if __name__ == "__main__": 17 | unsorted = [1, 2, 3, 4, 5, 6] 18 | # constant time 19 | hopefully_sorted = hopesort(unsorted) 20 | print(hopefully_sorted) 21 | -------------------------------------------------------------------------------- /Algorithms/sorting/insertionsort.py: -------------------------------------------------------------------------------- 1 | """ 2 | Insertion sort algorithm O(n^2). 3 | 4 | Programmed by Aladdin Persson 5 | * 2019-01-23 Initial programming 6 | * 2019-03-05 Made code cleaner 7 | """ 8 | 9 | 10 | def insertionsort(L): 11 | # loop through all except first element in list 12 | for index in range(1, len(L)): 13 | value = L[index] 14 | 15 | position = index - 1 16 | 17 | # inserts the key into the correct place 18 | while position >= 0 and L[position] > value: 19 | L[position + 1] = L[position] 20 | position -= 1 21 | 22 | L[position + 1] = value 23 | 24 | return L 25 | 26 | 27 | if __name__ == "__main__": 28 | unsorted = [7, 2, 4, 1, 5, 3] 29 | sorted = insertionsort(unsorted) 30 | print(sorted) 31 | -------------------------------------------------------------------------------- /Algorithms/sorting/mergesort.py: -------------------------------------------------------------------------------- 1 | def merge_sort(array): 2 | 3 | if len(array) <= 1: 4 | return array 5 | 6 | midpoint = int(len(array) / 2) 7 | 8 | left, right = merge_sort(array[:midpoint]), merge_sort(array[midpoint:]) 9 | 10 | return merge(left, right) 11 | 12 | 13 | def merge(left, right): 14 | result = [] 15 | left_pointer = right_pointer = 0 16 | 17 | while left_pointer < len(left) and right_pointer < len(right): 18 | if left[left_pointer] <= right[right_pointer]: 19 | result.append(left[left_pointer]) 20 | left_pointer += 1 21 | 22 | elif right[right_pointer] < left[left_pointer]: 23 | result.append(right[right_pointer]) 24 | right_pointer += 1 25 | 26 | result.extend(left[left_pointer:]) 27 | result.extend(right[right_pointer:]) 28 | 29 | return result 30 | 31 | 32 | # if __name__ == "__main__": 33 | # array = [5, 4, 3, 2, 1] 34 | # print(array) 35 | # 36 | # result = merge_sort(array) 37 | # print(result) 38 | -------------------------------------------------------------------------------- /Algorithms/sorting/quicksort.py: -------------------------------------------------------------------------------- 1 | # Quicksort with pivot always using first index as pivot 2 | 3 | 4 | def quicksort_firstpivot(L): 5 | if len(L) <= 1: 6 | return L 7 | 8 | pivot = L[0] 9 | 10 | i = 0 11 | 12 | for j in range(1, len(L)): 13 | if L[j] < pivot: 14 | L[j], L[i + 1] = L[i + 1], L[j] 15 | i += 1 16 | 17 | L[0], L[i] = L[i], L[0] 18 | 19 | left = quicksort_firstpivot(L[:i]) 20 | right = quicksort_firstpivot(L[i + 1 :]) 21 | left.append(L[i]) 22 | result = left + right 23 | return result 24 | 25 | 26 | # Quicksort with pivot always using last index as pivot 27 | def quicksort_lastpivot(x): 28 | if len(x) <= 1: 29 | return x 30 | 31 | x[0], x[-1] = x[-1], x[0] 32 | pivot = x[0] 33 | 34 | i = 0 35 | 36 | for j in range(1, len(x)): 37 | if x[j] < pivot: 38 | x[j], x[i + 1] = x[i + 1], x[j] 39 | i += 1 40 | 41 | x[0], x[i] = x[i], x[0] 42 | 43 | left = quicksort_lastpivot(x[:i]) 44 | right = quicksort_lastpivot(x[i + 1 :]) 45 | left.append(x[i]) 46 | 47 | result = left + right 48 | return result 49 | -------------------------------------------------------------------------------- /Algorithms/sorting/randomized_quicksort.py: -------------------------------------------------------------------------------- 1 | """ 2 | Purpose is to sort a list. The reason why randomizing is better is that on average, regardless on the input 3 | randomized quicksort will have a running time of O(n*logn). This is regardless of the ordering of the inputted list. 4 | This is in constrast to first pivot, median pivot, etc Quicksort. 5 | 6 | Programmed by Aladdin Persson 7 | * 2019-03-08 Initial programming 8 | 9 | """ 10 | 11 | import random 12 | 13 | 14 | def quicksort_randomized(L): 15 | if len(L) <= 1: 16 | return L 17 | 18 | # Randomly choose a pivot idx 19 | pivot_idx = random.randint(0, len(L) - 1) 20 | pivot = L[pivot_idx] 21 | 22 | # Swap pivot_idx to the first position 23 | L[0], L[pivot_idx] = L[pivot_idx], L[0] 24 | 25 | i = 0 26 | # range(1, len(L)) because we the pivot element is the first element 27 | for j in range(1, len(L)): 28 | if L[j] < pivot: 29 | L[j], L[i + 1] = L[i + 1], L[j] 30 | i += 1 31 | 32 | L[0], L[i] = L[i], L[0] 33 | 34 | left = quicksort_randomized(L[:i]) 35 | right = quicksort_randomized(L[i + 1 :]) 36 | left.append(L[i]) 37 | 38 | result = left + right 39 | 40 | return result 41 | 42 | 43 | if __name__ == "__main__": 44 | l = [6, 7, 3, 4, 5, 1, 3, 7, 123] 45 | sorted_l = quicksort_randomized(l) 46 | print(sorted_l) 47 | -------------------------------------------------------------------------------- /Algorithms/sorting/selectionsort.py: -------------------------------------------------------------------------------- 1 | """ 2 | Selection sort algorithm. T(n) = O(n^2) 3 | 4 | Programmed by Aladdin Persson 5 | * 2019-03-05 Initial coding 6 | 7 | """ 8 | 9 | # Selection sort that creates a copy. More "intuitive" but requires extra memory. 10 | def selectionsort_intuitive(L): 11 | correctly_sorted = [] 12 | 13 | while L: 14 | min = L[0] 15 | 16 | for element in L: 17 | min = element if element < min else min 18 | 19 | correctly_sorted.append(min) 20 | L.remove(min) 21 | 22 | return correctly_sorted 23 | 24 | 25 | def selectionsort(L): 26 | for i in range(len(L) - 1): 27 | min_index = i 28 | 29 | # Look through entire list, look which is the smallest element 30 | for j in range(i + 1, len(L)): 31 | if L[j] < L[min_index]: 32 | min_index = j 33 | 34 | # If the smallest isn't the index itself, then swap 35 | if min_index != i: 36 | L[i], L[min_index] = L[min_index], L[i] 37 | 38 | return L 39 | 40 | 41 | if __name__ == "__main__": 42 | unsorted = [10000, 2, 7, 4, 1, 5, 3, 15, 13, 169] 43 | sorted = selectionsort_intuitive(unsorted) 44 | print(sorted) 45 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Aladdin Perzon 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.com/AladdinPersson/Algorithms-Collection-Python.svg?branch=master)](https://travis-ci.com/AladdinPersson/Algorithms-Collection-Python) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![codecov](https://codecov.io/gh/aladdinpersson/Algorithms-Collection-Python/branch/master/graph/badge.svg)](https://codecov.io/gh/aladdinpersson/Algorithms-Collection-Python) 2 | 3 | # Algorithms Collection Python 4 | Whenever I face an interesting problem I document the algorithm that I learned to solve it. The goals of this repository is to have clean, efficient and most importantly correct code. 5 | 6 | :white_check_mark:: If the algorithm is tested \ 7 | :small_red_triangle:: If the algorithm is untested 8 | 9 | # Dynamic Programming 10 | * :white_check_mark: [Knapsack 0/1](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/dynamic_programming/knapsack/knapsack_bottomup.py) **- O(nC) Bottom-Up implementation (Loops)** 11 | * :white_check_mark: [:movie_camera:](https://youtu.be/XmyxiSc3LKg)[Sequence Alignment](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/dynamic_programming/sequence_alignment.py) **- O(nm)** 12 | * :white_check_mark: [:movie_camera:](https://youtu.be/dU-coYsd7zw)[Weighted Interval Scheduling](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/dynamic_programming/weighted_interval_scheduling.py) **- O(nlog(n))** 13 | 14 | # Graph theory 15 | * :white_check_mark: [Kahns Topological Sort](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/kahns-toposort/kahn_topological_ordering.py) **- O(n + m)** 16 | * :white_check_mark: [Bellman-Ford Shortest Path](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/bellman-ford/bellman_ford.py) **- O(mn)** 17 | * :small_red_triangle: [Floyd-Warshall Shortest Path](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/floyd-warshall/floyd-warshall.py) **- O(n3)** 18 | * :white_check_mark: [Dijkstra Shortest Path](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/dijkstra/dijkstra.py) **- Naive implementation** 19 | * :white_check_mark: [Dijkstra Shortest Path](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/dijkstra/heapdijkstra.py) **- O(mlog(n)) - Heap implementation** 20 | * :small_red_triangle: [Karger's Minimum cut](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/kargers/kargermincut.py) 21 | * :small_red_triangle: [Prim's Algorithm](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/prims/prim_naive.py) **- O(mn) Naive implementation** 22 | * :white_check_mark: [Prim's Algorithm](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/prims/prim_heap.py) **- O(mlog(n)) Heap implementation** 23 | * :small_red_triangle: [Kruskal's Algorithm](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/kruskal/kruskal.py) **- O(mn) implementation** 24 | * :white_check_mark: [Kruskal's Algorithm](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/kruskal/kruskal_unionfind.py) **- O(mlog(n))** 25 | * :white_check_mark: [Breadth First Search](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/breadth-first-search/BFS_queue_iterative.py) **- O(n + m) - Queue Implementation** 26 | * :white_check_mark: [Depth First Search](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/depth-first-search/DFS_stack_iterative.py) **- O(n + m) - Stack Implementation** 27 | * :white_check_mark: [Depth First Search](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/depth-first-search/DFS_recursive.py) **- O(n + m) - Recursive Implementation** 28 | 29 | # Mathematics 30 | ### Algebra 31 | * :small_red_triangle: [Karatsuba Multiplication](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/math/karatsuba/karatsuba.py) **- O(n1.585)** 32 | * :white_check_mark: [Intersection of two sets](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/math/intersection_of_two_sets/intersection_of_two_sets.py) **- O(nlog(n)) + O(mlog(m))** 33 | * :white_check_mark: [Union of two sets](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/math/union_of_two_sets/union_of_two_sets.py) **- O(nlog(n)) + O(mlog(m))** 34 | 35 | ### Number Theory 36 | * :small_red_triangle: [Pollard p-1 factorization](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/math/pollard_p1/pollard_p1.py) 37 | * :small_red_triangle: [Euclidean Algorithm](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/math/euclid_gcd/euclid_gcd.py) **- O(log(n))** 38 | * :small_red_triangle: [Extended Euclidean Algorithm](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/math/extended_euclidean_algorithm/euclid_gcd.py) **- O(log(n))** 39 | * :small_red_triangle: [Sieve of Eratosthenes](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/math/sieve_of_eratosthenes/sieve_eratosthenes.py) **- O(nlog(log(n)))** 40 | * :small_red_triangle: [Prime factorization](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/math/prime_factorization/primefactorization.py) **- O(sqrt(n))** 41 | 42 | ### Cryptography 43 | * :white_check_mark: [Ceasar Cipher](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/cryptology/ceasar_shifting_cipher/ceasar_shift_cipher.py) 44 | * :small_red_triangle: [Hill Cipher](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/cryptology/hill_cipher/hill_cipher.py) 45 | * :small_red_triangle: [Vigenere Cipher](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/cryptology/vigenere_cipher/vigenere.py)* 46 | * :small_red_triangle: [One time pad](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/cryptology/one_time_pad/one_time_pad.py) 47 | * :small_red_triangle: [RSA-Algorithm](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/cryptology/RSA_algorithm/RSA.py) 48 | 49 | 50 | ### Numerical Methods 51 | * :small_red_triangle: [Bisection Method](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/numerical_methods/bisection.py) 52 | * :small_red_triangle: [(simple) Fixpoint iteration](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/numerical_methods/fixpoint.py) 53 | 54 | # Other 55 | * :white_check_mark: [Maintaining Median](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/other/median_maintenance.py) **- O(nlog(n))** 56 | * :small_red_triangle: [Huffman Algorithm](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/other/Huffman/Huffman.py) 57 | * :white_check_mark: [:movie_camera:](https://youtu.be/SmPxC8m0yIY)[Interval Scheduling](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/other/interval_scheduling.py) **- O(nlog(n))** 58 | * :white_check_mark: [Binary Search](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/other/binarysearch.py) **- O(log(n))** 59 | 60 | # Sorting algorithms 61 | * :white_check_mark: [Bubble sort](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/sorting/bubblesort.py) **- O(n2)** 62 | * :small_red_triangle: [Hope sort](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/sorting/hopesort.py) **- O(1), hopefully** 63 | * :white_check_mark: [Insertion sort](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/sorting/insertionsort.py) **- O(n2)** 64 | * :white_check_mark: [Selection sort](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/sorting/selectionsort.py) **- O(n2)** 65 | * :white_check_mark: [Merge sort](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/sorting/mergesort.py) **- O(nlog(n))** 66 | * :white_check_mark: [Randomized Quick sort](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/sorting/randomized_quicksort.py) **- Average O(nlogn) (Input independent!)** 67 | * :white_check_mark: [Quick sort](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/sorting/quicksort.py) **- Average O(nlog(n))** 68 | 69 | # Contributing 70 | I appreciate feedback on potential improvements and/or if you see an error that I've made! Also if you would like to contribute then do a pull request with algorithm & tests! :) 71 | 72 | 73 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | unionfind==0.0.10 2 | numpy==1.18.1 3 | bitarray==1.2.1 4 | egcd==0.0.1.1 5 | sympy==1.5.1 6 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup 2 | 3 | setup( 4 | name="Algorithms", 5 | packages=["Algorithm_test"], 6 | version="0.0.7", 7 | description="Testing Algorithm Collection", 8 | url="https://github.com/aladdinpersson/Algorithms-Collection-Python", 9 | ) 10 | --------------------------------------------------------------------------------