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:








Sunday, April 2, 2017

Programming Challenge 9.12 - Element Shifter

/* Element Shifter - This program contains a function that accepts an
   int array and the array's size as arguments. The function creates
   a new array that is one element larger than the argument array. The
   first element of the new array is set to 0. Element 0 of the argument
   array is copied to element 1 of the new array, element 1 of the
   argument array is copied to element 2 of the new array, and so forth.
   The function returns a pointer to the new array. */

#include "Utility.h"

/* Function prototypes */
void getNumbers(int *, int);
void displayNumbers(const int *, const int);
int *shiftElements(const int *, int &, const int);
void displayShifted(const int *, const int);
void freeMem(int *, int *);

int main()
{
   int *numbers = nullptr;
   int *shifted = nullptr;

   int numels = 0,
       elemSize = 0;

   /* Ask for the number of elements the array should to hold */
   cout << "\n\tELEMENT SHIFTER\n\n"
        << "\tHow many numbers should your set contain? ";
   cin >> numels;

   /* Input Validation */
   while (numels <= 0)
   {
      cout << "\n\tInvalid Input!\n"
           << "\tHow many numbers should your set contain? ";
      cin >> numels;
   }

   /* Allocates a new array to hold the numbers */
   numbers = new int[numels];

   /* Creates a set of random numbers to fill the numbers array */
   getNumbers(numbers, numels);

   /* Displays the numbers in their original order */
   displayNumbers(numbers, numels);

   cout << "\n\n\tNow shifting the elements by one ...\n\n";

   /* Shifts the elements in the argument array */
   shifted = shiftElements(numbers, elemSize, numels);

   /* Displays the new array with elements shifted by one
      position */
   displayShifted(shifted, elemSize);

   /* Frees the memory */
   freeMem(numbers, shifted);

   pauseSystem();
   return 0;
}

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

   This function accepts numbers and numels as arguments. It
   fills numbers with (pseudo)random numbers in the range of
   1 through 200.
   ********************************************************** */

void getNumbers(int *numbers, int numels)
{
   const int MIN_NUM = 1,
             MAX_NUM = 200;

   srand((unsigned int) time(NULL));

   for (int index = 0; index < numels; index++)
   {
      *(numbers + index) = (rand() % (MAX_NUM - MIN_NUM + 1) + MIN_NUM);
   }
}

/* **********************************************************
   Definition: displayNumbers

   This function accepts numbers and numels as arguments. It
   displays the numbers in their original order.
   ********************************************************** */

void displayNumbers(const int *numbers, const int numels)
{
   cout << "\n\tThese are your numbers in their original order:\n\n";

   for (int index = 0; index < numels; index++)
   {
      cout << "\t" << *(numbers + index) << " \n";
   }
}

/* **********************************************************
   Definition: shiftElements

   This function accepts numbers, elemSize, and numels as
   arguments. It creates a new array, one element larger than
   numbers, the first element being initialized to 0. The
   elements are shifted by one position, each time an element
   from the argument array is copied to the new array. When
   finished, a pointer to the new array is returned.
   ********************************************************** */

int *shiftElements(const int *numbers, int &elemSize, const int numels)
{
   int *elemShifter = nullptr;

   int firstElem = 0,
       nextElem = 0;

   elemSize = numels + 1;

   /* Allocates a new array, one element larger than the argument
      array, to hold the shifted elements */
   elemShifter = new int[elemSize]();

   while (firstElem < numels)
   {
      ++nextElem;

      *(elemShifter + nextElem) = *(numbers + firstElem);

      ++firstElem;
   }

   return elemShifter;
}

/* **********************************************************
   Definition: displayShifted

   This function accepts shifted and elemSize as arguments.
   It displays the numbers in the new array, after having
   been shifted by 1 position.
   ********************************************************** */

