Inserting elements into 2D vector - c++

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.

Related

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

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.

Change from static array to vector

here's my code:
vector<int> Edge[1000000]; //size of array must be very high
scanf("%d%d",&N,&M );
//N = size of workable index numbers for Edge
for( i=1;i<=M;i++){
scanf("%d%d",&u,&v );
Edge[u].push_back( v );
}
But as you can see, it's a static array of vectors.
If i change it to this:
vector<vector<int>> Edge;
How can i do that for cycle and pushback? I need to create a vector of N+1 size and each position is also a vector.
I need to create a vector of N+1 size and each position is also a vector.
Considering that you know the size of the external container at compile time, you can also use std::array to store the vectors:
std::array<std::vector<int>, N + 1> Edge;
If you don't know the size at compile time, you could use:
std::vector<std::vector<int>> Edge;
but as a general rule of thumb, tend to avoid vectors of vectors, as they don't usually work nicely.
You can construct vectors of a given size by passing an int to their constructor. Then afterwards you can use a loop to initialize the subvectors.
int size;
vector<vector<int>> Edge(size); //Initializes Outer Array to have 'size' elements
for(auto i:Edge)
{
// i is a vector within Edge
}
The advantage is that you don't have to push back. If you still wanted to push_back in order (not have to track an iterator/int) you could use vector.reserve() instead.

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).

inserting into the middle of an array

I have an array int *playerNum which stores the list of all the numbers of the players in the team. Each slot e.g playerNum[1]; represents a position on the team, if I wanted to add a new player for a new position on the team. That is, inserting a new element into the array somewhere near the middle, how would I go about doing this?
At the moment, I was thinking you memcpy up to the position you want to insert the player into a new array and then insert the new player and copy over the rest of it?
(I have to use an array)
If you're using C++, I would suggest not using memcpy or memmove but instead using the copy or copy_backward algorithms. These will work on any data type, not just plain old integers, and most implementations are optimized enough that they will compile down to memmove anyway. More importantly, they will work even if you change the underlying type of the elements in the array to something that needs a custom copy constructor or assignment operator.
If you have to use an array, after having made sure you have enough storage (using realloc if necessary), use memmove to shift the items from the insertion point to the end by one position, then save your new player at the desired location.
You can't use memcpy if the source and target areas overlap.
This will fail as soon as the objects in your array have non-trivial copy-constructors, and it's not idiomatic C++. Using one of the container classes is much safer (std::vector or std::list for instance).
Your solution using memcpy is correct (under few assumptions mentionned by other).
However, and since you are programming in C++. It is probably a better choice to use std::vector and its insert method.
vector<int> myvector (3,100);
myvector.insert ( 10 , 42 );
An array takes a contiguous block of memory, there is no function for you to insert an element in the middle. you can create a new one of size larger than the origin's by one then copy the original array into the new one plus the new member
for(int i=0;i<arSize/2;i++)
{
newarray[i]<-ar[i];
}
newarray[i+1]<-newelemant;
for(int j=i+1<newSize;j++,i++)
{
newarray[i]<-ar[i];
}
if you use STL, ting becomes easier, use list.
As you're talking about an array and "insert" I assume that it is a sorted array. You don't necessarily need a second array provided that the capacity N of your existing array is large enough to store more entries (N>n, where n is the number of current entries). You can move the entries from k to n-1 (zero-indexed) to k+1 to n, where k is the desired insert position. Insert the new element at index position k and increase n by one. If the array is not large enough in the beginning, you can follow your proposed approach or just reallocate a new array of larger capacity N' and copy the existing data before applying the actual insert operation described above.
BTW: As you're using C++, you could easily use std::vector.
While it is possible to use arrays for this, C++ has a better solutions to offer. For starters, try std::vector, which is a decent enough general-purpose container, based on a dynamically-allocated array. It behaves exactly like an array in many cases.
Looking at your problem, however, there are two downsides to arrays or vectors:
Indices have to be 0-based and contiguous; you cannot remove elements from the middle without losing key/value associations for everything after the removed element; so if you remove the player on position 4, then the player from position 9 will move to position 8
Random insertion and deletion (that is, anywhere except the end) is expensive - O(n), that is, execution time grows linearly with array size. This is because every time you insert or delete, a part of the array needs to be moved.
If the key/value thing isn't important to you, and insertion/deletion isn't time critical, and your container is never going to be really large, then by all means, use a vector. If you need random insertion/deletion performance, but the key/value thing isn't important, look at std::list (although you won't get random access then, that is, the [] operator isn't defined, as implementing it would be very inefficient for linked lists; linked lists are also very memory hungry, with an overhead of two pointers per element). If you want to maintain key/value associations, std::map is your friend.
Losting the tail:
#include <stdio.h>
#define s 10
int L[s];
void insert(int v, int p, int *a)
{
memmove(a+p+1,a+p,(s-p+1)*4);
*(a+p) = v;
}
int main()
{
for(int i=0;i<s;i++) L[i] = i;
insert(11,6, L);
for(int i=0;i<s;i++) printf("%d %d\n", L[i], &L[i]);
return 0;
}

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.