Unexpected vector behavior using set intersection - c++

I am trying to compare a 2 dimensional vector against another 2 dimensional vector.
vector<vector<int> >::iterator rowit1;
for(rowit1 = aboveaveperms.begin(); rowit1 != aboveaveperms.end();rowit1++)
{
vector<vector<int> >::iterator row2it;
int s = 0;
for(row2it = afterave.begin(); row2it != afterave.end();row2it++)
{
vector<int> matches (9);
vector<int>::iterator itset;
itset = set_intersection(rowit1->begin(),rowit1->end(),row2it->begin() + 1,row2it->end(),matches.begin());
matches.resize(itset-matches.begin());
s = matches.size();
matches.erase(matches.begin(),matches.end()); // my attempt at trying to correct it
}
}
In the second loop on the first pass matches is created correctly holding 9 zeros. But once it begins the second loop, as soon as it hits the curly bracket, it comes out with 101 million instead of 9. Once it actually hits it's declaration it goes back to the 9 which is proper. I have noticed while debugging that it is holding all of the 2 dimensional vector I am checking against before the declaration corrects it to only holding 9 ints.
idzireit
APPENDUM:
As it has been pointed out I forgot to ask my question. The above code does work as I want the number of matches (between 5 and 9) but because of the erratic behaviour of the vector will it cause a memory leak or sigseg if the other vectors get too big?
Also, as whozcraig asked, I have row2it->begin() + 1 because the first element is the game number which is much bigger then the rest of the numbers. The rest of the numbers are sorted though.
Example of what I am trying to do is as follows:
perm vector 1
1 3 5 6 7
compare against 4 vectors and count for number of matches in each
5 8 9 10 11
3 7 11 14 18
1 5 6 7 8
so in running through the loop the first match should be 1 second should be 2 and third should be 4. Hope this helps to clarify what I am trying to do.
ADDENDUM 2:
Now that I have my windoze machine up and running and have reinstalled qt creator on it I have run the above code and works fine on windows. I do not get the 101 million elements like I did when running under ubuntu. Why does it work correctly on windoze and not ubuntu ?
idzireit

Firstly, according to https://en.cppreference.com/w/cpp/algorithm/set_intersection, both vectors be intersected must be sorted.
Secondly, you set an initial size of 9 to vector matches, but if the number of intersected elements is greater than 9, then std::set_intersection is writing out of bounds of matches, which may cause an undefined behaviour.
You can execute your code using a memory analyzer as Valgrind in order to detect a possible memory leak. You could use std::back_inserter to avoid this problem:
#include <iterator> // std::back_inserter
vector<int> matches;
std::back_insert_iterator<std::vector<int> > itset(matches);
itset = set_intersection(rowit1->begin(),rowit1->end(),row2it->begin() + 1,row2it->end(), std::back_inserter(matches));

Related

Retrieving values from vector at specific index through size of vector in C++

Is there any other way to access or retrieve the data/values that are in vector at a specific index through the size of the vector? I am currently looping through the vector starting at a desired index all the way to the size of vector or stopping at
lets say the values in the vector include 1 2 3 4 5 6 7 8
and I want to retrieve 3 4 5 6 7 8.
Is there any other way of sufficient way to obtain these values other than looping through the vector?
If you are trying to access and operate on values at index 2 through index 7, (3 4 5 6 7 8)
then looping through the vector to retrieve the values is the most efficient way. If you are trying to group this sub-data and keep a hard copy of your original vector then looping is still most efficient.
Example 1
std::vector<int> myVec{1,2,3,4,5,6,7,8};
for (int i = 2; i < vec.size(); i++)
{
// Do your operation on myVec[i]
// Push myVec[i] to a new list ?
}
If you are trying to obtain a new vector from your original vector which contains only the values you are interested in, then there is a better way. Note that the values 1 and 2 are now lost.
Example 2
myVec.erase (myVec.begin(),myVec.begin() + 2);
//myVec[0] now contains 3
//myVec.size() == 6
Putting Examples 1 and 2 together, if you are trying to obtain a new vector with the values at index 2 through index 7, you can use the assignment operator (=) to assign the data from an existing vector to a new one. Note that this is actually not any more efficient than looping through the vector yourself, but might look a little cleaner. After doing this then you can reference Example 2 to edit the new vector to your liking.

Decreasing value in vectors with SFML

I created 5 numbers using vector with SFML, but I want the second one to fall one by one at intervals of 1 second. But, they first three falling as one by one. I don't understand why something like this is happening. Can you help me?
if (second == 1)
{
random.at(2)-=1;
cout << random[2] << endl;
text.setString(to_string(random[2]));
text.setPosition(numbers[2].getPosition().x, numbers[2].getPosition().y);
numbers.push_back(text);
numbers.erase(numbers.begin() + 2);
clock.restart();
}
The program gif
Full code
I'll give you a hand.
Here's what's happening:
You create 5 numbers in the random array. You may not have noticed it, but they are numbered 0 to 4 (SFML is sitting on C++, and then it means that arrays starts at zero here).
Every second, you update the number stocked in the 3rd place of your random array.
Then it goes wrong: instead of updating the corresponding number in the numbers array, you cycle it with push_back and erase.
Understand me here: push_back create a new element at the end of the vector, while erase removes an element from the vector and then "sort out things" so there's not number gap in the index of the vector.
Effectively, you're handling random right, but when you try to update number you cycle through it. Like this:
seconds: 1 2 3 4 5 6
array content: 0 0 0 0 0 0
(vertical) 1 1 1 1 1 1
2 3 4 5 6 7
3 4 5 6 7 8
4 5 6 7 8 9
I'm not sure how clear I'm making this, but if you look at the array content, you'll see that by erasing and creating a new value at the end, you're cycling through the positions [2-4] of the array. That's why in your gif not all numbers are updated wrong, only 3 of them.
The obvious solutions would be to stop erasing and pushing back in the numbers array. You can update it the same way you updated the random array. It'll be fine.
Like this:
if (second == 1)
{
random.at(2)-=1;
cout << random[2] << endl;
numbers[2].setString(to_string(random[2]));
clock.restart();
}
Have fun.