void displayShifted(const int *shifted, const int elemSize)
{
   cout << "\n\tThese are your numbers after being shifted "
        << "by 1 position:\n\n";

   for (int index = 0; index < elemSize; index++)
   {
      cout << "\t" << *(shifted + index) << " \n";
   }
}

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

   This function accepts numbers and shifted as arguments. It
   frees the memory before the program exits.
   ********************************************************** */

void freeMem(int *numbers, int *shifted)
{
   delete[] numbers;
   delete[] shifted;

   numbers = nullptr;
   shifted = nullptr;
}

Example Output:




Programming Challenge 9.11 - Array Expander

/* Array Expander - This program contains a function that accepts an
   int array and the array's size as arguments. The function creates
   a new array that is twice the size of the argument array. The
   function copies the contents of the argument array to the new array
   and initialize the unused elements of the second array with 0. The
   function returns a pointer to the new array. */

#include "Utility.h"

/* Function prototypes */
void getNumbers(int *, int);
int *expandArray(const int *, int &, int);
void displayOriginal(const int *, const int);
void displayCopy(const int *, const int);
void freeMem(int *, int*);

int main()
{
   int *numbers = nullptr;
   int *arrExpander = nullptr;

   int numels = 0,
       expSize = 0;

   /* Get the initial number of elements the array should hold */
   cout << "\n\tARRAY EXPANDER\n\n"
        << "\tHow many numbers should your array contain? ";
   cin >> numels;

   /* Allocates a new array to hold the numbers */
   numbers = new int[numels]();

   /* Creates a set of random numbers to fill the numbers array */
   getNumbers(numbers, numels);

   /* Displays the original array and its contents */
   displayOriginal(numbers, numels);

   cout << "\n\n\tYour array will now be copied and expanded ...\n\n";

   /* Expands the array to hold twice the number of elements as its
      original */
   arrExpander = expandArray(numbers, expSize, numels);

   /* Displays the copy of the array */
   displayCopy(arrExpander, expSize);

   pauseSystem();
   return 0;
}

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

   This function accepts numbers and numels as arguments. It
   fills numbers with (pseudo)random numbers in the range of
   1 through 200.
   ********************************************************** */

void getNumbers(int *numbers, int numels)
{
   const int MIN_NUM = 1,
             MAX_NUM = 200;

   srand((unsigned int) time(NULL));

   for (int index = 0; index < numels; index++)
   {
      *(numbers + index) = (rand() % (MAX_NUM - MIN_NUM + 1) + MIN_NUM);
   }
}

/* **********************************************************
   Definition: displayOriginal

   This function accepts numbers and numels as arguments. It
   displays the original array.
   ********************************************************** */

void displayOriginal(const int *numbers, const int numels)
{
   cout << "\n\tThis is how your original array looks like:\n\n";

   for (int index = 0; index < numels; index++)
   {
      cout << "\t" << *(numbers + index) << "\n";
   }

   cout << "\n\tIt holds " << numels << " elements.\n";
}


/* **********************************************************
   Definition: displayCopy

   This function accepts expanded and numels as arguments. It
   displays the content of the argument array's copy.
   ********************************************************** */

void displayCopy(const int *expanded, const int expSize)
{
   cout << "\n\tThis is how your array's copy looks like:\n\n";

   for (int index = 0; index < expSize; index++)
   {
      cout << "\t" << *(expanded + index) << "\n";
   }

   cout << "\n\tIt can now hold " << expSize << " elements!\n";
}

/* **********************************************************
   Definition: arrayExpander

   This function accepts numbers and numels as arguments. It
   creates a copy of the argument array, twice the size of
   the original. The elements of the copy are initialized to
   0, then the argument array's content is copied into the
   copy. A pointer is returned from the function pointing to
   the copy of the argument array.
   ********************************************************** */

