Find the mode of a Dynamic array with pointers

I need to figure out the mode(s) from a dynamic array that was populated using a text file and pointers. I also need to account for multiple modes. I am trying to use another dynamic array for the modes to store 1 or more in there.

I am learning C++ and the assignment requires I use pointers and pointer arithmetic, no index operators except for when i create the array. I also needed to do various functions like finding the mean, median and mode.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
// Headers
#include <iostream>
#include <cstdlib>
#include <string>
#include <fstream>
#include <iomanip>
using namespace std;

// Global variables
const string FILENAME = "moviecount.txt";

// Function declarations
int readMovieData(int *& movies, string fileName);
double calculateAverage(int * movies, int size);
double calculateMedian(int * movies, int size);
int* calculateMode(int * movies, int size, int& numModes);
void sort(int *& movies, int size);

int main()
{
	int numStudents;				// number of students who watch movied
	int * movieCounts = nullptr;	// an array of integers to store counts of movies for each student
	

	// Read in the movie data
	try
	{
		numStudents = readMovieData(movieCounts, FILENAME);
	}
	catch (const char * message) // if file cannot be opened then catch the thrown exception
	{
		cout << message << endl;
		system("PAUSE");
		exit(EXIT_FAILURE);
	}
	
	cout << setprecision(2) << fixed << showpoint;	// set decimal places to two for average and median

	cout << "Total number of students who watched movies is " << numStudents << endl;
	cout << "The average number of movies watched by all students is " << calculateAverage(movieCounts, numStudents) << endl;
	cout << "The median number of movies watched by all students is " << calculateMedian(movieCounts, numStudents) << endl;

	int numModes = 0;	// number of modes in the list, there could be more than one
	int * modes = calculateMode(movieCounts, numStudents, numModes); // list of modes is returned and stored in modes
	cout << "The mode number of movies watched by all students is ";
	if (numModes >= 1)
	{
		cout << modes + 0;	// output the first mode
	}
	for (int i = 0; i < numModes; i++) // if there is more than one, output the remaining modes
	{
		cout << ", " << modes + i;
	}
	cout << endl;

	//	Make sure we place the end message on a new line
    cout << endl;

	//	The following is system dependent.  It will only work on Windows
    system("PAUSE");

    return 0;
}


int readMovieData(int *& movies, string fileName)
{
	ifstream in(FILENAME);
	if (!in)
	{
		throw "file did not open";
	}
	int count = 0;

	in >> count;

	if (count == 0)
	{
		throw "file has no data";
	}

	movies = new int[count];
	
	for (int i = 0; i < count; ++i)
	{
		in >> *(movies + i);
	}

	return count;

}

double calculateAverage(int * movies, int size)
{
	double sum = 0;
	double average;
	for (int i = 0; i < size; ++i)
	{
		sum += *(movies + i);
	}
	average = sum / size;
	return average;
}


double calculateMedian(int * movies, int size)
{
       sort(movies, size);
	int median, middle;
	middle = size / 2;
	//checking if size is even
	if (size % 2 == 0)
	{
		//Calculate the median.
		median = (*(movies + middle) + *(movies + middle - 1)) / 2;
	}
	//size is odd.
	else
	{
		//Calculate the median.
		median = *(movies + middle);
	}
	return median;
}

/***********************************************************
Description
PARAM:	movies points to a dynamic array
		size is the number of elements in array pointed to by movies
		numModes is a reference variable used to return the number of modes found in movies
PRE:	movies points to an array of size elements
POST:	Each mode value is stored in a dynamic array of integers with size of size
		The dynamic array of modes is returned
NOTE:	std::fill was used to clear the array when a new mode larger than other modes was found
		To make it easier to determine the number of like values, movies is sorted
************************************************************/
int * calculateMode(int * movies, int size, int & numModes)
{
        sort(movies,size);
	int * modes = new int[size];
	int current = 0, count = 0, maxCount = 0;
	for (int i = 0; i < size; i++)
	{
		if (*(movies + i) == *(movies + i + 1))	// check if next is the same number as current  aka duplicate
		{
			count++;					//increment current count if duplicate
			if (count > maxCount)		//check if current count is higher than maxCount
			{
				maxCount = count;		//if current count is higher than maxCount, current count is new maxCount
				*(modes + i) = current;	//store current number
			}
			else
			{
				count = 1; // Reset counter
			}
		}
	}
	//Need to also clear modes list when a new mode is found, unless there are multiple modes
	return modes;
}


void sort(int *& movies, int size)
{
	bool sorted = false;
	int *ptr = movies;
	while (!sorted)
	{
		sorted = true;
		for (int i = 0; i < size - 1; i++)
		{
			if (*(ptr + i) > *(ptr + i + 1)) 
			{
				int temp = *(ptr + i);
				*(ptr + i) = *(ptr + i + 1);
				*(ptr + i + 1) = temp;
				sorted = false; 
			}
		}
	}
}
Last edited on
I made a small change, but it still doesnt work the way I need it to.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
int * calculateMode(int * movies, int size, int & numModes)
{
	sort(movies,size);
	int * modes = new int[size];
	int current = 0, count = 0, maxCount = 0;
	for (int i = 0; i < size; i++)
	{
		if (*(movies + i) == *(movies + i + 1))	// check if next is the same number as current  aka duplicate
		{
			current = *(movies + i);
			count++;					//increment current count if duplicate
			if (count > maxCount)		//check if current count is higher than maxCount
			{
				maxCount = count;		//if current count is higher than maxCount, current count is new maxCount
				current >> *(modes + i);	//store current number
			}
			else
			{
				count = 1; // Reset counter
			}
		}
	}
	
	return modes;
}


when i step through it, it doesnt seem like modes is being updated.

I also tried *(modes + i) = current;
It's a good time to think how to find mode.

Here is a solution.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
int * calculateMode(int * movies, int size, int & numModes)
{
	sort(movies,size);
	
	// Since array ist sorted, you can count the occurrences of a movies.
	// We can use run-length encoding.
	struct runlength {int number, ncount;};
	runlength *rl = new runlength[size];
	
	// Since *(movies+i) === movies[i], I prefer operator [].
	// First member is a mode.
	int count = 0, maxCount = 1;
	rl[count].number = movies[0]; 
	rl[count].ncount = 1;
	
	// We start here with i = 1
	for (int i = 1; i < size; i++)
	{
	    if(movies[i] == rl[count].number){ 
	        // Count occurrences of the current number.
	        rl[count].ncount++;
	    }
	    else{ // It is a different number.
	        // Mode is the biggest ocurrences
	        if(maxCount < rl[count].ncount) 
	            maxCount = rl[count].ncount;
	            
	        // Start count with the new number
	        count++;
	        rl[count].number = movies[i];
	        rl[count].ncount = 1; 
           }
	}
	
	// Copy all modes to output
	int * modes = new int[count+1];
	int current = 0;
	for(int i=0; i<=count; i++){
	    if(rl[i].ncount == maxCount)
	        modes[current++] = rl[i].number;
	}
	
	numModes = current;
	delete [] rl;
	return modes;
}
Last edited on
Referring to your original post:
Line 115: this will return an integer. To return the average of the two values, change 2 to 2.0. That will force the numerator to be converted to double and it will do double precision division giving a double precision result.

Line 114: The last time through the loop, this will attempt to access beyond the end of the array.
Topic archived. No new replies allowed.