c++ vector not updating in nested for loop - c++

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).

Related

Can't figure out this stack output c++

So I have a stack example I created following a tutorial using the stack library
stack<string> custs;
custs.push("george");
custs.push("louie");
custs.push("florence");
// cout << "size" << custs.size() << endl;
if (!custs.empty()) {
for (int i = 0; i <= custs.size(); i++) {
cout << custs.top() << endl;
custs.pop();
}
}
I ran this and got the output:
florence
louie
My question is why isn't it outputting George as well? The program outputs the top data then pops it. This means it should output Gorge then pop it after. Why doesn't this happen? initially the code was i < cust.size so I thought because i is not less than 1 it would not ouput. So I switched it to <= and it still doesn't output George. How come?
It is because you are both increasing i and reducing the size of the stack in the loop.
You can rewrite your loop like this:
while (!custs.empty()) {
cout << custs.top() << endl;
custs.pop()
}
Here is a step by step explanation of what is happening so you can understand it better:
First, i starts as 0, and custs.size() returns 3. Since 0 <= 3 is true, the body of the loop executes, printing "florence" and removing it from the stack.
On the second iteration, i equals 1, and custs.size() returns 2, because you had 3 items but you removed one. Since 1 <= 2 is true, the body of the loop executes again, printing "louie" and removing it from the stack.
Then, i equals 2, and custs.size() returns 1, because you already removed 2 elements. Since 2 <= 1 is false, the body of the loop doesn't execute, and the loop ends.
As you can see, the problem is that your loop's condition changes on each iteration. There are a couple of ways to fix this:
int s = custs.size();
for (int i = 0; i < s; i++) {
cout << custs.top() << endl;
custs.pop();
}
By doing that, you store the original size of the stack, so you can iterate without problems.
Another solution would be to check if the stack is empty on each iteration with a while loop:
while (!custs.empty()) {
cout << custs.top() << endl;
custs.pop();
}
By doing that, you check if there are any elements left to print each time.
Hope this helps!
When you use for loop like this
for (int i = 0; i <= custs.size(); i++) {
cout << custs.top() << endl;
custs.pop();
}
it loops directly till the size of stack which decreases in each iteration.
which in my opinion is the main reason your code is not working. I rewrite this as
int z = custs.size() ;
for(int i=0;i<=z;i++)
{
cout<<custs.top()<<endl;
custs.pop();
}
and it worked perfectly fine. In my opinion, the best approach is to use while loop like this
while(!custs.empty())
{
cout<<custs.top()<<endl;
custs.pop();
}

Why isn't this x value increasing in this map for loop? c++

The purpose of this loop is to look through a 2d vector and count the frequency in which a value in the first column appears. If the value shows up all three times, then it is good to go. If it doesn't then I would like to delete the row that it's in from the vector. The "it" iterator stores the value as (value, frequency).
I can't figure out how to delete the row at this point though, i have been trying to use a counter "x" in the second for loop so that it can keep track of which row it is on, but when i run it through the debugger the x doesn't increment. What ends up happening is the vector deletes the first rows instead of the rows that make the if statement true.
Why isn't the "x" incrementing? Is there a different method i could use to keep track of which row the loop is currently in?
"data" is the 2d vector.
for (int i = 0; i < data.size(); i++) // Process the matrix.
{
occurrences[data[i][0]]++;
}
for (map<string, unsigned int>::iterator it = occurrences.begin(); it != occurrences.end(); ++it)
{
int x = 0;
if ((*it).second < 3) // if the value doesn't show up three times, erase it
{
data.erase(data.begin() + x);
}
cout << setw(3) << (*it).first << " ---> " << (*it).second << endl; // show results
x++;
}
You reset x back to 0 every loop. Initialize it outside the loop and it should work.
int x = 0;
You have to initialize x outside the for loop. If you declare it in the for loop it will be set to 0 every time. You current program deletes the first element each time because the x is always zero here: data.erase(data.begin() + x);
for (int i = 0; i < data.size(); i++) // Process the matrix.
{
occurrences[data[i][0]]++;
}
int x = 0;
for (map<string, unsigned int>::iterator it = occurrences.begin(); it != occurrences.end(); ++it)
{
if ((*it).second < 3) // if the value doesn't show up three times, erase it
{
data.erase(data.begin() + x);
}
cout << setw(3) << (*it).first << " ---> " << (*it).second << endl; // show results
x++;
}

Vector going out of bounds

