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.
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.
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.
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.
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.
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.
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.
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)
Related
I've coded an algorithm designed to produce a list of the closest triplets from three sorted arrays (one element contributed by each array). The algorithm finds the closest triplet, removes those elements, then repeats the process. The algorithm itself runs quite fast, however the code I'm using to "remove" the elements from each array slows it down significantly. Is there a more efficient method, or is random removal necessarily always O(n)?
My current strategy (effectively identical to std::move):
for(int i = 6; i < n; ++i)
array[i] = array[i+1];
Where n is the size of the array, and 6 is the index of the element to be removed.
Fastest way to remove an element from an array?
Note that there is no way to erase elements from an array. The size of an array cannot change. So to be clear, we are considering algorithm where the resulting array contains the elements excluding the "removed" value at the beginning of the array, with some irrelevant value in the end.
The algorithm that you show1 is the optimal one if there is an additional constraint that the order of other elements must not change. It can be slightly improved by using move assignment if the element type is non-trivial, but that doesn't improve asymptotic complexity. There is no need to write the loop, since there is a standard algorithm: std::move (the two-argument overload from <algorithm>).
If there is no constraint of stable order, then there is a more efficient algorithm: Only write the last element over the "removed" one.
is random removal [from array] necessarily always O(n)?
Only when the remaining elements need to have a stable order.
1 However, there is a bug in your implementation:
for(int i = 6; i < n; ++i)
array[i] = array[i+1];
Where n is the size of the array
If n is the size of the array, then array[n-1+1] is outside the bounds of the array.
There are a few more options you can consider.
Validity masks
You can have an additional array of bool initially everything is set to false to day values are not deleted. To delete the value you set the corresponding bool to true (or the other way if it makes more sense in your code).
This requires a bit of tweaks to the rest of the code to skip values that are marked as deleted.
Tombstones
Similar to the solution above, but doesn't require additional memory. If there's a value that it's not used (say all the values are supposed to be positive, then we can use -1) you can set the entry to that value. This also requires tweaks in the rest of the code to skip it.
Delayed deletion
This one is a bit more complicated. I'd only use it if iterating over the deleted entries significantly affects performance or complexity.
The idea is to tombsone or mark the entries as deleted. Next time you iterate over the array you also do the swaps. This makes the code kind of complex. The easiest, I think, you can do it is using custom iterators.
This is still O(N), but it's amortized O(1) within the overall algorithm.
Also note that if you do a loop O(N) to find the element to delete and than do another loop O(N) to delete it, then the overall solution is still O(N).
I got a decision making problem here. In my application, I need to merge two vectors. I can't use stl algorithms since data order is important (It should not be sorted.).
Both the vectors contains the data which can be same sometimes or 75% different in the worst case.
Currently I am confused b/w two approaches,
Approach 1:
a. take an element in the smaller vector.
b. compare it with the elements in bigger one.
c. If element matches then skip it (I don't want duplicates).
d. If element is not found in bigger one, calculate proper position to insert.
e. re-size the bigger one to insert the element (multiple time re-size may happen).
Approach 2:
a. Iterate through vectors to find matched element positions.
b. Resize the bigger one at a go by calculating total size required.
c. Take smaller vector and go to elements which are not-matched.
d. Insert the element in appropriate position.
Kindly help me to choose the proper one. And if there is any better approach or simpler techniques (like stl algorithms), or easier container than vector, please post here. Thank you.
You shouldn't be focusing on the resizes. In approach 1, you should use use vector.insert() so you don't actually need to resize the vector yourself. This may cause reallocations of the underlying buffer to happen automatically, but std::vector is carefully implemented so that the total cost of these operations will be small.
The real problem with your algorithm is the insert, and maybe the search (which you didn't detail). When you into a vector anywhere except at the end, all the elements after the insertion point must be moved up in memory, and this can be quite expensive.
If you want this to be fast, you should build a new vector from your two input vectors, by appending one element at a time, with no inserting in the middle.
Doesn't look like you can do this in better time complexity than O(n.log(n)) because removing duplicates from a normal vector takes n.log(n) time. So using set to remove duplicates might be the best thing you can do.
n here is number of elements in both vectors.
Depending on your actual setup (like if you're adding object pointers to a vector instead of copying values into one), you might get significantly faster results using a std::list. std::list allows for constant time insertion which is going to be a huge performance overhead.
Doing insertion might be a little awkward but is completely do-able by only changing a few pointers (inexpensive) vs insertion via a vector which moves every element out of the way to put the new one down.
If they need to end up as vectors, you can then convert the list to a vector with something like (untested)
std::list<thing> things;
//efficiently combine the vectors into a list
//since list is MUCH better for inserts
//but we still need it as a vector anyway
std::vector<thing> things_vec;
things_vec.reserve(things.size()); //allocate memory
//now move them into the vector
things_vec.insert(
things_vec.begin(),
std::make_move_iterator(things.begin()),
std::make_move_iterator(things.end())
);
//things_vec now has the same content and order as the list with very little overhead
I am creating a game where i have small "particles". Their number is changing very frequently (every few seconds) and i'm wondering what is the best way to store them. Is std::vector or std::deque better for this?
Is it okay to reserve space (in that container) that will never get used (I have upper limit)?
Instead of removing a particle you can just replace it with the other one in a vector if order does not matter (and I think it does not)
std::vector<Particle> particles;
when you remove a particle at index i - just fill the empty space with the last one:
particles[i] = particles.back();
particles.pop_back();
You can make it even faster if using vector of pointers.
If you reserve enough space for the vector, resize is not bad, because it doesn't need to copy the vector's content.
One the other hand, dequeue can grow more efficiently than the vectors with their capacity managed automatically, specially in large sequences, because massive reallocations are avoided.
It really comes down to usage. If your vector is unsorted, if you are actually removing that particle, it has complexity O(n) to find it within your vector and the whole vector will be copied so the data remains contiguous. With a deque, it still takes O(n) to find, but removal is trivial. However, if you are iterating like
foreach (particle in particles)
{
if(particle.update() == END_OF_LIFE)
{
particle.alive = false;
}
else
{
particle.draw();
}
}
you can do it with no significant overhead, but to insert new particles you will either need to iterate through each particle to find the first 'dead' one you can replace (O(n)), or keep track of that information in a separate std::list.
One thing we need to know to effectively answer - do you ever need to index to a particular particle ("give me the 1000th particle in the list")? Also, do you ever look up by some ID ("find the particle with id=421932")? If the former, vector performs that in constant time, whereas the latter would be performed in constant time by an std::unordered_set (c++ x11 version of hash_set, similar options in boost pre x11) and logn time by std::set.
Let's say I have to iterate over a potentially very large vector of numbers and copy the even and odd elements into new, separate vectors. (The source vector may have any proportion of evens to odds; it could be all evens, all odds, or somewhere in-between.)
For simplicity, push_back is often used for this sort of thing:
for (std::size_t Index; Index < Source.size(); Index++)
{
if (Source[Index] % 2) Odds.push_back(Source[Index]);
else Evens.push_back(Source[Index]);
}
However, I'm worried that this will be inefficient and be harmful if it's used as part of the implementation for something like a sorting algorithm, where performance is paramount. QuickSort, for example, involves separating elements much like this.
You could use reserve() to allocate memory before-hand so only one allocation is needed, but then you have to iterate over the entire source vector twice - once to count how many elements will need to be sorted out, and once more for the actual copying.
You could, of course, allocate the same amount of space as the source vector's size, since neither new vector will need to hold more than that, but that seems somewhat wasteful.
Is there a better method that I'm missing? Is push_back() usually trusted to manage this sort of thing for the programmer, or can it become burdensome for sensitive algorithms?
I'm going to answer the question I think you really meant to ask, which is "should push_back() be avoided in the inner loops of heavy algorithms?" rather than what others seem to have read into your post, which is "does it matter if I call push_back before doing an unrelated sort on a large vector?" Also, I'm going to answer from my experience rather than spend time chasing down citations and peer-reviewed articles.
Your example is basically doing two things that add up to the total CPU cost: it's reading and operating on elements in the input vector, and then it has to insert the elements into the output vector. You're concerned about the cost of inserting elements because:
push_back() is constant time (instantaneous, really) when a vector has enough space pre-reserved for an additional element, but slow when you've run out of reserved space.
Allocating memory is costly (malloc() is just slow, even when pedants pretend that new is something different)
Copying a vector's data from one region to another after reallocation is also slow: when push_back() finds it hasn't got enough space, it has to go and allocate a bigger vector, then copy all the elements. (In theory, for vectors that are many OS pages in size, a magic implementation of the STL could use the VMM to move them around in the virtual address space without copying — in practice I've never seen one that could.)
Over-allocating the output vectors causes problems: it causes fragmentation, making future allocations slower; it burns data cache, making everything slower; if persistent, it ties up scarce free memory, leading to disk paging on a PC and a crash on embedded platforms.
Under-allocating the output vectors causes problems because reallocating a vector is an O(n) operation, so reallocating it m times is O(m×n). If the STL's default allocator uses exponential reallocation (making the vector's reserve twice its previous size every time you realloc), that makes your linear algorithm O(n + n log m).
Your instinct, therefore, is correct: always pre-reserve space for your vectors where possible, not because push_back is slow, but because it can trigger a reallocation that is slow. Also, if you look at the implementation of shrink_to_fit, you'll see it also does a copy reallocation, temporarily doubling your memory cost and causing further fragmentation.
Your problem here is that you don't always know exactly how much space you'll need for the output vectors; the usual response is to use a heuristic and maybe a custom allocator. Reserve n/2+k of the input size for each of your output vectors by default, where k is some safety margin. That way you'll usually have enough space for the output, so long as your input is reasonably balanced, and push_back can reallocate in the rare cases where it's not. If you find that push_back's exponential behavior is wasting too much memory ( causing you to reserve 2n elements when really you just needed n+2 ), you can give it a custom allocator that expands the vector size in smaller, linear chunks — but of course that will be much slower in cases where the vectors are really unbalanced and you end up doing lots of resizes.
There's no way to always reserve the exact right amount of space without walking the input elements in advance; but if you know what the balance usually looks like, you can use a heuristic to make a good guess at it for a statistical performance gain over many iterations.
You could, of course, allocate the same amount of space as the source
vector's size, since neither new vector will need to hold more than
that, but that seems somewhat wasteful.
Then follow it up with a call to shrink_to_fit
However, I'm worried that this will be inefficient and harm things
like sorting algorithms. ... Is push_back() usually trusted to manage
this sort of thing for the programmer, or can it become burdensome for
sensitive algorithms?
Yes, push_back is trusted. Although honestly I don't understand what your concern is. Presumably, if you're using algorithms on the vector, you've already put the elements into the vector. What kind of algorithm are you talking about where it would matter how the vector elements got there, be it push_back or something else?
How about sorting the original vector with a custom predicate that puts all the evens before all the odds?
bool EvenBeforeOdd(int a, int b)
{
if ((a - b) % 2 == 0) return a < b;
return a % 2 == 0;
}
std::sort(v.begin(), v.end(), EvenBeforeOdd);
Then you just have to find the largest even number, which you can do e.g. with upper_bound for a very large even number or something like that. Once you found that, you can make very cheap copies of the ranges.
Update: As #Blastfurnace commented, it's much more efficient to use std::partition rather than sort, since we don't actually need the elements ordered within each partition:
bool isEven(int a) { return 0 == a % 2; }
std::vector<int>::const_iterator it = std::partition(v.begin(), v.end(), isEven);
std::vector<int> evens, odds;
evens.reserve(std::distance(v.begin(), it);
odds.reserve(std::distance(it, v.end());
std::copy(v.begin(), it, std::back_inserter(evens));
std::copy(it, v.end(), std::back_inserter(odds));
If your objects are created dynamically then the vectors are literally just storing pointers. This makes the vectors considerably more efficient, especially when it comes to internal reallocation. This would also save memory if same objects exist in multiple locations.
std::vector<YourObject*> Evens;
Note: Do not push pointers from context of function as this will cause data corruption outside of that frame. Instead objects would need to be allocated dynamically.
This might not solve your problem, but perhaps it is of use.
If your sub vectors are exactly half (odd / even) then simply allocate 50% of original vector for each. This would avoid wastage and shrink_to_fit.
I am maintaining a fixed-length table of 10 entries. Each item is a structure of like 4 fields. There will be insert, update and delete operations, specified by numeric position. I am wondering which is the best data structure to use to maintain this table of information:
array - insert/delete takes linear time due to shifting; update takes constant time; no space is used for pointers; accessing an item using [] is faster.
stl vector - insert/delete takes linear time due to shifting; update takes constant time; no space is used for pointers; accessing an item is slower than an array since it is a call to operator[] and a linked list .
stl list - insert and delete takes linear time since you need to iterate to a specific position before applying the insert/delete; additional space is needed for pointers; accessing an item is slower than an array since it is a linked list linear traversal.
Right now, my choice is to use an array. Is it justifiable? Or did I miss something?
Which is faster: traversing a list, then inserting a node or shifting items in an array to produce an empty position then inserting the item in that position?
What is the best way to measure this performance? Can I just display the timestamp before and after the operations?
Use STL vector. It provides an equally rich interface as list and removes the pain of managing memory that arrays require.
You will have to try very hard to expose the performance cost of operator[] - it usually gets inlined.
I do not have any number to give you, but I remember reading performance analysis that described how vector<int> was faster than list<int> even for inserts and deletes (under a certain size of course). The truth of the matter is that these processors we use are very fast - and if your vector fits in L2 cache, then it's going to go really really fast. Lists on the other hand have to manage heap objects that will kill your L2.
Premature optimization is the root of all evil.
Based on your post, I'd say there's no reason to make your choice of data structure here a performance based one. Pick whatever is most convenient and return to change it if and only if performance testing demonstrates it's a problem.
It is really worth investing some time in understanding the fundamental differences between lists and vectors.
The most significant difference between the two is the way they store elements and keep track of them.
- Lists -
List contains elements which have the address of a previous and next element stored in them. This means that you can INSERT or DELETE an element anywhere in the list with constant speed O(1) regardless of the list size. You also splice (insert another list) into the existing list anywhere with constant speed as well. The reason is that list only needs to change two pointers (the previous and next) for the element we are inserting into the list.
Lists are not good if you need random access. So if one plans to access nth element in the list - one has to traverse the list one by one - O(n) speed
- Vectors -
Vector contains elements in sequence, just like an array. This is very convenient for random access. Accessing the "nth" element in a vector is a simple pointer calculation (O(1) speed). Adding elements to a vector is, however, different. If one wants to add an element in the middle of a vector - all the elements that come after that element will have to be re allocated down to make room for the new entry. The speed will depend on the vector size and on the position of the new element. The worst case scenario is inserting an element at position 2 in a vector, the best one is appending a new element. Therefore - insert works with speed O(n), where "n" is the number of elements that need to be moved - not necessarily the size of a vector.
There are other differences that involve memory requirements etc., but understanding these basic principles of how lists and vectors actually work is really worth spending some time on.
As always ... "Premature optimization is the root of all evil" so first consider what is more convenient and make things work exactly the way you want them, then optimize. For 10 entries that you mention - it really does not matter what you use - you will never be able to see any kind of performance difference whatever method you use.
Prefer an std::vector over and array. Some advantages of vector are:
They allocate memory from the free space when increasing in size.
They are NOT a pointer in disguise.
They can increase/decrease in size run-time.
They can do range checking using at().
A vector knows its size, so you don't have to count elements.
The most compelling reason to use a vector is that it frees you from explicit memory management, and it does not leak memory. A vector keeps track of the memory it uses to store its elements. When a vector needs more memory for elements, it allocates more; when a vector goes out of scope, it frees that memory. Therefore, the user need not be concerned with the allocation and deallocation of memory for vector elements.
You're making assumptions you shouldn't be making, such as "accessing an item is slower than an array since it is a call to operator[]." I can understand the logic behind it, but you nor I can know until we profile it.
If you do, you'll find there is no overhead at all, when optimizations are turned on. The compiler inlines the function calls. There is a difference in memory performance. An array is statically allocated, while a vector dynamically allocates. A list allocates per node, which can throttle cache if you're not careful.
Some solutions are to have the vector allocate from the stack, and have a pool allocator for a list, so that the nodes can fit into cache.
So rather than worry about unsupported claims, you should worry about making your design as clean as possible. So, which makes more sense? An array, vector, or list? I don't know what you're trying to do so I can't answer you.
The "default" container tends to be a vector. Sometimes an array is perfectly acceptable too.
First a couple of notes:
A good rule of thumb about selecting data structures: Generally, if you examined all the possibilities and determined that an array is your best choice, start over. You did something very wrong.
STL lists don't support operator[], and if they did the reason that it would be slower than indexing an array has nothing to do with the overhead of a function call.
Those things being said, vector is the clear winner here. The call to operator[] is essentially negligible since the contents of a vector are guaranteed to be contiguous in memory. It supports insert() and erase() operations which you would essntially have to write yourself if you used an array. Basically it boils down to the fact that a vector is essentially an upgraded array which already supports all the operations you need.
I am maintaining a fixed-length table of 10 entries. Each item is a
structure of like 4 fields. There will be insert, update and delete
operations, specified by numeric position. I am wondering which is the
best data structure to use to maintain this table of information:
Based on this description it seems like list might be the better choice since its O(1) when inserting and deleting in the middle of the data structure. Unfortunately you cannot use numeric positions when using lists to do inserts and deletes like you can for arrays/vectors. This dilemma leads to a slew of questions which can be used to make an initial decision of which structure may be best to use. This structure can later be changed if testing clearly shows its the wrong choice.
The questions you need to ask are three fold. The first is how often are you planning on doing deletes/inserts in the middle relative to random reads. The second is how important is using a numeric position compared to an iterator. Finally, is order in your structure important.
If the answer to the first question is random reads will be more prevalent than a vector/array will probably work well. Note iterating through a data structure is not considered a random read even if the operator[] notation is used. For the second question, if you absolutely require numeric position than a vector/array will be required even though this may lead to a performance hit. Later testing may show this performance hit is negligible relative to the easier coding with numerical positions. Finally if order is unimportant you can insert and delete in a vector/array with an O(1) algorithm. A sample algorithm is shown below.
template <class T>
void erase(vector<T> & vect, int index) //note: vector cannot be const since you are changing vector
{
vect[index]= vect.back();//move the item in the back to the index
vect.pop_back(); //delete the item in the back
}
template <class T>
void insert(vector<T> & vect, int index, T value) //note: vector cannot be const since you are changing vector
{
vect.push_back(vect[index]);//insert the item at index to the back of the vector
vect[index] = value; //replace the item at index with value
}
I Believe it's as per your need if one needs more insert/to delete in starting or middle use list(doubly-linked internally) if one needs to access data randomly and addition to last element use array ( vector have dynamic allocation but if you require more operation as a sort, resize, etc use vector)