histogram program gives strange output C++ - c++

I have been writing code to produce a horizontal histogram. This program takes user input of any range of numbers into a vector. Then it asks the user for the lowest value they want the histogram to begin at, and how big they want each bin to be. For example:
if lowestValue = 1 and binSize = 20
and vector is filled with values {1, 2, 3, 20, 30, 40, 50} it would print something like:
(bin) (bars) (num)(percent)
[ 1-21) #### 4 57%
[21-41) ## 2 28%
[41-61) ## 2 28%
Here is most of the code that does so:
void printHistogram(int lowestValue, int binSize, vector<double> v)
{
int binFloor = lowestValue, binCeiling = 0;
int numBins = amountOfBins(binSize, (int)range(v));
for (int i = 0; i<=numBins; i++)
{
binCeiling = binFloor+binSize;
int amoInBin = amountInBin(v,binFloor, binSize);
double perInBin = percentInBin(v, amoInBin);
if (binFloor < 10)
{
cout << "[ " << binFloor << '-' << binCeiling << ") " << setw(20) << left << formatBars(perInBin) << ' ' << amoInBin << ' '<< setprecision(4) << perInBin << '%' << endl;
binFloor += binSize;
}
else
{
cout << '[' << binFloor << '-' << binCeiling << ") " << setw(20) << left << formatBars(perInBin) << ' ' << amoInBin << ' '<< setprecision(4) << perInBin << '%' << endl;
binFloor += binSize;
}
}
}
and the function that counts how many terms are in each bin:
int amountInBin(vector<double> v, int lowestBinValue, int binSize)
{
int count = 0;
for (size_t i; i<v.size(); i++)
{
if (v[i] >= lowestBinValue && v[i] < (lowestBinValue+binSize))
count += 1;
}
return count;
}
Now my issue:
For some reason, it is not counting values between 20-40. At least as far as I can see from my testing. Here is an image of a run:
Any help is appreciated.

