Inserting to set in a "Fixed" Size Loop - c++

So I wanted to insert the double of all the elements in my set back into the set. But obviously I need to grab the end iterator so that I don't keep iterating over new elements. (Don't worry, I checked, set::insert doesn't invalidate iterators: http://www.cplusplus.com/reference/set/set/insert/#validity) So given the input, set<int> foo = { 1, 2, 3 }, here's what I did:
for(auto it = begin(foo), finish = end(foo); it != finish; ++it) {
foo.insert(*it * 2);
}
I expected my set to contain:
1, 2, 3, 4, 6
Surprise! It contains:
-2147483648, -1073741824, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576, 32768, 49152, 65536, 98304, 131072, 196608, 262144, 393216, 524288, 786432, 1048576, 1572864, 2097152, 3145728, 4194304, 6291456, 8388608, 12582912, 16777216, 25165824, 33554432, 50331648, 67108864, 100663296, 134217728, 201326592, 268435456, 402653184, 536870912, 805306368, 1073741824, 1610612736
Live Example
Clearly end(foo) doesn't work as I thought it did. So... if I want to save the loops size and count to that?

Iterators are still valid, but as a std::set is a node-based container, the elements are always sorted, using std::less<Key> by default
See how iterators are jumping to lower values, making it to struggle for finish
Code snippet:
for( ; it != finish; ++it)
{
auto t = *it ;
std::cout << "At " << t << "\n";
foo.insert( t * 2 ) ;
std::cout << "Inserted " << t*2 << "\n";
}
At 1
Inserted 2
At 2
Inserted 4 <----+
At 3 |
Inserted 6 | <---+
At 4 // jumped back -----+ |
Inserted 8 |
At 6 // Jumped back -----------+
Inserted 12
At 8
.....

A typical method of doing this would be to iterate through your source set, and perform your function on each value, adding the result into a second set.
Once you are finished with the iteration process and have fully generated the second set, union the two sets together.

If you truly want to save the loops size and count to that, you can do something like this:
set<int> foo = { 1, 2, 3 };
int setSize = foo.size();
auto it = foo.begin();
for(int i = 0; i < setSize; ++i) {
foo.insert(*it * 2);
++it;
}
copy(cbegin(foo), cend(foo), ostream_iterator<int>(cout, " "));
This will give you the output: 1 2 3 4 6

This is obviously circular. The size is increasing in every step, making the loop never reach the end.
It's like saying: Take this list, start from the first element, and keep doing this for every element, and when you're done, add one more element to the same list.
Why would this ever end?
EDIT:
Answering: "So... if I want to save the loops size and count to that?":
int size = foo.size();
std::set<int> bar;
for(auto it = begin(foo); it != end(foo); ++it) {
bar.insert(*it * 2);
}
foo.insert(bar.begin(), bar.end());

