Question is quite simple, how do I print a deque, but from behind. Example: I have a deque with elements {5,4,3,2,1}. I want to print that deque, but starting from the last element, so I should have someting like 1 2 3 4 5 on my screen.
Usual for(int i(deque.size()); i > 0; i--) loop obviously won't work.
Little intro to the program. It finds numbers whose sum is even or odd, and sorts them into two different deques that are to be printed on screen.
This is the code that works for 'usual' printing. But my task says to print them backwards.
Oh, and the elements are added to the deque using push_front function. And no, I'm not allowed to use push_back to 'fix' it.
void PrintDek(Dek v4) {
for (int i(0); i < v4.size(); i++) {
std::cout << v4[i];
if (i != v4.size() - 1) std::cout << ",";
}
}
If some of you feel the need for the whole program's code, I'll edit my post.
You can use reverse iterators. See http://en.cppreference.com/w/cpp/container/deque/rbegin.
for(auto iter = deque.rbegin(); iter != deque.rend(); ++iter) {
// do stuff
}
So after seeing my code after a good few hours of sleep (this question was posted after 2AM according to my timezone), I've come to realize what my mistake was. By using deque.size() and moving all the way up to the value that the size() function returns, I was actually going out of range, accessing forbidden parts of memory.
Simple deque.size()-1 now works. So the loop would look like this for(int i(deque.size()-1); i >= 0; i--).
Related
So here's my problem.. I have a 2d array of 2 char strings.
9D 5C 6S 9D KS 4S 9D
9S
If 3 found I need to delete the first 3 based on the first char.
card
My problem is I segfault almost anything i do...
pool is the 2d vector
selection = "9S";
while(col != GameBoard::pool.size() ){
while(GameBoard::pool[col][0].at(0) == selection.at(0) || cardsRem!=0){
if(GameBoard::pool[col].size() == 1){
GameBoard::pool.erase(GameBoard::pool.begin() + col);
cardsRem--;
}
else{
GameBoard::pool[col].pop_back();
cardsRem--;
}
}
if(GameBoard::pool[col][0].at(0) != selection.at(0)){
col++;
}
}
I've tried a series of for loops etc, and no luck! Any thoughts would save my sanity!
So I've tried to pull out a code segment to replicate it. But I can't...
If I run my whole program in a loop it will eventually throw a segfault. If I run that exact code in the same circumstance it doesn't... I'm trying to figure out what I'm missing. I'll get back in if I figure out exactly where my issue is..
So in the end the issue is not my code itself, i've got memory leaks or something somewhere that are adding up to eventually crash my program... That tends to be in the same method each time I guess.
The safer and most efficient way to erase some elements from a container is to apply the erase-remove idiom.
For instance, your snippet can be rewritten as the following (which is testable here):
using card_t = std::string;
std::vector<std::vector<card_t>> decks = {
{"9D", "5C", "6S", "9D", "KS", "4S", "9D"},
{"9S"}
};
card_t selection{"9S"};
// Predicate specifing which cards should be removed
auto has_same_rank = [rank = selection.at(0)] (card_t const& card) {
return card.at(0) == rank;
};
auto & deck = decks.at(0);
// 'std::remove_if' removes all the elements satisfying the predicate from the range
// by moving the elements that are not to be removed at the beginning of the range
// and returns a past-the-end iterator for the new end of the range.
// 'std::vector::erase' removes from the vector the elements from the iterator
// returned by 'std::remove_if' up to the end iterator. Note that it invalidates
// iterators and references at or after the point of the erase, including the
// end() iterator (it's the most common cause of errors in code like OP's).
deck.erase(std::remove_if(deck.begin(), deck.end(), has_same_rank),
deck.end());
So for anyone else in the future who comes across this...
The problem is I was deleting an element in the array in a loop, with the conditional stop was it's size. The size is set before hand, and while it was accounted for in the code it still left open the possibility for while(array.size() ) which would be locked in at 8 in the loop be treated as 6 in the code.
The solution was to save the location in the vector to delete and then delete them outside of the loop. I imagine there is a better, more technical answer to this, but it works as intended now!
for (double col = 0; col < size; ++col)
{
if(GameBoard::pool[col][0].at(0) == selection.at(0)){
while(GameBoard::pool[col][0].at(0) == selection.at(0) && cardsRem !=0){
if( GameBoard::pool[col].size() > 1 ){
GameBoard::pool[col].pop_back();
cardsRem--;
}
if(GameBoard::pool[col].size() <2){
toDel.insert ( toDel.begin() , col );
//GameBoard::pool.erase(GameBoard::pool.begin() + col);
cardsRem--;
size--;
}
}
}
}
for(int i = 0; i< toDel.size(); i++){
GameBoard::pool.erase(GameBoard::pool.begin() + toDel[i]);
}
I want to run a loop on a std::vector<std::vector<int>> array to delete desired elements.
I'm using for (i = 0; i < array.size(); i++)
is it safe to invoke array.erase() from within the loop?
In my head I assume for checks array.size() at every iteration, but maybe it only does it once at initiation. If it did, for (i = 0; i < &array.size(); i++) would work a fine solution, would it not?
Thank you.
is it safe to invoke array.erase() from within the loop?
Yes, it is perfectly safe. Compiler is allowed to optimize the check by calling array.size() only once out of the loop only if it can prove that vector is not modified inside the loop, e,g, if the vector is constant and thus not modifiable. In that case optimizing that way won't change observable behavior. But since you are calling erase inside the loop compiler is not allowed to call array.size() only once.
In general, an implementation is allowed to do only those code transformations that do not change observable behavior. This is called as-if rule.
I'm using for (i = 0; i < array.size(); i++)
is it safe to invoke array.erase() from within the loop?
It is safe but it is going throw your iteration logic off.
Let's say you have {1 2 3 4 5} in array.
You removed 2 from the array. At that time, i is 1. After removing 2, array is now {1 3 4 5}. You increment i in the for statement, which makes i 2. You will end up accessing 4 from the array in the loop, which skips 3 altogether.
In my head I assume for checks array.size() at every iteration, but maybe it only does it once at initiation.
No, it does that check in every iteration of the loop.
If it did, for (i = 0; i < &array.size(); i++) would work a fine solution, would it not?
Not sure where you got that idea but it's wrong. Don't even go there.
You can use:
for ( i = 0; i < array.size(); /* Don't increment here */ )
{
// Code
// Check for erase.
if ( check-for-erase-logic )
{
// Erase item
// Don't increment iteration counter.
}
else
{
// Increment iteration counter.
++i;
}
}
i < array.size() is the condition part of the for statement which is evaluated before each iteration, and if it yields false, the loop is exited. This answers the question in your title.
However, erase will invalidate iterators. So you should be careful. It is better to use algorithms to achieve this. One way would be the remove/erase idiom.
In contrast to a range for loop aka for (T element : container), in normal loops the condition is checked every time. So yes your normal for loop is safe.
However be aware of iterator, references and pointer invalidation after erase, and also that your i could be outside of the new range after the erase
Here some do's and dont's
#include <iostream>
#include <vector>
int main() {
using T = std::vector<int>;
std::vector<T> vector{{3,4},{3,5},{5,9}};
for (size_t i = 0; i < vector.size(); ++i) {
auto &vec2 = vector.at(2);
if (i == 2) {
vector.erase(vector.begin() + 1); //fine}
}
auto &v = vector[i]; //NOT FINE UNDEFINED BEHAVIOUR!
if (i < vector.size()) //Could be optimized out by compiler because of UB!, when compiling with line above,
// as the for check
break;
std::cout << vec2.at(1); //Also UNdefined behaviour since many things are invalidated after erase
}
for (auto v : vector) {
vector.erase(vector.begin()); //Also NOT ALLOWED since for ranges are allowed to cache iterators
}
}
Given a vector of integers, I want to wrote a fast (not obvious O(n^2)) algorithm to remove all odd elements from it.
My idea is: iterate through vector till first odd element, then copy everything before it to the end of vector (call push_back method) and so on until we have looked through all original elements (except copied ones), then remove all of them, so that only the vector's tail survive.
I wrote the following code to implement it:
void RemoveOdd(std::vector<int> *data) {
size_t i = 0, j, start, end;
uint l = (*data).size();
start = 0;
for (i = 0; i < l; ++i)
{
if ((*data)[i] % 2 != 0)
{
end = i;
for (j = start, j < end, ++j)
{
(*data).push_back((*data)[j]);
}
start = i + 1;
}
}
(*data).erase((*data).begin(), i);
}
but it gives me lots of errors, which I can't fix. I'm very new to the programming, so expect that all of them are elementary and stupid.
Please help me with error corrections or another algorithm implementation. Any suggestions and explanations will be very appreciative. It is also better not to use algorithm library.
You can use the remove-erase idiom.
data.erase(std::remove_if(data.begin(), data.end(),
[](int item) { return item % 2 != 0; }), data.end());
You don't really need to push_back anything (or erase elements at the front, which requires repositioning all that follows) to remove elements according to a predicate... Try to understand the "classic" inplace removal algorithm (which ultimately is how std::remove_if is generally implemented):
void RemoveOdd(std::vector<int> & data) {
int rp = 0, wp = 0, sz = data.size();
for(; rp<sz; ++rp) {
if(data[rp] % 2 == 0) {
// if the element is a keeper, write it in the "write pointer" position
data[wp] = data[rp];
// increment so that next good element won't overwrite this
wp++;
}
}
// shrink to include only the good elements
data.resize(wp);
}
rp is the "read" pointer - it's the index to the current element; wp is the "write" pointer - it always points to the location where we'll write the next "good" element, which is also the "current length" of the "new" vector. Every time we have a good element we copy it in the write position and increment the write pointer. Given that wp <= rp always (as rp is incremented once at each iteration, and wp at most once per iteration), you are always overwriting either an element with itself (so no harm is done), or an element that has already been examined and either has been moved to its correct final position, or had to be discarded anyway.
This version is done with specific types (vector<int>), a specific predicate, with indexes and with "regular" (non-move) assignment, but can be easily generalized to any container with forward iterators (as its done in std::remove_if) and erase.
Even if the generic standard library algorithm works well in most cases, this is still an important algorithm to keep in mind, there are often cases where the generic library version isn't sufficient and knowing the underlying idea is useful to implement your own version.
Given pure algorithm implementation, you don't need to push back elements. In worst case scenario, you will do more than n^2 copy. (All odd data)
Keep two pointers: one for iterating (i), and one for placing. Iterate on all vector (i++), and if *data[I] is even, write it to *data[placed] and increment placed. At the end, reduce length to placed, all elements after are unecessary
remove_if does this for you ;)
void DeleteOdd(std::vector<int> & m_vec) {
int i= 0;
for(i= 0; i< m_vec.size(); ++i) {
if(m_vec[i] & 0x01)
{
m_vec.erase(m_vec.begin()+i);
i--;
}
}
m_vec.resize(i);
}
I am having difficulty understanding why the code is behaving this way. First of all I have read the relevant answered material and still found the explanations abit advanced. So I'm wondering if some-one could explain this in a simple fashion.
Ok, so I am erasing elements from a list.
The list contains int elements that are both odd and even numbers. This part I understand.
Here is the code I originally wrote to remove the odd numbers from the list
for(list<int>::iterator i = lNo.begin(); i != lNo.end(); i++)
{
if(*i%2 == 0 )
{
lNo.erase(i);
}
else
{
cout << " " << *i;
}
}
With this code, the program simply does not compile, and I read a message stating that the program has to shut down.
The erase function works when I write this code:
for(list<int>::iterator i = lNo.begin(); i != lNo.end(); i++)
{
if(*i%2 == 0 )
{
i = lNo.erase(i);
}
else
{
cout << " " << *i;
}
}
I just need to uderstand why the program works when I code i = lNo.erase(i) and not with just lNo.erase(i)?
A simple concise answer would be much appreciated.
I know that different containers have different constraints, so which constraint did I violate with the original piece of code?.
As stated in the documentation, the erase function invalidates the iterator passed in. That means it cannot be used again. The loop cannot proceed with that iterator.
The documentation also states that it returns an iterator to the element that was after the erased one. That iterator is valid and can be used to proceed.
Note however that since it returns an iterator to the element after the one that was erased, there is no need to increment that to advance, or that element will not be checked for oddness. The loop should catter for that and only increment when no erasure was done.
Even your second code is incorrect.
The correct code should be this:
for(list<int>::iterator i = lNo.begin(); i != lNo.end(); /*NOTHING HERE*/ )
{
if(*i%2 == 0 )
{
i = lNo.erase(i);
}
else
{
cout << " " << *i;
++i; //INCREMENT HERE, not in the for loop
}
}
Note that erase() erases the item and returns the iterator to the next item. That means, you don't need to increment i in your code when you erase; instead you just need to update i with the returned value from erase.
You could use erase-remove idiom as:
lNo.erase(std::remove_if(lNo.begin(),
lNo.end(),
[](int i) { return i%2 == 0; }),
lNo.end());
Live demo
The thing is that you're using an iterator that doesn't expect the chaining of your list to be modified.
So when you're calling erase() on your list, the chaining is effectively modified and so your iterator isn't valid anymore. The i++ statement doesn't work anymore.
But, in the 2nd version, you re-assign your iterator to valid object that still have the chaining intact, so the i++ statement can still work.
In some framework, you have 2 kinds of iterators, the kind that do reflect immediately what's happening to the underlying dataset (here is what you're using), and the kind that doesn't change their chaining whatever happening to the underlying dataset (so you don't have to use the weird trick of the 2nd version).
No doubt some of you have seen my recent posting, all regarding the same program. I keep running into problems with it. To reiterate: still learning, not very advanced, don't understand pointers very well, not taking a class, don't understand OOP concepts at all, etc. This code just merges two sorted vectors, farray and sarray, into a single sorted vector. At least, I hope that's what it does. Tell me:
//int num is to find the size of the original vector and
//build up farray and sarray; not used in the merge process
int num = original.size()
std::vector<int> final;
std::vector<int>::iterator it = farray.begin();
std::vector<int>::iterator iter = sarray.begin();
//farray.size() == (0 thru (num / 2))
//sarray.size() == ((num / 2) thru num)
for (;it != farray.end() && iter != sarray.end();) {
if (*it > *iter) {
final.push_back(*it);
it++;
}
else
{
final.push_back(*iter);
iter++;
}
if (it == farray.end()) {
for (int i = 0; iter < sarray.end(); i++) {
final.push_back(*iter);
}
}
if (iter == sarray.end()) {
for (int i = 0; it < farray.end(); i++) {
final.push_back(*iter);
}
}
}
I rewrote the merge part of my merge sort function so as to...well, make it work. I actually have several questions about this code:
Is it good form to compare against std::vector::iterators it && iter for my last two if statements if the for loop might change them on its next pass?
Will the values of iter and it change on this loop's last pass and screw up my code? Will putting my last if statements before the *it and *iter comparison?
Does the end() member function refer to the last value of whatever is calling it? It seems like it might extend past it somehow.
EDIT: I will respond to all replies tomorrow, so check back then if you want to hear more. It's past midnight. G'night.
1 . It's fine to compare iterators which are from the same container as a for loop condition, but this only makes sense if you are moving one or other iterators in either the increment part if the for loop statement or in the body of the for loop itself. In this for loop you compare iter against sarray.end() but the for loop never changes iter. This means that either there will be no iterations or the for loop will never terminate. Also, you probably want to use != and not < for the comparison. == and != work for all iterators, < doesn't.
for (int i = 0; iter != sarray.end(); i++) {
final.push_back(*iter);
}
As iter starts where you want the loop to begin, you may want something like this:
for (; iter != sarray.end(); ++iter) {
final.push_back(*iter);
}
As you're still learning (although aren't we all!), it's probably instructive to work through an algorithm like this, but you should be aware of std::merge which probably does what you want.
std::merge( farray.begin(), farray.end(), sarray.begin(), sarray.end(), std::back_inserter( final ) );
(You need to #include <iterator> and <algorithm>.)
2 . I don't see incrementing iter or it in the outer for loop invalidating the logic in the later for loops, the point in 1. aside.
3 . end() points to one past the end of a container, so you can use it for loop termination checks, but you shouldn't try to dereference an iterator which is "==" to ".end()".
I didn't check your algorithm's implementation, I will just refer to your three questions:
Iterators are much like pointers to values of a container. It's exactly like using size_t i and then ++i in the for loop. would you feel it's problematic to compare farray[i] with sarray[i]? probably not, therefore it's OK.
What I see you doing in your code here, is that you just read the values of *it and *iter, you don't actually change them, therefore they won't change.
The end() points to an invalid place. It doesn't point to the last value, but to "after it". It's like "NULL" if you will, therefore if(iter == sarray.end()) is true, you will crash if you will write *iter, because you can't dereference an iterator which is equal to end().
Some general advice: You need to think about variable names. Calling your iterators 'it' and 'iter' is going to confuse you at some point. Actually, if you look closely, it already has. If 'farray' and 'sarray' are meaningful names, how about 'fiter' and 'siter'.
Also, think through what the merge sort is doing. Those last two blocks are there just to "drain" whichever iterator has some stuff left. So they don't need to be in the first loop.
I'd probably write it as (pseudocode):
while not (list1.empty and list2.empty):
if list1.empty:
result.push(list2.pop)
else if list2.empty:
result.push(list1.pop)
else if list1.top > list2.top:
result.push(list2.pop)
else:
result.push(list1.pop)
Or in somewhat rusty cargo-culted C++:
std::vector<int>::iterator fiter = farray.begin();
std::vector<int>::iterator siter = sarray.begin();
while (fiter != farray.end() || siter != sarray.end()) {
if (fiter == farray.end()) final.push_back(*siter++);
else if (siter == sarray.end()) final.push_back(*fiter++);
else if (*fiter > *siter) final.push_back(*siter++);
else final.push_back(*siter++);
}
You have a few things to think about here.
First, if you are merging two ranges you would be much better off using the std::merge function rather that rolling your own.
Your code is a little difficult to read because you use varying styles for indentation and where you out your curly braces. Pick a style & stick to it.
The first part of your for loop seems to be a correct implementation of a merge:
for (;it != farray.end() && iter != sarray.end();) {
if (*it > *iter) {
final.push_back(*it);
it++;
}
else
{
final.push_back(*iter);
iter++;
}
...and this should be all you need to get the job done.
The second part of your loop has a couple problems:
for (;it != farray.end() && iter != sarray.end();) {
: :
if (it == farray.end()) {
for (int i = 0; iter < sarray.end(); i++) {
final.push_back(*iter);
}
}
if (iter == sarray.end()) {
for (int i = 0; it < farray.end(); i++) {
final.push_back(*iter);
}
}
}
For one thing, the for() conditionals are written so that both it and iter must not point to the end() of their respective collection, or else the loop ends. So it can never point to sarray.end(), iter can never point to farray.end(), and neither if statement can ever fire. They are both dead (unreachable) code.
But even if they weren't dead code, they have bugs. The conditional in the for(...) breaks the loop when the iterator points to the end of the collection, but this iterator is never moved, so you have an infinite loop.
Again both of these for(...)s are uneeded dead code because the iterators can never point to the end of the vector.
One simple comment: why not use while (condition) instead of for(; !condition; ).
The latter construction is nonstandard and hard to understand!