C++ pair data type issue - c++

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

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.

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.

Filling a vector with out-of-order data in C++

I'd like to fill a vector with a (known at runtime) quantity of data, but the elements arrive in (index, value) pairs rather than in the original order. These indices are guaranteed to be unique (each index from 0 to n-1 appears exactly once) so I'd like to store them as follows:
vector<Foo> myVector;
myVector.reserve(n); //total size of data is known
myVector[i_0] = v_0; //data v_0 goes at index i_0 (not necessarily 0)
...
myVector[i_n_minus_1] = v_n_minus_1;
This seems to work fine for the most part; at the end of the code, all n elements are in their proper places in the vector. However, some of the vector functions don't quite work as intended:
...
cout << myVector.size(); //prints 0, not n!
It's important to me that functions like size() still work--I may want to check for example, if all the elements were actually inserted successfully by checking if size() == n. Am I initializing the vector wrong, and if so, how should I approach this otherwise?
myVector.reserve(n) just tells the vector to allocate enough storage for n elements, so that when you push_back new elements into the vector, the vector won't have to continually reallocate more storage -- it may have to do this more than once, because it doesn't know in advance how many elements you will insert. In other words you're helping out the vector implementation by telling it something it wouldn't otherwise know, and allowing it to be more efficient.
But reserve doesn't actually make the vector be n long. The vector is empty, and in fact statements like myVector[0] = something are illegal, because the vector is of size 0: on my implementation I get an assertion failure, "vector subscript out of range". This is on Visual C++ 2012, but I think that gcc is similar.
To create a vector of the required length simply do
vector<Foo> myVector(n);
and forget about the reserve.
(As noted in the comment you an also call resize to set the vector size, but in your case it's simpler to pass the size as the constructor parameter.)
You need to call myVector.resize(n) to set (change) the size of the vector. calling reserve doesn't actually resize the vector, it just makes it so you can later resize without reallocating memory. Writing past the end of the vector (as you are doing here -- the vector size is still 0 when you write to it) is undefined behavior.

How to access an index in a vector without segfaulting

I know this is simple, so I apologize in advance.
I am segfaulting when trying to access a vector by index. For example...
vector<float> some_vec;
int i = 0;
for (some iterator loop here)
{
//snip
some_vec[i] = some_float;
i++;
}
What am I doing wrong?
After
std::vector<float> some_vec;
your vector is empty. You must not access any element in it then, because there isn't any.
If you want to put values into it, you need to append them to the vector using push_back()
for (some iterator loop here)
{
//snip
some_vec.push_back(some_float);
i++;
}
Alternatively, if you know the size in advance, and if the construction of dummy values in the vector is cheap (as it is for float and other built-ins), you can resize() the vector in advance
some_vec.resize(42);
or create it with the right amount of elements
std::vector<float> some_vec(42);
Given either of the two above, you can then access elements 0..41 in the vector.
call resize() function on your vector and then call push_back() to add elements. After this you can access elements using indexing.
Possibly a problem elsewhere in code we can't see, but mostly likely given you've not called resize(), push_back() or insert() that i is outside of the vector. Use some_vec.at(i) = some_float; to check that i is within the valid range for the vector.
My guess is that your vector is empty. Use push_back(some_float) to add elements to it.

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;
}