p04Books04
Home ] Up ]

 

//p04books04
//author
//date 07/26/2001


//////////////////////////////////////////////////////////////////////
//include files
//////////////////////////////////////////////////////////////////////
#include <iostream.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>


//////////////////////////////////////////////////////////////////////
//constants
//////////////////////////////////////////////////////////////////////
const int TITLE_LEN = 30;
const int AUTHOR_LEN = 30;
const int MAX_BOOKS = 15;
const int SUBJECT_LEN = 30;


//////////////////////////////////////////////////////////////////////
//test values
//////////////////////////////////////////////////////////////////////
const char *testTitles[] = 
  {
  "C++ with Pizza Flavor", "Java Learn Now", "COBOL How To Forget",
  "FORTRAN 77", "DB2: An Introduction", "XML In 24 Hours",
  "UNIX"
  };

const int MAX_TITLES = sizeof(testTitles)/sizeof(testTitles[0]);

const char *testAuthors[] = 
  {
  "John", "Adam", "Sumeer", "Natalie", "David", "Rustin"
  };

const int MAX_AUTHORS = sizeof(testAuthors)/sizeof(testAuthors[0]);

const int testYears[] = {1977, 1988, 1989, 1991, 2000, 2001};

const int MAX_YEARS = sizeof(testYears)/sizeof(testYears[0]);


const char *testSubjects[] = 
  {
  "Math", "Physics", "Chemistry", "Economics", "Art", "Biology"
  };

const int MAX_SUBJECTS = sizeof(testSubjects)/sizeof(testSubjects[0]);


void testSortByYear(void);
void testAdd(void);


//////////////////////////////////////////////////////////////////////
//CBook class definition
//////////////////////////////////////////////////////////////////////
class CBook
  {
  protected:
    char title[TITLE_LEN+1];
    char author[AUTHOR_LEN+1];
    int year;
    CBook *next;
  public:
    CBook(void);
    CBook(char t[], char a[], int y);
    CBook(char ch);
    CBook(const CBook &b); //CBook b2; CBook b1(b2);
    void display(void) const;
    void copy(const CBook &b2);
    void swap(CBook &b2);
    friend class CBooks;

    ~CBook(void);
    bool operator == (const CBook &b2) const;
    bool operator != (const CBook &b2) const;
    CBook & operator = (const CBook &b2);

    friend ostream & operator  << (ostream & john, const CBook &b); 
    friend void swapYear(CBook &b1, CBook &b2);

    friend ostream & operator  << (ostream & john, const CBooks &bc); 
    friend istream & operator  >> (istream & john, CBook &b); 

  };


//////////////////////////////////////////////////////////////////////
//CBook2 class definition
//////////////////////////////////////////////////////////////////////
class CBook2: public CBook
  {
  private:
    char subject[SUBJECT_LEN+1];
  public:
    CBook2(void);
    CBook2(char t[], char a[], int y, char s[]);
    CBook2(char ch);
    friend ostream & operator  << (ostream & john, const CBook2 &b); 
    friend istream & operator  >> (istream & john, CBook2 &b); 
  };


//////////////////////////////////////////////////////////////////////
//class CBooks
//////////////////////////////////////////////////////////////////////
class CBooks
  {
  private:
    int count;
    CBook *head;
    CBook *tail;
  public:
    CBook* addressByPos(int pos);
  public:
    CBooks(void);
    CBooks(int n);
    CBooks(const CBooks &bc);
    void display(void) const;
    void displayRev(void) const;
    void sortBubbleByYear(void);
    bool isSortedByYear(void) const;
    int add(char t[], char a[], int y);
    int remove(int loc); // Project #4
    ~CBooks(void);
    bool isEqualTo(const CBooks &bc2) const;
    bool operator ==(const CBooks &bc2) const;
    bool operator !=(const CBooks &bc2) const;

    friend ostream & operator  << (ostream & john, const CBooks &bc); 
    CBooks(char ch);
    void sortSelectionByYear(void);
    void sortBubbleByTitle(void);
    bool isSortedByTitle(void) const;

    void sortInsertionByYear(void);

    void removeAll(void);
    int add(const CBook &b);

    void displayRev(void);
    void shuffle(void);
    CBooks & operator = (const CBooks &bc2);

    void combine (const CBooks &list);
    bool deleteByAddress(CBook *p);
  };


