Store a table of unknown size in C++ - c++

I want to store a table in C++(gcc) whose size I dont know before hand it will be decided on realtime which kind of structure to use??

Make a vector of the structure you use for a record in the table:
vector<MyRecord> v;
You add records (objects of type MyRecord) using:
v.push_back(record);

If you mean arrays that for most purpose std::vector or std::deque is what you are looking for.
std::vector<ClassOrTypeYouNeedToStore> v;
v.push_back(1):
v.push_back(2):
v.push_back(3):
std::cout << "Length of vector " << v.size() << std::endl;
// Before C++11
for (std::vector<int>::iterator it = v.begin(); it != v.end(); it++) {
std::cout << "Next element is " << *it << std::endl;
}
// C++11+
for (auto it = v.begin(); it != v.end(); it++) {
std::cout << "Next element is " << *it << std::endl;
}

It depends what you need to store and what will vary. If the columns are fixed and of different types and you want to be able to insert and remove rows dynamically, you might want a std::vector<std::tuple<T,U,V>> (or instead of a tuple, you can use a struct of some sort).
If the columns are fixed but all the same type, give a std::vector<std::array<T,N>> a go.
If the number of rows and columns are fixed and of the same type then try std::array<std::array<T,N>,M>.
If the number of rows and columns are fixed but each column is of different types, std::array<std::tuple<T,U,V>,N> should suit you fine.
If you want the number of columns to also vary, then you'll want the inner type to be a std::vector of some sort.

Usually in that case I would use std::vector.
size_t rsz = 4;
size_t csz = 4;
std::vector<double> table(rsz*csz, 0.0);
for (size_t i = 0; i < rsz; i++) {
for (size_t j = 0; j < csz; j++) {
table[i*csz+j] = i * 10 + j;
}
}
I tend to prefer 1D vector and just doing the offset arithmetic myself. It keeps your helper functions from being over-specialized.

As suggested, you can use vector<vector<CellType>>, vector<RowType>, or, if by "size" you mean "the number of lines" you can use vector<array<RowSize, CellType>> (my favourite solution).
Arrays have the advantage of constant length (performance, memory footprint, memory alignment), and in this solution you get about the same flexibility as in a relational DB.

Related

How do you iterate on first N elements of a container?

I have created a set of pairs in C++ to hold potentially colliding pairs of particles for a simple particle simulation as follows:
std::set<std::pair<int, int>> uniquePairs;
Once populated I want to iterate through it ONLY for the live particles in the simulation to check the distances between them for interaction later. I can iterate through the complete set like so...
std::set<std::pair<int,int>>::iterator it;
for (it = uniquePairs.begin(); it != uniquePairs.end(); ++it)
{
std::cout << it->first << std::endl;
}
BUT, this will throw up a vector 'out of range' error since I would be trying to access particles that are not yet alive. Therefore I want to be able to access the list UP TO the same number of live particles .. i.e N = particles.size().
Please help,
Many thanks!
Not absolutely clear in the question, If the question is, 'How to iterate on first N elements of a container?', below is the way to do it.
void foo(std::set<std::pair<int,int>>& uniquePairs, int N) {
auto it = uniquePairs.begin();
for (int i = 0; i < N; ++i)
{
std::cout << it->first << std::endl;
++it;
assert(it != uniquePairs.end());
}
}
CC: https://gcc.godbolt.org/z/tSHQYP

C++ Persistent Vector, fill vector with data from a text file

