Laboratory‎ > ‎

C++

The following is a list of Java programming assignments done by Seunghoon Kim for CS225 Data Structures in Fall 2003 while attending University of Illinois at Urbana-Champaign. To be used for personal references only.


CS225 MP1: Compact Disc

A program for controlling attributes for a music compact disc

disc.h

// ***********************************************
// *                                             *
// *  disc.h (MP1 solution, file #1 of 2)        *
// *                                             *
// *  Interface for a class representing a CD    *
// *                                             *
// *  Written September 2003 by Seunghoon Kim    *
// *                                             *
// ***********************************************

#ifndef _DISC_H
#define _DISC_H

#include <iostream.h>
#include "string.h"


class CompactDisc
{
public:

   // CompactDisc
   //    - constructor
   //    - initializes CD to be a blank CD with 
   //        no information at all
   CompactDisc();

 

   // CompactDisc
   //    - constructor
   //    - parameters : artist - artist performing on CD
   //                 : title - title of CD
   //    - initializes CD to have the parameter artist and title,
   //          but no songs
   CompactDisc(const String& artist, const String& title);


 
   // AddTrack 
   //    - parameters : songName - title of song
   //                 : seconds - length of song, in seconds
   //    - return value : integer serving as boolean value
   //    - if adding this track to the CD would not exceed the
   //        bounds of 10 tracks per CD or 74 minutes per CD,
   //        then add track and return 1. Else, do NOT add
   //        track, and return 0.  
   int AddTrack(const String& songName, int seconds);


   // PrintTrack
   //    - parameters : number - the track number to print
   //    - if the track number is legal, prints the CD info
   //        and track info. Otherwise, prints an appropriate
   //        error message. 
   void PrintTrack(int number) const;

   

   // TrackCount
   //    - return value : integer holding a quantity
   //    - returns the number of tracks that have been 
   //        added to the CD 
   int TrackCount() const;


private:

    String CDartist;
    String CDtitle;
    
    String trackNames[10];
    int trackTimes[10];
    int numTracks;
    int totalTime;

};


#endif
  

disc.cpp

// ****************************************************
// *                                                  *
// *  disc.cpp (MP1 solution, file #2 of 2)           *
// *                                                  *
// *  Implementation for a class representing a CD    *
// *                                                  *
// *  Written September 2003 by Seunghoon Kim         *
// *                                                  *
// ****************************************************

#include "disc.h"


// CompactDisc
//    - constructor
//    - initializes CD to be a blank CD with 
//        no information at all
CompactDisc::CompactDisc()
{
   CDartist = "";
   CDtitle = "";
   numTracks = 0;
   totalTime = 0;
}




// CompactDisc
//    - constructor
//    - parameters : artist - artist performing on CD
//                 : title - title of CD
//    - initializes CD to have the parameter artist and title,
//          but no songs
CompactDisc::CompactDisc(const String& artist, const String& title)
{
   CDartist = artist;
   CDtitle = title;
   numTracks = 0;
   totalTime = 0;
}



// AddTrack 
//    - parameters : songName - title of song
//                 : seconds - length of song, in seconds
//    - return value : integer serving as boolean value
//    - if adding this track to the CD would not exceed the
//        bounds of 10 tracks per CD or 74 minutes per CD,
//        then add track and return 1. Else, do NOT add
//        track, and return 0.  
int CompactDisc::AddTrack(const String& songName, int seconds)
{
   int successOrNot;
   if ((numTracks <= 9) && (totalTime + seconds <= 74*60))
   {
      trackNames[numTracks] = songName;
      trackTimes[numTracks] = seconds;
      totalTime = totalTime + seconds;
      numTracks++;     
      successOrNot = 1;
   }
   else
      successOrNot = 0;

   return successOrNot; 
}



// PrintTrack
//    - parameters : number - the track number to print
//    - if the track number is legal, prints the CD info
//        and track info. Otherwise, prints an appropriate
//        error message. 
void CompactDisc::PrintTrack(int number) const
{
   if ((number >= 1) && (number <= numTracks))
   {
      cout << "Artist: " << CDartist << endl;
      cout << "Title: " << CDtitle << endl;
      cout << "Track #" << number << ": " << endl;
      cout << "   Song Title: " << trackNames[number-1] << endl;
      cout << "   Running Time: ";
      cout << (trackTimes[number-1] / 60) << " minutes, ";
      cout << (trackTimes[number-1] % 60) << " seconds" << endl;
   }
   else 
      cout << "Track #" << number << " does not exist!" << endl;
}



// TrackCount
//    - return value : integer holding a quantity
//    - returns the number of tracks that have been 
//        added to the CD 
int CompactDisc::TrackCount() const
{ 
   return numTracks;
}
  

CS225 MP2: Labeled Collection

This code handles collection of arrayed items with labeling task

labeled.h

// *****************************************************
// *                                                   *
// *   labeled.h                                       *   
// *                                                   *
// *   Interface for a LabeledCollection class         * 
// *                                                   *
// *   Written 9/19/2003 by Seunghoon Kim              * 
// *                                                   * 
// *****************************************************

#ifndef labeled_h
#define labeled_h

#include "string.h"
#include "array.h"
#include "asserts.h"
#include <stdlib.h>
#include <iostream.h>


template<class Etype>
class LabeledCollection
{
public:

   	// LabeledCollection
   	//    - default constructor
   	//    - initializes a labeledCollection with a capacity of twon
	LabeledCollection();

   	// LabeledCollection
   	//    - copy constructor
   	//    - parameters : origCollection - previously declared LabeledCollection object
   	//    - initializes LabeledCollection to be a copy of origCollection	
	LabeledCollection(const LabeledCollection& origCollection);

 
   	// ~LabeledCollection
   	//    - destructor
   	//    - deletes dynamically allocated memory	
	~LabeledCollection();
	
   	// operator=
   	//    - parameters : origCollection - previously allocated LabeledCollection object
   	//    - return value : reference to this LabeledCollection object
   	//    - sets object to be a copy of origCollection
	const LabeledCollection& operator=(const LabeledCollection& origCollection);

	// AddItem
	//    - parameters : newItem - value of generic type
	//		     newLabel - string label
	//    - adds a pair of string label and generic type newItem to the object			   
	void AddItem(Etype newItem, String newLabel);


	// RelabelItem
	//    - parameters : oldLabel - string label to be replaced
	//		     newLabel - a new string label
	//    - renames oldLabel to newLabel
	void RelabelItem(String oldLabel, String newLabel);

	// LabelExists
	//    - parameters : oldLabel - a string label to compare
	//    - return type: int variable that returns 1 if oldLabel exists, 0 if not.
	//    - checks the string array to see whether oldLabel exists in array
	int LabelExists(String oldLabel);
	
	// RetrieveItem
	//    - parameters : oldLabel - a string label to retrieve
	//    - return type: a generic type variable that corresponds to the string label entered
	//    - if oldLabel is in the collection, then associated item is returned			   
	Etype RetrieveItem(String oldLabel);
	
	// RemoveItem
	//    - parameters : oldLabel - a string label to remove
	//    - removes a pair of string label and generic type from the object			   
	void RemoveItem(String oldLabel);
	
	// NumPairs
	//    - no parameters
	//    - return type: int variable that represents number of pairs exist in collection
	//    - returns number of pairs that exist in collection	   
	int NumPairs();
	
	
	// LabelAtIndex
	//    - parameters : index - index integer
	//    - return type: string variable that corresponds to the index
	//    - takes in a index number and returns string value that corresponds to the index
	String LabelAtIndex(int index);
	
private:
	String* label;		// string array
	Etype* genType;		// generic type array
	int numLabels;		// size of the collection
	int capacity;		// capacity of the collection
};

#endif

  

labeled.cpp

// *****************************************************
// *                                                   *
// *   labeled.cpp                                     *   
// *                                                   *
// *   Implementation for a LabeledCollection class    * 
// *                                                   *
// *   Written 9/19/2003 by Seunghoon Kim              * 
// *                                                   * 
// *****************************************************

#include <stddef.h>
#include <stdlib.h>
#include <iostream.h>
#include "string.h"
#include "array.h"
#include "asserts.h"
#include "labeled.h"

// LabeledCollection
//    - default constructor
//    - initializes a labeledCollection with a capacity of twon
template<class Etype>
LabeledCollection<Etype>::LabeledCollection()
{
        label = new String[2];
        genType = new Etype[2];
        numLabels = 0;
        capacity = 2;
}

// LabeledCollection
//    - copy constructor
//    - parameters : origCollection - previously declared LabeledCollection object
//    - initializes LabeledCollection to be a copy of origCollection	
template<class Etype>
LabeledCollection<Etype>::LabeledCollection(const LabeledCollection& origCollection)
{
        numLabels = origCollection.numLabels;
        label = new String[numLabels];
	genType = new Etype[numLabels];
	capacity = origCollection.capacity;
        
        for (int i=0; i<numLabels; i++)
        {
        	label[i] = origCollection.label[i];
        	genType[i] = origCollection.genType[i];
        }
}

// ~LabeledCollection
//    - destructor
//    - deletes dynamically allocated memory	
template<class Etype>
LabeledCollection<Etype>::~LabeledCollection()
{
	delete[] label;
	delete[] genType;
	numLabels = 0;
	capacity = 0;
}

// operator=
//    - parameters : origCollection - previously allocated LabeledCollection object
//    - return value : reference to this LabeledCollection object
//    - sets object to be a copy of origCollection
template<class Etype>
const LabeledCollection<Etype>& LabeledCollection<Etype>::operator=(const LabeledCollection<Etype>& origCollection)
{
	if (this != &origCollection)
	{
		delete[] label;
		delete[] genType;
		label = NULL;
		genType = NULL;
		numLabels = origCollection.numLabels;
                capacity = origCollection.capacity;
                label = new String[capacity];
                genType = new Etype[capacity];
                for (int i=0; i<numLabels; i++)
                {
                label[i] = origCollection.label[i];
                genType[i] = origCollection.genType[i];
                }
        }
        return *this;
}

// AddItem
//    - parameters : newItem - value of generic type
//		     newLabel - string label
//    - adds a pair of string label and generic type newItem to the object			   
template<class Etype>
void LabeledCollection<Etype>::AddItem(Etype newItem, String newLabel)
{
	int exist = LabelExists(newLabel);
	if (exist == 1)
		Warn("AddItem: label already in collection!");
	else
	{
		if (numLabels == capacity)
		{
			String* tempLabel;
			tempLabel = new String[numLabels*2];
			Etype* tempGenType; 
			tempGenType = new Etype[numLabels*2];
		
			for (int i=0; i<numLabels; i++)
        	        {
        	                tempLabel[i] = label[i];
        	                tempGenType[i] = genType[i];
        	        }
                	capacity = capacity * 2;
        	        label = tempLabel;
        	        genType = tempGenType;
        	}
        	label[numLabels] = newLabel;
        	genType[numLabels] = newItem;
        	numLabels = numLabels + 1;
        }
}

// RelabelItem
//    - parameters : oldLabel - string label to be replaced
//		     newLabel - a new string label
//    - renames oldLabel to newLabel
template<class Etype>
void LabeledCollection<Etype>::RelabelItem(String oldLabel, String newLabel)
{
	int oldLabelCheck = LabelExists(oldLabel);
	int newLabelCheck = LabelExists(newLabel);
	if (oldLabelCheck == 0)
		Warn("RelabelItem: old label not in collection!");
	else if (newLabelCheck == 1)
		Warn("RelabelItem: new label already in collection!");	
	else
	{
		for(int i=0; i<numLabels; i++)
		{
			if (label[i] == oldLabel)
				label[i] = newLabel;
		}
	}
}

// LabelExists
//    - parameters : oldLabel - a string label to compare
//    - return type: int variable that returns 1 if oldLabel exists, 0 if not.
//    - checks the string array to see whether oldLabel exists in array
template<class Etype>
int LabeledCollection<Etype>::LabelExists(String oldLabel)
{
	int exist = 0;
	for(int i=0; i<numLabels; i++)
	{
		if (label[i] == oldLabel)
			exist = 1;
	}
	return exist;
}

// RetrieveItem
//    - parameters : oldLabel - a string label to retrieve
//    - return type: a generic type variable that corresponds to the string label entered
//    - if oldLabel is in the collection, then associated item is returned			   
template<class Etype>
Etype& LabeledCollection<Etype>::RetrieveItem(String oldLabel)
{
	int index = -1;
	for(int i=0; i<numLabels; i++)
	{
		if (label[i] == oldLabel)
			index = i;	
	}
	if (index > -1)
		return genType[index];
	else if (index == -1)
	{	
		Warn("RetrieveItem: label does not exist in collection!");
		return NULL;
	}	
}

// RemoveItem
//    - parameters : oldLabel - a string label to remove
//    - removes a pair of string label and generic type from the object			   
template<class Etype>
void LabeledCollection<Etype>::RemoveItem(String oldLabel)
{
	int index = -1;
	for(int i=0; i<numLabels; i++)
	{
		if (label[i] == oldLabel)
			index = i;	
	}
	if (index == -1)
		Warn("RemoveItem: label is not in collection!");
	else
	{
		//delete[] label[index];
		//delete[] label[index];
		label[index] = NULL;
		genType[index] = NULL;
		numLabels = numLabels - 1;
		for(int i=index; i<(numLabels); i++)
		{
			label[i] = label[i+1];
			genType[i] = genType[i+1];
			label[i+1] = NULL;
			genType[i] = genType[i+1];
		}
	}
}

// NumPairs
//    - no parameters
//    - return type: int variable that represents number of pairs exist in collection
//    - returns number of pairs that exist in collection	   
template<class Etype>
int LabeledCollection<Etype>::NumPairs()
{
	return numLabels;
}	

// LabelAtIndex
//    - parameters : index - index integer
//    - return type: string variable that corresponds to the index
//    - takes in a index number and returns string value that corresponds to the index
template<class Etype>
String LabeledCollection<Etype>::LabelAtIndex(int index)
{
	String indexedLabel;
	if (index<1 || index>numLabels)
		Warn("LabelAtIndex: index not legal!");
	else
	{
		for(int i=0; i<numLabels; i++)
		{
			if (i == index-1)
				indexedLabel = label[i];
		}	
	}
	return indexedLabel;
}
  

CS225 MP3: Double Linked List

This code handles linked list data structure

doubly-linked-list.h

// ***********************************************************
// *                                                         *
// *  doubly-linked-list.h                                   *
// *                                                         *
// *  Interface for a list class, implemented via            *
// *        doubly-linked memory                             * 
// *                                                         *
// *  Written September 2003 by Seunghoon Kim                *
// *                                                         *
// *********************************************************** 

#ifndef LIST_H
#define LIST_H

#include <stddef.h>
#include <iostream.h>
#include "asserts.h"

template <class Etype>
class List
{
public:

   // InsertBeforeLess
   //    - parameters : newElem - an element of the list's type, 
   //                       to be inserted
   //    - inserts newElem before every position of the list that is less than the parameter value.
   void InsertBeforeLess(const Etype& newElem);
   
   // Interlace
   //    - parameters : paramList - a list object to be interlaced with this list. 
   //    - weaves this list and the parameter list together to get a new list
   void Interlace(const List<Etype>& paramList);

   // PositionSwap
   //    - swaps every pair of positions in the list.
   void PositionSwap();

   // RemoveEvenPositions
   //    - removes every even-positioned value
   void RemoveEvenPositions();

   // List 
   //    - default constructor
   //    - creates an empty list
   List();
 
   // List 
   //    - copy constructor
   //    - parameters : origVal - a previously allocated List object 
   //    - initializes the list to be a copy of origVal 
   List(const List& origVal);


   // ~List
   //    - destructor 
   //    - deallocates all dynamically allocated memory associated 
   //        with the list  
   ~List();


   // operator=
   //    - parameters: origVal - a previously allocated List object
   //    - return value: reference to this List object, after it's 
   //         been assigned to be a copy of the parameter
   //    - sets this list to be a copy of origVal
   const List& operator=(const List& origVal);


   // Clear
   //    - deletes all values from list, resulting in an empty list 
   void Clear(); 



 // *** Singular Update

   // InsertAfter
   //    - parameters : newElem - an element of the list's type, 
   //                       to be inserted
   //    - inserts newElem after current position in list (or as
   //        the only element in the list, if the list is currently
   //        empty), and sets that new element as the current 
   //        position. Code does not check to prevent duplicates. 
   void InsertAfter(const Etype& newElem); 



   // InsertBefore
   //    - parameters : newElem - an element of the list's type, 
   //                       to be inserted
   //    - inserts newElem before current position in list (or as
   //        the only element in the list, if the list is currently
   //        empty), and sets that new element as the current 
   //        position. Code does not check to prevent duplicates. 
   void InsertBefore(const Etype& newElem); 


   // Remove
   //    - removes the element at the current position of the list.
   //       Upon completion of the removal, the current position
   //       will be the next element in the list, or if there is no
   //       next element, then the first position (or no position at
   //       all, if the list is empty). Attempting to remove using a
   //       meaningless current position (which for this class can
   //       only happen when the list is empty) will result in a warning.
   void Remove();


   // Update
   //    - parameters : updateElem - an element of the list's type
   //    - replaces the value at the current position with updateElem 
   //      Attempting to update using a meaningless current position
   //      (which for this class can only happen when the list is empty)
   //      will result in a warning.
   void Update(const Etype& updateElem); 



 // *** Control of Current Position

   // Head
   //    - makes the first position in the list the current position 
   //      Attempting to do this when there is no first position in the 
   //      list (which for this class can only happen when the list is 
   //      empty) will result in a warning.
   void Head();



   // Tail
   //    - makes the last position in the list the current position
   //      Attempting to do this when there is no last position in the 
   //      list (which for this class can only happen when the list is
   //      empty) will result in a warning.
   void Tail();


   // operator++ (postfix version)
   //    - moves the current position one position forward in the list.
   //      Attempting to move forward from a meaningless current position 
   //      (which for this class can only happen when the list is empty)
   //      will result in a warning. Attempting to move forward from the 
   //      last position in the list will result in a warning and the
   //      current position remaining unchanged. 
   List& operator++(int);


   // operator-- (postfix version)
   //    - moves the current position one position backward in the list.
   //      Attempting to move backward from a meaningless current position 
   //      (which for this class can only happen when the list is empty)
   //      will result in a warning. Attempting to move backward from the 
   //      first position in the list will result in a warning and the
   //      current position remaining unchanged. 
   List& operator--(int); 


 // *** Information Access 

   // Retrieve
   //    - returns the element at the current list position
   //      Attempting to retrieve from a meaningless current position
   //      (which for this class can only happen when the list is empty)
   //      will result in an error message and termination of program.
   const Etype& Retrieve() const; 

   
   // Find 
   //    - parameters : queryElem - an element of the list's type, 
   //                       to be searched for
   //    - return value : an integer serving as a boolean
   //    - searches list for queryElem...if found, make that position 
   //         the current position and return 1; otherwise, return 0 
   int Find(const Etype& queryElem);


   // Length
   //    - return value : an integer representing the list's length 
   //    - returns the length of the list 
   int Length() const; 


   // Print
   //    - prints out the list values
   void Print() const;
       


private:

   class ListNode  
   {
   public:

      // ListNode
      //    - constructor
      //    - initializes element to default Etype, and next to NULL
      ListNode()  { next = NULL; prev = NULL; }
  
      
      // ListNode
      //    - constructor
      //    - parameters : value - the value to store in the element field
      //    - initializes node to hold value and NULL
      ListNode(Etype value) { element = value; next = NULL; prev = NULL; } 

 
      Etype element;   // holds element of node
      ListNode* next;  // pointer to the next node in the list
      ListNode* prev;  // pointer to the previous node in the list
   };


   ListNode    *head,        // points to first node of list
               *current,     // points to node at current list position
               *tail;        // points to last node of list

   int size;          // number of nodes in list
};


#endif  

doubly-linked-list.cpp

// ***********************************************************
// *                                                         *
// *  doubly-linked-list.cpp                                 *
// *                                                         *
// *  Implementation for a list class, implemented via       *
// *        doubly-linked memory                             * 
// *                                                         *
// *  Written September 2003 by Seunghoon Kim                *
// *                                                         *
// *********************************************************** 

#include "doubly-linked-list.h"


   // InsertBeforeLess
   //    - parameters : newElem - an element of the list's type, 
   //                       to be inserted
   //    - inserts newElem before every position of the list that is less than the parameter value.
template <class Etype>
void List<Etype>::InsertBeforeLess(const Etype& newElem)
{
  if (size == 0)						//if size is zero, inserts node into list
    {
    	ListNode* tempNode = new ListNode(newElem);
    	current = head = tail = tempNode;
    	size = (size+1);
    }
  else
    {
      current = head;
      int counter = size;
      for(int i=0; i < counter; i++)				//checks every value in the list
	{
	  if (current->element < newElem)			//if value in element if less then parameter value
	    {
	      ListNode* tempNode = new ListNode(newElem);	//create a new node and insert before
	      tempNode->next = current;
	      if (head == current)
	      {
	      	tempNode->prev = NULL;
	      	head = tempNode;
	      }
	      else
	      	current->prev->next = tempNode;
	      current->prev = tempNode;
	      size = (size+1);					//increment size everytime new node created
	    }
	  if (current != tail)
	    current = current->next;
	}
    }
}

   // Interlace
   //    - parameters : paramList - a list object to be interlaced with this list. 
   //    - weaves this list and the parameter list together to get a new list
template <class Etype>
void List<Etype>::Interlace(const List<Etype>& paramList)
{
   if (paramList.size == 0)					//base cases: if the parameter list is empty, nothing changes.
     return;
   else if (size == 0)						// if the original list is empty,
     {								// the parameter list becomes the list.
       current = paramList.current;
       head = paramList.head;
       tail = paramList.tail;
     }
  else
    {      
      ListNode *tempPtr1;					
      ListNode *tempPtr2;
      current = head;
      tempPtr1 = paramList.head;
      tempPtr2 = tempPtr1->next;

      for(int i=0; i < (paramList.size); i++)			// loop runs according to the size of the parameter list
	{	
	  if (current == tail)					// if end of the original list is reached,
	    {							// the rest of the parameter list items
	      current->next = tempPtr1;				// gets after the last item of the original list.
	      tempPtr1->prev = current;
	      tail = paramList.tail;
	      break;
	    }
	  else
	    {
	      tempPtr1->next = current->next;			// interlace takes place
	      tempPtr1->prev = current;
	      current->next->prev = tempPtr1;
	      current->next = tempPtr1;
	      if (tempPtr1 == paramList.tail)
	      	break;
	    }
	  	  
	  current = current->next;
	  current = current->next;
	  tempPtr1 = tempPtr2;
	  if (tempPtr2->next != NULL)				// ends if the last element of parameter list is reached
	    tempPtr2 = tempPtr2->next;
	}
    }
    size = size + paramList.size;				// size of the resulting list is sum of the two.
}


   // PositionSwap
   //    - swaps every pair of positions in the list.
template <class Etype>
void List<Etype>::PositionSwap()
{
  current = head;
  ListNode* tempNode;
  
  if(size < 2)                    //can't swap list of zero and one elements
      return;

int count = (size-(size%2))/2;
  
  for(int i=0; i < count; i++)     //stay in loop as long as current next
    {                              //pointer does not equal NULL
      if(current->prev != NULL)
	  current->prev->next = current->next;  //prev next is changed
      else
	  head = current->next;
      current->next->prev = current->prev;
      current->prev = current->next;          //changing currents pointers
      current->next = current->next->next;
      current->prev->next = current;
      if(current->next == NULL)    //next prev of swapped becomes current
	  tail = current;
      else
      	{
          current->next->prev = current;             //at end of list, current becomes tail
	  current = current->next;    //updates current position
	}
    }
    tail = current;
}

   // RemoveEvenPositions
   //    - removes every even-positioned value