//////////////////////////////////////////////////////////////////////
//test function prototypes
//////////////////////////////////////////////////////////////////////
void testOperatorInsertionCBooks(void);
void testAdd(void);
void testConstructorRandCBooks(void);
void testOperatorEqualCBooks(void);
void testOperatorNotEqualCBooks(void);
void testConstructorCopyCBooks(void);
void testDisplayRev(void);
void testShuffle(void);
void testAssignCBooks(void);
void testDeleteByAddress(void);
void testCombine(void);

void testConstructorsCBook2(void);
void testOperatorExtactionCBook2(void);
void testOperatorExtractionCBook(void);


//////////////////////////////////////////////////////////////////////
//main function
//////////////////////////////////////////////////////////////////////
void main(void)
  {
  srand(time(NULL));
  //testOperatorInsertionCBooks();
  //testAdd();
  //testConstructorRandCBooks();
  //testOperatorEqualCBooks();
  //testOperatorNotEqualCBooks();
  //testConstructorCopyCBooks();
  //testDisplayRev();
  //testShuffle();
  //testAssignCBooks();
  //testDeleteByAddress();
  //testCombine();

  //testConstructorsCBook2();
  testOperatorExtactionCBook2();
  //testOperatorExtractionCBook();
  }


//////////////////////////////////////////////////////////////////////
//CBook2 constructor
//////////////////////////////////////////////////////////////////////
CBook2::CBook2(void)
  :CBook()
  {
  strcpy(subject, "-1");
  }


//////////////////////////////////////////////////////////////////////
//CBook2 constructor
//////////////////////////////////////////////////////////////////////
CBook2::CBook2(char t[], char a[], int y, char s[])
  :CBook(t, a, y)
  {
  strcpy(subject, s);
  }


//////////////////////////////////////////////////////////////////////
//function to input the contents of BookType variable
//////////////////////////////////////////////////////////////////////
CBook2::CBook2(char ch)
  :CBook(ch)
  {
  if (('i' == ch) || ('I' == ch))
      {
      cout << "Subject:"; cin >> subject;
      }
    else if (('r' == ch) || ('R' == ch))
      strcpy(subject, testSubjects[rand()%MAX_SUBJECTS]);
    else
      {
      strcpy((*this).title, "-2");
      strcpy(this->author, "-2");
      year = -2;
      strcpy(this->subject, "-2");
      }

  }


//////////////////////////////////////////////////////////////////////
//overload insertion operator for output
//////////////////////////////////////////////////////////////////////
ostream & operator  << (ostream & john, const CBook2 &b)
  {
  john << static_cast <CBook> (b);
  john << ", " << b.subject;

  return john;
  }


//////////////////////////////////////////////////////////////////////
//overload extraction operator for input
//////////////////////////////////////////////////////////////////////
istream & operator  >> (istream & john, CBook2 &b)
  {
  cout << "Title:  "; john >> b.title;
  cout << "Author: "; john >> b.author;
  cout << "Year:   "; john >> b.year;
  cout << "Subject:"; john >> b.subject;
  return john;
  }


//////////////////////////////////////////////////////////////////////
//test for extraction operator for input
//////////////////////////////////////////////////////////////////////
void testOperatorExtactionCBook2(void)
  {
  CBook2 b1;
  cin >> b1;
  cout << b1 << endl;

  CBook2 b2('i');
  cout << b2 << endl;

  }


//////////////////////////////////////////////////////////////////////
//test for CBook2 constructors
//////////////////////////////////////////////////////////////////////
void testConstructorsCBook2(void)
  {
  CBook2 b1, b2("Title", "Author", 1995, "Subject"), b3('r'), b4('s');
  cout << b1 << endl;
  cout << b2 << endl;
  cout << b3 << endl;
  cout << b4 << endl;
  }