i am currently trying to learn some C++ and now i got stuck in an exercise with vectors. So the task is to read ints from a text file and store them in the vector which should be dynamic.
I guess there is something wrong with the while-loop?
If I start this, the program fails and if I set the vector size to 6, I get
6 0 0 0 0 0 as output.
Thanks for any hints.
int main()
{
const string filename = "test.txt";
int s = 0;
fstream f;
f.open(filename, ios::in);
vector<int> v;
if (f){
while(f >> s){
int i = 0;
v[i] = s;
i = i+1;
}
f.close();
}
for(int i = 0; i < 6; i++){
cout << v[i] << "\n";
}
}
You don't grow the vector. It is empty and cannot hold any ints. You'll need to either resize it every time you want to add another int or you use push_back which automatically enlarges the vector.
You set i = 0 for every iteration so you would change the first value of the vector every iteration instead of the next one.
Go for:
v.push_back(s);
in your loop and
for(int i = 0; i < v.size(); i++) { // ...
Remark:
You normally don't hardcode vector sizes/bounds. One major point about using std::vector is its ability to behave dynamically with respect to its size. Thus, the code dealing with vectors should not impose any restrictions about the size of the vector onto the respective object.
Example:
for(int i = 0; i < 6; i++){ cout << v[i] << "\n"; }
requires the vector to have at least 6 elements, otherwise (less than 6 ints) you access values out of bounds (and you potentially miss elements if v contains more than 6 values).
Use either
for(int i = 0; i < v.size(); i++){ cout << v[i] << "\n"; }
or
for(std::vector<int>::const_iterator i = v.begin(); i != v.end(); ++i)
{
cout << *i << "\n";
}
or
for(auto i = v.begin(); i != v.end(); ++i)
{
cout << *i << "\n";
}
or
for(int x : v){ cout << x << "\n"; }
or
for(auto && x : v){ cout << x << "\n"; }
or
std::for_each(v.begin(), v.end(), [](int x){ std::cout << x << "\n"; });
or variants of the above which possibly pre-store v.size() or v.end()
or whatever you like as long as you don't impose any restriction on the dynamic size of your vector.
The issue is in the line i= 0. Fixing that will give an issue in the line v[i] = s.
You always initialise i to 0 in the while loop, and that is responsible for the current output. You should shift it out of the while loop.
After fixing that, you have not allocated memory to that vector, and so v[i] doesn't make sense as it would access memory beyond bounds. This will give a segmentation fault. Instead, it should be v.push_back(i), as that adds elements to the end of a vector, and also allocates memory if needed.
If you are using std::vector you can use v.push_back(i) to fill this vector
Error is this line int i = 0;
because you declare i=0 every time in while-loop.
To correct this move this line outside from loop.
Note: this will work, if you declare v like normal array for example int v[101]
When you use std vectors you can just push element at the end of vector with v.push_back(element);
v[i] = s; //error,you dont malloc room for vector
change into : v.push_back(s);

accessing a specific point of a vector with an iterator

I am trying to figure out the best way of accessing a position in a vector using an iterator. I'm aware iterators behave like pointers, so this is the only method I came up with. I would like to know if there's a better or just a different way. Here's the code:
//This is a pointer to a vector of the class Particle BTW. vector < Particle > *particleList;
vector<Particle>::iterator it = particleList->begin();
// I assign a specific position outside the loop to a new iterator that won't be affected
vector<Particle>::iterator it2 = particleList->begin() + 3;
for( it; it != particleList->end(); it++){
it->draw();
//I'm interested in the velocity of this element in particular
cout << it2->vel << endl;
}
Thanks,
M
Try the following
for (auto i = particleList->begin(); i < particleList->begin(); ++i) {
i->draw();
std::cout << (i+3)->vel << "\n";
}
Note, there is no reason to use std::endl, std::endl has an implicit flush which lowers performance when outputting to say a log file, and when outputting to console it is already line buffered meaning that a line ending will already flush.
Note 2, you can only use + with i since i is a random access iterator because particleList is a std::vector, if you change say particleList to a std::list then the iterator will be a bidirectional iterator instead of a random access iterator and you will not be able to use + in that case you would need to use std::advance like WhozCraig mentioned, but do so on a copy like so:
for (auto i = particleList->begin(); i < particleList->begin(); ++i) {
i->draw();
auto i2 = i;
std::advance(i2, 3)
std::cout << i2->vel << "\n";
}
Though personally, in this case I would just iterate with two iterators instead of std::advance since std::advance is linear in time. Do something like:
auto i = particleList->begin();
auto i2 = particleList->begin();
std::advance(i2, 3);
for (; i < particleList->end(); ++i, ++i2) {
i->draw();
std::cout << i2->vel << "\n";
}
Note 3: (i+3) and i2 will run off the end of your list (vector), so do something smart there.

Why can't I insert 6 million elements in STL set?

I am trying to insert a little over 6.5 million elements(ints) in an stl set. Here is the code:
set<int> s;
cout << s.max_size() << endl;
for(int i = 0; i < T.MULT * T.MAXP; i++) {
s.insert(a[i]);
}
T.MULT is 10; T.MAXP is 666013.
a is an array - statically allocated - (int a[T.MULT * T.MAXP];) that contains distinct elements.
After about 4.6 million elements s.insert() throws a bad_alloc exception. The resource monitor available on Windows 7 says I have 3 GB free memory left.
What am I doing wrong? Why can't STL set allocate the memory?
Edit: Here is the full code: http://ideone.com/rdrEnt
Edit2: apparently the inserted elements might not be distinct after all, but that should not be a problem.
Edit3: Here is a simplified version of the code: http://ideone.com/dTp0fZ
The problem actually lies in the fact that you statically allocated the array A with more than 6.5 million elements, which corrupts your program stack space. If you allocate the array on the heap, it actually works. I did some code change based on your description, it worked fine.
int *A = new int[T.MULT * T.MAXP];
for (int i= 0; i < T.MULT * T.MAXP; ++i)
{
A[i] = i; //for simplicity purpose, your array may have different elem. values
}
set<int> s;
for (int i = 0; i < T.MULT * T.MAXP; ++i )
{
s.insert(A[i]);
}
cout << s.size();
set<int>::iterator iter;
int count = 0;
for (iter = s.begin(); iter != s.end(); ++ iter)
{
cout << *iter << " ";
count ++;
if (count == 100)
{
cout <<endl;
count = 0;
}
}
delete [] A;
return 0;
It worked perfectly fine with both vector and set. It can print all those 6.6 million elements on the screen.
As other posts indicated, you may also want to try STXXL if you have interest.
You might want to take a look at STXXL.
While I can't answer your question directly, I think it is more efficient to store your data in a std::vector, sort it, and then use std::binary_search to test for the existence of the item. Storage in a std::set is relatively expensive compared to that of std::vector. That's because there is some overhead when storing each element.
As an example, here's how you could do it. This sorts the static array.
std::sort(a,a+(T.MULT*T.MAXP));
bool existence=std::binary_search(a,a+(T.MULT*T.MAXP),3);
Fast and easy.

tallying elements in an array

So, I'm trying to tally the elements of an array. By this I mean, I have a large array, and each element will have multiples of itself throughout the array. I am trying to figure out how many times each element occurs, however I keep running into the issue of there being duplicate tallies. Since "x" could exist at 12 different places in the array, when I loop through it and keep a running sum, I get the tally for "x" 12 different times. Does anyone know of a simpler/better way to keep a tally of an array with no duplicates?
My code is:
where count is the number of elements
for(i=0;i<count;i++)
{
for(x=0; x<count;x++)
{
if(array[i]==array[x])
{
tallyz++;
}
}
tally[i]=tallyz-1;
tallyz=0;
}
}
std::map<X, unsigned> tally;
for(i = 0; i < count; ++i)
++tally[array[i]];
Note that this is best if the redundancy in the array is fairly high. If most items are unique you're probably better just sorting the array as others have mentioned.
If you can sort the array, simply sort it. Then all you have left is a linear scan of the elements, checking if the element behind this one is the same as the current element (don't forget bounds checking).
As an alternative to sorting, you could use a map:
template<class T, size_t N>
void printSums(T (array&)[N]) {
map<T, size_t> m;
for(T*p = array; p < array+N; ++p) {
++m[*p];
}
for(map<T,size_t>::iterator it = m.begin(); it != m.end(); ++it) {
cout << it->first << ": " << it->second << "\n";
}
}
Warning: this is untested code.
first use a map just as John said,then traverse the tally array:
std::map<X, unsigned> data;
for(i = 0; i < count; i++)
data[array[i]]++;
for(i = 0; i < count; i++)
tally[i]=data[tally[i]]-1;