int *expandArray(const int *numbers, int &expSize, const int numels)
{
   int *expanded = nullptr;

   int count = 0;

   expSize = numels * 2;
  
   /* Allocates memory for an array to hold twice the number
      of elements as the original */
   expanded = new int[expSize]();

   while (count < numels)
   {
      *(expanded + count) = *(numbers + count);
     
      ++count;
   }
  
   /* Returns a pointer to the copy of the argument array */
   return expanded;
}

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

   This function accepts numbers expander as arguments. It
   frees the memory before the program exits.
   ********************************************************** */

void freeMem(int *numbers, int *arrExpander)
{
   delete[] numbers;
   delete[] arrExpander;

   numbers = nullptr;
   arrExpander = nullptr;
}

Example Output:



Programming Challenge 9.10 - Reverse Array

/* Reverse Array - This program contains a function that accepts an int
   array and the array's size as arguments. The function creates a copy
   of the array, except that the element values are reversed in the copy.
   The function returns a pointer to the new array. */

#include "Utility.h"

/* Function prototypes */
void getNumbers(int *, int);
int *reverseNumbers(const int *, const int);
void displayNumbers(const int *, const int);
void displayReverse(const int *, const int);
void freeMem(int *, int *);

int main()
{
   int *numbers = nullptr;
   int *revNumbers = nullptr;

   int numels = 0;

   /* Get the initial number of elements the array should contain */
   cout << "\tREVERSE NUMBERS\n\n"
        << "\tHow many numbers should your set contain? ";
   cin >> numels;

   /* Allocates a new array to hold the numbers */
   numbers = new int[numels];

   /* Creates a set of random numbers to fill the numbers array */
   getNumbers(numbers, numels);

   /* Displays the numbers in their original order */
   displayNumbers(numbers, numels);

   /* Creates a copy of numbers and fills the copy with the numbers
      in reverse order */
   revNumbers = reverseNumbers(numbers, numels);

   /* Displays the numbers in reverse order */
   displayReverse(revNumbers, numels);

   /* Frees the memory */
   freeMem(numbers, revNumbers);

   pauseSystem();
   return 0;
}

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

   This function accepts numbers and numels as arguments. It
   fills numbers with (pseudo)random numbers in the range of
   1 through 200.
   ********************************************************** */

void getNumbers(int *numbers, int numels)
{
   const int MIN_NUM = 1,
             MAX_NUM = 200;

   srand((unsigned int) time(NULL));

   for (int index = 0; index < numels; index++)
   {
      *(numbers + index) = (rand() % (MAX_NUM - MIN_NUM + 1) + MIN_NUM);
   }
}

/* **********************************************************
   Definition: displayNumbers

   This function accepts numbers and numels as arguments. It
   displays the numbers in their original order.
   ********************************************************** */

void displayNumbers(const int *numbers, const int numels)
{
   cout << "\n\tThese are your numbers in their original order:\n\n";

   for (int index = 0; index < numels; index++)
   {
      cout << "\t" << *(numbers + index) << " \n";
   }
}

/* **********************************************************
   Definition: reverseNumbers

   This function accepts numbers and numels as arguments. It
   creates a copy of the array, and reverses the numbers. A
   pointer to the copy containing the numbers in reverse
   order is returned.
   ********************************************************** */

int *reverseNumbers(const int *numbers, const int numels)
{
   int *revNumbers = nullptr;

   int firstElem = 0,
       lastElem = numels;

   /* Allocates a new array to hold the copy  of numbers in
      reverse order */
   revNumbers = new int[numels]();

   while (lastElem > 0)
   {
      --lastElem;
      *(revNumbers + firstElem) = *(numbers + lastElem);
      ++firstElem;     
   }

   /* Returns a pointer to the new array */
   return revNumbers;
}

/* **********************************************************
   Definition: displayReverse

   This function accepts revNumbers and numels as arguments. It
   displays the numbers in reverse order.
   ********************************************************** */

void displayReverse(const int *revNumbers, const int numels)
{
   cout << "\n\tThese are your numbers in reverse order:\n\n";

   for (int index = 0; index < numels; index++)
   {
      cout << "\t" << *(revNumbers + index) << " \n";
   }
}

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

   This function accepts numbers and numels as arguments. It
   frees the memory before the program exits.
   ********************************************************** */