////////////////////////////////////////////////////////////
//void CBooks::combine (const CBooks &bc)
////////////////////////////////////////////////////////////
//bc1.combine(bc2)
/*
------- ------ +-------
this    bc   |action
------- ------ +-------
empty   empty  |nothing
nempty  empty  |nothing
empty   nempty |combine
nempty  nempty |combine

if the bc is empty then 
    exit function
  else
    insert all the elements from bc to this bc

*/
void CBooks::combine (const CBooks &bc)
  {
  if (0 == bc.count) return;

  CBook *p;
  
  p = bc.head;

  while (p != NULL)
    {
    this->add(*p);
    p = p->next;
    }
  }


////////////////////////////////////////////////////////////
//d void testCombine(void)
////////////////////////////////////////////////////////////
void testCombine(void)
  {
  cout << "Testing combine(yourbc);\n";
  cout << "--------------------------\n";
  char ch;
  do
    {
    CBooks mybc('r'), yourbc('r');

    cout << "mybc:\n" << mybc;
    cout << "yourbc:\n" << yourbc;

    mybc.combine(yourbc);
    cout << "After mybc.combine(yourbc);\n";
      
    cout << "mybc:\n" << mybc;
    cout << "yourbc:\n" << yourbc;
    cin >> ch;
    }
    while (ch != '0');
  }


////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
/*
bool DeleteByAddress(CBook *p)
Possibility         Action
-------------       ----------
Empty bc          false
p is NULL           false
p is not in bc    false
single item         delete, true
head item          delete, true
tail item           delete, true
between two         delete, true

Empty bc
----------
if head is null then
  return false
  end if


p is NULL
---------
if p is null then
  return false
  end if


p is not in bc
----------------
found = false
q = head

while (q != null)
  if p = q then then found = true, break
  advance q
  wend

if found is false then 
  return false
  end if



single item
-----------
if head = tail  then
  if p = head then 
      delete p
      head = tail = null
      count = 0
      return true
    else
      return false
    end if

  
head item
----------
if p = head then
  advance head
  delete p
  count--
  return true
  end if


tail item
---------
if p = tail then
  make q point to node left of p
  make q point to null
  tail = q
  delete p
  count--
  return true
  end if

between two
-----------
if p <> tail p <> head then
  make q point to node left of p
  make q point to next of p
  delete p
  count--
  return true
  end if


*/
////////////////////////////////////////////////////////////
//d
////////////////////////////////////////////////////////////
bool CBooks::deleteByAddress(CBook *p)
  {
  //empty bc
  if (NULL == head)
      return false;

  //p is NULL
  if (NULL == p)
      return false;

  //head item or only item
  if (p == head)
    {
    head = head->next;
    delete p;
    if (NULL == head)
      tail = NULL;
    count--;
    return true;
    }

  //search for node at p
  CBook *q;
  q = head;
  while (p != q->next)
    {
    q = q->next;
    if (NULL == q)  //node not in bc
      return false;
    }
  
  //node in the bc
  q->next = p->next;
  if (p == tail) //tail node
    tail = q;
  count--;
  delete p;
  return true;
 
  }