I'm attempting to iterate through a list of 6 'Chess' pieces. Each round they move a random amount and if they land on another then they 'kill' it.
The problem is that when the last piece in my vector kills another piece I'm getting a vector 'out of range' error. I'm guessing it's because I'm iterating through a vector whilst also removing items from it, but I'm not increasing the count when I erase a piece so I'm not entirely sure. Any help would be greatly appreciated.
Here is my vector:
vector<Piece*> pieces;
pieces.push_back(&b);
pieces.push_back(&r);
pieces.push_back(&q);
pieces.push_back(&b2);
pieces.push_back(&r2);
pieces.push_back(&q2);
and this is the loop I iterate using:
while (pieces.size() > 1) {
cout << "-------------- Round " << round << " --------------" << endl;
round++;
cout << pieces.size() << " pieces left" << endl;
i = 0;
while (i < pieces.size()) {
pieces.at(i)->move(board.getMaxLength());
j = 0;
while (j < pieces.size()) {
if (pieces.at(i) != pieces.at(j) && col.detectCollision(pieces.at(i), pieces.at(j))) {
cout << pieces.at(i)->getName() << " has slain " << pieces.at(j)->getName() << endl << endl;
pieces.at(i)->setKills(pieces.at(i)->getKills() + 1);
pieces.erase(pieces.begin() + j);
}
else {
j++;
}
}
i++;
}
}
Solution
pieces.erase(pieces.begin() + j);
break;
Your logic needs a little refinement.
The way you coded it, it seems the "turn based" nature of chess has been replaced by a kind of "priority list" -- the pieces closer to the start of the vector are allowed to move first and, thus, get the priority into smashing other pieces.
I don't know if you want this logic to be right or wrong. Anyway, the trouble seems to be due to unconditionally executing the line
i++;
It should not be executed if you remove a piece for the same reason 'j++' isn't executed: you will jump over a piece.
I have a very strong feeling that this line of code:
i++;
is your culprit which is missing either a needed break condition or another conditional check that is missing from your loops. As it pertains to your nested while loops' conditions since they are based on the current size of your vector and are not being updated accordingly.
while (pieces.size() > 1) {
// ...
while (i < pieces.size()) {
// ...
while (j < pieces.size()) {
// ...
}
}
}
This is due to the fact that you are calling this within the inner most nested loop:
pieces.erase(pieces.begin() + j);
You are inside of a nested while loop and if a certain condition is met you are then erasing the object at this index location within your vector while you are still inside of the inner while loop that you never break from or check to see if the index is still valid.
Initially you are entering this while loop with a vector that has 6 entries, and you call erase on it within the nested loop and now your vector has 5 entries.
This can reek havoc on your loops because your index counters i & j were set according to the original length of your vector with a size of 6, but now the vector has been reduced to a size of 5 while you are still within the inner most nested loop that you never break from nor check to see if the indices are valid. On the next iteration these values are now invalidated as you never break out of the loops to reset the indices according to the new size of your vector, nor check to see if they are valid.
Try running this simple program that will demonstrate what I mean by the indices being invalidated within your nested loops.
int main() {
std::vector<std::string> words{ "please", "erase", "me" };
std::cout << "Original Size: " << words.size() << '\n';
for (auto& s : words)
std::cout << s << " ";
std::cout << '\n';
words.erase(words.begin() + 2);
std::cout << "New Size: " << words.size() << '\n';
for (auto& s : words)
std::cout << s << " ";
std::cout << '\n';
return 0;
}
-Output-
Original Size: 3
please erase me
New Size: 2
please erase
You should save locally pieces.at(i) and use this local variable everywhere you use pieces.at(i).
To avoid both elements out of bound and logical problems you can use std::list.
As aside, you should use std::vector<Piece*> only if these are non-owning pointers, otherwise you should use smart-pointers, probably unique_ptr.

Using file input to input integers

