def find_immediate_common_ancestor_5(root, value1, value2): """find_immediate_common_ancestor_5 algorithm: pre-order traversal with value for each level """ if not root: return ancestor, immediate_ancestor_level = {}, -1 stack = Stack([(root, 0)]) while stack: p, level = stack.pop() #^# ancestor[level] = p if p.value in (value1, value2): if immediate_ancestor_level == -1: immediate_ancestor_level = level - 1 else: return ancestor[immediate_ancestor_level].value if immediate_ancestor_level > level - 1: immediate_ancestor_level = level - 1 #$# if p.right: stack.append((p.right, level+1)) if p.left: stack.append((p.left, level+1))
def postorder_traverse_4(root): """postorder_traverse_4 algorithm: improve postorder_traverse_3 based on the fact that if last visited node is current node's right child, then current node should be popped up """ stack = Stack([], debug=True) node = root last_visited = None while True: # push while node: stack.append(node) node = node.left if not stack: break # top/pop node = stack[-1] if not node.right or node.right == last_visited: node = stack.pop() yield node last_visited = node # prepare next node = None else: # prepare next node = node.right
def find_immediate_common_ancestor_2(root, value1, value2): """find_immediate_common_ancestor_2 algorithm: in post-order, the stack holds all the parent node when find the first value, the parent list only shrink on the road to find the 2nd value. """ p, last_visited, immediate_ancestor = root, None, None #stack = Stack([], debug=True) stack = Stack([]) while p or stack: while p: stack.append(p) p = p.left p = stack[-1] if not p.right or p.right == last_visited: stack.pop() #^# if p.value in (value1, value2): if not immediate_ancestor: immediate_ancestor = stack[-1] else: return immediate_ancestor.value if p == immediate_ancestor: if stack: immediate_ancestor = stack[-1] #$# last_visited = p p = None else: p = p.right
def postorder_traverse_3(root): """postorder_traverse_3 algorithm: push/pop node to stack according to current node's state """ ns = [root, VISIT_LEFT] #(node, state) stack = Stack([], debug=True) while ns or stack: while ns: stack.append(ns) node, state = ns #ns[1] == VISIT_LEFT ns[1] = VISIT_RIGHT if node.left: ns = [node.left, VISIT_LEFT] else: ns = None ns = stack[-1] if ns[1] == VISIT_RIGHT: ns[1] = VISIT_SELF if ns[0].right: ns = [ns[0].right, VISIT_LEFT] else: ns = None elif ns[1] == VISIT_SELF: yield ns[0] stack.pop() ns = None
def dfs(self, starting_vertex, destination_vertex): """ Return a list containing a path from starting_vertex to destination_vertex in depth-first order. """ #make a stack s = Stack() #make set to track nodes visited visited = set() #mark node as visited visited.add(starting_vertex) while s.size() > 0: current_node = s.pop() if current_node in visited: continue visited.append(current_node) neighbors = self.get_neighbors(current_node) for neighbor in neighbors: s.append(neighbor) return s
def postorder_traverse(root): """postorder_traverse algorithm: postorder (left, right, root) is the reverse of (root, right, left) """ stack = Stack([root], debug=True) while stack: p = stack.pop() yield p if p.left: stack.append(p.left) if p.right: stack.append(p.right)
def preorder_traverse(root): """preorder traversal """ stack = Stack([root], debug=True) while stack: node = stack.pop() yield node if node.right: stack.append(node.right) if node.left: stack.append(node.left)
def find_nodes_with_sum(root, _sum): """find 2 nodes that their sum is _sum in a binary search tree. algorithm: basically 2 pointer for the left and right side of the list and move it closer based on the sum of the 2 nodes. """ #stack1 = Stack([], name="ascend ", debug=True) stack1 = Stack([], name="ascend ") #stack2 = Stack([], name="descend", debug=True) stack2 = Stack([], name="descend") p1 = p2 = root while (p1 or stack1) and (p2 or stack2): while p1: stack1.append(p1) p1 = p1.left while p2: stack2.append(p2) p2 = p2.right p1 = stack1[-1] p2 = stack2[-1] if p1 == p2: #same node stack2.pop() p2 = p2.left p1 = None continue if p1.value + p2.value > _sum: stack2.pop() p2 = p2.left p1 = None elif p1.value + p2.value < _sum: stack1.pop() p1 = p1.right p2 = None else: return (p1.value, p2.value)
def find_immediate_common_ancestor(root, value1, value2): """find_immediate_common_ancestor algorithm: in post-order, the stack holds all the ancestor node. record the 2 ancestor lists and compare them. """ p = root #stack = Stack([], debug=True) stack = Stack([]) last_visited = None count_found = 0 while p or stack: while p: stack.append(p) p = p.left p = stack[-1] if not p.right or p.right == last_visited: stack.pop() #^# if p.value in (value1, value2): count_found += 1 if count_found == 1: parent_stack1 = stack[:] elif count_found == 2: common_idx = -1 min_len = len(stack) < len(parent_stack1) and len(stack) or len(parent_stack1) idx = 0 while idx < min_len: if stack[idx] == parent_stack1[idx]: common_idx = idx idx += 1 else: break return stack[common_idx].value #$# last_visited = p p = None else: p = p.right
def inorder_traverse(root): """inorder traversal """ stack = Stack([], debug=True) node = root while True: # push while node: stack.append(node) node = node.left if len(stack) == 0: break # pop node = stack.pop() yield node # next node = node.right
def postorder_traverse_2(root): """postorder_traverse_2 algorithm: improve postorder_traverse by using 2 stacks and make the output in the rite order. """ stack1, stack2 = Stack([], debug=True), Stack([]) stack1.append(root) while stack1: p = stack1.pop() stack2.append(p) if p.left: stack1.append(p.left) if p.right: stack1.append(p.right) while stack2: p = stack2.pop() yield p
def reconstruct_tree_2(preorder, inorder): """reconstruct_tree_2 @param: preorder traversal list @param: inorder traversal list @return: root node algorithm: nonrecursive """ cur_pre_idx, pre_pre_idx = 0, -1 #stack = Stack([], debug = True) stack = Stack([]) while cur_pre_idx < len(preorder) or stack: if cur_pre_idx != pre_pre_idx: value = preorder[cur_pre_idx] #node node = Node(None, None, value) #split scheme idx = inorder.index(value) if stack: parent_range = stack[-1][1] parent_operation = stack[-1][2] else: parent_range = (0, len(inorder), -1) parent_operation = VISIT_LEFT if parent_operation == VISIT_LEFT: _range = (parent_range[0], idx, parent_range[1]) else: _range = (parent_range[1], idx, parent_range[2]) #current operation operation = VISIT_LEFT #push stack.append([ node, _range, operation]) pre_pre_idx = cur_pre_idx #check next value and continue build the stack if cur_pre_idx < len(preorder) -1: next_value = preorder[cur_pre_idx + 1] next_in_idx = inorder.index(next_value) else: next_value = None next_in_idx = -1 node, _range, operation = stack[-1] if operation == VISIT_LEFT and _range[0] <= next_in_idx < _range[1]: cur_pre_idx += 1 continue elif operation == VISIT_RIGHT and _range[1] <= next_in_idx < _range[2]: cur_pre_idx += 1 continue r = stack.pop() if not stack: return r[0] if stack[-1][2] == VISIT_LEFT: stack[-1][0].left = r[0] stack[-1][2] = VISIT_RIGHT elif stack[-1][2] == VISIT_RIGHT: stack[-1][0].right = r[0] stack[-1][2] = VISIT_SELF
def reconstruct_tree_2(preorder, inorder): """reconstruct_tree_2 @param: preorder traversal list @param: inorder traversal list @return: root node algorithm: nonrecursive """ cur_pre_idx, pre_pre_idx = 0, -1 #stack = Stack([], debug = True) stack = Stack([]) while cur_pre_idx < len(preorder) or stack: if cur_pre_idx != pre_pre_idx: value = preorder[cur_pre_idx] #node node = Node(None, None, value) #split scheme idx = inorder.index(value) if stack: parent_range = stack[-1][1] parent_operation = stack[-1][2] else: parent_range = (0, len(inorder), -1) parent_operation = VISIT_LEFT if parent_operation == VISIT_LEFT: _range = (parent_range[0], idx, parent_range[1]) else: _range = (parent_range[1], idx, parent_range[2]) #current operation operation = VISIT_LEFT #push stack.append([node, _range, operation]) pre_pre_idx = cur_pre_idx #check next value and continue build the stack if cur_pre_idx < len(preorder) - 1: next_value = preorder[cur_pre_idx + 1] next_in_idx = inorder.index(next_value) else: next_value = None next_in_idx = -1 node, _range, operation = stack[-1] if operation == VISIT_LEFT and _range[0] <= next_in_idx < _range[1]: cur_pre_idx += 1 continue elif operation == VISIT_RIGHT and _range[1] <= next_in_idx < _range[2]: cur_pre_idx += 1 continue r = stack.pop() if not stack: return r[0] if stack[-1][2] == VISIT_LEFT: stack[-1][0].left = r[0] stack[-1][2] = VISIT_RIGHT elif stack[-1][2] == VISIT_RIGHT: stack[-1][0].right = r[0] stack[-1][2] = VISIT_SELF