Monday, April 3, 2017

Programming Challenge 9.13 - Movie Statistics

/* Movie Statistics - This program can be used to gather statistical
   data about the number of movies college students see in a month.
   The program performs the following steps:
 
      * Ask the user how many students were surveyed. An array
        of integers with this many elements is then dynamically
        allocated.

      * The user is allowed to enter the number of movies each
        student saw into the array.

      * The average, median, and mode of the values entered is
        calculated and displayed. The functions written in
        Programming Challenge 9.8 and 9.9 are used to calculate
        the median and mode.

   Input Validation: No negative numbers are accepted for input. */

#include "Utility.h"

/* Function prototypes */
void mainMenu();
void getNumbers(int *, int);
void sortNumbers(int *, int);
double getAverage(int *, int);
double getMedian(int *, int);
void getFrequency(int *, int *, int);
void sortStats(int *, int *, int);
int getMode(int *, int *, int *, int);
void displayData(int *, double, double, int, int);
void displayHistogram(int *, int *, int);
void freeMem(int *, int *, int *);

int main()
{
   mainMenu();

   pauseSystem();
   return 0;
}

/* **********************************************************
   Definition: mainMenu

   This function offers a menu with the following options:

      * Enter survey data
      * View survey results
      * View histogram
      * Quit

   It calls all other functions to process the data once
   entered.
   ********************************************************** */

void mainMenu()
{
   const int SURVEY_DATA = 1,
             VIEW_RESULTS = 2,
             VIEW_HISTOGRAM = 3,
             QUIT = 4;

   int *numMovies = nullptr;
   int *frequency = nullptr;
   int *modes = nullptr;

   int surveyed = 0,
       mode = 0,
       menuItem = 0;

   double average = 0.0,
          median = 0.0;

   do
   {
      cout << "\n\n\tOka Gakuen Movie Club\n\n"
           << "\n\tMAIN MENU\n"
           << "\t--------------------\n"
           << "\t1. ENTER SURVEY DATA\n"
           << "\t2. VIEW SURVEY RESULTS\n"
           << "\t3. VIEW HISTOGRAM\n"
           << "\t4. QUIT\n\n"
           << "\tSELECT ITEM: ";
      cin >> menuItem;

      /* Input Validation */
      while (menuItem < SURVEY_DATA || menuItem > QUIT)
      {
         cin >> menuItem;
      }

      switch (menuItem)
      {
         case SURVEY_DATA:
         {      
            cout << "\n\n\tHow many students have been surveyed? ";
            cin >> surveyed;

            /* Dymically allocated arrays to hold the number of
               movies each student has watched, the frequency of
               numbers, and the modes */
            numMovies = new int[surveyed]();
            frequency = new int[surveyed]();
            modes = new int[surveyed]();

            /* Gets the number of movies each student watched */
            getNumbers(numMovies, surveyed);

            /* Sorts the numbers using an selection-sort algorithm */
            sortNumbers(numMovies, surveyed);

            /* Calculates the average number of movies watched */
            average = getAverage(numMovies, surveyed);

            /* Determines and returns the median */
            median = getMedian(numMovies, surveyed);

            /* Determines and stores the frequency of numbers
               in numMovies */
            getFrequency(numMovies, frequency, surveyed);

            /* Sorts the elements in numList and frequency in
               descending order using an dual-selection-sort
               algorithm */
            sortStats(numMovies, frequency, surveyed);

            /* Determines and stores the mode(s) in modes if there
               are any. If there is no mode, -1 is returned. */
            mode = getMode(numMovies, frequency, modes, surveyed);
         }
         break;

         case VIEW_RESULTS:
         {
            displayData(modes, average, median, mode, surveyed);
         }
         break;

         case VIEW_HISTOGRAM:
         {
            displayHistogram(numMovies, frequency, surveyed);
         }
         break;

         case QUIT:
         {
            cout << "\n\tNow closing the program ...\n\n";
         }
         break;
      }

   } while (menuItem != QUIT);

   /* Frees the memory */
   freeMem(numMovies, frequency, modes);
}

