├── .gitignore ├── LICENSE ├── README.md ├── autoresizelist.py ├── binary_search_tree.py ├── breadth_first_search.py ├── city_data.json ├── combinatorics.py ├── depth_first_search.py ├── dijkstra.py ├── fib.py ├── get_city_data.py ├── hashtable.py ├── heap.py ├── heap_speed_test.py ├── mergesort.py ├── nqueens.py ├── prefix_calc.py ├── quicksort.py ├── reverse.py ├── straight_city_distances.json └── test ├── test_autoresizelist.py ├── test_hashtable.py ├── test_heap.py ├── test_mergesort.py ├── test_nqueens.py └── test_quicksort.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | *.egg-info/ 23 | .installed.cfg 24 | *.egg 25 | 26 | # PyInstaller 27 | # Usually these files are written by a python script from a template 28 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 29 | *.manifest 30 | *.spec 31 | 32 | # Installer logs 33 | pip-log.txt 34 | pip-delete-this-directory.txt 35 | 36 | # Unit test / coverage reports 37 | htmlcov/ 38 | .tox/ 39 | .coverage 40 | .cache 41 | nosetests.xml 42 | coverage.xml 43 | 44 | # Translations 45 | *.mo 46 | *.pot 47 | 48 | # Django stuff: 49 | *.log 50 | 51 | # Sphinx documentation 52 | docs/_build/ 53 | 54 | # PyBuilder 55 | target/ 56 | 57 | .idea 58 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Caleb Madrigal 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 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Algorithm Implementations 2 | 3 | This is just a collection of algorithms I wanted to implement in order to improve my understanding. They are NOT optimized and probably shouldn't be used in production code. 4 | 5 | 6 | To run all unit tests: 7 | 8 | python3 -m unittest discover test 9 | 10 | 11 | ## quicksort 12 | 13 | Recursive implementation of the quick sort algorithm. 14 | 15 | To run tests: 16 | 17 | python3 quicksort.py 18 | 19 | 20 | ## mergesort 21 | 22 | Recursive implementation of the merge sort algorithm. 23 | 24 | To run tests: 25 | 26 | python3 mergesort.py 27 | 28 | 29 | ## hashtable 30 | 31 | Simple hashtable implementation 32 | 33 | 34 | ## autoresizelist 35 | 36 | A helper class used to implement the heap. 37 | 38 | To run tests: 39 | 40 | python3 autoresizelist.py 41 | 42 | 43 | ## heap 44 | 45 | Implementation of a heap. 46 | 47 | To run tests: 48 | 49 | python3 heap.py 50 | 51 | 52 | ## nqueens 53 | 54 | Backtracking solution to the n-queens problem (just finds the first one). 55 | 56 | To run: 57 | 58 | python3 nqueens.py 59 | 60 | To run tests: 61 | 62 | python3 -m unittest discover test --pattern="*nqueens*" 63 | 64 | 65 | ## combinatorics 66 | 67 | Various combinatoric functions like permutations and combinations. 68 | 69 | To run: 70 | 71 | python3 combinatorics.py 72 | 73 | -------------------------------------------------------------------------------- /autoresizelist.py: -------------------------------------------------------------------------------- 1 | """autoresizelist.py - list wrapper that automatically expands the list when 2 | indices outside its current range are accessed """ 3 | 4 | __author__ = 'caleb' 5 | __date__ = "2015-02-17" 6 | 7 | 8 | class AutoResizeList: 9 | def __init__(self, initial_data=None, fill=None): 10 | if initial_data is None: 11 | self._data = [] 12 | else: 13 | self._data = initial_data 14 | self.fill = fill 15 | 16 | def __setitem__(self, key, value): 17 | if key >= len(self._data): 18 | self._data += [self.fill] * (key - len(self._data) + 1) 19 | self._data[key] = value 20 | 21 | def __getitem__(self, key): 22 | #if key >= len(self._data): 23 | # self._data += [self.fill] * (key - len(self._data) + 1) 24 | return self._data[key] 25 | 26 | def __delitem__(self, key): 27 | del self._data[key] 28 | 29 | def __repr__(self): 30 | return str(self._data) 31 | 32 | def __eq__(self, other): 33 | return self._data == other._data 34 | 35 | def __len__(self): 36 | return len(self._data) 37 | 38 | def append(self, item): 39 | self._data.append(item) 40 | 41 | def prepend(self, item): 42 | self._data = [item] + self._data 43 | 44 | if __name__ == "__main__": 45 | import unittest 46 | testsuite = unittest.TestLoader().discover('test', pattern="*autoresizelist*") 47 | unittest.TextTestRunner(verbosity=1).run(testsuite) 48 | -------------------------------------------------------------------------------- /binary_search_tree.py: -------------------------------------------------------------------------------- 1 | """ Binary Search Tree implemented with embedded lists. 2 | 3 | Node format: [value, left child, right child]. 4 | Leaf nodes look like: [value, [], []]. 5 | """ 6 | 7 | __author__ = "Caleb Madrigal" 8 | __date__ = "2015-02-25" 9 | 10 | 11 | def node_value(node, new_value=None): 12 | """ Set value: node_value(node, value); Get value: node_value(node). """ 13 | 14 | if new_value is not None: 15 | node[0] = new_value 16 | return node[0] 17 | 18 | 19 | def left_child(node, new_node=None): 20 | """ Set left child: left_child(node, new_left_child); Get left node: left_child(node). """ 21 | 22 | if new_node is not None: 23 | node[1] = new_node 24 | return node[1] 25 | 26 | 27 | def right_child(node, new_node=None): 28 | """ Set right child: right_child(node, new_right_child); Get right node: right_child(node). """ 29 | 30 | if new_node is not None: 31 | node[2] = new_node 32 | return node[2] 33 | 34 | 35 | def add(tree, value): 36 | """ Adds value to tree and returns tree. """ 37 | 38 | if tree == []: 39 | tree = [value, [], []] 40 | elif node_value(tree) == None: 41 | node_value(tree, value) 42 | elif value < node_value(tree): 43 | left_child(tree, add(left_child(tree), value)) 44 | elif value > node_value(tree): 45 | right_child(tree, add(right_child(tree), value)) 46 | # If value == node_value(tree): It's already there - don't reinsert it 47 | return tree 48 | 49 | 50 | def _find_node(tree, value, parent=None, is_right_child=False): 51 | """ Returns (node, parent, is_right_child_of_parent) if found (parent is None if root). 52 | If not found, return (None, None, False). """ 53 | 54 | if tree == []: 55 | return (None, parent, is_right_child) 56 | if node_value(tree) == value: 57 | return (tree, parent, is_right_child) 58 | elif value < node_value(tree): 59 | return _find_node(left_child(tree), value, tree, False) 60 | else: # value > node_value(tree) 61 | return _find_node(right_child(tree), value, tree, True) 62 | 63 | 64 | def contains(tree, value): 65 | """ Returns true if value in tree; False otherwise. """ 66 | 67 | return _find_node(tree, value)[0] != None 68 | 69 | 70 | def _find_min_node(tree, parent=None, is_right_child=False): 71 | """ Finds the minimum node in a tree, and returns (node, parent, is_right_child), 72 | where node is the node with the minimum value, parent is the parent of the minimum 73 | node, and is_right_child is true if the minimum node is the right-child of its parent 74 | (or false if it is the left-child of its parent). """ 75 | 76 | if left_child(tree) == []: 77 | return (tree, parent, is_right_child) 78 | else: 79 | return _find_min_node(left_child(tree), tree, False) 80 | 81 | 82 | def _remove_node(node_to_remove, parent, is_right_child_of_parent): 83 | # If node not found, return 84 | if not node_to_remove: 85 | return 86 | 87 | def set_parent_reference(new_reference): 88 | if parent: 89 | if is_right_child_of_parent: 90 | right_child(parent, new_reference) 91 | else: 92 | left_child(parent, new_reference) 93 | 94 | # If the node to be removed has 2 children; Steps: 95 | # * Set the node_to_remove value to the min value in the right subtree 96 | # * call _remove_node() on the item which was swapped with 97 | if left_child(node_to_remove) != [] and right_child(node_to_remove) != []: 98 | (right_child_min_node, rchild_min_node_parent, is_min_right_child) = \ 99 | _find_min_node(right_child(node_to_remove), node_to_remove, True) 100 | node_value(node_to_remove, node_value(right_child_min_node)) 101 | _remove_node(right_child_min_node, rchild_min_node_parent, is_min_right_child) 102 | 103 | # If the node to be removed has just 1 child (the left child), set the parent reference 104 | # to the left child of the node to be removed 105 | elif left_child(node_to_remove) != []: 106 | set_parent_reference(left_child(node_to_remove)) 107 | 108 | # If the node to be removed has just 1 child (the right child), set the parent reference 109 | # to the right child of the node to be removed 110 | elif right_child(node_to_remove) != []: 111 | set_parent_reference(right_child(node_to_remove)) 112 | 113 | # The node has no children, so just remove it 114 | else: 115 | set_parent_reference([]) 116 | 117 | 118 | def remove(tree, value): 119 | (node_to_remove, parent, is_right_child_of_parent) = _find_node(tree, value) 120 | _remove_node(node_to_remove, parent, is_right_child_of_parent) 121 | 122 | 123 | def inorder(tree): 124 | if tree == [] or node_value(tree) == None: 125 | return [] 126 | return inorder(left_child(tree)) + [node_value(tree)] + inorder(right_child(tree)) 127 | 128 | 129 | def inorder_traverse(tree, visit_func): 130 | if tree == [] or node_value(tree) == None: 131 | return 132 | inorder_traverse(left_child(tree), visit_func) 133 | visit_func(node_value(tree)) 134 | inorder_traverse(right_child(tree), visit_func) 135 | 136 | 137 | def postorder_traverse(tree, visit_func): 138 | if tree == [] or node_value(tree) == None: 139 | return 140 | postorder_traverse(left_child(tree), visit_func) 141 | postorder_traverse(right_child(tree), visit_func) 142 | visit_func(node_value(tree)) 143 | 144 | 145 | def preorder_traverse(tree, visit_func): 146 | if tree == [] or node_value(tree) == None: 147 | return 148 | visit_func(node_value(tree)) 149 | preorder_traverse(left_child(tree), visit_func) 150 | preorder_traverse(right_child(tree), visit_func) 151 | 152 | 153 | def print_tree(tree, indent=0): 154 | if tree == [] or node_value(tree) == None: 155 | return 156 | print('\t'*indent + str(node_value(tree))) 157 | print_tree(left_child(tree), indent+1) 158 | print_tree(right_child(tree), indent+1) 159 | 160 | 161 | if __name__ == '__main__': 162 | tree = [] 163 | for i in [5, 3, 8, 5, 2, 10, 20, 15, 30, 0, 7]: 164 | tree = add(tree, i) 165 | print("Tree:") 166 | print_tree(tree) 167 | print(tree) 168 | print("Is 5 in tree?", contains(tree, 5)) 169 | print("Is 20 in tree?", contains(tree, 20)) 170 | print("Is 100 in tree?", contains(tree, 100)) 171 | print("Inorder:", inorder(tree)) 172 | print("Inorder traversal: ", end="") 173 | inorder_traverse(tree, lambda node: print(node, end=", ")) 174 | print("\nPostorder traversal: ", end="") 175 | postorder_traverse(tree, lambda node: print(node, end=", ")) 176 | print("\nPreorder traversal: ", end="") 177 | preorder_traverse(tree, lambda node: print(node, end=", ")) 178 | print() 179 | 180 | remove(tree, 8) 181 | print("Tree after removing 8:") 182 | print_tree(tree) 183 | print("Inorder:", inorder(tree)) 184 | -------------------------------------------------------------------------------- /breadth_first_search.py: -------------------------------------------------------------------------------- 1 | """ Breadth-first search 2 | 3 | This ignores the distance between the city data, and just cares about number of hops. 4 | 5 | This implementation is admittedly tightly-coupled to my particular city_data data set 6 | (to add clarity in understanding by making it tied to concrete data). 7 | 8 | The city_data is a list of 28 large cities in the United States, with some considered 9 | neighbors of the others. This would be the case in, say, a bus system which only 10 | travels between major cities. Using the shortest path on this data outputs 11 | the best path through these major cities. 12 | 13 | The format of city_data is like this: 14 | 15 | { "Milwaukee, WI": {"Minneapolis, MN": 542093, "Chicago, IL": 148198}, 16 | "Minneapolis, MN": {"Seattle, WA": 2665735, "Milwaukee, WI": 541660}, ... } 17 | 18 | So the neighbors of a city node can be found like this: list(city_data["Milwaukee, WI"].keys()) 19 | 20 | """ 21 | 22 | import json 23 | import sys 24 | from collections import deque 25 | 26 | 27 | def unroll_shortest_path(current, optimal_parent_map, path=()): 28 | if current is None: # Reached the start node 29 | return path 30 | else: 31 | return unroll_shortest_path(optimal_parent_map[current], optimal_parent_map, (current,) + path) 32 | 33 | 34 | def breadth_first_search(from_city, to_city, city_data): 35 | to_visit = deque([from_city]) 36 | visited = set([from_city]) 37 | parent_map = {from_city: None} 38 | 39 | while to_visit != []: 40 | current = to_visit.popleft() # Treat to_visit as queue 41 | print("Visiting:", current) 42 | neighbors = city_data[current].keys() 43 | 44 | for n in neighbors: 45 | if n == to_city: 46 | parent_map[n] = current 47 | return unroll_shortest_path(to_city, parent_map) 48 | 49 | elif n not in visited: 50 | parent_map[n] = current 51 | visited.add(n) 52 | to_visit.append(n) 53 | 54 | return None 55 | 56 | 57 | def get_city_data(): 58 | city_data = None 59 | with open("city_data.json","r") as f: 60 | city_data = json.loads(f.read()) 61 | return city_data 62 | 63 | 64 | if __name__ == '__main__': 65 | city_data = get_city_data() 66 | try: 67 | city_from = sys.argv[1] 68 | city_to = sys.argv[2] 69 | except IndexError: 70 | print("Usage:", sys.argv[0], "\"from city\" \"to city>\"") 71 | print("City choices:") 72 | for city in city_data: 73 | print(" -", city) 74 | sys.exit(1) 75 | 76 | print(breadth_first_search(city_from, city_to, city_data)) 77 | 78 | -------------------------------------------------------------------------------- /city_data.json: -------------------------------------------------------------------------------- 1 | {"Atlanta, GA": {"Cincinnati, OH": 741139, "Dallas, TX": 1257683, "Jacksonville, FL": 556216, "St. Louis, MO": 893097}, "Dallas, TX": {"Houston, TX": 385041, "Atlanta, GA": 1257752, "St. Louis, MO": 1015512, "Austin, TX": 314529, "Kansas City, MO": 816042, "Albuquerque, NM": 1035373}, "St. Louis, MO": {"Indianapolis, IN": 390419, "Atlanta, GA": 891353, "Kansas City, MO": 398642, "Chicago, IL": 477802, "Dallas, TX": 1014089}, "Miami, FL": {"Orlando, FL": 378239}, "Philadelphia, PA": {"Pittsburgh, PA": 490753, "New York, NY": 151616}, "Minneapolis, MN": {"Milwaukee, WI": 541660, "Seattle, WA": 2665735}, "San Francisco, CA": {"Portland, OR": 1021718, "Denver, CO": 2013984, "Los Angeles, CA": 613302}, "Las Vegas, NV": {"Denver, CO": 1204061, "Los Angeles, CA": 435660, "Phoenix, AZ": 477947}, "New York, NY": {"Boston, MA": 346522, "Philadelphia, PA": 151732}, "Cincinnati, OH": {"Atlanta, GA": 741739, "Indianapolis, IN": 174365, "Pittsburgh, PA": 463835, "Cleveland, OH": 401369}, "Kansas City, MO": {"Dallas, TX": 813639, "Denver, CO": 969112, "St. Louis, MO": 398584}, "Los Angeles, CA": {"San Francisco, CA": 614381, "Las Vegas, NV": 433665, "Phoenix, AZ": 598825}, "Albuquerque, NM": {"Dallas, TX": 1035081, "Denver, CO": 719078, "Phoenix, AZ": 676192}, "Milwaukee, WI": {"Chicago, IL": 148198, "Minneapolis, MN": 542093}, "Denver, CO": {"San Francisco, CA": 2014911, "Las Vegas, NV": 1205393, "Portland, OR": 1996215, "Kansas City, MO": 970515, "Albuquerque, NM": 716146}, "Cleveland, OH": {"Cincinnati, OH": 400243, "Pittsburgh, PA": 214818, "Chicago, IL": 554548, "Detroit, MI": 271835}, "Orlando, FL": {"Miami, FL": 379077, "Jacksonville, FL": 226439}, "Pittsburgh, PA": {"Cincinnati, OH": 465108, "Philadelphia, PA": 489601, "Cleveland, OH": 213505}, "Boston, MA": {"New York, NY": 347249}, "Portland, OR": {"San Francisco, CA": 1022620, "Denver, CO": 1996083, "Seattle, WA": 278478}, "Houston, TX": {"Dallas, TX": 384815, "San Antonio, TX": 317169}, "Chicago, IL": {"Milwaukee, WI": 148255, "Indianapolis, IN": 294793, "Detroit, MI": 454804, "Cleveland, OH": 556013, "St. Louis, MO": 477781}, "Seattle, WA": {"Portland, OR": 278445, "Minneapolis, MN": 2665127}, "Phoenix, AZ": {"Las Vegas, NV": 477754, "Los Angeles, CA": 599098, "Albuquerque, NM": 677561}, "Austin, TX": {"Dallas, TX": 314426, "San Antonio, TX": 128428}, "Indianapolis, IN": {"Cincinnati, OH": 180745, "Chicago, IL": 293881, "St. Louis, MO": 390167}, "Detroit, MI": {"Chicago, IL": 455103, "Cleveland, OH": 273335}, "San Antonio, TX": {"Houston, TX": 317554, "Austin, TX": 128201}, "Jacksonville, FL": {"Atlanta, GA": 556465, "Orlando, FL": 226582}} -------------------------------------------------------------------------------- /combinatorics.py: -------------------------------------------------------------------------------- 1 | """ Various combinatorics functions. """ 2 | 3 | __author__ = "Caleb Madriagl" 4 | __date__ = "2015-02-20" 5 | 6 | 7 | def factorial(n): 8 | if n == 0: 9 | return 1 10 | else: 11 | return n * factorial(n-1) 12 | 13 | 14 | def permutations(lst): 15 | result = [] 16 | 17 | def permute(current, rest): 18 | if rest == []: 19 | result.append(current) 20 | return 21 | 22 | for r in rest: 23 | permute(current + (r,), [i for i in rest if i != r]) 24 | 25 | permute((), lst) 26 | return result 27 | 28 | 29 | def subsets(lst): 30 | result = [] 31 | 32 | def _subsets(current, rest): 33 | if rest == []: 34 | result.append(current) 35 | return 36 | 37 | (first, *rest) = rest 38 | _subsets(current + (first,), rest) 39 | _subsets(current, rest) 40 | 41 | _subsets((), lst) 42 | return result 43 | 44 | 45 | if __name__ == "__main__": 46 | print("Permutations of ['a','b','c']:", permutations(['a','b','c'])) 47 | print("Subsets of ['a','b','c']:", subsets(['a','b','c'])) 48 | 49 | -------------------------------------------------------------------------------- /depth_first_search.py: -------------------------------------------------------------------------------- 1 | """ Depth-first search (recursive and iterative solutions) 2 | 3 | This ignores the distance between the city data, and just cares about number of hops. 4 | 5 | This implementation is admittedly tightly-coupled to my particular city_data data set 6 | (to add clarity in understanding by making it tied to concrete data). 7 | 8 | The city_data is a list of 28 large cities in the United States, with some considered 9 | neighbors of the others. This would be the case in, say, a bus system which only 10 | travels between major cities. Using the shortest path on this data outputs 11 | the best path through these major cities. 12 | 13 | The format of city_data is like this: 14 | 15 | { "Milwaukee, WI": {"Minneapolis, MN": 542093, "Chicago, IL": 148198}, 16 | "Minneapolis, MN": {"Seattle, WA": 2665735, "Milwaukee, WI": 541660}, ... } 17 | 18 | So the neighbors of a city node can be found like this: list(city_data["Milwaukee, WI"].keys()) 19 | 20 | """ 21 | 22 | import json 23 | import sys 24 | 25 | 26 | def unroll_shortest_path(current, optimal_parent_map, path=()): 27 | if current is None: # Reached the start node 28 | return path 29 | else: 30 | return unroll_shortest_path(optimal_parent_map[current], optimal_parent_map, (current,) + path) 31 | 32 | 33 | def depth_first_search_iter(from_city, to_city, city_data): 34 | to_visit = [from_city] 35 | visited = set([from_city]) 36 | parent_map = {from_city: None} 37 | 38 | while to_visit != []: 39 | current = to_visit.pop() 40 | visited.add(current) 41 | neighbors = city_data[current].keys() 42 | 43 | for n in neighbors: 44 | if n == to_city: 45 | parent_map[n] = current 46 | return unroll_shortest_path(to_city, parent_map) 47 | 48 | elif n not in visited: 49 | parent_map[n] = current 50 | to_visit.append(n) 51 | 52 | return None 53 | 54 | 55 | def depth_first_search(from_city, to_city, city_data): 56 | visited = set() 57 | 58 | def _depth_first_search(from_city, to_city, city_data, path=(from_city,)): 59 | # If destination found, return the path hereto compiled 60 | if from_city == to_city: 61 | return path 62 | else: 63 | visited.add(from_city) 64 | neighbors = city_data[from_city].keys() 65 | unvisited_neighbors = [n for n in neighbors if n not in visited] 66 | 67 | # If there are no more unvisited neighbors, this path doesn't lead to the goal 68 | if unvisited_neighbors == []: 69 | return None 70 | 71 | # Else, for each unvisited neighbor, recursively try to reach the solution 72 | # from it as the "from_city". Also update the path 73 | for n in unvisited_neighbors: 74 | result = _depth_first_search(n, to_city, city_data, path+(n,)) 75 | if result is not None: 76 | return result 77 | 78 | return _depth_first_search(from_city, to_city, city_data) 79 | 80 | 81 | def get_city_data(): 82 | city_data = None 83 | with open("city_data.json","r") as f: 84 | city_data = json.loads(f.read()) 85 | return city_data 86 | 87 | 88 | if __name__ == '__main__': 89 | city_data = get_city_data() 90 | try: 91 | city_from = sys.argv[1] 92 | city_to = sys.argv[2] 93 | except IndexError: 94 | print("Usage:", sys.argv[0], "\"from city\" \"to city>\"") 95 | print("City choices:") 96 | for city in city_data: 97 | print(" -", city) 98 | sys.exit(1) 99 | 100 | print("Recursive:", depth_first_search(city_from, city_to, city_data)) 101 | print("\nIterative:", depth_first_search_iter(city_from, city_to, city_data)) 102 | 103 | -------------------------------------------------------------------------------- /dijkstra.py: -------------------------------------------------------------------------------- 1 | """ Dijkstra's shortest-path algorithm implementation 2 | 3 | This implementation is admittedly tightly-coupled to my particular city_data data set 4 | (to add clarity in understanding by making it tied to concrete data). 5 | 6 | The city_data is a list of 28 large cities in the United States, with some considered 7 | neighbors of the others. This would be the case in, say, a bus system which only 8 | travels between major cities. Using the shortest path on this data outputs 9 | the best path through these major cities. 10 | 11 | The format of city_data is like this: 12 | 13 | { "Milwaukee, WI": {"Minneapolis, MN": 542093, "Chicago, IL": 148198}, 14 | "Minneapolis, MN": {"Seattle, WA": 2665735, "Milwaukee, WI": 541660}, ... } 15 | 16 | So it can be used like this: city_data["Milwaukee, WI"]["Chicago, IL"] to find the distance 17 | from Chicago, IL to Milwaukee, WI. 18 | 19 | Also, this implementation does NOT use a heap, which would be the optimal data structure 20 | for storing unvisited nodes in. So in-place of a heap, it uses a sorted list of this structure: 21 | 22 | unvisited = [ [distance_to_a, a], [distance_to_b, b] ] 23 | 24 | It also uses a city_node_lookup dictionary in order to quickly access each of the [distance_to_a, a] 25 | lists in O(1) time. It can use this to change the distance to a given node in the unvisited 26 | list quickly. The unvisited list is re-sorted after each node is visited. 27 | 28 | """ 29 | 30 | import json 31 | import sys 32 | 33 | 34 | def unroll_shortest_path(current, optimal_parent_map, path=()): 35 | if current is None: # Reached the start node 36 | return path 37 | else: 38 | return unroll_shortest_path(optimal_parent_map[current], optimal_parent_map, (current,) + path) 39 | 40 | 41 | def dijkstra(start_city, end_city, city_data, verbose=False): 42 | if start_city == end_city: 43 | return (start_city,) 44 | 45 | # Inefficiency: should be implemented as a priority queue 46 | start_city_distance_entry = [0, start_city] 47 | city_node_lookup = {start_city: start_city_distance_entry} 48 | unvisited = [start_city_distance_entry] 49 | visited = set() 50 | optimal_parent = {start_city: None} 51 | for city_name in city_data.keys(): 52 | if city_name != start_city: 53 | city_distance_entry = [999999999, city_name] 54 | city_node_lookup[city_name] = city_distance_entry 55 | unvisited.append(city_distance_entry) 56 | 57 | destination_reached = False 58 | while not destination_reached and unvisited != []: 59 | (distance_to_current, current) = unvisited.pop(0) 60 | if verbose: 61 | print("CURRENT: {}, DISTANCE: {:,} meters".format(current, distance_to_current)) 62 | visited.add(current) 63 | neighbors = city_data[current].keys() 64 | if verbose: 65 | print("\tNEIGHBORS:", list(neighbors)) 66 | for neighbor in neighbors: 67 | if verbose: 68 | print("\t\tNEIGHBOR: {}".format(neighbor)) 69 | if neighbor == end_city: 70 | destination_reached = True 71 | optimal_parent[neighbor] = current 72 | break 73 | elif neighbor not in visited: 74 | total_distance_to_neighbor = distance_to_current + city_data[current][neighbor] 75 | # Changing the distance here changes the distance in unvisited 76 | city_distance_entry = city_node_lookup[neighbor] 77 | if city_distance_entry[0] > total_distance_to_neighbor: 78 | if verbose: 79 | print("\t\t\tNEW OPTIMAL PARENT ({}) TO {}".format(current, neighbor)) 80 | city_distance_entry[0] = total_distance_to_neighbor 81 | optimal_parent[neighbor] = current 82 | 83 | unvisited.sort() # Needed in the abscence of heap 84 | 85 | if destination_reached: 86 | return unroll_shortest_path(end_city, optimal_parent) 87 | else: 88 | return None 89 | 90 | 91 | def get_city_data(): 92 | city_data = None 93 | with open("city_data.json","r") as f: 94 | city_data = json.loads(f.read()) 95 | return city_data 96 | 97 | if __name__ == '__main__': 98 | city_data = get_city_data() 99 | try: 100 | city_from = sys.argv[1] 101 | city_to = sys.argv[2] 102 | except IndexError: 103 | print("Usage:", sys.argv[0], "\"from city\" \"to city>\"") 104 | print("City choices:") 105 | for city in city_data: 106 | print(" -", city) 107 | sys.exit(1) 108 | 109 | print(dijkstra(city_from, city_to, city_data, False)) 110 | 111 | -------------------------------------------------------------------------------- /fib.py: -------------------------------------------------------------------------------- 1 | """ Fibonacci sequence. """ 2 | 3 | 4 | def fib(n): 5 | if n < 2: 6 | return 1 7 | else: 8 | return fib(n-1) + fib(n-2) 9 | 10 | 11 | def fib_iter(n): 12 | n_minus_1 = 1 13 | n_minus_2 = 0 14 | current = 1 15 | for i in range(n): 16 | current = n_minus_1 + n_minus_2 17 | n_minus_2 = n_minus_1 18 | n_minus_1 = current 19 | 20 | return current 21 | 22 | 23 | if __name__ == '__main__': 24 | print([fib(i) for i in range(10)]) 25 | print([fib_iter(i) for i in range(10)]) 26 | print(fib_iter(1000)) 27 | 28 | -------------------------------------------------------------------------------- /get_city_data.py: -------------------------------------------------------------------------------- 1 | """ Horrible run-once code to download city data. """ 2 | 3 | import time 4 | import json 5 | import itertools 6 | from urllib.request import urlopen, quote 7 | 8 | MAPS_API_TEMPLATE = "https://maps.googleapis.com/maps/api/distancematrix/json?origins={}&destinations={}&mode=car&units=metric" 9 | STRAIGHT_DISTANCE_TEMPLATE = "http://www.travelmath.com/flying-distance/from/{}/to/{}" 10 | 11 | 12 | def miles_to_meters(miles): 13 | return miles / 0.00062137 14 | 15 | 16 | def get_straight_distance(city_from, city_to): 17 | city_from = '+'.join(city_from.split(' ')) 18 | city_to = '+'.join(city_to.split(' ')) 19 | url = STRAIGHT_DISTANCE_TEMPLATE.format(city_from, city_to) 20 | raw_response = urlopen(url).read().decode(encoding='UTF-8') 21 | miles = raw_response.find("miles", 20000)-10 22 | start_index=raw_response.find(r'"', miles)+2 23 | end_index = raw_response.find(r' ', start_index+1) 24 | straight_distance = raw_response[start_index:end_index] 25 | num = int(straight_distance.replace(',','')) 26 | return miles_to_meters(num) 27 | 28 | 29 | def get_city_distance(city_from, city_to): 30 | url = MAPS_API_TEMPLATE.format(quote(city_from), quote(city_to)) 31 | raw_response = urlopen(url).read().decode(encoding='UTF-8').replace('\n','') 32 | parsed_response = json.loads(raw_response) 33 | distance_in_meters = parsed_response['rows'][0]['elements'][0]['distance']['value'] 34 | return distance_in_meters 35 | 36 | 37 | adjacency_list = { 38 | "Milwaukee, WI": ["Chicago, IL", "Minneapolis, MN"], 39 | "Chicago, IL": ["Milwaukee, WI", "St. Louis, MO", "Indianapolis, IN", "Detroit, MI", "Cleveland, OH"], 40 | "Detroit, MI": ["Chicago, IL", "Cleveland, OH"], 41 | "St. Louis, MO": ["Chicago, IL", "Kansas City, MO", "Indianapolis, IN", "Atlanta, GA", "Dallas, TX"], 42 | "Kansas City, MO": ["St. Louis, MO", "Dallas, TX", "Denver, CO"], 43 | "Minneapolis, MN": ["Milwaukee, WI", "Seattle, WA"], 44 | "Seattle, WA": ["Minneapolis, MN", "Portland, OR"], 45 | "Portland, OR": ["Seattle, WA", "Denver, CO", "San Francisco, CA"], 46 | "Denver, CO": ["Portland, OR", "Las Vegas, NV", "Albuquerque, NM", "Kansas City, MO", "San Francisco, CA"], 47 | "San Francisco, CA": ["Portland, OR", "Los Angeles, CA", "Denver, CO"], 48 | "Los Angeles, CA": ["San Francisco, CA", "Las Vegas, NV", "Phoenix, AZ"], 49 | "Las Vegas, NV": ["Los Angeles, CA", "Phoenix, AZ", "Denver, CO"], 50 | "Phoenix, AZ": ["Las Vegas, NV", "Los Angeles, CA", "Albuquerque, NM"], 51 | "Albuquerque, NM": ["Phoenix, AZ", "Denver, CO", "Dallas, TX"], 52 | "Dallas, TX": ["Albuquerque, NM", "Houston, TX", "St. Louis, MO", "Atlanta, GA", "Kansas City, MO", "Austin, TX"], 53 | "Houston, TX": ["Dallas, TX", "San Antonio, TX"], 54 | "Austin, TX": ["San Antonio, TX", "Dallas, TX"], 55 | "San Antonio, TX": ["Austin, TX", "Houston, TX"], 56 | "Atlanta, GA": ["Dallas, TX", "St. Louis, MO", "Jacksonville, FL", "Cincinnati, OH"], 57 | "Cincinnati, OH": ["Atlanta, GA", "Indianapolis, IN", "Pittsburgh, PA", "Cleveland, OH"], 58 | "Cleveland, OH": ["Chicago, IL", "Detroit, MI", "Pittsburgh, PA", "Cincinnati, OH"], 59 | "Indianapolis, IN": ["Chicago, IL", "Cincinnati, OH", "St. Louis, MO"], 60 | "Pittsburgh, PA": ["Cleveland, OH", "Cincinnati, OH", "Philadelphia, PA"], 61 | "Philadelphia, PA": ["Pittsburgh, PA", "New York, NY"], 62 | "New York, NY": ["Philadelphia, PA", "Boston, MA"], 63 | "Boston, MA": ["New York, NY"], 64 | "Jacksonville, FL": ["Atlanta, GA", "Orlando, FL"], 65 | "Orlando, FL": ["Jacksonville, FL", "Miami, FL"], 66 | "Miami, FL": ["Orlando, FL"], 67 | } 68 | 69 | def get_in_between_distances(): 70 | adjacency_list_with_distance = {} 71 | for city_from in adjacency_list: 72 | distances_to_adjacent_cities = {} 73 | for city_to in adjacency_list[city_from]: 74 | distance = get_city_distance(city_from, city_to) 75 | distances_to_adjacent_cities[city_to] = distance 76 | print("Distance from {} to {}: {}".format(city_from, city_to, distance)) 77 | time.sleep(.5) 78 | adjacency_list_with_distance[city_from] = distances_to_adjacent_cities 79 | print(adjacency_list_with_distance) 80 | with open("city_data.json", "w") as f: 81 | f.write(json.dumps(adjacency_list_with_distance)) 82 | 83 | 84 | def get_straight_distances(): 85 | all_cities = list(adjacency_list.keys()) 86 | straight_distances = dict([(key, {}) for key in all_cities]) 87 | for (city_from, city_to) in itertools.permutations(all_cities, 2): 88 | distance = get_straight_distance(city_from, city_to) 89 | straight_distances[city_from][city_to] = distance 90 | print("Straight distance from {} to {} is {}".format(city_from, city_to, distance)) 91 | 92 | with open("straight_city_distances.json", "w") as f: 93 | f.write(json.dumps(straight_distances)) 94 | 95 | if __name__ == '__main__': 96 | get_in_between_distances() 97 | #get_straight_distances() 98 | 99 | -------------------------------------------------------------------------------- /hashtable.py: -------------------------------------------------------------------------------- 1 | ############ HashTable helper functions 2 | def hash_function(key_str, size): 3 | return sum([ord(c) for c in key_str]) % size 4 | 5 | 6 | ############ HashTable class 7 | class HashTable: 8 | """ Hash table which uses strings for keys. Value can be any object. 9 | 10 | Example usage: 11 | 12 | ht = HashTable(10) 13 | ht.set('a', 1).set('b', 2).set('c', 3) 14 | ht['c'] = 30 15 | 16 | """ 17 | 18 | def __init__(self, capacity=1000): 19 | """ Capacity defaults to 1000. """ 20 | 21 | self.capacity = capacity 22 | self.size = 0 23 | self._keys = [] 24 | # Storage format: [ [ [key1, value], [key2, value] ], [ [key3, value] ] ] 25 | # The outmost list is the one which the hash function maps the index to. The next inner 26 | # Array is the list of objects in that storage cell. The 3rd level is the individual 27 | # item array, where the 1st item is the key, and the 2nd item is the value. 28 | self.data = [[] for _ in range(capacity)] 29 | 30 | def _find_by_key(self, key, find_result_func): 31 | index = hash_function(key, self.capacity) 32 | hash_table_cell = self.data[index] 33 | found_item = None 34 | for item in hash_table_cell: 35 | if item[0] == key: 36 | found_item = item 37 | break 38 | 39 | return find_result_func(found_item, hash_table_cell) 40 | 41 | def set(self, key, obj): 42 | """ Insert object with key into hash table. If key already exists, then the object will be 43 | updated. Key must be a string. Returns self. """ 44 | 45 | def find_result_func(found_item, hash_table_cell): 46 | if found_item: 47 | found_item[1] = obj 48 | else: 49 | hash_table_cell.append([key, obj]) 50 | self.size += 1 51 | self._keys.append(key) 52 | 53 | self._find_by_key(key, find_result_func) 54 | return self 55 | 56 | def get(self, key): 57 | """ Get object with key (key must be a string). If not found, it will raise a KeyError. """ 58 | 59 | def find_result_func(found_item, _): 60 | if found_item: 61 | return found_item[1] 62 | else: 63 | raise KeyError(key) 64 | 65 | return self._find_by_key(key, find_result_func) 66 | 67 | def remove(self, key): 68 | """ Remove the object associated with key from the hashtable. If found, the object will 69 | be returned. If not found, KeyError will be raised. """ 70 | 71 | def find_result_func(found_item, hash_table_cell): 72 | if found_item: 73 | hash_table_cell.remove(found_item) 74 | self._keys.remove(key) 75 | self.size -= 1 76 | return found_item[1] 77 | else: 78 | raise KeyError(key) 79 | 80 | return self._find_by_key(key, find_result_func) 81 | 82 | ####### Python's dict interface 83 | 84 | def keys(self): 85 | return self._keys 86 | 87 | def __setitem__(self, key, value): 88 | self.set(key, value) 89 | 90 | def __getitem__(self, key): 91 | return self.get(key) 92 | 93 | def __delitem__(self, key): 94 | return self.remove(key) 95 | 96 | def __repr__(self): 97 | return '{ ' + ', '.join([key + ':' + str(self.get(key)) for key in self._keys]) + ' }' 98 | 99 | if __name__ == "__main__": 100 | # Run unit tests 101 | import unittest 102 | testsuite = unittest.TestLoader().discover('test', pattern="*hashtable*") 103 | unittest.TextTestRunner(verbosity=1).run(testsuite) 104 | -------------------------------------------------------------------------------- /heap.py: -------------------------------------------------------------------------------- 1 | """heap.py - implementation of a heap priority queue. """ 2 | 3 | __author__ = "Caleb Madrigal" 4 | __date__ = "2015-02-17" 5 | 6 | import math 7 | from enum import Enum 8 | from autoresizelist import AutoResizeList 9 | 10 | 11 | class HeapType(Enum): 12 | maxheap = 1 13 | minheap = 2 14 | 15 | 16 | class Heap: 17 | def __init__(self, initial_data=None, heap_type=HeapType.maxheap): 18 | self.heap_type = heap_type 19 | if heap_type == HeapType.maxheap: 20 | self.comparator = lambda x, y: x > y 21 | else: 22 | self.comparator = lambda x, y: x < y 23 | 24 | self.data = AutoResizeList() 25 | if initial_data is not None: 26 | self.build_heap(initial_data) 27 | 28 | self._size = len(self.data) 29 | 30 | def _left_child(self, index): 31 | return 2*index + 1 32 | 33 | def _right_child(self, index): 34 | return 2*index + 2 35 | 36 | def _parent(self, index): 37 | return math.floor((index - 1) / 2.0) 38 | 39 | def _is_root(self, index): 40 | return index == 0 41 | 42 | def _swap(self, i1, i2): 43 | self.data[i1], self.data[i2] = self.data[i2], self.data[i1] 44 | 45 | def build_heap(self, initial_data): 46 | for i in initial_data: 47 | self.data.prepend(i) 48 | self.heap_down(0) 49 | 50 | def heap_up(self, index): 51 | # If we are at the root, return - we are done 52 | if self._is_root(index): 53 | return 54 | 55 | # Else, compare the current node with the parent node, and if this node should be higher 56 | # then the parent node, then swap and recursively call on the parent index 57 | parent_index = self._parent(index) 58 | if self.comparator(self.data[index], self.data[parent_index]): 59 | self._swap(index, parent_index) 60 | self.heap_up(parent_index) 61 | 62 | def heap_down(self, index): 63 | left_index = self._left_child(index) 64 | right_index = self._right_child(index) 65 | try: 66 | left = self.data[left_index] 67 | except IndexError: 68 | left = None 69 | try: 70 | right = self.data[right_index] 71 | except IndexError: 72 | right = None 73 | 74 | # Find the largest child 75 | largest_child = left 76 | largest_child_index = left_index 77 | if left is not None and right is not None: 78 | if self.comparator(right, left): 79 | largest_child = right 80 | largest_child_index = right_index 81 | elif right is not None: 82 | largest_child = right 83 | largest_child_index = right_index 84 | 85 | # If the largest child is not None and is higher priority than the current, then swap 86 | # and recursively call on on the child index 87 | if largest_child is not None and self.comparator(largest_child, self.data[index]): 88 | self._swap(index, largest_child_index) 89 | self.heap_down(largest_child_index) 90 | 91 | def push(self, item): 92 | insert_index = self._size # Insert at the end 93 | self._size += 1 94 | 95 | self.data[insert_index] = item 96 | self.heap_up(insert_index) 97 | 98 | return self 99 | 100 | def peek(self): 101 | return self.data[0] 102 | 103 | def pop(self): 104 | if len(self.data) < 1 or self.data[0] is None: 105 | return None 106 | 107 | # Take item from the root 108 | item = self.data[0] 109 | 110 | # Move the bottom-most, right-most item to the root 111 | self.data[0] = self.data[self._size-1] 112 | self.data[self._size-1] = None 113 | self._size -= 1 114 | 115 | self.heap_down(0) 116 | 117 | return item 118 | 119 | def size(self): 120 | return self._size 121 | 122 | def __repr__(self): 123 | return str(self.data) 124 | 125 | if __name__ == "__main__": 126 | import unittest 127 | testsuite = unittest.TestLoader().discover('test', pattern="*heap*") 128 | unittest.TextTestRunner(verbosity=1).run(testsuite) 129 | -------------------------------------------------------------------------------- /heap_speed_test.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import random 3 | import heap 4 | 5 | def test_with_heap(size): 6 | priority_queue = heap.Heap() 7 | for i in range(size): 8 | rand = random.randint(1, size) 9 | priority_queue.push(rand) 10 | 11 | top10 = [priority_queue.pop() for _ in range(10)] 12 | print("Top 10 (with heap):", top10) 13 | 14 | def test_with_sort(size): 15 | data = [] 16 | for i in range(size): 17 | rand = random.randint(1, size) 18 | data.append(i) 19 | sorted_data = sorted(data, reverse=True) 20 | top10 = sorted_data[0:10] 21 | print("Top 10 (with sort):", top10) 22 | 23 | def test_with_max(size): 24 | data = [] 25 | for i in range(size): 26 | rand = random.randint(1, size) 27 | data.append(i) 28 | 29 | top10 = [] 30 | for i in range(10): 31 | m = max(data) 32 | data.remove(m) 33 | top10.append(m) 34 | 35 | print("Top 10 (with sort):", top10) 36 | 37 | if __name__ == "__main__": 38 | size = 1000000 39 | if sys.argv[1] == 'heap': 40 | test_with_heap(size) 41 | if sys.argv[1] == 'sort': 42 | test_with_heap(size) 43 | if sys.argv[1] == 'max': 44 | test_with_heap(size) 45 | 46 | -------------------------------------------------------------------------------- /mergesort.py: -------------------------------------------------------------------------------- 1 | """mergesort.py - implementation of mergesort. """ 2 | 3 | __author__ = "Caleb Madrigal" 4 | __date__ = "2015-02-13" 5 | 6 | 7 | def merge(left, right): 8 | if len(left) < 1: 9 | return right 10 | elif len(right) < 1: 11 | return left 12 | else: 13 | first_left, *rest_left = left 14 | first_right, *rest_right = right 15 | if first_left <= first_right: 16 | return [first_left] + merge(rest_left, right) 17 | else: 18 | return [first_right] + merge(left, rest_right) 19 | 20 | 21 | def mergesort(lst): 22 | list_len = len(lst) 23 | if list_len < 2: 24 | return lst 25 | if list_len == 2: 26 | if lst[0] <= lst[1]: 27 | return lst 28 | else: 29 | return [lst[1], lst[0]] 30 | else: # list_len > 2 31 | split_point = list_len // 2 32 | left = lst[0:split_point] 33 | right = lst[split_point:] 34 | left_sorted = mergesort(left) 35 | right_sorted = mergesort(right) 36 | return merge(left_sorted, right_sorted) 37 | 38 | 39 | if __name__ == "__main__": 40 | import unittest 41 | testsuite = unittest.TestLoader().discover('test', pattern="*mergesort*") 42 | unittest.TextTestRunner(verbosity=1).run(testsuite) 43 | 44 | -------------------------------------------------------------------------------- /nqueens.py: -------------------------------------------------------------------------------- 1 | """ Backtracking solution to N-Queens problem. """ 2 | 3 | __author__ = "Caleb Madrigal" 4 | __date__ = "2015-02-19" 5 | 6 | import numpy as np 7 | 8 | 9 | def right_to_left_diagonals_valid(board): 10 | """ Returns True if there is no more than 1 "1" in each right-to-left diagonal; else False. 11 | 12 | The algorithm works like this: 13 | 14 | Matrix with indices for reference: 15 | [[ 0. 1. 2. 3. 4. 5. 6. 7.] 16 | [ 8. 9. 10. 11. 12. 13. 14. 15.] 17 | [ 16. 17. 18. 19. 20. 21. 22. 23.] 18 | [ 24. 25. 26. 27. 28. 29. 30. 31.] 19 | [ 32. 33. 34. 35. 36. 37. 38. 39.] 20 | [ 40. 41. 42. 43. 44. 45. 46. 47.] 21 | [ 48. 49. 50. 51. 52. 53. 54. 55.] 22 | [ 56. 57. 58. 59. 60. 61. 62. 63.]] 23 | 24 | It checks right-to-left columns in 2 steps: 25 | * Step 1: it checks each right-to-left diagonal that begins with each element on the first row 26 | (skipping the first index, since that "diagonal" is just element[0]) So the indices 27 | of each start of each row-based diagonal are: 1, 2, 3, 4, 5, 6, 7. In order to find the 28 | indices of each subsequent element in each diagonal, it adds (size-1) to the initial 29 | diagonal. For example: if we are checking the right-to-left diagonal starting with index 2, 30 | the diagonal should be indices: 2, 9, 16 (each is separated by 7). In order to perform 31 | this math, the nxn matrix is flattened. 32 | * Step 2: it does roughly the same thing for the right-to-left diagonals that start on the 33 | far-right column (indices 15, 23, 31, 39, 47, 55, 63). """ 34 | 35 | size = len(board) 36 | flat = board.reshape((1, size*size))[0] 37 | 38 | for row_index in range(1, size): 39 | index = row_index 40 | diag_sum = 0 41 | for diag_index in range(row_index+1): 42 | diag_sum += flat[index] 43 | index += (size - 1) 44 | if diag_sum > 1: 45 | return False 46 | 47 | col_diag_index = 0 48 | diag_lengths = list(range(size-1, 0, -1)) 49 | for last_col_index in range(2*size-1, size*size-1, size): 50 | index = last_col_index 51 | diag_sum = 0 52 | diag_len = diag_lengths[col_diag_index] 53 | col_diag_index += 1 54 | for diag_index in range(diag_len): 55 | diag_sum += flat[index] 56 | index += (size - 1) 57 | if diag_sum > 1: 58 | return False 59 | 60 | return True 61 | 62 | 63 | def left_to_right_diagonals_valid(board): 64 | """ Returns True if there is no more than 1 "1" in each left-to-right diagonal; else False. 65 | 66 | To check the left-to-right diagonals, just rotate the matrix by 90 degrees and 67 | then use the right-to-left algorithm on the rotated matrix. """ 68 | 69 | rotated_board = np.rot90(board) 70 | return right_to_left_diagonals_valid(rotated_board) 71 | 72 | 73 | def diags_valid(board): 74 | """ Returns True if there are no more than 1 "1" in any diagonal; else False. """ 75 | 76 | return right_to_left_diagonals_valid(board) and left_to_right_diagonals_valid(board) 77 | 78 | 79 | def print_board_indented(board, row): 80 | print('\t'*row + str(board).replace('\n', '\n'+('\t'*row))) 81 | 82 | 83 | def search(board, row=0, cols_taken=()): 84 | """ In-place search for solution to n-queens. Backtracking algorithm. """ 85 | 86 | # Return if we are at the maximum depth and the solution is valid 87 | if row == len(board) and diags_valid(board): 88 | return True 89 | 90 | # Otherwise, try each column and recursively work down the rows 91 | for col in range(len(board)): 92 | if col in cols_taken: 93 | continue 94 | 95 | board[row][col] = 1 96 | print_board_indented(board, row) 97 | 98 | if diags_valid(board): 99 | if search(board, row+1, cols_taken + (col,)): 100 | return True 101 | else: 102 | board[row][col] = 0 103 | else: 104 | board[row][col] = 0 105 | 106 | return False 107 | 108 | 109 | def n_queens(size): 110 | board = np.zeros((size, size)) 111 | if search(board): 112 | print("Solution found:") 113 | print(board) 114 | else: 115 | print("No solution found") 116 | 117 | if __name__ == '__main__': 118 | board_size = 8 119 | n_queens(board_size) 120 | 121 | -------------------------------------------------------------------------------- /prefix_calc.py: -------------------------------------------------------------------------------- 1 | """ Prefix calculator. Takes a space-delimited string like '* ( / 10 5 ) ( + ( - 5 2 ) ( * 1 3 ) )' 2 | and parses it, builds an AST, and reduces the AST to a number by running specified operators. """ 3 | 4 | __author__ = "Caleb Madrigal" 5 | __date__ = "2015-03-04" 6 | 7 | 8 | def calc(node): 9 | if node == (): 10 | return 11 | (op, a, b) = node[0], node[1], node[2] 12 | if type(a) == tuple: 13 | a = calc(a) 14 | if type(b) == tuple: 15 | b = calc(b) 16 | if op == '+': 17 | return a + b 18 | elif op == '-': 19 | return a - b 20 | elif op == '*': 21 | return a * b 22 | elif op == '/': 23 | return a / b 24 | 25 | 26 | def build_ast(token_list): 27 | if not token_list: 28 | return (), () 29 | token, *rest = token_list 30 | if token == '(': 31 | internal, remainder = build_ast(rest) 32 | internal2, remainder2 = build_ast(remainder) 33 | return (internal,) + internal2, remainder2 34 | elif token == ')': 35 | return (), rest 36 | elif token in ['+', '-', '*', '/']: 37 | internal, remainder = build_ast(rest) 38 | return (token,) + internal, remainder 39 | else: # Token is number 40 | internal, remainder = build_ast(rest) 41 | return (float(token),) + internal, remainder 42 | 43 | 44 | def parse(calc_str): 45 | return calc_str.split() 46 | 47 | if __name__ == '__main__': 48 | calc_str = '+ ( * 2 2 ) ( - ( + 3 2 ) 4 )' 49 | parsed = parse(calc_str) 50 | ast, _ = build_ast(parsed) 51 | print("Original: '{}'".format(calc_str)) 52 | print("Parsed:", parsed) 53 | print("AST:", ast) 54 | print("Result:", calc(ast)) 55 | 56 | calc_str2 = '* ( / 10 5 ) ( + ( - 5 2 ) ( * 1 3 ) )' 57 | ast, _ = build_ast(parse(calc_str2)) 58 | print("\nOriginal: '{}'".format(calc_str2)) 59 | print("AST:", ast) 60 | print("Result:", calc(ast)) 61 | 62 | -------------------------------------------------------------------------------- /quicksort.py: -------------------------------------------------------------------------------- 1 | """quicksort.py - implementation of quicksort. """ 2 | 3 | __author__ = "Caleb Madrigal" 4 | __date__ = "2015-02-14" 5 | 6 | 7 | def quicksort(lst): 8 | if len(lst) < 2: 9 | return lst 10 | else: 11 | pivot = lst[-1] 12 | low = [] 13 | high = [] 14 | for i in lst[:-1]: 15 | if i <= pivot: 16 | low.append(i) 17 | else: 18 | high.append(i) 19 | return quicksort(low) + [pivot] + quicksort(high) 20 | 21 | if __name__ == "__main__": 22 | import unittest 23 | testsuite = unittest.TestLoader().discover('test', pattern="*quicksort*") 24 | unittest.TextTestRunner(verbosity=1).run(testsuite) 25 | 26 | -------------------------------------------------------------------------------- /reverse.py: -------------------------------------------------------------------------------- 1 | """ Reverse function recursively and iteratively. """ 2 | 3 | 4 | def reverse(lst): 5 | if lst == []: 6 | return lst 7 | else: 8 | return reverse(lst[1:]) + [lst[0]] 9 | 10 | 11 | def reverse_iter(lst): 12 | for i in range(len(lst) // 2): 13 | lst[i], lst[-1*(i+1)] = lst[-1*(i+1)], lst[i] 14 | return lst 15 | 16 | 17 | if __name__ == '__main__': 18 | print(reverse(range(10))) 19 | print(reverse_iter(range(10))) 20 | 21 | -------------------------------------------------------------------------------- /straight_city_distances.json: -------------------------------------------------------------------------------- 1 | {"Miami, FL": {"Los Angeles, CA": 3764262.8385663936, "Las Vegas, NV": 3509985.9986803355, "Houston, TX": 1557847.9810740782, "Cincinnati, OH": 1536926.4689315546, "New York, NY": 1752578.978708338, "San Antonio, TX": 1849139.8039815247, "Cleveland, OH": 1749360.2845325652, "Milwaukee, WI": 2040652.1074400116, "Detroit, MI": 1855577.1923330706, "Minneapolis, MN": 2431723.4497964177, "Dallas, TX": 1787984.6146418399, "Pittsburgh, PA": 1627049.9058531953, "Indianapolis, IN": 1647971.4179957192, "Atlanta, GA": 972045.6410834125, "Chicago, IL": 1911904.340409096, "Portland, OR": 4358111.913996492, "St. Louis, MO": 1705907.9131596312, "Seattle, WA": 4399954.938281539, "Albuquerque, NM": 2732671.3552311826, "Kansas City, MO": 1998809.083154964, "Philadelphia, PA": 1639924.682556287, "Boston, MA": 2021339.9423853743, "Austin, TX": 1794422.0029933855, "Phoenix, AZ": 3188116.5811030464, "Orlando, FL": 328306.80592883466, "Denver, CO": 2776123.7266041166, "Jacksonville, FL": 524647.1506509809, "San Francisco, CA": 4174646.345977437}, "Los Angeles, CA": {"Miami, FL": 3764262.8385663936, "Austin, TX": 1974668.8768366673, "Las Vegas, NV": 368540.4831259958, "Houston, TX": 2211242.8987559746, "Cincinnati, OH": 3057759.4669842445, "New York, NY": 3944509.7124096756, "San Antonio, TX": 1937653.8938152792, "Cleveland, OH": 3297552.1830793247, "Milwaukee, WI": 2808310.6683618454, "Detroit, MI": 3191335.2752788193, "Minneapolis, MN": 2452644.9619389414, "Dallas, TX": 1995590.3889791912, "Pittsburgh, PA": 3439174.7268133317, "Indianapolis, IN": 2912918.2290744646, "Atlanta, GA": 3117305.309236043, "Chicago, IL": 2809920.015449732, "Portland, OR": 1327711.3475063166, "St. Louis, MO": 2557252.52265156, "Seattle, WA": 1543363.8572831003, "Albuquerque, NM": 1068606.4663565992, "Kansas City, MO": 2183883.9982619053, "Philadelphia, PA": 3851167.5813122615, "Boston, MA": 4177865.04015321, "Phoenix, AZ": 576146.2574633472, "Orlando, FL": 3543782.287525951, "Denver, CO": 1337367.4300336353, "Jacksonville, FL": 3456877.5447800825, "San Francisco, CA": 558443.4394965962}, "Las Vegas, NV": {"Miami, FL": 3509985.9986803355, "Los Angeles, CA": 368540.4831259958, "Houston, TX": 1976278.2239245537, "Cincinnati, OH": 2713359.190176545, "New York, NY": 3592062.700162544, "San Antonio, TX": 1726829.4253021549, "Cleveland, OH": 2943495.823744307, "Milwaukee, WI": 2446207.5735873957, "Detroit, MI": 2834060.2217680286, "Minneapolis, MN": 2084104.4788129455, "Dallas, TX": 1723610.731126382, "Pittsburgh, PA": 3088337.061654087, "Indianapolis, IN": 2565299.2580909925, "Atlanta, GA": 2809920.015449732, "Chicago, IL": 2452644.9619389414, "Portland, OR": 1216666.398442152, "St. Louis, MO": 2217680.2871075203, "Seattle, WA": 1401741.3135490932, "Albuquerque, NM": 777314.6434491527, "Kansas City, MO": 1839483.7214542062, "Philadelphia, PA": 3503548.61032879, "Boston, MA": 3822199.3337303055, "Austin, TX": 1746141.5903567923, "Phoenix, AZ": 411992.8544989298, "Orlando, FL": 3270193.2825852553, "Denver, CO": 975264.3352591854, "Jacksonville, FL": 3170413.7631362956, "San Francisco, CA": 672707.0827365338}, "Houston, TX": {"Miami, FL": 1557847.9810740782, "Los Angeles, CA": 2211242.8987559746, "Las Vegas, NV": 1976278.2239245537, "Cincinnati, OH": 1443584.3378341408, "New York, NY": 2283663.5177108645, "San Antonio, TX": 305775.94669842446, "Cleveland, OH": 1792812.6559054991, "Milwaukee, WI": 1615784.4762379902, "Detroit, MI": 1778328.5321145211, "Minneapolis, MN": 1699470.5248080853, "Dallas, TX": 362103.09477445, "Pittsburgh, PA": 1829827.6389268874, "Indianapolis, IN": 1392085.2310217745, "Atlanta, GA": 1129761.655696284, "Chicago, IL": 1512786.2626132579, "Portland, OR": 2954761.253359512, "St. Louis, MO": 1092746.6726748957, "Seattle, WA": 3043275.3431932665, "Albuquerque, NM": 1213447.7042663791, "Kansas City, MO": 1038028.8716867567, "Philadelphia, PA": 2158134.444855722, "Boston, MA": 2583002.0760577433, "Austin, TX": 236574.02191930733, "Phoenix, AZ": 1635096.6412926277, "Orlando, FL": 1366335.6776155913, "Denver, CO": 1413006.7431642984, "Jacksonville, FL": 1322883.3062426574, "San Francisco, CA": 2647375.9595732014}, "Cincinnati, OH": {"Miami, FL": 1536926.4689315546, "Austin, TX": 1564285.3694256241, "Las Vegas, NV": 2713359.190176545, "Houston, TX": 1443584.3378341408, "Los Angeles, CA": 3057759.4669842445, "New York, NY": 909281.1046558411, "San Antonio, TX": 1680158.359753448, "Cleveland, OH": 349228.31807135843, "Milwaukee, WI": 518209.7622994351, "Detroit, MI": 371759.1773017687, "Minneapolis, MN": 973654.9881712989, "Dallas, TX": 1318055.264978998, "Pittsburgh, PA": 407164.81323527044, "Indianapolis, IN": 160934.70878864444, "Atlanta, GA": 600286.4637816438, "Chicago, IL": 403946.11905949755, "Portland, OR": 3196163.3165424787, "St. Louis, MO": 502116.2914205707, "Seattle, WA": 3173632.4573120684, "Albuquerque, NM": 2018121.2482096013, "Kansas City, MO": 875484.8158102258, "Philadelphia, PA": 803064.1968553358, "Boston, MA": 1184479.4566844231, "Phoenix, AZ": 2549205.7872121283, "Orlando, FL": 1211838.3571784927, "Denver, CO": 1763844.4083235431, "Jacksonville, FL": 1012279.3182805736, "San Francisco, CA": 3292724.141815665}, "New York, NY": {"Miami, FL": 1752578.978708338, "Los Angeles, CA": 3944509.7124096756, "Las Vegas, NV": 3592062.700162544, "Houston, TX": 2283663.5177108645, "Cincinnati, OH": 909281.1046558411, "San Antonio, TX": 2547596.4401242416, "Cleveland, OH": 651785.5705940101, "Milwaukee, WI": 1181260.7625086503, "Detroit, MI": 775705.2963612663, "Minneapolis, MN": 1639924.682556287, "Dallas, TX": 2209633.5516680884, "Pittsburgh, PA": 508553.6797721165, "Indianapolis, IN": 1038028.8716867567, "Atlanta, GA": 1200572.9275632876, "Chicago, IL": 1147464.4736630348, "Portland, OR": 3934853.6298823566, "St. Louis, MO": 1406569.3548127525, "Seattle, WA": 3875307.7876305585, "Albuquerque, NM": 2920964.964513897, "Kansas City, MO": 1763844.4083235431, "Philadelphia, PA": 130357.114118802, "Boston, MA": 305775.94669842446, "Austin, TX": 2434942.1439721906, "Phoenix, AZ": 3450440.156428537, "Orlando, FL": 1509567.568437485, "Denver, CO": 2624845.100342791, "Jacksonville, FL": 1343804.8183851813, "San Francisco, CA": 4139240.710043935}, "San Antonio, TX": {"Miami, FL": 1849139.8039815247, "Los Angeles, CA": 1937653.8938152792, "Las Vegas, NV": 1726829.4253021549, "Houston, TX": 305775.94669842446, "Cincinnati, OH": 1680158.359753448, "New York, NY": 2547596.4401242416, "Cleveland, OH": 2022949.2894732608, "Milwaukee, WI": 1781547.226290294, "Detroit, MI": 1992371.6948034184, "Minneapolis, MN": 1786375.2675539535, "Dallas, TX": 405555.466147384, "Pittsburgh, PA": 2077667.0904613999, "Indianapolis, IN": 1607737.740798558, "Atlanta, GA": 1421053.4786037304, "Chicago, IL": 1693033.1364565396, "Portland, OR": 2768076.9911646843, "St. Louis, MO": 1274602.8936060641, "Seattle, WA": 2874293.8989651897, "Albuquerque, NM": 991357.8061380498, "Kansas City, MO": 1131371.0027841704, "Philadelphia, PA": 2425286.061444872, "Boston, MA": 2843716.3042953475, "Austin, TX": 119091.68450359689, "Phoenix, AZ": 1364726.330527705, "Orlando, FL": 1668892.930138243, "Denver, CO": 1289087.0173970421, "Jacksonville, FL": 1628659.2529410818, "San Francisco, CA": 2397927.1609508023}, "Cleveland, OH": {"Miami, FL": 1749360.2845325652, "Los Angeles, CA": 3297552.1830793247, "Las Vegas, NV": 2943495.823744307, "Houston, TX": 1792812.6559054991, "Cincinnati, OH": 349228.31807135843, "New York, NY": 651785.5705940101, "San Antonio, TX": 2022949.2894732608, "Milwaukee, WI": 540740.6215298453, "Detroit, MI": 144841.23790978, "Minneapolis, MN": 1015498.0124563464, "Dallas, TX": 1649580.7650836057, "Pittsburgh, PA": 185074.9151069411, "Indianapolis, IN": 423258.2841141349, "Atlanta, GA": 891578.2866890902, "Chicago, IL": 495678.9030690249, "Portland, OR": 3307208.2656066436, "St. Louis, MO": 791798.7672401307, "Seattle, WA": 3260537.2000579364, "Albuquerque, NM": 2286882.2118866374, "Kansas City, MO": 1126542.9615205112, "Philadelphia, PA": 577755.6045512336, "Boston, MA": 886750.2454254309, "Austin, TX": 1905466.9520575502, "Phoenix, AZ": 2814748.0567133916, "Orlando, FL": 1438756.2965704813, "Denver, CO": 1974668.8768366673, "Jacksonville, FL": 1239197.2576725623, "San Francisco, CA": 3487455.139449925}, "Milwaukee, WI": {"Miami, FL": 2040652.1074400116, "Los Angeles, CA": 2808310.6683618454, "Las Vegas, NV": 2446207.5735873957, "Houston, TX": 1615784.4762379902, "Cincinnati, OH": 518209.7622994351, "New York, NY": 1181260.7625086503, "San Antonio, TX": 1781547.226290294, "Cleveland, OH": 540740.6215298453, "Detroit, MI": 405555.466147384, "Minneapolis, MN": 481194.7792780469, "Dallas, TX": 1379210.454318683, "Pittsburgh, PA": 717768.8011973542, "Indianapolis, IN": 391071.34235640604, "Atlanta, GA": 1075043.854708145, "Chicago, IL": 130357.114118802, "Portland, OR": 2768076.9911646843, "St. Louis, MO": 526256.4977388673, "Seattle, WA": 2723015.272703864, "Albuquerque, NM": 1841093.0685420926, "Kansas City, MO": 711331.4128458084, "Philadelphia, PA": 1116886.8789931925, "Boston, MA": 1380819.8014065693, "Austin, TX": 1665674.23596247, "Phoenix, AZ": 2356084.136665755, "Orlando, FL": 1712345.3015111769, "Denver, CO": 1470943.2383282103, "Jacksonville, FL": 1516004.9567890307, "San Francisco, CA": 2966026.682974717}, "Detroit, MI": {"Miami, FL": 1855577.1923330706, "Los Angeles, CA": 3191335.2752788193, "Las Vegas, NV": 2834060.2217680286, "Houston, TX": 1778328.5321145211, "Cincinnati, OH": 371759.1773017687, "New York, NY": 775705.2963612663, "San Antonio, TX": 1992371.6948034184, "Cleveland, OH": 144841.23790978, "Milwaukee, WI": 405555.466147384, "Minneapolis, MN": 873875.4687223394, "Dallas, TX": 1609347.0878864445, "Pittsburgh, PA": 329916.15301672113, "Indianapolis, IN": 386243.30109274667, "Atlanta, GA": 959170.8643803209, "Chicago, IL": 383024.6069169738, "Portland, OR": 3168804.4160484094, "St. Louis, MO": 732252.9249883322, "Seattle, WA": 3118914.6563239293, "Albuquerque, NM": 2196758.7749649966, "Kansas City, MO": 1038028.8716867567, "Philadelphia, PA": 712940.7599336948, "Boston, MA": 986529.7648743904, "Austin, TX": 1874889.3573877078, "Phoenix, AZ": 2719796.5785280913, "Orlando, FL": 1538535.816019441, "Denver, CO": 1862014.5806846162, "Jacksonville, FL": 1337367.4300336353, "San Francisco, CA": 3366754.107858442}, "Minneapolis, MN": {"Miami, FL": 2431723.4497964177, "Los Angeles, CA": 2452644.9619389414, "Las Vegas, NV": 2084104.4788129455, "Houston, TX": 1699470.5248080853, "Cincinnati, OH": 973654.9881712989, "New York, NY": 1639924.682556287, "San Antonio, TX": 1786375.2675539535, "Cleveland, OH": 1015498.0124563464, "Milwaukee, WI": 481194.7792780469, "Detroit, MI": 873875.4687223394, "Dallas, TX": 1387257.1897581152, "Pittsburgh, PA": 1195744.8862996283, "Indianapolis, IN": 822376.3619099731, "Atlanta, GA": 1461287.1558008916, "Chicago, IL": 571318.2161996878, "Portland, OR": 2296538.2944139563, "St. Louis, MO": 749955.7429550831, "Seattle, WA": 2245039.18760159, "Albuquerque, NM": 1581988.187392375, "Kansas City, MO": 661441.6531213287, "Philadelphia, PA": 1585206.8815681478, "Boston, MA": 1808906.1267843635, "Austin, TX": 1680158.359753448, "Phoenix, AZ": 2059964.272494649, "Orlando, FL": 2105025.990955469, "Denver, CO": 1126542.9615205112, "Jacksonville, FL": 1916732.3816727553, "San Francisco, CA": 2550815.1343000145}, "Dallas, TX": {"Miami, FL": 1787984.6146418399, "Los Angeles, CA": 1995590.3889791912, "Las Vegas, NV": 1723610.731126382, "Houston, TX": 362103.09477445, "Cincinnati, OH": 1318055.264978998, "New York, NY": 2209633.5516680884, "San Antonio, TX": 405555.466147384, "Cleveland, OH": 1649580.7650836057, "Milwaukee, WI": 1379210.454318683, "Detroit, MI": 1609347.0878864445, "Minneapolis, MN": 1387257.1897581152, "Phoenix, AZ": 1425881.5198673897, "Pittsburgh, PA": 1722001.3840384956, "Indianapolis, IN": 1229541.1751452435, "Atlanta, GA": 1160339.2503661264, "Chicago, IL": 1293915.0586607014, "Portland, OR": 2628063.794518564, "St. Louis, MO": 881922.2041617716, "Seattle, WA": 2705312.4547371133, "Albuquerque, NM": 944686.7405893429, "Kansas City, MO": 729034.2308125594, "Philadelphia, PA": 2092151.2142523779, "Boston, MA": 2496097.3333118754, "Austin, TX": 292901.1699953329, "Orlando, FL": 1549801.245634646, "Denver, CO": 1065387.7721808262, "Jacksonville, FL": 1461287.1558008916, "San Francisco, CA": 2386661.731335597}, "Pittsburgh, PA": {"Miami, FL": 1627049.9058531953, "Los Angeles, CA": 3439174.7268133317, "Las Vegas, NV": 3088337.061654087, "Houston, TX": 1829827.6389268874, "Cincinnati, OH": 407164.81323527044, "New York, NY": 508553.6797721165, "San Antonio, TX": 2077667.0904613999, "Cleveland, OH": 185074.9151069411, "Milwaukee, WI": 717768.8011973542, "Detroit, MI": 329916.15301672113, "Minneapolis, MN": 1195744.8862996283, "Dallas, TX": 1722001.3840384956, "Indianapolis, IN": 531084.5390025267, "Atlanta, GA": 838469.8327888376, "Chicago, IL": 659832.3060334423, "Portland, OR": 3484236.4452741523, "St. Louis, MO": 899625.0221285225, "Seattle, WA": 3440784.0739012184, "Albuquerque, NM": 2412411.2847417803, "Kansas City, MO": 1256900.075639313, "Philadelphia, PA": 415211.5486747027, "Boston, MA": 777314.6434491527, "Austin, TX": 1963403.4472214624, "Phoenix, AZ": 2943495.823744307, "Orlando, FL": 1326102.0004184302, "Denver, CO": 2125947.5030979933, "Jacksonville, FL": 1131371.0027841704, "San Francisco, CA": 3645171.154062797}, "Indianapolis, IN": {"Miami, FL": 1647971.4179957192, "Los Angeles, CA": 2912918.2290744646, "Houston, TX": 1392085.2310217745, "Cincinnati, OH": 160934.70878864444, "New York, NY": 1038028.8716867567, "San Antonio, TX": 1607737.740798558, "Cleveland, OH": 423258.2841141349, "Milwaukee, WI": 391071.34235640604, "Detroit, MI": 386243.30109274667, "Minneapolis, MN": 822376.3619099731, "Dallas, TX": 1229541.1751452435, "Pittsburgh, PA": 531084.5390025267, "Las Vegas, NV": 2565299.2580909925, "Atlanta, GA": 687191.2065275118, "Chicago, IL": 265542.26950126333, "Portland, OR": 3035228.607753834, "St. Louis, MO": 371759.1773017687, "Seattle, WA": 3012697.748523424, "Albuquerque, NM": 1881326.7457392537, "Kansas City, MO": 729034.2308125594, "Philadelphia, PA": 939858.6993256835, "Boston, MA": 1298743.0999243606, "Austin, TX": 1490255.4033828476, "Phoenix, AZ": 2412411.2847417803, "Orlando, FL": 1321273.959154771, "Denver, CO": 1610956.434974331, "Jacksonville, FL": 1124933.6144326248, "San Francisco, CA": 3138226.821378567}, "Atlanta, GA": {"Miami, FL": 972045.6410834125, "Los Angeles, CA": 3117305.309236043, "Las Vegas, NV": 2809920.015449732, "Houston, TX": 1129761.655696284, "Cincinnati, OH": 600286.4637816438, "New York, NY": 1200572.9275632876, "San Antonio, TX": 1421053.4786037304, "Cleveland, OH": 891578.2866890902, "Milwaukee, WI": 1075043.854708145, "Detroit, MI": 959170.8643803209, "Minneapolis, MN": 1461287.1558008916, "Dallas, TX": 1160339.2503661264, "Pittsburgh, PA": 838469.8327888376, "Indianapolis, IN": 687191.2065275118, "Chicago, IL": 946296.0876772293, "Portland, OR": 3497111.2219772437, "St. Louis, MO": 751565.0900429696, "Seattle, WA": 3511595.3457682217, "Albuquerque, NM": 2047089.4957915575, "Kansas City, MO": 1087918.6314112365, "Philadelphia, PA": 1071825.160532372, "Boston, MA": 1507958.2213495984, "Austin, TX": 1318055.264978998, "Phoenix, AZ": 2562080.5639152196, "Orlando, FL": 645348.1822424643, "Denver, CO": 1950528.6705183708, "Jacksonville, FL": 458663.92004763667, "San Francisco, CA": 3444002.768076991}, "Chicago, IL": {"Miami, FL": 1911904.340409096, "Los Angeles, CA": 2809920.015449732, "Las Vegas, NV": 2452644.9619389414, "Houston, TX": 1512786.2626132579, "Cincinnati, OH": 403946.11905949755, "New York, NY": 1147464.4736630348, "San Antonio, TX": 1693033.1364565396, "Cleveland, OH": 495678.9030690249, "Milwaukee, WI": 130357.114118802, "Detroit, MI": 383024.6069169738, "Minneapolis, MN": 571318.2161996878, "Dallas, TX": 1293915.0586607014, "Pittsburgh, PA": 659832.3060334423, "Indianapolis, IN": 265542.26950126333, "Atlanta, GA": 946296.0876772293, "Portland, OR": 2830841.5275922557, "St. Louis, MO": 421648.93702624843, "Seattle, WA": 2795435.891658754, "Albuquerque, NM": 1816952.8622237958, "Kansas City, MO": 664660.3472971015, "Philadelphia, PA": 1070215.8134444857, "Boston, MA": 1369554.3717913642, "Austin, TX": 1575550.799040829, "Phoenix, AZ": 2339990.6657868903, "Orlando, FL": 1585206.8815681478, "Denver, CO": 1480599.3208555288, "Jacksonville, FL": 1388866.5368460016, "San Francisco, CA": 2991776.2363809003}, "Portland, OR": {"Miami, FL": 4358111.913996492, "Los Angeles, CA": 1327711.3475063166, "Las Vegas, NV": 1216666.398442152, "Houston, TX": 2954761.253359512, "Cincinnati, OH": 3196163.3165424787, "New York, NY": 3934853.6298823566, "San Antonio, TX": 2768076.9911646843, "Cleveland, OH": 3307208.2656066436, "Milwaukee, WI": 2768076.9911646843, "Detroit, MI": 3168804.4160484094, "Minneapolis, MN": 2296538.2944139563, "Dallas, TX": 2628063.794518564, "Pittsburgh, PA": 3484236.4452741523, "Indianapolis, IN": 3035228.607753834, "Atlanta, GA": 3497111.2219772437, "Chicago, IL": 2830841.5275922557, "St. Louis, MO": 2772905.032428344, "Seattle, WA": 233355.32774353446, "Albuquerque, NM": 1783156.5733781804, "Kansas City, MO": 2409192.5905660074, "Philadelphia, PA": 3881745.175982104, "Boston, MA": 4087741.603231569, "Austin, TX": 2750374.1731979335, "Phoenix, AZ": 1619003.1704137633, "Orlando, FL": 4070038.785264818, "Denver, CO": 1581988.187392375, "Jacksonville, FL": 3926806.8944429248, "San Francisco, CA": 861000.6920192478}, "St. Louis, MO": {"Miami, FL": 1705907.9131596312, "Los Angeles, CA": 2557252.52265156, "Las Vegas, NV": 2217680.2871075203, "Houston, TX": 1092746.6726748957, "Cincinnati, OH": 502116.2914205707, "New York, NY": 1406569.3548127525, "San Antonio, TX": 1274602.8936060641, "Cleveland, OH": 791798.7672401307, "Milwaukee, WI": 526256.4977388673, "Detroit, MI": 732252.9249883322, "Minneapolis, MN": 749955.7429550831, "Dallas, TX": 881922.2041617716, "Pittsburgh, PA": 899625.0221285225, "Indianapolis, IN": 371759.1773017687, "Atlanta, GA": 751565.0900429696, "Chicago, IL": 421648.93702624843, "Portland, OR": 2772905.032428344, "Seattle, WA": 2774514.3795162304, "Albuquerque, NM": 1516004.9567890307, "Kansas City, MO": 383024.6069169738, "Philadelphia, PA": 1303571.1411880201, "Boston, MA": 1670502.2772261293, "Austin, TX": 1157120.5561903536, "Phoenix, AZ": 2047089.4957915575, "Orlando, FL": 1385647.8426702288, "Denver, CO": 1282649.6290454962, "Jacksonville, FL": 1208619.6630027199, "San Francisco, CA": 2809920.015449732}, "Seattle, WA": {"Miami, FL": 4399954.938281539, "Los Angeles, CA": 1543363.8572831003, "Las Vegas, NV": 1401741.3135490932, "Houston, TX": 3043275.3431932665, "Cincinnati, OH": 3173632.4573120684, "New York, NY": 3875307.7876305585, "San Antonio, TX": 2874293.8989651897, "Cleveland, OH": 3260537.2000579364, "Milwaukee, WI": 2723015.272703864, "Detroit, MI": 3118914.6563239293, "Minneapolis, MN": 2245039.18760159, "Dallas, TX": 2705312.4547371133, "Pittsburgh, PA": 3440784.0739012184, "Indianapolis, IN": 3012697.748523424, "Atlanta, GA": 3511595.3457682217, "Chicago, IL": 2795435.891658754, "Portland, OR": 233355.32774353446, "St. Louis, MO": 2774514.3795162304, "Austin, TX": 2850153.692646893, "Albuquerque, NM": 1905466.9520575502, "Kansas City, MO": 2423676.7143569854, "Philadelphia, PA": 3828636.722081851, "Boston, MA": 4010492.94301302, "Phoenix, AZ": 1792812.6559054991, "Orlando, FL": 4103835.0741104335, "Denver, CO": 1643143.3767320598, "Jacksonville, FL": 3950947.1007612213, "San Francisco, CA": 1092746.6726748957}, "Albuquerque, NM": {"Miami, FL": 2732671.3552311826, "Los Angeles, CA": 1068606.4663565992, "Las Vegas, NV": 777314.6434491527, "Houston, TX": 1213447.7042663791, "Cincinnati, OH": 2018121.2482096013, "New York, NY": 2920964.964513897, "San Antonio, TX": 991357.8061380498, "Cleveland, OH": 2286882.2118866374, "Milwaukee, WI": 1841093.0685420926, "Detroit, MI": 2196758.7749649966, "Minneapolis, MN": 1581988.187392375, "Dallas, TX": 944686.7405893429, "Pittsburgh, PA": 2412411.2847417803, "Indianapolis, IN": 1881326.7457392537, "Atlanta, GA": 2047089.4957915575, "Chicago, IL": 1816952.8622237958, "Portland, OR": 1783156.5733781804, "St. Louis, MO": 1516004.9567890307, "Seattle, WA": 1905466.9520575502, "Kansas City, MO": 1160339.2503661264, "Philadelphia, PA": 2819576.0979770506, "Boston, MA": 3173632.4573120684, "Austin, TX": 991357.8061380498, "Phoenix, AZ": 531084.5390025267, "Orlando, FL": 2492878.6391361025, "Denver, CO": 537521.9273540725, "Jacksonville, FL": 2394708.4667750294, "San Francisco, CA": 1443584.3378341408}, "Kansas City, MO": {"Miami, FL": 1998809.083154964, "Los Angeles, CA": 2183883.9982619053, "Las Vegas, NV": 1839483.7214542062, "Houston, TX": 1038028.8716867567, "Cincinnati, OH": 875484.8158102258, "New York, NY": 1763844.4083235431, "San Antonio, TX": 1131371.0027841704, "Cleveland, OH": 1126542.9615205112, "Milwaukee, WI": 711331.4128458084, "Detroit, MI": 1038028.8716867567, "Minneapolis, MN": 661441.6531213287, "Dallas, TX": 729034.2308125594, "Pittsburgh, PA": 1256900.075639313, "Indianapolis, IN": 729034.2308125594, "Atlanta, GA": 1087918.6314112365, "Chicago, IL": 664660.3472971015, "Portland, OR": 2409192.5905660074, "St. Louis, MO": 383024.6069169738, "Seattle, WA": 2423676.7143569854, "Albuquerque, NM": 1160339.2503661264, "Philadelphia, PA": 1668892.930138243, "Boston, MA": 2013293.206945942, "Austin, TX": 1021935.4008078922, "Phoenix, AZ": 1688205.0951928804, "Orlando, FL": 1689814.4422807668, "Denver, CO": 898015.675040636, "Jacksonville, FL": 1528879.7334921223, "San Francisco, CA": 2425286.061444872}, "Philadelphia, PA": {"Miami, FL": 1639924.682556287, "Los Angeles, CA": 3851167.5813122615, "Las Vegas, NV": 3503548.61032879, "Houston, TX": 2158134.444855722, "Cincinnati, OH": 803064.1968553358, "New York, NY": 130357.114118802, "San Antonio, TX": 2425286.061444872, "Cleveland, OH": 577755.6045512336, "Milwaukee, WI": 1116886.8789931925, "Detroit, MI": 712940.7599336948, "Minneapolis, MN": 1585206.8815681478, "Dallas, TX": 2092151.2142523779, "Pittsburgh, PA": 415211.5486747027, "Indianapolis, IN": 939858.6993256835, "Atlanta, GA": 1071825.160532372, "Chicago, IL": 1070215.8134444857, "Portland, OR": 3881745.175982104, "St. Louis, MO": 1303571.1411880201, "Seattle, WA": 3828636.722081851, "Albuquerque, NM": 2819576.0979770506, "Kansas City, MO": 1668892.930138243, "San Francisco, CA": 4060382.7027374995, "Boston, MA": 436133.0608172265, "Austin, TX": 2312631.7652928205, "Phoenix, AZ": 3350660.6369795776, "Orlando, FL": 1388866.5368460016, "Denver, CO": 2539549.7046848093, "Jacksonville, FL": 1219885.092617925}, "Boston, MA": {"Miami, FL": 2021339.9423853743, "Los Angeles, CA": 4177865.04015321, "Las Vegas, NV": 3822199.3337303055, "Houston, TX": 2583002.0760577433, "Cincinnati, OH": 1184479.4566844231, "New York, NY": 305775.94669842446, "San Antonio, TX": 2843716.3042953475, "Cleveland, OH": 886750.2454254309, "Milwaukee, WI": 1380819.8014065693, "Detroit, MI": 986529.7648743904, "Minneapolis, MN": 1808906.1267843635, "Dallas, TX": 2496097.3333118754, "Pittsburgh, PA": 777314.6434491527, "Indianapolis, IN": 1298743.0999243606, "Atlanta, GA": 1507958.2213495984, "Chicago, IL": 1369554.3717913642, "Portland, OR": 4087741.603231569, "St. Louis, MO": 1670502.2772261293, "Seattle, WA": 4010492.94301302, "Albuquerque, NM": 3173632.4573120684, "Kansas City, MO": 2013293.206945942, "Philadelphia, PA": 436133.0608172265, "Austin, TX": 2729452.66105541, "Phoenix, AZ": 3701498.302138822, "Orlando, FL": 1794422.0029933855, "Denver, CO": 2848544.3455590066, "Jacksonville, FL": 1635096.6412926277, "San Francisco, CA": 4343627.790205514}, "Austin, TX": {"Miami, FL": 1794422.0029933855, "Los Angeles, CA": 1974668.8768366673, "Las Vegas, NV": 1746141.5903567923, "Houston, TX": 236574.02191930733, "Cincinnati, OH": 1564285.3694256241, "New York, NY": 2434942.1439721906, "San Antonio, TX": 119091.68450359689, "Cleveland, OH": 1905466.9520575502, "Milwaukee, WI": 1665674.23596247, "Detroit, MI": 1874889.3573877078, "Minneapolis, MN": 1680158.359753448, "Dallas, TX": 292901.1699953329, "Pittsburgh, PA": 1963403.4472214624, "Indianapolis, IN": 1490255.4033828476, "Atlanta, GA": 1318055.264978998, "Chicago, IL": 1575550.799040829, "Portland, OR": 2750374.1731979335, "St. Louis, MO": 1157120.5561903536, "Seattle, WA": 2850153.692646893, "Albuquerque, NM": 991357.8061380498, "Kansas City, MO": 1021935.4008078922, "Philadelphia, PA": 2312631.7652928205, "Boston, MA": 2729452.66105541, "Phoenix, AZ": 1400131.9664612068, "Orlando, FL": 1598081.6582712394, "Denver, CO": 1240806.6047604487, "Jacksonville, FL": 1546582.551458873, "San Francisco, CA": 2417239.3260054397}, "Phoenix, AZ": {"Miami, FL": 3188116.5811030464, "Los Angeles, CA": 576146.2574633472, "Las Vegas, NV": 411992.8544989298, "Houston, TX": 1635096.6412926277, "Cincinnati, OH": 2549205.7872121283, "New York, NY": 3450440.156428537, "San Antonio, TX": 1364726.330527705, "Cleveland, OH": 2814748.0567133916, "Milwaukee, WI": 2356084.136665755, "Detroit, MI": 2719796.5785280913, "Minneapolis, MN": 2059964.272494649, "Dallas, TX": 1425881.5198673897, "Pittsburgh, PA": 2943495.823744307, "Indianapolis, IN": 2412411.2847417803, "Atlanta, GA": 2562080.5639152196, "Chicago, IL": 2339990.6657868903, "Portland, OR": 1619003.1704137633, "St. Louis, MO": 2047089.4957915575, "Seattle, WA": 1792812.6559054991, "Albuquerque, NM": 531084.5390025267, "Kansas City, MO": 1688205.0951928804, "Philadelphia, PA": 3350660.6369795776, "Boston, MA": 3701498.302138822, "Austin, TX": 1400131.9664612068, "Orlando, FL": 2970854.7242383766, "Denver, CO": 943077.3935014565, "Jacksonville, FL": 2888778.0227561677, "San Francisco, CA": 1052512.9954777346}, "Orlando, FL": {"Miami, FL": 328306.80592883466, "Los Angeles, CA": 3543782.287525951, "Las Vegas, NV": 3270193.2825852553, "Houston, TX": 1366335.6776155913, "Cincinnati, OH": 1211838.3571784927, "New York, NY": 1509567.568437485, "San Antonio, TX": 1668892.930138243, "Cleveland, OH": 1438756.2965704813, "Milwaukee, WI": 1712345.3015111769, "Detroit, MI": 1538535.816019441, "Minneapolis, MN": 2105025.990955469, "Dallas, TX": 1549801.245634646, "Pittsburgh, PA": 1326102.0004184302, "Indianapolis, IN": 1321273.959154771, "Atlanta, GA": 645348.1822424643, "Chicago, IL": 1585206.8815681478, "Portland, OR": 4070038.785264818, "St. Louis, MO": 1385647.8426702288, "Seattle, WA": 4103835.0741104335, "Albuquerque, NM": 2492878.6391361025, "Kansas City, MO": 1689814.4422807668, "Philadelphia, PA": 1388866.5368460016, "Boston, MA": 1794422.0029933855, "Austin, TX": 1598081.6582712394, "Phoenix, AZ": 2970854.7242383766, "Denver, CO": 2494487.986223989, "Jacksonville, FL": 201168.38598580557, "San Francisco, CA": 3930025.5886186976}, "Denver, CO": {"Miami, FL": 2776123.7266041166, "Los Angeles, CA": 1337367.4300336353, "Las Vegas, NV": 975264.3352591854, "Houston, TX": 1413006.7431642984, "Cincinnati, OH": 1763844.4083235431, "New York, NY": 2624845.100342791, "San Antonio, TX": 1289087.0173970421, "Cleveland, OH": 1974668.8768366673, "Milwaukee, WI": 1470943.2383282103, "Detroit, MI": 1862014.5806846162, "Minneapolis, MN": 1126542.9615205112, "Dallas, TX": 1065387.7721808262, "Pittsburgh, PA": 2125947.5030979933, "Indianapolis, IN": 1610956.434974331, "Atlanta, GA": 1950528.6705183708, "Chicago, IL": 1480599.3208555288, "Portland, OR": 1581988.187392375, "St. Louis, MO": 1282649.6290454962, "Seattle, WA": 1643143.3767320598, "Albuquerque, NM": 537521.9273540725, "Kansas City, MO": 898015.675040636, "Philadelphia, PA": 2539549.7046848093, "Boston, MA": 2848544.3455590066, "Austin, TX": 1240806.6047604487, "Phoenix, AZ": 943077.3935014565, "Orlando, FL": 2494487.986223989, "Jacksonville, FL": 2360912.177929414, "San Francisco, CA": 1528879.7334921223}, "Jacksonville, FL": {"Miami, FL": 524647.1506509809, "Los Angeles, CA": 3456877.5447800825, "Las Vegas, NV": 3170413.7631362956, "Houston, TX": 1322883.3062426574, "Cincinnati, OH": 1012279.3182805736, "New York, NY": 1343804.8183851813, "San Antonio, TX": 1628659.2529410818, "Cleveland, OH": 1239197.2576725623, "Milwaukee, WI": 1516004.9567890307, "Detroit, MI": 1337367.4300336353, "Minneapolis, MN": 1916732.3816727553, "Dallas, TX": 1461287.1558008916, "Pittsburgh, PA": 1131371.0027841704, "Indianapolis, IN": 1124933.6144326248, "Atlanta, GA": 458663.92004763667, "Chicago, IL": 1388866.5368460016, "Portland, OR": 3926806.8944429248, "St. Louis, MO": 1208619.6630027199, "Seattle, WA": 3950947.1007612213, "Albuquerque, NM": 2394708.4667750294, "Kansas City, MO": 1528879.7334921223, "San Francisco, CA": 3822199.3337303055, "Boston, MA": 1635096.6412926277, "Austin, TX": 1546582.551458873, "Phoenix, AZ": 2888778.0227561677, "Orlando, FL": 201168.38598580557, "Denver, CO": 2360912.177929414, "Philadelphia, PA": 1219885.092617925}, "San Francisco, CA": {"Miami, FL": 4174646.345977437, "Los Angeles, CA": 558443.4394965962, "Las Vegas, NV": 672707.0827365338, "Houston, TX": 2647375.9595732014, "Cincinnati, OH": 3292724.141815665, "New York, NY": 4139240.710043935, "San Antonio, TX": 2397927.1609508023, "Cleveland, OH": 3487455.139449925, "Milwaukee, WI": 2966026.682974717, "Detroit, MI": 3366754.107858442, "Minneapolis, MN": 2550815.1343000145, "Dallas, TX": 2386661.731335597, "Pittsburgh, PA": 3645171.154062797, "Indianapolis, IN": 3138226.821378567, "Atlanta, GA": 3444002.768076991, "Chicago, IL": 2991776.2363809003, "Portland, OR": 861000.6920192478, "St. Louis, MO": 2809920.015449732, "Seattle, WA": 1092746.6726748957, "Albuquerque, NM": 1443584.3378341408, "Kansas City, MO": 2425286.061444872, "Philadelphia, PA": 4060382.7027374995, "Boston, MA": 4343627.790205514, "Austin, TX": 2417239.3260054397, "Phoenix, AZ": 1052512.9954777346, "Orlando, FL": 3930025.5886186976, "Denver, CO": 1528879.7334921223, "Jacksonville, FL": 3822199.3337303055}} -------------------------------------------------------------------------------- /test/test_autoresizelist.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import sys 3 | import os.path 4 | 5 | sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir))) 6 | from autoresizelist import AutoResizeList 7 | 8 | 9 | class AutoResizeListTest(unittest.TestCase): 10 | 11 | def testSet(self): 12 | a = AutoResizeList() 13 | a[5] = 5 14 | self.assertEqual(a._data, [None, None, None, None, None, 5]) 15 | 16 | b = AutoResizeList([0, 1, 2, 3], fill=0) 17 | b[6] = 6 18 | self.assertEqual(b._data, [0, 1, 2, 3, 0, 0, 6]) 19 | 20 | def testGet(self): 21 | c = AutoResizeList([], fill=100) 22 | c[10] = 1 23 | self.assertEqual(c[10], 1) 24 | self.assertEqual(c[9], 100) 25 | 26 | def testDel(self): 27 | d = AutoResizeList([0, 1, 2]) 28 | d[4] = 4 29 | del d[3] 30 | self.assertEqual(d._data, [0, 1, 2, 4]) 31 | 32 | def testEqual(self): 33 | a = AutoResizeList([1, 2, 3]) 34 | b = AutoResizeList([1, 2, 3]) 35 | self.assertEqual(a, b) 36 | 37 | def testLen(self): 38 | a = AutoResizeList([1, 2, 3]) 39 | self.assertEqual(len(a), 3) 40 | 41 | def testPrepend(self): 42 | a = AutoResizeList([1, 2, 3]) 43 | a.prepend(0) 44 | self.assertEqual(0, a._data[0]) 45 | 46 | if __name__ == '__main__': 47 | unittest.main() 48 | 49 | -------------------------------------------------------------------------------- /test/test_hashtable.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import sys 3 | import os.path 4 | 5 | sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir))) 6 | import hashtable 7 | 8 | 9 | class HashFunctionTest(unittest.TestCase): 10 | 11 | def test(self): 12 | hash10 = lambda key: hashtable.hash_function(key, 10) 13 | self.assertIn(hash10("a"), range(10)) 14 | self.assertIn(hash10("b"), range(10)) 15 | self.assertIn(hash10("caleb"), range(10)) 16 | self.assertIn(hash10("more than a feeling"), range(10)) 17 | 18 | hash4 = lambda key: hashtable.hash_function(key, 4) 19 | self.assertIn(hash4("a"), range(4)) 20 | self.assertIn(hash4("b"), range(4)) 21 | self.assertIn(hash4("caleb"), range(4)) 22 | self.assertIn(hash4("more than a feeling"), range(4)) 23 | 24 | 25 | class HashTableTest(unittest.TestCase): 26 | def testCreate(self): 27 | ht = hashtable.HashTable(10) 28 | self.assertEqual(ht.capacity, 10) 29 | self.assertEqual(ht.size, 0) 30 | 31 | ht = hashtable.HashTable() 32 | self.assertEqual(ht.capacity, 1000) 33 | 34 | def testSetAndGet(self): 35 | # Basic set and get 36 | ht = hashtable.HashTable(10) 37 | ht.set('a', 1) 38 | self.assertEqual(ht.get('a'), 1) 39 | self.assertEqual(ht.size, 1) 40 | 41 | # Check update functionality 42 | ht.set('a', 2) 43 | self.assertEqual(ht.get('a'), 2) 44 | self.assertEqual(ht.size, 1) 45 | 46 | # Make sure we can add a 2nd element 47 | ht.set('b', 10) 48 | self.assertEqual(ht.get('b'), 10) 49 | self.assertEqual(ht.get('a'), 2) 50 | self.assertEqual(ht.size, 2) 51 | 52 | # Assert ht.set returns itself (for fluent calls) 53 | self.assertEqual(ht.set('c', 5), ht) 54 | 55 | # Test fluent set functionality 56 | ht.set('d', 100).set('e', 200).set('f', 300) 57 | self.assertEqual(ht.get('d'), 100) 58 | self.assertEqual(ht.get('e'), 200) 59 | self.assertEqual(ht.get('f'), 300) 60 | 61 | def testBadGet(self): 62 | ht = hashtable.HashTable(10) 63 | self.assertRaises(KeyError, ht.get, 'a') 64 | 65 | def testRemove(self): 66 | ht = hashtable.HashTable(10) 67 | self.assertRaises(KeyError, ht.remove, 'a') 68 | 69 | ht.set('a', 1) 70 | removed_item = ht.remove('a') 71 | self.assertEqual(removed_item, 1) 72 | self.assertEqual(ht.size, 0) 73 | 74 | def testPythonDictInterface(self): 75 | ht = hashtable.HashTable(10) 76 | 77 | ht['a'] = 10 78 | self.assertEqual(ht.get('a'), 10) 79 | 80 | ht['a'] = 20 81 | self.assertEqual(ht['a'], 20) 82 | 83 | self.assertIn('a', ht.keys()) 84 | 85 | del ht['a'] 86 | self.assertRaises(KeyError, ht.get, 'a') 87 | 88 | if __name__ == '__main__': 89 | unittest.main() 90 | 91 | -------------------------------------------------------------------------------- /test/test_heap.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import sys 3 | import os.path 4 | import random 5 | 6 | sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir))) 7 | import heap 8 | 9 | 10 | def is_heap(h): 11 | sorted_data = list(sorted(filter(lambda x: x is not None, h.data), reverse=True)) 12 | pop_order = [h.pop() for _ in range(h.size())] 13 | print("\nsorted data: {0}\npop_order: {1}".format(sorted_data, pop_order)) 14 | return sorted_data == pop_order 15 | 16 | 17 | class HeapTest(unittest.TestCase): 18 | def testMaxHeapPushPop(self): 19 | # Test push 20 | h = heap.Heap() 21 | h.push(5).push(3).push(9).push(1) 22 | self.assertEqual(str(h), "[9, 3, 5, 1]") 23 | 24 | h.push(20) 25 | self.assertEqual(str(h), "[20, 9, 5, 1, 3]") 26 | 27 | h.push(2) 28 | self.assertEqual(str(h), "[20, 9, 5, 1, 3, 2]") 29 | 30 | h.push(7) 31 | self.assertEqual(str(h), "[20, 9, 7, 1, 3, 2, 5]") 32 | 33 | h.push(21) 34 | self.assertEqual(str(h), "[21, 20, 7, 9, 3, 2, 5, 1]") 35 | 36 | # Test peek 37 | self.assertEqual(h.peek(), 21) 38 | 39 | # Test pop 40 | self.assertEqual(h.pop(), 21) 41 | self.assertEqual(h.pop(), 20) 42 | self.assertEqual(h.pop(), 9) 43 | self.assertEqual(h.pop(), 7) 44 | 45 | # Larger test 46 | data = [93, 89, 91, 84, 87, 54, 71, 62, 75, 35, 43, 50, 77, 27, 14, 42, 13, 35, 10, 4] 47 | h2 = heap.Heap() 48 | for d in data: 49 | h2.push(d) 50 | 51 | self.assertTrue(is_heap(h2)) 52 | 53 | def testMinHeapPushPop(self): 54 | # Test Push 55 | h = heap.Heap([], heap.HeapType.minheap) 56 | h.push(5) 57 | self.assertEqual(str(h), "[5]") 58 | 59 | h.push(7) 60 | self.assertEqual(str(h), "[5, 7]") 61 | 62 | h.push(3) 63 | self.assertEqual(str(h), "[3, 7, 5]") 64 | 65 | h.push(4) 66 | self.assertEqual(str(h), "[3, 4, 5, 7]") 67 | 68 | h.push(-1) 69 | self.assertEqual(str(h), "[-1, 3, 5, 7, 4]") 70 | 71 | # Test peek 72 | self.assertEqual(h.peek(), -1) 73 | 74 | # Test pop 75 | self.assertEqual(h.pop(), -1) 76 | self.assertEqual(h.pop(), 3) 77 | self.assertEqual(h.pop(), 4) 78 | self.assertEqual(h.pop(), 5) 79 | h.push(-10) 80 | self.assertEqual(h.pop(), -10) 81 | 82 | def testMaxHeapBuild(self): 83 | data = [98, 45, 69, 85, 34, 66, 10, 2, 11, 3, 21, 30, 91, 32, 55, 74, 93, 17, 67, 19] 84 | h = heap.Heap(data) 85 | self.assertTrue(is_heap(h)) 86 | 87 | # data2 = [random.randint(1, 100) for _ in range(20)] 88 | # print("\n\ndata: {0}".format(data2)) 89 | # h3 = heap.Heap(data2[:]) 90 | # self.assertTrue(is_heap(h3)) 91 | 92 | if __name__ == '__main__': 93 | unittest.main() 94 | 95 | -------------------------------------------------------------------------------- /test/test_mergesort.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import sys 3 | import os.path 4 | 5 | sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir))) 6 | import mergesort 7 | 8 | 9 | class MergesortTest(unittest.TestCase): 10 | 11 | def testSort(self): 12 | a = [1,2,3,4,5,6,7,8,9] 13 | self.assertEqual(mergesort.mergesort(a), [1,2,3,4,5,6,7,8,9]) 14 | 15 | b = [8,7,6,5,4,3,2,1] 16 | self.assertEqual(mergesort.mergesort(b), [1,2,3,4,5,6,7,8]) 17 | 18 | c = [1,6,3,2,1,9,7,5,4,9] 19 | self.assertEqual(mergesort.mergesort(c), [1,1,2,3,4,5,6,7,9,9]) 20 | 21 | 22 | if __name__ == '__main__': 23 | unittest.main() 24 | 25 | -------------------------------------------------------------------------------- /test/test_nqueens.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import sys 3 | import os.path 4 | import numpy as np 5 | 6 | sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir))) 7 | import nqueens 8 | 9 | 10 | class NQueensTest(unittest.TestCase): 11 | 12 | def testDiagsValid(self): 13 | good_board = np.array([[0, 1, 0, 0], [0, 0, 0, 1], [1, 0, 0, 0], [0, 0, 1, 0]]) 14 | self.assertTrue(nqueens.diags_valid(good_board)) 15 | 16 | bad_board = np.array([[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) 17 | self.assertFalse(nqueens.diags_valid(bad_board)) 18 | 19 | bad_board2 = np.array([[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]]) 20 | self.assertFalse(nqueens.diags_valid(bad_board2)) 21 | 22 | if __name__ == '__main__': 23 | unittest.main() 24 | 25 | -------------------------------------------------------------------------------- /test/test_quicksort.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import sys 3 | import os.path 4 | 5 | sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir))) 6 | import quicksort 7 | 8 | 9 | class QuicksortTest(unittest.TestCase): 10 | 11 | def testSort(self): 12 | a = [1,2,3,4,5,6,7,8,9] 13 | self.assertEqual(quicksort.quicksort(a), [1,2,3,4,5,6,7,8,9]) 14 | 15 | b = [8,7,6,5,4,3,2,1] 16 | self.assertEqual(quicksort.quicksort(b), [1,2,3,4,5,6,7,8]) 17 | 18 | c = [1,6,3,2,1,9,7,5,4,9] 19 | self.assertEqual(quicksort.quicksort(c), [1,1,2,3,4,5,6,7,9,9]) 20 | 21 | 22 | if __name__ == '__main__': 23 | unittest.main() 24 | 25 | --------------------------------------------------------------------------------