I am trying to finish a problem where I read a file into the program and output a file with the average, min, max, and the count of how many times that number occurred in the program. However, I cannot figure out how to create an array for duplicated number of the "counts".
If the file that I was trying to read in had the values 19 5 26 5 5 19 16 8 1,
I need the outputted file to read 5---3 times; 8---1 time; 16---1 time; 19--2 times; 26--1 times.
I first sorted my array to read 5 5 5 8 16 19 19 26.
Below is my code with explanations of what I was trying to do:
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
using namespace std;
double averageArray(int a[], int length); // user defined function to get average
int maxval(int a[], int length); //user defined function to get max val
int minval(int a[], int length); //user defined function to get min val
void bsort(int arr[], int length);// udf to sort array from min to max
int countArray(int a[], int length); //attempt to create a function to get the number of occurrences of a number that is duplicated
int main()
{
char infilename[16];
int nums[50];//newly created array to read in the numbers from the file
int length(0);//array has a length defined by "length"
ifstream fin;
ofstream fout;
cout << "Please enter an input file name: ";
cin >> infilename;
cout << endl;
fin.open(infilename);
if (fin.fail())
{
cerr << "The file " << infilename << " can't be open!"<<endl;
return 1;
}
cout<<"The output to the file statistics.txt should be as follows: "<<endl;
fout.open("statistics.txt");
fout<<"N"<<"\t"<<"Count"<<endl;
cout<<"N"<<"\t"<<"Count"<<endl;
while (fin >> nums[length])
length++;
bsort(nums, length);
for (int i=0; i<length; i++) {
if (nums[i]==nums[i-1]) {
continue;
}
cout<<nums[i]<<"\t"<<countArray(nums,length)<<endl;
fout<<nums[i]<<"\t"<<endl;
}
cout << "\nAverage: " << averageArray(nums,length) << endl;
cout << "Max: "<< maxval(nums,length)<<endl;
cout << "Min: "<< minval(nums,length)<<endl;
fin.close();
return 0;
}
double averageArray (int a[], int length)
{
double result(0);
for (int i = 0; i < length ; i++)
result += a[i];
return result/length;
}
int maxval(int a[], int length)
{
int max(0);
for (int i=1; i<length; i++)
{
if (a[i]>max)
max=a[i];
}
return max;
}
int minval(int a[], int length)
{
int min(100);
for (int i=1; i<length; i++)
{
if (a[i]<min)
min=a[i];
}
return min;
}
void bsort(int a[], int length)
{
for (int i=length-1; i>0; i--)
for (int j=0; j<i; j++)
if (a[j]>a[j+1])
{
int temp=a[j+1];
a[j+1]=a[j];
a[j]=temp;
}
}
int countArray(int a[], int length)
{
int counter(0);
for (int i=0; i<length; i++){
if (a[i]==a[i+1]) //loop through array and if the number after is the same as the previous number, then count one
counter++;
}
return counter;
}
Though it compiles, the count only shows "3"s as shown in the picture below:
.
Before I give you the solution, please take a moment to remember, you are programming in C++, not C. As such, you ought to use vectors, istream iterators and std::sort. You also ought to use std::map, which easily accomplishes this purpose:
template <typename It>
std::map<int, int> count_occurrences(It it, It end)
{
std::map<int, int> output;
while (it != end) output[*it++]++;
return output;
}
How to combine this with your existing code is left as an exercise for the reader. I suggest you ought to read about iterators.
Your function int countArray(int a[], int length) has no input for the actual number. It always counts how often there are the same numbers behind each other in your array. That happens two times for fives and once for 19 => 3 times.
Solution:
int countArray(int a[], int length, int num)
{
int counter(0);
for (int i=0; i<length; i++){
if (a[i]==num) //loop through array and if the number is the one you are looking for
counter++;
}
return counter;
}
and call you function: countArray(nums, length, nums[i]);
void countArray(int a[], int length)
{
int counter(1);
bool flag(false);
//you take (i+1) index, it can go out of range
for (int i = 0; i < length - 1; i++){
if (a[i]==a[i+1]){ //loop through array and if the number after is the same as the previous number, then count one
flag = true;
counter++;
}
else {
if (flag){
cout<<a[i] << counter << endl;
}
flag = false;
counter = 1;
}
}
}
I didn't code on C for a long time, but I hope it'll help.
This procedure will print you the answer, and you have to call it just once.
I suggest to use std::map which is the best solution to solve your problem. I will try to explain easily the differents steps to do this:
I consider your variables initialized, for instance:
int length = 9;
int nums[length] = {19, 5, 26, 5, 5, 19, 16, 8, 1};
Create the std::map<int,int>, where the key (first int) will be your number and the value (second int) the number of occurence of this number store in the key.
std::map<int,int> listNumber;
Fill your map
// For all numbers read in your file
for(int i=0; i<length; ++i)
{
// Get number value
int n = nums[i];
// Find number in map
std::map<int, int>::iterator it = listNumber.find(n);
// Doesn't exists in map, add it with number of occurence set to 1...
if(it == listNumber.end())
{
listNumber.insert(std::pair<int,int>(n,1));
}
// ... otherwise add one to the number of occurence of this number
else
{
it->second = it->second+1;
}
}
Read the map
// Read all numbers and display the number of occurence
std::cout << "N" << "\t" << "Count" << std::endl;
for(std::map<int, int>::iterator it = listNumber.begin(); it!=listNumber.end(); ++it)
{
std::cout << it->first << "\t" << it->second << std::endl;
}
Related
I had a task from one course on Udemy to create a program which eliminates duplicates from array and i failed so I have looked to my instructors code and I don't understand few things.
Why don't you have to write the capacity of array (function input) ? it is because of that you already has written the elements of array so it was recognized how long it is ?
the if statement for not true Boolean: the counter is initialized to zero so for the first time when unique_data[counter++]=numbers[i=0] is counter also zero a then it is incremented ?
sorry for asking these questions but I am little bit worried that i have not been able to solve this myself
void unique_numbers( int numbers[], unsigned int collection_size){
int unique_data [20];
unsigned int unique_counter{};//Initialized to zero. Counts the elements we have in
//the unique_data array
for(unsigned int i{}; i < collection_size; ++i){
bool already_in{false};
//See if the element is not already in our unique_data
for(unsigned int j{};j < unique_counter; ++j){
if(unique_data[j] == numbers[i]){
already_in = true;
break;
}
}
if(!already_in){
unique_data[unique_counter++] = numbers[i];
}
}
std::cout << "The collection contains " << unique_counter << " unique numbers, they are : ";
for(unsigned int i{};i < unique_counter ; ++i){
std::cout << unique_data[i] << " ";
}
I have modified your program with std::vector and std::find . The logic is the same. Now it is more readable. Hope you will understand it.
#include <iostream>
#include <vector>
#include <algorithm>
void unique_numbers(int numbers[], unsigned int collection_size)
{
std::vector<int> unique_data;
for (unsigned int i{}; i < collection_size; ++i)
{
//Find numbers[i] in unique_data. If it is not found insert it in unique_data
auto it = std::find(unique_data.begin(), unique_data.end(), numbers[i]);
if (it == unique_data.end())
{
unique_data.push_back(numbers[i]);
}
}
//print unique_data vector
std::cout << "The collection contains " << unique_data.size() << " unique numbers, they are : ";
for (const auto& v : unique_data){
std::cout << v << " ";
}
std::cout << std::endl;
}
int main()
{
int a[] = { 1, 2, 3, 4, 5, 4, 3, 2, 1 };
unsigned int n = sizeof(a)/sizeof(int);
unique_numbers(a, n);
}
i have to return the max len of consecutive seq present in an array.
consider the example:-
N = 7
a[] = {2,6,1,9,4,5,3}
my code should return 6 but its giving 1. don't know how?
int findLongestConseqSubseq(int arr[], int N)
{
//Your code here
unordered_map<int,int> mp;
int ans=0;
for(int i=0;i<N;i++){
if(mp.count(arr[i])>0){
continue;
}
int len1=mp[arr[i]-1];
int len2=mp[arr[i]+1];
int ns=len1+len2+1;
ans=max(ans,ns);
mp[arr[i]-len1]=ns;
mp[arr[i]+len2]=ns;
// ans=max(ans,ns);
}
return ans;
}
There are two problems with your implementation.
The first issue is the code:
if(mp.count(arr[i])>0){
continue;
}
this code is not sufficient to ensure that repeated numbers do not make it into the rest of your loop (to see why this is, consider what happens with neither len1 or len2 are zero).
You can replace it with something like:
if(!mp.insert(pair<int,int>(arr[i], 1)).second) {
continue;
}
This will skip the rest of the loop if an entry for arr[i] exists, but also ensures that an entry will exist after the if expression is evaluated.
The second issue is with the code:
int len1=mp[arr[i]-1];
int len2=mp[arr[i]+1];
the subscript operator for maps in C++ has a side-effect of creating an entry if one does not exist. This is problematic for your algorithm because you do not want this to happen. If it did it would cause the previous piece of code to skip numbers it shouldn't. The solution is to use find but since the code for this is a little ugly (IMHO) it's probably neater to write a helper function:
inline int findOrDefault(const unordered_map<int, int>& map, int key, int defaultValue) {
auto find = map.find(key);
return (find == map.end()) ? defaultValue : find->second;
}
and use this to update your code to:
int len1=findOrDefault(mp, arr[i]-1, 0);
int len2=findOrDefault(mp, arr[i]+1, 0);
Putting this all together you end up with:
inline int findOrDefault(const unordered_map<int, int>& map, int key, int defaultValue) {
auto find = map.find(key);
return (find == map.end()) ? defaultValue : find->second;
}
int findLongestConseqSubseq(int arr[], int N)
{
unordered_map<int,int> mp;
int ans=0;
for(int i=0;i<N;i++){
if(!mp.insert(pair<int,int>(arr[i], 1)).second) {
continue;
}
int len1=findOrDefault(mp, arr[i]-1, 0);
int len2=findOrDefault(mp, arr[i]+1, 0);
int ns=len1+len2+1;
ans=max(ans,ns);
mp[arr[i]-len1]=ns;
mp[arr[i]+len2]=ns;
}
return ans;
}
Ok had a moment to look at this again and I came up with this. First we sort the array to make things easier. Then we can go through the numbers with one pass, counting each time the next consecutive number is greater by one. If the next number is not one greater after sorting, then we reset and start counting again, storing the highest streak count in max.
#include <iostream>
#include <algorithm>
#include <iterator>
using namespace std;
int main()
{
cout << "Get Longest Consecutive Streak: " << endl;
int intArray[] = { 9, 1, 2, 3, 4, 6, 8, 11, 12, 13, 14, 15 ,16 };
int arrayLength = size(intArray);
sort(intArray, intArray + arrayLength); //Sort Array passing in array twice plus amount of indexes in array
cout << "Sorted Array looks like this:" << endl; //Outputting sorted array to check
for (int i = 0; i < arrayLength; i++) {
cout << intArray[i] << " ";
}
cout << endl;
int count = 1;
int max = 1;
/*
* Loop through array, if the next number is one greater than current then add to count
* If it is not, reset the count.
* Store highest count value found passing through.
* */
for (int i = 0; i < arrayLength -1; i++) {
if (intArray[i + 1] == intArray[i] + 1) { //checking next value - is it equal to this one + 1?
count++;
}
else { //else if it is not, store the value if it is higher that what is currently there, then reset
if (max < count) {
max = count;
}
count = 1;
}
}
//Edge case: check again one more time if the current count (when finishing) is greater than any previous
if (max < count) {
max = count;
}
cout << "Longest Consecutive Streak:" << endl;
cout << max << endl;
return 0;
}
I am supposed to be creating a program that asks a user to populate an array of size 10. There are three functions which by their name are self-explanatory; one fills up the array with elements, the second one displays the array horizontally, and the third function checks to see if a number entered by the user is an element in the array.
#include<iostream>
#include<iomanip>
void fillUpArray(int array[], int size);
void displayArray(int array[], int size);
bool isNumberPresent(int array[], int size, int SearchNum);
int main(){
int s = 10; //size of array
int A[s]; //array A with size s
int num; //search number
fillUpArray(A, s);
std::cout <<"\n";
displayArray(A, s);
std::cout << "\n";
std::cout << "Enter a number to check if it is in the array:\n";
std::cin >> num;
std::cout << std::boolalpha << isNumberPresent(A, s, num) << std::endl;
return 0;
}
void fillUpArray(int array[], int size)
{
std::cout << "Enter 10 integers to fill up an array, press enter after every number:\n";
for(int i = 0; i < size; i++){
std::cin >> array[i];
}
}
void displayArray(int array[], int size)
{
for(int j = 0; j < size; j++){
std::cout << array[j] << "\t";
}
}
bool isNumberPresent(int array[], int size, int SearchNum)
{
bool isPresent;
for(int k = 0; k < size; k++){
if(array[k] == SearchNum)
isPresent = true;
else
isPresent = false;
}
return isPresent;
}
That last function, which is a bool function, is not performing the way I thought it would. I thought by doing array[k] whatever index k is then it should spit out the element in the array and then with the expression if(array[k] == SearchNum) it should then work as if(element == SearchNum) but that doesn't seem to be the case and the output is always false.
The for loop in your isNumberPresent function will run to the end of the array (until k equals size) unconditionally; in each run of that loop, you set the value of the isPresent variable according to whether or not the current element is a match for searchNum, overwriting the previous value. So, the function, as it stands, will simply return whether or not the last element in the array is the same as the given test number.
You can simplify that function and remove the need for the local variable: if you find a match, then return true immediately; if the loop ends without finding a match, then return false:
bool isNumberPresent(int array[], int size, int SearchNum)
{
for(int k = 0; k < size; k++){
if(array[k] == SearchNum) return true; // Found a match - we can return immediately
}
return false; // We didn't find a match
}
Note, also, that Variable Length Arrays (VLAs) are not part of Standard C++, though some compilers (like GNU g++) support them (they are part of the C language according to the C99 Standard). In your program, as you only use one (fixed) value for the array size, you can conform to Standard C++ simply by qualifying that s is a const:
int main()
{
const int s = 10; //size of array - make this a "const" be 'proper' C++
int A[s]; //array A with size s
//...
I need to sort the net pays of employees as part of a payroll program. Employees are identified by an id number followed by their net pay. Like this:
11111 456.78
22222 891.01
33333 112.13
I need to sort the data so that it looks like this
22222 891.01
11111 456.78
33333 112.13
So basically I need to sort them by their pay but I need the id number to match the sorted pay.
code i have so far:
#include <iostream>
#include <fstream>
#include <iomanip>
#include <algorithm>
using namespace std;
/* Read data from file into array*/
int readData(long int[], double[], int);
/*print data from array unsorted*/
void printUnsorted(long int[], double, int);
/* sort items from array*/
void sort(long int[], double[], int);
/*Display sorted data to console*/
void printSorted(long int[], double, int);
void main() {
const int MAXSIZE = 100;
int n;
long int id[MAXSIZE];
double netpay[MAXSIZE];
n = readData(id, netpay, MAXSIZE);
printUnsorted(id, netpay);
sort(id, netpay);
printSorted(id, netpay);
}
int readData(long int id[], double netpay[], int n) {
ifstream input;
input.open("netpay.txt");
n = 0;
while (input >> id[n] >> netpay[n]) n++;
input.close();
return n;
}
void printUnsorted(long int id[], double netpay[], int n) {
cout << "Unsorted Data" << endl;
for (int i = 0; i < n; i++) {
cout << id[i] << "\t" << netpay[i] << "\t" << endl;
}
void sort(long int id[], double netpay[], int n) {
for (int i = 0; i < n; i++) {
sort(netpay.begin(), netpay.end());
}
}
void printSorted(long int id[], double netpay[], int n) {
cout << "Sorted Data" << endl;
for (int i = 0; i < n; i++) {
cout << id[i] << "\t" << netpay[i] << "\t" << endl;
}
}
Very messy I know, can anyone give me a step in the right direction? After this I have to do the same thing with pointers.
The are lots of thing to improve in your code. You have several syntax errors too. I recommend trying to debug you code first. But, the sorting part can be done as follows. First, make pairs from the data (id, netpay). Then, save pairs in a container like std::vector. Next, sort the pairs using std::sort with respect to their second elements, netpays. Finally, write back the data from pairs into id and netpay arrays.
void my_sort(int id[], double netpay[], int n) {
typedef std::pair<int, double> data_pair_t;
std::vector<data_pair_t> data;
for (int i = 0; i < n; i++) {
data.push_back(make_pair(id[i], netpay[i]));
}
sort(data.begin(), data.end(), [](data_pair_t a, data_pair_t b) {
return a.second < b.second;
} );
for(int i = 0; i < n; i++) {
id[i] = data[i].first;
netpay[i] = data[i].second;
}
}
You may check the code here and extend it as you progress. Of course, things can be simplified if you use std::vector instead of arrays and particular data structure for your input data.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I've been learning c++ recently (coming from java) and I am attempting to count the number of repeating values in an array. For some reason the array is not being properly passed to my counter function.
#include <iostream>
#include <time.h>
using namespace std;
//quicksort for int arrays, left should be left index (0), right is right index(last one)
void quSort(int input[], int left, int right);
//binary search will return the index of the target or -1 if not found
int biSearch(int input[], int target, int iLeft, int iRight);
//count reapeats in the array with biSearch
int countRepeats(int input[], int target);
int main()
{
srand((unsigned int) time(0));
int test[1000];
//generate 100 random numbers under 1000
for(int i = 0; i < 1000; i++)
test[i] = rand()%1000;
//output test original
cout << "orig: ";
for(int i = 0; i < sizeof(test)/sizeof(*test); i++)
{
cout << test[i] << " ";
}
cout << endl << endl;
//sorting
quSort(test,0,( (sizeof(test)/sizeof(*test))-1));
cout << "sorted: ";
for(int i = 0; i < sizeof(test)/sizeof(*test); i++)
{
cout << test[i] << " ";
}
//binary search test
int target;
int iTarget;
cout << "\nenter target: ";
cin >> target;
iTarget = biSearch(test,target,0,sizeof(test)/sizeof(*test));
cout << "\n the target is at index: " << iTarget << " :: test[" << iTarget << "] = " << test[iTarget];
//count repeats
cout << "\nWith " << countRepeats(test,target) << " repeats";
system("pause");
return 0;
}
//quicksort function; effiecent array sorter; important for furture array analysis!!!
void quSort(int input[], int left, int right)
{
int pivot = input[(left+right)/2];
int l = left;//to control loop
int r = right;
while(l <= r)//will get smaller over iterations
{
int placeHold;// for use in swap, temp number
//finds value higher than the pivot from left
while(input[l] < pivot)
l++;
//find value lower than pivot on right
while(input[r] > pivot)
r--;
//swapper
if(l <= r)
{
//if the value greater than pivot is to the left of the value
//lessser than pivot
placeHold = input[l];
input[l] = input[r];
input[r] = placeHold;
l++;
r--;
}
//recursion to sort whole array until l=r
if(left<r)
quSort(input, left, r);
if(l < right)
quSort(input, l , right);
}
}
//binary search function; array MUST be sorted
int biSearch(int input[], int target, int iLeft, int iRight)
{
if(iLeft > iRight)
return -1;
else
{
int iMid = ((iLeft+iRight)/2);
if(input[iMid] > target)
return biSearch(input, target, iLeft, iMid-1);
else if(input[iMid] < target)
return biSearch(input, target, iMid+1, iRight);
else
return iMid;//target found
}
}
//Must be sorted
int countRepeats(int *input, int target)
{
int holder[sizeof(input)/sizeof(*input)];
int biSResult;
int counter = 0;
biSResult = biSearch(input,target,0,sizeof(input)/sizeof(*input));
//bug test
cout<<"c++" << biSResult << "c++";
//
while(biSResult != -1)
{
holder[biSResult] = target;
counter++;
input[biSResult] = 0;
quSort(input,0,( (sizeof(input)/sizeof(*input))-1));
biSResult = biSearch(input,target,0,sizeof(input)/sizeof(*input));
}
biSResult = biSearch(holder,target,0,sizeof(holder)/sizeof(*holder));
while(biSResult != -1)
{
input[biSResult] = target;
holder[biSResult] = 0;
quSort(holder,0,( (sizeof(holder)/sizeof(*holder))-1));
biSResult = biSearch(input,target,0,sizeof(holder)/sizeof(*holder));
}
return counter;
}
If anyone knows why this is happening it would be a great help
There are several issues in countRepeats():
(1) as already mentionned in other answers, there is an error in the way parameters are passed. There is no way to calculate the size of the array in the function whether you use int* or int[]. So best pass arguments to this function as you do in quSort() by giving not only the array address but also a start and an end counter.
(2) your programme will crash if the user would asks for a target of 0 : your while(biSResult != -1) would loop for ever.
(3) this function sorts again and again the array. This seems to be pretty bad for performance. Why don't you make use of the fact that the array is already sorted ? You could start counting from the found index . Just think that you'd have to count before and after this position, because you're not sure that iTarget is the very first occurence. This could look like:
int countRepeats(int input[], int pos, int start, int end )
{
if (pos<start || pos>=end) // you never know !
return 0;
int counter = 1;
for (int i=pos-1; i>=start && input[i]==input[pos]; i--)
counter++;
for (int i=pos+1; i<end && input[i]==input[pos]; i++)
counter++;
return counter;
}
By the way, I've tested it and it works. You just have to adapt the prototype and call it in your main function with
cout << "\nWith " << countRepeats(test, iTarget, 0,
sizeof(test)/sizeof(*test) ) << " repeats";
The first parameter of function countRepeats declared as
int countRepeats(int *input, int target)
that is it has type int *
So
sizeof(input)/sizeof(*input)
is equivalent to
sizeof( int * )/sizeof( int )
If for example sizeof( int * ) is equal to 4 and sizeof( int ) also is equal to 4 then the expression will be equal to 1. That is the value of the expression does not depend on how many elements the array that was passed to the function as argument has.
You should pass the size of the array explicitly as an argument of the function. So th function should be declared as
int countRepeats(int *input, int n, int target);
Or you could declare the first parameter of the function as a reference to array.
You can't calculate the size of an array inside a function that received a pointer to the array. This is because the value of sizeof(input) inside your counting function is just going to return the size of a pointer to an int. So sizeof(input)/sizeof(*input) will always be 1.
If you instead calculate the size of the array and store it as an int in main, then pass that to your counting function it should work. So changing your counting function call to:
cout << "\nWith " << countRepeats(test,target,sizeof(test)/sizeof(*test)) << " repeats";
And your countRepeats declaration to:
int countRepeats(int input[], int target, int size);
Then inside your countRepeats definition, everywhere you had (sizeof(input)/sizeof(*input)) you can just say size:
int countRepeats(int *input, int target, int size)
{
int holder[size];
int biSResult;
int counter = 0;
biSResult = biSearch(input,target,0,size);
//bug test
cout<<"c++" << biSResult << "c++";
//
while(biSResult != -1)
{
holder[biSResult] = target;
counter++;
input[biSResult] = 0;
quSort(input,0,(size-1));
biSResult = biSearch(input,target,0,size);
}
biSResult = biSearch(holder,target,0,size);
while(biSResult != -1)
{
input[biSResult] = target;
holder[biSResult] = 0;
quSort(holder,0,(size-1));
biSResult = biSearch(input,target,0,size);
}
return counter;
}
But you should really just use std::vector instead. Could have had std::vector<int> test (1000); and since your countRepeats changes your array through calls to quSort you can pass the vector as a reference (just as efficient as passing a pointer, allows changes to affect the original): int countRepeats(std::vector<int>&, int target); and you can always find its size by test.size()