C++ SparseArray class template for an array of arrays

Description

C++ SparseArray class template for an array of arrays

#include <string>
#include <iostream>
#include <memory>
using std::string;

template<typename T> class SparseArray
{
  class Node;//from w w  w . j a v a  2s.co  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
  void insert(T* pObj);                                      // Insert an element after the last

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;
  }

  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;
}

// Insert an element after the last
template<typename T> void SparseArray<T>::insert(T* pObj)
{
  PNode pNode;
  if (pLast)                          // If there is a last element add the new one after it
  {
    pNode = std::make_shared<Node>(pLast->index + 1);
    pLast->pNext = pNode;
    pNode->pPrevious = pLast;
    pLast = pNode;
  }
  else                               // Otherwise the new one is the first
    pFirst = pLast = pNode = std::make_shared<Node>(0);
  if (pObj)                           // If there is an object
    pNode->pObject = new T(*pObj);   // Create a duplicate
  else
    pNode->pObject = new T;          // Otherwise, create a default T
}
int main()
{
  string text;                               // Stores input prose or poem
  std::cout << "\nEnter a poem or prose over one or more lines."
    << "Terminate the input with #:\n";
  getline(std::cin, text, '#');

  SparseArray< SparseArray<string> > arrays; // Sparse array of arrays of strings
  string letters {"ABCDEFGHIJKLMNOPQRSTUVWXYZ"};

  // Extract words and store in the appropriate list
  string word;                                // Stores a word
  string separators {" \n\t,.\"?!;:"};       // Separators between words
  int start {};                           // Start of a word
  int end {};                             // separator position after a word
  while (string::npos != (start = text.find_first_not_of(separators, start)))
  {
    end = text.find_first_of(separators, start + 1);
    word = text.substr(start, end - start);
    arrays[letters.find(toupper(word[0]))].insert(&word);
    start = end;
  }

  // List the words in order 5 to a line
  const int perline {5};
  int count {};                           // Word counter
  int j {};
  for (int i {}; i < 26; ++i)
  {
    if (!arrays.element_exists(i))
      continue;
    j = 0;
    count = 0;
    while ((word = arrays[i][j++]).length())
    {
      std::cout << word << ' ';
      if (!(++count % perline))
        std::cout << std::endl;
    }
    std::cout << std::endl;
  }
  std::cout << std::endl;
}



PreviousNext

Related