template<class Etype>
void List<Etype>::RemoveEvenPositions()
{

  ListNode* removePtr;

  if (size == 0)
   {
      Warn("Attempt to remove an element from an empty list."); 	//cannot remove from an empty list
      return; 
   }   
  else if (size == 1)
       return;								//cannot remove when list if size 1
  else
    {
      current = head->next;
      int count = ((size-(size%2))/2);
      for(int i=0; i < count ; i++)					//checks every even position
      {
    	removePtr = current;
    	if (current->next == NULL)					//checks for tail case
	{
	  tail = current->prev;
	  current->prev->next = NULL;
	  current = head;
	}
        else
	{
	  current->prev->next = current->next;				//removes the positions by changing pointers
	  current->next->prev = current->prev;
	  current = current->next;
	  current = current->next;
	}
      delete removePtr;							//deletes temp node
      size = size-1;							//decrements size everytime node is removed
      }
    }
}


// **************** Creation/Destruction/Mass Update

// List
//    - default constructor
//    - creates an empty list
template <class Etype>
List<Etype>::List()
{
   head = current = tail = NULL; 
   size=0; 
}



// List
//    - copy constructor
//    - parameters : origVal - a previously allocated List object
//    - initializes the list to be a copy of origVal
template <class Etype>
List<Etype>::List(const List<Etype>& origVal)
{
   ListNode *paramListPtr, *thisListPtr, *newestNode;

   paramListPtr = origVal.head;
   if (paramListPtr == NULL)  // then origList is empty
   {
      current = head = tail = NULL;
      size=0;
   }
   else  
   {
      while (paramListPtr != NULL)
      {
         newestNode = new ListNode(paramListPtr->element);

         if (paramListPtr == origVal.head)
         {
            thisListPtr = newestNode;
            head = thisListPtr;
         }
         else
         {
            thisListPtr->next = newestNode;
            newestNode->prev = thisListPtr;  
            thisListPtr = thisListPtr->next;
         }
         if (paramListPtr == origVal.current)
            current = thisListPtr;
         paramListPtr = paramListPtr->next;
      }
      tail = thisListPtr;
      size = origVal.size;
   }
}



// ~List
//    - destructor
//    - deallocates all dynamically allocated memory associated 
//        with the list
template <class Etype>
List<Etype>::~List()
{
   Clear(); 
}




// operator=
//    - parameters: origVal - a previously allocated List object
//    - return value: reference to this List object, after it's 
//         been assigned to be a copy of the parameter
//    - sets this list to be a copy of origVal
template <class Etype>
const List<Etype>& List<Etype>::operator=(const List<Etype>& origVal)
{
   if (this != &origVal)
   {
      Clear(); 

      ListNode *paramListPtr, *thisListPtr, *newestNode;

      paramListPtr = origVal.head;
      if (paramListPtr == NULL)  // then origList is empty
      {
         current = head = tail = NULL; 
         size=0; 
      }
      else 
      {
         while (paramListPtr != NULL)
         {
            newestNode = new ListNode(paramListPtr->element);

            if (paramListPtr == origVal.head)
            {
               thisListPtr = newestNode;
               head = thisListPtr;
            }
            else
            {
               thisListPtr->next = newestNode;
               newestNode->prev = thisListPtr;
               thisListPtr = thisListPtr->next;
            }
            if (paramListPtr == origVal.current)
               current = thisListPtr;
            paramListPtr = paramListPtr->next;
         }
         tail = thisListPtr;
         size = origVal.size;
      }
   }  

   return *this;
} 



// Clear
//    - deletes all values from list, resulting in an empty list
template <class Etype>
void List<Etype>::Clear()
{

   ListNode* deletionPtr = head;
   current = head;

   while (current != NULL)
   {
      current = current->next;
      delete deletionPtr;
      deletionPtr = current;
   }

   head = current = tail = NULL;
   size = 0;
}



 // ************************ Singular Update



// InsertAfter
//    - parameters : newElem - an element of the list's type, 
//                       to be inserted
//    - inserts newElem after current position in list (or as
//        the only element in the list, if the list is currently
//        empty), and sets that new element as the current 
//        position. Code does not check to prevent duplicates. 
template <class Etype>
void List<Etype>::InsertAfter(const Etype& newElem)
{
   ListNode* tempNode;   // the allocation line repeated twice
                         //  below could go here once instead
    
   if (size == 0)
   {
      tempNode = new ListNode(newElem);
      current = head = tail = tempNode;
   }
   else
   {
      tempNode = new ListNode(newElem);

      tempNode->next = current->next; 
      tempNode->prev = current;
      if (current->next != NULL)
         current->next->prev = tempNode;
      current->next = tempNode; 
      if (tail == current)
         tail = tempNode; 

      current = tempNode;
   }
   size++; 
}




// InsertBefore
//    - parameters : newElem - an element of the list's type, 
//                       to be inserted
//    - inserts newElem before current position in list (or as
//        the only element in the list, if the list is currently
//        empty), and sets that new element as the current 
//        position. Code does not check to prevent duplicates. 
template <class Etype>
void List<Etype>::InsertBefore(const Etype& newElem)
{
   ListNode* tempNode = new ListNode(newElem);

   if (size == 0)
   {
      current = head = tail = tempNode;
   }
   else
   {
      tempNode->next = current;
      tempNode->prev = current->prev;
      if (current->prev != NULL)
         current->prev->next = tempNode;
      current->prev = tempNode;
      if (head == current)
         head = tempNode;

      current = tempNode;
   }
   size++;
}




// Remove
//    - removes the element at the current position of the list.
//       Upon completion of the removal, the current position  
//       will be the next element in the list, or if there is no
//       next element, then the first position (or no position at
//       all, if the list is empty). Attempting to remove using a 
//       meaningless current position (which for this class can 
//       only happen when the list is empty) will result in a warning.
template <class Etype> 
void List<Etype>::Remove()
{
   ListNode* removePtr; 
   
   if (size == 0)
   {
      Warn("Attempt to remove an element from an empty list."); 
      return; 
   }   
   else if (size == 1)
   {
      delete current; 
      head = current = tail = NULL;
   }
   else 
   {
      removePtr = current;

      if (current->prev == NULL)
         head = current->next;
      else
         current->prev->next = current->next;
    
      if (current->next == NULL)
      {
         tail = current->prev;
         current = head;
      }
      else
      {
         current->next->prev = current->prev;
         current = current->next;
      }
     
      delete removePtr;
   }
   size--; 
}





// Update
//    - parameters : updateElem - an element of the list's type
//    - replaces the value at the current position with updateElem
//      Attempting to update using a meaningless current position
//      (which for this class can only happen when the list is empty)
//      will result in a warning.
template <class Etype>
void List<Etype>::Update(const Etype& updateElem)
{  
   if (size > 0)
      current->element = updateElem;
   else
      Warn("Cannot update an element in an empty list."); 
}



 // ********************* Control of Current Position



// Head
//    - makes the first position in the list the current position
//      Attempting to do this when there is no first position in the 
//      list which for this class can only happen when the list is
//      empty) will result in a warning.
template <class Etype>
void List<Etype>::Head()
{
   if (size > 0)
      current = head;
   else
      Warn("Cannot move current to head of an empty list.");
}




// Tail
//    - makes the last position in the list the current position
//      Attempting to do this when there is no last position in the 
//      list (which for this class can only happen when the list is
//      empty) will result in a warning.
template <class Etype>
void List<Etype>::Tail()
{
   if (size > 0)
      current = tail; 
   else
      Warn("Cannot move current to tail of an empty list.");
}





// operator++ (postfix version)
//    - moves the current position one position forward in the list.
//      Attempting to move forward from a meaningless current position
//      (which for this class can only happen when the list is empty)
//      will result in a warning. Attempting to move forward from the
//      last position in the list will result in a warning and the
//      current position remaining unchanged.
template <class Etype>
List<Etype>& List<Etype>::operator++(int)
{
   if (size > 0)   // if there are nodes in the list
      if (current->next != NULL)  // and we are not at the last one
         current = current->next;   // increment the current pointer 
      else
         Warn("Cannot advance current position past end position.");
   else
      Warn("Cannot move to next position of an empty list.");
   return *this; 
}





// operator-- (postfix version)
//    - moves the current position one position backward in the list.
//      Attempting to move backward from a meaningless current position
//      (which for this class can only happen when the list is empty)
//      will result in a warning. Attempting to move backward from the
//      first position in the list will result in a warning and the
//      current position remaining unchanged.
template <class Etype>
List<Etype>& List<Etype>::operator--(int)
{
   if (size > 0)   // if there are nodes in the list
      if (current->prev != NULL)  // and we are not at the first one
         current = current->prev;   // increment the current pointer
      else
         Warn("Cannot decrement current position when at first element.");
   else
      Warn("Cannot move to previous position of an empty list.");
   return *this;
}




 // ******************** Information Access



// Retrieve
//    - returns the element at the current list position
//      Attempting to retrieve from a meaningless current position
//      (which for this class can only happen when the list is empty)
//      will result in an error message and termination of program.
template <class Etype>
const Etype& List<Etype>::Retrieve() const
{
   Assert(size > 0, "Cannot Retrieve an element from an empty list."); 
   return current->element;    
}




// Find
//    - parameters : queryElem - an element of the list's type,
//                       to be searched for
//    - return value : an integer serving as a boolean
//    - searches list for queryElem...if found, make that position 
//         the current position and return 1; otherwise, return 0
template <class Etype>
int List<Etype>::Find(const Etype& queryElem)
{
   ListNode* searchPtr = head;
   int result;

   while ((searchPtr !=NULL) && (searchPtr->element != queryElem))
      searchPtr = searchPtr->next; 
   if (searchPtr == NULL)
      result = 0;
   else
   {
      current = searchPtr; 
      result = 1;
   }
   return result;
}




// Length
//    - return value : an integer representing the list's length
//    - returns the length of the list
template <class Etype>
int List<Etype>::Length() const
{
   return size; 
}



// Print
//    - prints out the list values
template <class Etype>
void List<Etype>::Print() const
{
   ListNode* outPtr = head; 

   if (size==0)
      cout << "< empty list >";  
   else
   { 
      cout << "< "; 
      while (outPtr != NULL)  
      {
         cout << outPtr->element << " ";
         outPtr = outPtr->next; 
      } 
      cout << ">";
   } 
}




CS225 MP4: Vehicle Database

This code handles insert, lookup, print functionalities on the simple database structure of vehicle information

generics.h

// *************************************************************
// *                                                           *
// *   generics.h                                              *
// *                                                           *
// *   Declarations for generic functions and function objects *
// *                                                           *
// *   Written October 2003 by Seunghoon Kim                   *
// *                                                           *  
// *************************************************************

#ifndef GENERICS_H
#define GENERICS_H

#include "string.h"
#include "vehicle.h"
#include "name.h"
#include "date.h"


// print
//    - parameters : first- iterator to the first value in the
//                             relevant range
//                 : last - iterator just past the last value in
//                              the relevant_range
//                 : printer - a function object for formatting
//                               the value_type of the iterator
//    - prints out every element in the range [first, last), 
//       using the Formatter parameter to format the information
template <class Iterator, class Formatter>
void print(Iterator first, Iterator last, Formatter printer);

// findItem
//    - parameters : first - iterator to the first value in the relevant range
//                 : last - iterator just past the last value in the relevant range
//                 : searchObj - Etype object to be compared with the list or vector components
//                 : funcObj - a function object for the operator() function to be exeucted
//    - return type: Iterator to the object that holds the value the user is looking for or NULL value if not
//    - searches through the list or vector elements to find the value the user is looking for
template <class Iterator, class Etype, class SearchCriteria>
Iterator findItem(Iterator first, Iterator last, Etype searchObj, SearchCriteria funcObj);

// findFirstSatisfier
//    - parameters : first - iterator to the first value in the relevant range
//                 : last - iterator just past the last value in the relevant range
//                 : funcObj - a function object for the operator() function to be exeucted
//    - return type: Iterator to the object that satisfies the value the user is for or NULL value if not
//    - searches through the list or vector elements to find the value that satisfies what user is looking for
template <class Iterator, class SearchCriteria>
Iterator findFirstSatisfier(Iterator first, Iterator last, SearchCriteria funcObj);


class LastNameEqual
{
 public:

// operator()
//    - parameters : vehicleParam - pointer to the Vehicle
//                 : nameCompare - a name object
//    - return type: int variable that returns 1 if it found a name equal, else 0
//    - compares the name component of the Vehicle pointer parameter and name parameter
  int operator()(Vehicle* vehicleParam, Name nameCompare);
};

class maintenanceDateEqual
{
 public:

// operator()
//    - parameters : vehicleParam - pointer to the Vehicle
//                 : dateCompare - a date object
//    - return type: int variable that returns 1 if it found a date equal, else 0
//    - compares the date component of the Vehicle pointer parameter and date parameter
  int operator()(Vehicle* vehicleParam, Date dateCompare);
};

class greaterThanLastName
{
 public:
// greaterThanLastName
//    - default constructor
//    - parameters : setName - a name object
//    - initializes a greaterThanName with a name as a mamber variable
  greaterThanLastName(Name setName);

// operator()
//    - parameters : vehicleParam - pointer to the Vehicle
//    - return type: int variable that returns 1 if it found a name greater than the member Name variable, else 0
//    - compares the name component of the Vehicle pointer parameter to the member Name variable
  int operator()(Vehicle* vehicleParam);
 private:
  Name memberName;
};

class greaterThanDate
{
 public:
// greaterThanDate
//    - default constructor
//    - parameters : setDate - a date object
//    - initializes a greaterThanDate with a date as a mamber variable
  greaterThanDate(Date setDate);

// operator()
//    - parameters : vehicleParam - pointer to the Vehicle
//    - return type: int variable that returns 1 if it found a date greater than the member Date variable, else 0
//    - compares the date component of the Vehicle pointer parameter to the member Date variable
  int operator()(Vehicle* vehicleParam);
 private:
  Date memberDate;
};

class printVIDAndOwner
{
 public:
// operator()
//    - parameters : vehicleParam - pointer to the Vehicle
//    - return type: int variable that returns 0 after printing
//    - prints out the VID and owner components of the Vehicle item 
  int operator()(Vehicle* vehicleParam);
};

class printAll
{
 public:
// operator()
//    - parameters : vehicleParam - pointer to the Vehicle
//    - return type: int variable that returns 0 after printing
//    - prints out all the components of the Vehicle item 
  int operator()(Vehicle* vehicleParam);
};

#endif
 

generics.cpp


// *************************************************************
// *                                                           *
// *   generics.cpp                                            *
// *                                                           *
// *   Definitions for generic functions and function objects  *
// *                                                           *
// *   Written October 2003 by Seunghoon Kim                   *
// *                                                           *
// *************************************************************

#include "generics.h"
#include <stdlib.h>
#include <iostream.h>


// print
//    - parameters : first- iterator to the first value in the
//                             relevant range
//                 : last - iterator just past the last value in
//                              the relevant_range
//                 : printer - a function object for formatting
//                               the value_type of the iterator
//    - prints out every element in the range [first, last), 
//       using the Formatter parameter to format the information
template <class Iterator, class Formatter>
void print(Iterator first, Iterator last, Formatter printer)
{
   while (first != last)
   {
      printer(*first);
      first++;
   }
}

// findItem
//    - parameters : first - iterator to the first value in the relevant range
//                 : last - iterator just past the last value in the relevant range
//                 : searchObj - Etype object to be compared with the list or vector components
//                 : funcObj - a function object for the operator() function to be exeucted
//    - return type: Iterator to the object that holds the value the user is looking for or NULL value if not
//    - searches through the list or vector elements to find the value the user is looking for
template <class Iterator, class Etype, class SearchCriteria>
Iterator findItem(Iterator first, Iterator last, Etype searchObj, SearchCriteria funcObj)
{
  list<Vehicle*>::iterator tempItr;
  int temp = 0;
  while(first != last)
    {
      temp = funcObj.operator()(*first, searchObj);
      if (temp == 1)
	break;
      first++;
    }
  if (temp == 1)
    tempItr = first;
  else
    {
    *last = NULL;
    tempItr = last;
    }

  return tempItr;
}

// findFirstSatisfier
//    - parameters : first - iterator to the first value in the relevant range
//                 : last - iterator just past the last value in the relevant range
//                 : funcObj - a function object for the operator() function to be exeucted
//    - return type: Iterator to the object that satisfies the value the user is for or NULL value if not
//    - searches through the list or vector elements to find the value that satisfies what user is looking for
template <class Iterator, class SearchCriteria>
Iterator findFirstSatisfier(Iterator first, Iterator last, SearchCriteria funcObj)
{
  Iterator tempItr;
  int temp = 0;
  while(first != last)
    {
      temp = funcObj.operator()(*first);
      if (temp == 1)
	break;
      first ++;
    }
  if (temp == 1)
    tempItr = first;
  else
    {
      *last = NULL;
    tempItr = last;
    }

  return tempItr;
}


// operator()
//    - parameters : vehicleParam - pointer to the Vehicle
//                 : nameCompare - a name object
//    - return type: int variable that returns 1 if it found a name equal, else 0
//    - compares the name component of the Vehicle pointer parameter and name parameter
int LastNameEqual::operator()(Vehicle* vehicleParam, Name nameCompare)
{
    Vehicle tempVehicle = *vehicleParam;
    Name tempName = tempVehicle.getOwner();
    String compLastName1 = tempName.getLastName();
    String compLastName2 = nameCompare.getLastName();
    if (compLastName1 == compLastName2)
      return 1;
    else
      return 0;
}

// operator()
//    - parameters : vehicleParam - pointer to the Vehicle
//                 : dateCompare - a date object
//    - return type: int variable that returns 1 if it found a date equal, else 0
//    - compares the date component of the Vehicle pointer parameter and date parameter
int maintenanceDateEqual::operator()(Vehicle* vehicleParam, Date dateCompare)
{
  int tempInt = 0;
  Vehicle tempVehicle = *vehicleParam;
  Date tempDate = tempVehicle.getMaintenanceDate();
  if (tempDate.getYear() == dateCompare.getYear())
      {
	if (tempDate.getMonth() == dateCompare.getMonth())
	  {
	    if (tempDate.getDay() == dateCompare.getDay())
	      tempInt = 1;
	  }
      }
  return tempInt;
}

// greaterThanLastName
//    - default constructor
//    - parameters : setName - a name object
//    - initializes a greaterThanName with a name as a mamber variable
greaterThanLastName::greaterThanLastName(Name setName)
    {
      String tempFirst = setName.getFirstName();
      String tempLast = setName.getLastName();
      memberName = Name(tempFirst, tempLast);
    }

// operator()
//    - parameters : vehicleParam - pointer to the Vehicle
//    - return type: int variable that returns 1 if it found a name greater than the member Name variable, else 0
//    - compares the name component of the Vehicle pointer parameter to the member Name variable
int greaterThanLastName::operator()(Vehicle* vehicleParam)
  {
    Vehicle tempVehicle = *vehicleParam;
    Name tempName = tempVehicle.getOwner();
    String compLastName1 = tempName.getLastName();
    String compLastName2 = memberName.getLastName();
    if (compLastName1 > compLastName2)
      return 1;
    else
      return 0;
  }

// operator()
//    - parameters : vehicleParam - pointer to the Vehicle
//    - return type: int variable that returns 0 after printing
//    - prints out all the components of the Vehicle item 
greaterThanDate::greaterThanDate(Date setDate)
  {
    int tempYear = setDate.getYear();
    int tempMonth = setDate.getMonth();
    int tempDay = setDate.getDay();
    memberDate = Date(tempMonth, tempDay, tempYear);
  }

// operator()
//    - parameters : vehicleParam - pointer to the Vehicle
//    - return type: int variable that returns 1 if it found a name greater than the member Name variable, else 0
//    - compares the name component of the Vehicle pointer parameter to the member Name variable
int greaterThanDate::operator()(Vehicle* vehicleParam)
   {
    Vehicle tempVehicle = *vehicleParam;
    int tempInt = 0;
    Date tempDate = tempVehicle.getMaintenanceDate();
    if (memberDate.getYear() > tempDate.getYear())
	tempInt = 1;
    else if(memberDate.getYear() == tempDate.getYear())
      {
        if(memberDate.getMonth() > tempDate.getMonth())
	  tempInt = 1;
	else if(memberDate.getMonth() == tempDate.getMonth())
	  {
	    if(memberDate.getDay() > tempDate.getDay())
	      tempInt = 1;
	  }
      }   
    return tempInt;
   }
   
// operator()
//    - parameters : vehicleParam - pointer to the Vehicle
//    - return type: int variable that returns 1 if it found a date greater than the member Date variable, else 0
//    - compares the date component of the Vehicle pointer parameter to the member Date variable   
int printVIDAndOwner::operator()(Vehicle* vehicleParam)
  {
    Vehicle tempVehicle = *vehicleParam;
    int printVID = tempVehicle.getVID();
    Name tempName = tempVehicle.getOwner();
    String printFirst = tempName.getFirstName();
    String printLast = tempName.getLastName();
    cout << "Vehicle ID: " << printVID << "    Owner Name: " << printLast << ", " << printFirst << endl;
    return 0;
  }

// operator()
//    - parameters : vehicleParam - pointer to the Vehicle
//    - return type: int variable that returns 0 after printing
//    - prints out the VID and owner components of the Vehicle item    
int printAll::operator()(Vehicle* vehicleParam)
  { 
    Vehicle tempVehicle = *vehicleParam;
    int printVID = tempVehicle.getVID();
    Name tempName = tempVehicle.getOwner();
    String printFirst = tempName.getFirstName();
    String printLast = tempName.getLastName();
    Date tempDate1 = tempVehicle.getMaintenanceDate();
    Date tempDate2 = tempVehicle.getPurchaseDate();
    int maintenanceYear = tempDate1.getYear();
    int maintenanceMonth = tempDate1.getMonth();
    int maintenanceDay = tempDate1.getDay();
    int purchaseYear = tempDate1.getYear();
    int purchaseMonth = tempDate1.getMonth();
    int purchaseDay = tempDate1.getDay();

    cout << "Owner: " << printLast << ", " << printFirst << endl;
    cout << "Vehicle ID: " << printVID << endl;
    cout << "Purchase Date: " << purchaseMonth << "/" << purchaseDay << "/" << purchaseYear << endl;
    cout << "Date of Most Recent Maintenance: " << maintenanceMonth << "/" << maintenanceDay << "/" << maintenanceYear << endl;
    cout << endl;
    return 0;
  }

database.cpp



// **********************************************
// *                                            *
// *  database.cpp                              *
// *                                            *
// *  Interface for a vehicle info database     *
// *                                            *
// *  Written October 2003 by Seunghoon Kim     *
// *                                            *
// **********************************************

#include <stdlib.h>
#include <iostream.h>
#include "database.h"

   // Database
   //    - default constructor
   //    - initializes object to default values
Database::Database()
{
  vector<Vehicle*> tempVector;
  list<Vehicle*> tempList1;
  list<Vehicle*> tempList2;
  vehicleCollection = tempVector;
  maintenanceCollection = tempList1;
  ownerLastNameCollection = tempList2;
}
  
   // insertVehicle
   //    - parameters : theAuto - a pointer to a vehicle 
   //    - inserts vehicle into database
