how to push_back vector with no size in a specific location? - c++

I'm trying to get a solid understanding of Vectors. So i understand if we init vectors as following we specify the exact location in array for the vector to exist
vector<int> temp[5];
temp[i].push_back(randomInt);(i a random position)
but what if i'm trying to have a vector without specified size because i do not know the amount of input? how would i define the first index for example of temp as i did previously using the following init?
vector<int> temp;

here:
vector<int> temp[5];
you declared an array of 5 vectors, but going by your description it looks like you're meant to declare one vector with pre-allocated 5 elements (if so, then it should have been like vector<int> temp(5);)
how would i define the first index for example of temp as i did
previously using the following init?
all the std containers have methods allowing you to push / emplace data (i.e. to extend them) and method size() allowing to check the current size of the container.

Related

Does an array of vectors form a 2D vector?

Does the following statements form a 2D vector?
Also mention the dimensions of the vector if it does. Is there another way of declaring a global 2D vector?
Statements:
vector<int> *adj;
adj = new vector<int>[number_of_nodes];
The above statements have been used for declaration of a global adjacency matrix for a graph.
It seems the question isn't clear to much of you. I want to declare a global adjacency list using vectors such that I can use direct addition of edges in graph like v[a].push_back(b). For that, I have to specify first dimension of vector while declaring which I don't have until the main is executed.
No, but it gives similar behaviour. So what you have created is a pointer to an array of vectors. So you will end up with this:
adj[0] = []
adj[1] = []
...
adj[number_nodes] = []
and doing a push_back is a legitimate way to add to the vectors:
adj[0].push_back(some_num) --> adj[0] = [some_num]
But this is a terrible way to approach this! Why?
You are using raw memory that you will have to manage and make sure you delete.
You cant use any of the awesome std::vector functionality on the first dimension of the matrix.
There is no good way to figure out the size of the vector unless you know about the variable number_of_nodes.
... A long list, but you get it.
You can already see that a std::vector can be used as a 1D matrix. So use 2 vectors:
std::vector<std::vector<int>> Matrix2D;
If you need an initial size in some dimension then you can do this:
std::vector<std::vector<int>> Matrix2D(number_of_nodes, std::vector<int>());
Or this:
Matrix2D.resize(number_of_nodes);
Or if that size is fixed at compile time then you could even do this:
const int number_of_nodes = 10;
std::array<std::vector<int>, number_of_nodes> Matrix2D;
Or go extra big and get a library for Matrix use like Eigen.

Inserting elements into 2D vector

so I'm creating a class that implements an adjacency list. Currently in my class definition I initialized two vectors:
vector<vector<int>> adjList;
vector<int> neighbors;
and I declared two functions that I plan to use to make it:
bool constructAdjList();
bool insertIntoAdjList(int, int);
It's getting difficult wrapping my head around 2D vectors. I understand that it is essentially a vector of vectors, but I'm confused about how to insert a new value into one of the "subvectors". For example, I am able to create an adjacency list in createAdjList that is empty with the following loop:
for (int i = 0; i < numOfValues; i++){
neighbors.push_back(0);
adjList.push_back(neighbors);
neighbors.clear();
}
But how can I say, push_back the value 5 to the 4th vector in adjList, which would be represented in my insertIntoAdjList function as
insertIntoAdjList(4, 5);
I know I can access a specific value in a 2D vector by saying adjList[4][1], but how can I push one onto it?
Thanks!
To push on the vector that is an element of another vector, you simply do this
adjList[x].push_back();
If initially you do not have any values in the vector -
You can push values into one vector and then push this vector into the 2D vector.
For example:
vector< vector<int> > vt1;
vector<int> vt2;
vt2.push_back(value);
vt1.push_back(vt2);
If your vector is already populated then -
vt1[index].push_back(value);
A couple of notes here.
Your loop can be significantly shortened just be using the constructors of your two members:
vector<int> neighbors(1, 0); // set to length 1, value is zero
vector<vector<int>> adjList(numOfValues,neighbors); // "outer" vector is numOfValues long
. // each row is a *COPY* of neighbor
If you can't do this at construction time (maybe numOfValues isn't known yet), then there's still a better loop phrasing we can use:
// neighbors object can be reused
neighbors.clear(0);
neighbors.push_back(0);
adjList.reserve(numOfValues); // reserving memory ahead of time will prevent allocations
for (int i = 0; i < numOfValues; i++){
adjList.push_back(neighbors); // push_back is by *COPY*
}
In your example, by using clear and push_back to essentially build the same vector every loop iteration, you are risking an allocation and deallocation each iteration. In practice, most implementations won't do this, but if we can both shorten and potentially make things more efficient, we may as well.
Lastly, if the number of neighbors is relatively small and similar row to row (for instance a finite elements code with tetrahedral elements, where each element connects to ~5 others), then as others have suggested you may be better off with a different structure than vector-of-vector. For instance, a single vector that is logically organized such that a new "row" begins every N elements.

dynamically changing name of an array in c++

