Section 6 - Implementing Removal

5A.6.1 Removal

Removal is treated exactly like insertion -- it is not harder and no easier. We developed a general approach with our development of the mythical remsert() algorithm, and it works just fine for removing a node. We copy the remove() method from the simple BST template, then make the appropriate adjustments. Dust off your FHsearch_tree::remove() and place it in a nearby window so you can see the basis of the AVL version.

Here is the result, followed by some discussion.

template <class Comparable>
bool FHavlTree<Comparable>::remove( const Comparable & x, FHs_treeNode<Comparable> * & root )
{
   if (root == NULL)
      return false;

   if (x < root->data)
   {
      if ( !remove(x, root->lftChild) )
         return false;

      // rebalance - shortened left branch so right may now be higher by 2
      if(heightOf(root->rtChild) - heightOf(root->lftChild) == 2)
         if(heightOf(root->rtChild->rtChild) < heightOf(root->rtChild->lftChild))
            doubleWithRightChild(root);
         else
            rotateWithRightChild(root);
   }
   else if (root->data < x)
   {
      if ( !remove(x, root->rtChild) )
         return false;

      // rebalance - shortened right branch so left may now be higher by 2
      if(heightOf(root->lftChild) - heightOf(root->rtChild) == 2)
         if(heightOf(root->lftChild->lftChild) < heightOf(root->lftChild->rtChild))
            doubleWithLeftChild(root);
         else
            rotateWithLeftChild(root);
   }

   // found the node
   else if (root->lftChild != NULL && root->rtChild !=NULL)
   {
      // first simply copy min right data into the node marked for deletion
      FHs_treeNode<Comparable> *minNode = findMin(root->rtChild);
      root->data = minNode->data;

      // now we do a real deletion:  the old min is still in the right sub-tree
      remove(minNode->data, root->rtChild);

      // rebalance - shortened right branch so left may now be higher by 2
      if(heightOf(root->lftChild) - heightOf(root->rtChild) == 2)
         if(heightOf(root->lftChild->lftChild) < heightOf(root->lftChild->rtChild))
            doubleWithLeftChild(root);
         else
            rotateWithLeftChild(root);
   }
   else
   {
      // no rebalancing needed at this external (1+ NULL children) node
      FHs_treeNode<Comparable> *nodeToRemove = root;
      root = (root->lftChild != NULL)? root->lftChild : root->rtChild;
      delete nodeToRemove;
      return true;

   }
   // successfully removed and rebalanced at this and lower levels; now adjust height
   root->setHeight( max(heightOf(root->lftChild), heightOf(root->rtChild)) + 1);
   return true;
}

A short glance at the precursor BST version reveals that we are mimicking it step-for-step.

Perfunctory Observation:

Deeper Observations:

5A.6.2 Full Coding

We will not do the complete coding of AVL trees today. This has been a day for understanding the concepts and details of both the rotations and insert/delete algorithms that will be used in AVL trees. This is 90% of the work. What we have left is everything else - those things that have nothing to do with AVL and are exactly the same as basic BSTs. Because of that, ironically, we will have something more interesting to do.

If AVLs were different enough from BSTs we would simply duplicate the entire BST file and change the insert/delete logic (adding, of course the private rotation methods) and we'd be done. However, because of the great similarity, we want to avoid duplicating the template -- instead we will use inheritance to reuse the BST template, thus avoiding the need to redefine the other 20 or so functions (even if their definitions would be identical, requiring nothing more than a copy/paste). The idea is that if we have an improvement to, or find a bug in, the BST logic, we won't have to fix it in two places - just in the BST class. The AVL class will inherit the repairs automatically.

But that's for next time. See you then.