Comparison fails when trying to find closest value in binary search tree

Question:

I tried to get the closest value to a target value inside a binary tree with this programme and it didn’t work, although it worked well in manually (static) inserted tree !!!

    def clos(self,target):
        if self.root:
          self._clos(self.root,target)          
    
    def _clos(self,curnode,value):
        a = curnode.val
        l=[]
        kid = curnode.left if value < a else curnode.right
        if not kid:
          return a
       
        else:
          b = self._clos(kid, value)
        l.extend([value-a,value-b])
        return min(map(abs,l))
        #print(l) for showing the None_object error
        
                                    
tree = Tree()
l=[1, 2, 4, 5,7,13,15,22,70]
tree.array_to_bst(l)
print(tree.clos(3))

this return :

Traceback (most recent call last):
  File "C:UsersHPDocumentsCodesnew 1.py", line 110, in <module>
    print(tree.clos(3))
          ^^^^^^^^^^^^
  File "C:UsersHPDocumentsCodesnew 1.py", line 91, in clos
    self._clos(self.root,target)          
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:UsersHPDocumentsCodesnew 1.py", line 102, in _clos
    l.extend([_value-a,_value-b])
                       ~~~~~~^~
TypeError: unsupported operand type(s) for -: 'int' and 'NoneType'
Asked By: fond bcn

||

Answers:

The error occurs because your function does not always execute a return statement. You have put a return statement in comments, and instead print a result, but this means that None is returned to the caller, and that caller will assign that None to b, and then the expression value-b triggers the error you see.

Note that the clos method also lacks a return statement and so the caller of clos will always get None.

I did not quite understand which algorithm you had in mind, as even returning min(map(abs, l)) is not useful to the caller. You need to return an actual value that is in the tree, not a difference.

A common way to implement this is to pass a "window" to the recursive call, and have that window shrink every time you make a step further down the tree. When the end of the path is encountered, choose one of the two boundary values of that window, depending on which is closer to the given value.

Here is an implementation:

    def clos(self, target):
        if self.root:
            return self._clos(self.root, target, float('-inf'), float('inf'))          
    
    def _clos(self, curnode, value, low, high):
        if not curnode:
            # Determine which of the two is closest to value (low or high)
            if value - low < high - value:
                return low
            else:
                return high
        if value < curnode.val:
            return self._clos(curnode.left, value, low, curnode.val)
        else:
            return self._clos(curnode.right, value, curnode.val, high)
Answered By: trincot
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.