C++ vector - push_back - c++

In the C++ Primer book, Chapter (3), there is the following for-loop that resets the elements in the vector to zero.
vector<int> ivec; //UPDATE: vector declaration
for (vector<int>::size_type ix = 0; ix ! = ivec.size(); ++ix)
ivec[ix] = 0;
Is the for-loop really assigning 0 values to the elements, or do we have to use the push_back function?
So, is the following valid?
ivec[ix] = ix;
Thanks.

Is the for-loop really assigning 0
values to the elements? Or, we have to
use the push_back finction?
ivec[ix] =0 updates the value of existing element in the vector, while push_back function adds new element to the vector!
So, is the following valid?
ivec[ix] = ix;
It is perfectly valid IF ix < ivec.size().
It would be even better if you use iterator, instead of index. Like this,
int ix = 0;
for(vector<int>::iterator it = ivec.begin() ; it != ivec.end(); ++it)
{
*it = ix++; //or do whatever you want to do with "it" here!
}
Use of iterator with STL is idiomatic. Prefer iterator over index!

Yes, you can use the square brackets to retrieve and overwrite existing elements of a vector. Note, however, that you cannot use the square brackets to insert a new element into a vector, and in fact indexing past the end of a vector leads to undefined behavior, often crashing the program outright.
To grow the vector, you can use the push_back, insert, resize, or assign functions.

Using the array brackets the vector object acts just like any other simple array. push_back() increases its length by one element and sets the new/last one to your passed value.

The purpose of this for loop is to iterate through the elements of the vector.
Starting at element x (when ix is 0) up to the last element (when ix is ivec.size() -1).
On each iteration the current element of the vector is set to 9.
This is what the statement
ivec[ix] = 0;
does. Putting
ivec[ix] = ix;
in the for loop would set all the elements of the vector to their position in the vector. i.e, the first element would have a value of zero (as vectors start indexing from 0), the second element would have a value of 1, and so on and so forth.

Yes, assuming ix is a valid index, most likely: you have a vector of int though and the index is size_type. Of course you may want to purposely store -1 sometimes to show an invalid index so the conversion of unsigned to signed would be appropriate but then I would suggest using a static_cast.
Doing what you are doing (setting each value in the vector to its index) is a way to create indexes of other collections. You then rearrange your vector sorting based on a predicte of the other collection.
Assuming that you never overflow (highly unlikely if your system is 32 bits or more) your conversion should work.

Related

How unique() function for array works

int a[4] = {3,1,2,3};
sort(a,a+n);
int j = unique(a,a+n) - a; // j=3
In this code variable j returns total numbers of unique element in the array a. But I couldn't understand how this code is working.
I know that in lists,
list::unique() is an inbuilt function in C++ STL which removes all duplicate consecutive elements from the list. It works only on sorted lists.
std::unique() is going to move the duplicates in the range [a+0, a+n), and it returns a new iterator in that range that will mark the new "end" of the array, i.e, where the first non-unique item is now moved to in the array.
If you then subtract from that iterator the beginning iterator, which you do with unique(a,a+n) - a;, you get the number of elements that are between the start of the array and the new "end". This is how you are able to get the count of the unique elements.
It should be noted that I use "end" here because arrays have a fixed size. You aren't actually changing the size of the array at all, you are just moving the duplicate elements to the back of the array, and keeping the unique elements at the front.
It should also be noted that after this happens, everything at and after the iterator returned by unique() will have an unspecified value. It is legal to set new values to them, but using an unspecified value leads to undefined behavior.

How to copy a set of object to an array of object?

