Population program in C++ - c++

I'm in desperate need of assistance.
I'm working on a population program in C++ for my Systems Software class.
This is my first foray into C++ territory, I only have some Java knowledge to help me out.
Basically, the program is supposed simulate a simple population. The guidelines are as follows:
The first elements (starting population) have random age and sex.
2 elements can pair if their lifespan falls between [0.25,0.50] (assuming they die at 1) and they are of the opposite sex.
Each element can only pair twice.
So here's my code, and take it easy guys I'm not very well versed in C++ yet...:
#include <vector>
#include <ctime>
#include <stdlib.h>
#include <iostream>
#include <iterator>
using namespace std;
class Element {
public:
int pair;
double life;
int tag;
void setValues(double, int);
int getPair() {
return pair;
}
void incrementPair() {
pair = pair++;
}
double getLife() {
return life;
}
void incrementLife() {
life = life + 0.05;
}
int getTag() {
return tag;
}
}; //Element
void Element::setValues(double b, int c) {
pair = 0;
life = b;
tag = c;
}
int main() {
double Time = 0.0;
srand(time(NULL));
vector<Element> vec;
for (int i = 0; i<50; ++i) {
Element x;
x.setValues(((double) rand() / (RAND_MAX)), rand()%2);
vec.push_back(x);
}//for
while (vec.size() != 0) {
int newPopCount = 0;
int Dead = 0;
for(int count = 0; count != vec.size(); ) {
std::vector<Element>::iterator p = vec.begin();
std::vector<Element>::iterator i = vec.begin() + 1;
if ((p->getPair() == 2) || (p->getLife() < 0.25) || (p->getLife() > 0.50)) {
count++;
p++;
}//if
else {
for(int count1 = count + 1 ; count1 != vec.size() ; ) {
if ((i->getLife() < 0.25) || (i->getLife() > 0.50) || (i->getPair() == 2) || (p->getTag() == i->getTag())) {
++i;
count1++;
}//if
else {
cout << i->getTag() << " " << p->getTag() << endl;
cout << i->getPair() << " " << p->getPair() << endl;
cout << i->getLife() << " " << p->getLife() << endl;
p->incrementPair();
i->incrementPair();
newPopCount++;
count1++;
count++;
p++;
i++;
}//else
}//for
}//else
}//for
Time += 0.05;
for ( vector<Element>::iterator m = vec.begin(); m != vec.end(); ++m ) {
m->incrementLife();
if ( m->getLife() >= 1.00 ) {
Dead++;
//vec.clear();
vec.erase(m);
//vec.shrink_to_fit();
}//if
for (int i = 0; i = newPopCount; i++) {
Element woo;
woo.setValues(0.0, rand()%2);
vec.push_back(woo);
}//for
}//for
cout << "The total number of dead is: " << Dead << endl;
cout << "The total number born is: " << newPopCount << endl;
cout << "Current population is: " << vec.size() << endl;
cout << "Population has survived for: " << Time << endl;
sleep(1);
}//while
cout<< "The populace is now extinct." << endl;
cout<< "The populace survived for: " << Time << endl;
}//main
You can see my silly debugging methods, I was getting a Segmentation Fault error before, but I believe that to be fixed. The issue now is that I'm getting stuck in the loops. The program seems to run almost erratically, and I can't pinpoint the issue any closer than inside of one of the loops.
My Dead integer is incremented and displayed properly, but the newPopCount integer is not, which makes no sense to me.
Also the program never gets out of the while loop, it will continue until it gets stuck in another of the many loops I have.
I have had several other issues, which I've been fixing slowly but surely as you can see by my patchwork code.
Any help at all will be greatly appreciated.