I believe that your assumption is that a set is allocated into a contiguous container with the presumption that it initially had enough space that reallocation of the contiguous container was not necessary; in this assumed case I would also expect to see your behavior. (It should be noted though that even in a situation where this were a contiguous container, the container's capacity would need to be validated for this assumption to avoid undefined behavior.)
But even in your question you point out that insert doesn't invalidate iterators, which means that the container cannot be contiguous. In fact sets:
Are typically implemented as binary search trees
Understanding this you're really just continuing your loop till your iterator ends pointing to the last leaf node. Your compilers set implementation caused that to happen when you inserted the -2147483648 element, but that's implementation dependent, and thus may behave differently on another compiler.
You're looking for a behavior that is defined and compiler independent. Depending upon you're knowledge of the set contents you could reverse iterate over the set:
for(auto it = rbegin(foo); it != rend(foo); ++it) {
foo.insert(*it * 2);
}
This is only a good solution if the insertion creates elements that are sorted after those being iterated over. For example if foo contains negative numbers this won't work. You could evaluate this by checking: if(*cbegin(foo) < 0) in the else-block you could do the reverse iteration loop suggested above, but in the otherwise you'd need to do a temporary set allocation described in The Quantum Physicist's answer.

Related

Difference between for loop and the range based loop in C++

I am confused as to what what the difference is between for loop and for each loop in C++.
I read tutorials and some books but I am yet to see how for each loop is different.
With arrays, examples I have seen seem to suggest for each loop loops through the whole elements at a go. Could that be the special advantage range based loop has?
The main difference is that the ordinary for-loop uses an additional variable used as an index inside the array and has the scope of the loop and you can yourself write the condition of the for loop.
For example let's assume that you need to output either all even elements of an array or until an element with a zero value is encountered. You can write
#include <iostream>
int main()
{
int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 11, 12 };
const size_t N = sizeof( a ) / sizeof( *a );
for ( size_t i = 0; i < N && a[i] != 0; i++ )
{
if ( a[i] % 2 == 0 ) std::cout << i << ": " << a[i] << '\n';
}
return 0;
}
The program output is
1: 2
3: 4
5: 6
7: 8
How to do this with the range-based for loop? For starters before the loop you need to declare a variable that will play the role of the index. One drawback of this is the variable is not declared in the scope where it is used.
Also to stop the iterations of the loop you need to use a break statement within the loop. That also makes the code more complicated.
Compare the above program with this
#include <iostream>
int main()
{
int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 11, 12 };
const size_t N = sizeof( a ) / sizeof( *a );
size_t i = 0;
for ( const auto &item : a )
{
if ( item == 0 )
{
break;
}
else if ( item % 2 == 0 )
{
std::cout << i << ": " << item << '\n';
}
++i;
}
return 0;
}
In general to use the range based for loop the used container either shall have member functions begin and end or the general functions begin and end shall support the container. For arrays begin and end mean expressions a and a + N.
The difference between a for loop and a range based for loop is roughly analogous to the difference between goto and a for loop. Former is a more generic control flow, while the latter is more structured. Every range based loop can be written as a for loop and every for loop can be written as a goto. But the reverse is not true.
Goto encapsulates the idea of jumping elsewhere. Loop encapsulates the idea of repetition (which involves jumping back). Range based loop encapsulates the idea of iterating over a range from begin until end (which involves repetition).
If your intention is to iterate over an entire range, then the range based loop is typically syntactically simpler, and easier to understand than a for loop. Likewise, a for loop is easier to understand than a goto loop. This is what makes structured approach superior. Compare for example the following, and consider which one is easier to understand:
for (auto it = list.begin(), end = list.end(); it != end; ++it) {
auto& element = *it;
// do stuff with element
}
for (auto& element : list) {
// do stuff with element
}
loops through the whole elements at a go. Could that be the special advantage range based loop has?
Looping through an entire range is what range based loop can do. A for loop can do that too. But a for loop can do much more: it can iterate indices, it can iterate indefinitely, it can iterate until a terminator etc.

How to compare all elements of vector one to vector two and if a max element exists then comparing all the elements of vector two to vector three?

