EDIT Took a different approach and found the solution, updated the function to correctly find the mode or modes
I've been at this algorithm all day and night, I've looked at about 12 code examples 10x over but none of them seem to go above and beyond to address my problem.
Problem: Find the mode(s) in an array, if the array has more than one mode, display them all. (This is a homework assignment so I must use arrays/pointers)
Sample array:
-1, -1, 5, 6, 1, 1
Sample output:
This array has the following mode(s): -1, 1
The problem I'm having is trying to figure how to store and display just the highest mode OR the multiple modes if they exist.
I have used a lot of approaches and so I will post my most recent approach:
void getMode(int *arr, int size)
{
int *count = new int[size]; // to hold the number of times a value appears in the array
// fill the count array with zeros
for (int i = 0; i < size; i++)
count[i] = 0;
// find the possible modes
for (int x = 0; x < size; x++)
{
for (int y = 0; y < size; y++)
{
// don't count the values that will always occur at the same element
if (x == y)
continue;
if (arr[x] == arr[y])
count[x]++;
}
}
// find the the greatest count occurrences
int maxCount = getMaximum(count, size);
// store only unique values in the mode array
int *mode = new int[size]; // to store the mode(s) in the list
int modeCount = 0; // to count the number of modes
if (maxCount > 0)
{
for (int i = 0; i < size; i++)
{
if (count[i] == maxCount)
{
// call to function searchList
if (!searchList(mode, modeCount, arr[i]))
{
mode[modeCount] = arr[i];
modeCount++;
}
}
}
}
// display the modes
if (modeCount == 0)
cout << "The list has no mode\n";
else if (modeCount == 1)
{
cout << "The list has the following mode: " << mode[0] << endl;
}
else if (modeCount > 1)
{
cout << "The list has the following modes: ";
for (int i = 0; i < modeCount - 1; i++)
{
cout << mode[i] << ", ";
}
cout << mode[modeCount - 1] << endl;
}
// delete the dynamically allocated arrays
delete[]count;
delete[]mode;
count = NULL;
mode = NULL;
}
/*
definition of function searchList.
searchList accepts a pointer to an int array, its size, and a value to be searched for as its arguments.
if searchList finds the value to be searched for, searchList returns true.
*/
bool searchList(int *arr, int size, int value)
{
for (int x = 0; x < size; x++)
{
if (arr[x] == value)
{
return true;
}
}
return false;
}
It's best to build algorithms from smaller building blocks. The standard <algorithm> library is a great source of such components. Even if you're not using that, the program should be similarly structured with subroutines.
For homework at least, the reasoning behind the program should be fairly "obvious," especially given some comments.
Here's a version using <algorithm>, and std::unique_ptr instead of new, which you should never use. If it helps to satisfy the homework requirements, you might implement your own versions of the standard library facilities.
// Input: array "in" of size "count"
// Output: array "in" contains "count" modes of the input sequence
void filter_modes( int * in, int & count ) {
auto end = in + count;
std::sort( in, end ); // Sorting groups duplicate values.
// Use an ordered pair data type, <frequency, value>
typedef std::pair< int, int > value_frequency;
// Reserve memory for the analysis.
auto * frequencies = std::make_unique< value_frequency[] >( count );
int frequency_count = 0;
// Loop once per group of equal values in the input.
for ( auto group = in; group != end; ++ group ) {
auto group_start = group;
// Skip to the last equal value in this subsequence.
group = std::adjacent_find( group, end, std::not_equal_to<>{} );
frequencies[ frequency_count ++ ] = { // Record this group in the list.
group - group_start + 1, // One unique value plus # skipped values.
* group // The value.
};
}
// Sort <frequency, value> pairs in decreasing order (by frequency).
std::sort( frequencies.get(), frequencies.get() + frequency_count,
std::greater<>{} );
// Copy modes back to input array and set count appropriately.
for ( count = 0; frequencies[ count ].first == frequencies[ 0 ].first; ++ count ) {
in[ count ] = frequencies[ count ].second;
}
}
There's no real answer because of the way the mode is defined. Occasionally you see in British high school leaving exams the demand to identify the mode from a small distribution which is clearly amodal, but has one bin with excess count.
You need to bin the data, choosing bins so that the data has definite peaks and troughs. The modes are then the tips of the peaks. However little subsidiary peaks on the way up to the top are not modes, they're a sign that your binning has been too narrow. It's easy enough to eyeball the modes, a bit more difficult to work it out in a computer algorithm which has to be formal. One test is to move the bins by half a bin. If a mode disappears, it's noise rather than a real mode.
Related
I am using an arduino to read a sensor which stores 256 values into an array. I am trying to find local max's but some values being stored have repeating values to the left and right of itself causing the value to print multiple times. Is there a way to take all true values meaning they are a max value and store them in another array to process and reduce the repeated values to just 1 value...
OR is there a way to send the max values to another array where the repeated values get reduced to just 1? OR
IE:
Array1[] = {1,2,3,4,4,4,3,2,7,8,9,10}
max = 4 at index 3
max = 4 at index 4
max = 4 at index 5
since 4 is a peak point but repeats how can I reduce it so that the array looks like
Array2[] = {1,2,3,4,3,2,7,8,9,10}
max = 4 at index 3
I need the most basic breakdown if possible nothing on an expert level, thanks.
Code from Arduino:
int inp[20] = {24,100,13,155,154,157,156,140,14,175,158,102,169,160,190,100,200,164,143,20};
void setup()
{
Serial.begin(9600); // for debugging
}
void loop()
{
int i;
int count = 0;
for (i = 0; i < 20; i++)
{
Serial.println((String)inp[i]+" index at - "+i);
delay(100);
};
int N = 5; // loc max neighborhood size
for (int i = N-1; i < 19-N; i++)
{
bool loc = false;
for (int j = 1; j < N; j++) // look N-1 back and N-1 ahead
{
if (inp[i] > inp[i-j] && inp[i] > inp[i+j]) loc = true;
}
if (loc == true)
{
Serial.println((String)"max = "inp[i]+" at index "+i);
}
}
Serial.println("----------------------------------");
}
You can detect "local maxima" or peaks in a single loop without the need of copying something into another array. You just have to ignore repeating values, and you just have to keep track if the values considered are currently increasing or decreasing. Each value after which this status switches from increasing to decreasing is then a peak:
int main() {
int Array1[] = {1,2,3,4,4,4,3,2,7,8,9,10};
int prevVal = INT_MIN;
enum {
Ascending,
Descending
} direction = Ascending;
for (int i=0; i<sizeof(Array1)/sizeof(*Array1); i++) {
int curVal = Array1[i];
if (prevVal < curVal) { // (still) ascending?
direction = Ascending;
}
else if (prevVal > curVal) { // (still) descending?
if (direction != Descending) { // starts descending?
cout << "peak at index " << i-1 << ": " << prevVal << endl;
direction = Descending;
}
}
// prevVal == curVal is simply ignored...
prevVal = curVal;
}
}
This might sound like a repeat question but it is not because I haven't found the answer to my question in-spite of going through several references/related questions as listed below (and a lot more not listed).
Minimum difference in an array
Finding out the minimum difference between elements in an array
Find the minimum difference between two arrays
Find the minimum difference between two arrays
Dividing an array into two subsets of equal sizes having minimum difference in sum of values
http://www.geeksforgeeks.org/find-the-minimum-distance-between-two-numbers/
http://programmingpraxis.com/2013/10/15/find-the-minimum-difference/#comment-9146
https://www.daniweb.com/programming/software-development/threads/391082/distance-between-two-closest-elements-in-an-array
Following is my program and my own attempt to try and find the "Minimum difference between two elements within the array, any two pairs", then let be there more than one pair of numbers which gives the same minimum difference numerically. I tried to change loops to count them differently and also tried to change the if condition clause for different results but finally ended up with the following code:
#include <iostream> //input output stream
#include <cstdlib>
#include "math.h" //to be able to use math functions if any
using namespace std;
int main()
{
int x=0,y=0,number1 = 0,number2 = 0,size1=0,mindiff = 0;
int index = 0, count = 0, diff = 0;
cout<<"enter the size of array you want \n\n";
cin>>size1;
int arr1[size1];
cout<<"\n\n please enter elements of array \n\n";
for (int i =0;i<size1;i++)
{
cin>>arr1[i];
}
for ( x=0;x<size1;x++ )
{
diff = 0;
for ( y=0;y<size1;y++ )
{
diff = abs(arr1[x] - arr1[y]);
if (diff<mindiff)
{
mindiff = diff;
//index = x+1;
number1 = arr1[x];
number2 = arr1[y];
}
}
}
cout<<"\nthe elements amongst which the minimum difference was given are "<<number1<<" & "<<number2<<endl;
cout<<"the difference between them is "<<abs(mindiff)<<endl;
system("pause");
return 0;
}
//end of program
All the above references and lots more but could not find anyone that follows my perspective. I know that i may be doing something really silly/wrong out here because i get a maximum difference and not minimum difference.Where am I going wrong?
I anyways have to keep on assigning the new minimum every time a lower difference is found as written in the if condition statement right???
following is the output
enter the size of array you want
6
please enter elements of array
1
2
34345
7
8
9
the elements amongst which the minimum difference was given are 1 & 34345
the difference between them is 34344
Press any key to continue . . .
Use the abs(x) function to make sure that diff is positive. Otherwise, the difference between arr1[x]:5 and arr1[y]:10 (5-10=-5) will be smaller than the difference between arr1[x]:5 and arr1[y]:4 (5-4=1).
http://www.cplusplus.com/reference/cstdlib/abs/
You also want to make sure that you never check with the same index, i.e. x=y.
You can improve your algorithm a little bit (halving the comparisons, actually) by considering the underlying simmetry:
#include <iostream>
#include <limits>
using std::cout;
// I'll use a struct to return the values
struct dif_t {
int first;
int second;
int dif;
};
dif_t min_difference( const int *x, size_t n ) {
dif_t min{0,0,0};
min.dif = std::numeric_limits<int>::max();
for ( size_t i = 0; i < n; ++i ) {
//remember that abs(x[i]-x[j])=abs(x[j]-x[i]) and x[i]-x[i]=0
for ( size_t j = i + 1; j < n; ++j ) {
// ^^^^^^^
int dif = abs( x[i] - x[j] );
if ( dif < min.dif ) {
min.dif = dif;
min.first = x[i];
min.second = x[j];
}
}
}
return min;
}
int main() {
// I'll skip the input part
int numbers[] = { 1, 20, 34345, 89, 7, 88 };
dif_t edif = min_difference(numbers, sizeof(numbers)/sizeof(int));
std::cout << "The elements with the minimum difference are:\n"
<< edif.first << " and " << edif.second << '\n'
<< "The difference between them is:\n" << edif.dif << '\n';
return 0;
}
If you want to find all the pairs with the same minimum difference you can modify the previous program like this:
#include <iostream>
#include <limits>
#include <vector>
#include <utility>
using std::cout;
using std::vector;
using std::pair;
struct dif_t {
vector<pair<int,int>> pairs;
int dif;
};
dif_t min_difference( const vector<int> &x ) {
dif_t min;
min.dif = std::numeric_limits<int>::max();
for ( size_t i = 0; i < x.size(); ++i ) {
for ( size_t j = i + 1; j < x.size(); ++j ) {
int dif = abs( x[i] - x[j] );
if ( dif > min.dif ) continue;
// if the difference is less then the minimum, empties the container
if ( dif < min.dif ) {
min.dif = dif;
min.pairs.clear();
}
// add the couple to the vector
min.pairs.push_back(std::make_pair(x[i], x[j]));
}
}
return min;
}
int main() {
vector<int> numbers = { 1, 2, 4, 34345, 34346, 6, 89, 7, 88 };
dif_t edif = min_difference(numbers);
cout << "The elements with the minimum difference are:\n";
// loop for each couple in the container
for ( auto & c : edif.pairs ) {
cout << c.first << " and " << c.second << '\n';
}
cout << "The difference between them is:\n" << edif.dif << '\n';
return 0;
}
Which outputs:
The elements with the minimum difference are:
1 and 2
34345 and 34346
6 and 7
89 and 88
The difference between them is:
1
If the number of elements is bigger, as others pointed out, you can sort the vector before calculating the differences, so you will minimize the comparison needed.
// this will change the original vector
dif_t min_diff_sorted( vector<int> &x ) {
// erase the reference symbol ^ if you want to sort a copy of the vector
dif_t min;
min.dif = std::numeric_limits<int>::max();
// usually sorting algorithms have N*logN complexity
std::sort( x.begin(), x.end() );
// now that the vector is sorted we can compare the adiacent elements only.
// This time I'll use two iterators to access the elements of the vector
// ix will iter from the beginning of the vector to the last - 1 element
// jx points to the element adjacent (+1) to ix
for ( auto ix = x.begin(), jx = ix + 1;
jx != x.end(); // stop condition
ix = jx, jx++ ) {
// the inner part doesn't change, it's only executed N-1 times
// instead of N*(N-1)/2
int dif = abs( *ix - *jx );
if ( dif > min.dif ) continue;
if ( dif < min.dif ) {
min.dif = dif;
min.pairs.clear();
}
min.pairs.push_back(std::make_pair(*ix, *jx));
}
return min;
}
You can calculate mindiff at start as abs(arr1[0]-arr1[1]) and then proceed to calculate it inside the loop:
// check whether array size is >=2 or not
mindiff = abs(arr1[0]-arr1[1]);
for ( x=0;x<size1;x++ )
{
for ( y=0;y<size1;y++ )
{
// do not calculate the difference of same number
if(x!=y){
diff = abs(arr1[x] - arr1[y]);
if (diff<=mindiff)
{
mindiff = diff;
number1 = arr1[y];
number2 = arr1[x];
cout<<number1<< ","<<number2<<endl;
}
}
}
}
cout<<"\nthe elements amongst which the minimum difference was given are "<<number1<<" & "<<number2<<endl;
cout<<"the difference between them is "<<abs(mindiff)<<endl;
Taking the advice from Beta and also looking at the only answer that i found aligning with my code perspective, i came up with the following smal but critical edit of my own code above. Not much change but a very important and essential change.
PFB the code which indicates that fact that i had a logical error in not loading the difference value temporarily in a variable before exiting the innermost loop for the next iteration for comparing the absolute difference value.
#include <iostream> //input output stream
#include <cstdlib>
//#include <vector> not used //to enable usage and implementation of vectors
#include "math.h" //to be able to do complex math functions if any
//#include <algorithm> not used //to be able to use max_element() and distance() functions on iterator.
using namespace std;
int main()
{
/*
first different variables for loop counters and
size of array is taken in advanced instead of calculating during the program to reduce program time
*/
int x=0,y=0,number1 = 0,number2 = 0,size1=0,mindiff = 0;
int index = 0, count = 0, diff = 0;
cout<<"enter the size of array you want \n\n";
cin>>size1;
int arr1[size1];
cout<<"\n\n please enter elements of array \n\n";
for (int i =0;i<size1;i++)
{
cin>>arr1[i];
}
for ( x=0;x<size1;x++ )
{
for ( y=0;y<size1;y++ )
{
if (x!=y)
/*
now load the difference in a variable named diff
and use a comparisional conditional statement to select
value of minimum difference
*/
{
diff = abs(arr1[x] - arr1[y]);
if(count == 0)
{
mindiff = diff;
}
else
{
if (diff<mindiff)
{
cout<<diff<<" minimum difference "<<"\n";
mindiff = diff;
//index = x+1;
number1 = arr1[x];
number2 = arr1[y];
}
}
count++;
}
}
}
cout<<"\nthe elements amongst which the minimum difference was given are "<<number1<<" & "<<number2<<endl;
cout<<"the difference between them is "<<abs(mindiff)<<endl;
cout<<endl<<endl;
system("pause");
return 0;
}
This lets me perceive that perspective of coding does work for this case. Sure it might be slow and inefficient but its a result.
gratitude to all for their time.
So, this is a weekly project for school, and I have got it completely working, but feel as if the way I did it, probably isn't one of of the best ways to do it ( or even a good way ). I was hoping you guys could help optimize it / give a better solution. I have already submitted this version, but would like to know a more optimal solution to the problem.
So to start, here's the problem...
It's almost Halloween and Linus is setting out to the garden to wait for the Great Pumpkin. Unfortunately, due to diversification, there are lots of other gourds in the garden this year, so he needs you to write a program to tell him how many patches of pumpkins there are and how big they are.
The input to this program will be a number of different gardens. The first line of the input for each garden will be the dimensions of the garden, r, the number of rows in the garden, and c, the number of columns, where 0 ≤ r ≤ 40 and 0 ≤ c ≤ 40. Following the dimensions will be r lines with c characters on each line. Each of these characters will be a lower case letter representing the type of gourd grown in the square. A lower case 'p' will represent pumpkins. A garden with 0 for the number of rows and/or columns indicates the end of input and should not be processed.
Example input:
10 10
pzzzzzzzzp
pyypzzzzzy
ppppssssyy
ssspssssyy
ssssppssyy
ssssppsspy
zzzzzzsspy
zzzzzzsspy
yyyypzsspy
yyyypppppy
3 4
pppp
pppp
pppp
1 7
zzzzzzz
0 0
For each garden, output the number of the garden (with the first input set being garden 1), the number of pumpkin patches in the garden, and the size of the pumpkin patches in order from smallest to largest. If there is more than one patch of a given size, print the size as many times as it occurs. Use the following format:
Example Output:
Garden # 1: 4 patches, sizes: 1 4 8 10
Garden # 2: 1 patches, sizes: 12
Garden # 3: 0 patches, sizes:
Note: Even though the problem says to input from a file, our professor told us to input through the keyboard.
My approach to this was to put the garden into a 2d array with a border of x's around it. I would then use a function to find a pumpkin patch ( and return its coordinates ). I would then use another function that recursively found if a pumpkin was attached to that one through above, below, left, and right, and returned the size of the pumpkin patch. This function also 'deletes' each pumpkin when it finds it by replacing it by an 'x'. This allowed me to not have to worry about finding pumpkins multiple times.
So here's my code, pretty well commented so that you guys could hopefully understand what I was trying to do.
#include <iostream>
#include <fstream>
using namespace std;
const int MAX_ROW = 41;
const int MAX_COL = 41;
char input ();
int checkForPatchSize ( char arr[][MAX_COL], int numOne, int numTwo );
bool findPatch ( char arr[][MAX_COL], int &row, int&col );
void sort ( int arr[], int size);
int main ()
{
int inputNumOne = -1; // Defaulted to -1, First number for Patch Size
int inputNumTwo = -1; // Defaulted to -1, Second number for Patch Size
int i, j; // i, j are indexes for loops, number
int numArr[MAX_ROW][MAX_COL]; // Array for storing Data
int indexGarden = 0;
int index = 1;
while ( inputNumOne != 0 )
{
cin >> inputNumOne; // User inputs Dimension
cin >> inputNumTwo; // Of Garden...
if ( inputNumOne != 0 and inputNumTwo != 0 ) // End case is that both are 0.
{
char pumpkinPatch[MAX_ROW][MAX_COL]; // Array for storing pumpkin patch info.
for ( i = 0; i < inputNumOne+2; i++ )
{
for ( j = 0; j < inputNumTwo+2; j++ )
{
// This if statement surrounds the garden in X's so that I have a border (allows me to not have to worry about test cases.
if ( i == 0 or j == 0 or i == inputNumOne + 1 or j == inputNumTwo + 1 )
{
pumpkinPatch[i][j] = 'x';
}
else // This is the input of the garden into a 2d array.
{
pumpkinPatch[i][j] = input();
}
}
}
int row, col, size, numberOfPatches = 0;
bool foundPatch = true;
index = 1;
while ( foundPatch == true )
{
row = inputNumOne+2; // Because I added a border to the garden
col = inputNumTwo+2; // the size is +2 of what the user input.
foundPatch = findPatch ( pumpkinPatch, row, col ); // Finds the start of a pumpkin patch, and returns the coordinates ( as row and col ).
if ( foundPatch == true ) // If a patch is found....
{
numberOfPatches++; // Increase number of patches
size = checkForPatchSize ( pumpkinPatch, row, col); // find size of particular patch
numArr[indexGarden][index] = size; // put size into data arr (to be printed to screen later).
index++;
}
}
numArr[indexGarden][0] = numberOfPatches; // Put number of patches as first item in each column of data arr.
indexGarden++;
}
}
for ( index = 0; index < indexGarden; index++ ) // Print out Garden Info
{
cout << "Garden # " << index + 1 <<": " << numArr[index][0] << " patches, sizes: ";
int temp = numArr[index][0]; // temp is the number of patches in particular garden.
int tempArr[temp]; // temp array to be used for sorting
int indexTwo;
for ( indexTwo = 0; indexTwo < temp; indexTwo++ )
{
tempArr[indexTwo] = numArr[index][indexTwo+1]; // Transfer sizes into a temp array so that they can be sorted.
}
sort (tempArr, temp); // Sort ( Sorts arr from smalles to larges )
for ( indexTwo = 0; indexTwo < temp; indexTwo++ ) // Output sorted array to screen.
{
cout << tempArr[indexTwo] << " ";
}
cout << endl;
}
}
char input()
{
char letter;
cin >> letter;
return letter;
}
/////////////// findPatch /////////////////////////////////////////////////
// Requirements: a 2D array of garden, and the size of it (row and col). //
// Returns a bool, true if patch is found, false if no patches found. //
// row and col are returned by reference to be the coordinates of one //
// of the pumpkins in the patch. //
///////////////////////////////////////////////////////////////////////////
bool findPatch ( char arr[][MAX_COL], int &row, int&col )
{
int rowIndex = 0;
int colIndex = 0;
while ( arr[rowIndex][colIndex] != 'p' and rowIndex < row )
{
colIndex = 0;
while ( arr[rowIndex][colIndex] != 'p' and colIndex < col )
{
colIndex++;
}
if ( arr[rowIndex][colIndex] != 'p' )
{
rowIndex++;
}
}
if ( arr[rowIndex][colIndex] != 'p' )
{
return false;
}
row = rowIndex;
col = colIndex;
return true;
}
/////////////// checkForPatchSize /////////////////////////////////////////
// Requirements: a 2D array of garden, and the coordinates of the start //
// of a patch. (Gotten from findPatch) //
// Returns an int, which is the size of the patch found //
// All p's or pumpkins are changed to x's so that they are not used //
// multiple times. //
///////////////////////////////////////////////////////////////////////////
int checkForPatchSize ( char arr[][MAX_COL], int numOne, int numTwo )
{
int index = 0;
if ( arr[numOne][numTwo] == 'p' )
{
index++;
arr[numOne][numTwo] = '0';
// Check Above
index += checkForPatchSize ( arr, numOne - 1, numTwo );
// Check to Left
index += checkForPatchSize ( arr, numOne, numTwo - 1 );
// Check Below
index += checkForPatchSize ( arr, numOne + 1, numTwo );
// Check to Right
index += checkForPatchSize ( arr, numOne, numTwo + 1 );
return index;
}
return 0;
}
/////////////// sort //////////////////////////////////////////////////////
// Requirements: an integer array, and the size of it (amount of //
// numbers in it). //
// //
// Sorts an array from smalles to largest numbers //
///////////////////////////////////////////////////////////////////////////
void sort ( int arr[], int size )
{
int index = 0;
bool changeMade = true;
while ( changeMade == true )
{
changeMade = false;
for ( index = 0; index < size - 1; index++ )
{
if ( arr[index] > arr[index+1] )
{
int temp = arr[index];
arr[index] = arr[index+1];
arr[index+1] = temp;
changeMade = true;
}
}
}
}
Alright, after reading through your code, I see your approach. Generally, I would approach this from a visual perspective. As it is, your code should work just fine, and is quite an elegant solution. The single weakness of your algorithm is the fact that it iterates over the same patch each time it moves. For example, when it moves upwards, it checks downwards. Avoiding redundancy is the surest sign of an optimal algorithm, but in terms of the small-scale at which you are deploying the algorithm, it need not be optimal.
In a way, the recursive nature of your code makes it quite beautiful because it traverses the pumpkin patch like little sparks that die out, which I really do like. Recursion is something which I don't often bother myself with, mostly because I don't think recursively, but after spending a moment wrapping my head around your algorithm, I really do see its value in cases like this. I would love to see the algorithm at work with dynamic visuals.
As for the accuracy of your algorithm, I can not imagine that it would fail in any manner to count the pumpkins correctly because it functions by making a small wave around the picked pumpkin in which the algorithm repeats itself, effectively propagating through the patch until it is all counted. As I said, the only shortcoming of your algorithm is that it would fall into an infinite loop if you did not somehow mark pumpkins as found (it checks the position it was called from). Beyond that, I can only say that you've proposed an excellent solution and that your doubts are almost entirely misplaced. Using a recursive algorithm was an excellent choice in this regard because it doesn't require a long list of cases in order to 'count'; it simply jumps into adjacent positions, returning to itself with the full count.
So I'm trying to make a basic program to learn the basics of C++, I'm generating 100 random numbers from 0 to 100 and storing them in a vector, I am then displaying the sum, mean, median, mode, high and low of the vector. I have everything else done except the mode which is where I get stuck. Here is the code I have so far.
int modeFunction()
{
numMode = 0;
count = 0;
for (int n = 0; n < 100; n++)
{
for (int y = 0; y < 100; y++)
{
if (numVector.at(y) == numVector.at(n))
{
numMode = numVector.at(y);
count++;
}
}
}
return numMode;
}
After that I get stuck because in my mind that should work but it doesn't. It just out puts the last number, usually 100. Any help would be much appreciated.
since all the values are between 0 and 100, you can find the mode efficiently with a histogram:
std::vector<int> histogram(101,0);
for( int i=0; i<100; ++i )
++histogram[ numVector[i] ];
return std::max_element( histogram.begin(), histogram.end() ) - histogram.begin();
Since mode is the number that occurs most frequent you shouldn't change numMode unless the new number's count is greater than numMode's count.
EDIT: To clarify, you need to keep a separate count for the current element and the current number that you think is the mode. Ideally, setting newMode to the first element is a good approach.
In addition, mode isn't necessary unique (i.e. "1 1 2 2"). You may want to keep that in mind if you care about that.
newMode = element[0]
modeCount = # of occurrence of newMode
for ( i-th element from [1 to end] ) {
tmpCount = # of occurrence of element[i]
if tmpCount > modeCount {
newMode = element[i]
modeCount = tmpCount
}
}
bmcnett's approach works great if number of elements are small enough. If you have large number of elements but the all element value are with in a small range using map/hashmap works well. Something like
typedef std::pair<int, int> mode_pair;
struct mode_predicate
{
bool operator()(mode_pair const& lhs, mode_pair const& rhs)
{
return lhs.second < rhs.second;
}
};
int modeFunction()
{
std::map<int, int> mode_map;
for (int n = 0; n < 100; n++)
mode_map[numVector[n]]++;
mode_predicate mp;
return std::max_element(mode_map.begin(), mode_map.end(), mp)->first;
}
Your algorithm is wrong - it outputs the last number in the array because that's all it can ever do. Every time the number at index y matches the number at index n you overwrite the results for the previous n. Since you're using the same loop conditions, y and n are always the same at at least one point in the nested loop for each possible n value - and you'll always end up with numMode being numVector.at(99).
You need to change your algorithm to save the count for each n index along the way (or at least which n index ended up with the greatest count), so that you can know at the end of the n loop which entry occured the most times.
Alternative solutions. Note: untested.
int mode1(const std::vector<int>& values)
{
int old_mode = 0;
int old_count = 0;
for(size_t n=0; n < values.size(); ++n)
{
int mode = values[n];
int count = std::count(values.begin()+n+1, values.end(), mode);
if(count > old_count)
{
old_mode = mode;
old_count = count;
}
}
return old_mode;
}
int mode2(const std::vector<int>& values)
{
return std::max_element(values.begin(), values.end(), [](int value)
{
return std::count(values.begin(), values.end(), value);
});
}
Mode means a number with highest frequency. The logic should be -
//Start of function
int mode = 0, globalCount = 0 ;
// Start of outer for loop
for i = 0 to length - 1
int localCount = 0
// Start of inner for loop
for j = 0 to length - 1
if vec[i] == vec[j]
++localCount
// End of Inner for loop
if ( localCount > globalCount )
globalCount = localCount
mode = vec[i]
// End of outer for loop
if globalCount > 1 // This should be checked whether vec has repetitions at all
return mode
else
return 0
// End of function
int number = array_list[0];
int mode = number;
int count = 1;
int countMode = 1;
for (int i=1; i<size_of_list; i++)
{
if (array_list[i] == number)
{ // count occurrences of the current number
count++;
if (count > countMode)
{
countMode = count; // mode is the biggest ocurrences
mode = number;
}
}
else
{ // now this is a different number
if (count > countMode)
{
countMode = count; // mode is the biggest ocurrences
mode = number;
}
count = 1; // reset count for the new number
number = array_list[i];
}
}
I'm C++ begginer. I did this excercise from Deitel's book:
Use a one-dimensional array to solve
the following problem. Read in 20
numbers, each of which is between 10
and 100, inclusive. As each number is
read, validate it and store it in the
array only if it is not a duplicate of
a number already read. After reading
all the values, display only the
unique values that the user entered.
Provide for the "worst case" in which
all 20 numbers are different. Use the
smallest possible array to solve this
problem.
Here is my code:
#include <iostream>
using namespace std;
bool compare(int arrayNum[],int arraySize,int element);
int main()
{
const int size=20;
int i=1;
int num[size];
int arrayElement;
int counter=0;
while(i<=20)
{
cin>>arrayElement;
if(i==1) //stores first element in array
num[0]=arrayElement;
//compare new element with stored elements
//if element is not a duplicate store it in array
else if (compare(num,size,arrayElement))
{
counter++;
num[counter]=arrayElement;
}
i++;
}
//displays array elements
for(int k=0;k<=counter;k++)
cout<<num[k]<<endl;
return 0;
}
//compare elements in array
bool compare(int arrayNum[],int arraySize,int element)
{
for(int j=0;j<arraySize;j++)
{
if(arrayNum[j]==element)
return false;
}
return true;
}
It works, but I'm not sure if I have interpreted the task correctly. I assume then I don't have to include conditional statement for range of numbers (10 to 100 inclusive), as this will be read from the keyboard and input by me. Therefore why was this instruction included? Also at the end it says
use the smallest possible array
I assume the max size has to be 20,but I don't think there is a way to dynamically expand array size (for example while storing new elements) as array size is const. I would appreciate if someone could help me with this. Any comments regarding code, or better solution are welcome.
As each number is read, validate
it and store it in the array
Emphasis mine. The text clearly says that your program has to validate the input. In other words, it has to check that the entered number is between 10 and 100, and if it is not, handle the error appropriately. So yes, you do need a conditional, although exactly what you do to handle the error is up to you.
And you're right, since arrays aren't dynamically resizable, the array size has to be at least 20.
You do need a conditional. Basically it's saying to take in a number between 10 and 100. If it's not a number between those ranges, don't store it. Also, if that number already exists in the array, don't store it. Then just print out the values in the array.
You assume correct about the array size, it's maximum size would be 20, although you may not store all 20 values (again, because some input might be bad).
The smallest possible array is a char[12], where the individual bits are used as flags.
char data[12]; // memset(data, 0, sizeof(data)); in main();
void set(int n_raw;)
{
int n = n_raw - 10;
int index = n/8;
int offset = n-8*index;
data[index] |= 1 << offset; // added "1 <<"
}
Reading the values back is left as an exercise for the student.
I assume then I don't have to include
conditional statement for range of
numbers (10 to 100 inclusive), as this
will be read from the keyboard and
input by me. Therefore why was this
instruction included?
Sure, in this case you wrote the code and know to enter numbers within the range expected; however, it is a standard best-practice to always validate input data from a user, always. That way erroneous values are handled gracefully (with an appropriate error message) and helps to make your program more robust.
Also at the end it says
use the smallest possible array
I assume the max size has to be 20,,,
I think what they might have been getting at here is that you could have used an array of 91 bytes as shown below.
int cnt = 0; // count of unique values entered
byte values[91]; // values entered indicator array
int valIdx; // used as values array index
memset((void *)values, 0, sizeof(values)); // initialize array to all zeros
while ( cnt < 20 )
{
// [code for the following comments not shown]
// have user input a number
// validate the number (>= 10 && <= 100)
// subtract 10 from the number and store it in valIdx
// (now valIdx will contain a number >= 0 <= 90)
if ( !values[valIdx] )
{
values[valIdx] = 1;
++cnt;
}
}
// then to show the unique values...
for ( valIdx = 0; valIdx < sizeof(values); valIdx++ )
{
if ( values[valIdx] )
{
cout << valIdx + 10 << endl;
}
}
That solution however, would not have met the "use the smallest array possible" requirement.
Back to your code...
I would go ahead and add the user input validation, just for completeness (and to get into the habit of never trusting users (especially yourself).
As far as improvements go, here is one thing to think about. The compare routine goes through every array element when a unique number has been entered. It only needs to check against those that have a stored value in them. Making that change should lead you to refactor the contents of your while loop as well.
I'm studying C++ in the same book!!
My first implementation for solving this problem was one that don't use any complementar array.. it uses a linear search to find duplicates..
take a look:
#include <iostream>
using namespace std;
// remember: size_t = unsigned int
const size_t arraySize = 20;
size_t _array[ arraySize ];
// global variable to keep track of the last used
// position in the _array
size_t counter = 0;
// the argument is not changed, so pass it by
// const reference
bool dupSearch( const int & );
int main()
{
// disregard this
ios_base::sync_with_stdio( false );
// "temp" variable declared outside the loop to
// avoid repeated allocation and deallocation
int i = arraySize, temp;
// look at the loop condition below " ( i-- ) "
// remember:
// false = ( every expression evaluated to 0 )
// true = ( every expression evaluated to a non-zero result )
// more details on pag. 108 of the book. 8/e Portability tip 4.1
while ( i-- )
{
// read the number from the user
cin >> temp;
// if the number entered is valid, put the
// number on _array[ counter ] and increment 'counter'
if ( dupSearch( temp ))
{
_array[ counter ] = temp;
++counter;
}
}
// print the result in column format
cout << endl;
for ( size_t j = 0; j < counter; ++j )
cout << _array[ j ] << endl;
}
// validation: if the value is out of the described range, return false
// if is in the range, check for duplicates using linear search.
// if a duplicate is found, return false
// otherwise, return true.
bool dupSearch( const int &a )
{
if ( a < 10 || a > 100 )
return false;
else
for ( size_t i = 0; i < counter; ++i )
if ( _array[ i ] == a )
return false;
return true;
}
the number of comparisons is
n = ( n * ( n + 1 )) / 2
where n = counter. worst case --> counter = 20 numbers --> loop 210 times through the program execution.