/****************************************************************************** * ************************************************************************** * * * ********************************************************************** * * * * * ****************************************************************** * * * * * * * ************************************************************** * * * * * * * * * ********************************************************** * * * * * * * * * * * ****************************************************** * * * * * * * * * * * * * ************************************************** * * * * * * * * * * * * * * * ********************************************** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Please do not read this until * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * after you have made a serious * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * attempt at writing all the * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * code, including templates. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Reading the solution will not * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * help you understand how to program. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ********************************************** * * * * * * * * * * * * * * * ************************************************** * * * * * * * * * * * * * ****************************************************** * * * * * * * * * * * ********************************************************** * * * * * * * * * ************************************************************** * * * * * * * ****************************************************************** * * * * * ********************************************************************** * * * ************************************************************************** * ******************************************************************************/ /****************************************************************************** * ************************************************************************** * * * ********************************************************************** * * * * * ****************************************************************** * * * * * * * ************************************************************** * * * * * * * * * ********************************************************** * * * * * * * * * * * ****************************************************** * * * * * * * * * * * * * ************************************************** * * * * * * * * * * * * * * * ********************************************** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * YOU HAVE BEEN WARNED :-) * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ********************************************** * * * * * * * * * * * * * * * ************************************************** * * * * * * * * * * * * * ****************************************************** * * * * * * * * * * * ********************************************************** * * * * * * * * * ************************************************************** * * * * * * * ****************************************************************** * * * * * ********************************************************************** * * * ************************************************************************** * ******************************************************************************/ #ifndef ARRAY_H #define ARRAY_H #include #include #include #include "Exception.h" template class Array { private: int array_capacity; Type *internal_array; int array_size; public: Array( int = 10 ); Array( Array const & ); ~Array(); int size() const; int capacity() const; bool empty() const; bool full() const; Type operator[]( int ) const; Type sum() const; double average() const; double variance() const; double std_dev() const; Array &operator=( Array ); void swap( Array & ); bool append( Type const & ); void clear(); // Friends: this is a global function template friend std::ostream &operator<<( std::ostream &, Array const & ); }; /* * Constructor * * Create a new array with a capacity of at least one. * The default value of the argument is 10. * * The array is initially empty, and * there is no need to zero out the entries of the array; */ template Array::Array( int n ): array_capacity( std::max( n, 1 ) ), internal_array( new Type[capacity()] ), array_size( 0 ) { // does nothing } /* * Copy constructor * * Make a deep copy of the argument array. */ template Array::Array( Array const &other ): array_capacity( other.capacity() ), internal_array( new Type[capacity()] ), array_size( other.size() ) { for ( int i = 0; i < other.size(); ++i ) { internal_array[i] = other.internal_array[i]; } } /* * Destructor * * Deallocate the memory assigned to 'internal_array' */ template Array::~Array() { delete [] internal_array; } /* * Size * * Return the number of objects currently stored in this array. */ template int Array::size() const { return array_size; } /* * Capacity * * Return the capacity of this array (the maximum number of objects * this array can store). */ template int Array::capacity() const { return array_capacity; } /* * Empty * * Returns true if the array is empty (the size is 0), and false otherwise. */ template bool Array::empty() const { return (size() == 0); } /* * Full * * Returns true if the number of objects stored in the array (the size) * equals the capacity. */ template bool Array::full() const { return (size() == capacity()); } /* * operator[]( int n ) * * If n >= 0 and n < size(), return the object stored at index n of this array. * If n < 0, throw an underflow exception. * If n >= size(), throw an overflow exception. */ template Type Array::operator[]( int n ) const { return internal_array[n]; } /* * Sum * * Return the sum of the objects stored in this array. */ template Type Array::sum() const { Type result = 0; for ( int i = 0; i < array_size; ++i ) { result += internal_array[i]; } return result; } /* * Average * * Calculate the arithmetic average of the entries in the array. * The average is not defined if the array is empty, throw an underflow exception. */ template double Array::average() const { if ( empty() ) { throw underflow(); } // The average is the sum of the entries divided by the size return static_cast( sum() )/static_cast( size() ); } /* * Variance * * Calculate the sample variance of the entries in the array. * This value is the sum of the squares of the differences of * the entries divided by the size minus 1. * * The sample variance is not defined if the array does not * have at least two objects in it, throw an underflow exception. */ template double Array::variance() const { if ( size() <= 1 ) { throw underflow(); } double av = average(); // Calculate the sum of the squares of the differences // between the objects and the average. double ssdiff = 0.0; for ( int i = 0; i < size(); ++i ) { ssdiff += (internal_array[i] - av)*(internal_array[i] - av); } // Return the sum divided by the size minus 1 return ssdiff/(size() - 1); } /* * Standard deviation * * Calculate the sample standard deviation of the entries in the array. * This value is the square root of the sample variance. * * The sample standard deviation is not defined if the array does not * have at least two objects in it, throw an underflow exception. */ template double Array::std_dev() const { // variance() will throw an exception if size() < 2 return std::sqrt( variance() ); } /* * Swap * * Swap the member variables of 'this' object and those of * the argument 'other'. * * We are using the standard library 'swap' function. */ template void Array::swap( Array &other ) { std::swap( array_capacity, other.array_capacity ); std::swap( internal_array, other.internal_array ); std::swap( array_size, other.array_size ); } /* * Assignment operator * * Assign the argument to this array. */ template Array &Array::operator=( Array rhs ) { swap( rhs ); return *this; } /* * Append * * If the array is full, do nothing and return false. * * Otherwise, append the argument to the next available location * in the array, increment the array size, and return true. */ template bool Array::append( Type const &obj ) { if ( full() ) { return false; } // currently, entries 0, ..., array_size - 1 are occupied internal_array[array_size] = obj; ++array_size; return true; } /* * Clear * * Empty the array; that is, set the array size to 0. * * Note: nothing else has to be done here. We do not have * to delete the array, we do not have to set the entries in * the array to 0, nullptr or anything else. */ template void Array::clear() { array_size = 0; } /* * Printing the array * * This is a globally defined function, and therefore it is not a member variable * of the Array class. In order for this function to access the private member variables * and (though none in this example) private member functions, this global function * must be declared to be a 'friend' of the Array class. If you return to the Array class * definition, you will see the statement. * * The format of the printing will be to create the string where: * - each value is displayed, and * - any entries that are available but not filled are displayed with a '-' * * For example, the array with default size after having 2, 3 and 4 appended would be * displayed as the string * "2 3 4 - - - - - - -" * * Note to interested students: * If you enter * cout << my_array; * the compiler treats this as a call to the global function operator<<( cout, my_array ), * and the function below takes as its arguments an ostream object and an Array object. * * You will note that this globally defined overloaded operator takes two arguments, * while the overloaded assignment operator declared as a class member takes only * one argument. In essence, if @ is any operator (+, -, *, /, =, <<, etc.) and the * compiler sees x @ y where x and y are instances of classes XX and YY, then: * * If the class XX has a member function operator@( YY ), it will call that * member function. * * If there is globally defined function operator@( XX, YY ), it will call that one. * * In this case, because the user is unable to add a member function to the 'ostream' * class, we must go the route of declaring a global function. */ template std::ostream &operator<<( std::ostream &out, Array const ¶m ) { if ( param.empty() ) { out << "-"; } else { out << param.internal_array[0]; } for ( int i = 1; i < param.size(); ++i ) { out << " " << param.internal_array[i]; } for ( int i = param.size(); i < param.capacity(); ++i ) { out << " -"; } return out; } #endif