def test_prepend(self): linked_list = LinkedList() linked_list.prepend(1) linked_list.prepend(2) assert linked_list.to_array() == [2, 1]
def consolidate(self): """ Restructure the tree back to a binomial tree """ trees_by_rank = {} tree_stack = Stack() for tree in self.trees: tree_stack.push(tree) # Iterate over the trees and merge trees of the same rank while not tree_stack.is_empty(): tree = tree_stack.pop() if tree is None: continue if tree.rank in trees_by_rank: existing_tree = trees_by_rank[tree.rank] del trees_by_rank[tree.rank] tree_stack.push(tree.merge_min(existing_tree)) else: trees_by_rank[tree.rank] = tree # Build a new tree list and find the new min node new_trees = trees_by_rank.values() self.trees = LinkedList() self.min_tree = None for new_tree in new_trees: self.trees.append(new_tree) if self.min_tree is None or self.min_tree.value.value > new_tree.value: self.min_tree = self.trees.get_tail_node()
def test_exercise_4(self): linked_list_a = LinkedList.from_array([1, 2, 3]) linked_list_b = LinkedList.from_array([3, 2, 1]) linked_list_c = LinkedList.from_array([0, 0, 7, 1]) assert (linked_list_a + linked_list_b).to_array() == [4, 4, 4] assert (linked_list_a + linked_list_c).to_array() == [1, 2, 0, 2]
def test_exercise_1(self): assert LinkedList.from_array([]).remove_duplicates().to_array() == [] assert LinkedList.from_array([1, 1, 1, 1, 1, 1 ]).remove_duplicates().to_array() == [1] assert LinkedList.from_array( [1, 3, 4, 6, 2, 3, 1]).remove_duplicates().to_array() == [1, 3, 4, 6, 2]
def __init__(self, data=None): if not data: data = [] self.trees = LinkedList() self.min_tree = None for i in data: self.insert(i)
def test_exercise_5(self): linked_list = LinkedList.from_array([1, 2, 3, 4, 5]) assert linked_list.find_loop() is None # Insert a circular dependency 5 -> 2 linked_list.get_tail_node().set_next_node(linked_list.head.get_next_node()) assert linked_list.find_loop().value == 2 empty_linked_list = LinkedList.from_array([]) assert_raises(IndexError, empty_linked_list.get_tail_node)
def test_exercise_2(self): assert list( LinkedList.from_array( [1, 2, 3, 4, 5, 6, 7]).get_nth_to_last(0)) == [1, 2, 3, 4, 5, 6, 7] assert list( LinkedList.from_array([1, 2, 3, 4, 5, 6, 7]).get_nth_to_last(5)) == [6, 7] assert_raises( IndexError, lambda x: list( LinkedList.from_array([1, 2, 3, 4, 5, 6, 7]).get_nth_to_last(x) ), 7)
def test_exercise_5(self): linked_list = LinkedList.from_array([1, 2, 3, 4, 5]) assert linked_list.find_loop() is None # Insert a circular dependency 5 -> 2 linked_list.get_tail_node().set_next_node( linked_list.head.get_next_node()) assert linked_list.find_loop().value == 2 empty_linked_list = LinkedList.from_array([]) assert_raises(IndexError, empty_linked_list.get_tail_node)
def test_linked_list_get(self): ll = LinkedList.from_array([1, 2, 3, 4]) assert ll.get(3).value == 4 assert ll.get(0).value == 1 assert len(ll) == 4 assert_raises(IndexError, ll.get, 4)
def test_linked_list_insert(self): ll = LinkedList.from_array([1, 2, 3]) ll.insert(0, 4) assert ll.to_array() == [4, 1, 2, 3] assert len(ll) == 4 ll.insert(4, 10) assert ll.to_array() == [4, 1, 2, 3, 10] assert len(ll) == 5
def test_linked_list_remove(self): ll = LinkedList.from_array([2, 3, 4, 5, 6]) assert len(ll) == 5 ll.remove(0) assert ll.to_array() == [3, 4, 5, 6] assert len(ll) == 4 ll.remove(3) assert ll.to_array() == [3, 4, 5] assert len(ll) == 3 assert_raises(IndexError, ll.remove, 3)
class FibonacciHeap(object): def __init__(self, data=None): if not data: data = [] self.trees = LinkedList() self.min_tree = None for i in data: self.insert(i) def insert(self, value): tree = BinomialTreeNode(value) tree.marked = False self.trees.append(tree) # Update the min node reference if needed if self.min_tree is None or self.min_tree.value.value > value: self.min_tree = self.trees.get_tail_node() def pop(self): """ Remove the minimum node from the heap Actual cost. O(rank(H)) + O(trees(H)) * O(rank(H)) to meld min's children into root list. * O(rank(H)) + O(trees(H)) to update min. * O(rank(H)) + O(trees(H)) to consolidate trees. """ if not self.min_tree: raise IndexError() value = self.min_tree.value.value for child in self.min_tree.value.children: self.trees.append(child) self.min_tree.value = None self.min_tree = None self.consolidate() return value def merge(self, heap: 'FibonacciHeap'): if len(self.trees) == 0: self.trees = heap.trees self.trees.merge(heap.trees) if heap.min_tree and ( self.min_tree is None or heap.min_tree.value.value < self.min_tree.value.value): self.min_tree = heap.min_tree def decrease_min(self, node: BinomialTreeNode, value): if node.value < value: raise ValueError('Value should be smaller than this value') parent = node.parent while parent: # Remove node from parent and add it to the tree list parent.children.remove(node) node.parent = None self.trees.append(node) node.marked = False if self.min_tree is None or self.min_tree.value > node.value: self.min_tree = self.trees.get_tail_node() # Mark the parent if parent.marked: pass # Todo: finish decrease min # Utility functions def consolidate(self): """ Restructure the tree back to a binomial tree """ trees_by_rank = {} tree_stack = Stack() for tree in self.trees: tree_stack.push(tree) # Iterate over the trees and merge trees of the same rank while not tree_stack.is_empty(): tree = tree_stack.pop() if tree is None: continue if tree.rank in trees_by_rank: existing_tree = trees_by_rank[tree.rank] del trees_by_rank[tree.rank] tree_stack.push(tree.merge_min(existing_tree)) else: trees_by_rank[tree.rank] = tree # Build a new tree list and find the new min node new_trees = trees_by_rank.values() self.trees = LinkedList() self.min_tree = None for new_tree in new_trees: self.trees.append(new_tree) if self.min_tree is None or self.min_tree.value.value > new_tree.value: self.min_tree = self.trees.get_tail_node() def number_of_trees(self): return len(self.trees) def get_max_rank(self): if self.trees.get(0): return max(map(lambda x: x.rank, self.trees)) def __find_min_tree(self) -> LinkedListNode: """ Find the binomial subtree with the minimal element """ node = self.trees.head current_min = None while node: if node.value and node.value.value: if current_min and current_min.value: current_min = node if current_min.value.value > node.value.value else current_min else: current_min = node node = node.get_next_node() return current_min def __len__(self): return sum(map(lambda x: len(x) if x else 0, self.trees)) def is_empty(self): return self.min_tree is None
class FibonacciHeap(object): def __init__(self, data=None): if not data: data = [] self.trees = LinkedList() self.min_tree = None for i in data: self.insert(i) def insert(self, value): tree = BinomialTreeNode(value) tree.marked = False self.trees.append(tree) # Update the min node reference if needed if self.min_tree is None or self.min_tree.value.value > value: self.min_tree = self.trees.get_tail_node() def pop(self): """ Remove the minimum node from the heap Actual cost. O(rank(H)) + O(trees(H)) * O(rank(H)) to meld min's children into root list. * O(rank(H)) + O(trees(H)) to update min. * O(rank(H)) + O(trees(H)) to consolidate trees. """ if not self.min_tree: raise IndexError() value = self.min_tree.value.value for child in self.min_tree.value.children: self.trees.append(child) self.min_tree.value = None self.min_tree = None self.consolidate() return value def merge(self, heap: 'FibonacciHeap'): if len(self.trees) == 0: self.trees = heap.trees self.trees.merge(heap.trees) if heap.min_tree and (self.min_tree is None or heap.min_tree.value.value < self.min_tree.value.value): self.min_tree = heap.min_tree def decrease_min(self, node: BinomialTreeNode, value): if node.value < value: raise ValueError('Value should be smaller than this value') parent = node.parent while parent: # Remove node from parent and add it to the tree list parent.children.remove(node) node.parent = None self.trees.append(node) node.marked = False if self.min_tree is None or self.min_tree.value > node.value: self.min_tree = self.trees.get_tail_node() # Mark the parent if parent.marked: pass # Todo: finish decrease min # Utility functions def consolidate(self): """ Restructure the tree back to a binomial tree """ trees_by_rank = {} tree_stack = Stack() for tree in self.trees: tree_stack.push(tree) # Iterate over the trees and merge trees of the same rank while not tree_stack.is_empty(): tree = tree_stack.pop() if tree is None: continue if tree.rank in trees_by_rank: existing_tree = trees_by_rank[tree.rank] del trees_by_rank[tree.rank] tree_stack.push(tree.merge_min(existing_tree)) else: trees_by_rank[tree.rank] = tree # Build a new tree list and find the new min node new_trees = trees_by_rank.values() self.trees = LinkedList() self.min_tree = None for new_tree in new_trees: self.trees.append(new_tree) if self.min_tree is None or self.min_tree.value.value > new_tree.value: self.min_tree = self.trees.get_tail_node() def number_of_trees(self): return len(self.trees) def get_max_rank(self): if self.trees.get(0): return max(map(lambda x: x.rank, self.trees)) def __find_min_tree(self) -> LinkedListNode: """ Find the binomial subtree with the minimal element """ node = self.trees.head current_min = None while node: if node.value and node.value.value: if current_min and current_min.value: current_min = node if current_min.value.value > node.value.value else current_min else: current_min = node node = node.get_next_node() return current_min def __len__(self): return sum(map(lambda x: len(x) if x else 0, self.trees)) def is_empty(self): return self.min_tree is None
def test_exercise_1(self): assert LinkedList.from_array([]).remove_duplicates().to_array() == [] assert LinkedList.from_array([1, 1, 1, 1, 1, 1]).remove_duplicates().to_array() == [1] assert LinkedList.from_array([1, 3, 4, 6, 2, 3, 1]).remove_duplicates().to_array() == [1, 3, 4, 6, 2]
def test_linked_list_iter(self): ll = LinkedList.from_array([1, 2, 3]) assert list(ll) == [1, 2, 3]
def test_linked_list_reverse(self): ll = LinkedList.from_array([1, 2, 3]) ll.reverse() assert ll.to_array() == [3, 2, 1]
def test_exercise_2(self): assert list(LinkedList.from_array([1, 2, 3, 4, 5, 6, 7]).get_nth_to_last(0)) == [1, 2, 3, 4, 5, 6, 7] assert list(LinkedList.from_array([1, 2, 3, 4, 5, 6, 7]).get_nth_to_last(5)) == [6, 7] assert_raises(IndexError, lambda x: list(LinkedList.from_array([1, 2, 3, 4, 5, 6, 7]).get_nth_to_last(x)), 7)