/* **********************************************************
   Definition: getNumbers

   This function accepts numMovies and surveyed, indicating
   the number of elements contained in the array. It asks the
   user to enter the number of movies each student watched.
   ********************************************************** */

void getNumbers(int *numMovies, int surveyed)
{
   cout << "\n\n\tNumber of movies watched:\n"
        << "\t------------------------\n";

   for (int index = 0; index < surveyed; index++)
   {
      cout << "\tStudent #" << (index + 1) << ": ";
      cin >> *(numMovies + index);

      /* Input Validation */
      while (*(numMovies + index) <= 0)
      {
         cout << "\tStudent #" << (index + 1) << ": ";
         cin >> *(numMovies + index);
      }
   }
}

/* **********************************************************
   Definition: sortNumbers

   This function accepts numMovies and surveyed as arguments.
   It uses a selection-sort algorithm to sort the numbers in
   an ascending order.
   ********************************************************** */

void sortNumbers(int *numMovies, int surveyed)
{
   int startScan = 0,
       index = 0,
       minIndex = 0,
       minEl = 0;

   for (startScan = 0; startScan < surveyed; startScan++)
   {
      minIndex = startScan;
      minEl = *(numMovies + startScan);

      for (index = startScan + 1; index < surveyed; index++)
      {
         if (*(numMovies + index) < minEl)
         {
            minEl = *(numMovies + index);
            minIndex = index;
         }
      }

      *(numMovies + minIndex) = *(numMovies + startScan);
      *(numMovies + startScan) = minEl;
   }
}

/* **********************************************************
   Definition: getAverage

   This function accepts numMovies and surveyed as arguments.
   It calculates the average number of movies watched. This
   number is returned from the function.
   ********************************************************** */

double getAverage(int *numMovies, int surveyed)
{
   double total = 0.0;
   double average = 0.0;

   for (int index = 0; index < surveyed; index++)
   {
      total += *(numMovies + index);
   }

   return average = total / surveyed;
}

/* **********************************************************
   Definition: getMedian

   This function accepts numMovies and surveyed as arguments.
   It determines the median and returns it.
   ********************************************************** */

double getMedian(int *numMovies, int surveyed)
{
   double median = 0.0,
          midLower = 0.0,
          midUpper = 0.0;

   int      middleElem = surveyed / 2;
 
   surveyed % 2 == 0 ? midLower = *(numMovies + middleElem - 1),
                       midUpper = *(numMovies + middleElem),
                       median = (midUpper + midLower) / 2 :
                       median = *(numMovies + middleElem);

   return median;
}

/* **********************************************************
   Definition: getFrequency

   This function accepts numMovies, frequency and surveyed as
   arguments. It counts the numbers stored in numMovies,
   totals these numbers, and stores the result in frequency.
   ********************************************************** */

void getFrequency(int *numMovies, int *frequency, int surveyed)
{
   int total = 0,
       count = 0;

   /* Find numbers that are equal, and count these */
   for (int index = 0; index < surveyed; index++)
   {
      total = 0;
      count = 1;

      while (*(numMovies + index) == *(numMovies + index + 1))
      {
         count++;
         index++;
      }

      total = count;
      *(frequency + index) = total;
   }
}

/* **********************************************************
   Definition: sortStats

   This function accepts numMovies, frequency and surveyed as
   arguments. It uses a dual-selection-sort algorithm to sort
   numMovies and frequency in descending order.
   ********************************************************** */

void sortStats(int *numMovies, int *frequency, int surveyed)
{
   int startScan = 0,
       index = 0,
       maxIndex = 0,
       tempList = 0,
       maxEl = 0;

   for (startScan = 0; startScan < surveyed; startScan++)
   {
      maxIndex = startScan;
      maxEl = *(frequency + startScan);
      tempList = *(numMovies + startScan);

      for (index = startScan + 1; index < surveyed; index++)
      {
         if (*(frequency + index) > maxEl)
         {
            maxEl = *(frequency + index);
            tempList = *(numMovies + index);
            maxIndex = index;
         }
      }

      *(frequency + maxIndex) = *(frequency + startScan);
      *(numMovies + maxIndex) = *(numMovies + startScan);

      *(frequency + startScan) = maxEl;
      *(numMovies + startScan) = tempList;
   }
}