void freeMem(int *numbers, int *revNumbers)
{
   delete[] numbers;
   delete[] revNumbers;

   numbers = nullptr;
   revNumbers = nullptr;
}

Example Output:




Saturday, April 1, 2017

Programming Challenge 9.9 - Median Function

/* Median Function - In statistics, when a set of values is sorted in
   ascending or descending order, its median is the middle value. If
   the set contains an even number of values, the median is the mean,
   or average, of the two middle values.
  
   This program contains a function that accepts the following:
  
      * An array of integers
      * An integer that indicates the number of elements in the array

   The function determines the median of the array. This value is
   returned as double. (The numbers are sorted).

   Pointer prowess is demonstrated by using pointer notation instead
   of array notation. */

#include "Utility.h"

void   getNumbers(int *, int);
void   sortNumbers(int *, int);
double getMedian(int *, int);
void   freeMem(int *);

int main()
{
   /* Dynamically allocated array to
      hold a list of numbers */
   int   *numList = nullptr;

   int    numels = 0;
   double median = 0.0;

   cout << "\n\tMEDIAN DISCOVERY FUNCTION\n\n"
        << "\n\tHow many elements should your set of numbers contain? ";
   cin >> numels;

   numList = new int[numels];

   /* Gets a list of numbers by way of input */
   getNumbers(numList, numels);

   /* Sorts the numbers in ascending order by using an selection-sort
      algorithm */
   sortNumbers(numList, numels);

   /* Determines and returns the median */
   median = getMedian(numList, numels);

   /* Display the median value */
   cout << fixed << showpoint << setprecision(2);
   cout << "\n\tThe median is: " << median << " ";

   /* Frees the memory before the program exits */
   freeMem(numList);

   pauseSystem();
   return 0;
}

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

   This function accepts numList and numels as arguments. The
   numbers entered by the user are stored in numlist.
   ********************************************************** */

void getNumbers(int *numList, int numels)
{
   cout << "\n\n\tPlease enter " << numels << " numbers:\n\n";

   for (int index = 0; index < numels; index++)
   {
      cout << "\tNumber #" << (index + 1) << ": ";
      cin >> *(numList + index);
   }
   cout << "\n";
}

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

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

void sortNumbers(int *numList, int numels)
{
   int startScan = 0,
       index = 0,
       minIndex = 0,
       minEl = 0;

   for (startScan = 0; startScan < numels; startScan++)
   {
      minIndex = startScan;
      minEl = *(numList + startScan);

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

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

   cout << "\n\tYour numbers in sorted order:\n\n";

   for (int index = 0; index < numels; index++)
   {
      cout << "\t" << *(numList + index) << " \n";
   }
}

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

   This function accepts numList and numels as arguments. It
   determines the median and returns it. This is achieved by
   using a ternary operator, that does the following:

      * The first condition determines whether the number of
        elements in the array is even or odd.

      * If the number is even, midLower gets the middle value
        found in the lower half of the array, and midUpper is
        assigned the middle value at the upper half of the
        array.

      * Then the median is calculated by adding the middle
        values and dividing the sum by 2.

      * If the number of elements is odd, median gets the
        middle element. The calculation to determine it has
        already been carried out.

   Once the median is found, it is returned.
   ********************************************************** */

double getMedian(int *numList, int numels)

   double median = 0.0;

   int      middleElem = numels / 2,
          midLower = 0,
          midUpper = 0;

   numels % 2 == 0 ? midLower = *(numList + middleElem - 1),
                                  midUpper = *(numList + middleElem),
                                  median = (midUpper + midLower) / 2 :
                                  median = *(numList + middleElem);

   return median;
}

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

   This function accepts numList as argument. It frees the
   allocated memory before the program exits.
   ********************************************************** */

void freeMem(int *numList)
{
   delete[] numList;

   numList = nullptr;
}

