Problems using 3-dimensional vector - c++

How can I work with a 3 dimensional vector in C++?
vector<vector<vector<int> > > vec (1,vector<vector<int> >(1,vector <int>(1,12)));
When I try something like this
cout << vec[0][0][0]; vec[0][0][1] = 13;
everything works just fine.
The problem is that I can only change the last elements. If I try accessing the first and second element, like this
vec[0][1][0] = 13;
or this
vec.push_back(vector<vector<int > >());
vec[0].push_back(vector<int>());
v[1][0].push_back(13);
my program crashes.
How can I add and access elements in a 3d vector?

I would never do vector<vector<vector<int> > > as in this way you have many allocations what could be expensive. I would simply use vector<int> with smart indexing (e.g.: see below). If you will work with double based matrices, in this way intel MKL or any other BLAS library easily could be used.
Its price is increased complexity when matrix sizes are changed, but you could win many in performance.
Useful link: C++ FAQ.
static int const M = 16;
static int const N = 16;
static int const P = 16;
inline int& set_elem(vector<int>& m_, size_t i_, size_t j_, size_t k_)
{
// you could check indexes here e.g.: assert in debug mode
return m_[i_*N*P + j_*P + k_];
}
inline const int& get_elem(const vector<int>& m_, size_t i_, size_t j_, size_t k_)
{
// you could check indexes here e.g.: assert in debug mode
return m_[i_*N*P + j_*P + k_];
}
vector<int> matrix(M*N*P, 0);
set_elem(matrix, 0, 0, 1) = 5;

vector<vector<vector<int> > > vec (1,vector<vector<int> >(1,vector <int>(1,12)));
cout << vec[0][0][0]; vec[0][0][1] = 13;
evething is OK.
You are mistaken. Everything is not OK. The vector vec[0][0] has only one element and thus vec[0][0][1] is out of bounds and therefore the assignment has undefined behaviour. You have the same problem with vec[0][1][0] = 13; and v[1][0].push_back(13)
You can fix that by accessing only indices that exist in your vectors. If you want more than one element, then either construct the vectors with more elements initially, or push them after construction.
At the begining I have 1x1x1 vector. So how can I push elements. using push_back() ? For example I have 1x1x1 and I want to add v[1][1][0] = 2 ?
If you for some reason want to start with 1x1x1 vector of vectors of vectors of ints and want to access v[1][1][0], here is example code to add the v[1][1][0] element with minimal changes to the original vector:
// vector of ints that contains one element, 2
// this will vector eventually be the v[1][1] and the integer element will be v[1][1][0]
// since we initialize the integer as 2, there's no need to assign it later though
vector<int> vi(1, 2);
// vector of vectors that contains one default constructed vector
// vvi will eventually be the v[1] element and the default constructed vector will be v[1][0]
vector<vector<int>> vvi(1);
// push vi into vvi, making it vvi[1] and eventually v[1][1]
vvi.push_back(vi);
// push vvi into v, making it v[1]
v.push_back(vvi);

What you have,
vector<vector<vector<int> > > vec (1,vector<vector<int> >(1,vector <int>(1,12)));
creates 1 x 1 x 1 matrix with the value of the only element set to 12.
To create something that is analogous to a M x N x P matrix, you need to use:
vector<vector<vector<int> > > vec (M,vector<vector<int> >(N,vector <int>(P,x)));
That will create an M x N x P matrix with the value of each element set to x.

Related

C++ - A 3-d data structure - should I use vector of pointers or vector of vectors?

