C++ SparseArray class template

Description

C++ SparseArray class template

#include <cstdlib>
#include <ctime>
#include <string>
#include <iostream>
#include <iomanip>
#include <memory>
using std::string;

template<typename T> class SparseArray
{
  class Node;//from ww w  .j a  v  a  2 s .c o  m
  using PNode = std::shared_ptr < Node >;
private:
  PNode pFirst;                                              // Pointer to first element node
  PNode pLast;                                               // Pointer to last element node

public:
  SparseArray() = default;                                   // Constructor
  SparseArray(const SparseArray& array);                     // Copy constructor
  SparseArray& operator=(const SparseArray& array);          // Assignment operator
  T& operator[](int index);                               // Subscript SparseArray
  bool element_exists(int index);                         // Return true if element exists
  void show();                                               // display array elements

private:
  // Node class definition
  class Node
  {
  public:
    int index {};                       // Index of element
    T* pObject;                      // Address of object
    PNode pNext;                     // Pointer to next node
    PNode pPrevious;                 // Pointer to previous node

    Node(int newIndex) : index(newIndex), pObject(new T) {}                    // Constructor
    Node(const Node& node) : index(node.index), pObject(new T(*node.pObject)) {}  // Copy constructor
    ~Node(){ delete pObject; }                                                    // Destructor
  };
};
// Copy constructor template
template<typename T> SparseArray<T>::SparseArray(const SparseArray& array)
{
  if (array.pFirst)
  {                              // If there is a first element
    pLast = pFirst = std::make_shared<Node>(*array.pFirst);     // Duplicate it

    PNode pTemp;
    PNode pCurrent {array.pFirst};
    while (pCurrent = pCurrent->pNext)
    {                                                           // Duplicate any further nodes
      pTemp = pLast;                                            // Save the address of the last
      pLast = std::make_shared<Node>(*pCurrent);                // Make the new one the last
      pTemp->pNext = pLast;                                     // Set the next pointer of old last
      pLast->pPrevious = pTemp;                                 // Set previous pointer of new last
    }
  }
}

// Assignment operator template
template<typename T> SparseArray<T>& SparseArray<T>::operator=(const SparseArray& array)
{
  if (this == &array)                                           // Check for rhs same as lhs
    return *this;

  PNode pCurrent;
  if (array.pFirst)
  {
    pLast = pFirst = std::make_shared<Node>(*array.pFirst);
    Node* pTemp;
    pCurrent = array.pFirst;
    while (pCurrent = pCurrent->pNext)
    {
      pTemp = pLast;
      pLast = std::make_shared<Node>(*pCurrent);
      pTemp->pNext = pLast;
      pLast->pPrevious = pTemp;
      pTemp = pLast;
    }
  }
  return *this;
}

// Subscript operator for non-const objects
template<typename T> T& SparseArray<T>::operator[](int index)
{
  // Search the list for a node corresponding to index
  PNode pCurrent {pFirst};
  while (pCurrent)
  {
    if (pCurrent->index == index)
      return *pCurrent->pObject;
    if (pCurrent->index > index)
      break;
    pCurrent = pCurrent->pNext;
  }

  // If we get to here, the element doesn't exist
  // so we must create one
  PNode pNode = std::make_shared<Node>(index);
  pNode->pObject = new T;
  if (pCurrent)                                                 // If its not the end of the list we must insert the element
  {
    if (pCurrent->pPrevious)                                    // If current has a previous node just insert the new node
    {
      pCurrent->pPrevious->pNext = pNode;
      pNode->pPrevious = pCurrent->pPrevious;
      pCurrent->pPrevious = pNode;
      pNode->pNext = pCurrent;
    }
    else                                                        // Current must be the first so add new node as first
    {
      pNode->pNext = pCurrent;
      pCurrent->pPrevious = pNode;
      pFirst = pNode;
    }
  }
  else
  {                                                             // We must append the element
    if (pLast)
    {
      pLast->pNext = pNode;
      pNode->pPrevious = pLast;
      pLast = pNode;
    }
    else
      pFirst = pLast = pNode;
  }
  return *pNode->pObject;                                       // Return the new element
}

// Display the elements of a SparseArray
template<typename T> void SparseArray<T>::show()
{
  PNode pCurrent {pFirst};
  while (pCurrent)
  {
    std::cout << "\n[" << std::setw(2) << pCurrent->index << "] = " << *pCurrent->pObject;
    pCurrent = pCurrent->pNext;
  }
  std::cout << std::endl;
}

// Test for existence of element at index
template<typename T>
bool SparseArray<T>::element_exists(int index)
{
  PNode p {pFirst};
  while (p)
  {
    if (p->index == index) return true;
    p = p->pNext;
  }
  return false;
}

// Function to generate a random integer 0 to count-1
int random(int count)
{
  return static_cast<int>((count*static_cast<unsigned long>(rand()))/(RAND_MAX+1UL));
}

int main()
{
  SparseArray<int> numbers;                 // Create sparse array
  const int count {20};                  // Number of elements to be created
  int index {};                          // Stores new index value
  srand((unsigned)time(0));                 // Seed random number generator

  try
  {
    for (int i {}; i < count; ++i)       // Create count entries in numbers array
    {
      // Must ensure that indexes after the first are not duplicates
      for(;;)
      {
        index = random(500);                // Get a random index 0 to 499
        if (numbers.element_exists(index)) continue;
        break;                              // We have a unique index
      }
      numbers[index] = 32+random(181);      // Store value at new index position
    }
  }
  catch(std::exception& e)
  {
    std::cout << "\nException thrown " << e.what() << std::endl;
  }
  numbers.show();
}



PreviousNext

Related