////////////////////////////////////////////////////////////
//d
////////////////////////////////////////////////////////////
void testDeleteByAddress(void)
  {
  cout << "Testing deleteByAddress =\n";
  cout << "-------------------------\n";
  char ch;
  do
    {
    switch (rand()%7)
      {
      case 0: //empty bc
        {
        cout << "case 0:\n";
        CBooks mybc;
        CBook *p = new CBook;
        cout << mybc;
        cout << mybc;
        cout << "Node to be deleted at " << p << endl;
        bool result = mybc.deleteByAddress(p);
        if (result) 
            cout << "delete successful\n";
          else
            cout << "delete not successful\n";
        cout << mybc;
        delete p;
        break;
        }
      case 1: //1 p is NULL
        {
        cout << "case 1:\n";
        CBooks mybc('r');
        CBook *p = NULL;
        cout << mybc;
        cout << "Node to be deleted at " << p << endl;
        bool result = mybc.deleteByAddress(p);
        if (result) 
            cout << "delete successful\n";
          else
            cout << "delete not successful\n";
        cout << mybc;
        break;
        }
      case 2: //2 p is not in bc
        {
        cout << "case 2:\n";
        CBooks mybc('r');
        CBook *p = new CBook;
        cout << mybc;
        cout << "Node to be deleted at " << p << endl;
        bool result = mybc.deleteByAddress(p);
        if (result) 
            cout << "delete successful\n";
          else
            cout << "delete not successful\n";
        cout << mybc;
        delete p;
        break;
        }
      case 3: //3 single item
        {
        cout << "case 3:\n";
        CBooks mybc(1);
        CBook *p;
        p = mybc.addressByPos(0);
        cout << mybc;
        cout << "Node to be deleted at " << p << endl;
        bool result = mybc.deleteByAddress(p);
        if (result) 
            cout << "delete successful\n";
          else
            cout << "delete not successful\n";
        cout << mybc;
        break;
        }
      case 4: //4 head item
        {
        cout << "case 4:\n";
        CBooks mybc(2+rand()%5);
        CBook *p;
        p = mybc.addressByPos(0);
        cout << mybc;
        cout << "Node to be deleted at " << p << endl;
        bool result = mybc.deleteByAddress(p);
        if (result) 
            cout << "delete successful\n";
          else
            cout << "delete not successful\n";
        cout << mybc;
        break;
        }
      case 5:  //5 tail item 
        {
        cout << "case 5:\n";
        int n = 2+rand()%5;
        CBooks mybc(n);
        CBook *p;
        p = mybc.addressByPos(n-1);
        cout << mybc;
        cout << "Node to be deleted at " << p << endl;
        bool result = mybc.deleteByAddress(p);
        if (result) 
            cout << "delete successful\n";
          else
            cout << "delete not successful\n";
        cout << mybc;
        break;
        }
      case 6: //6 between two nodes
        {
        cout << "case 6:\n";
        int n = 5;
        CBooks mybc(n);
        CBook *p;
        p = mybc.addressByPos(1 + rand()%3);
        cout << mybc;
        cout << "Node to be deleted at " << p << endl;
        bool result = mybc.deleteByAddress(p);
        if (result) 
            cout << "delete successful\n";
          else
            cout << "delete not successful\n";
        cout << mybc;
        break;
        }
      default:;
      }
    
    
    cin >> ch;
    }
    while (ch != '0');
  }


 

//overload = operator
// *this (n)        bc2 (m)
// n=0              m =0 
// n=m              m=n
// n=0              m>0
// n>0              m=0
// n>m              n>m
// n<m              n<m
CBooks & CBooks::operator = (const CBooks &bc2)
  {
  this->removeAll();

  CBook *p;

  p = bc2.head;
  while (p != NULL)
    {
    this->add(*p);
    p = p->next;
    }

  return *this;
  }


void testAssignCBooks(void)
  {
  CBooks bc1('r'), bc2('r'), bc3('r');
  cout << bc1;
  cout << bc2;
  cout << bc3;
  bc1 = bc2 = bc3;
  cout << "After bc1 = bc2 = bc3;\n";
  cout << bc1;
  cout << bc2;
  cout << bc3;
  }


void CBooks::shuffle(void)
  {
  if (count <=1) 
      return;

  int i, j;
  CBook *p, temp;

  for (i=1; i<=count*2000; i++)
    {
    j = rand()%count;
    p = this->addressByPos(j);

    temp = *p;
    *p = *head;
    *head = temp;
    }
  }


void testShuffle(void)
  {
  CBooks bc('r');
  cout << bc;
  cout << "******************SHUFFLED\n";
  bc.shuffle();
  cout << bc;
  }


//addressByPos
//returns address of the node at a given position (0, 1, 2, 3)
CBook* CBooks::addressByPos(int pos)
  {
  CBook *p;

  p = head;

  //advance p (i-1 times)
  for (int j=0; j<=pos-1; j++)
    p = p->next;

  return p;
  }


//////////////////////////////////////////////////////////////////////
//revDisplay
//////////////////////////////////////////////////////////////////////
void CBooks::displayRev(void)
  {
  CBook *p;
  int i;

  for (i=count; i>=1; i--)
    {
    p = addressByPos(i-1);
    cout << *p;
    }

  }