Example Output: 




Monkey Business - Back with a vengance

Some of my regular visitors may remember my post about all the troubles I have had with finishing the Monkey Business programming challenge. As the title of this blog post suggests, it came back with a vengeance, this time with the Mode programming challenge. Before I share this story with you, catch a cup and make yourself comfortable, as I foresee that this post is going to be a long one. 

Picture Copyright: My own work, a free for all.

When I started with this challenge, it seemed to turn out to be quite easy, a day maybe two and it should be done. What was asked for seemed to be clear enough: 

"Create an array, fill it with numbers, discover the highest number, and return it. Or return -1 if no   number occurs more frequently than any others."

This lulled me into a false sense of security, and with my guard down, no research about mode(s) done, I simply planned out my program, all the functions it should have, so on so forth. To finish writing the code was taking half a day at most. Everything was working, the code along with some screenshots ready to be uploaded, or so I thought. Then I started thinking ... and instead of uploading the supposedly finished program, I started doing some research on the topic of mode(s).

The very first thing I learned is that a set of numbers can contain more than one mode. Most of the examples I found were looking like this: 1, 2, 2, 2, 3, 3, 3 making the modes of this set 2 and 3. Up to this point I wasn't considering to change any of my existing code, because the challenge didn't ask to return more than one mode, but only the mode, should there be any, or -1 if none is discovered. This last condition has been covered by my original code. This newfound knowledge then led me to believe that if a set of numbers looks like this: 2, 2, 3, 3, 4, 4, 5, 5 it does not contain a mode. Or this set: 3, 3, 3, 4, 4, 4 both numbers are there 3 times, so there is no mode.

Of course this had to be taken into consideration, so I was trying to change my code accordingly. I failed, and failed, and failed some more. I was working on it for days and all my efforts led to my having to start over. I eventually reached the point, about 7 days in, I lost all hope of ever finding a way to get this problem solved. In desperate need for help I sought help in a coding community called http://www.cplusplus.com/ which I suppose many of you do know. Stating my problem according to what I thought was the core of my problem, I asked for a simple line of code, an if-statement, which I couldn't come up with, should suffice.

In the course of an exchange between an experienced member going by the nick of lastchance who helped me out so much, I discovered what the real problem was. At first a mere question was asked, that - by knowing at least something about mode(s) I was able to answer easily: 1, 2, 2, 3, 3, 4, 4, 5 which, do I think, is or are the mode(s)? My answer was, 2, 3, and 4, because they both occur at least two times making it three modes. Suffice to say that this question alone caused me to feel very stupid at first, but in turn helped me to discover the core of the actual problem.

This changed my view of the problem I was in part causing myself, by knowing that there can be both a single as well as more than one mode. Still, the problem to solve was in part still the same:
A set like this 1, 2, 2, 3, 3, 4, according to the websites explaining modes in statistics, has two modes, and a mode is the number occurring most frequently. It should take some more time to learn from lastchance that 2, 2, 2, 3, 3, 3 is containing two modes, 2 and 3, so making it a set of two modes. 

I found out about the fact myself by visiting calculatorsoup,com a great website for doing all sorts of calculations, among others, all explaining that:
"Mode is the value or values in the data set that occur most frequently." 
Yet, when entering 2, 2, 3, 3, 4, 4 not only the above mentioned website but all others as well, would say that the modes are 2, 3, 4. lastchance provided a code example delivering much the same result. This, then, after numerous failed attempts to return -1 if there is in fact more than one mode, I considered adding another array containing the mode(s), and having the function return -1 if there indeed is no mode, in light of this new discovery. Without this the program would not be complete. Also a histogram would have been nice to have. 

With this I started out too plan and write the umpteenth version of the program. This time it would work out, or so I thought. Until completion I found about a major problem that made it yet another failed attempt in solving the challenge. The reason for failing the way it did was not very obvious, and the problem as such surfaced only after being finished writing the code. Up to this point i was working with simple input to fill numList, the array containing all the numbers.