void Database::insertVehicle(Vehicle* theAuto)
{
  vector<Vehicle*>::iterator insertAfter = vehicleCollection.end();
  vehicleCollection.insert(insertAfter, theAuto);

  Date autoDate = theAuto->getMaintenanceDate();
  greaterThanDate compDate = greaterThanDate(autoDate);
  list<Vehicle*>::iterator listStart = maintenanceCollection.begin();
  list<Vehicle*>::iterator listEnd = maintenanceCollection.end();
  list<Vehicle*>::iterator insertBefore = findFirstSatisfier(listStart, listEnd, compDate);
  maintenanceCollection.insert(insertBefore, theAuto);

  Name autoName = theAuto->getOwner();
  greaterThanLastName compName = greaterThanLastName(autoName);
  listStart = ownerLastNameCollection.begin();
  listEnd = ownerLastNameCollection.end();
  insertBefore = findFirstSatisfier(listStart, listEnd, compName);
  ownerLastNameCollection.insert(insertBefore, theAuto);

}

   // lastNameLookup
   //    - parameters : theLast - the last name of a vehicle owner
   //    - return value : pointer to either an existing vehicle,
   //                         or NULL
   //    - returns a pointer to the vehicle with the given owner;
   //         if no such vehicle, return NULL
Vehicle* Database::lastNameLookup(Name theLast)
{
  list<Vehicle*>::iterator listStart = ownerLastNameCollection.begin();
  list<Vehicle*>::iterator listEnd = ownerLastNameCollection.end();
  LastNameEqual operFunc;
  list<Vehicle*>::iterator ptr = findItem(listStart, listEnd, theLast, operFunc);
  Vehicle* tempPtr = *ptr;
  return tempPtr;
}

   // maintenanceDateLookup
   //    - parameters : lastServed -- the maintenance data of 
   //                          a vehicle
   //    - return value : pointer to either an existing vehicle,
   //                         or NULL
   //    - returns a pointer to the vehicle with the given maintenance
   //         date; if no such vehicle, return NULL
Vehicle* Database::maintenanceDateLookup(Date lastServed)
{
  list<Vehicle*>::iterator listStart = maintenanceCollection.begin();
  list<Vehicle*>::iterator listEnd = maintenanceCollection.end();
  maintenanceDateEqual operFunc;
  list<Vehicle*>::iterator ptr = findItem(listStart, listEnd, lastServed, operFunc);
  Vehicle* tempPtr = *ptr;
  return tempPtr;
}

   // performMaintenance
   //    - parameters : VID -- the ID of the vehicle to perform
   //                      maintenance on
   //                   recentDate -- the date the maintenance
   //                      is performed 
   //    - finds the vehicle with the given ID and updates its 
   //          maintenance date 
void Database::performMaintenance(int VID, Date recentDate)
{
  int compVID;
  
  vector<Vehicle*>::iterator vectorStart = vehicleCollection.begin();
  vector<Vehicle*>::iterator vectorEnd = vehicleCollection.end();
  while(vectorStart != vectorEnd)
  {
    Vehicle* tempPtr = *vectorStart;
    Vehicle tempVehicle = *tempPtr;
    compVID = tempVehicle.getVID();
    if(compVID == VID)
      tempVehicle.performMaintenance(recentDate);
    vectorStart++;
  }
  
  list<Vehicle*>::iterator listStart = maintenanceCollection.begin();
  list<Vehicle*>::iterator listEnd = maintenanceCollection.end();
  list<Vehicle*>::iterator permanentStart = listStart;
  while(listStart != listEnd)
  {
    Vehicle* tempPtr = *listStart;
    Vehicle tempVehicle = *tempPtr;
    compVID = tempVehicle.getVID();
    if(compVID == VID)
    {
      Name tempOwner = tempVehicle.getOwner();
      Vehicle* newVehiclePtr = new Vehicle(compVID, tempOwner, recentDate);      
      Vehicle newVehicle = *newVehiclePtr;
      *tempPtr = newVehicle;
      
      list<Vehicle*>::iterator tempStart = listStart;
      greaterThanDate compDate = greaterThanDate(recentDate);

      list<Vehicle*>::iterator insertBefore = findFirstSatisfier(permanentStart, listEnd, compDate);
      maintenanceCollection.insert(insertBefore, tempPtr);
      listEnd--;
      listStart = listEnd;
      listEnd++;
      maintenanceCollection.erase(tempStart);
    }
    listStart++;
  }

  listStart = ownerLastNameCollection.begin();
  listEnd = ownerLastNameCollection.end();
  while(listStart != listEnd)
  {
    Vehicle* tempPtr = *listStart;
    Vehicle tempVehicle = *tempPtr;
    compVID = tempVehicle.getVID();
    if(compVID == VID)
      tempVehicle.performMaintenance(recentDate);
    listStart++;
  }
}

   // printMaintenanceNotifications();
   //    - prints out VID/owner info for all vehicles, in order from 
   //        most recently maintained to least-recently maintained 
void Database::printMaintenanceNotifications()
{
  list<Vehicle*>::iterator listStart = maintenanceCollection.begin();
  list<Vehicle*>::iterator listEnd = maintenanceCollection.end();
  printVIDAndOwner tempPrint;
  list<Vehicle*>::iterator tempReturn = findFirstSatisfier(listStart, listEnd, tempPrint);
} 


   // printOwners
   //    - prints out all info of all vehicles, in alphabetical order
   //          by last name of owner
void Database::printOwners()
{
  list<Vehicle*>::iterator listStart = ownerLastNameCollection.begin();
  list<Vehicle*>::iterator listEnd = ownerLastNameCollection.end();
  printAll tempPrint;
  list<Vehicle*>::iterator tempReturn = findFirstSatisfier(listStart, listEnd, tempPrint);
}


   // printCollection
   //    - prints out all info of all vehicles, in order of which
   //        they were added to the database
void Database::printCollection()
{
  vector<Vehicle*>::iterator listStart = vehicleCollection.begin();
  vector<Vehicle*>::iterator listEnd = vehicleCollection.end();
  printAll tempPrint;
  vector<Vehicle*>::iterator tempReturn = findFirstSatisfier(listStart, listEnd, tempPrint);
}

CS225 MP5: Threaded Tree

This code handles threaded tree data structure

threadedTree.h


// *******************************************************
// *                                                     *
// *  threadedTree.h                                     *
// *                                                     *
// *  Interface for a threaded tree, which was designed  *
// *  in the spirit of the C++ STL interfaces and        *
// *  which can (among other things) be used to          *
// *  implement the map class.                           *
// *                                                     *
// *  Written October 2003 by Seunghoon Kim              *  
// *                                                     *
// ******************************************************* 


#ifndef THREADEDTREE_H
#define THREADEDTREE_H

#include <stddef.h>
#include "asserts.h"
#include "strings.h"
#include "utility225.h"



// **************************************************************
// *                                                            *
// *  Class : ThreadedTree                                      *
// *                                                            *
// *  The interface class for the threaded implementation       * 
// *                                                            *
// **************************************************************

template <class Etype>
class ThreadedTree 
{

private:  

   class ThreadedTree_node;  


public:

   // *****************************************
   // *                                       *
   // *  Section 1: typedefs                  *
   // *                                       *
   // *****************************************

   typedef Etype mapped_type;  // type 16, what we map to in this tree
   typedef Etype* pointer;     // pointer to type tree holds
   typedef const Etype* const_pointer;  // like "pointer" but const
   typedef Etype& reference; // a reference var to the type the tree holds
   typedef const Etype& const_reference; // like "reference" but const


   // *****************************************
   // *                                       *
   // *  Section 2: iterator classes          *
   // *    iterator                           *
   // *    const_iterator                     *
   // *    reverse_iterator                   *
   // *    const_reverse_iterator             * 
   // *                                       *
   // *****************************************

   // **************************************************
   // *                                                *
   // *  ThreadedTree<>::iterator                      *
   // *                                                *
   // *  standard iterator for our threaded tree class *
   // *                                                *
   // **************************************************

   class iterator 
   {
   public:
     
      // iterator
      //    - default constructor 
      //    - creates a null iterator 
      iterator() { ptr = NULL; }


      // operator==
      //    - parameters : origVal - another iterator
      //    - return type : boolean integer
      //    - returns 1 if this iterator and the parameter
      //       iterator point to the same location, 0 else.
      int operator==(const iterator& origVal) const
          { return (ptr == origVal.ptr); }


      // operator!=
      //    - parameters : origVal - another iterator
      //    - return type : boolean integer
      //    - returns 1 if this iterator and the parameter
      //       iterator do NOT point to the same location, 0 else.
      int operator!=(const iterator& origVal) const
          { return (ptr != origVal.ptr); }


      // operator*
      //    - return type : reference to a node value
      //    - returns the value pointed to by this iterator
      Etype& operator*() { return (ptr->element); }


      // operator->
      //    - return type : reference to a node value
      //    - returns the address of the value in the node
      //         pointed to by this iterator 
      Etype* operator->()  { return &(ptr->element); } 

   
      // operator++ (prefix)
      //    - return type : an iterator
      //    - moves the iterator to the next value in the
      //        sequence. If you are at the final, "null"
      //        element, an error message is printed instead
      //        since there is no element to move to. 
      iterator& operator++() 
      {   
         // if our iterator points to the header node, meaning
         //   there is no in order successor for this iterator's node,
         //   then either we are at end(), or else we are at
         //   begin() in an empty tree, which is the same as end()
         //   in that tree. In either case, you can't ++ from end(),
         //   so it's error message time. 
         //
         //   Our "header" node is set to have a height of zero,
         //   yet point to the leftmost and rightmost values of the
         //   tree, or itself if the tree is empty. So, the left and
         //   right pointers of the "header" are never NULL. Thus, if
         //   our node has height 0 and yet does not have two NULL pointers
         //   for children, it must be the header node.

        if (ptr->rightFlag == 1)
         {
            ptr = ptr->right;
            while (ptr->leftFlag == 1)
               ptr = ptr->left;
         }
         else   // ptr->right == NULL
			ptr = ptr->right;

         return *this;
      }



      // operator++ (postfix)
      //    - return type : an iterator
      //    - postfix version of operator++, performs ++ on
      //        the iterator, but returns the old value, not the
      //        new one
      iterator operator++(int)
      {
         iterator temp = *this;
         ++(*this);
         return temp;
      }


      // operator-- (prefix)
      //    - return type : an iterator
      //    - moves the iterator to the previous value in the
      //        sequence. If you are at the first 
      //        element, an error message is printed instead
      //        since there is no element to move to. 
      iterator& operator--() 
      { 
        if (ptr->leftFlag == 1)
         {
            ptr = ptr->left;
            while (ptr->rightFlag == 1)
               ptr = ptr->right;
         }
         else   // ptr->left == NULL
			ptr = ptr->left;

         return *this;
      }



      // operator-- (postfix)
      //    - return type : an iterator
      //    - postfix version of operator--, performs -- on 
      //       iterator but returns the old value, not the
      //       new one
      iterator operator--(int) 
      { 
         iterator temp = *this;
         --(*this);
         return temp;
      }



   private:

      // this exists so that ThreadedTree functions can freely get
      //  to the constructor below.
      friend class ThreadedTree<Etype>;

      ThreadedTree_node* ptr; // the pointer to the node type that
                          // the iterator class controls access to

      // iterator
      //    - constructor
      //    - parameters : assignPtr - pointer to store in this
      //                       iterator
      //    - initializes iterator to point to same node as
      //        assignPtr. This function must be private to
      //        protect encapsulation. Right now, clients can
      //        only set iterators to other iterators; if this
      //        function were public, they could set iterators
      //        to any address, thereby breaking the protective
      //        wrapper of encapsulation around the iterator's 
      //        member data (its internal pointer).
      iterator(ThreadedTree_node* assignPtr) { ptr = assignPtr; }

   };





   // *********************************************
   // *                                           *
   // *  Section 3: ThreadedTree public functions *
   // *    constructors, etc.                     *
   // *    iterator functions                     *
   // *    collection-editing functions           *   
   // *    information retrieval functions        *
   // *                                           *
   // *********************************************


  // ****************** constructors, etc. 

 public:

   // ThreadedTree
   //    - default constructor 
   //    - initializes tree to be empty
   ThreadedTree(); 


   // ThreadedTree
   //    - copy constructor
   //    - parameters : origVal - previously allocated ThreadedTree object
   //    - initializes object to be a copy of origVal
   ThreadedTree(const ThreadedTree& origVal); 


   // There is a third constructor that is supposed to exist,
   // which initializes the threaded tree to hold a particular rage
   // of values, but it requires that a member function be a 
   // template and the compiler doesn't quite like that yet. 


   // ~ThreadedTree
   //    - destructor
   //    - deletes dynamically allocated memory
   ~ThreadedTree(); 


   // operator= 
   //    - parameters : origVal - previously allocated ThreadedTree object
   //    - return value - const reference to this object
   //    - sets object to be a copy of origVal
   const ThreadedTree& operator=(const ThreadedTree& origVal);



 // **************** iterator functions


   // begin
   //    - return type : iterator
   //    - returns iterator to first location in container 
   iterator begin();

   // end
   //    - return type: iterator
   //    - returns iterator to "one past the end" container location
   iterator end();

   // find
   //    - parameters : searchElem - element to be found
   //    - return value : boolean integer
   //    - returns 1 if searchElem is found in tree, 0 else
   //        also, if found, points internal pointer to that node 
   int find(const Etype& searchElem)
     {
       return find(searchElem, root);
     }
 
   // insert
   //    - parameters : insElem - value to be inserted
   //    - return value : none
   //    - inserts insElem into tree (does nothing if key is
   //         already there
   void insert(const Etype& insElem)
     {
       insert(insElem, root);
     }

   // remove
   //    - parameters : remElem - element to be removed 
   //    - removes remElem from tree if it is in tree
   void remove(const Etype& remElem)
   {
     remove(remElem, root);
   }

   // preorder
   //    - prints tree in preorder format
   void preorder()
   {
     preorder(root);
   }

   // size
   //    - return value : size of tree
   //    - returns number of elements in tree
   int size() const; 



private:

   // ************** Member data for threaded tree
   // **************
   ThreadedTree_node* root;        // pointer to header node
   ThreadedTree_node* solitaryNode;     // pointer to the solitary node
   int treeSize;                     // number of nodes in tree


 // ************* Binary search tree functions

   // copy
   //    - parameters : TN - a treenode pointer
   //    - return value : a treenode pointer
   //    - makes a new treenode which is a copy of the
   //        parameter node -- including subtrees -- and returns it
   ThreadedTree_node* copy(const ThreadedTree_node* TN);


   // clear
   //    - parameters : TN - reference to a treenode pointer
   //    - recursively clears the tree
   void clear(ThreadedTree_node*& TN);

   
   // preorder
//    - parameters : TN - reference to a tree node pointer
//    - recursively prints tree in preorder format; assumes Etype has
//       has operator<< defined
   void preorder(const ThreadedTree_node* TN);


   // insert
   //    - parameters : insElem - element to be inserted
   //                 : TN - a treenode pointer
   //                 : parentOfTN - the parent of the node *TN 
   //    - return type : an iterator to the newly inserted element
   //    - recursively inserts insElem into tree (does nothing if
   //         it is already there), and corrects balances
   void insert(const Etype& insElem, ThreadedTree_node*& TN);


   // remove
   //    - parameters : remElem - element to be removed
   //                 : TN - a treenode pointer
   //    - recursively removes remElem from tree if it is in tree
   //         and corrects balances
   void remove(const Etype& remElem, ThreadedTree_node*& TN);


   // find
   //    - parameters : searchElem - element to be found
   //                 : TN - a treenode pointer
   //    - return value : treenode pointer
   //    - returns 1 if searchElem is found in tree, 0 else
   //        also, if found, returns pointer to that node
   int find(const Etype& searchElem, ThreadedTree_node* TN);


private:

   // friend declarations to make sure the iterators can
   //  access the ThreadedTreeNode class
   friend class iterator;


   // *********************************************
   // *                                           *
   // *  ThreadedTree<>::ThreadedTree_node        *
   // *                                           *
   // *  The node class for our threaded tree.    * 
   // *                                           *
   // *********************************************
   class ThreadedTree_node
   {
   public:   // public within scope of ThreadedTree implementation.
             //  not within global scope

      friend class iterator;

      // ThreadedTree_node
      //    - default constructor
      //    - initializes node to default values
      ThreadedTree_node() : element(), left(NULL), right(NULL),
                               leftFlag(0), rightFlag(0){}


      // ThreadedTree_node
      //    - constructor
      //    - parameters : elmt - initialization element
      //                 : leftPtr - initialization left pointer
      //                 : rightPtr - initialization right pointer
      //                 : leftFlag - initialization of height
      //                 : rightFlag - 
      //    - initializes node to parameter values
      ThreadedTree_node(Etype elmt, ThreadedTree_node* leftPtr,
			ThreadedTree_node* rightPtr, int lfg, int rfg) :
	element(elmt), left(leftPtr), right(rightPtr), leftFlag(lfg), rightFlag(rfg){}


      Etype element;   // value element of node 
      ThreadedTree_node* left;           // pointer to left subtree
      ThreadedTree_node* right;          // pointer to right subtree
      int leftFlag;                   // flag for left pointer
      int rightFlag;                  // flag for right pointer
   }; 
};

#endif


threadedTree.cpp



// **********************************************************
// *                                                        *
// *  threadedTree.cpp                                      *
// *                                                        *
// *  Implementation for a threaded tree, which was designed*
// *  in the spirit of the C++ STL interfaces and           *
// *  which can (among other things) be used to             *
// *  implement the map class.                              *
// *                                                        *
// *  Written October 2003 by Seunghoon Kim                 *  
// *                                                        *
// **********************************************************

#include <stdlib.h>
#include "threadedTree.h"
#include "asserts.h"
#include <iostream.h>


// ThreadedTree
//    - default constructor
//    - initializes tree to be empty
template <class Etype>
ThreadedTree<Etype>::ThreadedTree()
{
  treeSize = 0;
  root = new ThreadedTree_node();
  solitaryNode = new ThreadedTree_node();
}



// ThreadedTree
//    - copy constructor
//    - parameters : origVal - previously allocated ThreadedTree object
//    - initializes object to be a copy of origVal
template <class Etype>
ThreadedTree<Etype>::ThreadedTree(const ThreadedTree<Etype>& origVal)
{
   
   root = copy(origVal.root);
   treeSize = origVal.treeSize;

   ThreadedTree_node* tempLeft = new ThreadedTree_node();
   ThreadedTree_node* tempRight = new ThreadedTree_node();
   tempLeft = tempRight = root;
   while(tempLeft->leftFlag == 1)
     tempLeft = tempLeft -> left;
   while(tempRight->rightFlag == 1)
     tempRight = tempRight -> right;
   solitaryNode = new ThreadedTree_node(0, tempRight, tempLeft, 0, 0);
   tempLeft->left = solitaryNode;
   tempRight->right = solitaryNode;
   // Then, make root->left point to leftmost in tree
   //    and root->right point to rightmost in tree
}



// ~ThreadedTree
//    - destructor
//    - deletes dynamically allocated memory
template <class Etype>
ThreadedTree<Etype>::~ThreadedTree()
{ 
   clear(root);
   delete root;
}



// operator=
//    - parameters : origVal - previously allocated ThreadedTree object
//    - return value - const reference to this object  
//    - sets object to be a copy of origVal
template <class Etype>
const ThreadedTree<Etype>& ThreadedTree<Etype>::operator=(const ThreadedTree<Etype>& origVal)
{
   if(this != &origVal) 
   {
      clear(root);
      clear(solitaryNode);

      // Then, make root->left point to leftmost in tree
      //    and root->right point to rightmost in tree
   root = copy(origVal.root);
   treeSize = origVal.treeSize;

   ThreadedTree_node* tempLeft = root;
   ThreadedTree_node* tempRight = root;
   while(tempLeft->leftFlag == 1)
     tempLeft = tempLeft -> left;
   while(tempRight->rightFlag == 1)
     tempRight = tempRight -> right;
   solitaryNode = new ThreadedTree_node(0, tempRight, tempLeft, 0, 0);
   tempLeft->left = solitaryNode;
   tempRight->right = solitaryNode;
   }
   return *this;
}


// begin
//    - return type : iterator
//    - returns iterator to first location in container 
template <class Etype>
typename ThreadedTree<Etype>::iterator ThreadedTree<Etype>::begin()
{
  return iterator(solitaryNode -> right);
}


// end
//    - return type: iterator
//    - returns iterator to "just after container" location
template <class Etype>
typename ThreadedTree<Etype>::iterator ThreadedTree<Etype>::end()
{ 
  return iterator(solitaryNode);
}



   // find
   //    - parameters : searchElem - element to be found
   //                   TN - pointer to the treeNode
   //    - return value : boolean integer
   //    - returns 1 if searchElem is found in tree, 0 else
   //        also, if found, points internal pointer to that node 
template <class Etype>
int ThreadedTree<Etype>::find(const Etype& searchElem, ThreadedTree_node* TN)
{
  if (TN->element == searchElem)
    return 1;
  else if ((TN->element < searchElem) && (TN->rightFlag == 1))
    return find(searchElem, TN->right);
  else if ((TN->element > searchElem) && (TN->leftFlag == 1))
    return find(searchElem, TN->left);
  else
    return 0;
}


   // insert
   //    - parameters : insElem - value to be inserted
   //    - return value : none
   //    - inserts insElem into tree (does nothing if key is
   //         already there
template <class Etype>
void ThreadedTree<Etype>::insert(const Etype& insElem, ThreadedTree_node*& TN)
{ 
  ThreadedTree_node *tempNode;		// base case
  if (treeSize == 0)
  {
  	root->element = insElem;
  	root->right = root->left = solitaryNode;
	solitaryNode->left = solitaryNode->right = root;
	root->rightFlag = root->leftFlag = 0;
  	treeSize = 1;
  }
  else if (insElem < TN->element)	// move to the left
    {
      if (TN->leftFlag == 0)
	{
	  tempNode = new ThreadedTree_node(insElem, TN->left, TN, TN->leftFlag, 0);
	  TN->leftFlag = 1;
	  TN->left = tempNode;
	  treeSize++;
	}
      else
	insert(insElem, TN->left);
    }
  else if (insElem > TN->element)	// move to the right
    {
      if (TN->rightFlag == 0)
	{
	  tempNode = new ThreadedTree_node(insElem, TN, TN->right, 0, TN->rightFlag);
	  TN->rightFlag = 1;
	  TN->right = tempNode;
	  treeSize++;
	}
      else
	insert(insElem, TN->right);
    }
  // else insElem = TN->element
     // skip
     
   // update the endpoints
   ThreadedTree_node* tempLeft = root;	
   ThreadedTree_node* tempRight = root;
   while(tempLeft->leftFlag == 1)
     tempLeft = tempLeft -> left;
   while(tempRight->rightFlag == 1)
     tempRight = tempRight -> right;
   solitaryNode->left = tempRight;
   solitaryNode->right = tempLeft;
}

   // remove
   //    - parameters : remElem - element to be removed 
   //    - removes remElem from tree if it is in tree
   template <class Etype>
   void ThreadedTree<Etype>::remove(const Etype& remElem, ThreadedTree_node*& TN) 
{
    ThreadedTree_node *Tmp_Cell;
    
   if ((treeSize == 1)&&(root->element == remElem))	// base case
  {
  	root->element = NULL;
  	root->right = root->left = NULL;
	solitaryNode->left = solitaryNode->right = solitaryNode;
	root->rightFlag = root->leftFlag = 0;
  	treeSize = 0;
  }    

   else if (remElem > TN->element)			// move to the right
   {
   	if (TN->rightFlag == 0)
   	   return;
   	else
	  {
	    Tmp_Cell = TN->right;
	    if(TN->right->element == remElem)
	    {
	      if(Tmp_Cell->leftFlag == 0)
	      {
	      	if(Tmp_Cell->rightFlag == 0)
	      	   TN->rightFlag = 0;
	      	TN->right = Tmp_Cell->right;
	      }
	      else if(Tmp_Cell->rightFlag == 0)
	      	TN->right = Tmp_Cell->left;
	    }
   	   remove(remElem, Tmp_Cell);
	  }
   }
   else	if(remElem < TN->element)			//move to the left
   {
   	if (TN->leftFlag == 0)
   	   return;
   	else // there is a child
	  {
	    Tmp_Cell = TN->left; 
	    if(TN->left->element == remElem)
	    {
	      if(Tmp_Cell->rightFlag == 0)
	      {
	      	if(Tmp_Cell->leftFlag == 0)
	      	   TN->leftFlag = 0;
	      	TN->left = Tmp_Cell->left;
	      }
	      else if(Tmp_Cell->leftFlag == 0)
	      	TN->left = Tmp_Cell->right;
	    }
   	   remove(remElem, Tmp_Cell);
	  }
   }
   else			// Found element to be removed.
   {
      if((TN->leftFlag == 1) && (TN->rightFlag == 1))  // Two children.
      {	
         // Replace with smallest in right subtree.
        Tmp_Cell = TN->right;
        ThreadedTree_node* tempMove = new ThreadedTree_node();
        tempMove = TN->right;
        while(tempMove->leftFlag == 1)
           tempMove = tempMove->left;
        TN->element = tempMove->element;
        if(TN->right->leftFlag == 0)
        {
           if(TN->right->rightFlag == 0)
              TN->rightFlag = 0;
           TN->right = TN->right->right;
        }
	remove(TN->element, Tmp_Cell);
      }
      else	// One child or zero children
      {
      	 ThreadedTree_node* tempMove = new ThreadedTree_node();
         if ((TN->leftFlag == 0)&&(TN->rightFlag == 1))	// Only a right child.
         {
      	    Tmp_Cell = TN;
            tempMove = TN->right;
            while(tempMove->leftFlag == 1)
            	tempMove = tempMove -> left;
            tempMove->left = TN->left;
            TN = TN->right;
            delete Tmp_Cell;
         }
         else if ((TN->rightFlag == 0)&&(TN->leftFlag == 1))	// Only a left child.
         {
            Tmp_Cell = TN;
            tempMove = TN->left;
            while(tempMove->rightFlag == 1)
            	tempMove = tempMove -> right;
            tempMove->right = TN->right;
            TN = TN->left;
            delete Tmp_Cell;
         }
         else  //no children -> do nothing
           delete TN;
         treeSize--;
         // update the endpoints
   	ThreadedTree_node* tempLeft = root;	
   	ThreadedTree_node* tempRight = root;
  	while(tempLeft->leftFlag == 1)
     	  tempLeft = tempLeft -> left;
   	while(tempRight->rightFlag == 1)
   	  tempRight = tempRight -> right;
   	solitaryNode->left = tempRight;
   	solitaryNode->right = tempLeft;
      }
   }
}