I have to maintain a data structure which is 3 dimensional. So let us say it's dimensions are :- l x m x n. In the program that I wish to write l and m will be known since the time the data structure is being constructed . But n has to be dynamic throughout runtime. And n may be different for the different vectors in the grid lxm. (Once this structure is created I never intend to destruct it as I will be needing it throughout).
For the moment let us assume it's a 2-dimensional data structure that I wish to make, should I make a vector<vector<int>> or a vector<vector<int>*> ? Also I know how I might initialise the vector to the required size in the first case, i.e I might do something like :-
vector<vector<int> > A(m)
to initialise the size of the outer dimension to m. But in the second case, once I have created a vector of pointers to vectors, how do I create the vectors to which the pointers point.
Carrying this to the 3-d case, should I use ,
a vector<vector<vector>> or a vector<vector<vector*>> or some other combination ?
Please, suggest any changes so that I may reframe the question if it's not framed properly.
You're better using a single vector (and not nested ones), since the memory is guaranteed to be contiguous in this case and your code will be way faster due to no cache misses. In this case, you need to map from 3D (2D) to 1D and vice-versa, but this is pretty straightforward
for 2D:
(x,y) <-> y*DIM_X + x;
for 3D:
(x,y,z) <-> z*(DIM_Y*DIM_X) + y*DIM_X + x;
If you really insist to use nested vectors, you can do something like:
#include <vector>
template<typename T>
using vec = std::vector<T>; // to save some typing
int main()
{
// creates a 5 x 4 x 3 vector of vector of vector
vec<vec<vec<double>>> v{5, vec<vec<double>>{4, vec<double>{3}}};
}
EDIT
Responding to your latest edit: use
std::vector<std::vector<double>> v{DIM_X*DIM_Y, std::vector<double>};
// address (x,y,z)
v[y*DIM_X+x, z] = val_x_y_z;
If you further happen to know the dimensions of the inner vectors, you can preallocate memory for them using std::vector::reserve. This will speed things up since there won't be any (slow) re-allocations.
No, use a proper multidimensional array: Boost MultiArray http://www.boost.org/doc/libs/1_59_0/libs/multi_array/doc/user.html
#include "boost/multi_array.hpp"
int main () {
// Create a 3D array that is 3 x 4 x 2
typedef boost::multi_array<int, 3> array_type;
typedef array_type::index index;
array_type A(boost::extents[3][4][2]);
// Assign values to the elements
int values = 0;
for(index i = 0; i != 3; ++i)
for(index j = 0; j != 4; ++j)
for(index k = 0; k != 2; ++k)
A[i][j][k] = values++;
}

Accessing a dynamic vector of vector

Here is my code:
std::vector< std::vector<int> > v;
v.push_back(std::vector<int>(2));
v[0].push_back(10);
std::cout<<(v[0])[0];
But it prints "0" instead of 10.
I am trying to make a dynamic vector that holds a vector with fixed size.
Can someone help me visualize what's happening?
The code is buggy:
std::vector<int>(2)
makes a vector of size 2 initialized with deault constructed int (which is zero), so pushing 10 just makes a vector of size 3 w/ 10 at the end (index 2).
After reading more about push_back, here's what i understand so far and how i fixed it
std::vector< std::vector<int> > vo; //empty vector of vectors
v.push_back(std::vector<int>(2)); //insert element
v.push_back(std::vector<int>(2)); //insert element
v[0][0] = 1;
v[0][1] = 2; //allocated so it's alright to add elements
v[1][0] = 3;
v[1][1] = 4;
std::cout<<v[1][1]; //4

Not getting the input values when printing vector of pairs

