Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, 
© 2005 Pearson Education, Inc. All rights reserved. 0-13-140909-3 

 

 

Figure 12.1& 7 Binary Search Tree Class Template

/* BST.h contains the declaration of class template BST.
   Basic operations:
     Constructor: Constructs an empty BST
     empty:       Checks if a BST is empty
     search:      Search a BST for an item
     insert:      Inserts a value into a BST
     remove:      Removes a value from a BST
     inorder:     Inorder traversal of a BST -- output the data values
     graph:       Output a grapical representation of a BST
   Private utility helper operations:
     search2:     Used by delete
     inorderAux:  Used by inorder
     graphAux:    Used by graph
  Other operations described in the exercises:
     destructor
     copy constructor
     assignment operator
     preorder, postorder, and level-by-level traversals
     level finder
---------------------------------------------------------------------------*/

#include <iostream>

#ifndef BINARY_SEARCH_TREE
#define BINARY_SEARCH_TREE

template <typename DataType>
class BST
{
 private:
  /***** Node structure *****/
  class BinNode 
  {
   public:
    DataType data;
    BinNode * left;
    BinNode *  right;

    // BinNode constructors
    // Default -- data part undefined; both links null
    BinNode()
    : left(0), right(0)
    {}

    // Explicit Value -- data part contains item; both links null
    BinNode(DataType item)
    : data(item), left(0), right(0)
    {}
  };

  typedef BinNode * BinNodePointer; 

 public:
  /***** Function Members *****/
  BST();
  /*------------------------------------------------------------------------
    Construct a BST object.

    Precondition:  None.
    Postcondition: An empty BST has been constructed.
   -----------------------------------------------------------------------*/

  bool empty() const;
  /*------------------------------------------------------------------------
    Check if BST is empty.

    Precondition: None.
    Postcondition: Returns true if BST is empty and false otherwise.
   -----------------------------------------------------------------------*/

  bool search(const DataType & item) const; 
  /*------------------------------------------------------------------------
    Search the BST for item.

    Precondition:  None.
    Postcondition: Returns true if item found, and false otherwise.
   -----------------------------------------------------------------------*/

   void insert(const DataType & item);
  /*------------------------------------------------------------------------
    Insert item into BST.

    Precondition:  None.
    Postcondition: BST has been modified with item inserted at proper 
        position to maintain BST property. 
  ------------------------------------------------------------------------*/

  void remove(const DataType & item);
  /*------------------------------------------------------------------------
    Remove item from BST.

    Precondition:  None.
    Postcondition: BST has been modified with item removed (if present);
        BST property is maintained.
    Note: remove uses auxiliary function search2() to locate the node
          containing item and its parent.
 ------------------------------------------------------------------------*/

  void inorder(ostream & out);
  /*------------------------------------------------------------------------
    Inorder traversal of BST.

    Precondition:  ostream out is open.
    Postcondition: BST has been inorder traversed and values in nodes 
        have been output to out.
    Note: inorder uses private auxiliary function inorderAux().
 ------------------------------------------------------------------------*/

  void graph(ostream & out);
  /*------------------------------------------------------------------------
    Graphic output of BST.

    Precondition:  ostream out is open.
    Postcondition: Graphical representation of BST has been output to out.
    Note: inorder uses private auxiliary function graphAux().
 ------------------------------------------------------------------------*/

 private:
  /***** Private Function Members *****/
  void search2(const DataType & item, bool & found,
               BinNodePointer & locptr, BinNodePointer & parent);
 /*------------------------------------------------------------------------
   Locate a node containing item and its parent.
 
   Precondition: None.
   Postcondition: locptr points to node containing item or is null if 
       not found, and parent points to its parent
 ------------------------------------------------------------------------*/

  void inorderAux(ostream & out, BinNodePointer subtreePtr);
  /*------------------------------------------------------------------------
    Inorder traversal auxiliary function.

    Precondition:  ostream out is open; subtreePtr points to a subtree 
        of this BST.
    Postcondition: Subtree of this BST with subtreePtr as root has been
        output to out.
 ------------------------------------------------------------------------*/