Two obvious issues, which your compiler will warn you about if you turn up your warnings high enough.
First:
void incrementPair() {
pair = pair++;
}
This is undefined behavior. Should be just:
void incrementPair() {
++pair;
}
Second:
for (int i = 0; i = newPopCount; i++) {
Element woo;
woo.setValues(0.0, rand()%2);
vec.push_back(woo);
}
That condition in your for loop is almost certainly wrong. It likely should be i <= newPopcount, or something like that.
As a side note, your setValues() member function looks like it's doing the job that a constructor should be doing.
EDIT: Look here:
for(int count = 0; count != vec.size(); ) {
std::vector<Element>::iterator p = vec.begin();
std::vector<Element>::iterator i = vec.begin() + 1;
Imagine you have a std::vector with only one element in it, and then think about what i is going to represent when you do i->getLife() a few lines later. Just having those definitions inside the for loop looks a bit suspicious in itself, since you increment both p and i during the loop, but you're going to reset them again on every iteration, but it's not all that easy to follow the logic, so perhaps that's what you intended.

vec.erase(m); results in an invalid m. You want to do m = vec.erase(m)

Related

Vector subscript out of range on iterator

#include <iostream>
#include <random>
#include <fstream>
#include <time.h>
using namespace std;
bool generateRandomValue()
{
static std::default_random_engine e{};
static std::uniform_int_distribution<int> d{ 0, 100 };
bool headsTails = (d(e) > 50) ? true : false;
return headsTails;
}
int main()
{
clock_t tStart = clock();
ofstream outputFile("output.txt");
int totalHeads = 0;
int totalTails = 0;
vector<int> headList(100,0);
vector<int> tailList(100,0);
for (int out = 0; out <= 100; out++)
{
char result = '\0';
int heads = 0, tails = 0;
for (int i = 0; i < 100000; i++)
{
result = (generateRandomValue()) ? 'H' : 'T';
if (result == 'H')
{
heads++;
}
else
{
tails++;
}
}
outputFile << "Trial " << out << ": Heads: " << heads << " Tails: " << tails << endl << endl;
headList.push_back(heads);
tailList.push_back(tails);
}
for (vector<int>::iterator i = headList.begin(); i < headList.end(); i++)
{
totalHeads += headList[*i];
totalTails += tailList[*i];
}
cout << "It took: " << (double)(clock() - tStart) / CLOCKS_PER_SEC << " seconds to calculate and execute this program.\n";
outputFile << "Total number of heads: " << totalHeads << " Total number of tails: " << totalTails << endl;
return 0;
}
Above is some code I've been messing with just to try out vectors (never used them in class). The code compiles in VS2015, but the program crashes with the following error: "Vector subscript out of range".
I assume this is telling me that at some point in my program a vector is attempting to be addressed at a location outside of its bounds. I haven't been able to tell whether the error is being thrown on my storage vectors or the iterator vector in the last for loop, and debugging doesn't work because the program crashes before it can begin to debug (weird that it isn't a compile time error then).
In this code:
for (vector<int>::iterator i = headList.begin(); i < headList.end(); i++)
{
totalHeads += headList[*i];
totalTails += tailList[*i];
}
iterator i iterates over all elements of headList vector. *i gives you that value (which is amount of heads in that iteration). You use that as an index for vectors totalHeads and totalHeads which seams to be wrong. Your loop should be:
for (size_t i = 0; i < headList.size(); i++)
{
totalHeads += headList[i];
totalTails += tailList[i];
}
Note: though this loop:
for (vector<int>::iterator i = headList.begin(); i < headList.end(); i++)
works for random access iterator, it is more common to write it in form:
for (vector<int>::iterator i = headList.begin(); i != headList.end(); ++i)
this way it will also work for forward iterator and you may change container type without modifying much code. ++i can be more efficient especially for iterator, not integral type.

Derive the execution time growth rate (BigO) of the following code

What is execution time growth rate Big O of this code?
void doDiff(int setA[], int setB[], int sizeA, int sizeB) {
const int MAX = 10;
// validate setA and setB
if ((sizeA == 0) && (sizeB == 0))
cout << "both sets are empty " << endl;
else
cout << "symmetric difference: { " ;
for (int i = 0; i < sizeA; i++ )
if (!member(setB, setA[i],sizeB))
cout << setA[i] << " ";
for (int i = 0; i < sizeB;i++ )
if (!member(setA, setB[i],sizeA))
cout << setB[i] << " ";
cout << "}" << endl;
}
bool member(int set[], int n, int size)
{
for (; size > 0; size--)
if (set[size-1] == n)
return true;
return false;
}
When I calculate the big O of this code, I end up with O(N*N*N) || O(N^3)
I am not sure what exact execution time growth rate is for this code.
please help me.
Thank you in advance
It seems inappropriate to fill an answer with questions, but since this sounds like homework, I think they're a better way to the goal (which is for YOU to figure out how this works):
What is the "big-O" of member? This is important, since doDiff relies on it so much.
How many times does doDiff call member?
If every call to member takes the same amount of time, member is O(X), and doDiff calls member Y times, what is the "big-O" of doDiff?

Painfully slow maze making program

I am writing a program that generates any size maze you want. It does this by first creating every cell in the maze and assuming they are entirely walled in. They are each declared as their own set. Then a random cell is selected and then a random direction to break down a wall. The random direction funcion makes sure that its also a valid direction for that cell. The program makes sure that the two cells its looking to join arent already connected somehow and if they arent it breaks the wall. If they are already connected either directly or indirectly then it selects a new random cell and direction. This continues until the number of sets left is just 1 ensuring that you can get from any point in the maze to any other point. The program works but it is painfully slow. I dont think it should be as slow as it is and I am unsure why.
I can imagine a scenario where all the cells are connected but one. Thus it would take a little while to randomly select that one cell and that could slow things down but I would imagine when you are dealing with under 100,000 cells it still shouldn't take as long as it does. Rand should be prettu fast at spitting out numbers.
Ive attatched my code below. Its fairly simple but I am sorry about the lack of notes.
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <vector>
#include <string>
#include <sstream>
#include <algorithm>
using namespace std;
class dset {
struct element {
element() { rank=0, parent=-1; }
int rank;
int parent;
vector<int> connections;
};
public:
dset(int nr=0,int nc=0);
int size() {return Nsets; }
int merge (int, int);
int find(int);
// Functions
bool isin(int i, vector<int> test);
int randdir(int i);
int randcell();
int dir(int, int);
void print();
vector<int> possibledir(int cell);
vector<int> walls(int cell, vector<int> possible);
private:
int Nsets;
int nrows, ncols;
vector<element> S;
};
int main(int argc, char* argv[]){
int nrows, ncols, cell, direction;
if (argc != 3){
cout << "Usage: nrows ncols\n";
}
stringstream convert;
convert << argv[1];
convert << " ";
convert << argv[2];
convert >> ncols;
convert >> nrows;
dset maze(nrows,ncols);
srand(time(NULL));
while(maze.size() != 1){
cell = maze.randcell();
// cell = 11;
direction = maze.randdir(cell);
// direction = 0;
// cout << "cell: " << cell << " direction: " << direction << " new cell: " << maze.dir(cell, direction) <<endl << endl;
// cout << maze.size() << endl<<endl;;
maze.merge(cell, maze.dir(cell, direction));
}
maze.print();
}
dset::dset(int nr,int nc) {
nrows = nr;
ncols = nc;
int N = (nrows * ncols);
if (0<N) S.insert(S.end(), N, element());
Nsets = N;
}
void dset::print(){
vector<int> wall;
cout << "MAZE " << nrows << " " << ncols << endl;
for ( int i = 0; i < (nrows*ncols); i++ ){
wall = walls(i,possibledir(i));
for( int j = 0; j < wall.size(); j++){
if (i < wall[j])
cout << i << " " << wall[j] << endl;
}
}
}
int dset::randcell(){
return (rand()%(nrows*ncols));
}
int dset::dir(int cell, int direction){
if(direction == 0)
return (cell - 1);
if(direction == 1)
return (cell - (ncols));
if(direction == 2)
return (cell+1);
if(direction == 3)
return (cell + ncols);
}
int dset::randdir(int i){
srand(time(NULL));
int direction;
vector<int> used;
//cout << "i : " << i << endl;
while (true){
direction = rand() % 4;
while (true){
if(isin(direction,used))
direction = rand()%4;
else
break;
}
// cout << "rand: " << direction << endl;
if(direction ==0){
if( i != 0){
// cout << 0 << " i%(ncols -1) :" << (i%(ncols -1)) << endl;
if(i%(ncols) != 0){
break;
}
}
}
if(direction == 1){
// cout << 1 << " i - ncols :" << (i-ncols) << endl;
if(i-ncols > 0){
break;
}
}
if (direction == 2){
// cout << 2 << " i%(ncols) :" << (i%ncols) << endl;
if ( i == 0 )
break;
if (i%ncols != ncols-1){
break;
}
}
if (direction == 3){
if (i+ncols < ((nrows*ncols))){
// cout << 3 << " i+ncols :" << (i+ncols) << endl;
break;
}
}
used.push_back(direction);
}
return direction;
}
vector<int> dset::possibledir(int cell){
vector<int> possible;
// cout << "cell " << cell << " possible connections:\n";
for (int i = 0; i < 4; i++){
if (i == 0){
if( cell != 0 ){
if(cell%(ncols) !=0){
// cout << dir(cell,i) <<endl;
possible.push_back(dir(cell,i));
}
}
}
if(i==1){
if (cell-ncols > 0){
// cout<<dir(cell,i) <<endl;
possible.push_back(dir(cell,i));
}
}
if(i==2){
if(cell == 0){
// cout<<dir(cell,i) <<endl;
possible.push_back(1);
}else if(cell%ncols != ncols-1){
// cout<<dir(cell,i) <<endl;
possible.push_back(dir(cell,i));
}
}
if(i==3){
if ( cell+ncols < ((nrows*ncols))){
// cout<<dir(cell,i) <<endl;
possible.push_back(dir(cell,i));
}
}
}
// cout << endl;
return possible;
}
vector<int> dset::walls(int cell, vector<int> possible){
vector<int> walls;
// cout << cell << " connection 0: " << S[cell].connections[0] << endl;
for(int i = 0; i < possible.size(); i++){
if (!isin(possible[i], S[cell].connections)){
// cout << "true\n";
walls.push_back(possible[i]);
}
// cout << "false\n";
}
return walls;
}
int dset::merge(int i, int j) {
int cell1 = i;
int cell2 = j;
i = find(i);
j = find(j);
if (i != j) {
element &Si = S[i];
element &Sj = S[j];
// Adjust Adjacency List
// cout << "inconnections\n";
S[cell1].connections.push_back(cell2);
S[cell2].connections.push_back(cell1);
// cout << "notinconnections\n";
// merge (union) by rank
if (Si.rank > Sj.rank) Sj.parent = i;
else if (Si.rank < Sj.rank) Si.parent = j;
else { Sj.parent = i; Si.rank +=1; }
Nsets -=1;
}
return find(i);
}
int dset::find(int i) {
if (S[i].parent == -1){
return i;
}
// recursive path compression
S[i].parent = find(S[i].parent);
return S[i].parent;
}
bool dset::isin(int i, vector<int> test){
bool out = false;
for(int j = 0; j < test.size(); j++){
if(test[j] == i)
out = true;
}
return out;
}
Please learn to pass by reference, not value.
For example:
bool dset::isin(int i, vector<int> test)
You are passing a vector by value. That means that an entire copy is made when the function is called. If your vector has 100,000 items, then an unnecessary copy is made. Change to this:
bool dset::isin(int i, vector<int>& test)
Now no copy is done. Make this same change in all of your other functions.
You also return a vector by value, but I would leave those alone unless it is proven that your compiler can't or won't optimize the copy away.
Also, make sure you are timing a release, optimized program, and not a "debug" or unoptimized program. Since you didn't mention the compiler you're using, use the settings that generate optimized code when building your program.
Although I do not know much about c++, it would seem to me from your program description at the start that your slowdown may happen when your program is determining whether two prospectively connectable cells are already connected. Since the majority if not all cases when this is done that are used must determine that the cells are NOT connected, so that there is only one proper solution, every time this is done your program has to examine/solve the entire maze to that point to make sure that there is no way in which it could already be connected. This means that as the existing part of the maze gets larger, the time it takes to complete this task will get longer and longer.
To test whether this is the case, you could have your program record how long it takes to determine if two cells are connected every time ( or 10 times) it does so, and if the times on the list get longer linearly, then this or something similar is part of the issue.
You could fix this by either allowing already-connected to be connected by another path, or by simplifying the way in which your program checks what cells are connected.
Sorry I can't give better code-specific advice, but I'm researching how to create a maze and ran across your question, hopefully my answer at least is food for thought.

Commenting on my code [closed]

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 11 years ago.
I'm having difficulty commenting on my code for a blackjack app for c++. I have coded it but now I am confused as to what to put in for comments, my instructor is frugal when it comes to commenting.
Thanks for any and all help! :)
here is my code:
#include <iostream> // in/out for form
#include <ctime> // uses time for randomizing
#include <Windows.h> //
using namespace std; // prevents redundancey of ::STD
char enter[1]; //
int hand[52] = {}, dealer[52]; // array of 52 for 52 cards that holds zero
int GetScore(int param) // function prototype that calls getscore
{
int score = 0; //
int temp[52]; //
if(param == 0) for(int i = 0; i < 52; i++) temp[i] = hand[i]; //
if(param == 1) for(int i = 0; i < 52; i++) temp[i] = dealer[i]; //
for(int i = 0; i < 52; i++) //
{
if(temp[i] == 0) break; //
if(temp[i] != 11)
{
score += temp[i];
}
}
for(int i = 0; i < 52; i++) // simple loop to ....
{
if(temp[i] == 0) break;
if(temp[i] == 11)
{
if(temp[i] + score <= 21)
{
score += 11;
}
else
{
score += 1;
}
}
}
return score;
}
void ShowDealersHand(int show) //
{
cout << "\n Dealer's hand: "; //
if(show == 1) //
{
if(dealer[0] == 11)
{
cout << "A [Not Shown]";
}
else
{
cout << dealer[0] << " [Not Shown]";
}
}
else
{
for(int i = 0; i < 52; i++)
{
if(dealer[i] == 0) break;
if(dealer[i] == 11)
{
cout << "A ";
}
else
{
cout << dealer[i] << " ";
}
}
}
}
void Blackjack()
{
for(int i = 0; i < 2; i++) //
{
int num, temp;
if(hand[0] == 0) temp = 0;
else temp = 1;
num = rand() % 10 + 2;
hand[temp] = num;
num = rand() % 10 + 2;
dealer[temp] = num;
}
ShowDealersHand(1); //
cout << endl << endl << " Your hand: "; //
for(int i = 0; i < 52; i++) //
{
if(hand[i] == 0) break;
if(hand[i] == 11)
{
cout << "A ";
}
else
{
cout << hand[i] << " ";
}
}
cout << endl << " Your score: " << GetScore(0) << endl << endl;
while(GetScore(0) <= 21)
{
cout << " Hit(h) or stand(s): ";
cin >> enter;
if(strcmp(enter, "h") == 0)
{
int card = rand() % 10 + 2;
for(int i = 0; i < 52; i++)
{
if(hand[i] == 0)
{
hand[i] = card;
break;
}
}
cout << " Your hand: ";
for(int i = 0; i < 52; i++)
{
if(hand[i] == 0) break;
if(hand[i] == 11)
{
cout << "A ";
}
else
{
cout << hand[i] << " ";
}
}
cout << endl << " Your score: " << GetScore(0) << endl << endl;
if(GetScore(0) > 21)
{
cout << " - ..BUST.. -" << endl ;
cout << "\n - !!House Wins!! -";
goto end;
break;
}
}
else if(strcmp(enter, "s") == 0)
{
cout << endl;
break;
}
system("pause > nul");
}
Sleep(2000);
ShowDealersHand(0);
cout << endl << " Dealer score: " << GetScore(1) << endl << endl;
if(GetScore(1) < GetScore(0))
{
while(GetScore(1) < 17 && GetScore(0) <= 21)
{
Sleep(2000);
int card = rand() % 10 + 2;
for(int i = 0; i < 52; i++)
{
if(dealer[i] == 0)
{
dealer[i] = card;
break;
}
}
cout << " Dealer's hand: ";
for(int i = 0; i < 52; i++)
{
if(dealer[i] == 0) break;
if(dealer[i] == 11)
{
cout << "A ";
}
else
{
cout << dealer[i] << " ";
}
}
cout << endl << " Dealer score: " << GetScore(1) << endl << endl;
if(GetScore(1) >= GetScore(0)) break;
}
}
end:
if(GetScore(1) > GetScore(0) && GetScore(1) <= 21)
{
cout << " - !!House Wins!! -";
}
else if(GetScore(1) == GetScore(0) && GetScore(0) <= 21)
{
cout << " * Tie * - !!House Wins!! -";
}
else if(GetScore(0) <= 21)
{
cout << " - !!!You win!!! -"; // outputs if you win
}
system("pause > nul");
system("cls");
}
void main() // no return on main for form to start
{
srand((unsigned int)time(0)); // randomizer unasigned initializer
cout << " *-*-*-*-*Zachattack's Blackjack*-*-*-*-*" << endl << endl; // Name of program outputs to user
Blackjack();
}
As they are, you comments are useless. Take, for example, this:
int hand[52] = {}, dealer[52]; // array of 52 for 52 cards that holds zero
Anyone that uses C/C++ is expected to know what that line is doing, without having to read the comment.
Instead of commenting what your code does ("this line declares an int"), comment why the code does what it does (what you were thinking when you wrote that code), or, if the algorithm is complicated, comment on how it does something, or document how to use your functions.
For example, your GetScore function takes has a parameter called param. I've no idea what values I am expected to give to param, so you should explain it: "when param is 1, this happens, when it is 0, that happens".
Another example: in your code you have a line Sleep(2000). Why did you use that function? Explain it in a comment:
// Sleep 2 seconds to make the game more exciting
Sleep(2000);
Always assume that the person reading your code knows how to use the language. Never assume that the person reading your code is able to understand your way of thinking about a certain problem.
Comments should explain why, not what.
So your comment for using namespace std; is unnecessary, because any C++ programmer will already know what the using keyword does.
However, for the GetScore() function, you've omitted to give the rules for totalling the score.
The comments should add value, not just duplicate things that are obvious from even a cursory look at the code.
Assume the person reading the code is familiar with the programming environment, but wasn't party to what was going on in your mind as you wrote it.
Here's an example I sometimes use - a piece of code with useless comments (can you work out what is going on here, and why?):
// Is the new selection end above the selection start?
if newSelEnd.Line < FSelection.SelStart.Line then
begin
// Is the selection start at the left margin and above the selection end?
if (FSelection.SelStart.Line < FSelection.SelEnd.Line) and
(FSelection.SelStart.Column = 0) then
begin
// Move the selection start down one line
Inc(FSelection.SelStart.Line);
And with helpful comments:
if newSelEnd.Line < FSelection.SelStart.Line then
begin
// The new selection end is above the selection start, so will become the
// top of the new selection.
if (FSelection.SelStart.Line < FSelection.SelEnd.Line) and
(FSelection.SelStart.Column = 0) then
begin
// The start of the selection was at the top of the old selection and the
// new line is above this, so the selection is about to change direction.
// Since the start column is 0 we assume the original selection was an
// entire line, so we keep the original line selected by moving the start
// position down one line.
Inc(FSelection.SelStart.Line);
Function/method purpose with parameters purposes
Magic numbers
Those are my most important rules about commenting. Optional is "why am I iterating/what am I looking for" about loops. Magic numbers is every declaration/condition that uses const values like GetScore(0) <= 21, or hand[52].
Those are places that should be commented even for yourself... It feels realy good when you look at your code after year or more and still read it without any problem.
Apart from the other answers, often, it is a good idea to get rid of a comment by replacing it with a named function:
// Find top-scorers:
for (Iter it=scorers.begin(), end=scorers.end(); it!=end; ++it) {
...
{
top.push_back (*it);
}
}
Instead, do:
const std::vector<Scorer> top = find_top_scorers (scorers.begin(),
scorers.end());
This decreases miss-maintenance (comments are not enforced and may get out-of-date) and reusability. Personally, I always endeavour for commentless code, as I am sick of out-of-date comments, when possible and sane.
Of course, in the example above, you should probably use std::partial_sort, std::partition or std::stable_partition.
Also, magic numbers should be replaced by constants instead, with the same argumentation about miss-maintenance and reusability:
const float x = radius * 3.14159...; // radius * pi
const float pi = 3.14159...,
x = radius * pi;

How to refactor this simple code to avoid code duplication?

I am solving the following simple problem(on one of OnlineJugde sites which is in Russian, so I won't give a link here:). It is easier to state the problem via an example than definition.
Input:
10 // this is N, the number of the integers to follow
1 1 1 2 2 3 3 1 4 4
Output:
3 times 1.
2 times 2.
2 times 3.
1 times 1.
2 times 4.
Constraints:
All the numbers in the input(including N) are positive integer less than 10000.
Here is the code I got Accepted with:
#include <iostream>
using namespace std;
int main()
{
int n;
cin >> n;
int prevNumber = -1;
int currentCount = 0;
int currentNumber;
while(n --> 0) // do n times
{
cin >> currentNumber;
if(currentNumber != prevNumber)
{
if(currentCount != 0) //we don't print this first time
{
cout << currentCount << " times " << prevNumber << "." << endl;
}
prevNumber = currentNumber;
currentCount = 1;
}
else //if(currentNumber == prevNumber)
{
++currentCount;
}
}
cout << currentCount << " times " << prevNumber << "." << endl;
}
Now here's my problem. A little voice inside me keeps telling me that I am doing this line two times:
cout << currentCount << " times " << prevNumber << "." << endl;
I told that voice inside me that it might be possible to avoid printing separately in the end. It told me that there would then be perhaps way too many if's and else's for such a simple problem. Now, I don't want to make the code shorter. Nor do I want do minimize the number of if's and else's. But I do want to get rid of the special printing in the end of the loop without making the code more complicated.
I really believe this simple problem can be solved with simpler code than mine is. Hope I was clear and the question won't be deemed as not constructive :)
Thanks in advance.
i came up with this. no code duplication, but slightly less readable. Using vector just for convenience of testing
EDIT my answer assumes you know the numbers ahead of time and not processing them on the fly
vector<int> numbers;
numbers.push_back(1);
numbers.push_back(1);
numbers.push_back(1);
numbers.push_back(2);
numbers.push_back(2);
numbers.push_back(3);
numbers.push_back(3);
numbers.push_back(1);
numbers.push_back(4);
numbers.push_back(4);
for (int i=0; i<numbers.size(); i++)
{
int count = 1;
for (int j=i+1; j<numbers.size() && numbers[i] == numbers[j]; i++, j++)
{
count++;
}
cout << count << " times " << numbers[i] << "." << endl;
}
My version: reading the first value as a special case instead.
#include <iostream>
int main()
{
int n;
std::cin >> n;
int value;
std::cin >> value;
--n;
while (n >= 0) {
int count = 1;
int previous = value;
while (n --> 0 && std::cin >> value && value == previous) {
++count;
}
std::cout << count << " times " << previous << ".\n";
}
}
Run your loop one longer (>= 0 instead of > 0), and in the last round, instead of reading currentNumber from cin, do currentNumber = lastNumber + 1 (so that it's guaranteed to differ).
slightly more CREATIVE answer, this one does not make assumption about input being all known before the start of the loop. This prints the total every time, but makes use of \r carriage return but not line feed. A new line is inserted when a different number is detected.
int prev_number = -1;
int current_number;
int count = 0;
for (int i=0; i<numbers.size(); i++)
{
current_number = numbers[i];
if (current_number != prev_number)
{
count = 0;
cout << endl;
}
count++;
prev_number = current_number;
cout << count << " times " << numbers[i] << "." << "\r";
}
only problem is that the cursor is left on the last line. you may need to append cout << endl;
I think this will work:
#include <iostream>
using namespace std;
int main()
{
int n;
cin >> n;
int prevNumber = -1;
int currentCount = 0;
int currentNumber;
int i = 0;
while(i <= n)
{
if(i != n) cin >> currentNumber;
if(currentNumber != prevNumber || i == n)
{
if(currentCount != 0)
{
cout << currentCount << " times " << prevNumber << "." << endl;
}
prevNumber = currentNumber;
currentCount = 1;
}
else
{
++currentCount;
}
i++;
}
}
I would use a for loop, but I wanted to stay as close to the original as possible.