// preorder
//    - parameters : TN - reference to a tree node pointer
//    - recursively prints tree in preorder format; assumes Etype has
//       has operator<< defined
template <class Etype>
void ThreadedTree<Etype>::preorder(const ThreadedTree_node* TN) 
{
   cout << TN->element << endl; 
   if (TN->leftFlag == 1)
      preorder(TN->left);
   if (TN->rightFlag == 1)
      preorder(TN->right);
}

// size
//    - return value : size of tree
//    - returns number of elements in tree
template <class Etype>
int ThreadedTree<Etype>::size() const
{
  return treeSize;
}


// copy
//    - parameters : TN - a treenode pointer
//    - return value : a treenode pointer
//    - makes a new treenode which is a copy of the
//        parameter node -- including subtrees -- and returns it
template <class Etype>
typename ThreadedTree<Etype>::ThreadedTree_node* 
ThreadedTree<Etype>::copy(const ThreadedTree_node* TN)
{
    ThreadedTree_node* tempNode;
    ThreadedTree_node* tempMove = new ThreadedTree_node();
    if((TN->leftFlag == 1)&&(TN->rightFlag == 1))			// tree node with two children
    {
        tempNode = new ThreadedTree_node
                  (TN->element, (ThreadedTree_node*) copy(TN->left), 
                        (ThreadedTree_node*) copy(TN->right), TN->leftFlag, TN->rightFlag);
	tempMove = tempNode->left;
	while(tempMove->rightFlag == 1)
	  tempMove = tempMove->right;
	tempMove->right = tempNode;

	tempMove = tempNode->right;
	while(tempMove->leftFlag == 1)
	  tempMove = tempMove->left;
	tempMove->left = tempNode;

    }
    else if((TN->leftFlag == 1)&&(TN->rightFlag == 0))			// tree node with only a left child
    {
    	tempNode = new ThreadedTree_node
    		  (TN->element, (ThreadedTree_node*) copy(TN->left),
    		  	NULL, TN->leftFlag, TN->rightFlag);
	tempMove = tempNode->left;
	while(tempMove->rightFlag == 1)
	  tempMove = tempMove->right;
	tempMove->right = tempNode;
    }
    else if((TN->leftFlag == 0)&&(TN->rightFlag == 1))			// tree node with only a right child
    {
    	tempNode = new ThreadedTree_node
    		  (TN->element, NULL, (ThreadedTree_node*) copy(TN->right),
    		  	TN->leftFlag, TN->rightFlag);

	tempMove = tempNode->right;
	while(tempMove->leftFlag == 1)
	  tempMove = tempMove->left;
	tempMove->left = tempNode;
	
	//if(tempMove->left->element == NULL)
	//  solitaryNode = tempMove->left;
    }
    else								// no children
    {
    	tempNode = new ThreadedTree_node(TN->element, NULL, NULL, 
    			 TN->leftFlag, TN->rightFlag);
    }
    return tempNode;
}



// clear
//    - parameters : TN - reference to a treenode pointer
//    - recursively clears the tree
template <class Etype>
void ThreadedTree<Etype>::clear(ThreadedTree_node*& TN)
{
   if (TN->leftFlag == 1)
      clear(TN->left);
   if (TN->rightFlag == 1)
      clear(TN->right);   
   delete TN;
   TN = NULL;
}


CS225 MP6: InfoGraph

This code handles a simple graph data structure

graph.cpp



// ************************************************************
// *                                                          *
// *  graph.cpp                                               *
// *                                                          *
// *  Implementations for graph-related classes               *
// *                                                          *
// *  Written Nov 1998 by Jason Zych                          *
// *   Updated by Nov 2003 by Seunghoon Kim                   *
// *      - Mass Update and Remove functions repaired         *
// *      - general code cleanup and commenting               *
// *                                                          *
// *  Inspiration for this graph class drawn from             *
// *   the publicly posted interface of the LEDA              *
// *   library: http://www.mpi-sb.mpg.de/LEDA/                *
// *                                                          *
// *  This file consists of five separate classes which       *
// *   are all related:                                       *
// *                                                          *
// *       - VertexNode : internal vertex implementation      *
// *       - Vertex : external "iterator" on VertexNode       *
// *                    objects, client uses Vertex objects   *
// *       - EdgeNode : internal edge implementation          *
// *       - Edge : external "iterator" on EdgeNode           *
// *                    objects, client uses Edge objects     *
// *       - Graph : internally, holds collection of vertices *
// *                   and collection of edges; functions     *
// *                   take Vertex and Edge objects as        *
// *                   parameters and manipulate the internal *
// *                   VertexNode and EdgeNode objects they   *
// *                   refer to.                              *
// *                                                          * 
// ************************************************************

#include <stddef.h>
#include <iostream.h>
#include "graph.h"



// InsertVertexAfter
//    - parameters : position - vertex reference
//    - return value : the new vertex
//    - adds a new vertex to graph after the vertex reference and returns it
Vertex Graph::InsertVertexAfter(Vertex position)
{
   // Step 1 : create new VertexNode for the list of vertices
   //    - assign this node an array key, for use in parameterized
   //        class
   //    - verify edge direction or lack of it in this graph 

   VertexNode* insVert = new VertexNode(); 
   vertexKeyCounter++; 
   insVert->vertexKey = vertexKeyCounter; 
   insVert->isDirected = isDirected; 


   // Step 2 : insert this VertexNode at end of vertex list
 
   if (vHead == NULL)
      vHead = insVert;
   else if (position.VPtr() == NULL)
   {
     insVert->nextVertex = vHead;
     insVert->prevVertex = vHead->prevVertex;
     if (vHead->prevVertex != NULL)
       vHead->prevVertex->nextVertex = insVert;
     vHead->prevVertex = insVert;
   }
   else
   {
      VertexNode* refVert = new VertexNode();
      refVert = position.VPtr();

      insVert->nextVertex = refVert->nextVertex; 
      insVert->prevVertex = refVert; 
      if (refVert->nextVertex != NULL)
        refVert->nextVertex->prevVertex = insVert;
      refVert->nextVertex = insVert; 
   }
   vSize++; 


   // Step 3 : return a Vertex that stores a pointer to the 
   //            new VertexNode

   return Vertex(insVert);  
}



// InsertVertexBefore
//    - parameters : position - vertex reference
//    - return value : the new vertex
//    - adds a new vertex to graph before the vertex reference and returns it
Vertex Graph::InsertVertexBefore(Vertex position)
{
   // Step 1 : create new VertexNode for the list of vertices
   //    - assign this node an array key, for use in parameterized
   //        class
   //    - verify edge direction or lack of it in this graph 

   VertexNode* insVert = new VertexNode(); 
   vertexKeyCounter++; 
   insVert->vertexKey = vertexKeyCounter; 
   insVert->isDirected = isDirected; 

   // Step 2 : insert this VertexNode at end of vertex list 

   if (vHead == NULL)
      vHead = insVert; 
   else if (position.VPtr() == NULL)
   {
     insVert->nextVertex = vHead;
     insVert->prevVertex = vHead->prevVertex;
     if (vHead->prevVertex != NULL)
       vHead->prevVertex->nextVertex = insVert;
     vHead->prevVertex = insVert;
     vHead = insVert;
   }
   else
   {
      VertexNode* refVert = new VertexNode();
      refVert = position.VPtr();

      insVert->prevVertex = refVert->prevVertex; 
      insVert->nextVertex = refVert; 
      if (refVert->prevVertex != NULL)
        refVert->prevVertex->nextVertex = insVert;
      refVert->prevVertex = insVert; 
   }
   vSize++; 


   // Step 3 : return a Vertex that stores a pointer to the 
   //            new VertexNode

   return Vertex(insVert);  
}


// InsertEdgeAfter
//    - parameters : sourceVert - source vertex of new edge
//                 : targetVert - target vertex of new edge
//                 : sourcePosition - source edge reference
//                 : targetPosition - target edge reference
//                 : listPosition - edge list reference
//    - return value : the new edge 
//    - adds a new edge to the graph between the parameter vertices, after the parameter edges
//         returns that edge
Edge Graph::InsertEdgeAfter(Vertex sourceVert, Vertex targetVert, Edge sourcePosition, Edge targetPosition, Edge listPosition)
{
   // extract VertexNode pointers from Vertex parameters 
   VertexNode* srcEndpoint = sourceVert.VPtr(); 
   VertexNode* tarEndpoint = targetVert.VPtr(); 
   EdgeNode* srcEdge = sourcePosition.EPtr();
   EdgeNode* tarEdge = targetPosition.EPtr();

   // Step 1 : create new EdgeNode for the list of edges 
   //    - assign this node an array key, for use in parameterized
   //        class
   //    - verify edge direction or lack of it in this graph

   EdgeNode* insEdge = new EdgeNode(); 
   edgeKeyCounter++; 
   insEdge->edgeKey = edgeKeyCounter; 
   insEdge->isDirected = isDirected; 


   // Step 2 : insert node into edge list

   if (eHead == NULL)
      eHead = insEdge; 
   else
     {
       if (srcEdge == NULL)
	 {
	   insEdge->nextSourceEdge = NULL;
	   insEdge->prevSourceEdge = NULL;
	 }
       else
	 {
	   insEdge->nextSourceEdge = srcEdge->nextSourceEdge; 
	   insEdge->prevSourceEdge = srcEdge; 
	   if (srcEdge->nextSourceEdge != NULL)
	     srcEdge->nextSourceEdge->prevSourceEdge = insEdge; 
	   srcEdge->nextSourceEdge = insEdge; 
	 }
       if (tarEdge == NULL)
	 {
	   insEdge->nextTargetEdge = NULL;
	   insEdge->prevTargetEdge = NULL;
	 }
       else
	 {
	   insEdge->nextTargetEdge = tarEdge->nextTargetEdge; 
	   insEdge->prevTargetEdge = tarEdge; 
	   if (tarEdge->nextTargetEdge != NULL)
	     tarEdge->nextTargetEdge->prevTargetEdge = insEdge; 
	   tarEdge->nextTargetEdge = insEdge; 
	 }
     }   
   eSize++; 


   // Step 3 : insert node into source and target edge lists
   // insertion into edge lists is different depending on 
   //   whether graph is directed or undirected

   insEdge->source = srcEndpoint;
   insEdge->target = tarEndpoint;
   if (isDirected)
      InsertEdgeIntoDirected(insEdge); 
   else
      InsertEdgeIntoUndirected(insEdge);


   // Step 4 : return an Edge that stores a pointer to the
   //            new EdgeNode

   return Edge(insEdge);
}


// InsertEdgeBefore
//    - parameters : sourceVert - source vertex of new edge
//                 : targetVert - target vertex of new edge
//                 : sourcePosition - source edge reference
//                 : targetPosition - target edge reference
//                 : listPosition - edge list reference
//    - return value : the new edge 
//    - adds a new edge to the graph between the parameter vertices, before the parameter edges
//         returns that edge
Edge Graph::InsertEdgeBefore(Vertex sourceVert, Vertex targetVert, Edge sourcePosition, Edge targetPosition, Edge listPosition)
{
   // extract VertexNode pointers from Vertex parameters 
   VertexNode* srcEndpoint = sourceVert.VPtr(); 
   VertexNode* tarEndpoint = targetVert.VPtr(); 
   EdgeNode* srcEdge = sourcePosition.EPtr();
   EdgeNode* tarEdge = targetPosition.EPtr();

   // Step 1 : create new EdgeNode for the list of edges 
   //    - assign this node an array key, for use in parameterized
   //        class
   //    - verify edge direction or lack of it in this graph

   EdgeNode* insEdge = new EdgeNode(); 
   edgeKeyCounter++; 
   insEdge->edgeKey = edgeKeyCounter; 
   insEdge->isDirected = isDirected; 


   // Step 2 : insert node into edge list

   if (eHead == NULL)
      eHead = insEdge; 
   else
     {
       if (srcEdge == NULL)
	 {
	   insEdge->nextSourceEdge = NULL;
	   insEdge->prevSourceEdge = NULL;
	 }
       else
	 {
	   insEdge->prevSourceEdge = srcEdge->prevSourceEdge; 
	   insEdge->nextSourceEdge = srcEdge;
	   if (srcEdge->prevSourceEdge != NULL)	  
	     srcEdge->prevSourceEdge->nextSourceEdge = insEdge; 
	   srcEdge->prevSourceEdge = insEdge; 
	 }
       if (tarEdge == NULL)
	 {
	   insEdge->nextTargetEdge = NULL;
	   insEdge->prevTargetEdge = NULL;
	 }
       else
	 {
	   insEdge->prevTargetEdge = tarEdge->prevTargetEdge; 
	   insEdge->nextTargetEdge = tarEdge; 
           if (tarEdge->prevTargetEdge != NULL)
	     tarEdge->prevTargetEdge->nextTargetEdge = insEdge; 
	   tarEdge->prevTargetEdge = insEdge; 
	 }
     }
   eSize++; 


   // Step 3 : insert node into source and target edge lists
   // insertion into edge lists is different depending on 
   //   whether graph is directed or undirected

   insEdge->source = srcEndpoint;
   insEdge->target = tarEndpoint;
   if (isDirected)
      InsertEdgeIntoDirected(insEdge); 
   else
      InsertEdgeIntoUndirected(insEdge);


   // Step 4 : return an Edge that stores a pointer to the
   //            new EdgeNode

   return Edge(insEdge);
}




// *** END OF YOUR CODE

// **************************************************************
// *                                                            *
// *  Class : VertexNode                                        *
// *                                                            *
// *  A vertex implementation, to be manipulated by a           *
// *     Graph class but hidden from the user of the Graph      *
// *     class. This is the implementation for the class.       *
// *                                                            *
// **************************************************************


// VertexNode
//    - default constructor
//    - initializes object to default values
VertexNode::VertexNode()
{
   vertexKey = vertexMark = 0;          
   isDirected = 1;                      // defaults to directed


   numDepartEdges = numEnterEdges = 0;  // no edges of any kind yet
   departingEdges = NULL;  
   enteringEdges =  NULL;  

   prevVertex = this;    // If this is the only vertex
   nextVertex = this;    //   in the list, then it is also 
			 //   its own successor and predecessor,
			 //   since the list is circular. If it
			 //   is not the only vertex in the list,
			 //   these fields can be altered in the
			 //   vertex insertion algorithms. 
}




// **************************************************************
// *                                                            *
// *  Class : Vertex                                            *
// *                                                            *
// *  A vertex wrapper class. This class will provide access    *
// *     to a VertexNode object, but only from within the       *
// *     actual Graph class itself. The only parts of this      *
// *     interface that are available to the user are the       *
// *     creation and assignment operators. This way, the user  *
// *     can maintain "pointers" to vertices without actually   *
// *     being able to access their fields or needing to know   *
// *     their implementation.                                  *
// *                                                            *
// **************************************************************


// Vertex
//    - default constructor
//    - initializes object to default values
Vertex::Vertex()
{
   vertexNodePtr = NULL; 
}



// operator==
//    - parameters : compareVert - a vertex to which we can compare
//                      this object
//    - return value : boolean integer
//    - returns 1 if the two vertices point to the same node,
//         otherwise returns 0
int Vertex::operator==(const Vertex& compareVert)
{
   return (vertexNodePtr == compareVert.vertexNodePtr);
}



// operator!=
//    - parameters : compareVert - a vertex to which we can compare
//                      this object
//    - return value : boolean integer
//    - returns 0 if the two vertices point to the same node,
//         otherwise returns 1
int Vertex::operator!=(const Vertex& compareVert)
{
   return (vertexNodePtr != compareVert.vertexNodePtr);
}



// Vertex
//    - constructor
//    - parameters : initPtr - a VertexNode pointer used to
//                     initialize this object
//    - a private constructor which initializes the Vertex object
//         given a VertexNode pointer. Essentially, this function
//         "casts" the VertexNode pointer to a Vertex object.
Vertex::Vertex(VertexNode* initVPtr)
{
   vertexNodePtr = initVPtr; 
}



// VPtr
//    - return value : pointer to the internal VertexNode pointer
//    - returns the value held in the internal VertexNode pointer.
//         Used to shorten the syntax needed to access the
//         "vertexNodePtr" field of this object
VertexNode* Vertex::VPtr()
{
   return vertexNodePtr; 
}




// **************************************************************
// *                                                            *
// *  Class : EdgeNode                                          *
// *                                                            *
// *  An edge implementation, to be manipulated by a            *
// *     Graph class but hidden from the user of the Graph      *
// *     class. This is the implementation for the class.       *
// *                                                            *
// *  Written 13 Nov 1998 by Jason Zych                         *
// *                                                            *
// **************************************************************


// EdgeNode
//    - default constructor
//    - initializes object to default values
EdgeNode::EdgeNode()
{
   edgeKey = edgeMark = 0;        
   isDirected = 1;               // defaults to directed  

   
   source = NULL;                // endpoints are unknown at 
   target = NULL;                //    creation time



   // EdgeNode objects are part of three lists:
   //    1) the list of all edges
   //    2) the list of all edges departing from its source vertex
   //    3) the list of all edges entering its target vertex
   // For each list, if this is the only edge in the list, then
   // it is also its own successor and predecessor, since we want
   // the lists to be circular. If it is not the only vertex in 
   // a certain list, then these fields can be altered in the edge
   // insertion algorithms. 

   prevEdge = nextEdge = this;               // list of all edges
   prevSourceEdge = nextSourceEdge = this;   // list of edges from source
   prevTargetEdge = nextTargetEdge = this;   // list of edges to target
} 



// ********************************************************************
// *                                                                  *
// *  Class : Edge                                                    *
// *                                                                  *
// *  An edge wrapper class. This class will provide access           *
// *     to an EdgeNode object, but only from within the              *
// *     actual Graph class itself. The only parts of this            *
// *     interface that are available to the user are the             *
// *     creation and assignment operators. This way, the user        *
// *     can maintain "pointers" to edges without actually            *
// *     being able to access their fields or needing to know         *
// *     their implementation.                                        *
// *                                                                  *
// *  Written 13 Nov 1998 by Jason Zych                               *
// *                                                                  *
// ********************************************************************



// Edge
//    - default constructor
//    - initializes object to default values
Edge::Edge()
{
   edgeNodePtr = NULL; 
}


// operator==
//    - parameters : compareEdge - an edge to which we can compare
//                      this object
//    - return value : boolean integer
//    - returns 1 if the two Edge objects wrap around the same edge, 
//         otherwise returns 0
int Edge::operator==(const Edge& compareEdge)
{
   return (edgeNodePtr == compareEdge.edgeNodePtr);
}



// operator!=
//    - parameters : compareEdge - an edge to which we can compare
//                      this object
//    - return value : boolean integer
//    - returns 0 if the two Edge objects wrap around the same edge 
//         otherwise returns 1
int Edge::operator!=(const Edge& compareEdge)
{
   return (edgeNodePtr != compareEdge.edgeNodePtr);
}



// Edge 
//    - constructor
//    - parameters : initEPtr - an EdgeNode pointer used to 
//                     initialize this object
//    - a private constructor which initializes the Edge object
//         given an EdgeNode pointer. Essentially, this function
//         "casts" the EdgeNode pointer to a Edge object.
Edge::Edge(EdgeNode* initEPtr)
{ 
   edgeNodePtr = initEPtr; 
}



// EPtr
//    - return value : pointer to the internal EdgeNode pointer
//    - returns the value held in the internal EdgeNode pointer.
//         Used to shorten the syntax needed to access the
//         "edgeNodePtr" field of this object
EdgeNode* Edge::EPtr()
{
   return edgeNodePtr; 
}





// *********************************************************************
// *                                                                   *
// *  Class : Graph                                                    *
// *                                                                   *
// *  A class providing a graph representation. The interface          *
// *   functions allow the user to manipulate the graph with           *
// *   full knowledge of and access to the structure of the            *
// *   graph -- that is, knowledge of the existence of                 *
// *   vertices and edges, and which vertices are adjacent to          *
// *   which other vertices via which edges -- but the user            *
// *   does not have access to the actual vertex and edge              *
// *   implementations, but rather only knowledge of the               *
// *   _existence_ of the vertices and edges. Therefore, any           *
// *   manipulation of the graph _must_ be done via the graph          *
// *   functions themselves, and therefore the user is able            *
// *   to view the graph in a very abstract manner.                    *
// *                                                                   *
// *  Written 13 Nov 1998 by Jason Zych                                *
// *                                                                   *
// *********************************************************************


// ********************** Mass Update **********************


// Graph
//    - default constructor
//    - initializes object to default values
Graph::Graph(int isDirectedFlag)
{   
   vHead = NULL;         // circularly-linked list of vertices
   vSize = 0;            //   starts out empty

   eHead = NULL;         // circularly-linked list of edges
   eSize = 0;            //   start out empty

   isDirected = isDirectedFlag;   // defaults to directed

   vertexKeyCounter = 0;
   edgeKeyCounter = 0;
}



// Graph
//    - copy constructor
//    - parameters : origVal - previously allocated Graph object
//    - initializes object to be a copy of origVal
Graph::Graph(const Graph& origVal)
{
   Copy(origVal);   
}
 