I would suggest a different approach. Making two passes, first calculating the number of bins, then another pass to add them up, looks fragile, and error-prone. Not really surprise to see you trying to figure out a bug of this kind. I think your original approach is too complicated.
As the saying goes "the more you overthink the plumbing, the easier it is to stop up the drain". Find the simplest way to do something, and it will have the least amount of surprises and gotchas, to deal with.
I think it's simpler to make a single pass over the values, calculating which bin each value belongs to, and counting the number of values seen per bin. Let's use a std::map, keyed by bin number, with the value being the number of values in each bin.
void printHistogram(int lowestValue, int binSize, const std::vector<double> &v)
{
std::map<int, size_t> histogram;
for (auto value:v)
{
int bin_number= value < lowestValue ? 0:(value-lowestValue)/binSize;
++histogram[bin_number];
}
And ...that's it. histogram is now your histogram. histogram[0] is now the number of values in the first bin, [lowestValue, lowestValue+binSize), which also includes all values less than lowestValue. histogram[1] will be the number of values found for the next bin, and so on.
Now, you just have to iterate over the histogram map, and generate your actual histogram.
Now, the tricky part here is that the histogram map will only include keys for which at least 1 value was found. If no value was dropped into the bin, the map will not include the bin number. So, if there were no values in the first bin, histogram[0] won't even exist, the first value in the map will be the bin for the lowest value in the vector.
This isn't such a difficult problem to solve, by iterating over the map with a little bit of extra intelligence:
int next_bin_number=0;
for (auto b=histogram.begin(); b != histogram.end(); b++)
{
while (next_bin_number < b->first)
{
// next_bin_number had 0 values. Print the histogram row
// for bin #next_bin_number, showing 0 values in it.
++next_bin_number;
}
int n_values=b->second;
// Bin #n_next_number, with n_values, print its histogram row
++next_bin_number;
}

The code in the loop doesn't initialize i, so the results are at best unpredictable.

Related

How to pick the max top 10 quantity from HashTable C++?

I already wrote a working project but my problem is, the last part.I have already Read 500.000 row from csv file into vector, then put into the hashtable.I can print whole hashtable but I need to pick top 10 Quantity from my hashtable.Just be clear, I am not about to sort the whole hashtable, just pick top 10.
The topic of my project is,program must be able to store individual products (given with StockCode) from csv file and insert it into a suitable data structure. If that product is already inserted into the structure, its counter must be increased by the quantity of the order.After reading and processing is over, your program must list the “top 10” products ordered by individuals.
There is rule about the libraries, This will be a proper C++ class. You must be able to create many instances of this class. (Please use no third party libraries and C++ STL, Boost etc.) However, you can use, iostream, ctime, fstream, string like IO and string classes.
Important note: Only thing I should focus is speed, storage or size is not a problem.
What I've done so far is,
Read Csv file row by row into vector
Stockcodes in row[1], Quantity in row[3]
Put them into Hashtable and increase their quantity by the quantity of the order.
Print the whole hash table.
What I need to do is,
Print the Top 10 Quantity
Now let's share Example csv file, Driver program codes, Output of the print function.
Csv File look like this:
InvoiceNo;StockCode;Description;Quantity;
536365;85123A;WHITE HANGING HEART T-LIGHT HOLDER;6
536365;71053;WHITE METAL LANTERN;6;
536365;84029G;KNITTED UNION FLAG HOT WATER BOTTLE;6;
536365;84029E;RED WOOLLY HOTTIE WHITE HEART.;6;
536365;22752;SET 7 BABUSHKA NESTING BOXES;2;
536365;21730;GLASS STAR FROSTED T-LIGHT HOLDER;6;
main.cpp
void printMaxQuantity() {
int maxValue=0;
for (int i = 0; i < 1000000; ++i) {
if(table[i] != nullptr) {
if (table[i]->quantity > maxValue)
maxValue = table[i]->quantity;
if (table[i]->quantity == maxValue) {
cout << "Index: " << i << endl;
cout << "StockCode: " << table[i]->stockCode << endl;
cout << "Quantity: " << table[i]->quantity << endl;
cout << endl << endl;
}
}
}
}
};
Here the output:(After edit the code StockCode: 85123A is correct output, but still struggling about the top 10)
Index: 41240
StockCode: 10002
Quantity: 48
Index: 309193
StockCode: 85123A
Quantity: 72
Process finished with exit code 0
Also one last note, I am doing this for a school project so I shouldn't use any third party software or include any different libraries because it is not allowed (I will implement my own vector class later)
Since this is homework, I will avoid writing actual code. Since you do not have any prior information about the actual data set, you will need to loop through it, which is a linear complexity. In order to find the top 10 items I advise you to create an array of 10 items to store the best items you get so far.
The first step is to copy the first 10 elements into your array.
The second step is sort your array of 10 items descendingly, so you will always use the last item for comparison.
Now you can loop the big structure and on each step, compare the current item with the last one of the array of ten elements. If it's lower, then do nothing. If it's higher, then find the highest ranked item in your array of 10 items which is smaller than the item you intend to insert due to higher quality. When you find that item, loop from the end until this item until your array of ten elements and on each step override the curret element with the current one. Finally override the now duplicate element.
Example: Assuming that your 7th element has lower quality than the one you intend to insert, but the 6th has higher quality override 9th element with the 8th, then the 8th with the 7th and then the 7th with the item you just found. Remember that array indexes start from 0.
This is what you want clearly.This code pick the top 10 from your hash table
void hashTable::printTopTen() {
int maxValue = 0;
int indexHolder = 0;
cout << "#" << " " << "Stock Code" << "\t" << "Description" << "\t\t\t" << "Quantity" << endl;
for (int i = 0; i < 10; ++i) { //-> This loop for top 10
for (int index = 0; index < TABLE_SIZE; ++index) { //-> base loop to find max quantity in hash table
if (table[index] != nullptr) { // to check if index is NULL or not
if (table[index]->quantity > maxValue) {
maxValue = table[index]->quantity; //update the maxValue with biggest quantity
indexHolder = index; // -> to store index number of max quantity in hash table
}
}
}
for (int indeX = 0; indeX < TABLE_SIZE; ++indeX) { //find the max quantity's stockCode,description
if (table[indeX] != nullptr) { // to check if index is NULL or not
if (table[indeX]->quantity == maxValue) { //if we have reached the maxValue then it's quantity is top 1
cout << i + 1 << "." << " " << table[indeX]->stockCode << "\t" << table[indeX]->description
<< "\t" << table[indeX]->quantity << endl;
table[indexHolder]->quantity = 0; //after cout the max one, delete the index so it can't be top 1 again
}
}
}
maxValue = 0; // update max value 0 again for second base loop
}
}
This question already has an answer. But I want to show you how to perform selection sort so you can compare it with your code.
**Performance trick: ** Quick Sort algorithm can be used instead of Selection Sort
hashMap=hashTable, hashEntry=Node, so this what I did:
void hashTable::selectionSort() {
int firstCounter, secondCounter;
Node *emptyOne = new Node("empty", "thisEmpty", 0);
Node *temp;
for (firstCounter = 1; firstCounter < TABLE_SIZE; firstCounter++) {
if (table[firstCounter] == nullptr) {
table[firstCounter] = emptyOne;
}
temp = table[firstCounter];
secondCounter = firstCounter - 1;
if (table[secondCounter] == nullptr) {
table[secondCounter] = emptyOne;
}
while (secondCounter >= 0 && table[secondCounter]->quantity > temp->quantity) {
table[secondCounter + 1] = table[secondCounter];
secondCounter = secondCounter - 1;
if (table[secondCounter] == nullptr) {
table[secondCounter] = emptyOne;
}
}
table[secondCounter + 1] = temp;
}
}

