Reputation: 1197
I am making a program that solves this problem here: http://opc.iarcs.org.in/index.php/problems/BOOKLIST
and the only places i am using vectors are:
for(int i =0;i < total_books; i++){
int temp;
cin >> temp;
books_order.push_back(temp);
}
and
for(int i = 0;i < total_entries; i++){
int index;
cin >> index;
index--;
cout << books_order[index] << endl;
books_order.erase(books_order.begin()+index);
}
(here is my full code: http://cpaste.org/1377/)
The only functions i am using from vectors are vector::erase, vector::push_back and vector::begin. For large inputs my code take more time than 3 seconds(which is the time limit for that problem), but when i remove the vector function, it runs much faster(but gives a wrong answer ofcourse)
I understood that it is wrong using vectors in this problem and that my algorithm is very slow, but i did not understand why it is slow.
If you know why the functions i am using are slow please explain them to me. Thank you.
Upvotes: 6
Views: 3024
Reputation: 36777
IMO the culprit is vector::erase
as it will shift all the elements after the one removed. So unless you're removing always the last element it can be quite slow.
Upvotes: 7
Reputation: 43517
The only functions i am using from vectors are vector::erase, vector::push_back and vector::begin
I would say this is your problem. vector::erase
is O(n)
, the others are constant time and should not cause efficiency issues in online judge problems. Avoid the erase method.
However, in general, if you know the size of your array in advance, I would just use a simple array. Don't add any unnecessary overhead if you can help it.
To solve the problem you linked to though, consider using a set: its erase method is O(log n)
, as are its insertion methods. That is what you should use generally if you need random removals.
Edit: I forgot that C++ had priority queues too, so look into those as well. Since you only care about the max here, it might be faster than a set, although they both have the same theoretical complexities (a heap can retrieve the min/max in O(1)
, but removing it, which you must do for this problem, is O(log n)
) in this case, and either one should work just fine.
Upvotes: 10
Reputation: 15964
If you know that the vector has a certain number of elements in it in advance you can reserve enough space to contain everything to save yourself reallocations of space within the vector:
books_order.reserve(total_books)
for(int i=0 ;i < total_books; ++i){
int temp;
cin >> temp;
books_order.push_back(temp);
}
However that's not the issue here, I'm sure if you profiled your code you would see a large overhead from the .erase()
usage. Removing elements from the middle of a vector is slow because of how a vector is implemented it will need to move all the elements part the one that is removed. Consider using a different data structure instead such as std::array
instead.
Upvotes: 1
Reputation: 21351
Unless you have called reserve
to size your vector to the number of elements you have, calls to push_back
will reallocate memory every time the new size will exceed the vector capacity. Consider using reserve
to allocate memory sufficient for your elements and you should see a performance speed up, particularly if the vector is large. Also take heed of the other answers regarding use of erase
.
Upvotes: 3
Reputation: 8027
Removing elements from the middle of a vector (with vector::erase
) is slow. This is because all the higher elements of the vector must be moved down to fill the gap left by the element you've removed.
So this is not a case of vectors being slow, but you algorithm being slow because you've chosen an inappropriate data structure.
Upvotes: 2
Reputation: 10828
your problem is the call to "erase". If you check the documentation here, you'll note that:
Because vectors keep an array format, erasing on positions other than the vector end also moves all the elements after the segment erased to their new positions, which may not be a method as efficient as erasing in other kinds of sequence containers (deque, list).
either run the loop from the end or erase after the loop.
Upvotes: 2
Reputation: 5440
Do you really need a vector to achieve what you are doing?
You have to keep in mind how vectors work: They're essentially dynamic arrays that resize as you add more items in them. Resizing a vector is an O(n) operation (where n is the number of items in your vector) as it allocates new memory and copies the items over to the new vector.
You can read about what vectors are good at here.
I would recommend using a standard array instead -- which seems completely plausible since you already know how many total elements there are (which is total_books
)
Upvotes: 0