// ~Graph
//    - destructor
//    - deletes dynamically allocated memory
Graph::~Graph()
{
   Clear(); 
}



// operator=
//    - parameters : origVal - previously allocated Graph object
//    - return value : reference to this object
//    - sets object to be a copy of origVal
Graph& Graph::operator=(const Graph& origVal)
{
   if (this!=&origVal)
   {
      Clear();
      Copy(origVal);
   }
   return *this; 
}




// Clear 
//    - sets object to be a copy of default (empty) graph. 
//      Graph will remain directed or remain undirected; this
//      function call will not change that.
void Graph::Clear()
{
   // Step 1 : Delete vertex list
   //    - traverse circularly-linked list of VertexNode
   //       objects, deleting them one-by-one 

   VertexNode *frontVPtr, *prevVPtr; 
   frontVPtr = vHead;

   // if there are vertices in the vertex list, set the last
   //   node to point to NULL rather than the first node, 
   //   for ease of loop stopping
   if (frontVPtr!=NULL)
      frontVPtr->prevVertex->nextVertex = NULL; 

   while (frontVPtr != NULL)
   {
      prevVPtr = frontVPtr;
      frontVPtr = frontVPtr->nextVertex; 
      delete prevVPtr; 
   }

 
   // Step 2 : Delete edge list
   //    - traverse circularly-linked list of EdgeNode
   //       objects, deleting them one-by-one

   EdgeNode *frontEPtr, *prevEPtr; 
   frontEPtr = eHead; 

   // if there are edges in the edge list, set the last 
   //   node point to NULL rather than the first node, 
   //   for ease of loop stopping
   if (frontEPtr!=NULL)
      frontEPtr->prevEdge->nextEdge = NULL; 
  
   while (frontEPtr != NULL)
   {
      prevEPtr = frontEPtr; 
      frontEPtr = frontEPtr->nextEdge; 
      delete prevEPtr; 
   }


   // Step 3 : re-initialize the Graph member data, EXCEPT
   //   for the "isDirected" flag. Whatever the user last set
   //   this graph to be -- directed or undirected -- is what
   //   it should still be. 

   vHead = NULL;         // circularly-linked list of vertices
   vSize = 0;            //   is once again empty

   eHead = NULL;         // circularly-linked list of edges
   eSize = 0;            //   is once again empty

   vertexKeyCounter = 0;
   edgeKeyCounter = 0;

}





// ******************* Graph structure alteration *******************

// MakeUndirected
//    - if graph is undirected, function returns without
//       doing anything. If graph is directed, it is converted
//       to an undirected graph. The new graph will be the old
//       graph with direction removed from the edges -- that
//       is, if you previously had an edge from a->b, you now
//       have an a-b edge (i.e. the edge becomes undirected).
void Graph::MakeUndirected()
{
   if (isDirected)
   {
      isDirected = 0;
      int moreVertices;
      VertexNode* vertPtr;
      EdgeNode* tempEdge;
      vertPtr = vHead;    // first vertex of graph
      if (vertPtr == NULL)
         moreVertices = 0;
      else
         moreVertices = 1;
      while (moreVertices)
      {
         if (vertPtr->departingEdges == NULL)
         {
            vertPtr->departingEdges = vertPtr->enteringEdges;
            vertPtr->enteringEdges = NULL;
         }
         else if (vertPtr->enteringEdges != NULL)
         {
            tempEdge = vertPtr->enteringEdges->prevTargetEdge;
            vertPtr->departingEdges->prevSourceEdge->nextSourceEdge =
                vertPtr->enteringEdges;
            vertPtr->enteringEdges->prevTargetEdge->nextTargetEdge =
                vertPtr->departingEdges;
            vertPtr->enteringEdges->prevTargetEdge =
                vertPtr->departingEdges->prevSourceEdge;
            vertPtr->departingEdges->prevSourceEdge = tempEdge;
            vertPtr->numDepartEdges += vertPtr->numEnterEdges;
            vertPtr->enteringEdges = NULL;
            vertPtr->numEnterEdges = 0;
         }

         vertPtr = vertPtr->nextVertex;
         if (vertPtr == vHead)
            moreVertices = 0;
      }

   }
}




// InsertVertex
//    - return value : the new vertex
//    - adds a new vertex to graph and returns it
Vertex Graph::InsertVertex()
{
   // Step 1 : create new VertexNode for the list of vertices
   //    - assign this node an array key, for use in parameterized
   //        class
   //    - verify edge direction or lack of it in this graph 

   VertexNode* insVert = new VertexNode(); 
   vertexKeyCounter++; 
   insVert->vertexKey = vertexKeyCounter; 
   insVert->isDirected = isDirected; 


   // Step 2 : insert this VertexNode at end of vertex list
 
   if (vHead == NULL)
      vHead = insVert; 
   else
   {
      insVert->prevVertex = vHead->prevVertex; 
      insVert->nextVertex = vHead; 
      vHead->prevVertex->nextVertex = insVert;
      vHead->prevVertex = insVert; 
   }
   vSize++; 


   // Step 3 : return a Vertex that stores a pointer to the 
   //            new VertexNode

   return Vertex(insVert);  
}



 
// RemoveVertex
//    - parameters : delVert - vertex to be deleted
//    - deletes parameter vertex from graph
void Graph::RemoveVertex(Vertex delVert)
{
   // extract VertexNode pointer from Vertex
   VertexNode* deleteVertNode = delVert.VPtr();

   EdgeNode *travPtr,   // for traversing down lists of edges 
            *delPtr;    // for deleting edges


   // Step 1 : delete departing edges of delVert 

   travPtr = deleteVertNode->departingEdges; 
   if (travPtr != NULL)   // if the vertex has departing edges 
   {
      // exit loop when our current edge is the last one in
      //   the list, i.e. when the next edge in the circularly
      //   linked list is also the first one
      while (travPtr->nextSourceEdge != deleteVertNode->departingEdges)
      {
         delPtr = travPtr; 
         travPtr = travPtr->nextSourceEdge;
         RemoveEdge(Edge(delPtr));
      }
      RemoveEdge(Edge(travPtr));  // now, take care of that last edge 
   }


   // Step 2 : delete entering edges of delVert

   travPtr = deleteVertNode->enteringEdges;
   if (travPtr != NULL)
   {
      // exit loop when our current edge is the last one in 
      //   the list, i.e. when the next edge in the circularly
      //   linked list is also the first one 
      while (travPtr->nextTargetEdge != deleteVertNode->enteringEdges)
      {
         delPtr = travPtr; 
         travPtr = travPtr->nextTargetEdge;
         RemoveEdge(Edge(delPtr));
      }
      RemoveEdge(Edge(travPtr));  // now, take care of that last edge
   }


   // Step 3 : remove the vertex itself from the graph
    
   // if the vertex points to itself, it is the only vertex in 
   //    the vertex list
   if (deleteVertNode == deleteVertNode->nextVertex)   
      vHead = NULL;    // no more vertices left in list 
   else   // else there is more than vertex in the vertex list
   {
      deleteVertNode->nextVertex->prevVertex = deleteVertNode->prevVertex; 
      deleteVertNode->prevVertex->nextVertex = deleteVertNode->nextVertex; 

      // if the first vertex in the list is being deleted, point the
      //   list pointer (vHead) to the next vertex instead
      if (vHead == deleteVertNode)            
         vHead = deleteVertNode->nextVertex; 
   }                               

   delete deleteVertNode; 
   vSize--;  
}




// InsertEdge
//    - parameters : sourceVert - source vertex of new edge
//                 : targetVert - target vertex of new edge
//    - return value : the new edge 
//    - adds a new edge to the graph between the parameter vertices, 
//         returns that edge
Edge Graph::InsertEdge(Vertex sourceVert, Vertex targetVert)
{
   // extract VertexNode pointers from Vertex parameters 
   VertexNode* srcEndpoint = sourceVert.VPtr(); 
   VertexNode* tarEndpoint = targetVert.VPtr(); 

   // Step 1 : create new EdgeNode for the list of edges 
   //    - assign this node an array key, for use in parameterized
   //        class
   //    - verify edge direction or lack of it in this graph

   EdgeNode* insEdge = new EdgeNode(); 
   edgeKeyCounter++; 
   insEdge->edgeKey = edgeKeyCounter; 
   insEdge->isDirected = isDirected; 


   // Step 2 : insert node into edge list

   if (eHead == NULL)
      eHead = insEdge; 
   else
   {
      insEdge->prevEdge = eHead->prevEdge; 
      insEdge->nextEdge = eHead; 
      eHead->prevEdge->nextEdge = insEdge; 
      eHead->prevEdge = insEdge; 
   }
   eSize++; 


   // Step 3 : insert node into source and target edge lists
   // insertion into edge lists is different depending on 
   //   whether graph is directed or undirected

   insEdge->source = srcEndpoint;
   insEdge->target = tarEndpoint;
   if (isDirected)
      InsertEdgeIntoDirected(insEdge); 
   else
      InsertEdgeIntoUndirected(insEdge);


   // Step 4 : return an Edge that stores a pointer to the
   //            new EdgeNode

   return Edge(insEdge);
}



// RemoveEdge
//    - parameters : delEdge - edge to be deleted
//    - deletes parameter edge
void Graph::RemoveEdge(Edge delEdge)
{
   // Extract EdgeNode pointer from edge
   EdgeNode* deleteEdgeNode = delEdge.edgeNodePtr;


   // Step 1 : Disconnect deleteEdgeNode from the two lists
   //              of vertex's edges that it is a part of 

   if (isDirected)
      RemoveEdgeFromDirected(deleteEdgeNode);
   else
      RemoveEdgeFromUndirected(deleteEdgeNode);



   // Step 2: Remove deleteEdgeNode from list of all edges 
    
   if (eSize == 1)
      eHead = NULL;
   else  // else there is more than one edge in the edge list
   {
      deleteEdgeNode->nextEdge->prevEdge = deleteEdgeNode->prevEdge;
      deleteEdgeNode->prevEdge->nextEdge = deleteEdgeNode->nextEdge;
    
      // if the first edge in the list is being deleted, point the
      //   list pointer (eHead) to the next edge instead
      if (eHead == deleteEdgeNode)
         eHead = deleteEdgeNode->nextEdge;
   }

   delete deleteEdgeNode;
   eSize--;
}



// ReverseEdge
//    - parameters : revEdge - edge to reverse
//    - reverse revEdge (i.e. makes its former source endpoint
//       its target endpoint and vice-versa)
void Graph::ReverseEdge(Edge revEdge)
{
   // Extract EdgeNode pointer from edge
   EdgeNode* edgeToReverse = revEdge.edgeNodePtr;

   VertexNode* tempVert;
   EdgeNode* tempEdge;

   if (isDirected)
   {
      // if this is the last departing edge, then there are now none
      if (edgeToReverse->source->numDepartEdges == 1)
         edgeToReverse->source->departingEdges = NULL;
      // otherwise, if this is the first of many departing edges,
      //   the next one is now first
      else if (edgeToReverse->source->departingEdges == edgeToReverse)
         edgeToReverse->source->departingEdges =
                                edgeToReverse->nextSourceEdge;
      // otherwise, nothing special about this edge as far as its
      //   source vertex is concerned

      // extract from doubly, circularly linked departing edge list
      //    of source
      edgeToReverse->prevSourceEdge->nextSourceEdge =
                                edgeToReverse->nextSourceEdge;
      edgeToReverse->nextSourceEdge->prevSourceEdge =
                                edgeToReverse->prevSourceEdge;
      (edgeToReverse->source->numDepartEdges)--;



      // if this is the last entering edge, then there are now none
      if (edgeToReverse->target->numEnterEdges == 1)
         edgeToReverse->target->enteringEdges = NULL;
      // otherwise, if this is the first of many entering edges,
      //   the next one is now first
      if (edgeToReverse->target->enteringEdges == edgeToReverse)
         edgeToReverse->target->enteringEdges =
                                edgeToReverse->nextTargetEdge;
      // otherwise, nothing special about this edge as far as its
      //   target vertex is concerned

      // extract from doubly, circularly linked entering edge list
      //    of target
      edgeToReverse->prevTargetEdge->nextTargetEdge =
                                edgeToReverse->nextTargetEdge;
      edgeToReverse->nextTargetEdge->prevTargetEdge =
                                edgeToReverse->prevTargetEdge;
      (edgeToReverse->target->numEnterEdges)--;

   

      // reverse source and target
      tempVert = edgeToReverse->source;
      edgeToReverse->source = edgeToReverse->target;
      edgeToReverse->target = tempVert;


      // insert into departing edge list of new source
      if (edgeToReverse->source->departingEdges == NULL)
      {
         edgeToReverse->source->departingEdges = edgeToReverse;
         edgeToReverse->nextSourceEdge = edgeToReverse;
         edgeToReverse->prevSourceEdge = edgeToReverse;
      }
      else
      {
         edgeToReverse->prevSourceEdge =
                edgeToReverse->source->departingEdges->prevSourceEdge;
         edgeToReverse->nextSourceEdge =
                edgeToReverse->source->departingEdges;
         edgeToReverse->source->departingEdges->prevSourceEdge->nextSourceEdge =
                edgeToReverse;
         edgeToReverse->source->departingEdges->prevSourceEdge = edgeToReverse;
      }
      (edgeToReverse->source->numDepartEdges)++;


      // insert into entering edge list of new target
      if (edgeToReverse->target->enteringEdges == NULL)
      {
         edgeToReverse->target->enteringEdges = edgeToReverse;
         edgeToReverse->nextTargetEdge = edgeToReverse;
         edgeToReverse->prevTargetEdge = edgeToReverse;
      }
      else
      {
         edgeToReverse->prevTargetEdge =
                edgeToReverse->target->enteringEdges->prevTargetEdge;
         edgeToReverse->nextTargetEdge =
                edgeToReverse->target->enteringEdges;
         edgeToReverse->target->enteringEdges->prevTargetEdge->nextTargetEdge =
                edgeToReverse;
         edgeToReverse->target->enteringEdges->prevTargetEdge = edgeToReverse;
      }
      (edgeToReverse->target->numEnterEdges)++;
   }
}






// ******************* Graph structure information ******************


//      ---------- Graph information

// NumGraphVertices
//    - return value : integer quantity
//    - returns the number of vertices in the graph
int Graph::NumGraphVertices()
{
   return vSize; 
}


// NumGraphEdges
//    - return value : integer quantity
//    - returns the number of edges in the graph
int Graph::NumGraphEdges()
{ 
   return eSize; 
}



//      ---------- Vertex information

// NumDepartEdges
//    - parameters : queryVert - vertex which we want information about
//    - return value : integer quantity
//    - returns the number of edges departing from Vertex queryVert
int Graph::NumDepartEdges(Vertex queryVert)
{
   return queryVert.VPtr()->numDepartEdges; 
}



// NumEnterEdges
//    - parameters : queryVert - vertex which we want information about
//    - return value : integer quantity
//    - returns the number of edges entering Vertex queryVert
int Graph::NumEnterEdges(Vertex queryVert)
{
   return queryVert.VPtr()->numEnterEdges;
}



// NumTotalEdges
//    - parameters : queryVert - vertex which we want information about
//    - return value : integer quantity
//    - returns the number of edges departing or entering Vertex queryVert
int Graph::NumTotalEdges(Vertex queryVert)
{
   return (queryVert.VPtr()->numEnterEdges + 
	  queryVert.VPtr()->numDepartEdges); 
}




//      ---------- Edge information

// Source
//    - parameters : queryEdge - edge which we want information about
//    - return value : a vertex of the graph
//    - returns source vertex of this edge (i.e. the vertex it departs)
Vertex Graph::Source(Edge queryEdge)
{
   return Vertex(queryEdge.EPtr()->source); 
}


// Target
//    - parameters : queryEdge - edge which we want information about
//    - return value : a vertex of the graph
//    - returns target vertex of this edge (i.e. the vertex it enters)
Vertex Graph::Target(Edge queryEdge)
{
   return Vertex(queryEdge.EPtr()->target); 
}


// OtherEndpoint
//    - parameters : queryEdge - edge which we want information about
//                 : endpointOne - one of the two endpoints of the edge
//    - return value : a vertex of the graph
//    - if endpointOne is the source vertex of this edge, the target 
//        vertex of this edge will be returned. If endpointOne is 
//        instead the target vertex of this edge, the source vertex 
//        will be returned. If endpointOne is not an endpoint of this
//        edge, the nil vertex will be returned
Vertex Graph::OtherEndpoint(Edge queryEdge, Vertex endpointOne)
{
   if (queryEdge.EPtr()->source == endpointOne.VPtr())
      return Vertex(queryEdge.EPtr()->target); 
   else if (queryEdge.EPtr()->target == endpointOne.VPtr())
      return Vertex(queryEdge.EPtr()->source); 
   else 
      return Vertex(); 
}





// ********************** Graph traversal *******************


//      ---------- Vertex traversal 

// FirstVertex
//    - return type : a vertex of the graph
//    - returns the "first" vertex in the abstract set of
//        vertices of the graph. If graph is empty, returns
//        the nil vertex.
Vertex Graph::FirstVertex()
{
   if (vHead == NULL)
      return Vertex(); 
   else
      return Vertex(vHead); 
}



// LastVertex
//    - return type : a vertex of the graph
//    - returns the "last" vertex in the abstract set of
//        vertices of the graph. If graph is empty, returns
//        the nil vertex.
Vertex Graph::LastVertex()
{
   if (vHead == NULL)
      return Vertex(); 
   else
      return Vertex(vHead->prevVertex); 
}



// NextVertex
//    - parameters : currentVert - a vertex of the graph
//    - return type : a vertex of the graph
//    - returns the vertex "after" currentVert in the abstract set 
//        of vertices of the graph. If currentVert is the last vertex 
//        in the vertex set, returns the nil vertex.
Vertex Graph::NextVertex(Vertex currentVert)
{
   if (currentVert.VPtr()->nextVertex == vHead)
      return Vertex(); 
   else
      return Vertex(currentVert.VPtr()->nextVertex); 
}



// PrevVertex
//    - parameters : currentVert - a vertex of the graph
//    - return type : a vertex of the graph
//    - returns the vertex "before" currentVert in the abstract set 
//        of vertices of the graph. If currentVert is the first 
//        vertex in the vertex set, returns the  nil vertex.
Vertex Graph::PrevVertex(Vertex currentVert)
{
   if (currentVert.VPtr() == vHead)
      return Vertex(); 
   else
      return Vertex(currentVert.VPtr()->prevVertex); 
}




//      ---------- Edge traversal 

// FirstEdge
//    - return type : an edge of the graph
//    - returns the "first" edge in the abstract set of
//        edges of the graph. If graph has no edges, returns
//        the nil edge.
Edge Graph::FirstEdge()
{
   if (eHead == NULL)
      return Edge(); 
   else
      return Edge(eHead); 
}


// LastEdge
//    - return type : an edge of the graph
//    - returns the "last" edge in the abstract set of
//        edges of the graph. If graph has no edges, returns
//        the nil edge.
Edge Graph::LastEdge()
{
   if (eHead == NULL)
      return Edge(); 
   else
      return Edge(eHead->prevEdge); 
}


// NextEdge
//    - parameters : currentEdge - an edge of the graph
//    - return type : an edge of the graph
//    - returns the edge "after" currentEdge in the abstract
//        set of edges of the graph. If currentEdge is the last
//        edge in the edge set, returns the nil edge
Edge Graph::NextEdge(Edge currentEdge)
{
   if (currentEdge.EPtr()->nextEdge == eHead) 
      return Edge(); 
   else
      return Edge(currentEdge.EPtr()->nextEdge);  
}


// PrevEdge
//    - parameters : currentEdge - an edge of the graph
//    - return type : an edge of the graph
//    - returns the edge "before" currentEdge in the abstract 
//        set of edges of the graph. If currentEdge is the first 
//        edge in the edge set, returns the nil edge
Edge Graph::PrevEdge(Edge currentEdge)
{
   if (currentEdge.EPtr() == eHead)
      return Edge(); 
   else
      return Edge(currentEdge.EPtr()->prevEdge);  
}



//      ---------- Vertex departing edge traversal
//                     --- meant for directed graphs

// FirstDepartEdge
//    - parameters : departFromVert - vertex we are inspecting
//    - return value : an edge of the graph
//    - returns the "first" edge in the abstract set
//        of all edges departing from the vertex departFromVert. 
//        If departFromVert has no departing edges, returns
//        the nil edge.
Edge Graph::FirstDepartEdge(Vertex departFromVert)
{
   if (departFromVert.VPtr()->departingEdges == NULL)
      return Edge(); 
   else
      return Edge(departFromVert.VPtr()->departingEdges); 
}


// LastDepartEdge
//    - parameters : departFromVert - vertex we are inspecting
//    - return value : an edge of the graph
//    - returns the "last" edge in the abstract set
//        of all edges departing from the vertex departFromVert. 
//        If departFromVert has no departing edges, returns
//        the nil edge.
Edge Graph::LastDepartEdge(Vertex departFromVert)
{
   if (departFromVert.VPtr()->departingEdges == NULL)
      return Edge(); 
   else 
      return Edge(departFromVert.VPtr()->departingEdges->prevSourceEdge); 
}



// NextDepartEdge
//    - parameters : currentEdge - an edge of the graph
//    - return value : an edge of the graph
//    - returns the edge "after" currentEdge in the abstract
//        set of all edges which depart from the same source 
//        vertex as currentEdge. (The source vertex can be found
//        from the edge, which is why we don't need to pass in
//        the source vertex as a parameter.) If this is the last
//        edge in the set described above, returns the nil edge. 
Edge Graph::NextDepartEdge(Edge currentEdge)
{
   if (currentEdge.EPtr()->nextSourceEdge == 
		currentEdge.EPtr()->source->departingEdges)
      return Edge(); 
   else
      return Edge(currentEdge.EPtr()->nextSourceEdge);  
}



// PrevDepartEdge
//    - parameters : currentEdge - an edge of the graph
//    - return value : an edge of the graph
//    - returns the edge "before" currentEdge in the abstract
//        set of all edges which depart from the same source 
//        vertex as currentEdge. (The source vertex can be found
//        from the edge, which is why we don't need to pass in
//        the source vertex as a parameter.) If this is the first 
//        edge in the set described above, returns the nil edge. 
Edge Graph::PrevDepartEdge(Edge currentEdge)
{
   if (currentEdge.EPtr() == currentEdge.EPtr()->source->departingEdges)
      return Edge(); 
   else
      return Edge(currentEdge.EPtr()->prevSourceEdge);  
}



//      ---------- Vertex entering edge traversal
//                     --- meant for directed graphs

// FirstEnterEdge
//    - parameters : enterIntoVert - vertex we are inspecting
//    - return value : an edge of the graph
//    - returns the "first" edge in the abstract set
//        of all edges entering the vertex enterIntoVert. 
//        If enterIntoVert has no entering edges, returns
//        the nil edge.
Edge Graph::FirstEnterEdge(Vertex enterIntoVert)
{
   if ((enterIntoVert.VPtr()->enteringEdges == NULL) || (!isDirected))
      return Edge(); 
   else
      return Edge(enterIntoVert.VPtr()->enteringEdges); 
}


// LastEnterEdge
//    - parameters : enterIntoVert - vertex we are inspecting
//    - return value : an edge of the graph
//    - returns the "last" edge in the abstract set
//        of all edges entering the vertex enterIntoVert. 
//        If enterIntoVert has no entering edges, returns
//        the nil edge.
Edge Graph::LastEnterEdge(Vertex enterIntoVert)
{
   if ((enterIntoVert.VPtr()->enteringEdges == NULL) || (!isDirected))
      return Edge(); 
   else 
      return Edge(enterIntoVert.VPtr()->enteringEdges->prevTargetEdge); 
}