Program only works with inclusion of (side effects free) cout statements?

So I've been working on problem 15 from the Project Euler's website , and my solution was working great up until I decided to remove the cout statements I was using for debugging while writing the code. My solution works by generating Pascal's Triangle in a 1D array and finding the element that corresponds to the number of paths in the NxN lattice specified by the user. Here is my program:
#include <iostream>
using namespace std;
//Returns sum of first n natural numbers
int sumOfNaturals(const int n)
{
int sum = 0;
for (int i = 0; i <= n; i++)
{
sum += i;
}
return sum;
}
void latticePascal(const int x, const int y, int &size)
{
int numRows = 0;
int sum = sumOfNaturals(x + y + 1);
numRows = x + y + 1;
//Create array of size (sum of first x + y + 1 natural numbers) to hold all elements in P's T
unsigned long long *pascalsTriangle = new unsigned long long[sum];
size = sum;
//Initialize all elements to 0
for (int i = 0; i < sum; i++)
{
pascalsTriangle[i] = 0;
}
//Initialize top of P's T to 1
pascalsTriangle[0] = 1;
cout << "row 1:\n" << "pascalsTriangle[0] = " << 1 << "\n\n"; // <--------------------------------------------------------------------------------
//Iterate once for each row of P's T that is going to be generated
for (int i = 1; i <= numRows; i++)
{
int counter = 0;
//Initialize end of current row of P's T to 1
pascalsTriangle[sumOfNaturals(i + 1) - 1] = 1;
cout << "row " << i + 1 << endl; // <--------------------------------------------------------------------------------------------------------
//Iterate once for each element of current row of P's T
for (int j = sumOfNaturals(i); j < sumOfNaturals(i + 1); j++)
{
//Current element of P's T is not one of the row's ending 1s
if (j != sumOfNaturals(i) && j != (sumOfNaturals(i + 1)) - 1)
{
pascalsTriangle[j] = pascalsTriangle[sumOfNaturals(i - 1) + counter] + pascalsTriangle[sumOfNaturals(i - 1) + counter + 1];
cout << "pascalsTriangle[" << j << "] = " << pascalsTriangle[j] << '\n'; // <--------------------------------------------------------
counter++;
}
//Current element of P's T is one of the row's ending 1s
else
{
pascalsTriangle[j] = 1;
cout << "pascalsTriangle[" << j << "] = " << pascalsTriangle[j] << '\n'; // <---------------------------------------------------------
}
}
cout << endl;
}
cout << "Number of SE paths in a " << x << "x" << y << " lattice: " << pascalsTriangle[sumOfNaturals(x + y) + (((sumOfNaturals(x + y + 1) - 1) - sumOfNaturals(x + y)) / 2)] << endl;
delete[] pascalsTriangle;
return;
}
int main()
{
int size = 0, dim1 = 0, dim2 = 0;
cout << "Enter dimension 1 for lattice grid: ";
cin >> dim1;
cout << "Enter dimension 2 for lattice grid: ";
cin >> dim2;
latticePascal(dim1, dim2, size);
return 0;
}
The cout statements that seem to be saving my program are marked with commented arrows. It seems to work as long as any of these lines are included. If all of these statements are removed, then the program will print: "Number of SE paths in a " and then hang for a couple of seconds before terminating without printing the answer. I want this program to be as clean as possible and to simply output the answer without having to print the entire contents of the triangle, so it is not working as intended in its current state.
There's a good chance that either the expression to calculate the array index or the one to calculate the array size for allocation causes undefined behaviour, for example, a stack overflow.
Because the visibility of this undefined behaviour to you is not defined the program can work as you intended or it can do something else - which could explain why it works with one compiler but not another.
You could use a vector with vector::resize() and vector::at() instead of an array with new and [] to get some improved information in the case that the program aborts before writing or flushing all of its output due to an invalid memory access.
If the problem is due to an invalid index being used then vector::at() will raise an exception which you won't catch and many debuggers will stop when they find this pair of factors together and they'll help you to inspect the point in the program where the problem occurred and key facts like which index you were trying to access and the contents of the variables.
They'll typically show you more "stack frames" than you expect but some are internal details of how the system manages uncaught exceptions and you should expect that the debugger helps you to find the stack frame relevant to your problem evolving so you can inspect the context of that one.
Your program works well with g++ on Linux:
$ g++ -o main pascal.cpp
$ ./main
Enter dimension 1 for lattice grid: 3
Enter dimension 2 for lattice grid: 4
Number of SE paths in a 3x4 lattice: 35
There's got to be something else since your cout statements have no side effects.
Here's an idea on how to debug this: open 2 visual studio instances, one will have the version without the cout statements, and the other one will have the version with them. Simply do a step by step debug to find the first difference between them. My guess is that you will realize that the cout statements have nothing to do with the error.

how to convert an for loop to while loop c++

I'm trying to convert a for loop to while loop in c++ and do some checking for duplicates in a random number generator for generating lotto numbers so far all the stuff i'm trying seems to make the compiler very unhappy and I could really use a few pointers. It's the for loop in the Harray() function that feeds the Balls[] array
that i want to convert to a while loop.
#include<iostream>
#include<cstdlib> // to call rand and srand.
#include<ctime> // to make rand a bit more random with srand(time(0)) as first call.
#include<iomanip> // to manipulate the output with leading 0 where neccesary.
using namespace std;
// Hrand() function create and return a random number.
int Hrand()
{
int num = rand()%45+1; // make and store a random number change 45 for more or less Balls.
return num; // return the random number.
}
// Harray() function create and fill an array with random numbers and some formatting.
void Harray()
{
int Balls[6]; // change the number in Balls[6] and in the for loop for more or less nrs. a row.
for(int x=0; x<=6; x++) //the loop to fill array with random numbers.
{
int a; // made to pass the Balls[x] data into so i can format output.
int m = Hrand(); // calling the Hrand() function and passing it's value in int m.
Balls[x] = m; // throwing it into the array tought i did this because of an error.
a = Balls[x]; // throwing it into int a because of an type error.
cout<<"["<<setfill('0')<<setw(02)<<a<<"]"; //format output with leading 0 if neccesary.
}
cout<<endl; // start new row on new line.
}
// Main function do the thing if compiler swallows the junk.
int main() // start the program.
{
int h; // int to store user cchoice.
srand(time(0)); // make rand more random.
cout<<"How many rows do you want to generate?"<<endl; // ask how many rows?
cin>>h; // store user input.
for(int i=h; h>0; h--) // produce rows from user input choice.
{
Harray(); // calling Harray function into action.
}
return 0; // return zero keep the comipler happy.
}
I would like to always have six diffrent numbers in a row but i don't see how to get there with the for loops i think the while loop is way to go but am open to any suggestion that will work. I'm just starting with c++ i might have overlooked some options.
int x=0;
while(x<6)
{
int a;format output.
int m = Hrand();value in int m.
Balls[x] = m; because of an error.
a = Balls[x];
cout<<"["<<setfill('0')<<setw(02)<<a<<"]";
x++;
}
Here, I also fixed a bug. Since Balls has 6 elements, the last element will be 5. Thus you want x<6 instead of x<=6. That goes for the for loop too.
One drawback of while loops is that you cannot declare local variables with them.
First of all, you should realize that the difference between a for loop and a while loop is mostly syntactic--anything you can do with one, you can also do with the other.
In this case, given what you've stated as your desired output, what you probably really want is something like this:
std::vector<int> numbers;
std::set<int> dupe_tracker;
while (dupe_tracker.size() < 6) {
int i = Hrand();
if (dupe_tracker.insert(i).second)
numbers.push_back(i);
}
The basic idea here is that dupe_tracker keeps a copy of each number you've generated. So, you generate a number, and insert it into the set. That will fail (and return false in retval.second) if the number is already in the set. So, we only add the number to the result vector if it was not already in the set (i.e., if it's unique).
How convert for-loop to while-loop
#include <iostream>
class T545_t
{
// private data attributes
int j;
public:
int exec()
{
// A for-loop has 3 parameters, authors often fill 2 of them with magic
// numbers. (magic numbers are usually discouraged, but are expected
// in for-loops)
// Here, I create names for these 3 for-loop parameters
const int StartNum = 2;
const int EndNum = 7;
const int StrideNum = 2;
std::cout << std::endl << " ";
for (int i = StartNum; i < EndNum; i += StrideNum ) {
std::cout << i << " " << std::flush;
}
std::cout << std::flush;
// A while-loop must use / provide each of these 3 items also, but
// because of the increased code-layout flexibility (compared to
// for-loop), the use of magic numbers should be discouraged.
std::cout << std::endl << " ";
j = StartNum;
do {
if (j >= EndNum) break;
std::cout << j << " " << std::flush;
j += StrideNum;
} while(true);
std::cout << std::flush;
std::cout << std::endl << " ";
j = StartNum;
while(true) {
if (j >= EndNum) break;
std::cout << j << " " << std::flush;
j += StrideNum;
}
std::cout << std::flush;
std::cout << std::endl << " ";
j = StartNum;
while(j < EndNum) {
std::cout << j << " " << std::flush;
j += StrideNum;
}
std::cout << std::endl;
return 0;
}
}; // class T545_t
int main(int , char** )
{
T545_t t545;
return(t545.exec());
}
Ask me where 'j' is declared?
This code is marked as C++, so in this case, I have declared 'j' in the private data attribute 'section' of this class definition. That is where you'd look for it, right?
If your c++ code does not have class, what's the point?