When entering 1, 1, 2, 2, 3, 3 the output as far as modes is concerned was correct, histogram, frequency and numbers also. Then I entered the following sequence: 1, 2, 1, 2, 1, 2, 1, 2 expecting that the output would be: 

mode(s): 1
mode(s): 2

Instead I got both 1 and two displayed numerous times, each being counted only once by the function that determines the frequency of numbers. My first instinct told me that this is merely a matter of changing the if statement dealing with output of the modes, which, in its initial version looked like this:

if (*(mutiMode + index) > 0 && *(multiMode + index) != *(multiMode + index + 1)
{
     cout << "Mode(s): " << *(multiMode + index) << "\n";
}
This didn't help at all. Remember the word histogram! The output from this function was the same as the one in the mode function: 1, 2, 1, 2, 1, 2, 1, 2 freq: 1 ..... 1. In conclusion adding the same condition into this function as well, hoping for the correct result, being 1, 2 - 2, 2. Of course it didn't work out that way. Next thing I tried to change was the function taking care of counting the frequency, again, no luck. It has gotten so far that I even changed my sorting function, which I only have had one initially, so that it would sort by numbers not frequency. The lesson to be learned, which I learned the hard way, is this:

"If parts of your code do not work they are supposed to, don't try to add fixes in different parts of your code, because you are likely to introduce even more errors."

But what was the problem, then? In one word: Sorting. As mentioned, I had one sorting function, sorting both frequency and numList in descending order. In my next revision I had one for numList one for frequency, until in my final version I had one for frequency, and a dual-sort for both the arrays which then led to working code, doing as it should. Although I must admit that the histogram looks a bit strange as far as output of numbers goes. This is something that I considered to be fine as is, as long as the program is doing the job it is supposed to. 

So, to my fellow learners, as well as readers old and new, whom I heartily welcome to my humble abode, I hope you will be able to learn something from this. And my hope for the next challenge, which involves writing a function to calculate the median, is that it turns out to be an easy one! With this, it is time to get back to my IDE, and write some more code.

Programming Challenge 9.8 - Mode Function

/* Mode Function - In statistics, the mode of a set of values is the
   value that occurs most often or with the greatest frequency. This
   program contains a function that accepts the following arguments:
  
      * An array of integers
      * An integer that indicates the number of elements in the array
  
   The function determines the mode of the array. That is, it determines
   which value in the array occurs most often. The mode is the value the
   function returns. If the array has no mode (none of the values occur
   more than once), the function returns -1. (The assumption is that the
   array will always contain nonnegative values.)

   Pointer prowess is demonstrated by using pointer notation instead of
   array notation in this function. */

#include "Utility.h"

void getNumbers(int *, int);
void sortNumbers(int *, int);
void getFrequency(int *, int *, int);
void dualSort(int *, int *, int);
int  getMode(int *, int *, int *, int);
void displayMode(int *, int);
void displayHistogram(int *, int *, int);
void freeMem(int *, int *, int *);

int main()
{
   /* Dynamically allocated arrays to hold a list of numbers */
   int *numList = nullptr;
   int *frequency = nullptr;
   int *modes = nullptr;

   int numels = 0,
       count = 0,
       mode = 0;

   cout << "\n\tMODE DISCOVERY PROGRAM\n\n"
        << "\tHow many elements should your set of numbers contain? ";
   cin >> numels;

   numList = new int[numels];
   frequency = new int[numels]();
   modes = new int[numels]();
     
   /* Gets a set of (pseudo)random numbers and stores them in numList */
   getNumbers(numList, numels);

   /* Sorts the numbers with an selection-sort algorithm */
   sortNumbers(numList, numels);

   /* Determines and stores the frequency of numbers found in numList */
   getFrequency(numList, frequency, numels);

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

   /* Determines and returns the mode(s) or -1 if there is no mode */
   mode = getMode(numList, frequency, modes, numels);

   /* If the mode returned is not -1, the mode or modes are displayed */
   if (mode != -1)
   {
      displayMode(modes, numels);
   }
   else
   {
      cout << "\n\tThis set of numbers does not contain any modes!";
   }
  
   /* Displays a histogram */
   displayHistogram(numList, frequency, numels);

   /* Frees the memory before the program exits */
   freeMem(numList, frequency, modes);

   pauseSystem();
   return 0;
}

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

   This function accepts numList and numels as its arguments.
   It creates a random list of numbers in the range from 1 to
   15 and stores these in the numList.
   ********************************************************** */

void getNumbers(int *numList, int numels)
{
   const int MIN_NUM = 1,
             MAX_NUM = 15;

   srand((unsigned int) time(NULL));

   for (int index = 0; index < numels; index++)
   {
      *(numList + index) = (rand() % (MAX_NUM - MIN_NUM + 1) + MIN_NUM);
   }
}

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

   This function accepts numList and numels as its arguments.
   It uses a selection-sort algorithm to sort the number in
   ascending order.
   ********************************************************** */

void sortNumbers(int *numList, int numels)
{
   int startScan = 0,
       index = 0,
       minIndex = 0,
       minEl = 0;

   for (startScan = 0; startScan < numels; startScan++)
   {
      minIndex = startScan;
      minEl = *(numList + startScan);

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

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

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

   This function accepts numList, frequency and numels as its
   arguments. It counts the numbers stored in numList, totals
   these numbers, and stores the sum-total in frequency.
   ********************************************************** */

void getFrequency(int *numList, int *frequency, int numels)
{
   int total = 0,
       count = 0;

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

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

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

/* **********************************************************
   Definition: sortFrequency

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

void dualSort(int *numList, int *frequency, int numels)
{
   int startScan = 0,
       index = 0,
       maxIndex = 0,
       tempList = 0,
       maxEl = 0;

   for (startScan = 0; startScan < numels; startScan++)
   {
      maxIndex = startScan;
      maxEl = *(frequency + startScan);
      tempList = *(numList + startScan);

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

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

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

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

   This function accepts numList, frequency, modes, and
   numels as arguments. First the function determines whether
   there are numbers more frequent than any other, modes gets
   this number. If there is no mode, -1 is returned.
   ********************************************************** */

int getMode(int *numList, int *frequency, int *modes, int numels)
{
   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 (*(numList + index) == *(numList + index + 1) ||
       *(frequency + index) == 1)
   {
      mode = -1;
   }

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

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

   return mode;
}

/* **********************************************************
   Definition: displayMode

   This function accepts modes, mode and numels as arguments.
   It displays the mode or modes found in the numList array.
   If no mode has been found, a message is displayed.
   ********************************************************** */

void displayMode(int *modes, int numels)
{
   cout << "\n\n\tMODES\n\n"
        << "\tThese mode(s) have been discovered: \n\n";

   for (int index = 0; index < numels; index++)
   {
      if (*(modes + index) > 0)
      {
         cout << "\tMode #" << (index + 1) << setw(14) << right
              << *(modes + index) << " \n";
      }
   }
}

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

   This function accepts numList, frequency and numels as
   arguments. It displays all numbers in numList, sorted in
   order from highest to lowest, the frequency, and of occurence.
   ********************************************************** */

void displayHistogram(int *numList, int *frequency, int numels)
{
   int index = 0,
       total = 0,
       count = 0;

   cout << "\n\t\n\tHISTOGRAM\n\n"
        << "\tNUMBERS: " << setw(17) << right
        << "FREQUENCY:" << setw(17) << right
        << "HISTOGRAM:\n";

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

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

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

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

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

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

   This function accepts numList, frequencies and multiMode
   as its arguments. It frees the memory before the program
   exits.
   ********************************************************** */

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

   numList = nullptr;
   frequency = nullptr;
   modes = nullptr;
}

Example Output: