How to copy a set of object to an array of object? - c++

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.

Related

Adding elements to a vector from an array of pointers in C++

I've been trying to use an array of pointers to point to vectors, which I have so far been able to implement, however, in trying to add an element to one of the sub-vectors, I repeatedly get an unknown error on run-time.
I have previously defined my array as so:
std::vector<std::string> *frequency_table[10000];
I then try to add an element to a specific one of the vectors. This is the line that causes the run-time error.
frequency_table[index]->push_back(value);
Any ideas?
At first glance the problem looks like you haven't allocated any memory for the pointer so it has nowhere to push the value to. Though i can't be sure without the error message.
If that is the case however you would need to use new to allocate the memory
Your approach involves mixing vectors (and vectors are a good thing) and C-style arrays of pointers to objects (which betrays a mix-up since there are already vectors in your code).
If you want 10000 vectors of vectors of string, then just write
std::vector<std::vector<std::string> > frequency_table(10000);
. . .
frequency_table[index].push_back(value);
The first line declares a vector, each element of which is a vector<string>, allocates 10000 elements to it and initializes each element.
Using the input from you guys, I realized that my problem was the vectors were not being initialized, so I added this loop before the loop in which I populate the vectors, and it works now:
for(int i = 0; i < 5000; ++i)
{
frequency_table[i] = new std::vector<std::string>;
}
The final code looks like this:
for(int i = 0; i < 5000; ++i)
{
frequency_table[i] = new std::vector<std::string>;
}
for(auto itr = frequency_map.begin(); itr != frequency_map.end(); ++itr)
{
std::string key = itr->first;
double value = itr->second;
frequency_table[(int)value]->push_back(key);
}
Thanks all!
ps I halved the 10000 for testing purposes

Container Template Class - Decreasing Container Size

I've written some code to decrease the capacity of a templated container class. After an element is removed from the container, the erase function checks to see whether or not 25% of the total space is in use, and whether reducing the capacity by half would cause it to be less than the default size I've set. If these two return true, then the downsize function runs. However, if this happens while I'm in the middle of a const_iterator loop, I get a segfault.
edit again: I'm thinking it's because the const_iterator pointer is pointing to the old array and needs to be pointed to the new one created by downsize()...now how to go about doing that...
template <class T>
void sorted<T>::downsize(){
// Run the same process as resize, except
// in reverse (sort of).
int newCapacity = (m_capacity / 2);
T *temp_array = new T[newCapacity];
for (int i = 0; i < m_size; i++)
temp_array[i] = m_data[i];
// Frees memory, points m_data at the
// new, smaller array, sets the capacity
// to the proper (lower) value.
delete [] m_data;
m_data = temp_array;
setCap(newCapacity);
cout << "Decreased array capacity to " << newCapacity << "." << endl;
}
// Implementation of the const_iterator erase method.
template <class T>
typename sorted<T>::const_iterator sorted<T>::erase(const_iterator itr){
// This section is reused from game.cpp, a file provided in the
// Cruno project. It handles erasing the element pointed to
// by the constant iterator.
T *end = &m_data[m_capacity]; // one past the end of data
T *ptr = itr.m_current; // element to erase
// to erase element at ptr, shift elements from ptr+1 to
// the end of the array down one position
while ( ptr+1 != end ) {
*ptr = *(ptr+1);
ptr++;
}
m_size--;
// Once the element is removed, check to
// see if a size reduction of the array is
// necessary.
// Initialized some new values here to make
// sure downsize only runs when the correct
// conditions are met.
double capCheck = m_capacity;
double sizeCheck = m_size;
double usedCheck = (sizeCheck / capCheck);
int boundCheck = (m_capacity / 2);
if ((usedCheck <= ONE_FOURTH) && (boundCheck >= DEFAULT_SIZE))
downsize();
return itr;
}
// Chunk from main that erases.
int i = 0;
for (itr = x.begin(); itr != x.end(); itr++) {
if (i < 7) x.erase(itr);
i++;
}
To prevent issues with invalidated iterators during an erase loop, you can use:
x.erase(itr++);
instead of separate increment and increment calls (obviously if you're not erasing everything you loop over you'd need an else case to increment past the non-erased items.) Note this is a case where you need to use post-increment rather than pre-increment.
The whole thing looks a bit inefficient though. The way you convert to an array suggests that it's only going to work with certain container types anyway. If you expect lots of erasing from the middle of the container you might be able to avoid the memory issue by just choosing a different container; list maybe.
If you choose vector, you might find that calling shrink_to_fit is what you want.
Also note that erase has a return value that will point to the (new) location of the element after the erased one.
If you go down the line of returning an iterator to a newly created down-sized version of the container, note that comparing to the original containers end() iterator wouldn't work.
I figured out the segfault problem!
What was going on was that my x.end() was using the size of the array (NOT the capacity), where the size is the number of data elements stored in the array, instead of the capacity which is actually the size of the array. So when it was looking for the end of the array, it was seeing it as numerous elements before the actual end.
Now on to more interesting problems!