I am stuck here having trouble figuring out as to why this loop is not inserting the integers from a text file into an array.
I have a textfile that contains 100 integers, all separated by spaces. I am trying to insert these integers into an array. However when I output, for example a[2], it outputs 0, leading me to believe that the numbers are not being inserted into the array.
listFile.open("unsortedlist.txt");
cout << endl << "Unsorted list = ";
for (int i = 0; i < 100; i++)
{
while (listFile >> individualNum )
{
a[i] = individualNum;
cout << individualNum << ", ";
}
}
cout << "\n" << a[1] << "\n";
Because of the while statement, all the numbers that are successfully read are assigned to a[0] only. As a consequence, the final value of a[0] is the last valid input while nothing is assigned to any of the other elements of a.
You can use something like:
for (int i = 0; i < 100 && listFile >> individualNum; i++)
{
a[i] = individualNum;
cout << individualNum << ", ";
}
The inner loop will diligently read every number from the file.
And assign every number to a[i]. The same array element, each and every time.
On the first iteration of the outer loop, i is 0, so the code will read every number from the file, assigning each number to a[0].
When the inner loop reaches the end of the file, it will terminate. Then, the outer for loop will increment i to 1, iterate again, and run the inner loop. Since the entire file has been read, the inner loop will not do anything. Neither it will do anything more, for the remaining 98 elements of the array.
The loop should probably be, simply:
for (int i = 0; i < 100; i++)
listFile >> a[i];
Keep in mind that this will work correctly, of course, only when there are exactly 100 integers in the file.

How would I know if the counter increments are at the correct place to keep track the # of comparisons ~ C++?

// Question solved. I am confused on where to add the counters at to report the number of
comparisons. It always stay at a fixed number and never changes. Assume the vector contain two-digit random numbers every time the program runs. //
Edit: New question. I'm not sure if the counter increments are at the correct place or not for insertion sort and selection sort.
Code pasted at a safe link: http://ideone.com/Bk90du
int insertionSort(vector<int> &v)
{
// Variables
int temp, i, j, counter;
counter = 0;
for (i = 1; i < v.size(); i++)
{
temp = v[i];
j = i-1;
while(temp < v[j] && j >= 0)
{
v[j+1]=v[j];
j--;
counter++; // tracking # of comparisons.
}
v[j+1]=temp;
}
return counter; // return counter
}
According to the (now deleted) comment, this is main():
int main() {
int numCount;
vector<int> myVector2(myVector);
insertionSort(myVector2);
cout << endl << endl;
cout << "Vector after Insertion Sort: ";
printVector(myVector2);
cout << endl << endl;
numCount = insertionSort(myVector2);
cout << "Number of comparisons: " << numCount;
You sort the same vector two times, and print the comparision count of the second sort run. When the vector is already sorted, the number of comparisons is equal to the number of elements in the vector, because no work has to be done.
To get the true number of comparisons, change your main() to:
int main() {
int numCount;
vector<int> myVector2(myVector);
numCount = insertionSort(myVector2);
cout << endl << endl;
cout << "Vector after Insertion Sort: ";
printVector(myVector2);
cout << endl << endl;
cout << "Number of comparisons: " << numCount;
Without knowing what your test cases are, it's not possible to comment on number of comparisons they perform. If all cases have similar attributes, it is quite possible the code is behaving as it should.
EDIT: the following added in response to claim by OP in comments that the test cases are vectors with 100 randomly generated two-digit elements.
If, as you have said in comments, your test cases involve vectors with 100 random two-digit values, then the value of counter will depend on how "unsorted" the elements are (with the minimum value possible related to the number of elements). Assuming all of your test cases are the same size, then the only way the value of counter will be the same is if the vectors are sorted similarly BEFORE calling your function. For example, if all your vectors are pre-sorted in ascending order and the same size, every test case will give the exact same return value. Similarly, if all your vectors are pre-sorted in descending order and the same size, every test case will give the exact same return value (albeit different from the value returned if they are initially in ascending order).
For that reason, I do not believe your comment that the test cases are random. They are probably presorted (or maybe partially sorted) in some way. For example, you might be calling your function twice for each test case, and only printing out the value of count after the second call ..... when the vector is (if your code behaves as it should) already pre-sorted.
End Edit
That said, the variable counter in your code is accumulating the number of times the body of the while loop is executed. That has nothing to do with number of comparisons being performed, as there is no comparison performed in the body of that loop. It is related to the number of insertions, not the number of comparisons.
If, by "comparison", you want mean evaluating the expression temp < v[j] (as distinct from other expressions, like i < v.size() or j >= 0, which could also be called comparisons in your code) then you might consider doing something like
while (++counter && temp < v[j] && j >= 0)
and removing incrementing of counter from the loop body.
Since counter is initialised to zero, this will count the number of times temp < v[j] is evaluated (++counter will always produce a non-zero result). Note that, since temp < v[j] can be false, it will not count the number of times j >= 0 is computed.