//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
void testDisplayRev(void)
  {
  cout << "TEST DISPLAY REVERSE\n";
  CBooks bc('r');
  cout << bc;
  cout << "IN REVERSE ORDER\n";
  bc.displayRev();
  }

/*
void CBooks::sortInsertionByYear(void)
  {
  int i, k;
  CBook temp;

  for (i=1; i<=count-1; i++)
    {
    if (books[i-1].year <= books[i].year)
        continue;
    temp = books[i];
    k = i;
    while (true)
      {
      books[k] = books[k-1];
      k--;

      if ((0 == k) || (books[k-1].year <= temp.year))
          {
          books[k] = temp;
          break;
          }
      }
    }
  }


//////////////////////////////////////////////////////////////////////
//test function for sortSelectionByYear
//////////////////////////////////////////////////////////////////////
void testSortInsertionByYear(void)
  {
  int n = rand()% (MAX_BOOKS + 1);

  CBooks bc(n);
  cout << "Original\n";
  bc.display();

  if (bc.isSortedByYear())
      cout << "SORTED\n";
    else
      cout << "NOT SORTED\n";

  bc.sortInsertionByYear();
  cout << "After sort\n";
  bc.display();

  if (bc.isSortedByYear())
      cout << "SORTED\n";
    else
      cout << "NOT SORTED\n";

  }


*/
  
/*
//////////////////////////////////////////////////////////////////////
//sortBubbleByTitle()
//////////////////////////////////////////////////////////////////////
void CBooks::sortBubbleByTitle(void)
  {
  bool sorted;
  int i;
  
  do 
    {
    sorted = true;
    for (i=0; i<=count-2; i++)
      {
      if (strcmp(books[i].title, books[i+1].title) > 0) 
        {
        books[i].swap(books[i+1]);
        sorted = false;
        }
      }
    }
    while (!sorted); 
  }


//////////////////////////////////////////////////////////////////////
//test function for sortByTitle
//////////////////////////////////////////////////////////////////////
void testSortByTitle(void)
  {
  int n = rand()% (MAX_BOOKS + 1);

  CBooks bc(n);
  cout << "Original\n";
  bc.display();

  if (bc.isSortedByTitle())
      cout << "SORTED\n";
    else
      cout << "NOT SORTED\n";

  bc.sortBubbleByTitle();
  cout << "Sorted\n";
  bc.display();

  if (bc.isSortedByYear())
      cout << "SORTED\n";
    else
      cout << "NOT SORTED\n";

  }


//////////////////////////////////////////////////////////////////////
//checks if sorted by title
//////////////////////////////////////////////////////////////////////
bool CBooks::isSortedByTitle(void) const
  {
  if (count <= 1)
      return true;

  for (int i=0; i<=count-2; i++)
    {
    if (strcmp(books[i].title, books[i+1].title) > 0)
        return false;
    }
  
  return true;
  }


*/


/*
void CBooks::sortSelectionByYear(void)
  {
  int n = count;
  int iMax, vMax, i;
  while (n > 1)
    {
    iMax = 0;
    vMax = books[iMax].year;
    for (i=1; i<=n-1; i++)
      {
      if (books[i].year > vMax)
          {
          iMax = i;
          vMax = books[i].year;
          }
      }

    books[iMax].swap(books[n-1]);
    n--;
    }
  }


//////////////////////////////////////////////////////////////////////
//test function for sortSelectionByYear
//////////////////////////////////////////////////////////////////////
void testSortSelectionByYear(void)
  {
  int n = rand()% (MAX_BOOKS + 1);

  CBooks bc(n);
  cout << "Original\n";
  bc.display();

  if (bc.isSortedByYear())
      cout << "SORTED\n";
    else
      cout << "NOT SORTED\n";

  bc.sortSelectionByYear();
  cout << "Sorted\n";
  bc.display();

  if (bc.isSortedByYear())
      cout << "SORTED\n";
    else
      cout << "NOT SORTED\n";

  }

*/