Hi I have a problem where at compile time, I don't know how many vectors in my program are needed. The number required depends on a data set given at run-time, which will results in the range of vectors needed to be from 1 to N.
So if the data set requires ten vectors, it will create vec1,vec2,......vecN
How can i dynamically create the vectors so that they all have a different name?
I would then need to call each array separately. Presumably
I could just use strings and a few loops for this.
You can't do that directly. However, you could use a map to store a vector name, and the vector itself:
map<string, vector<int> > myMap;
You can add elements simply like this (if the element with such key doesn't exist yet):
vector<int> vec;
myMap["vec"] = vec;
If you'll do it with a key that already exists, the value will be replaced. For example:
vector<int> vec;
vector<int> vec1;
myMap["vec"] = vec;
myMap["vec"] = vec1;//now myMap["vec"] holds the vec1 vector
You can also easlly access elements like this:
myMap["vec"]//this will access the vector with the key "vec1"
You can create a vector to contain your vectors:
std::vector<std::vector<int>> my_vector_of_vectors;
// Add a vector
my_vector_of_vectors.push_back(std::vector<int>{});
// Add a number to the inner vector
my_vector_of_vectors[0].push_back(1);
you have a vector of vectors, vec[0] to vec[n], each one containing the vector.
However, this works est if you know the number of vectors (eg 10). If you need to add new ones on-demand, then a list of vectors or a map might be a better option for you.

how to store vector of vector by index

Hi I have to store the below mentioned information in a vector of vectors format...
vector <vector <int>> ph;
vector<int> p, q;
p.push_back(1);
p.push_back(2);
p.push_back(3);
q.push_back(10);
q.push_back(20);
q.push_back(30);
q.push_back(40);
Now instead of using:
ph.push_back(p);
ph.push_back(q);
I want to use:
ph.at(0)=p
ph.at(1)=q
(This is the error that I am getting when I am using this: terminate called after throwing an instance of 'std::out_of_range'
what(): vector::_M_range_check)
The reason why I want to store it this way is....later I want to access the elements of a particular vector identified by its index i.e. 1 or 0.
For example I wish to access ph[0].size() i.e the size of p...identified by its index. That is, I want to perform the same operation as we are able to do in the case of simple arrays in c++ i.e. store the data in that array at a particular index and access the data from a particular index.
You are getting the error because when you instantiate the vector of vectors, it has size 0, and the at() method is allowed to do bound checks and raise an exception.
If you want to access by index like that then you are better off with an std::map or std::unordered_map. That makes the index independent of the order of insertion:
std::map<int, std::vector<int>> MapOfVectors;
std::vector<int> p, q;
// fill vectors
MapOfVectors[1] = q;
MapOfVectors[0] = p;
Otherwise, you would have to make sure your vector of vectors is large enough to insert elements by index:
// instantiate vector with size 2. You can insert p and q by index. (0, 1) only
vector<vector<int>> ph(2);
Or, resize it after creation:
vector<vector<int>> ph;
ph.resize(2);
When you define vector<vector<int>> ph the vector ph is empty. The .at() member function does bounds checking and correctly throws an exception when you try to write to non-existing elements.
You could do ph.resize(2) so that indices 0-1 would then be valid or just use push_back like you do currently.
I want to use:
ph.at(0)=p ph.at(1)=q
That attempts to access indices past the end of the array, hence the exception.
The reason why I want to store it this way is....later I want to access the elements of a particular vector identified by its index i.e. 1 or 0.
For example I wish to access ph[0].size() i.e the size of p...identified by its index. That is, I want to perform the same operation as we are able to do in the case of simple arrays in c++ i.e. store the data in that array at a particular index and access the data from a particular index.
You can achieve this by first filling the outer vector with empty inner vectors:
vector<vector<int> > ph(2);
Here, the 2 says to construct the outer vector to contain 2 default-constructed elements (themselves vector<int>).
Alternatively, you can use:
vector<vector<int> > ph;
ph.resize(2);
After you've done that, it will be safe to access the elements to store non-default-constructed values. That means the following won't throw:
ph.at(0)=p; ph.at(1)=q;

C++ pair data type issue

I am writing a friend recommendation algorithm and in a part I have to store 350 random friendship using the data type std::pair in C++. I basically use an adjacency list (implemented as vector of vectors). I create a vector that stores data type pair<int,int>. I select a random value from the adjacency list and select one of it's friends randomly, however, even though I'm quite sure that I push the data type as pair however I cannot iterate through it.
What could be the possible reason?
int FRIENDS_AND_UNFRIENDS_TO_STORE=350,randomNode=rand()%adjacencyList.size(),randomFriend;
vector< pair<int,int> >listForPR;
listForPR.resize(FRIENDS_AND_UNFRIENDS_TO_STORE*2);
for(int i=0;i<FRIENDS_AND_UNFRIENDS_TO_STORE;i++) {
while(adjacencyList[randomNode].size()<1)
randomNode=rand()%adjacencyList.size();
randomFriend=rand()%adjacencyList[randomNode].size();
listForPR.push_back(make_pair(randomNode,adjacencyList[randomNode][randomFriend]));
}
for(int i=0;i<350;i++)
cout<<"Node #"<<listForPR[i].first<<" & It's Friend: "<<listForPR[i].second<<endl;
Added this and !mysteriously solved the problem;
for(int i=0;i<FRIENDS_AND_UNFRIENDS_TO_STORE;i++) {
while(adjacencyList[randomNode].size()<1)
randomNode=rand()%adjacencyList.size();
randomFriend=rand()%adjacencyList[randomNode].size();
pair<int,int> temp=make_pair(randomNode,adjacencyList[randomNode][randomFriend]);//added
listForPR.push_back(temp);
}
Your vector contains 350/2 = 175 elements that you pushed in during the loop, but you are going through 350 elements when you iterate.
You shouldn't mix resize and push_back.
The first resize fills listForPR with 350 zeroed items.
Then push_back adds items to the end of the vector.
Deleting resize statement should fix the problem. Even better solution is to use reserve (it just prepares buffer in vector for insertion).