private void delete(RBNode z) {
    
    RBNode x = factory.create();	// work node to contain the replacement node
    RBNode y;					// work node
    
    // find the replacement node (the successor to x) - the node one with
    // at *most* one child.
    if(z.getLeft() == sentinelNode || z.getRight() == sentinelNode)
      y = z;						// node has sentinel as a child
    else {
      // z has two children, find replacement node which will
      // be the leftmost node greater than z
      y = z.getRight();				        // traverse right subtree
      while(y.getLeft() != sentinelNode)		// to find next node in sequence
        y = y.getLeft();
    }
    
    // at this point, y contains the replacement node. it's content will be copied
    // to the valules in the node to be deleted
    
    // x (y's only child) is the node that will be linked to y's old parent.
    if(y.getLeft() != sentinelNode)
      x = y.getLeft();
    else
      x = y.getRight();
    
    // replace x's parent with y's parent and
    // link x to proper subtree in parent
    // this removes y from the chain
    x.setParent(y.getParent());
    if(y.getParent() != null)
      if(y == y.getParent().getLeft())
        y.getParent().setLeft(x);
      else
        y.getParent().setRight(x);
    else
      setRoot(x);		// make x the root node
    
    // copy the values from y (the replacement node) to the node being deleted.
    // note: this effectively deletes the node.
    if(y != z) {
      z.setValue(y.getValue());
    }
    
    if(y.getColor() == Color.BLACK)
      restoreAfterDelete(x);
  }