I want to add a pair to a vector of pairs.
When I print the vector elements, I don't get the integers I input.
Please help.
#include<iostream>
#include<vector>
#include<utility>
using namespace std;
int main()
{
vector<vector<unsigned long int> >matrix;
vector<pair<int,int> >pmat;
int L;
cin>>L;
int n1, n2;
pmat.resize(L);
for(int k = 0; k<L; k++)
{
cin>>n1>>n2;
pair<int,int> p = make_pair(n1,n2);
cout<<p.first<<p.second<<endl;
pmat.push_back(p);
}
for(int k = 0; k<L; k++)
{
cout<<pmat[k].first<<','<<pmat[k].second<<' ';
}
cout<<endl;
return 0;
}
Method 1:
Delete this line:
pmat.resize(L);
You don't need to resize it in the first place as you do push_back() when adding afterwards.
Method 2:
Change the following line
pmat.push_back(p);
to
pmat[k] = p;
You can do resize() in the first place, but after this, you should not use push_back() when adding, just use pmat[k] = p.
PS: you should not mix these two ways up. Always use one of them consistently.
Since you're using pmat.resize(L) and L times pmat.push_back(...), you're ending up having stored 2 * L entries in your vector. However you're printing just the first half, index 0 to L - 1. The values you want are stored from index L to 2 * L - 1.
Just change pmat.resize(L) to pmat.reserve(L).
Alternatively, you can use the resize(L), but to end up with L entries, you need to store each input pair to pmat[k], hence you write pmat[k] = p;.
As a rule of thumb, I recommend using the reserve + push_back approach if you know how many elements you're going to add. The reason is, that resize initializes the elements, while reserving just asserts that there will be enough space and no reallocation will be necessary with any following push_back.
You don't want to add more pairs after you allocated them. You can now directly access them.
Just use pmat[k] = p; instead of pmat.push_back(p);
If you print the size of the vector after reading the values, you will notice a small problem with your program:
./test
2
1 2
12
3 4
34
Size of the vector: 4
0,0 0,0
Huh? Even though I only entered 2 pairs, the size of the vector is 4. How did this happen?
If you look at the documentation for resize, it says
Resizes the container to contain count elements.
So even before you read any values, your vector will already contain 2 elements! Those will be default-constructed and therefore be 0. When you then push_pack the elements you read in, those will land at the indices 2 and 3 in the vector, so the end vector has twice as much elements as you wanted (4 in this case). You only print out the first half, which are the zero values.
The solution is to use reserve instead of resize, which doesn't create the elements but only reserves space for them, or just delete the call to resize. Using reserve is more efficient though, because then the vector will only need to allocate memory once.
pmat.resize(L);
if vector in empty its going to initialize a vector pmat with size L then assign default values to vector so now pmat size is L with default values
for(int k = 0; k<L; k++)
{
cin>>n1>>n2;
pair<int,int> p = make_pair(n1,n2);
cout<<p.first<<p.second<<endl;
pmat.push_back(p);
}
then u r pushing values to pmat L times so the final size is 2*L
for(int k = 0; k<L; k++)
{
cout<<pmat[k].first<<','<<pmat[k].second<<' ';
}
here u r going to read from 0 to L-1 , it contains default values you can see your values from L-1 to 2L-1.
so finally what i want say is use reserve instead of resize
or
pmat.resize(L); comment this line

sort one vector in a class and the second vector should move with the first

I want to sort a vector<vector<double> > and record the original index with vector<int>
ex A[0][1].............[N], and A[0][0] = X, A[0][1] = Y, A[0][2] = Z
A[0] = (1,5,3), A[1] = (3,2,1) A[2] = (2,8,4) after sorting
index: 0 1 2
A[0] = (1,5,3), A[1] = (2,8,4) A[2] = (3,2,1)
original index : 0 2 1
so I write the following code, and I want to use the STL sort, but I don't know how to write the compare function.
class point{
public:
point(int totalLength = 0, int elementLength = 0);
vector<vector<double> > pointSet;
vector<double> pointIndex;
};
point::point(int totalLength, int elementLength){
pointSet.resize(totalLength,vector<double>(elementLength, 0));
pointIndex.resize(elementLength);
}
and suggestion or other way to achieve it?
Thank for your reading.
The first thing I'm talking about is introducing separate data structure for points. Usually, when you talk about points and some geometry, you know exact number dimensions.
So, you can use
struct Point
{
double x;
double y;
double z;
};
instead of
std::vector<double>
Even if you do not know number of dimensions, you'd better use
typedef std::vector<double> Point;
to represent a single point.
And your std::vector<std::vector<double> > becomes std::vector<Point>. It is just easier to read at least.
Then, it is impossible to sort 2 arrays simultaneously, using std::sort. So, you have to combine your pointSet and pointIndex array in one data structure to sort.
An obvious way, you can create
typedef std::pair<Point, int> IndexedPoint;
std::vector<IndexedPoint> indexedPoints;
Then you fill this structure with given points and its indexes and then sort:
for(int indx = 0; indx < pointsSet.size(); ++indx) {
indexedPoints.push_back(std::make_pair(pointsSet[indx], indx));
}
std::sort(indexedPoints.begin(), indexedPoints.end(), &lessThen);
Less then implementation depends on algorithm of comparison. For example, if you want to compare point by first coordinate, you can write
bool lessThen(const IndexedPoint& l, const IndexedPoint& r)
{
return l.first.x < r.first.x; //or return l.first[0] < r.first[0]; -- ensure point has at lest 1 dimension here!
}