Printing out a Histogram C++

I am attempting to print out a histogram of values that correspond to the amount of times a pixel value appears in a .pgm file. I know I am reading in the values correctly, it's when I try to print them where I have issues.
int pixelHold[product];
for(long int i = 0; i < product; i++)
{
pixelHold[pixels[i]]++;
//cout << pixels[i] << ' ' << endl;
}
for(long int j = 0; j < product; j++)
{
cout << pixelHold[j] << ' ';
}
"product" is the Width x Height pixel value, which corresponds to the size of the vector I'm using to store all of the values. "pixelHold" is just an array that I'm using to increment every time it comes across a pixel value. For example, it if came across "222" 3 times, it would print a "3" for the "222" slot.
However, the issue is that, when I print the histogram, I get a bunch of zeroes, and then garbage for the last 100 slots or so. When I change the parameters of the for loop to a smaller number, like "221", it prints out the correct histogram up to that point.
Any help is much appreciated!
You always need to initalize your arrays - otherwise they contain absolutely arbitrary contents - the contents of RAM where the compiler decided to put your array.
Also, your histogram table should have the dimensions of 256 - since that's how many (8-bit) colors there are in a greyscale image.
The following code should do the trick:
const int histogramLevels = 256;
int pixelHold[histogramLevels];
for (int i=0; i<histogramLevels; i++) pixelHold[i] = 0;
for(long int i = 0; i < product; i++)
{
pixelHold[pixels[i]]++;
//cout << pixels[i] << ' ' << endl;
}
for (int i=0; i<histogramLevels; i++) {
cout << pixelHold[j] << ' ';
}