//////////////////////////////////////////////////////////////////////
//CBooks(char ch) constructor
//////////////////////////////////////////////////////////////////////
CBooks::CBooks(char ch)
  {
  head = tail = NULL;
  count = 0;

  if (('r' == ch) || ('R' == ch))
      {
      int n = rand()%(MAX_BOOKS+1);

      for (int i=0; i<n; i++)
        this->add(CBook('r'));
      }
  }


//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
void testConstructorRandCBooks(void)
  {
  CBooks bc1('r'), bc2('s');
  cout << bc1 << endl;
  cout << endl;
  cout << bc2 << endl;
  }


//////////////////////////////////////////////////////////////////////
//insertion operator overloaded for output
//////////////////////////////////////////////////////////////////////
ostream & operator  << (ostream & john, const CBooks &bc)
  {
  john << "Book Collection[" << bc.count << "]= \n";
  /*
  CBook *p;
  p = bc.head;
  while (p != NULL)
    {
    john << *p;
    p = p->next;
    }

  john << endl;
  */

  for (CBook *p = bc.head; p != NULL; p = p->next)
    john << p << ": " << *p << endl;

  return john;
  }


//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
void testOperatorInsertionCBooks(void)
  {
  //CBooks bc1(5), bc2(5);

  CBooks bc1, bc2;

  cout << bc1 << bc2 << endl;
  }


//////////////////////////////////////////////////////////////////////
//compares for equality CBooks objects
//////////////////////////////////////////////////////////////////////
bool CBooks::operator ==(const CBooks &bc2) const
  {
  if (count != bc2.count)
      return false;

  CBook *p, *q;

  // if != overloaded for CBook
  for (p=head, q=bc2.head; p!=NULL; p=p->next, q=q->next)
    if (*p != *q)
      return false;

  return true;
  }


//////////////////////////////////////////////////////////////////////
//test operator equal
//////////////////////////////////////////////////////////////////////
void testOperatorEqualCBooks(void)
  {
    {
    CBooks bc1(5), bc2(5);
    cout << bc1;
    cout << bc2;

    if (bc1 == bc2)
        cout << "EQUAL\n";
      else
        cout << "NOT Equal\n";
    }

    {
    CBooks bc1, bc2;
    cout << bc1;
    cout << bc2;

    if (bc1 == bc2)
        cout << "EQUAL\n";
      else
        cout << "NOT Equal\n";

    CBooks bc3(bc1);
    if (bc1 == bc3)
        cout << "EQUAL\n";
      else
        cout << "NOT Equal\n";
    }
  }



//////////////////////////////////////////////////////////////////////
//compares for inequality CBooks objects
//////////////////////////////////////////////////////////////////////
bool CBooks::operator !=(const CBooks &bc2) const
  {
  return !((*this) == bc2);
  }


//////////////////////////////////////////////////////////////////////
//test operator not equal to
//////////////////////////////////////////////////////////////////////
void testOperatorNotEqualCBooks(void)
  {
    {
    CBooks bc1('r'), bc2('R');
    if (bc1 != bc2)
        cout << "Not EQUAL\n";
      else
        cout << "Equal\n";

    CBooks bc3(bc1);
    if (bc1 != bc3)
        cout << "NOT EQUAL\n";
      else
        cout << "Equal\n";
    }

    {
    CBooks bc1, bc2;
    if (bc1 != bc2)
        cout << "Not EQUAL\n";
      else
        cout << "Equal\n";

    /*
    CBooks bc3(bc1);
    if (bc1 != bc3)
        cout << "NOT EQUAL\n";
      else
        cout << "Equal\n";
    */
    }

  }


//////////////////////////////////////////////////////////////////////
//removeAll function
//////////////////////////////////////////////////////////////////////
void CBooks::removeAll(void)
  {
  while (head != NULL) 
    {
    tail=head; 
    head = head->next; 
    //cout << "deleting " << *tail;
    delete tail;
    }
  tail = NULL;
  count = 0;
  }


//////////////////////////////////////////////////////////////////////
//Cooks destructor 
//////////////////////////////////////////////////////////////////////
CBooks::~CBooks(void)
  {
  removeAll();
  }


