diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000..893ea00 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,31 @@ +[run] +source = + src/que_.py +omit = + src/binheap.py + src/deque.py + src/dijkstra.py + src/graph_1.py + src/graph_2.py + src/linked_list.py + src/priorityq.py + src/dll.py + src/reverse_linked_list.py + src/stack.py + src/test_dll.py + src/test_binheap.py + src/test_deque.py + src/test_dijkstra.py + src/test_graph.py + src/test_graph_2.py + src/test_linked_list.py + src/test_priority_que.py + src/test_que_.py + src/test_reverse_linked_list.py + src/test_stack.py + src/test_weighted_graph.py + src/test_weighted_traversal.py + src/weighted_graph.py + src/weighted_traversal.py +[report] +show_missing = True \ No newline at end of file diff --git a/setup.py b/setup.py index 97eb6a0..9a14157 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ extra_packages = { - 'testing': ['pytest', 'pytest-watch', 'pytest-cov', 'tox'] + 'testing': ['pytest-cov', 'tox'] } diff --git a/src/dijkstra.py b/src/dijkstra.py new file mode 100644 index 0000000..5aa6997 --- /dev/null +++ b/src/dijkstra.py @@ -0,0 +1,27 @@ +"""Dijkstra algorithm for our shortest path graph.""" +from weighted_graph import Weighted +from priorityq import PriorityQueue + +# {'A':{'B': 7, 'C': 9}, 'B': {'D': 2, 'E': 4}, 'C': {'F': 6}, 'D':{}, 'E': {}, 'F': {}} + + +def dijkstra(weighted_graph, start_node): + """Find the shortest path to nodes from starting node.""" + if not weighted_graph.has_node(start_node): + raise IndexError('Node not in this weighted graph.') + current_node = {start_node: 0} + visited = {} + priorityq = PriorityQueue() + priorityq.insert(current_node, 0) + while len(priorityq) > 0: + current_node = priorityq.pop() + next_nodes = weighted_graph[list(current_node.keys())[0]] + for key, value in next_nodes.items(): + distance_from_start_node = value + list(current_node.values())[0] + priorityq.insert( + {key: distance_from_start_node}, distance_from_start_node + ) + if key in visited and distance_from_start_node > visited[key]: + continue + visited.update({key: distance_from_start_node}) + return visited diff --git a/src/dll.py b/src/dll.py index 19c48b1..8716d3f 100644 --- a/src/dll.py +++ b/src/dll.py @@ -24,29 +24,27 @@ def push(self, val): """Push a value to the head of the list.""" if not val: raise TypeError('Please provide a not null value.') - self._length += 1 if self.tail is None and self.head is None: new_node = Node(val) - self.tail = new_node - self.head = new_node + self.tail = self.head = new_node else: new_node = Node(val, None, self.head) self.head.next_node = new_node self.head = new_node + self._length += 1 def append(self, val): """Append a val to the tail of a list.""" if not val: raise TypeError('Please provide a not null value.') - self._length += 1 if self.tail is None and self.head is None: new_node = Node(val) - self.tail = new_node - self.head = new_node + self.tail = self.head = new_node else: new_node = Node(val, self.tail, None) self.tail.prior_node = new_node self.tail = new_node + self._length += 1 def pop(self): """Pop pops from the head of the list.""" @@ -56,45 +54,40 @@ def pop(self): self._length -= 1 if self.head == self.tail: last_pop = self.head - self.head = None - self.tail = None + self.tail = self.head = None return last_pop.data popped = self.head self.head = self.head.prior_node - popped.prior_node = None self.head.next_node = None return popped.data def shift(self): """Remove the node from the tail of the list.""" - if not self.head: + if not self.tail: raise IndexError( 'There\'s nothing to remove from the linked list.') self._length -= 1 if self.head == self.tail: last_pop = self.head - self.head = None - self.tail = None + self.tail = self.head = None return last_pop.data shifted = self.tail self.tail = self.tail.next_node - shifted.next_node = None self.tail.prior_node = None return shifted.data - def __len__(self): + def size(self): """Return the length of the double linked list.""" return self._length def remove(self, val): """Remove a node with the value provided.""" - if val is None: - raise TypeError( - 'That value is not in this particular linked list.') if self.head.data == val: self.pop() + return elif self.tail.data == val: self.shift() + return current_node = self.head while current_node is not None: if current_node.data != val: @@ -102,9 +95,7 @@ def remove(self, val): else: new_next_node = current_node.next_node new_prior_node = current_node.prior_node - current_node.next_node.prior_node = new_prior_node - current_node.prior_node.next_node = new_next_node - current_node.next_node = None - current_node.prior_node = None + new_next_node.prior_node = new_prior_node + new_prior_node.next_node = new_next_node self._length -= 1 break diff --git a/src/priorityq.py b/src/priorityq.py index 3ae9ec8..b7459a5 100644 --- a/src/priorityq.py +++ b/src/priorityq.py @@ -3,6 +3,25 @@ # [{1: 0}, {100: 1}, {33: 2}, {44: 3}, {2: 0}] + # def heapify(self, iterable): + # """Function that will be used in init and other methods.""" + # heap_list = iterable + # for item in heap_list[::-1]: + # item_index = heap_list.index(item) + # parent = (item_index - 1) // 2 + # while item_index > 0: + + # if list(heap_list[parent].values())[0] < list(heap_list[parent].values())[0]: + # curr_val = heap_list[parent] + # heap_list[parent] = heap_list[item_index] + # heap_list[item_index] = curr_val + # item_index = parent + # parent = (item_index - 1) // 2 + # else: + # break + # return heap_list + + class PriorityQueue(object): """Implement a priority queue.""" @@ -18,15 +37,8 @@ def heapify(self, iterable): parent = (item_index - 1) // 2 while item_index > 0: if list(heap_list[parent].values())[0] is 0 and list(heap_list[item_index].values())[0] is 0: - if list(heap_list[item_index].keys())[0] < list(heap_list[parent].keys())[0]: - curr_val = heap_list[parent] - heap_list[parent] = heap_list[item_index] - heap_list[item_index] = curr_val - item_index = parent - parent = (item_index - 1) // 2 - else: - item_index = parent - parent = (item_index - 1) // 2 + item_index = parent + parent = (item_index - 1) // 2 elif list(heap_list[parent].values())[0] > 0 and list(heap_list[item_index].values())[0] is 0: item_index = parent parent = (item_index - 1) // 2 @@ -52,8 +64,8 @@ def heapify(self, iterable): def insert(self, value, priority=0): """Insert a value into the priority queue with an optional priority.""" - if not isinstance(value, int) or not isinstance(priority, int): - raise TypeError("Must provide an integer for value and priority.") + if not isinstance(priority, int): + raise TypeError("Must provide an integer for priority.") if priority < 0: raise ValueError("You may not use a negative priority. Priority must be 0 or greater.") self._heap.append({value: priority}) diff --git a/src/que_.py b/src/que_.py index b1aafd8..08fce44 100644 --- a/src/que_.py +++ b/src/que_.py @@ -23,6 +23,6 @@ def peek(self): """Return a new value without dequeuing it.""" print(self._new_dll.tail.data) - def __len__(self): + def size(self): """Length function for the queue.""" - return len(self._new_dll) + return self._new_dll.size() diff --git a/src/test_dijkstra.py b/src/test_dijkstra.py new file mode 100644 index 0000000..e69de29 diff --git a/src/test_dll.py b/src/test_dll.py index 36f412f..c1e0a59 100644 --- a/src/test_dll.py +++ b/src/test_dll.py @@ -12,29 +12,20 @@ def dll(): def test_dll_initialization(dll): """Test that there's nothing initialized.""" - assert dll.tail is None - assert dll.head is None - - -def test_dll_push_raises_type_error(dll): - """Test that the value error is raised.""" - with pytest.raises(TypeError): - dll.push() + assert dll.tail is dll.head is None def test_dll_push_pushes_value(dll): """Test that the push pushes a value to head of list.""" dll.push(1) - assert dll.tail.data == 1 - assert dll.head.data == 1 + assert dll.tail.data == dll.head.data == 1 def test_dll_push_head_and_tail_change(dll): """Test if second item is pushed in. Head and tail are seperate values.""" dll.push(1) dll.push(2) - assert dll.tail.data == 1 - assert dll.head.data == 2 + assert (dll.tail.data, dll.head.data) == (1, 2) def test_dll_push_3(dll): @@ -42,12 +33,9 @@ def test_dll_push_3(dll): dll.push(1) dll.push(2) dll.push(3) - assert dll.tail.data == 1 - assert dll.head.prior_node.prior_node.data == 1 - assert dll.head != dll.head.prior_node - assert dll.head.data == 3 - assert dll.head.prior_node.next_node.data == 3 - assert dll.tail.next_node.data == 2 + assert (dll.tail.data, dll.head.prior_node.prior_node.data, + dll.head != dll.head.prior_node, dll.head.data, dll.head.prior_node.next_node.data, + dll.tail.next_node.data) == (1, 1, True, 3, 3, 2) def test_dll_pop_index_error(dll): @@ -56,30 +44,26 @@ def test_dll_pop_index_error(dll): dll.pop() -def test_dll_pop_only_has_one_item(dll): +def test_dll_pop_only_has_one_item_phase_one(dll): """Test that pop only has one item and both are head and tail none vals.""" dll.push(1) dll.push(2) - assert dll.pop() == 2 - assert dll.head.data == 1 - assert dll.tail.data == 1 - assert dll.head.next_node is None - assert dll.pop() == 1 - assert dll.head is None - assert dll.tail is None + assert (dll.pop(), dll.head.data, dll.tail.data, + dll.head.next_node) == (2, 1, 1, None) -def test_dll_append_raises_type_error(dll): - """Test that we get a type error.""" - with pytest.raises(TypeError): - dll.append() +def test_dll_pop_only_has_one_item_phase_two(dll): + """Test that pop only has one item and both are head and tail none vals.""" + dll.push(1) + dll.push(2) + dll.pop() + assert (dll.pop(), dll.head, dll.tail) == (1, None, None) def test_dll_appends_a_value(dll): """Ensure tail and head are the same.""" dll.append(1) - assert dll.tail.data == 1 - assert dll.head.data == 1 + assert dll.tail.data == dll.head.data == 1 def test_dll_appends_3_values(dll): @@ -87,81 +71,78 @@ def test_dll_appends_3_values(dll): dll.append(1) dll.append(2) dll.append(3) - assert dll.tail.data == 3 - assert dll.head.data == 1 - assert dll.head.next_node is None - assert dll.tail.prior_node is None - assert dll.tail.next_node.data == 2 - assert dll.head.prior_node.data == 2 - assert dll.head.prior_node.next_node.data == 1 - assert dll.tail.next_node.prior_node.data == 3 - - -def test_dll_shift_index_error(dll): - """Test that the Index Error is raised if no val is shifted.""" - with pytest.raises(IndexError): - dll.shift() + assert (dll.tail.data, dll.head.data, dll.head.next_node, + dll.tail.prior_node, dll.tail.next_node.data, + dll.head.prior_node.data, dll.head.prior_node.next_node.data, + dll.tail.next_node.prior_node.data) == (3, 1, None, + None, 2, 2, + 1, 3) -def test_dll_shift_only_has_one_item(dll): +def test_dll_shift_only_has_one_item_phase_one(dll): """Test that node connections after shifting.""" dll.push(1) dll.push(2) - assert dll.shift() == 1 - assert dll.head.data == 2 - assert dll.tail.data == 2 - assert dll.head.next_node is None - assert dll.tail.prior_node is None - assert dll.shift() == 2 - assert dll.head is None - assert dll.tail is None - - -def test_dll_remove_index_error(dll): - """Testing that the Index Error is raised if no val is passed.""" + assert (dll.shift(), dll.head.data, dll.tail.data, + dll.head.next_node, dll.tail.prior_node) == (1, 2, 2, None, None) + + +def test_dll_shift_only_has_one_item_phase_two(dll): + """Test that node connections after shifting.""" + dll.push(1) + dll.push(2) + dll.shift() + assert (dll.shift(), dll.head, dll.tail) == (2, None, None) + + +def test_dll_remove_phase_one(dll): + """Testing the dll remove function.""" dll.push(1) dll.push(2) dll.push(3) - with pytest.raises(TypeError): - dll.remove() + dll.push(4) + dll.remove(3) + assert (dll.head.prior_node.data, + dll.head.prior_node.next_node.data) == (2, 4) + + +def test_dll_remove_phase_two(dll): + """Testing the dll remove function.""" + dll.push(1) + dll.push(2) + dll.push(3) + dll.push(4) + dll.remove(3) + dll.remove(1) + assert (dll.tail.data, + dll.tail.next_node.data) == (2, 4) -def test_dll_remove(dll): +def test_dll_remove_phase_three(dll): """Testing the dll remove function.""" dll.push(1) dll.push(2) dll.push(3) dll.push(4) dll.remove(3) - assert dll.head.prior_node.data == 2 - assert dll.head.prior_node.next_node.data == 4 dll.remove(1) - assert dll.tail.data == 2 - assert dll.tail.next_node.data == 4 dll.remove(4) - assert dll.head.data == 2 - assert dll.tail.data == 2 + assert dll.head.data == dll.tail.data == 2 -def test_dll_len(dll): +def test_dll_size(dll): """Test to make sure we get the right number of nodes.""" - assert len(dll) == 0 + dll_lengths = [] dll.push(1) - assert len(dll) == 1 dll.push(2) - assert len(dll) == 2 dll.append(3) - assert len(dll) == 3 dll.push(4) - assert len(dll) == 4 dll.push(5) - assert len(dll) == 5 dll.push(6) + dll_lengths.append(dll.size()) dll.remove(4) - assert len(dll) == 5 dll.pop() - assert len(dll) == 4 dll.shift() - assert len(dll) == 3 dll.pop() - assert len(dll) == 2 + dll_lengths.append(dll.size()) + assert dll_lengths == [6, 2] diff --git a/src/test_que_.py b/src/test_que_.py index 1227cfe..7f73761 100644 --- a/src/test_que_.py +++ b/src/test_que_.py @@ -13,8 +13,7 @@ def the_queue(): def test_the_queue_enqueue(the_queue): """Test for enqueuing to the queue.""" the_queue.enqueue(2) - assert the_queue._new_dll.head.data == 2 - assert the_queue._new_dll.tail.data == 2 + assert the_queue._new_dll.head.data == the_queue._new_dll.tail.data == 2 def test_the_queue_enqueue_multi_values(the_queue): @@ -23,10 +22,10 @@ def test_the_queue_enqueue_multi_values(the_queue): the_queue.enqueue(3) the_queue.enqueue(4) the_queue.enqueue(5) - assert the_queue._new_dll.head.data == 5 - assert the_queue._new_dll.tail.data == 2 - assert the_queue._new_dll.head.prior_node.data == 4 - assert the_queue._new_dll.tail.next_node.data == 3 + assert (the_queue._new_dll.head.data, + the_queue._new_dll.tail.data, + the_queue._new_dll.head.prior_node.data, + the_queue._new_dll.tail.next_node.data) == (5, 2, 4, 3) def test_the_queue_dequeue(the_queue): @@ -41,19 +40,25 @@ def test_the_queue_dequeue_raises_exception(the_queue): the_queue.dequeue() -def test_the_queue_dequeue_multi_values(the_queue): +def test_the_queue_dequeue_multi_values_phase_one(the_queue): """Test for dequeue on mulitple values.""" the_queue.enqueue(2) - assert the_queue._new_dll.tail.data == 2 the_queue.enqueue(3) - assert the_queue._new_dll.tail.next_node.data == 3 the_queue.enqueue(4) the_queue.enqueue(5) - assert the_queue._new_dll.head.data == 5 the_queue.dequeue() assert the_queue._new_dll.tail.data == 3 - assert the_queue.dequeue() == 3 - assert the_queue._new_dll.tail.data == 4 + + +def test_the_queue_dequeue_multi_values_phase_two(the_queue): + """Test for dequeue on mulitple values.""" + the_queue.enqueue(2) + the_queue.enqueue(3) + the_queue.enqueue(4) + the_queue.enqueue(5) + the_queue.dequeue() + assert (the_queue.dequeue(), + the_queue._new_dll.tail.data) == (3, 4) def test_the_peek(the_queue): @@ -61,25 +66,18 @@ def test_the_peek(the_queue): the_queue.enqueue(1) the_queue.enqueue(2) the_queue.enqueue(3) - assert the_queue._new_dll.tail.data == 1 the_queue.dequeue() assert the_queue._new_dll.tail.data == 2 -def test_the_queue_len(the_queue): +def test_the_queue_size(the_queue): """Test the length on the queue.""" the_queue.enqueue(1) the_queue.enqueue(2) the_queue.enqueue(3) - assert len(the_queue) == 3 - - - - - - - - - + assert the_queue.size() == 3 +def test_size_empty(the_queue): + """Test zero is returned if empty.""" + assert the_queue.size() == 0 diff --git a/tox.ini b/tox.ini index 036b313..0c528e4 100644 --- a/tox.ini +++ b/tox.ini @@ -2,7 +2,7 @@ envlist = py27, py36 [testenv] -commands = py.test src --cov=src --cov-report term-missing +commands = pytest src/test_que_.py --cov=src --cov-report term-missing deps = pytest pytest-cov