I want to store 256*256 entries in a 2D array. I am doing like this:
struct Data
{
int Serial_Number;
int NextIndex;
} ;
struct Data Index[256][256];
Data obj1;
obj1.Serial_Number=1;
obj1.NextIndex=5;
Index[3][240]=obj1;
Now once I have stored all these values then How will I retrieve each value from an array element?
Like I want to retrieve a value stored at Index[3][240].
Secondly, Is this approach faster than unordered_map?
struct Data
{
int Serial_Number;
int NextIndex;
} ;
struct Data Index[256][256]; //should be this
Data obj1;
obj1.Serial_Number=1;
obj1.NextIndex=5;
Index[3][240]=obj1;
retrive the data:
struct Data data = Index[3][240];
acceess the struct's data:
data.Serial_Number;
If you want to retrieve each value one by one, just use the index from Index[0][0] to Index [256-1][256-1]. but if you want to access specific element from the array, you need to loop the array to find it.
for(int i = 0; i < 256; ++i)
for(int j = 0; j < 256; ++j)
if(Index[i][j] == what you are looking for)
{
found!
}
time complexity of this is O(m*n)(m is the length and n is width of the array) while unordered_map::find() runs in O(1) in the best case, O(n) in worst case (n is the number of elements, this may happen when the hash function is not good leading to too many hash collisions since unordered_map use hash table in its implementation).
Related
In the constructor of a class called Stamp have two vectors:
vector<double> data has a size of data.size()
vector<vector <double>> collectedData has a size of [nsamples][data.size()/nsamples]
I need to cycle them in order to have something like this:
collectedData[0][0->nsamples] has the first "nsamples" elements of data
'collectedData[1][0->nsamples]' has the second "nsamples" elements of data
...
'collectedData[i][0->nsamples]' has the i'th "nsamples" elements of data (and '0' if I went over data.size())
This is the C++ code I'm trying, but I receive a segmentation fault. And I don't understand if it is an algorithmic problem, or a wrong usage of vector problem:
Stamp(vector<double> data, int nsamples) : data(data), nsamples(nsamples){
long ll = data.size()/nsamples;
int row;
//Reserve space in collectedData:
collectedData.reserve(nsamples);
for (int i=0;i<nsamples;i++){
collectedData[i].reserve(ll);
}
for (int i=0;i<=data.size();i+=nsamples){
for (int j=0;(j<=nsamples)&&((row*i)<data.size());j++){
collectedData[i].push_back(data[i]);
}
row++;
}
}
Firstly, the reserve() function only reserves space without actualy adding elements. You should use resize() to add (or remove) elements.
Secondly, the condition i<=data.size() in the for loop is wrong. You cannot use data[data.size()]. It should be i<data.size().
Thirdly, there doesn't seem a guarantee that data.size() <= nsamples, so you should add elements again not to cause out-of-range access by collectedData[i] in the second for loop.
Finally, as #molbdnilo pointed out in the comment, the value of non-static local variable row is used without initialization. You should set some proper value to the variable before using that.
Stamp(vector<double> data, int nsamples) : data(data), nsamples(nsamples){
long ll = data.size()/nsamples;
int row = 0; // initialize row
//Reserve space in collectedData:
if (collectedData.size() < nsamples){
collectedData.resize(nsamples); // use resize() to add elements
}
if (collectedData.size() < data.size()){
collectedData.resize(data.size()); // use resize() again to allocate enough size
}
for (int i=0;i<nsamples;i++){
collectedData[i].reserve(ll); // using reserve() here because elements are added via push_back() later
}
for (int i=0;i<data.size();i+=nsamples){ // use correct condition
for (int j=0;(j<=nsamples)&&((row*i)<data.size());j++){
collectedData[i].push_back(data[i]);
}
row++;
}
}
The two structures used in my code, one is nested
struct Class
{
std::string name;
int units;
char grade;
};
struct Student
{
std::string name;
int id;
int num;
double gpa;
Class classes[20];
};
I am trying to figure out a way to sort the structures within the all_students[100] array in order of their ID's in ascending order. My thought was, to start counting at position 1 and then compare that to the previous element. If it was smaller than the previous element then I would have a temporary array of type Student to equate it to, then it would be a simple matter of switching them places within the all_students array. However, when I print the results, one of the elements ends up being garbage numbers, and not in order. This is for an intermediate C++ class in University and we are not allowed to use pointers or vectors since he has not taught us this yet. Anything not clear feel free to ask me.
The function to sort the structures based on ID
void sort_id(Student all_students[100], const int SIZE)
{
Student temporary[1];
int counter = 1;
while (counter < SIZE + 1)
{
if (all_students[counter].id < all_students[counter - 1].id)
{
temporary[0] = all_students[counter];
all_students[counter] = all_students[counter - 1];
all_students[counter - 1] = temporary[0];
counter = 1;
}
counter++;
}
display(all_students, SIZE);
}
There are a few things wrong with your code:
You don't need to create an array of size 1 to use as a temporary variable.
Your counter will range from 1 to 100, you will go out of bounds: the indices of an array of size 100 range from 0 to 99.
The following solution uses insertion sort to sort the array of students, it provides a faster alternative to your sorting algorithm. Note that insertion sort is only good for sufficiently small or nearly sorted arrays.
void sort_id(Student* all_students, int size)
{
Student temporary;
int i = 1;
while(i < size) // Read my note below.
{
temporary = all_students[i];
int j = i - 1;
while(j >= 0 && temporary.id < all_students[j].id)
{
all_students[j+1] = all_students[j]
j--;
}
all_students[j+1] = temporary;
i++;
}
display(all_students, size);
}
Note: the outer while-loop can also be done with a for-loop like this:
for(int i = 1; i < size; i++)
{
// rest of the code ...
}
Usually, a for-loop is used when you know beforehand how many iterations will be done. In this case, we know the outer loop will iterate from 0 to size - 1. The inner loop is a while-loop because we don't know when it will stop.
Your array of Students ranges from 0, 99. Counter is allowed to go from 1 to 100.
I'm assuming SIZE is 100 (in which case, you probably should have the array count also be SIZE instead of hard-coding in 100, if that wasn't just an artifact of typing the example for us).
You can do the while loop either way, either
while(counter < SIZE)
and start counter on 0, or
while (counter < SIZE+1)
and start counter on 1, but if you do the latter, you need to subtract 1 from your array subscripts. I believe that's why the norm (based on my observations) is to start at 0.
EDIT: I wasn't the downvoter! Also, just another quick comment, there's really no reason to have your temporary be an array. Just have
Student temporary;
I overlooked the fact that I was allowing the loop to access one more element than the array actually held. That's why I was getting garbage because the loop was accessing data that didn't exist.
I fixed this by changing while (counter < SIZE + 1)
to: while (counter < SIZE )
Then to fix the second problem which was about sorting, I needed to make sure that the loop started again from the beginning after a switch, in case it needed to switch again with a lower element. So I wrote continue; after counter = 1
I want to make a map such that a set of pointers point to arrays of dynamic size.
I did use hashing with chaining. But since data I am using it for is huge, the program give std::bad_alloc after few iterations. The reason of which may be new used to generate the linked list.
Someone please suggest which data structure shall I use?
Or anything else that can improve memory usage with my hash table?
Program is in C++.
This is what my code looks like:
Initialization of hashtable:
class Link
{
public:
double iData;
Link* pNext;
Link(double it) : iData(it)
{ }
void displayLink()
{ cout << iData << " "; }
};
class List
{
private:
Link* pFirst;
public:
List()
{ pFirst = NULL; }
void insert(double key)
{
if(pFirst==NULL)
pFirst = new Link(key);
else
{
Link* pLink = new Link(key);
pLink->pNext = pFirst;
pFirst = pLink;
}
}
};
class HashTable
{
public:
int arraySize;
vector<List*> hashArray;
HashTable(int size)
{
hashArray.resize(size);
for(int j=0; j<size; j++)
hashArray[j] = new List;
}
};
main snippet:
int t_sample = 1000;
for(int i=0; i < k; i++) // initialize random position
{
x[i] = (cal_rand() * dom_sizex); //dom_sizex = 20e-10 cal_rand() generates rand no between 0 and 1
y[i] = (cal_rand() * dom_sizey); //dom_sizey = 10e-10
}
for(int t=0; t < t_sample; t++)
{
int size;
size = cell_nox * cell_noy; //size of hash table cell_nox = 212, cell_noy = 424
HashTable theHashTable(size); //make table
int hashValue = 0;
for(int n=0; n<k; n++) // k = 10*212*424
{
int m = x[n] /cell_width; //cell_width = 4.7e-8
int l = y[n] / cell_width;
hashValue = (kx*l)+m;
theHashTable.hashArray[hashValue]->insert(n);
}
-------
-------
}
First things first, use a Standard Container. In your specific case, you might want:
either std::unordered_multimap<int, double>
or std::unordered_map<int, std::vector<double>>
(Note: if you do not have C++11, those are available in Boost)
Your main loop becomes (using the second option):
typedef std::unordered_map<int, std::vector<double>> HashTable;
for(int t = 0; t < t_sample; ++t)
{
size_t const size = cell_nox * cell_noy;
// size of hash table cell_nox = 212, cell_noy = 424
HashTable theHashTable;
theHashTable.reserve(size);
for (int n = 0; n < k; ++n) // k = 10*212*424
{
int m = x[n] / cell_width; //cell_width = 4.7e-8
int l = y[n] / cell_width;
int const cellId = (kx*l)+m;
theHashTable[cellId].push_back(n);
}
}
This will not leak memory (reliably), although of course you might have other leaks, and thus will give you a reliable baseline. It is also probably faster than your approach, with a more convenient interface, etc...
In general you should not re-invent the wheel, unless you have a specific need that is not addressed by the available wheels or you are actually trying to learn how to create a wheel or to create a better wheel.
The OS has to solve the same issues with the memory pages, maybe it's worth looking at how that is done? First of all, let's assume all pages are on the disk. A page is a fixed size memory chunk. For your use case, let's say it's an array of your records. Because RAM is limited, the OS maintains a mapping between the page number and it's location in RAM.
So, let's say your pages have 1000 records, and you want to access record 2024, you would ask the OS for page 2, and read record 24 from that page. That way, your map is only 1/1000 in size.
Now, if your page has no mapping to a memory location, then it is either on disk or has never been accessed before (is empty). Then you need to swap out another page, and load that page from disk (and update the location mapping).
This is a very simplified description of what happens and i wouldn't be surprised if someone jumps me in the neck for describing it like this.
The point is:
What does this mean for you?
First of all, your data exceeds your RAM - you won't get around writing to disk, if you don't want to try compression first.
Second, your chains can work as pages if you want, but i wonder whether just paging your hashcode would work better. What i mean is, use the upper bits as page number, and the lower bits as offset in the page. Avoiding collisions is still key, as you want to load the least pages possible. You can still chain your pages, and end up with a much smaller map.
Second - a crucial part is deciding which pages to swap out to make room for the new pages. LRU should do ok. If you can better predict which pages you will (not) need, so much better for you.
Third - you need placeholders for your pages to tell you whether they are in-memory or on disk.
Hope this helps.
I have a Deque that contains this kind of stucts.
struct New_Array {
array<array<int,4>,4> mytable;
int h;
};
In this stuct 2 different arrays may have same value of h.
deque<New_Array> Mydeque;
I also know how many different h are in the deque(the value of steps). And how many stucts are in the deque(Mydeque.size()).
I need to print one array for each h. Starting from h=0 till h=steps (steps is a known int value). Each array that is going to be printed must be the closer to the end of the deque.
I tried something like this:
void foo(deque<New_Array> Mydeque, int steps)
for(int i=0; i<steps; i++)
{
deque<New_Array>::iterator it;
it = find(Mydeque.begin(),Mydeque.end(),i);
PrintBoard(*it); // This if a function where you enter the New_Array struct
// and it prints the array
}
}
The above gives me : error C2679: binary '==' : no operator found which takes a right-hand operand of type 'const bool' (or there is no acceptable conversion)
Or something like this:
void foo(deque<New_Array> Mydeque, int steps)
for(int i=0; i<steps; i++)
{
deque<New_Array>::iterator it;
for(unsigned int j=0;j<Mydeque.size();j++)
{
it = find_if(Mydeque.begin(),Mydeque.end(),Mydeque[j].h==i);
PrintBoard(*it);
break;
}
}
The above gives me: error C2064: term does not evaluate to a function taking 1 arguments
EDIT: The deque is not sorted. For each h an array should be printed. This array should be the one that is at this moment closer to the end of the deque.
Remember the last value and skip:
assert(!Mydeque.empty());
int old_h = Mydeque[0].h + 1; // make sure it's different!
for (std::size_t i = 0, end != Mydeque.size(); i != end; ++i)
{
if (Mydeque[i].h == old_h) continue;
print(Mydeque[i]);
old_h = Mydeque[i].h;
}
Firstly, note that you declare your std::array on the stack, so the storage will also be on the stack. This means that iterating over the structure involves loading a (4*4+1)*int for each comparison. If this is performance-sensitive, I would suggest using std::vector since the load will be only of the outer vector pointer and the h when only comparing h.
struct New_Array {
vector<vector<int,4>,4> mytable;
int h;
};
Secondly, if you need to access these tables through their h values, or access all the tables with a given h at once, make it easier for everyone and store them as vectors in a map, or a sorted vector of vectors:
std::map<int,std::vector<New_Array> > rolodex;
rolodex[someNewArray.h].push_back(someNewArray);
If you construct this in-order, then the first item in each vector will be the one to print:
for(auto it : rolodex) {
vector<New_Array> tablesForThisH = it->second;
if(tablesForThisH.begin() != tablesForThisH.end())
PrintBoard(it->second[0]);
}
Since std:map stores (and iterates) its keys in ascending (I think) order, this will run over the different h values in ascending order. Again it will only need to load the stack-stored struct, which is just the h int and the vector header (probably 12 bytes, as mentioned in this question).
Forgive me if the code is wrong, my stl is a little rusty.
Loop through the deque, and insert all elements into a map, using h as the key. Since your set of h values seems to be sequential, you can use a vector instead, but testing whether an element has already been found will be more difficult.
The solution is :
void Find_Solution_Path(deque<New_Array> Mydeque, int steps)
{
for(int i=0; i<steps+1; i++)
{
for(int j=Mydeque.size()-1;j>-1;j--)
{
if (Mydeque[j].h==i)
{
PrintBoard(Mydeque[j]);
cout<<endl;
break;
}
}
}
}
Suppose I have bunch of numbers. I have to first put the least significant digit into the corresponding bucket. Ex: 530 , I have to first put into the bucket 0. For number 61, I have to put into bucket 1.
I planned to use a multidimensional array to do this. So I create a 2-dimenional array, which nrows is 10 ( for 0~ 9) and ncolumns is 999999 ( because I don't know how large will the list be):
int nrows = 10;
int ncolumns = 999999;
int **array_for_bucket = (int **)malloc(nrows * sizeof(int *));
for(i = 0; i < nrows; i++)
array_for_bucket[i] = (int *)malloc(ncolumns * sizeof(int));
left = (a->value)%10;
array_for_bucket[left][?? ] = a->value;
Then I created one node call a. In this node a, there is a value 50. To find out which bucket I want to put it in, I calculate "left" and I got 0. So I want to put this a-> value into bucket 0. But now I am stuck. How do I put this value into the bucket? I have to use a pointer array to do this.
I thought for a long time but still couldn't find a good way to do it. So please share some ideas with me. thank you!
There is a much easier way of doing this, and instead of radix*nkeys space you only need an nkeys-sized buffer.
Allocate a second buffer that can fit nkeys keys. Now do a first pass through your data and simply count how many keys end up in each bucket. You now can create a radix-sized array of pointers where each pointer is to the start of that bucket in the output buffer. Finally, the second pass though the data moves the keys. Every time you move a key, increment that bucket pointer.
Here's some C code to make into C++:
void radix_sort(int *keys, int nkeys)
{
int *shadow = malloc(nkeys * sizeof(*keys));
int bucket_count[10];
int *bucket_ptrs[10];
int i;
for (i = 0; i < 10; i++)
bucket_count[i] = 0;
for (i = 0; i < nkeys; i++)
bucket_count[keys[i] % 10]++;
bucket_ptrs[0] = shadow;
for (i = 1; i < 10; i++)
bucket_ptrs[i] = bucket_ptrs[i-1] + bucket_count[i-1];
for (i = 0; i < nkeys; i++)
*(bucket_ptrs[keys[i] % 10]++) = keys[i];
//shadow now has the sorted keys
free(shadow);
}
But I may have misunderstood the question. If you are doing something a little different than radix sort, pleas add some details.
Look the Boost Pointer containers library if you want to store pointers.
C++ isn't my forte but this code from wikipedia-Raidx Sort is very comprehensive and probably is more C++-ish than what you've implemented so far. Hope it helps
This is C++, we don't use malloc anymore. We use containers. A two-dimensional array is a vector of vectors.
vector<vector<int> > bucket(10);
left = (a->value)%10;
bucket[left].push_back(a->value);