//////////////////////////////////////////////////////////////////////
//add function
//////////////////////////////////////////////////////////////////////
int CBooks::add(const CBook &b)
  {
  CBook *p;
  p = new CBook;

  if (NULL == p) 
      return -1;

  strcpy(p->title, b.title);
  strcpy(p->author, b.author);
  p->year = b.year;
  p->next = NULL;

  if (NULL == head)
      head = tail = p;
    else
      {
      tail->next = p;
      tail = p;
      }

  count++;
  return count-1;
  }


//////////////////////////////////////////////////////////////////////
//add function
//////////////////////////////////////////////////////////////////////
int CBooks::add(char t[], char a[], int y)
  {
  CBook *p;
  p = new CBook;

  if (NULL == p) 
      return -1;

  strcpy(p->title, t);
  strcpy(p->author, a);
  p->year = y;
  p->next = NULL;

  if (NULL == head)
      head = tail = p;
    else
      {
      tail->next = p;
      tail = p;
      }

  count++;
  return count-1;
  }


//////////////////////////////////////////////////////////////////////
//test add
//////////////////////////////////////////////////////////////////////
void testAdd(void)
  {
  CBooks bc;
  cout << bc;
  for (int i=1; i<=5; i++)
    {
    cout << "+++++++++++++++++++++++++++\n";
    cout << bc.add("Title", "Author", i) << endl;
    cout << bc;
    }

  CBooks bc2;
  cout << bc2;
  for (int j=1; j<=5; j++)
    {
    cout << "+++++++++++++++++++++++++++\n";
    cout << bc2.add(CBook('r')) << endl;
    cout << bc2;
    }
  }


//////////////////////////////////////////////////////////////////////
//constructor CBooks()
//////////////////////////////////////////////////////////////////////
CBooks::CBooks(void)
  {
  count = 0;
  head = tail = NULL;
  }


//////////////////////////////////////////////////////////////////////
//constructor CBooks(n)
//////////////////////////////////////////////////////////////////////
CBooks::CBooks(int n)
  {
  if (n < 0) 
    n = 0;
  
  if (n > MAX_BOOKS)
    n = MAX_BOOKS;

  count = 0;
  head = tail = NULL;

  for (int i=0; i<n; i++)
    {
    this->add(CBook('r'));
    }
  }


//////////////////////////////////////////////////////////////////////
//constructor CBooks(CBooks bc)
//////////////////////////////////////////////////////////////////////
CBooks::CBooks(const CBooks &bc)
  {
  count =0;
  head = tail = NULL;
  CBook *p;

  for (p=bc.head; p!=NULL; p=p->next)
    this->add(*p);
  }


//////////////////////////////////////////////////////////////////////
//tes function for copy constructor
//////////////////////////////////////////////////////////////////////
void testConstructorCopyCBooks(void)
  {
  CBooks bc1('r'), bc2('r');

  cout << bc1 << bc2 << endl;
  CBooks bc3(bc2);
  cout << bc3;
  }


istream & operator  >> (istream & john, CBook &b)
  {
  cout << "Title:  "; john >> b.title;
  cout << "Author: "; john >> b.author;
  cout << "Year:   "; john >> b.year;

  return john;
  }

//////////////////////////////////////////////////////////////////////
//test function for insertion operator
//////////////////////////////////////////////////////////////////////
void testOperatorExtractionCBook(void)
  {
  CBook b1('r'), b2('r');

  cin >> b1 >> b2;
  cout << b1 << endl << b2 << endl;
  }


//////////////////////////////////////////////////////////////////////
//insertion operator overloaded for output
//////////////////////////////////////////////////////////////////////
ostream & operator  << (ostream & john, const CBook &b)
  {
  john << b.title ;
  john << ", " << b.author;
  john << ", " << b.year;

  return john;
  }


//////////////////////////////////////////////////////////////////////
//test function for insertion operator
//////////////////////////////////////////////////////////////////////
void testOperatorInsertionCBook(void)
  {
  CBook b1('r'), b2('r');

  cout << b1 << b2 << endl;
  }