  void graphAux(ostream & out, int indent, BinNodePointer subtreeRoot);
  /*------------------------------------------------------------------------
    Graph auxiliary function.

    Precondition:  ostream out is open; subtreePtr points to a subtree 
        of this BST.
    Postcondition: Graphical representation of subtree of this BST with 
        subtreePtr as root has been output to out, indented indent spaces.
 ------------------------------------------------------------------------*/

 /***** Data Members *****/
  BinNodePointer myRoot; 

}; // end of class template declaration

//--- Definition of constructor
template <typename DataType>
inline BST<DataType>::BST()
: myRoot(0)
{}

//--- Definition of empty()
template <typename DataType>
inline bool BST<DataType>::empty() const
{ return myRoot == 0; }

//--- Definition of search()
template <typename DataType>
bool BST<DataType>::search(const DataType & item) const
{
  BST<DataType>::BinNodePointer locptr = myRoot;
  bool found = false;
  for (;;)
  {
    if (found || locptr == 0) break;
    if (item < locptr->data)       // descend left
      locptr = locptr->left;
    else if (locptr->data < item)  // descend right
      locptr = locptr->right;
    else                           // item found
      found = true;
  }
  return found;
}

//--- Definition of insert()
template <class DataType>
inline void BST<DataType>::insert(const DataType & item)
{
   BST<DataType>::BinNodePointer 
        locptr = myRoot,   // search pointer
        parent = 0;        // pointer to parent of current node
   bool found = false;     // indicates if item already in BST
   while (!found && locptr != 0)
   {
      parent = locptr;
      if (item < locptr->data)       // descend left
         locptr = locptr->left;
      else if (locptr->data < item)  // descend right
         locptr = locptr->right;
      else                           // item found
         found = true;
   }
   if (!found)
   {                                 // construct node containing item
      locptr = new BST<DataType>::BinNode(item);  
      if (parent == 0)               // empty tree
         myRoot = locptr;
      else if (item < parent->data )  // insert to left of parent
         parent->left = locptr;
      else                           // insert to right of parent
         parent->right = locptr;
   }
   else
      cout << "Item already in the tree\n";
}

//--- Definition of remove()
template <class DataType>
void BST<DataType>::remove(const DataType & item)
{
   bool found;                      // signals if item is found
   BST<DataType>::BinNodePointer 
      x,                            // points to node containing
      parent;                       //    "    " parent of x and xSucc
   search2(item, found, x, parent);

   if (!found)
   {
      cout << "Item not in the BST\n";
      return;
   }
   //else
   if (x->left != 0 && x->right != 0)
   {                                // node has 2 children
      // Find x's inorder successor and its parent
      BST<DataType>::BinNodePointer xSucc = x->right;
      parent = x;
      while (xSucc->left != 0)       // descend left
      {
         parent = xSucc;
         xSucc = xSucc->left;
      }

     // Move contents of xSucc to x and change x 
     // to point to successor, which will be removed.
     x->data = xSucc->data;
     x = xSucc;
   } // end if node has 2 children

   // Now proceed with case where node has 0 or 2 child
   BST<DataType>::BinNodePointer 
      subtree = x->left;             // pointer to a subtree of x
   if (subtree == 0)
      subtree = x->right;
   if (parent == 0)                  // root being removed
      myRoot = subtree;
   else if (parent->left == x)       // left child of parent
      parent->left = subtree; 
   else                              // right child of parent
      parent->right = subtree;
   delete x;
}

//--- Definition of inorder()
template <class DataType>
inline void BST<DataType>::inorder(ostream & out)
{ 
   inorderAux(out, myRoot); 
}

//--- Definition of graph()
template <class DataType>
inline void BST<DataType>::graph(ostream & out)
{ graphAux(out, 0, myRoot); }

//--- Definition of search2()
template <class DataType>
void BST<DataType>::search2(const DataType & item, bool & found,
                            BST<DataType>::BinNodePointer & locptr, 
			    BST<DataType>::BinNodePointer & parent)
{
   locptr = myRoot;
   parent = 0;
   found = false;
   while (!found && locptr != 0)
   {
      if (item < locptr->data)       // descend left
      {
         parent = locptr;
         locptr = locptr->left;
      }
      else if (locptr->data < item)  // descend right
      {
         parent = locptr;
         locptr = locptr->right;
      }
      else                           // item found
         found = true;
   }
}

