Reverse iterator is being advanced by std::set::erase - c++11

I am trying to erase the element that I just traversed into. I initially forgot to store the return value of s1.erase(... inside the for loop to ultimately set the condition to exit the loop. With the way the code is right now, I expected the loop to continue indefinitely. But it works just the way it was originally intended to work.
It looks like std::erase advances the iterator and stores the value in rit. I am not able to find any documentation that explains this behavior.
https://en.cppreference.com/w/cpp/container/set/erase says that the iterator returned has to be stored. All arguments of the set::erase are passed by value, so how is the reverse iterator being advanced?
How is this loop completing?
std::set<int> s1;
s1.insert(20);
s1.insert(30);
s1.insert(50);
auto rit = s1.rbegin();
for (; rit!= s1.rend();)
{
std::cout << "rit is " << *rit << " size is " << s1.size() << std::endl;
s1.erase(std::next(rit).base());
std::cout << "rit after erase is " << *rit << std::endl;
}
The output is
rit is 50 size is 3
rit after erase is 30
rit is 30 size is 2
rit after erase is 20
rit is 20 size is 1
Segmentation fault

Recall that reverse_iterator::base() is always one element behind the apparent iterator's value. For example, after auto rit = s1.rbegin(), *rit returns the last element, while rit.base() == s1.end().
In other words, *rit == *prev(rit.base())
In your loop, initially rit.base() == s1.end(). Then std::next(rit).base() refers to the last element; that element is being erased. In std::set, erasing an element only invalidates iterators to that element, but not any others. s1.end() is still a valid iterator, and so is rit, with rit.base() still equal to s1.end(). So on the next iteration of the loop, you erase the last element again, and leave rit.base() == s1.end() again. And so on.
At some point, the last element is erased, s1 becomes empty, and then *rit exhibits undefined behavior. Recall that *rit == *prev(rit.base()), but there is no previous element anymore.

Related

vector, v.end() and v.begin()

vector <int>v;
vector <int>:: iterator it,it1;
it=v.begin();
it1=v.end();
v.insert(it,12); // in this line doesn't matter what i write it or it1
it=v.begin(); it1=v.end(); // here *it=12, also it is first element and it1 = last element + 1
v.insert(it1,15); // if i write it instead of it1, then v contains 15 12
it=v.begin(); it1=v.end();
cout<<*(it+1); // this line outputs 15;
if my comments are correct, then how v.insert(v.end(), any number); can be correct?
Never debug comments. Always debug the code. :)
std::vector::insert(iterator, value) inserts the value before the iterator passed in. Since std::vector::end() is passed to insert(), this inserts 15 before the end of the vector - that is, after 12. Therefore when the element after the first element is printed, this should print 15.
iterator insert( iterator pos, const T& value ); inserts the element before the specified position.
So here it will insert at the back, and then the end position will shift by one.
Your it1=v.end() will be invalidated by the insert, so you'll need to re-set it. (Thanks #Mgetz)
To insert into an empty vector, you can still insert to end. Just because end() == begin() in an empty vector doesn't mean they're set to the same thing.

Ruby code qn. How to decrease iteration