// NextEnterEdge
//    - parameters : currentEdge - an edge of the graph
//    - return value : an edge of the graph
//    - returns the edge "after" currentEdge in the abstract
//        set of all edges which enter same target 
//        vertex as currentEdge. (The target vertex can be found
//        from the edge, which is why we don't need to pass in
//        the target vertex as a parameter.) If this is the last
//        edge in the set described above, returns the nil edge.
Edge Graph::NextEnterEdge(Edge currentEdge)
{
   if ((currentEdge.EPtr()->nextTargetEdge == 
		currentEdge.EPtr()->target->enteringEdges) || (!isDirected))
      return Edge(); 
   else
      return Edge(currentEdge.EPtr()->nextTargetEdge); 
}



// PrevEnterEdge
//    - parameters : currentEdge - an edge of the graph
//    - return value : an edge of the graph
//    - returns the edge "before" currentEdge in the abstract
//        set of all edges which enter the same target 
//        vertex as currentEdge. (The target vertex can be found
//        from the edge, which is why we don't need to pass in
//        the target vertex as a parameter.) If this is the first 
//        edge in the set described above, returns the nil edge. 
Edge Graph::PrevEnterEdge(Edge currentEdge)
{
   if ((currentEdge.EPtr() == 
              currentEdge.EPtr()->target->enteringEdges) || (!isDirected))
      return Edge(); 
   else 
      return Edge(currentEdge.EPtr()->prevTargetEdge); 
}



//      ---------- Vertex adjacent edge traversal 
//                      --- meant for undirected graphs

// FirstAdjacentEdge
//    - parameters : endpointVert - vertex we are inspecting
//    - return value : an edge of the graph
//    - returns the "first" edge in the abstract set
//        of all edges which have endpointVert as an endpoint 
//        If endpointVert is not an endpoint of any edge, returns
//        the nil edge.
Edge Graph::FirstAdjacentEdge(Vertex endpointVert)
{
   if (endpointVert.VPtr()->departingEdges == NULL)
      return Edge(); 
   else
      return Edge(endpointVert.VPtr()->departingEdges); 
}




// LastAdjacentEdge
//    - parameters : endpointVert - vertex we are inspecting
//    - return value : an edge of the graph
//    - returns the "last" edge in the abstract set
//        of all edges which have endpointVert as an endpoint 
//        If endpointVert is not an endpoint of any edge, returns
//        the nil edge.
Edge Graph::LastAdjacentEdge(Vertex endpointVert)
{
   VertexNode* vert1 = endpointVert.VPtr(); 
   if (vert1->departingEdges == NULL)
      return Edge(); 
   else if (vert1->departingEdges->source == vert1)
      return Edge(vert1->departingEdges->prevSourceEdge); 
   else   // vert1->departingEdges->target == vert1
      return Edge(vert1->departingEdges->prevTargetEdge); 
}
      


// NextAdjacentEdge
//    - parameters : currentEdge - an edge in the graph
//                 : endpointVert - an endpoint of currentEdge 
//    - return value : an edge of the graph
//    - returns the edge "after" currentEdge in the abstract 
//        set of all edges that have the vertex endpointVert 
//        as an endpoint. If this is the last edge in the set 
//        described above, returns the nil edge.
Edge Graph::NextAdjacentEdge(Edge currentEdge, Vertex endpointVert)
{
   VertexNode* vert1 = endpointVert.VPtr(); 
   EdgeNode* edge1 = currentEdge.EPtr(); 
   EdgeNode* possibleNextEdge; 
   
   if (edge1->source == vert1)
      possibleNextEdge = edge1->nextSourceEdge; 
   else if (edge1->target == vert1)
      possibleNextEdge = edge1->nextTargetEdge; 
   else // vertex not endpoint of edge
   {
      cout << "ERROR!!!! " << endl; 
      return Edge(); 
   }

   if (possibleNextEdge == vert1->departingEdges)
      return Edge(); 
   else
      return Edge(possibleNextEdge); 
}


// PrevAdjacentEdge
//    - parameters : currentEdge - an edge in the graph
//                 : endpointVert - an endpoint of currentEdge 
//    - return value : an edge of the graph
//    - returns the edge "before" currentEdge in the abstract 
//        set of all edges that have the vertex endpointVert 
//        as an endpoint. If this is the first edge in the set 
//        described above, returns the nil edge.
Edge Graph::PrevAdjacentEdge(Edge currentEdge, Vertex endpointVert)
{
   VertexNode* vert1 = endpointVert.VPtr(); 
   EdgeNode* edge1 = currentEdge.EPtr(); 
   EdgeNode* possiblePrevEdge; 
   
   if (edge1->source == vert1)
      possiblePrevEdge = edge1->prevSourceEdge; 
   else if (edge1->target == vert1)
      possiblePrevEdge = edge1->prevTargetEdge; 
   else // vertex not endpoint of edge
   {
      cout << "ERROR!!!! " << endl; 
      return Edge(); 
   }

   if (edge1 == vert1->departingEdges)
      return Edge(); 
   else
      return Edge(possiblePrevEdge); 
}


// *************** Mark processing *********************


//      ---------- Vertex marks

// GetVertexMark
//    - parameters : markVert - vertex with mark to read 
//    - return value : integer flag
//    - returns the mark value of the vertex markVert
int Graph::GetVertexMark(Vertex markVert)
{
   return (markVert.VPtr()->vertexMark);
}



// SetVertexMark
//    - parameters : markVert - vertex to be marked 
//                 : markToAssign - mark to assign to vertex
//    - sets the mark of vertex markVert to be equal to markToAssign
void Graph::SetVertexMark(Vertex markVert, int markToAssign)
{
   markVert.VPtr()->vertexMark = markToAssign; 
}


// ClearVertexMarks
//    - sets all vertex mark fields to 0
void Graph::ClearVertexMarks()
{
   VertexNode* nodePtr = vHead;
   if (nodePtr != NULL)   // if we have some vertices
   {
      while (nodePtr->nextVertex != vHead)
      {
         nodePtr->vertexMark = 0;
         nodePtr = nodePtr->nextVertex;
      }
      nodePtr->vertexMark = 0;
   }
}



//      ---------- Edge Marks

// GetEdgeMark
//    - parameters : markEdge - edge with mark to read
//    - return value : integer flag
//    - returns the mark value of the edge markEdge
int Graph::GetEdgeMark(Edge markEdge)
{
   return (markEdge.EPtr()->edgeMark);
}



// SetEdgeMark
//    - parameters : markEdge - edge to be marked
//                 : markToAssign - mark to assign to edge
//    - sets the mark of edge markEdge to be equal to markToAssign
void Graph::SetEdgeMark(Edge markEdge, int markToAssign)
{
   markEdge.EPtr()->edgeMark = markToAssign; 
}



// ClearEdgeMarks
//    - sets all edge mark fields to 0
void Graph::ClearEdgeMarks()
{
   EdgeNode* nodePtr = eHead;
   if (nodePtr != NULL)   // if we have some edges 
   {
      while (nodePtr->nextEdge != eHead)
      {
         nodePtr->edgeMark = 0;
         nodePtr = nodePtr->nextEdge;
      }
      nodePtr->edgeMark = 0;
   }
}



// ****************** Queries ***********************

// IsEmpty
//    - return value : boolean integer
//    - returns 1 if the graph has no vertices or edges, and
int Graph::IsEmpty()
{
   return ((vHead == NULL) && (eHead == NULL));
}



// IsDirected
//    - return value : boolean integer
//    - returns 1 if the graph is directed, and 0 otherwis
int Graph::IsDirected()
{
   return isDirected;
}



// IsUndirected
//    - return value : boolean integer
//    - returns 1 if the graph is undirected, and 0 otherwise
int Graph::IsUndirected()
{
   return !isDirected; 
}



// IsNil
//    - parameters : queryVert
//    - return value : boolean integer
//    - returns 1 if queryVert is the nil vertex, and 0 otherwise
int Graph::IsNil(Vertex queryVert)
{
   return (queryVert.VPtr() == NULL);
}



// IsNil
//    - parameters : queryEdge
//    - return value : boolean integer
//    - returns 1 if queryEdge is the nil Edge, and 0 otherwise
int Graph::IsNil(Edge queryEdge)
{
   return (queryEdge.EPtr() == NULL); 
}




// **************** Protected Functions ***********************



// VertexKey
//    - parameters : infoVertex - the vertex whose key we want
//    - return value : integer which is a vertex key
//    - returns the vertex-to-information map key stored inside
int Graph::VertexKey(Vertex infoVertex)
{
   return infoVertex.VPtr()->vertexKey;
}


// EdgeKey
//    - parameters : infoEdge - the edge whose key we want
//    - return value : integer which is an edge key
//    - returns the edge-to-information map key stored inside
//        the edge
int Graph::EdgeKey(Edge infoEdge)
{
   return infoEdge.EPtr()->edgeKey;
}



// ****************** Copying helper functions ******************


// Copy
//    - parameters : origVal - previously allocated Graph object
//    - sets this object to be a copy of origVal; helper function
//         for the copy constructor and assignment operator
void Graph::Copy(const Graph& origVal)
{
   // arrays to map index keys to pointers to the VertexNode
   //   and EdgeNode objects in the new graph. This will make  
   //   setting the pointer fields of those new graph nodes much
   //   easier.  
   Array<VertexNode*> vArray(1, origVal.vertexKeyCounter);
 
   int i;
   for (i = 1; i<=origVal.vertexKeyCounter; i++)
      vArray[i] = NULL; 
   Array<EdgeNode*> eArray(1, origVal.edgeKeyCounter);
   for (i = 1; i<=origVal.edgeKeyCounter; i++)
      eArray[i] = NULL; 

   // copy the vertex list 
   CopyVertexNodes(origVal, vArray); 
   // copy the edge list
   CopyEdgeNodes(origVal, eArray);

   // correctly set the departing/entering edge list pointers in 
   //    the new graph's vertices 
   CopyVertexConnections(origVal, eArray); 
   // correctly set the source/target vertex pointers and the 
   //   source/target edge list pointers in the new graph's edges 
   CopyEdgeConnections(origVal, vArray, eArray); 
   
   isDirected = origVal.isDirected;
}


// CopyVertexNodes
//    - parameters : origVal - previously allocated Graph object
//                 : vArray - array mapping vertex keys to 
//                       VertexNode pointers
//    - correctly creates a copy of the VertexNode list of origVal  
//         and stores it as the VertexNode list of this object.
//         The pointers to EdgeNodes are not set here, but the rest
//         of the VertexNode fields and all other Graph fields that
//         are VertexNode-related will be correctly set (i.e. size
//         and "maximum key value so far").
void Graph::CopyVertexNodes(const Graph& origVal, 
				Array<VertexNode*>& vArray)
{
   int stillVerticesToCopy = 1; 

   vSize = origVal.vSize; 
   if (vSize == 0)
      vHead = NULL; 
   else
   {
      vHead = new VertexNode(*(origVal.vHead)); 
      vArray[vHead->vertexKey] = vHead; 
      
      VertexNode *oldTrav = origVal.vHead; 
      VertexNode *newTrav = vHead; 
      if (oldTrav->nextVertex == origVal.vHead)
         stillVerticesToCopy = 0; 
      while (stillVerticesToCopy)
      {
         oldTrav = oldTrav->nextVertex; 
         newTrav->nextVertex = new VertexNode(*oldTrav); 
         newTrav->nextVertex->prevVertex = newTrav; 
         newTrav = newTrav->nextVertex; 
         newTrav->nextVertex = vHead; 
         vHead->prevVertex = newTrav;
         
         vArray[newTrav->vertexKey] = newTrav; 
         if (oldTrav->nextVertex == origVal.vHead)
            stillVerticesToCopy = 0; 
      }
      vertexKeyCounter = origVal.vertexKeyCounter;
   }
}


// CopyEdgeNodes
//    - parameters : origVal - previously allocated Graph object
//                 : eArray - array mapping edge keys to EdgeNode 
//                       pointers
//    - correctly creates a copy of the EdgeNode list of origVal  
//         and stores it as the EdgeNode list of this object.
//         The only pointers set here are the ones to the previous
//         and next EdgeNode in the main edge list. In addition, all 
//         other Graph fields that are EdgeNode-related will also be 
//         correctly set (i.e. size and "maximum key value so far").
void Graph::CopyEdgeNodes(const Graph& origVal, 
                                Array<EdgeNode*>& eArray)
{
   int stillEdgesToCopy = 1; 

   eSize = origVal.eSize; 
   if (eSize == 0)
      eHead = NULL; 
   else
   {
      eHead = new EdgeNode(*(origVal.eHead)); 
      eArray[eHead->edgeKey] = eHead; 
      
      EdgeNode *oldTrav = origVal.eHead; 
      EdgeNode *newTrav = eHead; 
      if (oldTrav->nextEdge == origVal.eHead)
         stillEdgesToCopy = 0; 
      while (stillEdgesToCopy)
      {
         oldTrav = oldTrav->nextEdge; 
         newTrav->nextEdge = new EdgeNode(*oldTrav); 
         newTrav->nextEdge->prevEdge = newTrav; 
         newTrav = newTrav->nextEdge; 
         newTrav->nextEdge = eHead; 
         eHead->prevEdge = newTrav;
         
         eArray[newTrav->edgeKey] = newTrav; 
         if (oldTrav->nextEdge == origVal.eHead)
            stillEdgesToCopy = 0; 
      }
      edgeKeyCounter = origVal.edgeKeyCounter;
   }
}


// CopyVertexConnections
//    - parameters : origVal - previously allocated Graph object
//                 : eArray - array mapping edge keys to EdgeNode
//                       pointers
//    - correctly reconstructs in this object (the new Graph) the 
//         connections between the VertexNode objects and the EdgeNode 
//         objects which are the heads of the entering and departing
//         edge lists of those VertexNode objects. The object origVal
//         (the old Graph) is used as a guide to do this, and the
//         array eArray is used to quickly obtain a desired EdgeNode, 
//         given its key 
void Graph::CopyVertexConnections(const Graph& origVal, 
			            const Array<EdgeNode*>& eArray)
{
   int stillVerticesToSet = 1; 
   VertexNode *oldTrav = origVal.vHead;
   VertexNode *newTrav = vHead; 
   if (newTrav == NULL)
      stillVerticesToSet = 0; 
   while (stillVerticesToSet)
   {
      if (oldTrav->departingEdges == NULL)
         newTrav->departingEdges = NULL; 
      else
         newTrav->departingEdges = eArray[oldTrav->departingEdges->edgeKey]; 
      if (oldTrav->enteringEdges == NULL)
         newTrav->enteringEdges = NULL; 
      else
         newTrav->enteringEdges = eArray[oldTrav->enteringEdges->edgeKey];
      newTrav = newTrav->nextVertex; 
      oldTrav = oldTrav->nextVertex; 
      if (newTrav==vHead)
         stillVerticesToSet = 0; 
   }
}



// CopyEdgeConnections
//    - parameters : origVal - previously allocated Graph object
//                 : vArray - array mapping vertex keys to 
//                       VertexNode pointers 
//                 : eArray - array mapping edge keys to edge
//                       pointers
//    - correctly reconstructs in this object (the new Graph) the 
//         connections between the EdgeNode objects and 
//            1) the VertexNode objects which are its source and target
//            2) the EdgeNode objects which are its neighbors in the
//                 departing edge list of some VertexNode and the entering 
//                 edge list of some VertexNodes
//         The object origVal (the old Graph) is used as a guide to do 
//         this, and the arrays vArray and eArray are used to quickly 
//         obtain a desired VertexNode or EdgeNode, given its key
void Graph::CopyEdgeConnections(const Graph& origVal, 
			const Array<VertexNode*>& vArray, 
			const Array<EdgeNode*>& eArray)
{
   int stillEdgesToSet = 1; 
   EdgeNode *oldTrav = origVal.eHead; 
   EdgeNode *newTrav = eHead;
   if (newTrav == NULL)
      stillEdgesToSet = 0; 
   while (stillEdgesToSet)
   {
      newTrav->source = vArray[oldTrav->source->vertexKey];
      newTrav->target = vArray[oldTrav->target->vertexKey];
      newTrav->prevSourceEdge = eArray[oldTrav->prevSourceEdge->edgeKey];
      newTrav->nextSourceEdge = eArray[oldTrav->nextSourceEdge->edgeKey];
      newTrav->prevTargetEdge = eArray[oldTrav->prevTargetEdge->edgeKey];
      newTrav->nextTargetEdge = eArray[oldTrav->nextTargetEdge->edgeKey];
   
      newTrav = newTrav->nextEdge;
      oldTrav = oldTrav->nextEdge;

      if (newTrav == eHead)
         stillEdgesToSet = 0;  
   }
}



// ************** Vertex addition helper functions ***************


// InsertEdgeIntoDirected
//    - parameters : insEdge - pointer to EdgeNode being inserted  
//                               into graph
//    - inserts insEdge into the departing edge list of its 
//         source vertex, and into the entering edge list of 
//         its target vertex 
void Graph::InsertEdgeIntoDirected(EdgeNode* insEdge)
{
   VertexNode* source = insEdge->source;
   VertexNode* target = insEdge->target;


   // Step 1 : Insert insEdge into source's departing edges list

   // if there are no entering edges, new edge is the only edge
   if (source->departingEdges == NULL)
      source->departingEdges = insEdge;
   else  // else insert new edge into doubly and circularly linked list
   {
      insEdge->prevSourceEdge = source->departingEdges->prevSourceEdge;
      insEdge->nextSourceEdge = source->departingEdges;
      source->departingEdges->prevSourceEdge->nextSourceEdge = insEdge;
      source->departingEdges->prevSourceEdge = insEdge;
   }
   (source->numDepartEdges)++;



   // Step 2 : Insert insEdge into target's entering edges list

   // if there are no entering edges, new edge is the only edge
   if (target->enteringEdges == NULL)
      target->enteringEdges = insEdge;
   else  // else insert new edge into doubly and circularly linked list 
   {
      insEdge->prevTargetEdge = target->enteringEdges->prevTargetEdge;
      insEdge->nextTargetEdge = target->enteringEdges;
      target->enteringEdges->prevTargetEdge->nextTargetEdge = insEdge;
      target->enteringEdges->prevTargetEdge = insEdge;
   }
   (target->numEnterEdges)++;
}




// InsertEdgeIntoUndirected
//    - parameters : insEdge - pointer to EdgeNode being inserted 
//                                into graph
//    - inserts insEdge into the edge lists of both of its endpoints 
void Graph::InsertEdgeIntoUndirected(EdgeNode* insEdge)
{
   // In an undirected graph, all the edges are listed in a vertex's
   //  "departing edges" list and no edges are listed in a vertex's
   //  "entering edges" list; however, the edge nodes themselves still
   //  point to two endpoints, so one is named "source" and one is named
   //  "target", though from the abstract point of view, the edge's two
   //  endpoints are just "endpoint1" and "endpoint2"
   VertexNode* endpoint1 = insEdge->source;
   VertexNode* endpoint2 = insEdge->target;


   // Step 1 : insert insEdge into endpoint1's departing edges list

   // if there are no adjacent edges, new edge is the only edge 
   if (endpoint1->departingEdges == NULL)
      endpoint1->departingEdges = insEdge;
   else  // else insert into doubly and circularly linked list
   {
      // endpoint1 is the "source" vertex for this edge, simply because
      // it happened to be listed first in the "InsertEdge" function
      // call. But, conceptually, there *is* no "source vertex", there is
      // just an "endpoint1" --  because this is an undirected edge.

      // **** Pointer Assignment #1
      insEdge->nextSourceEdge = endpoint1->departingEdges;

      // Since this graph is undirected, all of a vertex's edges are
      // on its "departing" edges list. Therefore, all the edges which 
      // had that given vertex as its "first" endpoint, AND all the edges 
      // which had that given vertex as its "second" endpoint, are ALL on 
      // that vertex's departing edge list. This means that some edges on a 
      // vertex's departing edge list (again, only for undirected graphs) 
      // point to that vertex with their "source" pointers, and other edges 
      // on that vertex's departing edge list point to that vertex with 
      // their "target" pointers.

      // If the first node in the current list sees endpoint1 as its
      // "first" or "source" endpoint, then it will be connected to the 
      // last vertex in the list with its source list pointers and so it 
      // is those source list pointers we must read and assign to.
      if (endpoint1->departingEdges->source == endpoint1)
      {
         // **** Pointer Assignments #2 and #3 -- possibility 1
         insEdge->prevSourceEdge = endpoint1->departingEdges->prevSourceEdge;
         endpoint1->departingEdges->prevSourceEdge = insEdge;
      }
      // Otherwise, the first node in the current list sees endpoint1
      //  as its "second" or "target" endpoint and it will be connected
      //  to its list neighbors via its target list pointers
      else    // then endpoint1->departingEdges->target == endpoint1 
      {
         // **** Pointer Assignments #2 and #3 - possibility 2
         insEdge->prevSourceEdge = endpoint1->departingEdges->prevTargetEdge;
         endpoint1->departingEdges->prevTargetEdge = insEdge;
      }

      // Likewise, we don't know whether the *last* edge in endpoint1's
      //  edge list thinks of endpoint1 as its "source" or "target" 
      //  endpoint 
      if (insEdge->prevSourceEdge->source == endpoint1 )
         // **** Pointer Assignment #4 - possibility 1
         insEdge->prevSourceEdge->nextSourceEdge = insEdge;
      else    // insEdge->prevSourceEdge->target == endpoint1
         // **** Pointer Assignment #4 - possibility 2
         insEdge->prevSourceEdge->nextTargetEdge = insEdge;
   }
   (endpoint1->numDepartEdges)++;


   // Step 2 : insert insEdge into endpoint2's departing edges list

   // if there are no adjacent edges, then new edge is the only one 
   if (endpoint2->departingEdges == NULL)
      endpoint2->departingEdges = insEdge;
   else // insert into doubly and circularly linked list
   {

      // **** Pointer Assignment #1
      insEdge->nextTargetEdge = endpoint2->departingEdges;


      // If the first node in the current list sees endpoint2 as its
      // "first" or "source" endpoint, then it will be connected to the
      // last vertex in the list with its source list pointers and so it
      // is those source list pointers we must read and assign to.
      if (endpoint2->departingEdges->source == endpoint2)
      {
         // **** Pointer Assignments #2 and #3 -- possibility 1
         insEdge->prevTargetEdge = endpoint2->departingEdges->prevSourceEdge;
         endpoint2->departingEdges->prevSourceEdge = insEdge;
      }
      // Otherwise, the first node in the current list sees endpoint2
      //  as its "second" or "target" endpoint and it will be connected
      //  to its list neighbors via its target list pointers
      else      // then endpoint2->departingEdges->target == endpoint2
      {
         // **** Pointer Assignments #2 and #3 - possibility 2
         insEdge->prevTargetEdge = endpoint2->departingEdges->prevTargetEdge;
         endpoint2->departingEdges->prevTargetEdge = insEdge;
      }

      // Likewise, we don't know whether the *last* edge in endpoint2's
      //  edge list thinks of endpoint2 as its "source" or "target"
      //  endpoint
      if (insEdge->prevTargetEdge->source == endpoint2)
         // **** Pointer Assignment #4 - possibility 1
         insEdge->prevTargetEdge->nextSourceEdge = insEdge;
      else    // insEdge->prevSourceEdge->target == endpoint2
         // **** Pointer Assignment #4 - possibility 2
         insEdge->prevTargetEdge->nextTargetEdge = insEdge;
   }
   (endpoint2->numDepartEdges)++;
}