//--- Definition of inorderAux()
template <class DataType>
void BST<DataType>::inorderAux(ostream & out, 
                               BST<DataType>::BinNodePointer subtreeRoot)
{
   if (subtreeRoot != 0)
   {
      inorderAux(out, subtreeRoot->left);    // L operation
      out << subtreeRoot->data << "  ";      // V operation
      inorderAux(out, subtreeRoot->right);   // R operation
   }
}

//--- Definition of graphAux()
#include <iomanip>

template <class DataType>
void BST<DataType>::graphAux(ostream & out, int indent, 
                             BST<DataType>::BinNodePointer subtreeRoot)
{
  if (subtreeRoot != 0)
    {
      graphAux(out, indent + 8, subtreeRoot->right);
      out << setw(indent) << " " << subtreeRoot->data << endl;
      graphAux(out, indent + 8, subtreeRoot->left);
    }
}

#endif 

 

 

 

Figure 12.8 Testing Binary Search Tree Class Template

/*----- treetester.cpp ----------------------------
  Program for testing class template BST.
  ------------------------------------------------*/
#include <iostream>
using namespace std;

#include "BST.h"

/*---- PART 3 ----
                                 // makeCopy() is a function with a
void makeCopy(BST<int> aBST)     // BST value parameter
{                                // to test the copy constructor
  cout << "\nNow copying the BST and adding 38999,"
          " -12312, and 55657 to the copy:\n";
  aBST.insert(38999);
  aBST.insert(-12312);
  aBST.insert(55657);
  cout << "--Inorder Traversal of the copy: \n";
  aBST.inorder(cout);
}
---- END PART 3 ----*/

int main()
{
  // Testing Constructor and empty()
  BST<int> intBST;            // test the class constructor
  cout << "Constructing empty BST\n";
  cout << "BST " << (intBST.empty() ? "is" : "is not") << " empty\n";

  // Testing inorder
  cout << "Inorder Traversal of BST: \n";
  intBST.inorder(cout);

  // Testing insert
  cout << "\nNow insert a bunch of integers into the BST."
          "\nTry items not in the BST and some that are in it:\n";
  int number;
  for (;;)
  {
    cout << "Item to insert (-999 to stop): ";
    cin >> number;
    if (number == -999) break;
    intBST.insert(number);
  }
  intBST.graph(cout);

  cout << "BST " << (intBST.empty() ? "is" : "is not") << " empty\n";
  cout << "Inorder Traversal of BST: \n";
  intBST.inorder(cout);

  cout << endl;

  // Testing search()
  cout << "\n\nNow testing the search() operation."
          "\nTry both items in the BST and some not in it:\n";
  for (;;)
  {
    cout << "Item to find (-999 to stop): ";
    cin >> number;
    if (number == -999) break;
    cout << (intBST.search(number) ? "Found" : "Not found") << endl;
  }

  // Testing remove()
  cout << "\nNow testing the remove() operation."
          "\nTry both items in the BST and some not in it:\n";
  for (;;)
  {
    cout << "Item to remove (-999 to stop): ";
    cin >> number;
    if (number == -999) break;
    intBST.remove(number);
    intBST.graph(cout);
  }
  cout << "\nInorder Traversal of BST: \n";
  intBST.inorder(cout);
  cout << endl;

/* ---- PART 1 ----
  // Testing Preorder and Postorder
  cout << "\nInorder Traversal of BST: \n";
  intBST.inorder(cout);
  cout << "\nPreorder Traversal of BST: \n";
  intBST.preorder(cout);
  cout << "\nPostorder Traversal of BST: \n";
  intBST.postorder(cout);
  cout << endl;
---- END PART 1 ----*/


/* ---- PART 2 ----
  // Testing the Destructor
  cout << "\nNow testing the destructor.  Remember to add an output\n"
          "statement to your destructor to indicate when it is called.\n";
  {
    BST<int> anotherBST;
    anotherBST.insert(6); anotherBST.insert(9); anotherBST.insert(5);
    anotherBST.insert(1); anotherBST.insert(3); anotherBST.insert(7);
    cout << "\nInorder Traversal of another BST: \n";
    anotherBST.inorder(cout);
    cout << "\n\nLifetime of this BST is over -- now destroy it.\n";
  }
---- END PART 2 ----*/


/* ---- PART 3 ----
  // Testing the Copy Constructor
  cout << "\nNow testing the copy constructor.\n";
  cout << "-- First with an initializing declaration: "
          "BST<int> copy = intBST;\n";
  BST<int> copy = intBST;
  cout << "-- Inorder traversal of copy:\n";
  copy.inorder(cout);
  cout << "\n\n-- Now by passing intBST to a value parameter:\n";
  makeCopy(intBST);
  cout << "\n--Check that original BST hasn't been changed.\n"
          "-- Inorder traversal of original:\n";
  intBST.inorder(cout);
  cout << endl;
---- END PART 3 ----*/


/* ---- PART 4 ----
  // Testing the Assignment Operator
  cout << "\nNow testing the assignment constructor with the statement:\n"
          "        copy = anotherBST = intBST;\n";
  BST<int> anotherBST;
  copy = anotherBST = intBST;
  cout << "\n-- Inorder traversal of intBST:\n";
  intBST.inorder(cout);
  cout << endl;
  cout << "\n-- Inorder traversal of anotherBST:\n";
  anotherBST.inorder(cout);
  cout << endl;
  cout << "\n-- Inorder traversal of copy:\n";
  copy.inorder(cout);
  cout << endl;
  cout << "\Now testing self-assignment with:  copy = copy;\n";
  copy = copy;
  cout << endl;
  cout << "\n-- Inorder traversal of copy:\n";
  copy.inorder(cout);
  cout << endl;  
---- END PART 4 ----*/

} 

 

 

