Question

I am trying to solve the following: finding the weight of the heaviest node in the tree and also representing that node as a list. This is what I came up with, but I am pretty sure that it is a very messy solution. Any advice on doing it more efficiently within the frame of the class given?

Given the class:

    class Tree_node():
        def __init__(self,key,val):
            self.key=key
            self.val=val
            self.left=None
            self.right=None  

    def __repr__(self):
    return "[" + str(self.left) + " " + str(self.key) + " " + \
                str(self.val) + " " + str(self.right) + "]"     

I calculate the weight of the heaviest path:

def weight(node):
    if node == None:
        return 0
    if weight(node.left)>weight(node.right):
        return node.val+weight(node.left)
    else:
        return node.val+weight(node.right)

And then I try to return the heaviest path as a list:

def heavy_path(node):
    if node==None:
        return []
    elif node.val+weight(node.left)> node.val+weight(node.right):
        return [node.val] + filter_values(path_values(node.left))
    else:return [node.val] + filter_values(path_values(node.right))

def path_values(node):
    if node == None:
        return 0
    return [node.val,path_values(node.left),path_values(node.right)]

def filter_values (node):
    values = []
    sub_lists = []
    if node != 0:
        for value in node:
            if isinstance(value, list):
                sub_lists = filter_values(value)
            else:
                if value != 0:
                    values.append(value)
    return values+sub_lists

So that given a tree like [[None a 7 None] b 5 [[None c 8 None] d 3 None]]:

>>> weight(t)
16
>>> heavy_path(t)
[5, 3, 8]

What would be a better way of doing this?

Was it helpful?

Solution

Assuming that you are interpreting the heaviest path as being a path that always begins with the root of the tree and descends down to a single leaf. You could try merging the weight-finding and path-building operations:

def heavy_path(node):
  if not node
    return (0,[])
  [lweight,llist] = heavy_path(node.left)
  [rweight,rlist] = heavy_path(node.right)
  if lweight>rweight:
    return (node.val+lweight,[node.val]+llist)
  else:
    return (node.val+rweight,[node.val]+rlist)

Or using a time-honoured technique to speed up this kind of calculation through Memoization. Once you've used memoization once, you could just keep the pathweight values up to date as you alter your tree.

def weight(node):
  if node == None:
      return 0
  node.pathweight=node.val+max(weight(node.left),weight(node.right))
  return node.pathweight

def heavy_edge(node):
  if not node.left:
    lweight=0
  else:
    lweight=node.left.pathweight
  if not node.right:
    rweight=0
  else:
    rweight=node.right.pathweight
  if lweight>rweight:
    return [node.val,heavy_edge(node.left)]
  else:
    return [node.val,heavy_edge(node.right)]

weight(t) #Precalculate the pathweight of all the nodes in O(n) time
heavy_edge(T) #Use the precalculated pathweights to efficient find list the heaviest path in O(lg n) time
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top