I have stl vector consisting of several elements. I need to iterate through this vector and delete elements which meets some criteria. So I wrote this code
for (int j = imageDataVector.size()-1; j >= 0; j--) {
if(imageDataVector[i] < threshold)
imageDataVector.erase(imageDataVector.end() - j);
}
This code works fine for almost all cases, however if all elements of vector meets the criteria I get an error:
vector erase iterator outside the range
This error occurs if I have only one element left in the vector. What do I do wrong ?
if(imageDataVector[i] < threshold)
imageDataVector.erase(imageDataVector.end()-j);
Should likely be:
if(imageDataVector[j] < threshold)
imageDataVector.erase(imageDataVector.begin()+j);
EDIT: for completeness, the erase-remove way and the iterator way:
imageDataVector.erase(std::remove_if(imageDataVector.begin(), imageDataVector.end(), std::bind2nd(std::less<vector_data_type>(), threshold)), imageDataVector.end());
vector<type>::iterator it = imageDataVector.begin();
while (it != imageDataVector.end()) {
if (*it < threshold)
it = imageDataVector.erase(it);
else
++it;
}
You're mixing forward and backward indexing.
I'd consider using std::remove_if instead. That way if you're removing multiple elements you don't shift the entire vector forwards on each erase.
It would look something like this:
imageDataVector.erase(std::remove_if(imageDataVector.begin(), imageDataVector.end(), std::bind2nd(std::less<data_type>(), threshold)), imageDataVector.end());
Alternately try the following, noting that it will result in a lot of movement if you remove multiple items from the vector.
for (int j=imageDataVector.size()-1 ;j>=0;j--)
{
if(imageDataVector[i] < threshold)
imageDataVector.erase(imageDataVector.begin()+j);
}
You're trying to count down j to zero, and imageDataVector.end() - 0 is not a valid iterator. In the standard C++ library containers, the end iterator points one past the last element, not at the last element.
Related
I initially thought up some sorting algorithm to code in C++ for practice. People told me it's very inefficient (indeed, sorting a few hundred numbers took ~10 seconds). The algorithm was to remember the first element ("pivot") in a vector, then parse through every other element, moving each element to the left of the pivot if it is smaller, or not do anything otherwise. This would split the list into to smaller lists to sort; the rest is done through recursion.
So now I know that dividing the list into two and doing recursions like this is essentially what quicksorting does (although there are a lot of variations on how to do the partitioning). I didn't understand why my original code was so inefficient, so I wrote up a new one. Someone had mentioned that it is because of the insert() and erase() functions, so I made sure to not use those, but instead used swap().
Old (slow):
void sort(vector<T>& vec){
int size = vec.size();
if (size <= 1){ //this is the most basic case
return;
}
T pivot = vec[0];
int index = 0; //to help split the list later
for (int i = 1; i < size; ++i){ //moving (or not moving) the elements
if (vec[i] < pivot){
vec.insert(vec.begin(), vec[i]);
vec.erase(vec.begin() + i + 1);
++index;
}
}
if (index == 0){ //in case the 0th element is the smallest
vec.erase(vec.begin());
sort(vec);
vec.insert(vec.begin(), pivot);
}
else if(index == size - 1){ //in case the 0th element is the largest
vec.pop_back();
sort(vec);
vec.push_back(pivot);
}
//here is the main recursive portion
vector<T> left = vector<T>(vec.begin(), vec.begin() + index);
sort(left);
vector<T> right = vector<T>(vec.begin() + index + 1, vec.end());
sort(right);
//concatenating the sorted lists together
left.push_back(pivot);
left.insert(left.end(), right.begin(), right.end());
vec = left;
}
new (fast):
template <typename T>
void quickSort(vector<T>& vec, const int& left, const int& right){
if (left >= right){ //basic case
return;
}
T pivot = vec[left];
int j = left; //j will be the final index of the pivot before the next iteration
for (int i = left + 1; i <= right; ++i){
if (vec[i] < pivot){
swap(vec[i], vec[j]); //swapping the pivot and lesser element
++j;
swap(vec[i], vec[j]); //sending the pivot next to its original spot so it doesn't go the to right of any greater element
}
}
//recursion
quickSort(vec, left, j - 1);
quickSort(vec, j + 1, right);
}
The difference in performance is insane; the newer version can sort through tens of thousands of numbers in less than a second, while the first one can't do that with 100 numbers. What are erase() and insert() doing to slow it down, exactly? Is it really the erase() and insert() causing the bottleneck, or is there something else I am missing?
First of all, yes, insert() and erase() will be much slower than swap().
insert() will, in the best case, require every element after the spot where you're inserting into the vector to be moved to the next spot in the vector. Think about what happens if you shove yourself into the middle of a crowded line of people - everyone behind you will have to take one step back to make room for you. In the worst case, because inserting into the vector increases the vector's size, the vector may run out of space in its current memory location, leading to the entire vector (element by element) being copied into a new space where it has room to accommodate the newly inserted item. When an element in the middle of a vector is erase()'d, every element after it must be copied and moved up one space; just like how everyone behind you in a line would take one step up if you left said line. In comparison, swap() only moves the two elements being swapped.
In addition to that, I also noticed another major efficiency improvement between the two code samples:
In the first code sample, you have:
vector<T> left = vector<T>(vec.begin(), vec.begin() + index);
sort(left);
vector<T> right = vector<T>(vec.begin() + index + 1, vec.end());
sort(right);
which uses the range constructor of C++ vectors. Every time the code reaches this point, when it creates left and right, it is traversing the entirety of vec and copying each element one-by-one into the two new vectors.
In the newer, faster code, none of the elements are ever copied into a new vector; the entire algorithm takes place in the exact memory space in which the original numbers existed.
Vectors are arrays, so inserting and deleting elements in places other than the end position is done by relocate all the elements that were after position to their new positions.
Create a function that checks whether an array has two opposite elements or not for less than n^2 complexity. Let's work with numbers.
Obviously the easiest way would be:
bool opposite(int* arr, int n) // n - array length
{
for(int i = 0; i < n; ++i)
{
for(int j = 0; j < n; ++j)
{
if(arr[i] == - arr[j])
return true;
}
}
return false;
}
I would like to ask if any of you guys can think of an algorithm that has a complexity less than n^2.
My first idea was the following:
1) sort array ( algorithm with worst case complexity: n.log(n) )
2) create two new arrays, filled with negative and positive numbers from the original array
( so far we've got -> n.log(n) + n + n = n.log(n))
3) ... compare somehow the two new arrays to determine if they have opposite numbers
I'm not pretty sure my ideas are correct, but I'm opened to suggestions.
An important alternative solution is as follows. Sort the array. Create two pointers, one initially pointing to the front (smallest), one initially pointing to the back (largest). If the sum of the two pointed-to elements is zero, you're done. If it is larger than zero, then decrement the back pointer. If it is smaller than zero, then increment the front pointer. Continue until the two pointers meet.
This solution is often the one people are looking for; often they'll explicitly rule out hash tables and trees by saying you only have O(1) extra space.
I would use an std::unordered_set and check to see if the opposite of the number already exist in the set. if not insert it into the set and check the next element.
std::vector<int> foo = {-10,12,13,14,10,-20,5,6,7,20,30,1,2,3,4,9,-30};
std::unordered_set<int> res;
for (auto e : foo)
{
if(res.count(-e) > 0)
std::cout << -e << " already exist\n";
else
res.insert(e);
}
Output:
opposite of 10 alrready exist
opposite of 20 alrready exist
opposite of -30 alrready exist
Live Example
Let's see that you can simply add all of elements to the unordered_set and when you are adding x check if you are in this set -x. The complexity of this solution is O(n). (as #Hurkyl said, thanks)
UPDATE: Second idea is: Sort the elements and then for all of the elements check (using binary search algorithm) if the opposite element exists.
You can do this in O(n log n) with a Red Black tree.
t := empty tree
for each e in A[1..n]
if (-e) is in t:
return true
insert e into t
return false
In C++, you wouldn't implement a Red Black tree for this purpose however. You'd use std::set, because it guarantees O(log n) search and insertion.
std::set<int> s;
for (auto e : A) {
if (s.count(-e) > 0) {
return true;
}
s.insert(e);
}
return false;
As Hurkyl mentioned, you could do better by just using std::unordered_set, which is a hashtable. This gives you O(1) search and insertion in the average case, but O(n) for both operations in the worst case. The total complexity of the solution in the average case would be O(n).
I'm trying to iterate a vector from the nth element onwards. Not sure how should i go about doing this.
I have a vector A and B. My vector A has 10 elements of PC1-PC10 and my vector B has 20 elements of User1-User20.
So what I want to do is that when both my vector A and B reaches the 10th element, meaning to say the last element for vector A, I want to repeat iterating vector A but start iterating vector B from the 11th element so that I can do some stuff with it.
Below is the simplified code that I came up with but technically its about the same thing:
vector<string>::iterator b = vecB.begin();
for (int i = 1; i < 2; i++) {
for (vector<string>::iterator a = vecA.begin(); a != vecA.end() ; a++) {
if (a == vecA.end()) {
b = vecB.begin() + 10; //here the iterator for verB should start from the 11th element
}
++b
}
}
Should I mess with the iterator for vector B? Or is there another alternative?
EDIT
It seems that I have been asking the wrong question after all. I have marked the answer to this question and will be posting another shortly. Thanks for the quick response to my question!
The if condition inside the nested loop will never be true, because it conflicts with the loop condition:
for (vector<string>::iterator a = vecA.begin(); a != vecA.end() ; a++) {
// This check ----------------------------------^^^^^^^^^^^^^^^
// guarantees that this will never succeed:
// vvvvvvvvvvvvvvv
if (a == vecA.end()) {
...
}
}
You should rewrite the code like this:
vector<string>::iterator b = vecB.begin();
// Check that vecB has sufficient number of elements before entering the loop.
for (int i = 1 ; i < 2 ; i++) {
for (vector<string>::iterator a = vecA.begin(); a != vecA.end() ; ++a, ++b) {
...
}
// At this point we know for sure that a == vecA.end(),
// because it is a post-condition of the for loop above.
b = std::next(vecB.begin(), 11);
}
The call of ++b can be moved into the loop header.
Note the use of std::next: although
b = vecB.begin() + 10;
compiles for vectors, it is not guaranteed for all kinds of containers. Use std::next instead:
b = std::next(vecB.begin(), 11);
Note: This code makes an assumption that vecB has at least 11 elements more than vecA does. This may be OK if you check that assumption before entering the loop. If this assumption is broken, the code would have undefined behavior.
Others have already answered how to reset or advance an iterator, so I'll just answer, how to solve your problem in a simpler way. It's much simpler to iterate two vectors in parallel using the index rather than two iterators:
// assumes vecB is bigger than vecA as described in the question
for (std::size_t i = 0; i < vecB.size(); i++) {
auto user = vecB[i];
auto pc = vecA[i % vecA.size()];
}
Pay attention to how the smaller vector is iterated using the remainder operator.
In addition to using std::next, as shown in the answer by #dasblinkenlight, you can also use std::advance.
b = vecB.begin();
std::advance(b, 10);
You don't need to change the iterator for B, it will automatically continue with 11th element. But you need to restart iteration on A at the beginning of the for loop (or you would work with a.end() which is not a valid element):
if (a == vecA.end()) {
a = vecA.begin();
}
Also you should iterate over both but check for end on b only; if you check on a, the for would end before the if would turn true:
for (auto a = vecA.begin(), b = vecB.begin(); b != vecB.end(); ++a, ++b)
You can see the whole code here.
I actually prefer to manually iterate over vectors pre-C++11 because it looks way cleaner and more readable than iterators:
for (unsigned int i = 0; i < my_vector.size(); i++) {
my_vector[i]; //Do Something
}
You can specify the range you want to iterate over simply by modifying the for loop conditional (i.e. unsigned int i = n)
Edit: Before downvoting actually read my entire answer. Using iterators on vectors is overly verbose and makes your code virtually unreadable. If there is a legitimate reason this method should not be used in favor of iterators, then please leave a comment.
Most people aren't looking for an ultra-generic, drop-in-any-container solution. Most people know they need a dynamic list, vector fits the bill, so why not make your code easy to read for the next guy?
I have some code and an array where each iteration I delete the first element, add an element at the end, and then sum the contents of the array. Naturally, the array stays the same size. I have tried using both vector and list, but both seem pretty slow.
int length = 400;
vector <int> v_int(length, z);
list <int> l_int(length, z);
for(int q=0; q < x; q++)
{
int sum =0;
if(y) //if using vector
{
v_int.erase(v_int.begin()); //takes `length` amount of time to shift memory
v_int.push_back(z);
for(int w=0; w < v_int.size(); w++)
sum += v_int[w];
}
else //if using list
{
l_int.pop_front(); //constant time
l_int.push_back(z);
list<int>::iterator it;
for ( it=l_int.begin() ; it != l_int.end(); it++ ) //seems to take much
sum += *it; //longer than vector does
}
}
The problem is that erasing the first element of the vector requires that each other element be shifted down, multiplying, by the size of the vector, the amount of time taken each iteration. Using a linked list avoids this (constant time removal of elements), and should not sacrifice any time summing the array (linear time traversal of the array), except that in my program it seems to be taking way longer to sum the contents than the vector does (at least 1 order of magnitude longer).
Is there a better container to use here? or a different way to approach the problem?
Why not keep a running sum with sum -= l_int.front(); sum += z?
Also the data structure you're looking for with that delete/insert performance is a queue
Efficient additions and deletions of end elements in a container is what the deque was made for.
If you are just inserting at one end and deleting at the other then you can use a queue
std::next_permutation (and std::prev_permutation) permute all values in the range [first, last) given for a total of n! permutations (assuming that all elements are unique).
is it possible to write a function like this:
template<class Iter>
bool next_permutation(Iter first, Iter last, Iter choice_last);
That permutes the elements in the range [first, last) but only chooses elements in the range [first, choice_last). ie we have maybe 20 elements and want to iterate through all permutations of 10 choices of them, 20 P 10 options vs 20 P 20.
Iter is a random access iterator for my purposes, but if it can be implemented as a bidirectional iterator, then great!
The less amount of external memory needed the better, but for my purposes it doesn't matter.
The chosen elements on each iteration are input to the first elements of the sequence.
Is such a function possible to implement? Does anyone know of any existing implementations?
Here is essentially what I am doing to hack around this. Suggestions on how to improve this are also welcome.
Start with a vector V of N elements of which I want to visit each permutation of R elements chosen from it (R <= N).
Build a vector I of length R with values { 0, 1, 2, ... R - 1 } to serve as an index to the elements of V
On each iteration, build a vector C of length R with values { V[I[0]], V[I[1]], ... V[I[R - 1]] }
Do something with the values in C.
Apply a function to permute the elements of I and iterate again if it was able to.
That function looks like this:
bool NextPermutationIndices(std::vector<int> &I, int N)
{
const int R = I.size();
for (int i = R - 1; ; --i) {
if (I[i] < N - R + i) {
++I[i];
return true;
}
if (i == 0)
return false;
if (I[i] > I[i-1] + 1) {
++I[i-1];
for (int j = i; j < R; ++j)
I[j] = I[j-1] + 1;
return true;
}
}
}
That function is very complicated due to all the possible off-by-one errors, as well everything using it are more complicated than is probably necessary.
EDIT:
It turns out that it was significantly easier than I had even imagined. From here, I was able to find exact implementations of many of the exact algorithms I needed (combinations, permutations, etc.).
template<class BidirectionalIterator>
bool next_partial_permutation(BidirectionalIterator first,
BidirectionalIterator middle,
BidirectionalIterator last)
{
std::reverse(middle, last);
return std::next_permutation(first, last);
}
Plus there is a combination algorithm there that works in a similar way. The implementation of that is much more complication though.
To iterate over nPk permutations, I've used the for_each_permutation() algorithm presented in this old CUJ article before. It uses a nice algorithm from Knuth which rotates the elements in situ, leaving them in the original order at the end. Therefore, it meets your no external memory requirement. It also works for BidirectionalIterators. It doesn't meet your requirement of looking like next_permutation(). However, I think this is a win - I don't like stateful APIs.
Source code for a Java combination generator is at http://www.merriampark.com/comb.htm. Strip out the Java idioms, and it's almost exactly what you're looking for, implemented as a generator to keep a lid on your memory usage.
This problem is from the mathematical field known as Combinatorics, which is part of Discrete mathematics. Discrete math is crucial to practitioners of computer science, as it includes nearly all of the math we use daily (like logic, algorithms, counting, relations, graph theory, etc.). I highly recommend Discrete and Combinatorial Mathematics: An applied introduction or
Discrete Mathematics and Its Applications, if you can afford it.
(Note: this question is related to "Algorithm for Grouping," but not quite a duplicate since this question asks to solve it in the general case.)
An algorithmic simplification would be to split this into two separate steps.
Generate a list of all possible selections of R elements out of the original data.
For each of those selections, create all possible permutations of the selected elements.
By interleaving those operations, you can avoid allocating the intermediate lists.
Selection can be implemented on a bidirectional iterator by skipping over non-selected items. Generate all selections, e.g. by permuting a sequence of R ones and (N-R) zeroes. This will need O(N) additional memory, but enables you to permute the original sequence in place.
For what its worth, here is an implementation that sort of works.
It requires that the elements above choice start in sorted order. It only works if there are no duplicate elements in the sequence (if there are, it misses some permutations, and doesn't end in the correct perumtation). It also might be missing some edge cases as I didn't really test it thoroughly as I have no plans on actually using it.
One benefit of this way over this answer's, is that way doesn't visit permutations in lexicographical order, which may (but probably not) be important. It also is kind of a pain to use boost::bind sometimes to create a functor to pass to for_each.
template<class Iter>
bool next_choice_permutation(Iter first, Iter choice, Iter last)
{
if (first == choice)
return false;
Iter i = choice;
--i;
if (*i < *choice) {
std::rotate(i, choice, last);
return true;
}
while (i != first) {
Iter j = i;
++j;
std::rotate(i, j, last);
--i;
--j;
for (; j != last; ++j) {
if (*i < *j)
break;
}
if (j != last) {
std::iter_swap(i, j);
return true;
}
}
std::rotate(first, ++Iter(first), last);
return false;
}