I have to copy the first size element from a set of Solution (a class) named population to an array of solution named parents. I have some problems with iterators because i should do an hybrid solution between a normal for loop
and a for with iterators. The idea is this: when I'm at the ith iteration of the for I declare a new iterator that's pointing the beginning
of population, then I advance this iterator to the ith position, I take this solution element and I copy into parents[i]
Solution* parents; //it is filled somewhere else
std::set<Solution> population; //it is filled somewhere else
for (int i = 0; i < size; i++) {
auto it = population.begin();
advance(it, i);
parents[i] = *it;
}
Two error messages popup with this sentence: 'Expression: cannot dereference end map/set iterator'
and 'Expression: cannot advance end map/set iterator'
Any idea on how to this trick? I know it's kinda bad mixing array and set, i should use vector instead of array?
You use std::copy_n.
#include <algorithm>
extern Solution* parents; //it is filled somewhere else
extern std::set<Solution> population; //it is filled somewhere else
std::copy_n(population.begin(), size, parents);
It seems like size may be incorrectly set. To ensure that your code behaves as expected, you should just use the collection's size directly:
auto it = population.begin();
for (int i = 0; i < population.size(); i++) {
parents[i] = *it;
++it;
}
This can also be solved with a much simpler expression:
std::copy(population.begin(), population.end(), parents);
I have to copy the first size element from a set [..] to an array
You can use std::copy_n.
for (int i = 0; i < size; i++) {
auto it = population.begin();
advance(it, i);
The problem with this is that you're iterating over the linked list in every iteration. This turns the copy operation from normally linear complexity to quadratic.
Expression: cannot dereference end map/set iterator'
The problem here appears to be that your set doesn't contain at least size number of elements. You cannot copy size number of elements if there aren't that many. I suggest that you would copy less elements when the set is smaller.
i should use vector instead of array?
Probably. Is the array very large? Is the size of the vector not known at compile time? If so, use a vector.

How can I overwrite an item pointed by the index of a vector?

I would like to overwrite an item pointed by index even if that index doesn't exist yet. operator[] works up until it is not out of bound. emplace seems to do this, but it need an iterator for the first param. I could use myvector.begin()+index but it's invalid when the vector is empty.
Clarification. My current implementation:
while (index < myvector.size())
myvector.push_back("");
myvector[index] = val;
I was hoping for an std method. The array is always very small (few elements).
Using the accepted answer, my code changes to:
if (index >= myvector.size()) // to avoid destroying the remaining elements when the index is smaller than current size
myvector.resize(index+1);
myvector[index] = val;
To overwrite an element of given index, that index must be inside valid vector bounds.
You can set the size of your vector to whatever value using vector::resize, and just use operator[] with indexes in the range [0, size-1]:
std::vector<std::string> data;
...
data.resize(100);
// Use data[i] for i = 0,1,2,...99

Erasing elements in a vector

So I have a vector of unsigned ints (vector<unsigned int> is called vector1). I have another vector of a struct I created (vector<struct> is called vector2). vector<int> holds an integer that is the index of the vector<struct>. For example, let's say that vector<int = {5, 17, 18, 19}. That means vector2.at(5) == vector2.at(vector1.at(0)).
In the struct, I have a bool variable called var. In most cases, var is false. I want to delete all of the elements in vector1 that have var = true.
What I did was:
for (unsigned int i = 0; i < vector1.size(); i++)
{
if (vector2.at(vector1.at(i)).var)
vector1.erase(vector.begin() + i);
}
The only problem with this is that it does not delete all of the true elements. I have run the for loop multiple times for all values to be delete. Is this the correct behavior? If it is not, where did I go wrong?
You have to use the erase-remove idiom to delete elements from a vector.
v.erase(std::remove(v.begin(), v.end(), value), v.begin);
std::remove moves the elements to the end of the vector and erase will erase the element from the vector.
You can keep a temporary vector, copy of vector1 and iterate over it in the for loop and delete from vector1.
You are erasing elements in the vector while at the same time iterating over it. So when erasing an element, you always jump over the next element, since you increase i while having just shortened the vector at i (it would be even worse, had you used a proper iterator loop instead of an index loop). The best way to do this would be to seperate both opretions, first "marking" (or rather reordering) the elements for removal and then erasing them from the vector.
This is in practice best done using the erase-remove idiom (vector.erarse(std::remove(...), vector.end())), which first uses std::remove(_if) to reorganize the data with the non-removed elements at the beginning and returns the new end of the range, which can then be used to really delete those removed elements from the range (effectively just shortening the whole vector), using std::vector::erase. Using a C++11 lambda, the removal condition can be expressed quite easily:
vector1.erase(std::remove_if( //erase range starting here
vector1.begin(), vector1.end(), //iterate over whole vector
[&vector2](unsigned int i) //call this for each element
{ return vector2.at(i).var; }), //return true to remove
vector1.end()); //erase up to old end
EDIT: And by the way, as always be sure if you really need std::vector::at instead of just [] and keep in mind the implications of both (in particular the overhead of the former and "maybe insecurity" of the latter).

C++ reorder std::vector elements using std::list of pointers

I ran into this problem when I tried to write out an new algorithm to reorder elements in std::vector. The basic idea is that I have std::list of pointters pointing into std::vector in such way that *list.begin() == vector[0], *(++list.begin()) == vector[1] and so on.
However, any modifications on list's element positions breaks the mapping. (Including appended pointers) When the mapping is broken the list's elements can be in random order but they point still into correct elements on vector. The task would be to reorder the elements in vector to correct the mapping.
Simplest method to do it (How I have done it now):
create new empty std::vector and resize it to equal size of the old vector.
iterate through the list and read elements from the old vector and write them into new vector. Set the pointer to point into new vector's element.
swap vectors and release the old vector.
Sadly the method is only useful when I need more capacity on the vector. It's inefficient when the current vector holding the elements has enough capacity to store all incoming elements. Appended pointers on the list will point into diffrent vector's storgate. The simple method works for this because it only reads from the pointers.
So I would want to reorder the vector "in place" using constant amount of memory. Any pointer that was not pointing into current vector's storgate are moved to point into current vector's storgate. Elements are simple structures. (PODs)
I'll try post an example code when I have time..
What should I do to achieve this? I have the basic idea done, but I'm not sure if it is even possible to do the reordering with constant amount of memory.
PS: I'm sorry for the (possibly) bad grammar and typos in the post. I hope it's still readable. :)
First off, why do you have a list of pointers? You might as well keep indices into the vector, which you can compute as std::distance(&v[0], *list_iter). So, let's build a vector of indices first, but you can easily adapt that to use your list directly:
std::vector<T> v; // your data
std::list<T*> perm_list; // your given permutation list
std::vector<size_t> perms;
perms.reserve(v.size());
for (std::list<T*>::const_iterator it = perm_list.begin(), end = perm_list.end(); it != end; ++it)
{
perms.push_back(std::distance(&v[0], *it));
}
(There's probably a way to use std::transform and std::bind, or lambdas, to do this in one line.)
Now to do the work. We simply use the cycle-decomposition of the permutation, and we modify the perms vector as we go along:
std::set<size_t> done;
for (size_t i = 0; i < perms.size(); while(done.count(++i)) {})
{
T tmp1 = v[i];
for (size_t j = perms[i]; j != i; j = perms[j])
{
T tmp2 = v[j];
v[j] = tmp1;
tmp1 = tmp2;
done.insert(j);
}
v[i] = tmp1;
}
I'm using the auxiliary set done to track which indices have already been permuted. In C++0x you would add std::move everywhere to make this work with movable containers.