Assertion Error, using STL Vector

for(myIterator = numbers.begin();myIterator != numbers.end() ;myIterator++)
{
resultVect.push_back(*myIterator+2);
numbers.erase(myIterator+2);
}
numbers consist of a series of numbers (eg 1,2,3,4,5,6,7)
Then I would like to erase every 3rd number.
Something like,
1 2 3 4 5 6 ( First round -> 3 is out)
1 2 4 5 6 ( Second round -> 6 is out)
1 2 4 5 ( Third round -> 4 is out)
and so on.
I will store the number that goes out in another vector (resultVect).
Im getting Assertion error. Pls advise tq
When you use erase for a vector, it will relocate the elements after the erase position so the iterators after that will be invalidated.
Second when you say iterator + 2 and that could go beyond the range of the vector too.
Removing an element from the vector invalidates all iterators to that element and beyond (in the current standard, there is an open issue to change this).
The first question is how efficient you want the process to be, if you don't care (much) about performance you can do a simple loop:
for (int i = 3; i < input.size(); i+=3) {
result.push_back(input[i]);
}
for (int i = (input.size()+2)/3 - 1; i >= 0; --i) {
input.erase(input.begin()+i*3);
}
If performance is critical, you can take a look at the std::remove algorithm and use the same approach to avoid doing multiple copies of the elements while you run the algorithm. Basically you need a read and a write head into the original container and you only copy from the read to the write location if the condition is not met.
Simply put: you cannot modify a vector while iterating it. The iterator will become invalid and that will get you an assertion.
To properly do what you want, you might consider creating a copy of the vector with values to keep, and a vector with values to remove. Then replace the number vector by the one with the values to keep.

set intersection

I want to calculate the gcd of two numbers m and n by prime factorization and taking common factors
like this. Take example m = 36 n = 48
vector<int> factors1 = prime_factorization(m); // 2 2 3 3
vector<int> factors2 = prime_factorization(n); // 2 2 2 2 3
vector<int> intersection(10);
set_intersection(factors1.begin(), factors1.end(), factors2.begin(), factors2.end(), intersection.begin());
intersection is now 2 2 3 0 0 0 0 0 0 0. For this i must set the size of the vector beforehand. Also the remaining elements are set to 0. I don't want this to happen.
Is there a better way to do this? Using sets or anything else?
Also, how do i calculate the product of elements in the vector intersection (2*2*3) using stl ignoring the zeroes?
You can use a back-inserter:
vector<int> intersection;
set_intersection(..., back_inserter(intersection));
Note that there are much better ways of determining the GCD, such as Euclid's algorithm.
Oli's answer is best in the situation as you describe it. But if you were using a vector that already existed and had elements that you were writing over, and you wanted to chop off the extra numbers, you can do it a different way. By calling the vector member erase using the return value of set_intersection:
intersection.erase(
set_intersection(factors1.begin(), factors1.end(), factors2.begin(), factors2.end(), intersection.begin()),
intersection.end());

Position of elements in vector

I have several elements in a vector type that are read from cin and then i perfrom some calculations on the vector and it's order of elements gets changed. The problem is that I need to print the positions of the vector elements after the calculations. I don't know how to explain this well that's why i'll give an example:
10 1 100 1000
and 10 is 1st element, 1 is 2nd, 100 is 3rd etc. After the calculations the vector changes in :
100 10 1 1000
so I should print
3 1 2 4
because 100 is the 3rd element of the input, 10 is the 1st etc. etc.
I tried with an array[1000] (because there aren't numbers larger than 1000 in the input), but it won't work because there can be multiple numbers with the same value, like:
10 10 10 100
and the output can be 1 2 3 4 or 2 3 1 4 or 3 1 2 4 etc. but here i need to output 1 2 3 4 because it's the 'smallest'.
I tried with array f[1001] and f[10] = 1, f[100] = 2, f[1] = 3 - if the numbers from the input are 10 100 1. But in case there are multiple numbers with the same value like 10 10 100, then my idea's not working. Please help me in any possible way.
Sounds like you need to store both the value and the initial position. You should be able to do this with an array of structs:
struct UserInput
{
unsigned int initialPosition;
int userInputValue;
};
int main()
{
userInput theUserInput[100];
// increment a counter, starting at 1, and place it in
// "initialPosition" in the struct as user input is read
}
I'll leave the rest up to you... as it is after all homework :) good luck.
Use an associative array if you know what it is.
Use linear search to determine the index if the number of input is limited.
Consider using log10 (or strlen) to transform the 1, 10, 100, 1000, etc. into 0, 1, 2, 3, etc.
From your description of such example:
10(3) 10(2) 10(1) 100(4)
What we have to output is 1 2 3 4, instead of 3 2 1 4.
So I don't think your requirement is just print the initial position directly. You've to make the position sequences as small as possible.
Following is my solution:
Use a direct-mapping hash table to store all the initial positions for specified element. All the initial positions for the same element is sorted. So if you want output the smallest position sequence, you only need to read the initial positions for this specified element from first to last.
The detailed implementation is left to you, since it's a homework.