C++ Most efficient way iterate specific contents in vector

I have two vectors, vec and p, such that p is a vector of pointers to different locations in vec.
So something like:
p[0] = &vec[12]
p[1] = &vec[20]
p[3] = &vec[1]
etc.
p's size will always be less than or equal to vec, and will contain no duplicate references to the same location in vec.
What I'd like to have is some data structure that I can iterate through to get the dereferenced values of p in the order of the index they are pointing to in a. So for the above example, the result would need to iterate through in the order vec[1], vec[12], vec[20].
I know can get the position in vec the p is pointing to be doing something like p[i] - &vec[0], and could probably implement this using std::sort and a custom comparing function, but I feel like there is a more efficient way to do this than the O(nlogn) of the sort function. I could also be completely wrong about that.
Thanks for any help!
After discarding a few mental ideas, I thought of a simple one:
std::vector<char> is_pointed_to(vec.size(), 0);//initialize the "bools" to "false"
//set is_pointed_to values
for(T* pointer : p) {
size_t orig_index = pointer - &vec[0];
is_pointed_to[orig_index] = 1; //set this index to "true"
}
//now do the iteration
for(int i=0; i<vec.size(); ++i) {
if(is_pointed_to[i]) {
//DO TASK HERE
}
}
This is clearly a two-pass algorithm, so O(n). Easy.
StilesCrisis reminds me that this is an implementation of the counting sort.

Deleting an element from an array of pointers

I'm creating a custom vector class as part of a homework assignment. What I am currently trying to do is implement a function called erase, which will take an integer as an argument, decrease my array length by 1, remove the element at the position specified by the argument, and finally shift all the elements down to fill in the gap left by "erased" element.
What I am not completely understanding, due to my lack of experience with this language, is how you can delete a single element from an array of pointers.
Currently, I have the following implemented:
void myvector::erase(int i)
{
if(i != max_size)
{
for(int x = i; x < max_size; x++)
{
vec_array[x] = vec_array[x+1];
}
vec_size --;
//delete element from vector;
}
else
//delete element from vector
}
The class declaration and constructors look like this:
template <typename T>
class myvector
{
private:
T *vec_array;
int vec_size;
int max_size;
bool is_empty;
public:
myvector::myvector(int max_size_input)
{
max_size = max_size_input;
vec_array = new T[max_size];
vec_size = 0;
}
I have tried the following:
Using delete to try and delete an element
delete vec_size[max_size];
vec_size[max_size] = NULL;
Setting the value of the element to NULL or 0
vec_size[max_size] = NULL
or
vec_size[max_size] = 0
None of which are working for me due to either operator "=" being ambiguous or specified type not being able to be cast to void *.
I'm probably missing something simple, but I just can't seem to get passed this. Any help would be much appreciated. Again, sorry for the lack of experience if this is something silly.
If your custom vector class is supposed to work like std::vector, then don't concern yourself with object destruction. If you need to erase an element, you simply copy all elements following it by one position to the left:
void myvector::erase(int i)
{
for (int x = i + 1; x < vec_size; x++) {
vec_array[x - 1] = vec_array[x];
}
vec_size--;
}
That's all the basic work your erase() function has to do.
If the elements happen to be pointers, you shouldn't care; the user of your vector class is responsible for deleting those pointers if that's needed. You cannot determine if they can actually be deleted (the pointers might point to automatic stack variables, which are not deletable.)
So, do not ever call delete on an element of your vector.
If your vector class has a clear() function, and you want to make sure the elements are destructed, simply:
delete[] vec_array;
vec_array = new T[max_size];
vec_size = 0;
And this is how std::vector works, actually. (Well, the basic logic of it; of course you can optimize a hell of a lot of stuff in a vector implementation.)
Since this is homework i wont give you a definitive solution, but here is one method of erasing a value:
loop through and find value specified in erase function
mark values position in the array
starting from that position, move all elements values to the previous element(overlapping 'erased' value)
for i starting at position, i less than size minus one, i plus plus
element equals next element
reduce size of vector by 1
see if this is a big enough hint.

C++ vector - push_back

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.