// RemoveEdgeFromDirected
//    - parameters : deleteEdgeNode - pointer to edge node that
//                      is to be deleted
//    - extracts deleteEdgeNode from the list of edges departing 
//         from its source vertex, and also from the list of edges
//         entering its target vertex
void Graph::RemoveEdgeFromDirected(EdgeNode* deleteEdgeNode)
{
   // Step 1: Remove deleteEdgeNode from source's departing edges list

   // if this is the last edge left in the list of its source vertex 
   if (deleteEdgeNode == deleteEdgeNode->nextSourceEdge)
      deleteEdgeNode->source->departingEdges = NULL;
   else  // else there is more than one vertex in this edge list
   {
      deleteEdgeNode->nextSourceEdge->prevSourceEdge = 
			         deleteEdgeNode->prevSourceEdge;
      deleteEdgeNode->prevSourceEdge->nextSourceEdge = 
                                 deleteEdgeNode->nextSourceEdge;
  
      // if the source vertex's "departing edges" pointer points
      //   to this edge, point it to the next edge instead
      if (deleteEdgeNode->source->departingEdges == deleteEdgeNode)
         deleteEdgeNode->source->departingEdges = 
                                        deleteEdgeNode->nextSourceEdge;
   }
   (deleteEdgeNode->source->numDepartEdges)--; 


   // Step 2: Remove deleteEdgeNode from target's entering edges list

   // if this is the last edge left in the list of its target vertex
   if (deleteEdgeNode == deleteEdgeNode->nextTargetEdge)
      deleteEdgeNode->target->enteringEdges = NULL;
   else  // else there is more than one vertex in this edge list
   {
      deleteEdgeNode->nextTargetEdge->prevTargetEdge = 
				     deleteEdgeNode->prevTargetEdge;
      deleteEdgeNode->prevTargetEdge->nextTargetEdge = 
				     deleteEdgeNode->nextTargetEdge;
  
      // if the target vertex's "entering edges" pointer points
      //   to this edge, point it to the next edge instead 
      if (deleteEdgeNode->target->enteringEdges == deleteEdgeNode)
         deleteEdgeNode->target->enteringEdges = 
                                      deleteEdgeNode->nextTargetEdge;
   }
   (deleteEdgeNode->target->numEnterEdges)--;
}




// RemoveEdgeFromUndirected
//    - parameters : deleteEdgeNode - pointer to edge node that
//                      is to be deleted
//    - extracts deleteEdgeNode from the edge list of deleteEdgeNode's
//         first endpoint, and also extracts it from the edge list of 
//         its second endpoint
void Graph::RemoveEdgeFromUndirected(EdgeNode* deleteEdgeNode)
{
   // In an undirected graph, the "source" and "target" vertices
   //   are really just "endpoint1" and "endpoint2" since the edge
   //   has no direction
   VertexNode* endpoint1 = deleteEdgeNode->source;
   VertexNode* endpoint2 = deleteEdgeNode->target;


   // Step 1: Remove deleteEdgeNode from endpoint1's edge list

   // if this is the last edge left in the list of endpoint1 
   if (deleteEdgeNode == deleteEdgeNode->nextSourceEdge)
      endpoint1->departingEdges = NULL;
   else  // else there is more than one vertex in this edge list
   {
      // the edge after this one in endpoint1's edge list might see 
      //    endpoint1 as its "source" OR as its "target" 
      if (deleteEdgeNode->nextSourceEdge->source == endpoint1)
         deleteEdgeNode->nextSourceEdge->prevSourceEdge = 
                                 deleteEdgeNode->prevSourceEdge;
      else  // deleteEdgeNode->nextSourceEdge->target == endpoint1
         deleteEdgeNode->nextSourceEdge->prevTargetEdge = 
				 deleteEdgeNode->prevSourceEdge;

      // the edge before this one in endpoint1's edge list might see 
      //    endpoint1 as its "source" OR as its "target" 
      if (deleteEdgeNode->prevSourceEdge->source == endpoint1)
         deleteEdgeNode->prevSourceEdge->nextSourceEdge = 
                                 deleteEdgeNode->nextSourceEdge;
      else   // deleteEdgeNode->prevSourceEdge->target == endpoint1
         deleteEdgeNode->prevSourceEdge->nextTargetEdge = 
				 deleteEdgeNode->nextSourceEdge; 
 
 
      // if endpoint1's "departing edges" pointer points
      //   to this edge, point it to the next edge instead
      if (endpoint1->departingEdges == deleteEdgeNode)
         endpoint1->departingEdges = deleteEdgeNode->nextSourceEdge;
   }
   (endpoint1->numDepartEdges)--; 


   // Step 2: Remove deleteEdgeNode from endpoint2's edge list 

   // if this is the last edge left in the list of its target vertex
   if (deleteEdgeNode == deleteEdgeNode->nextTargetEdge)
      deleteEdgeNode->target->enteringEdges = NULL;
   else  // else there is more than one vertex in this edge list
   {
      // the edge after this one in endpoint2's edge list might see 
      //    endpoint2 as its "source" OR as its "target" 
      if (deleteEdgeNode->nextTargetEdge->source == endpoint2)
         deleteEdgeNode->nextTargetEdge->prevSourceEdge =
                                 deleteEdgeNode->prevTargetEdge;
      else  // deleteEdgeNode->nextTargetEdge->target == endpoint2
         deleteEdgeNode->nextTargetEdge->prevTargetEdge = 
                                 deleteEdgeNode->prevTargetEdge;

      // the edge before this one in endpoint2's edge list might see 
      //    endpoint2 as its "source" OR as its "target" 
      if (deleteEdgeNode->prevTargetEdge->source == endpoint2)
         deleteEdgeNode->prevTargetEdge->nextSourceEdge =
                                 deleteEdgeNode->nextTargetEdge;
      else   // deleteEdgeNode->prevTargetEdge->target == endpoint2
         deleteEdgeNode->prevTargetEdge->nextTargetEdge =   
                                 deleteEdgeNode->nextTargetEdge;


      // if endpoint2's "departing edges" pointer points
      //   to this edge, point it to the next edge instead 
      if (endpoint2->enteringEdges == deleteEdgeNode)
         endpoint2->enteringEdges = deleteEdgeNode->nextTargetEdge;
   }
   (endpoint2->numEnterEdges)--;
}



infograph.cpp

// ****************************************************
// *                                                  *
// *  infograph.cpp                                   *
// *                                                  *
// *  Implementation for a parameterized graph class  *
// *                                                  *
// *  Written 11 Nov 2003 by Seunghoon Kim            *
// *                                                  *
// *  Inspiration for this graph class drawn from     *
// *   the publicly posted interface of the LEDA      *
// *   library: http://www.mpi-sb.mpg.de/LEDA/        *
// *                                                  *
// *  Directed flag added to constructor              *
// *    3 August 1999 by Jason Zych                   *
// ****************************************************

#include "infograph.h"


// InsertVertexAfter
//    - parameters : position - vertex reference
//		     info - information record for the new vertex
//    - return value : the new vertex
//    - adds a new vertex to graph after the vertex reference and returns it
template <class Vtype, class Etype>
Vertex InfoGraph<Vtype, Etype>::InsertVertexAfter(Vertex position, Vtype info)
{
   Vertex newVert = Graph::InsertVertexAfter(position); 
   vertexInfo[VertexKey(newVert)] = info;
   return newVert;
}

// InsertVertexBefore
//    - parameters : position - vertex reference
//		     info - information record for the new vertex
//    - return value : the new vertex
//    - adds a new vertex to graph before the vertex reference and returns it
template <class Vtype, class Etype>
Vertex InfoGraph<Vtype, Etype>::InsertVertexBefore(Vertex position, Vtype info)
{
   Vertex newVert = Graph::InsertVertexBefore(position); 
   vertexInfo[VertexKey(newVert)] = info;
   return newVert;
}

// InsertEdgeAfter
//    - parameters : sourceVert - source vertex of new edge
//                 : targetVert - target vertex of new edge
//                 : sourcePosition - source edge reference
//                 : targetPosition - target edge reference
//                 : listPosition - edge list reference
//		   : info - information record for the new edge
//    - return value : the new edge 
//    - adds a new edge to the graph between the parameter vertices, after the parameter edges
//         returns that edge
template <class Vtype, class Etype>
Edge InfoGraph<Vtype, Etype>::InsertEdgeAfter(Vertex sourceVert, Vertex targetVert, Edge sourcePosition, Edge targetPosition, Edge listPosition, Etype info)
{
   Edge newEdge = Graph::InsertEdgeAfter(sourceVert, targetVert, sourcePosition, targetPosition, listPosition); 
   edgeInfo[EdgeKey(newEdge)] = info;
   return newEdge;
}

// InsertEdgeBefore
//    - parameters : sourceVert - source vertex of new edge
//                 : targetVert - target vertex of new edge
//                 : sourcePosition - source edge reference
//                 : targetPosition - target edge reference
//                 : listPosition - edge list reference
//		   : info - information record for the new edge
//    - return value : the new edge 
//    - adds a new edge to the graph between the parameter vertices, before the parameter edges
//         returns that edge
template <class Vtype, class Etype>
Edge InfoGraph<Vtype, Etype>::InsertEdgeBefore(Vertex sourceVert, Vertex targetVert, Edge sourcePosition, Edge targetPosition, Edge listPosition, Etype info)
{
   Edge newEdge = Graph::InsertEdgeBefore(sourceVert, targetVert, sourcePosition, targetPosition, listPosition); 
   edgeInfo[EdgeKey(newEdge)] = info;
   return newEdge;
}


// InfoGraph
//    - default constructor
//    - initializes object to default values
template <class Vtype, class Etype>
InfoGraph<Vtype, Etype>::InfoGraph(int isDirectedFlag) : Graph(isDirectedFlag)
{
   vertexInfo.SetBounds(1, 100); 
   edgeInfo.SetBounds(1, 100); 
}


// InsertVertex
//    - parameters : vertValue - value to be attached to new vertex
//    - return value : the new vertex
//    - adds a new vertex to graph, assigns the vertex the value
//         vertValue, and returns the vertex
template <class Vtype, class Etype>
Vertex InfoGraph<Vtype, Etype>::InsertVertex(Vtype vertValue)
{
   Vertex v1 = Graph::InsertVertex(); 
   vertexInfo[VertexKey(v1)] = vertValue;
   return v1;
}


// InsertEdge
//    - parameters : sourceVert - source vertex of new edge
//                 : targetVert - target vertex of new edge
//                 : edgeValue - value to be attached to new edge
//    - return value : the new edge
//    - adds a new edge to the graph between the parameter vertices,
//         assigns the edge the value edgeValue, and returns that edge
template <class Vtype, class Etype>
Edge InfoGraph<Vtype, Etype>::InsertEdge(Vertex sourceVert, 
					Vertex targetVert, Etype edgeValue)
{
   Edge e1 = Graph::InsertEdge(sourceVert, targetVert); 
   edgeInfo[EdgeKey(e1)] = edgeValue;
   return e1; 
}



// VertexInfo
//    - parameters : infoVert - vertex whose value we want
//    - return type : a vertex information value
//    - returns the information variable stored in this vertex
template <class Vtype, class Etype>
Vtype InfoGraph<Vtype, Etype>::VertexInfo(Vertex infoVert)
{
   return vertexInfo[VertexKey(infoVert)]; 

}


// EdgeInfo
//    - parameters : infoEdge - edge whose value we want
//    - return type : an edge information value
//    - returns the information variable stored in this edge
template <class Vtype, class Etype>
Etype InfoGraph<Vtype, Etype>::EdgeInfo(Edge infoEdge)
{
   return edgeInfo[EdgeKey(infoEdge)];
}


// VertexAssign
//    - parameters : infoVert - vertex at which we will store info
//                 : vertValue - information value for the vertex
//    - stores the value vertValue at the vertex infoVert, writing
//       over whatever information used to be at infoVert, if any
template <class Vtype, class Etype>
void InfoGraph<Vtype, Etype>::VertexAssign(Vertex infoVert, Vtype vertValue)
{
   vertexInfo[VertexKey(infoVert)] = vertValue;
}


// EdgeAssign
//    - parameters : infoEdge - edge at which we will store info
//                 : edgeValue - information value for the edge
//    - stores the value edgeValue at the edge infoEdge, writing
//       over whatever information used to be at infoEdge, if any
template <class Vtype, class Etype>
void InfoGraph<Vtype, Etype>::EdgeAssign(Edge infoEdge, Etype edgeValue)
{
   edgeInfo[EdgeKey(infoEdge)] = edgeValue; 
}



CS225 MP7: Patricia Tree

This code defines and implements a Patricia tree data structure

patricia.h


// *******************************************************
// *                                                     *
// *  patricia.h                                         *
// *                                                     *
// *  Interface for a Patricia tree                      *
// *                                                     *
// *   Written December 2003 by Seunghoon Kim            *
// *                                                     *
// *******************************************************

#ifndef _PATRICIATREE_H
#define _PATRICIATREE_H

#include "string.h"
#include "array.h"
#include "asserts.h"
class PatriciaTreeNode;

class PatriciaTree
{
public:

   // PatriciaTree
   //   - default constructor
   //   - initializes object to default values
   PatriciaTree();


   // PatriciaTree
   //   - copy constructor
   //   - parameters : origVal - previously allocated PatriciaTree object
   //   - initializes object to be a copy of origVal
   PatriciaTree(const PatriciaTree& origVal);


   // ~PatriciaTree
   //   - destructor
   //   - deletes dynamically allocated memory
   ~PatriciaTree();


   // operator=
   //   - parameters : origVal - previously allocated PatriciaTree object
   //   - return value : reference to PatriciaTreeNode
   //   - sets object to be a copy of origVal
   PatriciaTree& operator=(const PatriciaTree& origVal);


   // insert
   //   - parameters : newString - new key to add
   //   - inserts newString into the PatriciaTree
   void insert(String newString);


   // find
   //   - parameters : searchString - key value to search for
   //   - return value : boolean "succesful or not"
   //   - returns 0 if string is not in the tree; else returns 1
   int find(String searchString);


   // remove
   //   - parameters : removeString - key to be removed
   //   - removes removeString if it is in the PatriciaTree
   void remove(String removeString);


   // Print
   //   - prints the info of the PatriciaTree
   void print();


private:
   class PatriciaTreeNode
   {
   public:

      // PatriciaTreeNode
      //   - default constructor
      //   - initializes node to default value as internal array node
      PatriciaTreeNode()
      {
         nodeLevel = 0;
         nodeType = 1;   // arrayNode
         numChildren = 0;
         ArrayPtr = new Array<PatriciaTreeNode*>(1, 27);
         ArrayPtr->Initialize(NULL);
      }


      // PatriciaTreeNode
      //   - constructor
      //   - parameters : initString - string key initializer
      //                : theNodeType - int defining if node is leaf or not
      //   - initializes node to be tree leaf or array node
      PatriciaTreeNode(String initString, int theNodeType)
      {
         nodeLevel = 0;
         nodeType = theNodeType;
         numChildren = 0;
         if (nodeType == 1)
         {
            ArrayPtr = new Array<PatriciaTreeNode*>(1, 27);
            ArrayPtr->Initialize(NULL);
         }
         else
            ArrayPtr = new Array<PatriciaTreeNode*>();
         key = initString;
      }


      // ~PatriciaTreeNode
      //   - destructor
      //   - deletes dynamically allocated memory
      ~PatriciaTreeNode()
      {
         delete ArrayPtr;
      }

      int nodeLevel;				// level of the node
      int nodeType;				// type of the node
      Array<PatriciaTreeNode*>* ArrayPtr;	// ptr to array in array nodes
      String key;				// string key
      int numChildren;				// number of children
   };



   PatriciaTreeNode* root;	// pointer to root node of patricia tree


   // Copy
   //   - parameters : origVal - pointer to a patricia tree structure
   //   - return value : PatriciaTreeNode pointer
   //   - returns a pointer to a copy of the parameter tree
   PatriciaTreeNode* Copy(PatriciaTreeNode*& origVal);


   // Clear
   //   - parameter : origVal - pointer to a patricia tree structure
   //   - clears the entire tree
   void Clear(PatriciaTreeNode*& origVal);


   // ascIndex
   //   - parameters : indexChar - a character for which we want an index
   //   - return value : integer index
   //   - returns the index from 1 - 27 that represents this character
   int ascIndex(char indexChar);


   // insert
   //   - parameters : newString - new key value to add
   //                : nodePtr - pointer to the node currently being examined
   //                : prevLevel - level of the node that contains nodePtr
   //   - inserts newString into the PatriciaTree as a leaf node
   void insert(String newString, PatriciaTreeNode*& nodePtr, int prevLevel);


   // find
   //   - parameters : searchString - key value to search for
   //                : nodePtr - pointer to the node currently being examined
   //   - return value : boolean "succesful or not"
   //   - returns 0 if string is not in tree; else returns 1
   int find(String searchString, PatriciaTreeNode*& nodePtr);


   // remove
   //   - parameters : removeString - key value to be removed
   //                : nodePtr - pointer to the node currently being examined
   //                : prevLevel - level of the node that contains nodePtr
   //   - removes removeString from the PatriciaTree
   void remove(String removeString, PatriciaTreeNode*& nodePtr, int prevLevel);


   // print
   //   - prints the info of the PatriciaTree
   void print(PatriciaTreeNode*& nodePtr);


};
#endif

patricia.cpp


// *******************************************************
// *                                                     *
// *  patricia.cpp                                       *
// *                                                     *
// *  Implementation for a Patricia tree	         *
// *                                                     *
// *   Written December 2003 by Seunghoon Kim            *
// *                                                     *
// *******************************************************

#include <stddef.h>
#include "patricia.h"
#include "asserts.h"

// PatriciaTree
//   - default constructor
//   - initializes object to default values
PatriciaTree::PatriciaTree()
{
  root = NULL;
}


// PatriciaTree
//   - copy constructor
//   - parameters : origVal - previously allocated PatriciaTree object
//   - initializes object to be a copy of origVal
PatriciaTree::PatriciaTree(const PatriciaTree& origVal)
{
  root = Copy(origVal.root);
}


// ~PatriciaTree
//   - destructor
//   - deletes dynamically allocated memory
PatriciaTree::~PatriciaTree()
{
  Clear(root);
}


// operator=
//   - parameters : origVal - previously allocated PatriciaTree object
//   - return value : reference to PatriciaTreeNode
//   - sets object to be a copy of origVal
PatriciaTree& PatriciaTree::operator=(const PatriciaTree& origVal)
{
  Clear(root);
  root = Copy(origVal.root);
  return *this;
}


// insert
//   - parameters : newString - new key to add
//   - inserts newString into the PatriciaTree
void PatriciaTree::insert(String newString)
{
  insert(newString, root, -1);
}


// find
//   - parameters : searchString - key value to search for
//   - return value : boolean "succesful or not"
//   - returns 0 if string is not in the tree; else returns 1
int PatriciaTree::find(String searchString)
{
  return find(searchString, root);
}


// remove
//   - parameters : removeString - key to be removed
//   - removes removeString if it is in the PatriciaTree
void PatriciaTree::remove(String removeString)
{
  if (find(removeString))
    remove(removeString, root, -1);
}


// print
//   - prints the info of the PatriciaTree
void PatriciaTree::print()
{
  print(root);
}


// Copy
//   - parameters : origVal - pointer to a patricia tree structure
//   - return value : PatriciaTreeNode pointer
//   - returns a pointer to a copy of the parameter tree
PatriciaTree::PatriciaTreeNode* PatriciaTree::Copy(PatriciaTreeNode*& origVal)
{
  PatriciaTreeNode* retVal = new PatriciaTreeNode(origVal->key,
						  origVal->nodeType);
  //if we reached an array
  if (origVal->nodeType == 1)
    {
      for (int i=1; i<=27; ++i)
	{
	  if ((*(origVal->ArrayPtr))[i] != NULL)
            (*(retVal->ArrayPtr))[i] = Copy((*(origVal->ArrayPtr))[i]);
	}
      retVal->nodeLevel = origVal->nodeLevel;
      retVal->numChildren=origVal->numChildren;
    }
  else	//leaf node, all leaf nodes have zero children
    {
      retVal->nodeLevel = origVal->nodeLevel;
      retVal->numChildren=0;
    }

  return retVal;
}


// Clear
//   - parameter : origVal - pointer to a patricia tree structure
//   - clears the entire tree
void PatriciaTree::Clear(PatriciaTreeNode*& origVal)
{
  if (origVal->nodeType == 1)	//array node
    {
      for (int i=1; i<27; i++)
	if ((*(origVal->ArrayPtr))[i] != NULL)
	  {
            Clear((*(origVal->ArrayPtr))[i]);
            ((*(origVal->ArrayPtr))[i]) = NULL;
	  }
    }

  delete origVal;
}


// ascIndex
//   - parameters : indexChar - a character for which we want an index
//   - return value : integer index
//   - returns the index from 1 - 27 that represents this character
int PatriciaTree::ascIndex(char indexChar)
{
  if ((indexChar>='a') && (indexChar<='z'))   // lowercase letter
    return (indexChar-'a'+1);
  else if (indexChar == 0)  // null character
    return 27;
  else
    Assert(0, "Bizarre character in string!");
}


