#define NIL 0
#include <iostream.h>

// template list node header
struct ListNode {
     int data;
     ListNode *next;
     };
    
// template list header
class List {
public:
    List (void); 
    /* pre:  true;
      post:  the list is initialized */

    void insert (int item);  
    /* pre:  the list has been initialized
      post:  the specified item is placed at the front of the list  */

    bool isin (int item);
    /* pre:  the list has been initialized
      post:  function returns TRUE if item is in list and FALSE otherwise */

    void print (void);
    /* pre:  the list has been initialized
      post:  a title is printed, followed by the items from front to back */

    void print_reverse (void);
    /* pre:  the list has been initialized
      post:  a title is printed, followed by the items from back to front */

    void count (void);
    /* pre:  the list has been initialized
      post:  the items in the list are counted and printed */

protected:  // allow access to first in derived classes (e.g., OrderedList)
    ListNode *first;

private:    // these functions can be accessed only by class List functions
    void printData (ListNode *front);
    void printReverse (ListNode *front);
    int countNode (ListNode *front);

}; // List


// template ordered list header
class OrderedList : public List{//follows unordered list, except for insert
public:
    void insert (int item);  
    /* pre:  the list has been initialized
      post:  the item is placed in the list to maintain ordering by < */

protected: 
    void rec_insert (int item, ListNode **front);
}; // OrderedList

// template list implementation

List::List (void)   
    /* pre:  true;
      post:  the List is initialized */
{   first=NIL;
}


void List::insert (int item)
    /* pre:  the list has been initialized
      post:  the specified item is placed at the front of the list  */
{  ListNode *temp = new ListNode;
   temp->data=item;
   temp->next=first;
   first = temp;
}

bool List::isin (int item)
    /* pre:  the list has been initialized
      post:  function returns TRUE if item is in list and FALSE otherwise */
{   ListNode *temp = first;
    while (temp) {
       if (temp->data == item)
          {return (true);}
          else {temp = temp->next;}
    }
    return (false);
}

void List:: print (void)
    /* pre:  the list has been initialized
      post:  a title is printed, followed by the items from front to back */
{   cout << "The items on the list, from front to back, are:" << endl;
    printData(first);

}

void List::print_reverse (void)
    /* pre:  the list has been initialized
      post:  a title is printed, followed by the items from back to front */
{   cout << "The items on the list, from back to front, are:" << endl;
    printReverse(first);
}

void List::count (void)
    /* pre:  the list has been initialized
      post:  the items in the list are counted and printed */
{   cout << "The number of nodes in the list is " << countNode (first) << endl;
}

void List::printData (ListNode *front)
{   if (front != NIL) {
        cout << front->data << endl;
        List::printData (front->next);}
}


void List::printReverse (ListNode *front)
{   if (front != NIL) {
        List::printReverse (front->next);
        cout << front->data << endl;}
}

int List::countNode (ListNode *front)
/* helping function to recursively count the number of nodes in the list */
{   if (front == NIL)
        return (0);
        else return (1 + List::countNode(front->next));
}

void OrderedList::insert (int item)
    /* pre:  the list has been initialized
      post:  the specified item is placed at the front of the list  */
{  rec_insert(item, &first);
}

void OrderedList::rec_insert (int item, ListNode **front)
    /* pre:  the list has been initialized
      post:  the specified item is placed at the front of the list  */
{ if ((*front == NIL) || (item < (*front)->data))
     { ListNode *temp = new ListNode;
       temp->data=item;
       temp->next=*front;
       *front = temp;
     } else { rec_insert (item, &((*front)->next));}
}