/* **********************************************************
   Definition: getMode

   This function accepts numMovies, frequency, modes, and
   surveyed as arguments. First the function determines
   whether there is a mode, and if there is, it is stored in
   modes. If there is no mode, -1 is returned.
   ********************************************************** */

int getMode(int *numMovies, int *frequency, int *modes, int surveyed)
{
   int index = 0,
       frHigh = 0,
       mode = 0;

   /* If all numbers in numList are the same, 3, 3, 3, or if
      frequency equals 1, meaning that no number has a higher
      occurence than any others, mode gets -1. */
   if (*(numMovies + index) == *(numMovies + index + 1) ||
       *(frequency + index) == 1)
   {
      mode = -1;
   }

   for (int index = 0; index < surveyed; index++)
   {
      if (*(frequency + index) > frHigh)
      {
         frHigh = *(frequency + index);
      }

      if (frHigh == *(frequency + index))
      {
         *(modes + index) = *(numMovies + index);
      }
   }

   return mode;
}

/* **********************************************************
   Definition: displayData

   This function accepts modes, average, median, mode, and
   surveyed as arguments. It displays the mode(s), average
   number of movies watched by all students, and the median
   or middle value.
   ********************************************************** */

void displayData(int *modes, double average, double median,
                 int mode, int surveyed)
{
   cout << fixed << showpoint << setprecision(2);

   cout << "\n\n\tOka Gakuen Movie Club - Survey Results\n\n"
        << "\n\tAccording to our survey, in which " << surveyed
        << " students have\n"
        << "\tkindly participated, the average number of movies\n"
        << "\twatched has been " << average << "\n\n"
        << "\tThe median, or middle value we found, was " << median
        << "\n\n";

   if (mode != -1)
   {
      cout << "\tThese mode(s), or numbers occuring most frequently\n"
           << "\tin our survey, have been discovered: \n\n";

      for (int index = 0; index < surveyed; index++)
      {
         if (*(modes + index) > 0)
         {
            cout << "\tMode #" << (index + 1) << setw(14) << right
               << *(modes + index) << " \n";
         }
      }
   }
   else
   {
      cout << "\n\tOur survey does not contain any modes ...\n\n";
   }
}


/* **********************************************************
   Definition: displayHistogram

   This function accepts numMovies, frequency and surveyed as
   arguments. It displays the number of movies watched. The
   numbers are displayed in order of frequency. If there are
   no numbers with higher frequency, then the numbers are
   displayed from lowest to highest.
   ********************************************************** */

void displayHistogram(int *numMovies, int *frequency, int surveyed)
{
   int index = 0,
       total = 0,
       count = 0;

   cout << "\n\n\tOka Gakuen Movie Club - Survey Histogram\n\n"
        << "\tMOVIES WATCHED: " << setw(17) << right
        << "FREQUENCY:" << setw(17) << right
        << "HISTOGRAM:\n";

   cout << "\t--------------" << setw(18) << right
        << "---------" << setw(17) << right
        << "---------\n";

   for (index = 0; index < surveyed; index++)
   {
      total = 0;

      if (*(frequency + index) > 0)
      {
         total = *(frequency + index);

         cout << setw(11) << right << *(numMovies + index)
              << setw(22) << right << *(frequency + index)
              << setw(15) << right;

         for (count = 1; count <= total; ++count)
         {
            cout << "*";
         }
         cout << "\n";
      }
   }
}

/* **********************************************************
   Definition: freeMem

   This function accepts numMovies, frequency, and modes as
   arguments. It frees the allocated memory before the
   program exits.
   ********************************************************** */

void freeMem(int *numMovies, int *frequency, int *modes)
{
   delete[] numMovies;
   delete[] frequency;
   delete[] modes;

   numMovies = nullptr;
   frequency = nullptr;
   modes = nullptr;
}

Example Output:








No comments:

Post a Comment