code: def qbe_tree(graph, nodes, root=None):
      
      if root:
          start = root
      else:
          index = random.randint(0, len(nodes) - 1)
          start = nodes[index]
      # A queue to BFS instead DFS
      to_visit = deque()
      cnodes = copy(nodes)
      visited = set()
      # Format is (parent, parent_edge, neighbor, neighbor_field)
      to_visit.append((None, None, start, None))
      tree = {}
      while len(to_visit) != 0 and nodes:
          parent, parent_edge, v, v_edge = to_visit.pop()
          # Prune
          if v in nodes:
              nodes.remove(v)
          node = graph[v]
          if v not in visited and len(node) > 1:
              visited.add(v)
              # Preorder process
              if all((parent, parent_edge, v, v_edge)):
                  if parent not in tree:
                      tree[parent] = []
                  if (parent_edge, v, v_edge) not in tree[parent]:
                      tree[parent].append((parent_edge, v, v_edge))
                  if v not in tree:
                      tree[v] = []
                  if (v_edge, parent, parent_edge) not in tree[v]:
                      tree[v].append((v_edge, parent, parent_edge))
              # Iteration
              for node_edge, neighbor, neighbor_edge in node:
                  value = (v, node_edge, neighbor, neighbor_edge)
                  to_visit.append(value)
      remove_leafs(tree, cnodes)
      return tree, (len(nodes) == 0)
docs: Given a graph, nodes to explore and an optinal root, do a breadth-first
      search in order to return the tree.