Figure 12.9 Validating Computer Logins

#include <iostream>
#include <fstream>
#include <string>
using namespace std;

/*---------------------------------------------------------------------
  Program to validate computer user-ids and passwords.  A list of
  valid ids and passwords is read from UsersFile and is stored in
  a BST.  When user-ids and passwords are entered during execution,
  this BST is searched to determine whether they are legal.
 
   Input (file):     UserInfo records for valid users
   Input (keyboard): Ids and passwords of users logging in
   Output (screen):  Messages indicating whether user-ids and
                       passwords are valid
 --------------------------------------------------------------------*/

//----- Class containing user information -----//
//      with >>, ==, and < operators
class UserInfo
{
 public: 
  // ***** Function Members and Friends ***** //
  //--- id accessor
  string id() const { return myId; }

  //--- input function
  void read(istream & in)
  {
    in >> myId >> myPassword;
  }

  //--- equals operator
  bool operator==(const UserInfo & user) const
  { return myId == user.myId &&
           myPassword == user.myPassword; }

  //--- less-than operator
  bool operator<(const UserInfo & user) const
  { return myId < user.myId ||
           myId == user.myId && myPassword < user.myPassword; }

  private: 
  // ***** Data Members ***** //
  string myId,
         myPassword;
};

//--- Definition of input operator
istream & operator>>(istream & in, UserInfo & user)
{
  user.read(in);
}


#include "BST.h"

int main()
{
  // Open stream to file of legal user-ids and password
  string userFile;
  cout << "Enter name of user-info file: ";
  getline(cin, userFile);
  ifstream inStream(userFile.data());
  if (!inStream.is_open())
  {
    cerr << "Cannot open " << userFile << "\n";
    exit(1);
  }

  // Build the BST of user records
  BST<UserInfo> userTree;   // BST of user records
  UserInfo user;            // a user record
  for(;;)
  {
    inStream >> user;
    if (inStream.eof()) break;

    userTree.insert(user);
  }

  // Validate logins
  cout << "Enter Q Q to stop processing.\n";
  for (;;)
  {
    cout << "\nUser id & password: ";
    cin >> user;
    if (user.id() == "Q") break;
    if (userTree.search(user))
      cout << "Valid user\n";
    else
      cout << "Not a valid user\n";
  }
} 
Hosted by www.Geocities.ws

1