I'm new to ruby and I'm wondering why this error comes up. (Sorry for bad formatting)
Error:
rb37: in '%': nil can't be coerced into Fixnum (TypeError)
And also I need help with my question. I'm suppose to come up with a method to run through a list of 1 million ID numbers to find a specific ID using the most efficient way possible (in less than 5min). I've been at this the whole afternoon :(
def exist?(id)
dump = []
employee_list = $employee_list.sort #employee_list is an array of 1 million lines of data, I have to look for a specific "id"
while dump.length < id
dump << employee_list.first
if dump.last != id
if id%dump.last != 0 && dump.last != 1
employee_list.delete_if { |n| n%dump.last == 0 }
#what im doing here is to delete ID from employee_list that are multiples of n
elsif id%dump.last == 0
employee_list.delete_if { |m| m%dump.last == 0 && m!=id }
#deleting multiples of m (excluding id itself)
end
elsif dump.last == id
return true
end
end
return false
end
I honestly have absolutely no idea what your code is trying to do, but here's the problem: you loop until the length of your dump array is greater than the id you are searching. In the loop, you append the first element of the employee_list array to the end of dump. You also delete stuff from employee_list.
Now, depending on how large id is, you are going to loop very often. E.g. imagine id is, say, 1234567890, you are going to loop over a billion times, and you are appending over a billion elements to your dump array. At the same time, you are also constantly deleting stuff from employee_list. It is very likely, that at some point in time, employee_list will become empty, which means that employee_list.first will become nil, you will append nil as the last element of dump, and thus you will try to take the modulus of id and nil in line 9, 10, 12, or 13.
Like I said, I don't actually understand what you are doing at all, so I can't tell you how to fix the problem.
Here's how I would solve the problem:
def exist?(id)
$employee_list.find(id)
end

Why the following code prints garbage values for input strings greater than 128 bytes?

This is a problem of codechef that I recently came across. The answer seems to be right for every test case where the value of input string is less than 128 bytes as it is passing a couple of test cases. For every value greater than 128 bytes it is printing out a large value which seems to be a garbage value.
std::string str;
std::cin>>str;
vector<pair<char,int>> v;
v.push_back(make_pair('C',0));
v.push_back(make_pair('H',0));
v.push_back(make_pair('E',0));
v.push_back(make_pair('F',0));
int i=0;
while(1)
{
if(str[i]=='C')
v['C'].second++;
else if (str[i]=='H')
{
v['H'].second++;
v['C'].second--;
}
else if (str[i]=='E')
{
v['E'].second++;
v['C'].second--;
}
else if (str[i]=='F')
v['F'].second++;
else
break;
i++;
Even enclosing the same code within
/*reading the string values from a file and not console*/
std::string input;
std::ifstream infile("input.txt");
while(getline(infile,input))
{
istringstream in(input);
string str;
in>>str;
/* above code goes here */
}
generates the same result. I am not looking for any solution(s) or hint(s) to get to the right answer as I want to test the correctness of my algorithm. But I want to know why this happens as I am new to vector containers`.
-Regards.
if(str[i]=='C')
v['C'].second++;
You're modifying v[67]
... which is not contained in your vector, and thus either invalid memory or uninitialized
You seem to be trying to use a vector as an associative array. There is already such a structure in C++: a std::map. Use that instead.
With using this v['C'] you actually access the 67th (if 'A' is 65 from ASCII) element of a container having only 4 items. Depending on compiler and mode (debug vs release) you get undefined behavior for the code.
What you probably wanted to use was map i.e. map<char,int> v; instead of vector<pair<char,int>> v; and simple v['C']++; instead of v['C'].second++;

Proper save/restore of RNG state in boost::random behaving unexpectedly

I have a small test program that attempts to save and restore the state of a random number generator using boost::random, but it is not behaving as the documentation indicates. From the boost docs:
Classes which model a pseudo-random number generator should also model the Streamable concept, i.e. implement operator<< and operator>>. If so, operator<< writes all current state of the pseudo-random number generator to the given ostream so that operator>> can restore the state at a later time. The state shall be written in a platform-independent manner, but it is assumed that the locales used for writing and reading be the same. The pseudo-random number generator with the restored state and the original at the just-written state shall be equivalent.
As I understand it, if a RNG state is saved and then a number is pulled from it, the state should change. If the state is later restored, this should allow the exact same number to be generated as the generator has been rolled back. I made a test program that examines this, but at first glance it seems like the state is not restored. Consider the code:
unsigned int s = static_cast<unsigned int>(std::time(0));
//typedef boost::minstd_rand base_generator_type;
typedef boost::mt19937 base_generator_type;
base_generator_type randgen(s);
boost::uniform_01<base_generator_type> getrand(randgen);
//boost::normal_distribution<float> noise(0,1);
//boost::variate_generator<base_generator_type,
//boost::normal_distribution<float> > getrand(randgen, noise);
double numsbefore[2], numsrightafter[2], numsnew[4];
//generate a short sequence, save it, and display
numsbefore[0] = getrand();
numsbefore[1] = getrand();
cout << "First Sequence, before save: "
<< numsbefore[0] << " "
<< numsbefore[1] << endl;
//save the current RNG state to a file using the stream interface
std::ofstream rngfileout("test_rngfile.txt");
rngfileout << randgen;
rngfileout.close();
//generate the next two numbers and display
numsrightafter[0] = getrand();
numsrightafter[1] = getrand();
cout << "Next, right after save: "
<< numsrightafter[0] << " "
<< numsrightafter[1] << endl;
//read in the RNG state that was saved, back into the RNG, restoring the state
//to be such as it was prior to the most recent two calls to randgen()
std::ifstream rngfilein("test_rngfile.txt", ifstream::in);
if(!rngfilein.good())
{
cout << "Couldn't read from file\n";
return 0;
}
rngfilein >> randgen;
rngfilein.close();
//declare and initialize a new variate generator to the newly-restored generator
boost::uniform_01<base_generator_type> getrand2(randgen);
// boost::variate_generator<base_generator_type,
// boost::normal_distribution<float> > getrand2(randgen, noise);
//copy the new variate function into the old one, to allow us to use
//the old one on the restored generator
getrand = getrand2;
//generate the next sequence
//The first two should be the same as the most recent two called
//The next two should be new random numbers
numsnew[0] = getrand();
numsnew[1] = getrand();
numsnew[2] = getrand();
numsnew[3] = getrand();
cout << "Restored, Next: "
<< numsnew[0] << " "
<< numsnew[1] << " "
<< numsnew[2] << " "
<< numsnew[3] << endl;
The output for a given time seed is:
First Sequence, before save: 0.970021 0.266862
Next, right after save: 0.110485 0.267466
Restored, Next: 0.970021 0.266862 0.110485 0.267466
The code's comments illustrate what I think should be happening. Also, some lines include commented code to do the same test with a different generator and different distribution. The same problem occurs for any of those: the next two values taken from the generator randgen after the state has been restored are not the same as the two that are generated immediately after the save, as they should be.
Upon closer inspection (debugging), it appears that calls to the variate generator getrand() do not change the state of the generator randgen at all no matter how many times I call getrand() on it, and so when I save it, it remains the same as if it were just created, and thus, when I pull from it again after restoration, it just starts from the beginning.
Shouldn't each call to the generator cause the state to advance? How am I even getting sequences that are not the same numbers if the RNG state never changes? Is the generator I'm viewing/saving not the "real" one, or something?
Also, the assignment operation of getrand = getrand2 might look sketchy but the = operator is defined for those,and replacing the last 4 calls with getrand2() doesn't make a difference.
Is the generator I'm viewing/saving not the "real" one, or something?
That is indeed the case. The uniform_01 constructor you're using actually makes a copy of the provided engine, rather than taking a reference.
If you're using Boost 1.39 or later, you can use it like this instead:
boost::uniform_01<> getrand;
getrand(randgen);
If you're stuck on an older Boost and you don't need getrand to be copyable, changing uniform_01's type parameter from base_generator_type to base_generator_type& should also work.

Print array length for each element of an array

Given a string array of variable length, print the lengths of each element in the array.
For example, given:
string[] ex = {"abc", "adf", "df", "ergd", "adfdfd");
The output should be:
2 3 4 6
One possibility I'm considering is to use a linked list to save each string length, and sort while inserting and finally display the results.
Any other suggestions for efficient solutions to this problem?
Whenever you want to maintain a collection of distinct things (ie: filter out duplicates), you probably want a set.
There are many different data structures for storing sets. Some of these, like search trees, will also "sort" the values for you. You could try using one of the many forms of binary search trees.
What you are doing now (or the given answer) is called the insertion sort. It basically compare the length of the string-to-insert from the inserted strings. After then, when printing, teh length of string-to-print (at current pointer) will be compared to the length of the string before it and after it, if has the same length, do not print!
Another approach is, the bubble sort, it will sort two strings at a time, sort them, then move to next string...
The printing is the most important part in your program, regardless of what sorting algorithm you use, it doesn't matter.
Here's an algorithm for bubble sort and printing process, it's VB so just convert it...
Dim YourString(4) As String
YourString(0) = "12345" 'Will not be printed
YourString(1) = "12345" 'Will not be printed
YourString(2) = "123" 'Will be printed
YourString(3) = "1234" 'Will be printed
Dim RoundLimit As Integer = YourString.Length - 2
'Outer loop for how many times we will sort the whole array...
For CycleCounter = 0 To RoundLimit
Dim CompareCounter As Integer
'Inner loop to compare strings...
For CompareCounter = 0 To RoundLimit - CycleCounter - 1
'Compare lengths... If the first is greater, sort! Note: this is ascending
If YourString(CompareCounter).Length > YourString(CompareCounter + 1).Length Then
'Sorting process...
Dim TempString = YourString(CompareCounter)
YourString(CompareCounter) = YourString(CompareCounter + 1)
YourString(CompareCounter + 1) = TempString
End If
Next
Next
'Cycles = Array length - 2 , so we have 2 cycles here
'First Cycle!!!
'"12345","12345","123","1234" Compare 1: index 0 and 1 no changes
'"12345","123","12345","1234" Compare 2: index 1 and 2 changed
'"12345","123","1234","12345" Compare 3: index 2 and 3 changed
'Second Cycle!!!
'"123","12345","1234","12345" Compare 1: index 0 and 1 changed
'"123","1234","12345","12345" Compare 2: index 1 and 2 changed
'"123","1234","12345","12345" Compare 3: index 2 and 3 no changes
'No more cycle!
'Now print it! Or use messagebox...
Dim CompareLimit As Integer = YourString.Length - 2
For CycleCounter = 0 To CompareLimit
'If length is equal to next string or the preceeding string, do not print...
If ((CycleCounter - 1) <> -1) Then 'Check if index exist
If YourString(CycleCounter).Length = YourString(CycleCounter - 1).Length Then
Continue For 'The length is not unique, exit compare, go to next iteration...
End If
End If
If ((CycleCounter + 1) <> YourString.Length - 1) Then 'Check if index exist
If YourString(CycleCounter).Length = YourString(CycleCounter + 1).Length Then
Continue For 'The length is not unique, exit compare, go to next iteration...
End If
End If
'All test passed, the length is unique, show a dialog!
MsgBox(YourString(CycleCounter))
Next
The question as stated doesn't say anything about sorting or removing duplicates from the results. It is only the given output that implies the sorting and duplicate removal. It doesn't say anything about optimisation for speed or space or writing for maintainability.
So there really isn't enough information for a "best" solution.
If you want a solution that will work in most languages you probably should stick with an array. Put the lengths in a new array, sort it, then print in a loop that remembers that last value to skip duplicates. I wouldn't want to use a language that couldn't cope with that.
If a language is specified you might be able to take advantage of set or associate array type data structures to handle the duplicates and/or sorting automatically. E.g., in Java you could pick a collection class that automatically ignores duplicates and sorts, and you could structure your code such that a one line change to use a different class would let you keep duplicates, or not sort. If you are using C# you could probably write the whole thing as a one-line LINQ statement...
Here is a C++ solution:
#include <set>
#include <vector>
#include <string>
#include <iostream>
using namespace std;
int main()
{
string strarr[] = {"abc", "adf", "df", "ergd", "adfsgf"};
vector< string > vstr(strarr, strarr + 5);
set< size_t > s;
for (size_t i = 0; i < vstr.size(); i++)
{
s.insert( vstr[i].size() );
}
for (set<size_t>::iterator ii = s.begin(); ii != s.end(); ii++)
cout << *ii << " ";
cout << endl;
return 0;
}
Output:
$ g++ -o set-str set-str.cpp
$ ./set-str
2 3 4 6
A set is used because (quoting from here):
Sets are a kind of associative container that stores unique elements,
and in which the elements themselves are the keys.
Associative containers are containers especially designed to be
efficient accessing its elements by their key (unlike sequence
containers, which are more efficient accessing elements by their
relative or absolute position).
Internally, the elements in a set are always sorted from lower to
higher following a specific strict weak ordering criterion set on
container construction.
Sets are typically implemented as binary search trees.
And for details on vector see here and here for string.
Depending on the language, the easiest way might be to iterate through the array using a for loop
for (i=0;i<array.length;i++){
print array[i].length;
}
do you need to print them in order?

Resources