I want to compare all element of vector x to all elements of vector y and if I find a element greater in vector y than being compared to, I have to take that particular element of vector y and compare to all elements of vector z and if it is true return true else if i don't find a greater element in first iteration i,e when elements of vector x are compared to vector y i have to break the loop and return false.
I tried to iterate through all the elements of stackarmies but I don't know how to take the first element of vector one and compare with all the elements of vector, since all the vectors are merged into the last vector.
vector<int> stack;
int noofstack, noofoperations, stackno, OperationType;
// Taking the input number of stacks
cin >> noofstack;
vector<vector<int>> stackarmies;
for (int i = 0; i < noofstack; i++)
{
int stacksize;
//Since vectors are dynamic and we don't need to declare the size but as per the problem statement I've added it/
cin >> stacksize;
for (int k = 0; k < stacksize; k++)
{
//Taking the input of all the vectors one by one and then adding all the vectors into one vector
int armyheight;
cin>>armyheight;
stack.push_back(armyheight);
}
stackarmies.push_back(stack);
Test cases
Input 1
2
3 3 5 4
3 1 1 2
Resulting stackarmies: { {3, 5, 4}, {3, 5, 4, 1, 1, 2} }
Desired output: False
We will take first element of vector 1 : 3 and compare with all
elements of vector 2 , in vector 2 no element is greater than 3.
Input 2
2
3 1 0 4
3 2 1 3
Resulting stackarmies: { {1, 0, 4}, {1, 0, 4, 2, 1, 3} }
Desired output: True
We will take first element of vector 1 : 1 and compare with all
elements of vector 2, in vector 2, the first element is greater than 1,
so true
Input 3
2
3 1 9 0
2 0 11
Resulting stackarmies: { {1, 9, 0}, {1, 9, 0, 0, 11} }
Desired output: True
We will take first element of vector 1 : 1 and compare with all
elements of vector 2, in vector 2, the last element is greater than 1,
so true
Input 4
3
3 0 8 0
3 4 0 11
3 0 9 0
Resulting stackarmies: { {0, 8, 0}, {0, 8, 0, 4, 0, 11} , {0, 8, 0, 4, 0, 11, 0, 9, 0} }
Desired output: True
We will take the second element of vector 1: 8 and compare with
all elements of vector 2 , 11 is greater than 8 so we will compare 11 of
vector 2 with vector , since there are no values greater than 11, so it's
false
I don't know how to take the first element of vector one and compare with all the elements of vector, since all the vectors are merged into the last vector.
You're getting ahead of yourself. Why do you want all the vectors merged into the last vector? Answer: you don't; that's just what happened. Why did all the vectors merge into the last vector? Answer: because you have a bug in your code that reads the data. Fix that bug instead of spending ten times as much effort trying to handle the malformed data.
That whole spiel about what you intend to do next is nothing more than a distraction that wastes the time of the people from whom you are asking help. Ask for help with the real problem (the loading bug) instead of driving people away with a confusing question that assumes bad data is good.
There are several ways to fix the bug. I think the most helpful approach is one that would have avoided the bug in the first place. You try to do too much in a single function. Divide and conquer; when you have a non-trivial sub-step, create a function to handle it. Good programming practices lead to fewer bugs.
Specifically, reading the heights of the fighters in a stack is non-trivial. Delegate that to a helper and reduce the body of your outer for loop to a single line.
for (int i = 0; i < noofstack; i++)
{
//* This is non-trivial, so use a helper function.
stackarmies.push_back(read_fighter_heights());
}
This helper function is responsible for reading a line of data, generating a stack (a vector<int>) from it, and returning that stack. That covers most of the body of your loop, leaving only the simple task of pushing the returned stack onto your vector of stacks.
Creating this helper function from your existing code is fairly simple. Mostly, just move the body of the loop into an appropriate function definition. In addition, you should notice that stack is needed (only) in this function, so also move that variable's declaration into the new function's definition.
vector<int> read_fighter_heights()
{
vector<int> stack;
int stacksize;
//Since vectors are dynamic and we don't need to declare the size but as per the problem statement I've added it/
cin >> stacksize;
for (int k = 0; k < stacksize; k++)
{
//Taking the input of all the vectors one by one and then adding all the vectors into one vector
int armyheight;
cin>>armyheight; //* Reading a single integer is trivial, so no need for another function here.
stack.push_back(armyheight);
}
return stack;
}
Presto! Problem solved. All you had to do was be more organized.
Addendum: The reason this solves the problem is that extra step of moving the declaration of stack. In the original code, this variable was declared outside the outer loop, and it was never cleared. The result was that it accumulated values from each line that was read. In this version, the variable is re-initialized before reading each line, so values do not accumulate. You could get the same result by moving the line in the original code, without splitting off a new function. However, splitting off a new function is a good habit to get into, as it almost forces you to declare stack at the right level, avoiding the problem in the first place.
bool CompareVectors(vector<vector<int>> st)
{
bool result = true;
for (int k = 0; k < st.size(); k++)
{
if (k != st.size() - 1)
{
if (result)
{
for (auto i = st[k].begin(); i != st[k].end(); ++i)
{
for (auto j = st[k+1].begin(); j != st[k+1].end(); ++j)
{
if (*i < *j)
{
result = true;
break;
}
else
{
result = false;
}
}
if (result)
{
break;
}
}
}
}
}
return result;
}

Iterator out of range run time exception with an iteration by 2 in a for loop

Here is a piece of my code:
vector<int> v {1, 2, 10, 4, 5, 6, 7, 8, 9 };
for (auto i = v.begin(); i != v.end(); i = i + 2) {
cout << (*i) << " ";
}
What I want to do is to advance the iterator by 2 elements after each iteration. However, there is a runtime exception: offset out of range. So my question is:
Is there a way to iterate by 2 elements each time with a for loop and if possible, can the condition to prevent this exception be defined in the for() statement?
Is there a way to iterate by 2 elements each time with a for loop and
if possible, can the condition to prevent this exception be defined in
the for() statement?
Sure there is a way. The most natural would be this
vector<int> v {1, 2, 10, 4, 5, 6, 7, 8, 9 };
for (size_t i=0; i < v.size(); i = i + 2) {
cout << v[i] << " ";
}
Iterators (just like anything else) arent the best tool for every situation. Iterators are meant to be an abstraction that does not care about an index. Thus when you actually do care about the index, I would not use iterators, but a plain index based loop. Of course its a matter of taste, but being so much used to loops that go from begin to end incremented via ++it, it can help a lot to distinguish a loop that deviates from this usual pattern.
As #tobi303 said, the most suitable way for you is to use indexes and not iterators. Anyway, there's a reason for the Out of Range Exception. If you try with this vector (or in general if you add another element to it):
{1, 2, 10, 4, 5, 6, 7, 8, 9, 1 }
You won't obtain that exception. This is what the doc says about the end method:
Returns an iterator referring to the past-the-end element in the vector container.
The past-the-end element is the theoretical element that would follow the last element in the vector. It does not point to any element, and thus shall not be dereferenced.
So, when *i is equal to 9, and the for loop checks for the end of the vector, it will go on. But if you add 2 to i, the end method will never match the actual end.

How to increase value of a k consecutive elements in an vector in c++?

Suppose we have an vector in c++ of size 8 with elements {0, 1, 1, 0, 0, 0, 1, 1} and i want to increase the size of a specific portion of vector by one, for example, lets say the portion of vector which needs to be increase by 1 is 0 to 5, then our final result is {1, 2, 2, 1, 1, 0, 0, 1, 1}.
Is it possible to do this in constant time using standard method of vectors (like we a memset in c), without running any loop?
No... and by the way with memset you don't have a guaranteed constant-time operation either (in most implementation is just very fast but still linear in the number of elements).
If you need to do this kind of operation (addition/subtraction of a constant over a range) on a very huge vector a lot of times and you need to get the final result then you can get O(1) per update using a different algorithm:
Step 1: convert the data to its "derivative"
This mean replacing each element with the difference from previous one.
// O(n) on the size of the vector, but done only once
for (int n=v.size()-1; i>0; i--) {
v[i] -= v[i-1];
}
Step 2: do all the interval operations (each in constant time)
With this representation adding a constant to a range simply means adding it to the first element and subtracting it from the element past the ending one. In code:
// intervals contains structures with start/stop/value fields
// Operation is O(n) on the **number of intervals**, and does
// not depend on the size of them
for (auto r : intervals) {
v[r.start] += r.value;
v[r.stop+1] -= r.value;
}
Step 3: Collect the results
Finally you just need to un-do the initial processing, getting back to the normal values on each cell by integrating. In code:
// O(n) on the size of vector, but done only once
for (int i=1,n=v.size(); i<n; i++) {
v[i] += v[i-1];
}
Note that both step 1 and 3 (derivation and integration) can be done in parallel on N cores with perfect efficiency if the size is large enough, even if how this is possible may be not obvious at a first sight (it wasn't for me, at least).

Find runs of consecutive values in int array

Let's say I have this integer array of separate integer elements:
111100010011010
I'd like to find out if there exists 0000 in this array, which obviously does not, but 000 exists. Same goes for other lengths of consecutive runs.
I know this is easily done with strings, there are built in functions for this, but is there something built in which accomplishes what I want to do?
Or is there another easy method I overlooked? All I can come up with are complicated non efficient algorithms going through the array and saving values in a temporary other array.
No need to save values to a temporary array.
All you need to do is keep track of the largest length found (initially zero) and the location of its first element (initially NULL if you use a pointer to indicate that).
Then walk through the array until you find the value of interest. Count the number of consecutive occurrences. If that number exceeds the maximum length found, set the location to point at the first one found.
Repeat until end of array is reached.
Done. If the largest length found is zero, it means there were no occurrences of the value sought.
No, I'm not going to write code for the above. The description of the approach is enough.
There are also plenty of alternative options using standard algorithms
Just for the record, another way is to use use std::search.
#include <algorithm>
using namespace std;
const int elements[] = { 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0 };
const int test1[] = { 0, 0, 0, 0 };
const int test2[] = { 0, 0, 0 };
auto it1 = std::search(begin(elements), end(elements), begin(test1), end(test1));
auto it2 = std::search(begin(elements), end(elements), begin(test2), end(test2));
std::cout << "Test 0000: " << (it1 == end(elements) ? "no" : "yes") << "\n";
std::cout << "Test 000: " << (it2 == end(elements) ? "no" : "yes") << "\n";
Prints out:
Test 0000: no
Test 000: yes
Even easier if your array is a standard container, like std::array or vector.