c++ vector not updating in nested for loop

So I create and initialize a vector (of size nmask+3) to 0, and I assign an initial value to one of the elements. I then make a for loop that goes through the first nmask elements of the vector and assigns to each element an average of 26 other elements in the vector (defined by the 4D int array voxt, which contains vector addresses).
My problem is that when I check the values of nonzero elements in my vector (phi) within the nested loop (the first cout), the values are fine and what I expect. However, when the loop finishes going through all nmask elements (for (int i= 0; i<nmask; i++) exits), I check the nonzero elements of phi again, and they are all lost (reset to 0) except for the last non-zero element (and element tvox which is manually set to 1).
I feel that since phi is initialized outside of all the loops, there should be no resetting of values going on, and that any updated elements within the nested loop should remain updated upon exit of the loop. Any ideas as to what is going on / how to fix this? Code is below; I tried to comment in a sense of the outputs I'm getting. Thanks in advance.
vector<double> phi(nmask+3, 0); //vector with nmask+3 elements all set to 0 (nmask = 13622)
phi[tvox]= 1; //tvox is predefined address (7666)
for (int n= 0; n<1; n++)
{
vector<double> tempPhi(phi); //copy phi to tempPhi
for (int i= 0; i<nmask; i++)
{
for (int a= -1; a<=1; a++)
{
for (int b= -1; b<=1; b++)
{
for (int c= -1; c<=1; c++)
{
if (!(a==0 && b==0 && c==0))
{
//oneD26 is just (double) 1/26
phi[i]= tempPhi[i]+oneD26*tempPhi[voxt[i][1+a][1+b][1+c]];
if (phi[i]!=0)
{
//this gives expected results: 27 nonzero elements (including tvox)
cout << n << " " << i << " " << a << b << c << " " << phi[i] << endl;
}
}
}
}
}
}
phi[svox]= 0; //svox = 7681
phi[tvox]= 1;
for (int q= 0; q<nmask; q++)
{
//this gives only 2 nonzero values: phi[tvox] and phi[9642], which was the last nonzero value from 1st cout
if (phi[q]!=0)
cout << q << " " << phi[q] << endl;
}
}
Difficult to tell just what is going on, but the easiest explanation is that after phi[i] gets set to non-zero and displayed to cout, it gets set to zero again in one of the later iterations through the inner loops.
If you do some tracing and check phi[i] just before updating you'll see that you often overwrite a non-zero element with zero.
Note: I have no idea what your code does, this is pure Sherlock Holmes reasoning.. if after the loops you find only 2 non-zero elements then the only logical consequence is that after updating something to non-zero later in the loop you update it to zero.
phi[i]= tempPhi[i]+oneD26*tempPhi[voxt[i][1+a][1+b][1+c]];
The nested for-loops using a, b, and c run for a combined 9 iterations with the same value of i. Since you overwrite phi[i] to a new value every time, you only retain the value from the last iteration where a, and c are all 1. If that last iteration happens to produce zero values, then phi[i] will have lots of zeroes. Perhaps you meant to do something like phi[i] += ... instead of phi[i] = ...?
I do suggest to replace the meat of the loop with something like
const boost::irange domain(-1,2);
for (int i: boost::irange(0, nmask)) for (int a: domain) for (int b: domain) for (int c: domain)
{
if (a==0 && b==0 && c==0)
continue;
//oneD26 is just (double) 1/26
phi[i]= tempPhi[i]+oneD26*tempPhi[voxt[i][1+a][1+b][1+c]];
if (phi[i]!=0)
{
//this gives expected results: 27 nonzero elements (including tvox)
cout << n << " " << i << " " << a << b << c << " " << phi[i] << endl;
}
}
Of course, for brevity I assume both boost/range.hpp and c++0x compiler. However, with trivial macro's you can achieve the same. That is without writing/using a proper combinations algorithm (why is that not in the standard, anyway).