// insert
//   - parameters : newString - new key value to add
//                : nodePtr - pointer to the node currently being examined
//                : prevLevel - level of the node that contains nodePtr
//   - inserts newString into the PatriciaTree as a leaf node
void PatriciaTree::insert(String newString, PatriciaTreeNode*& nodePtr,
			  int prevLevel)
{
  if (nodePtr == NULL)		//NULL case
    {
      nodePtr = new PatriciaTreeNode(newString, 0);
      nodePtr->nodeLevel = newString.length()+1;
      return;
    }

  else if (nodePtr->nodeType == 0)		//leaf case
    {
      if (nodePtr->key == newString)
	{
	  cout << "key already exists!" << endl;
	  return;
	}
      else
	{
	  int i;
	  for (i = prevLevel+1; i<=nodePtr->nodeLevel-2; i++)
	    //check nodePtr's key to see if it matches newString
	    {
	      if ((i>=newString.length()) || ((nodePtr->key)[i] != newString[i]))
		{
		  String tempKey = nodePtr->key;
		  PatriciaTreeNode* tempNode = new PatriciaTreeNode(tempKey, 0);

		  tempNode->nodeLevel = nodePtr->nodeLevel;
		  nodePtr->nodeLevel = i;
		  nodePtr->numChildren = 2;
		  nodePtr->nodeType = 1;
		  nodePtr->ArrayPtr->SetBounds(1, 27);
		  nodePtr->ArrayPtr->Initialize(NULL);

		  if((i-(prevLevel+1))==0)
		    nodePtr->key=NULL;

		  else
		      nodePtr->key = tempKey.substring(prevLevel+1, i-(prevLevel+1));

		  (*(nodePtr->ArrayPtr))[ascIndex(tempKey[i])] = tempNode;
		  if (i>=newString.length())
		    insert(newString, (*(nodePtr->ArrayPtr))[27],
			   nodePtr->nodeLevel);
		  else
		    insert(newString,
			   (*(nodePtr->ArrayPtr))[ascIndex(newString[i])],
			   nodePtr->nodeLevel);
		  return;
		}
	    }
	  String tempKey = nodePtr->key;
	  PatriciaTreeNode* tempNode = new PatriciaTreeNode(tempKey, 0);

	  tempNode->nodeLevel = nodePtr->nodeLevel;
	  nodePtr->nodeLevel = i;
	  tempNode->numChildren = nodePtr->numChildren;
	  nodePtr->numChildren = 2;
	  nodePtr->nodeType = 1;
	  nodePtr->ArrayPtr->SetBounds(1, 27);
	  nodePtr->ArrayPtr->Initialize(NULL);

	  if((i-(prevLevel+1))==0)
	    nodePtr->key=NULL;
	  else
	    nodePtr->key = tempKey.substring(prevLevel+1, i-(prevLevel+1));
	  (*(nodePtr->ArrayPtr))[27] = tempNode;
	  insert(newString, (*(nodePtr->ArrayPtr))[ascIndex(newString[i])],
		 nodePtr->nodeLevel);
	}
    }

  else		//non-NULL array node case
    {
      	//where nodePtr's level is the correct level to insert
      if ((nodePtr->nodeLevel == newString.length())&&(nodePtr->key==NULL))
	{
	  nodePtr->numChildren++;
	  insert(newString, (*(nodePtr->ArrayPtr))[27], nodePtr->nodeLevel);
	}

      else if (prevLevel+1 == nodePtr->nodeLevel)
	//where nodePtr has NOT skipped levels
	{
	  PatriciaTreeNode* insNode =
	    (*(nodePtr->ArrayPtr))[ascIndex(newString[nodePtr->nodeLevel])];
	  insert(newString, insNode, nodePtr->nodeLevel);
	  (*(nodePtr->ArrayPtr))[ascIndex(newString[nodePtr->nodeLevel])] = insNode;
	  if (insNode->nodeType == 0)
            (nodePtr->numChildren)++;
	  return;
	}

      else		//where nodePtr HAS skipped levels
	{
	  int k = 1;
	  for (int i = prevLevel+1; i<=nodePtr->nodeLevel-1; i++)
	    //check nodePtr's key to see if it matches newString
	    {
	      if ((i>=newString.length()) || (nodePtr->key[k-1] != newString[i]))
		{
		  PatriciaTreeNode* tempNode = new PatriciaTreeNode();
		  String tempKey = nodePtr->key;

		  tempNode->nodeLevel = nodePtr->nodeLevel;
		  nodePtr->nodeLevel = i;
		  tempNode->numChildren = nodePtr->numChildren;
		  nodePtr->numChildren = 2;
		  for (int j=1; j<=27; j++)
		    {
		      (*(tempNode->ArrayPtr))[j] = (*(nodePtr->ArrayPtr))[j];
		      (*(nodePtr->ArrayPtr))[j] = NULL;
		    }
		  if (tempKey.length()>1)
		    {
		      nodePtr->key = tempKey.substring(0, k-1);
		      tempNode->key = tempKey.substring(k,tempKey.length()-k);
		    }
		  else
		    nodePtr->key = tempNode->key = NULL;
		  (*(nodePtr->ArrayPtr))[ascIndex(tempKey[k-1])] = tempNode;
		  if (i>=newString.length())
		    insert(newString, (*(nodePtr->ArrayPtr))[27],
			   nodePtr->nodeLevel);
		  else
		    insert(newString,
			   (*(nodePtr->ArrayPtr))[ascIndex(newString[i])],
			   nodePtr->nodeLevel);
		  return;
		}
	      k++;
	    }
	  int charIndex = (nodePtr->key).length()+prevLevel+1;
	  nodePtr->numChildren++;
	  insert(newString, (*(nodePtr->ArrayPtr))[ascIndex(newString[charIndex])],
		 nodePtr->nodeLevel);
	}
    }
}


// find
//   - parameters : searchString - key value to search for
//                : nodePtr - pointer to the node currently being examined
//   - return value : boolean "succesful or not"
//   - returns 0 if string is not in tree; else returns 1
int PatriciaTree::find(String searchString, PatriciaTreeNode*& nodePtr)
{
  if (nodePtr == NULL)		//NULL case
    return 0;
  else if (nodePtr->nodeType == 0)		//leaf case
    {
      if (nodePtr->key == searchString)
	return 1;
      else
	return 0;
    }
  else		//non-NULL array node case
    {
      if (nodePtr->nodeLevel == searchString.length())
	//search string would be in NULL cell if it exists
	return find(searchString, (*(nodePtr->ArrayPtr))[27]);
      else if (nodePtr->nodeLevel > searchString.length())
	//search string got skipped over so it doesn't exist
	return 0;
      else
	//keep looking through array
	return find (searchString,
		     (*(nodePtr->ArrayPtr))[ascIndex(searchString[nodePtr->nodeLevel])]);
    }
}


// remove
//   - parameters : removeString - key value to be removed
//                : nodePtr - pointer to the node currently being examined
//                : prevLevel - level of the node that contains nodePtr
//   - removes removeString from the PatriciaTree
void PatriciaTree::remove(String removeString, PatriciaTreeNode*& nodePtr,
			  int prevLevel)
{
  //base case
  if (nodePtr->nodeType == 0)
    {
      delete nodePtr;
      return;
    }
  else
    {
      PatriciaTreeNode* nodeToRemoveFrom =
	(*(nodePtr->ArrayPtr))[ascIndex(removeString[nodePtr->nodeLevel])];
      int isLeaf = 0;

      //if the node we wish to remove is a leaf
      if (nodeToRemoveFrom->nodeType == 0)
	isLeaf = 1;

      remove(removeString,
	     (*(nodePtr->ArrayPtr))[ascIndex(removeString[nodePtr->nodeLevel])],
	     nodePtr->nodeLevel);

      //if it is a leaf we set the array cell equal to NULL
      if (isLeaf)
	{
	  (*(nodePtr->ArrayPtr))[ascIndex(removeString[nodePtr->nodeLevel])] =
	    NULL;
	}
    }

  PatriciaTreeNode* childNode =
    (*(nodePtr->ArrayPtr))[ascIndex(removeString[nodePtr->nodeLevel])];
    //tempNode is child of nodePtr

  //if the deleted node is now NULL, we decrease the total number of non-NULL cells in the array
  if (childNode == NULL)
    {
      nodePtr->numChildren--;

      //if the root now only has one child
      if ((nodePtr == root) && (nodePtr->numChildren == 1))
	{
	  for (int i=1; i<=27; i++)
            if ((*(nodePtr->ArrayPtr))[i] != NULL)
	      childNode = (*(nodePtr->ArrayPtr))[i];

	  if (childNode->nodeType == 0)		//root's only child is a leaf
	    {
	      delete nodePtr;
	      root = childNode;
	    }
	  else
	    {
	      // int to char conversion
	      int index;
	      for (int i=1; i<=27; i++)
		if ((*(nodePtr->ArrayPtr))[i] != NULL)
                  index = i;
	      char indexChar = char(index-1+'a');

	      if (childNode->key == NULL)
		childNode->key = String(&indexChar);
	      else
		childNode->key = String(&indexChar) + childNode->key;

	      delete nodePtr;
	      root = childNode;
	    }
	}
    }

  //if number of non-NULL cells is now equal to 1
  else if (childNode->numChildren == 1)
    {
      PatriciaTreeNode* grandChild;
      for (int i=1; i<=27; i++)
	if ((*(childNode->ArrayPtr))[i] != NULL)
	  grandChild = (*(childNode->ArrayPtr))[i];

      //have "grandpa" point at "grandchild"
      if (grandChild->nodeType == 0)		//nodePtr's grandchild is a leaf
	{
	  delete childNode;
	  (*(nodePtr->ArrayPtr))[ascIndex(removeString[nodePtr->nodeLevel])] = grandChild;
	}

    }

  //if the number of non-NULL cells is greater than one, array is fine so simply return
  else if (childNode->numChildren > 1)
    return;

}


// print
//   - prints the info of the PatriciaTree
void PatriciaTree::print(PatriciaTreeNode*& nodePtr)
{
  if (nodePtr != NULL)
    {
      //if we reach an internal array
      if(nodePtr->nodeType == 1)
	{
	  cout <<"Internal node at level "<<nodePtr->nodeLevel<<endl;

	  int i;
	  for (i=1; i<=27; i++)
	    {
	      if((*(nodePtr->ArrayPtr))[i]!=NULL)
		{
		  cout<<"The ";
		  if (i==27)
		     cout << "null-character";
		  else
		     cout << char(i-1+'a');
		  cout <<" subtree pointed to by level "<<nodePtr->nodeLevel
		       <<" is as follows: "<<endl;
		  print((*(nodePtr->ArrayPtr))[i]);
		  cout<<"The ";
		  if (i==27)
		     cout << "null-character";
		  else
		     cout << char(i-1+'a');
		  cout <<" subtree pointed to by level "<<nodePtr->nodeLevel
		       <<" has been explored. "<<endl;
		}
	    }

	   if(nodePtr->key == NULL)
	     cout<<"There is no skipped substring for this node. "<<endl;
	   else if(nodePtr->key!=NULL)
	     cout<<"skipped substring for this node is: "<<nodePtr->key<<endl;

	}

      //if we reach a leaf
      if (nodePtr->nodeType == 0)
	{
	  cout << "Leaf node at level "<< nodePtr->nodeLevel <<" has string "
	       <<nodePtr->key << endl;
	  return;
	}

   } } 

CS296: Red and Black Tree

This code defines and implements a red & black tree data structure

rbtree.h

// *******************************************************
// *                                                     *
// *  rbtree.h                                           *
// *                                                     *
// *  Interface for a red and black tree                 *
// *                                                     *
// *   Written November 2003 by Seunghoon Kim            *
// *                                                     *
// *******************************************************

#ifndef RBTREE_H
#define RBTREE_H

#include <stddef.h>
#include "utility225.h"


// **************************************************************
// *                                                            *
// *  Class : rb_tree                                           *
// *                                                            *
// *  The interface class for the red and black implementation  * 
// *                                                            *
// **************************************************************
template <class Ktype, class Etype>
class rb_tree
{
public:

   // rb_tree
   //    - default constructor 
   //    - initializes tree to be empty
   rb_tree();

   // insert
   //    - parameters : insElem - value to be inserted
   //    - return value : none
   //    - inserts insElem into tree (does nothing if key is
   //         already there
   void insert(const pair<Ktype, Etype>& insElem)
   {
      insert(insElem, root(), headerNode);
   }

   // erase
   //    - parameters : key - key to the element to be erased
   //    - erases element pointed by remKey from tree if it is in tree
   void erase(const Ktype& key)
   {
      erase(key, root(), headerNode);
   }

   // preorder
   //    - prints tree in preorder format
   void preorder()
   {
      preorder(root());
   }
   
private:
// *********************************************
// *                                           *
// *  rbtree<>::rb_tree_node                   *
// *                                           *
// *  The node class for our red & black tree. * 
// *                                           *
// *********************************************
   class rb_tree_node
   {
   public:
   
      // rb_tree_node
      //    - default constructor
      //    - initializes node to default values
      rb_tree_node() : element(), left(NULL), right(NULL), parent(NULL),
                                                            color(0) {}
      
      
      // rb_tree_node
      //    - constructor
      //    - parameters : elem - initialization element
      //                 : leftPtr - initialization left pointer
      //                 : rightPtr - initialization right pointer
      //                 : color - initialization color
      //    - initializes node to parameter values
      rb_tree_node(pair<Ktype, Etype> elem, rb_tree_node* leftPtr = NULL,
            rb_tree_node* rightPtr = NULL, rb_tree_node* parentPtr = NULL,
                                                         int clr = 0) :
            element(elem), left(leftPtr), right(rightPtr), parent(),
                                                      color(clr) {}
      
      
      pair<Ktype, Etype> element;
      rb_tree_node* left;
      rb_tree_node* right;
      rb_tree_node* parent;
      int color;
      
   };    // end rb_tree_node class
   
   
 // ************* Member data for Red-Black tree
 
 rb_tree_node* headerNode;
 int treeSize;
 
   
   
 // ************* Node access functions
 
   // root
   //    - return value : a reference to an RB tree node pointer
   //    - returns a refernce to root of RB tree
   rb_tree_node*& root() const { return headerNode->parent; }
   
      
   // key
   //    - parameters : value - a value pair we want the key of
   //    - return type : a key value
   //    - value stores a (Key, Info) pair. This function
   //       will extract the key from this pair and return it.
   Ktype key(const pair<Ktype, Etype> value) const { return value.first; }


   // insert
   //    - parameters : insElem - element to be inserted
   //                 : TN - a treenode pointer
   //                 : parentOfTN - the parent of the node TN
   //    recursively inserts insElem into tree if insElem does not already
   //       exists
   void insert(const pair<Ktype, Etype>& insElem, rb_tree_node*& TN,
                                             rb_tree_node* parentOfTN);
   
   
   // remove
   //    - paremeters : remElem - element to be removed
   //                 : TN - a treenode pointer
   //    - recursively removes remElem from tree if exists
   void erase(const Ktype& remElem, rb_tree_node*& TN,
                                          rb_tree_node* parentOfTN);
   
   
   // preorder
   //    - helper function for preorder()
   void preorder(rb_tree_node* TN) const;
   
   
   
 // ************* Additional helper functions
   
   
   // right_rotation
   //    - parameters : k2 - root of subtree
   //    - performs a single right rotation on k2
   void right_rotation(rb_tree_node* k2);
   
   
   // left_rotation
   //    - parameters : k2 - root of subtree
   //    - performs a single left rotation on k2
   void left_rotation(rb_tree_node* k2);
   
};


#endif


rbtree.cpp


// *******************************************************
// *                                                     *
// *  rbtree.cpp                                         *
// *                                                     *
// *  Implementation for a red and black tree	         *
// *                                                     *
// *   Written November 2003 by Seunghoon Kim            *
// *                                                     *
// *******************************************************
#include <stdlib.h>
#include "rbtree.h"
#include <iostream.h>



// rb_tree
//    - default constructor
//    - initializes tree to be empty
template <class Ktype, class Etype>
rb_tree<Ktype, Etype>::rb_tree() : treeSize(0), headerNode(new rb_tree_node())
{
   headerNode->left = headerNode->right = headerNode;
}



// insert
//    - parameters : insElem - element to be inserted
//                 : TN - a treenode pointer
//                 : parentOfTN - the parent of the node TN
//    recursively inserts insElem into tree if insElem does not already
//       exists
template <class Ktype, class Etype>
void rb_tree<Ktype, Etype>::insert(const pair<Ktype, Etype>& insElem,
                           rb_tree_node*& TN, rb_tree_node* parentOfTN)
{
   if (TN == NULL)
   {
      TN = new rb_tree_node();
      TN->element = insElem;
      TN->color = 0; 
      TN->parent = parentOfTN;
      
      if ((treeSize==0) || (key(insElem) < key(headerNode->left->element)))
         headerNode->left = TN;
      if ((treeSize==0) || (key(insElem) > key(headerNode->right->element)))
         headerNode->right = TN;
      
      
      rb_tree_node* X = TN;
      treeSize++;
      
      while ((X != root() ) && (X->parent->color == 0) )
      {
         if ((key(X->element) < key(X->parent->parent->element) ) &&
            (!(X->parent->parent->right) ||
            (X->parent->parent->right->color == 1) ) )				// case 1
         {
            if ((key(X->element) < key(X->parent->element) ) &&
               (key(X->parent->element) > key(X->parent->parent->element) ) )
            {
               rb_tree_node* tmp_X = X->parent;
               right_rotation(X->parent);
               X = tmp_X;
            }
            else if ((key(X->element) > key(X->parent->element) ) &&
               (key(X->parent->element) < key(X->parent->parent->element) ) )
            {
               rb_tree_node* tmp_X = X->parent;
               left_rotation(X->parent);
               X = tmp_X;
            }
            
            
            X->parent->parent->color = 0;
            X->parent->color = 1;
            right_rotation(X->parent->parent);
         }
         
         else if ((key(X->element) > key(X->parent->parent->element) ) &&
            (!(X->parent->parent->left) ||
            (X->parent->parent->left->color == 1) ) )
         {
            if ((key(X->element) < key(X->parent->element) ) &&
               (key(X->parent->element) > key(X->parent->parent->element) ) )
            {
               rb_tree_node* tmp_X = X->parent;
               right_rotation(X->parent);
               X = tmp_X;
            }
            else if ((key(X->element) > key(X->parent->element) ) &&
               (key(X->parent->element) < key(X->parent->parent->element) ) )
            {
               rb_tree_node* tmp_X = X->parent;
               left_rotation(X->parent);
               X = tmp_X;
            }
            
            
            X->parent->parent->color = 0;
            X->parent->color = 1;
            left_rotation(X->parent->parent);
         }
         
         else													// Case 2
         {
            X->parent->parent->left->color = 1;
            X->parent->parent->right->color = 1;
            X->parent->parent->color = 0;
            X = X->parent->parent;
         }

      } 
      

      root()->color = 1;
   
   }
   
   else if (key(insElem) < key(TN->element) )
   {														      // insert in the left subtree
      insert(insElem, TN->left, TN);
   }
   else if (key(insElem) > key(TN->element) )
   {																// insert in the right subtree
      insert(insElem, TN->right, TN);
   }
   // else key(insElem) == key(TN->element)
   else
   {
      return;
   } // BST insert end
}


// remove
//    - paremeters : remElem - element to be removed
//                 : TN - a treenode pointer
//    - recursively removes remElem from tree if exists
template <class Ktype, class Etype>
void rb_tree<Ktype, Etype>::erase(const Ktype& remElem, rb_tree_node*& TN,
                                                rb_tree_node* parentOfTN)
{
   rb_tree_node *tmp_cell, *tmpCellParent, *newCell, *X;
   
   if (TN == NULL)
      return;
   else if (remElem < key(TN->element) )
   {
      erase(remElem, TN->left, TN);
   }
   else if (remElem > key(TN->element) )
   {
      erase(remElem, TN->right, TN);
   }
   else
   {
      if ((TN->left != NULL) && (TN->right != NULL) )
      {

         tmp_cell = TN->right;
         while (tmp_cell->left != NULL)
            tmp_cell = tmp_cell->left;
         
         tmpCellParent = tmp_cell->parent;
         newCell = new rb_tree_node();
         
         newCell->right = tmp_cell->right;
         newCell->left = tmp_cell->left;
         newCell->element = tmp_cell->element;
         newCell->color = tmp_cell->color;
         newCell->parent = tmp_cell->parent;
         
         if (tmpCellParent->left == tmp_cell)
            tmpCellParent->left = newCell;
         else if (tmpCellParent->right == tmp_cell)
            tmpCellParent->right = newCell;
         
         tmp_cell->right = TN->right;
         tmp_cell->parent = TN->parent;
         tmp_cell->left = TN->left;
         tmp_cell->color = TN->color;
         
         delete TN;
         TN = tmp_cell;
         TN->left->parent = TN;
         TN->right->parent = TN;
         
         erase(key(TN->element), TN->right, TN);
         
         X = NULL;
      }
      
      else 
      {
         treeSize--;
         
         if (TN == headerNode->left)
            headerNode->left = TN->parent;
         if (TN == headerNode->right)
            headerNode->right = TN->parent;
         if (treeSize == 1)
         {
            if ((TN->parent == headerNode) && (TN->left) )
               headerNode->right = headerNode->left = TN->left;
            else if ((TN->parent == headerNode) && (TN->right) )
               headerNode->right = headerNode->left = TN->right;
            else
               headerNode->right = headerNode->left = root();
         }
         
         if ((TN->left == NULL) && (TN->right == NULL) ) 
         {
            X = TN;
            
            if ((X->color == 0) || (X == root() ) )
            {
               delete X;
               X = NULL;
            }
            else
               X->left = X;
            
            TN = NULL;
            
         }
         else if ((TN->left == NULL) && (TN->right != NULL) )
         {
            TN = TN->right;
            TN->parent = parentOfTN;
            
            X = TN;
         }
         else if ((TN->left != NULL) && (TN->right == NULL) )
         {
            TN = TN->left;
            TN->parent = parentOfTN;
            
            X = TN;
         }
      }
      
      if (X == NULL)
         return;
      else
      {
         while ((X != root() ) && (X->color == 1) )
         {
																					// Case 1
            if ((key(X->element) < key(X->parent->element) ) &&
               (X->parent->right->color == 0) )
            {
               X->parent->right->color = 1;
               X->parent->color = 0;
               left_rotation(X->parent);
            }
            else if ((key(X->element) > key(X->parent->element) ) &&
               (X->parent->left->color == 0) )
            {
               X->parent->left->color = 1;
               X->parent->color = 0;
               right_rotation(X->parent);
            }
																					//  Case 2a
            if ((key(X->element) < key(X->parent->element) ) &&
               (X->parent->right->left) &&
               (X->parent->right->left->color == 0) &&
               (!(X->parent->right->right) ||
               (X->parent->right->right->color == 1) ) )
            {
               X->parent->right->color = 0;
               X->parent->right->left->color = 1;
               right_rotation(X->parent->right);
            }
            else if ((key(X->element) > key(X->parent->element) ) &&
               (X->parent->left->right) &&
               (X->parent->left->right->color == 0) &&
               (!(X->parent->left->left) ||
               (X->parent->left->left->color == 1) ) )
            {
               X->parent->left->color = 0;
               X->parent->left->right->color = 1;
               left_rotation(X->parent->left);
            }
               
            if ((key(X->element) < key(X->parent->element) ) &&										// Case 2b
               (X->parent->right->right) &&
               (X->parent->right->right->color == 0) )
            {
               X->parent->right->right->color = 1;
               X->parent->right->color = X->parent->color;
               X->parent->color = 1;
               left_rotation(X->parent);
               
               if (X->left == X)
                  delete X;
               
               X = root();
            }
            else if ((key(X->element) > key(X->parent->element) ) &&
               (X->parent->left->left) &&
               (X->parent->left->left->color == 0) )
            {
               X->parent->left->left->color = 1;
               X->parent->left->color = X->parent->color;
               X->parent->color = 1;
               right_rotation(X->parent);
               
               if (X->left == X)
                  delete X;
               
               X = root();  
            }
            
            else																	// Case 3
            {
               if (key(X->element) < key(X->parent->element) )
                  X->parent->right->color = 0;
               else if (key(X->element) > key(X->parent->element) )
                  X->parent->left->color = 0;
               
               rb_tree_node* tmp_X = X;
               X = X->parent;
               
               if (tmp_X->left == tmp_X)
                  delete tmp_X;
            }
         
            
         }
         X->color = 1;
      
      }
   
   }
}


// preorder
//    - helper function for preorder()
template <class Ktype, class Etype>
void rb_tree<Ktype, Etype>::preorder(rb_tree_node* TN) const
{
   if (TN)
   {
      cout << key(TN->element) << endl;
      preorder(TN->left);
      preorder(TN->right);
   }
}




// right_rotation
//    - parameters : k2 - root of subtree
//    - performs a single right rotation on k2
template <class Ktype, class Etype>
void rb_tree<Ktype, Etype>::right_rotation(rb_tree_node* k2)
{
   rb_tree_node *k1 = k2->left;
   rb_tree_node *parentOfk2 = k2->parent;
   
   // rotate k1 up to "root" and k2 down to right
   k2->left = k1->right;
   if (k2->left != NULL)
     k2->left->parent = k2;
   
   k1->right = k2;
   k2->parent = k1;
   
   k1->parent = parentOfk2;
   
   // correct root
   if (k2 == root())
      root() = k1;
   else
   {
      // correct child pointer
      if (key(k1->element) < key(k1->parent->element) )
         k1->parent->left = k1;
      else
         k1->parent->right = k1;
   }
}


// left_rotation
//    - parameters : k2 - root of subtree
//    - performs a single left rotation on k2
template <class Ktype, class Etype>
void rb_tree<Ktype, Etype>::left_rotation(rb_tree_node* k2)
{
   rb_tree_node *k1 = k2->right;
   rb_tree_node *parentOfk2 = k2->parent;
   
   // rotate k1 up to "root" and k2 down to left
   k2->right = k1->left;
   if (k2->right != NULL)
     k2->right->parent = k2;
   k1->left = k2;
   k2->parent = k1;
   
   k1->parent = parentOfk2;
   
   // correct root
   if (k2 == root())
      root() = k1;
   else
   {
      // correct child pointer
      if (key(k1->element) < key(k1->parent->element) )
         k1->parent->left = k1;
      else
         k1->parent->right = k1;
   }
}

Comments