Multi-dimensional vector

How can I create a 2D vector? I know that in 2D array, I can express it like:
a[0][1]=98;
a[0][2]=95;
a[0][3]=99;
a[0][4]=910;
a[1][0]=98;
a[1][1]=989;
a[1][2]=981;
a[1][3]=987;
How can one do this using the C++ STL Vector?
vector<vector<int> > a;
If you want to define the rows and columns,
vector<vector<int> > a{{11, 2, 4}, {4, 5, 6}, {10, 8, -12}};
std::vector< std::vector< int > > a; // as Ari pointed
Using this for a growing matrix can become complex, as the system will not guarantee that all internal vectors are of the same size. Whenever you grow on the second dimension you will have to explicitly grow all vectors.
// grow twice in the first dimension
a.push_back( vector<int>() );
a.push_back( vector<int>() );
a[0].push_back( 5 ); // a[0].size() == 1, a[1].size()==0
If that is fine with you (it is not really a matrix but a vector of vectors), you should be fine. Else you will need to put extra care to keep the second dimension stable across all the vectors.
If you are planing on a fixed size matrix, then you should consider encapsulating in a class and overriding operator() instead of providing the double array syntax. Read the C++ FAQ regarding this here
std::vector< std::vector<int> > a;
//m * n is the size of the matrix
int m = 2, n = 4;
//Grow rows by m
a.resize(m);
for(int i = 0 ; i < m ; ++i)
{
//Grow Columns by n
a[i].resize(n);
}
//Now you have matrix m*n with default values
//you can use the Matrix, now
a[1][0]=98;
a[1][1]=989;
a[1][2]=981;
a[1][3]=987;
//OR
for(i = 0 ; i < m ; ++i)
{
for(int j = 0 ; j < n ; ++j)
{ //modify matrix
int x = a[i][j];
}
}
If you don't have to use vectors, you may want to try Boost.Multi_array. Here is a link to a short example.
Declaration of a matrix, for example, with 5 rows and 3 columns:
vector<vector<int> > new_matrix(5,vector<int>(3));
Another way of declaration to get the same result as above:
vector<int> Row;
One row of the matrix:
vector<Row> My_matrix;
My_matrix is a vector of rows:
My_matrix new_matrix(5,Row(3));
dribeas' suggestion is really the way to go.
Just to give a reason why you might want to go the operator() route, consider that for instance if your data is sparse you can lay it out differently to save space internally and operator() hides that internal implementation issue from your end user giving you better encapsulation and allowing you to make space or speed improving changes to the internal layout later on without breaking your interface.
Just use the following method to use 2-D vector.
int rows, columns;
// . . .
vector < vector < int > > Matrix(rows, vector< int >(columns,0));
Or
vector < vector < int > > Matrix;
Matrix.assign(rows, vector < int >(columns, 0));
// Do your stuff here...
This will create a Matrix of size rows * columns and initializes it with zeros because we are passing a zero(0) as a second argument in the constructor i.e vector < int > (columns, 0).
As Ari pointed, vector< vector< int>> is the right way to do it.
In addition to that, in such cases I always consider wrapping the inner vector (actually, whatever it represents) in a class, because complex STL structures tend to become clumsy and confusing.