/**
   * Ensures that this BinarySearchTree object contains a specified element. The worstTime(n) is
   * O(n) and averageTime(n) is O(log n).
   *
   * @param element - the element whose presence is ensured in this BinarySearchTree object.
   * @return true - if this BinarySearchTree object changed as a result of this method call (that
   *     is, if element was actually inserted); otherwise, return false.
   * @throws ClassCastException - if element cannot be compared to the elements already in this
   *     BinarySearchTree object.
   * @throws NullPointerException - if element is null.
   */
  public boolean add(E element) {
    if (root == null) {
      if (element == null) throw new NullPointerException();
      root = new Entry<E>(element, null);
      size++;
      return true;
    } // empty tree
    else {
      Entry<E> temp = root;

      int comp;

      while (true) {
        comp = ((Comparable) element).compareTo(temp.element);
        if (comp == 0) return false;
        if (comp < 0)
          if (temp.left != null) temp = temp.left;
          else {
            temp.left = new Entry<E>(element, temp);
            size++;
            return true;
          } // temp.left == null
        else if (temp.right != null) temp = temp.right;
        else {
          temp.right = new Entry<E>(element, temp);
          size++;
          return true;
        } // temp.right == null
      } // while
    } // root not null
  } // method add
 protected Entry<E> copy(Entry<? extends E> p, Entry<E> parent) {
   if (p != null) {
     Entry<E> q = new Entry<E>(p.element, parent);
     q.left = copy(p.left, q);
     q.right = copy(p.right, q);
     return q;
   } // if
   return null;
 } // method copy