//////////////////////////////////////////////////////////////////////
//assign operator for CBook overloaded
//////////////////////////////////////////////////////////////////////
CBook & CBook::operator = (const CBook &b2)
  {
  strcpy(title, b2.title);
  strcpy(author, b2.author);
  year = b2.year;
  return *this;
  }


//////////////////////////////////////////////////////////////////////
//test function for assign operator
//////////////////////////////////////////////////////////////////////
void testOperatorAssignCBook(void)
  {
  CBook b1('r'), b2('r'), b3('R');
  cout << b1;
  cout << b2;
  cout << b3;

  b1 = b2 = b3;
  cout << b1;
  cout << b2;
  cout << b3;
  }


//////////////////////////////////////////////////////////////////////
//operator != overloaded
//////////////////////////////////////////////////////////////////////
bool CBook::operator != (const CBook &b2) const
  {
  return !(*this == b2);
  }


//////////////////////////////////////////////////////////////////////
//test operator !=
//////////////////////////////////////////////////////////////////////
void testOperatorNotEqualCBook(void)
  {
  CBook b1('r'), b2('r');
  cout << b1;
  cout << b2;
  if (b1 != b2)
      cout << "NOT EQUAL\n";
    else
      cout << "EQUAL\n";

  b2 = b1;
  cout << b1;
  cout << b2;
  if (b1 != b2)
      cout << "NOT EQUAL\n";
    else
      cout << "EQUAL\n";

  }


//////////////////////////////////////////////////////////////////////
//operator == overloaded
//////////////////////////////////////////////////////////////////////
bool CBook::operator == (const CBook &b2) const
  {
  if (strcmp(this->title, b2.title) != 0)
      return false;

  if (strcmp(this->author, b2.author) != 0)
      return false;

  if (this->year != b2.year)
      return false;

  return true;
  }


//////////////////////////////////////////////////////////////////////
//test operator ==
//////////////////////////////////////////////////////////////////////
void testOperatorEqualCBook(void)
  {
  CBook b1('r'), b2('r');
  cout << b1;
  cout << b2;
  if (b1 == b2)
      cout << "EQUAL\n";
    else
      cout << "NOT EQUAL\n";

  b2 = b1;
  cout << b1;
  cout << b2;
  if (b1 == b2)
      cout << "EQUAL\n";
    else
      cout << "NOT EQUAL\n";

  }


//////////////////////////////////////////////////////////////////////
//destructor CBook
//////////////////////////////////////////////////////////////////////
CBook::~CBook(void)
  {
  }


//////////////////////////////////////////////////////////////////////
//function to initialize the contents of CBook variable
//////////////////////////////////////////////////////////////////////
CBook::CBook(char t[], char a[], int y)
  {
  strcpy((*this).title, t);//strcpy(title, t);
  strcpy(this->author, a); //strcpy(author, a);
  year = y;
  }


//////////////////////////////////////////////////////////////////////
//function to initialize the contents of CBook variable
//////////////////////////////////////////////////////////////////////
CBook::CBook(void)
  {
  strcpy((*this).title, "-1");
  strcpy(this->author, "-1");
  year = -1;
  }


//////////////////////////////////////////////////////////////////////
//function to initialize the contents of CBook variable
//////////////////////////////////////////////////////////////////////
CBook::CBook(const CBook &b)
  {
  strcpy(title, b.title);
  strcpy(author, b.author);
  year = b.year;
  }


//////////////////////////////////////////////////////////////////////
//function to input the contents of BookType variable
//////////////////////////////////////////////////////////////////////
CBook::CBook(char ch)
  {
  if (('i' == ch) || ('I' == ch))
      {
      cout << "Title:  "; cin >> title;
      cout << "Author: "; cin >> author;
      cout << "Year:   "; cin >> year;
      }
    else if (('r' == ch) || ('R' == ch))
      {
      strcpy(title, testTitles[rand()%MAX_TITLES]);
      strcpy(author, testAuthors[rand()%MAX_AUTHORS]);
      year = testYears[rand()%MAX_YEARS];
      }
    else
      {
      strcpy((*this).title, "-1");
      strcpy(this->author, "-1");
      year = -1;
      }

  }