sllistUtils0.h


#ifndef SLLISTUTILS_H
#define SLLISTUTILS_H

#include <cstdlib>  // for NULL


/**
 *  Utility operations for singly linked lists
 *
 */




template <typename Data>
struct LListNode
{
  Data data;
  LListNode<Data>* next;

  LListNode() {next = 0;}
  LListNode (const Data& d, LListNode<Data>* nxt = 0)
    : data(d), next(nxt)
  {}
};


template <typename Data>
struct LListHeader {

  LListNode<Data>* first;

  LListHeader();

  void addToFront (const Data& value);
  void addToEnd (const Data& value);

  // Add value after the indicated position
  void addAfter (LListNode<Data>* afterThis, const Data& value);
  
  // Add value before the indicated position
  void addBefore (LListNode<Data>* beforeThis, const Data& value);

  // Add value in sorted order.
  //Pre: all existing values are already ordered
  void addInOrder (const Data& value);

  // Remove value at the indicated position
  void remove (LListNode<Data>* here);
  
  // Add value after the indicated position
  void removeAfter (LListNode<Data>* afterThis);


  // Search for a value. Returns null if not found
  LListNode<Data>* find (const Data& value) const;

  // Search an ordered list for a value. Returns null if not found
  LListNode<Data>* findOrdered (const Data& value) const;


  // Empty the list
  void clear();

};



template <typename Data>
LListHeader<Data>::LListHeader()
  : first(NULL)
{}

template <typename Data>
void LListHeader<Data>::addToFront (const Data& value)
{
  LListNode<Data>* newNode = new LListNode<Data>(value, first);
  first = newNode;
}

template <typename Data>
void LListHeader<Data>::addToEnd (const Data& value)
{ 
  LListNode<Data>* newNode = new LListNode<Data>(value, NULL);
  if (first == NULL)
    {
      first = newNode;
    }
  else
    {
      // Move to last node 
      LListNode<Data>* current = first;
      while (current->next != NULL)
	current = current->next;
      
      // Link after that node
      current->next = newNode;
    }
}

// Add value after the indicated position
template <typename Data>
void LListHeader<Data>::addAfter (LListNode<Data>* afterThis, const Data& value)
{
  LListNode<Data>* newNode = new LListNode<Data>(value, afterThis->next);
  afterThis->next = newNode;
}
  
  // Add value before the indicated position
template <typename Data>
void LListHeader<Data>::addBefore (LListNode<Data>* beforeThis, const Data& value)
{
  if (beforeThis == first)
    addToFront (value);
  else
    {
      // Move to front of beforeThis
      LListNode<Data>* current = first;
      while (current->next != beforeThis)
	current = current->next;
      
      // Link after that node
      addAfter (current, value);
    }
}

// Add value in sorted order.
//Pre: all existing values are already ordered
template <typename Data>
void LListHeader<Data>::addInOrder (const Data& value)
{
  if (first == NULL)
    first = new LListNode<Data>(value, NULL);
  else 
    {
      LListNode<Data>* current = first;
      LListNode<Data>* prev = NULL;
      while (current != NULL && value < current->data)
	{
	  prev = current;
	  current = current->next;
	}
      // Add between prev and current
      if (prev == NULL)
	addToFront (value);
      else
	addAfter (prev, value);
    }
}


// Add all values from another list onto the end of this one
template <typename Data>
void LListHeader<Data>::append (const LListHeader<Data>& list)
{
  // Move to last node 
  LListNode<Data>* last = first;
  while (last->next != NULL)
    last = last->next;

  // Append new nodes onto end of list
  const LListNode<Data>* current = list.first;
  while (current != NULL)
    {
      LListNode<Data>* newNode = new LListNode<Data>(current->data, NULL);
      if (last != NULL)
	  last->next = newNode;
      last = newNode;
    }
}

// Remove value at the indicated position
template <typename Data>
void LListHeader<Data>::remove (LListNode<Data>* here)
{
  if (here == first)
    {
      LListNode<Data>* after = first->next;
      delete first;
      first = after;
    }
  else
    {
      LListNode<Data>* prev = first;
      while (prev->next != here)
	prev = prev->next;
      prev->next = here->next;
      delete here;
    }
}


  
  // Remove value after the indicated position
template <typename Data>
void LListHeader<Data>::removeAfter (LListNode<Data>* afterThis)
{
  LListNode<Data>* toRemove = afterThis->next;
  afterThis->next = toRemove->next;
  delete toRemove;
}


  // Search for a value. Returns null if not found
template <typename Data>
LListNode<Data>* LListHeader<Data>::find (const Data& value) const
{
  LListNode<Data>* current = first;
  while (current != NULL && value != current->data)
    current = current->next;
  return current;
}

  // Search an ordered list for a value. Returns null if not found
template <typename Data>
LListNode<Data>* LListHeader<Data>::findOrdered (const Data& value) const
{
  LListNode<Data>* current = first;
  while (current != NULL && value < current->data)
    current = current->next;
  if (current != NULL && value == current->data)
    return current;
  else
    return NULL;
}

template <typename Data>
void LListHeader<Data>::clear()
{
  LListNode<Data>* current = first;
  LListNode<Data>* nxt = NULL;
  while (current != NULL)
    {
      nxt = current->next;
      delete current;
      current = nxt;
    }
  first = NULL;
}

#endif