I'm in the process of trying to learn how to do things in C++, and one of the aspects with which I'm grappling is how to efficiently implement dynamically allocated multidimensional arrays.
For example, say I have an existing function:
void myfunc(int *lambda, int *D, int *tau, int r[*tau][*D])
{
int i, j, k, newj, leftovers;
r[0][0] = *lambda;
j = 0; // j indexes the columns; start with zero
for(i = 1; i < *tau; i++){ // i indexes the rows
leftovers = *lambda;
for(k = 0; k < j; k++){
r[i][k] = r[i - 1][k]; // copy prior to j
leftovers = leftovers - r[i][k];
}
r[i][j] = r[i - 1][j] - 1; // decrement
r[i][j+1] = leftovers - r[i][j]; // initialize to the right of j
if(j == *D - 2){ // second to last column
for(k = 0; k <= j; k++){ if(r[i][k] != 0){ newj = k; } }
j = newj; // can't think of a better way to do this
}else{
j++; // increment j
}
} // next row please
}
From what I've read, it seems a common recommendation is to use std::vector for this purpose. Would anyone care to offer some advice or code snippet on how to implement the r matrix above using the std::vector equivalent?
I would have thought this is a fairly common situation, but interestingly, google turned up fewer than 50 hits for "C99 into C++".
Thank you!
Ben
I think this would be about the most straightforward conversion:
void myfunc(int *lambda, std::vector<std::vector<int> > &r)
{
int i, j, k, newj, leftovers;
int tau = r.size();
r[0][0] = *lambda;
j = 0; // j indexes the columns; start with zero
for(i = 1; i < tau; i++){ // i indexes the rows
int D = r[i].size();
leftovers = *lambda;
for(k = 0; k < j; k++){
r[i][k] = r[i - 1][k]; // copy prior to j
leftovers = leftovers - r[i][k];
}
r[i][j] = r[i - 1][j] - 1; // decrement
r[i][j+1] = leftovers - r[i][j]; // initialize to the right of j
if(j == D - 2){ // second to last column
for(k = 0; k <= j; k++){ if(r[i][k] != 0){ newj = k; } }
j = newj; // can't think of a better way to do this
}else{
j++; // increment j
}
} // next row please
}
You have numerous options.
The quick change:
void myfunc(const int& lambda, const size_t& D, const size_t& tau, int* const* const r) {
...
Using a vector (which will not enforce matching sizes at compilation):
void myfunc(const int& lambda, std::vector<std::vector<int>>& r) {
const size_t tau(r.size()); // no need to pass
const size_t D(r.front().size()); // no need to pass
...
Or using std::array for static sizes:
enum { tau = 5, D = 5 };
void myfunc(const int& lambda, std::array<std::array<int,D>,tau>& r) {
...
Or using template parameters for fixed sizes:
template < size_t tau, size_t D >
void myfunc(const int& lambda, std::array<std::array<int,D>,tau>& r) {
...
or just:
template < size_t tau, size_t D >
void myfunc(const int& lambda, int r[D][tau]) {
...
Note that you can also combine static and dynamic sized arrays as needed in C++.
Finally, Multi Arrays are here to help you: http://www.boost.org/doc/libs/1_53_0/libs/multi_array/doc/user.html
I would change all r[x][y] to R(x,y) and use
int * r;
#define R(x,y) r[ (x) * (*D) + (y) ]
Or maybe change *D to *tau, I can never keep those straight.
Related
void initialize(int arr[], int size[], int n)
{
int i;
for(i = 1; i <= n; i++) {
arr[i] = i;
size[i] = 1;
}
}
class hell
{
public:
int edges;
int vertices;
pair<int , pair<int,int>> p[100000];
int disjoint_set[10000];
int cc_size[10000]; // size of connected components
hell(int e, int v)
{
edges = e;
vertices = v;
initialize(disjoint_set, cc_size, vertices);
}
};
In the following class when I create an object using vertices=100000 and edges=100000, the code stops working. But when we remove the initialize(disjoint_set, cc_size, vertices) it starts working. I don't have any clue to such behavior. Please guide me.
Arrays in C++ are zero indexed, which means that valid index is in [0..n[ range. Your code does it wrong:
for(i = 1; i <= n; i++) {
arr[i] = i;
size[i] = 1;
}
it should be:
for(i = 0; i < n; i++) {
arr[i] = i + 1;
size[i] = 1 + 1;
}
or better use algo std::iota() and std::fill():
std::iota( arr, arr + n, 1 );
std::fill( size, size + n, 1 );
and you better use std::vector, which will adjust its size properly, rather than have huge array.
My code has a 4D matrix in it for some math problem solving
int**** Sads = new int***[inputImage->HeightLines];
for (size_t i = 0; i < inputImage->HeightLines; i++)
{
Sads[i] = new int**[inputImage->WidthColumns];
for (size_t j = 0; j < inputImage->WidthColumns; j++)
{
Sads[i][j] = new int*[W_SIZE];
for (size_t k = 0; k < W_SIZE; k++)
{
Sads[i][j][k] = new int[W_SIZE];
}
}
}
//do something with Sads...
for (int i = 0; i < inputImage->HeightLines; i++)
{
int*** tempI = Sads[i];
for (int j = 0; j < inputImage->WidthColumns; j++)
{
int** tempJ = tempI[j];
for (int k = 0; k < W_SIZE; k++)
{
delete[] tempJ[k];
}
delete[] Sads[i][j];
}
delete[] Sads[i];
}
delete[] Sads;
The sizes are very large WidthColumns = 2018, HeightLines = 1332, W_SIZE =7, the memory allocation is very fast but the memory deallocation (delete) is very slow.
Is there a way to optimize it?
I tired openMP but it throws unrelated errors of missing DLL which are there... if I removed the #pragma omp parallel for everything works fine. but slow...
Using a pointer to a pointer to... is a bad idea because it will fragment your data a lot.
I would create a class ta manage the indices transform and use 1D array, it's a bit more complicated but it will be faster.
Anyway, a trick: nothing prevent you to build your int**** with pointers to a zone in memory that isn't sparse (1D array you preallocated) and then use it as a 4D array.
I'd probably be inclined to use a std::vector. Now memory allocation is taken care of for me (in one allocation/deallocation) and I get free copy/move semantics.
All I have to do is provide the offset calculations:
#include <vector>
#include <cstddef>
struct vector4
{
vector4(std::size_t lines, std::size_t columns)
: lines_(lines), columns_(columns)
, storage_(totalSize())
{}
auto totalSize() const -> std::size_t
{
return lines_ * columns_ * w_size * w_size;
}
int* at(std::size_t a)
{
return storage_.data() + (a * columns_ * w_size * w_size);
}
int* at(std::size_t a, std::size_t b)
{
return at(a) + (b * w_size * w_size);
}
int* at(std::size_t a, std::size_t b, std::size_t c)
{
return at(a, b) + (c * w_size);
}
int& at(std::size_t a, std::size_t b, std::size_t c, std::size_t d)
{
return *(at(a, b, c) + d);
}
private:
std::size_t lines_, columns_;
static constexpr std::size_t w_size = 32; // ?
std::vector<int> storage_;
};
int main()
{
auto v = vector4(20, 20);
v.at(3, 2, 5, 1) = 6;
// other things
// now let it go out of scope
}
The correct way to create, use, and delete a 4D array is this, using the closure of the statement group to delete the automatic variables.
{
const int H = 10;
const int I = 10;
const int J = 10;
const int K = 10;
int h = 0;
int i = 0;
int j = 0;
int k = 0;
int fourDimArray [H][I][J][K];
fourDimArray[h][i][j][k] = 0;
}
If you have a need to dynamically allocate, then use either STL's list or vector class or use something like this with perhaps inline methods to calculate the index of the 1D array from the 4D array indices if you need blazing speed.
int * fourDimArrayAsOneDim = new int[H*I*J*K];
fourDimArrayAsOneDim[indexFromIndices(h, i, j, k)] = 0;
delete [] fourDimArrayAsOneDim;
I have to eliminate duplicates from a array of characters using pointers and a function.
I can t get it to work correctly:
void del_copy(char *p){
int n = strlen(p);
for (int i = 0; i < n; i++){ // Element that we compare
for (int j = i + 1; j < n;j++){ //We compare p + i element with the rest of the elements
if (*(p + i) == *(p + j)){ //If we find two similar, we eliminate that element by shifting
for (int k = i; k < n; k++)
*(p + k) = *(p + k + 1);
}
}
}
}
After you do a shift the length changes. But your n doesn't take that into account.
Here's a simple algorithm:
let s be the empty set (characters encountered so far)
let result be an empty string
for each character c in the input string (
if c is not in s (
include c in s and
append c to the end of result
)
)
result is the result
For the char type on an ordinary machine with 8-bit byte, you can just use a std::bitset as set s.
Another simple algorithm is to sort the string first, if there is no requirement on preserving order. Then you can just scan it and look for duplicates.
sample to fix
void del_copy(char *p){
char c;
for (int i = 0; c=*(p+i); i++){
char *p2, *p3;
for(p2 = p+i+1, p3 = p2; *p3; ++p3){
if(*p3 != c)
*p2++ = *p3;
}
*p2 = '\0';
}
}
Here's my take at the problem. It basically uses a lookup table to check if the character has been seen before but is templated. You could use any kind of value_type.
#include <algorithm>
#include <unordered_map>
template <typename Container>
Container unique_all(Container const& c) {
Container out;
::std::unordered_map<typename Container::value_type,::std::size_t> lookup;
::std::copy_if(c.begin(), c.end(),
::std::back_inserter(out),
[&](typename Container::value_type ch) {return !lookup[ch]++;});
return out;
}
You can call it like this:
unique_all(::std::string("hello dear world"))
I have managed to fix my own code also. Thank you everyone for support.
I had to change the if loop for a while loop and to decrement de lenght #ScottMcP-MVP.
void del_copy(char *p){
int n = strlen(p);
for (int i = 0; i < n-1; i++){ // Element that we compare
for (int j = i + 1; j < n;j++){ //We compare p + i element with the rest of the elements
while(*(p + i) == *(p + j)){ //If we find two similar, we eliminate that element by shifting
for (int k = j; k < n; k++)
*(p + k) = *(p + k + 1);
n--; //decrement n because the lenght if smaller now
}
}
}
}
I am getting two errors in implementing the algorithm from pseudocode:
One of my problems is int L[n1+1]; error: needs to be a constant; cannot allocate constant size 0. The only way to run this is to make the size a number like 10. I may be implementing the psuedocode wrong that is why I included the statement above that. This may be the cause of my next problem.
My other problem is I am printing only one line of code unsorted. My print function is flawless and works for all of the sorting programs. I believe the MERGE function is only running once. I posted the output of the Sort at the bottom.
I have a random number generator for the array A, from 0 to RAND_MAX.
Initial call is MERGESORT(A,1,n);
void MERGE(int *A, int p, int q, int r)
{
int n1 = q-(p+1);
int n2 = r-q;
//psuedocode states, let L[1..n1+1] & R[1..n1+1] be new arrays
int L[n1+1];
int R[n2+1];
for(int i=1; i<n1;i++)
{
L[i]=A[p+(i-1)];
}
for(int j=1; j<n2; j++)
{
R[j] = A[q+j];
}
L[n1+1]=NULL; //sentinel
R[n2+1]=NULL; //sentinel
int i=1;
int j=1;
for (int k=p; k<r; k++)
{
if(L[i]<=R[j])
{
A[k]=L[i];
i=i+1;
}
else
{
A[k]=R[j];
j=j+1;
}
}
}
void MERGESORT(int *A,int p, int r)
{
if (p<r)
{
int q=floor((p+r)/2);
MERGESORT(A,p,q);
MERGESORT(A,q+1,r);
MERGE(A,p,q,r);
}
}
With int L[10]; and my A[10]; my output is:
Sort: 7474 28268 32506 13774 14411
Press any key to continue . . .
If someone could just assist in the two problems, I more than likely will get it to work.
You are failing to detect the end of your merge arrays:
for (int k=p; k<r; k++)
{
// You need to check that i/j are still in range.
// otherwise the following test are not valid.
if ((i < n1) && (j < n2))
{
if(L[i]<=R[j])
{
A[k]=L[i];
i=i+1;
}
else
{
A[k]=R[j];
j=j+1;
}
}
else
{ /* More work here */
}
Other comments:
Identifiers that are all capitol MERGE MERGESORT are generally reserved for macros. If you use them you are likely to hit problems. Prefer function names of mixed case.
You can simulate arrays with vector:
// Simulate L[1..n1+1]
minI = 1;
maxI = n1-1;
std::vector<int> const L(A+(minI-1), A+(maxI-1));
Arrays in C++ are zero indexed. You seem to be having off by one errors (especially in accessing the end of the array). I would advice you to start the count at 0 rather than 1. Most C++ code is written in terms of iterators from [begining..1PastEnd). I think you will find your algorithm easier to implement if you adapt that style.
There are several issues with your code, I've pointed them out in comments. This is a solution closest to your code, and it's far from best. Consider using C++ containers, like std::vector for example. Naming is at least disputable, and of course merge sort should be implemented as an in place algorithm.
//L and R are auxiliary arrays
//preallocated with (inputSize/2 + 1) constant size
void MERGE(int *A, int p, int q, int r, int* L, int* R)
{
if (p > q || q > r)
{
return;
}
int n1 = q - p + 1;
int n2 = r - q;
// note 0-based indices
int i = 0;
int j = 0;
for(;i < n1;i++)
{
L[i] = A[p + i];
}
for(;j < n2;j++)
{
R[j] = A[q + j + 1]; //+1 because p + n1 - 1 == q + 0
}
//again - note 0-based indices
i = 0;
j = 0;
for (int k = p; k <= r; ++k)
{
// The most important fix - in your code you didn't check
// for left/right array bounds at all.
// Sentinel values aren't needed - size is known
if(i < n1 && (j >= n2 || L[i] <= R[j]))
{
A[k] = L[i];
++i;
}
else if (j < n2)
{
A[k] = R[j];
++j;
}
}
}
void MERGESORT(int* A, int p, int r, int* L, int* R)
{
if (p < r)
{
int q = (p + r) / 2; //floor was redundant
MERGESORT(A, p, q, L, R);
MERGESORT(A, q+1, r, L, R);
MERGE(A, p, q, r, L, R);
}
}
void MERGESORT(int* A, int size)
{
int*L = new int[size/2 + 1]; //preallocate auxiliary arrays
int*R = new int[size/2 + 1]; //size/2 + 1 is what will be needed at most
MERGESORT(A, 0, size - 1, L, R);
delete L;
delete R;
}
int main()
{
int A[5]{ 7474, 28268, 32506, 13774, 14411 };
MERGESORT(A, 5);
for (int i = 0;i < 5;++i)
{
std::cout << A[i] << std::endl;
}
return 0;
}
Output:
7474
13774
14411
28268
32506
Credit goes also to DyP for spotting all the mistakes in the previous version :)
In my solution code for project euler problem 11, I got the following functions. Max_consecutive_prod is a class which calculates the max product of consecutive input()ed numbers, generalised from problem 8. The six functions calculate max product in different series of different directions and start from different edges of the grid.
The only difference in these functions is indexes in for statements, how to elimilate the obvious duplication? The situation here is somehow the opposite to the typical application of template method pattern: the operation is identical but the control framework is different, is there another design pattern for this?
Edit: all the modifications specified in comments are to the (two) for statements, and the loop body in each function is identical to the first.
template <size_t size> unsigned process_row(const unsigned (&grid)[size][size])
{
unsigned prodMax = 0;
for (int i = 0; i < size; ++i)
{
Max_consecutive_prod mcp;
for (int j = 0; j < size; ++j)
{
mcp.input(grid[i][j]);
}
if (mcp.result() > prodMax)
{
prodMax = mcp.result();
}
}
return prodMax;
}
// exchange i, j in process_row
template <size_t size> unsigned process_col(const unsigned (&grid)[size][size])
{
// ...
}
template <size_t size> unsigned process_diag_lower(const unsigned (&grid)[size][size])
{
unsigned prodMax = 0;
for (int init = 0; init < size; ++init)
{
Max_consecutive_prod mcp;
for (int i = init, j = 0; i < size && j < size; ++i, ++j)
// ...
// ...
}
return prodMax;
}
// exchange i, j in process_diag_lower
template <size_t size> unsigned process_diag_upper(const unsigned (&grid)[size][size])
{
// ...
}
// flip j in process_diag_lower
template <size_t size> unsigned process_rev_diag_lower(const unsigned (&grid)[size][size])
{
unsigned prodMax = 0;
for (int init = 0; init < size; ++init)
{
Max_consecutive_prod mcp;
for (int i = init, j = size-1; i < size && j >= 0; ++i, --j)
// ...
// ...
}
return prodMax;
}
// change ++j in process_diag_upper to --j
template <size_t size> unsigned process_rev_diag_upper(const unsigned (&grid)[size][size])
{
unsigned prodMax = 0;
for (int init = 0; init < size; ++init)
{
Max_consecutive_prod mcp;
for (int j = init, i = 0; j >=0 && i < size; ++i, --j)
// ...
// ...
}
return prodMax;
}
Based on random-hacker's code, which shows the real commonality and variability in control flows of the six function, I wrote my version and made the code more self-explaining and C++ idiomatic, using a stragegy class, defining local variables to clarify the code and improve effiency. I define a non-template version of process(), to avoid binary code bloat when instantizing for different size (see 'Effective C++', Item 44).
If you still get confused, please read random-hacker's answer for explanation. :)
namespace Grid_search
{
enum Step { neg = -1, nul, pos };
enum Index_t { i, j };
struct Strategy
{
Step direction[2];
Index_t varOuter;
};
const size_t typeCount = 6;
const Strategy strategy[typeCount] = { {{pos, nul}, i}, {{nul, pos}, j}, {{pos, pos}, i}, {{pos, pos}, j}, {{pos, neg}, i}, {{pos, neg}, j} };
};
template <size_t size> inline unsigned process(const Grid_search::Strategy& strategy, const unsigned (&grid)[size][size])
{
return process(strategy, reinterpret_cast<const unsigned*>(&grid), size);
}
unsigned process(const Grid_search::Strategy& strategy, const unsigned* grid, size_t size)
{
using namespace Grid_search;
const Index_t varOuter = strategy.varOuter, varInner = static_cast<Index_t>(!varOuter);
const Step di = strategy.direction[i], dj = strategy.direction[j];
const unsigned initInner = strategy.direction[varInner] == pos ? 0 : size -1;
unsigned prodMax = 0;
unsigned index[2];
unsigned &indexI = index[i], &indexJ = index[j];
for (unsigned initOuter = 0; initOuter < size; ++initOuter)
{
Max_consecutive_prod mcp;
for (index[varOuter] = initOuter, index[varInner] = initInner;
0 <= indexI && indexI < size && 0 <= indexJ && indexJ < size;
indexI += di, indexJ += dj)
{
mcp.input(grid[indexI*size + indexJ]);
if (mcp.result() > prodMax)
{
prodMax = mcp.result();
}
}
}
return prodMax;
}
int main()
{
static const size_t N = 20;
unsigned grid[N][N];
std::ifstream input("d:/pro11.txt");
for (int count = 0; input >> grid[count/N][count%N]; ++count)
{
}
unsigned prodMax = 0;
for (int i = 0; i < Grid_search::typeCount; ++i)
{
unsigned prod = process(Grid_search::strategy[i], grid);
if (prod > prodMax)
{
prodMax = prod;
}
}
}
Although I think what you already have will be fine after sticking the inner loop code blocks in an ordinary function as suggested by Adam Burry and Tony D, if you want you can combine the loops, using tables to encode the possible directions to move in. The trick is to use an array p[2] instead of separate i and j, to enable the question of which index is varied in the outer loop to be driven by a table. Then the only tricky thing is making sure that the other index, which will be varied in the inner loop, needs to start at its maximum value (instead of 0) iff it will decrement at each step:
enum indices { I, J }; // Can just use 0 and 1 if you want
template <size_t size> unsigned process(const unsigned (&grid)[size][size]) {
static int d[][2] = { {1, 0}, {0, 1}, {1, 1}, {1, -1}, {1, 1}, {1, -1} };
static int w[] = { J, I, J, J, I, I };
unsigned prodMax = 0; // Note: not 1
for (int k = 0; k < sizeof d / sizeof d[0]; ++k) { // For each direction
for (int init = 0; init < size; ++init) {
Max_consecutive_prod mcp;
int p[2]; // p[I] is like i, p[J] is like j
for (p[w[k]] = init, p[!w[k]] = (d[k][!w[k]] == -1 ? size - 1 : 0);
min(p[I], p[J]) >= 0 && max(p[I], p[J]) < size;
p[I] += d[k][I], p[J] += d[k][J])
{
mcp.input(grid[p[I]][p[J]]);
prodMax = max(prodMax, mcp.result());
}
}
}
return prodMax;
}
You could create an enum for the different states and then pass it into the function. You would then create an if statement that would set the values based on the passed value.
Your process_row() has a bug: from the example in the link, zero entries are allowed in the matrix, so if a row begins with e.g.
x y z 0 ...
and any of x, xy or xyz is larger than all other 4-element products on the rest of that row and on any other row in the matrix, it will incorrectly report that the this is the largest 4-element product. (I'm assuming here that Max_consecutive_prod calculates a rolling product of the last 4 elements provided with input()).
Unless your Max_consecutive_prod is unusually aware of how it is being called, you will also get erroneous results "wrapping" from the end of one row to the next, and from one process_...() call to the next.
Suppose you flattened the grid so that it was just 400 numbers in a row, reading left to right and then top to bottom. The topmost row would consist of the first 20 numbers (that is, indices 0, ..., 19); the second rwo of the next 20 numbers, etc. In general, row i (starting from 0) would correspond to indices i*20, i*20 + 1, i*20 + 2, ..., i*20 + 19.
Now, what about columns? The leftmost column starts at position 0, just like the topmost row. It's next element at position 20 (the first element in the second row), and then 40, and... So it's not hard to see that the indices for column j are j, j + 20, j + 40, ..., j + 19*20.
Diagonals are not much different. Try it on paper (grid-ruled paper is good for this sort of thing.)
One more hint: Does it make a difference if you find the product of four elements, multiplying left-to-right, than the same four elements multiplying right-to-left?
First, the Context object approach - this just packages the arguments to the support functions mentioned in my comment on your question... it's about as useful as the problem was significant ;-].
struct Context
{
unsigned& proxMax;
int i, j;
Max_consecutive_prod mcp;
Context(unsigned& prodMax) : prodMax(prodMax) { }
};
template <size_t size> unsigned process_diag_lower(const unsigned (&grid)[size][size])
{
unsigned prodMax = 0;
for (int init = 0; init < size; ++init)
{
Context context(prodMax);
for (context.i = init, context.j = 0; context.i < size && context.j < size; ++context.i, ++context.j)
loop_ij(context);
loop_outer(context);
}
return prodMax;
}
Visitor pattern. Now, I said in my comment "you don't show us enough loop bodies to see the common requirements", and haven't seen anything since, so on the basis of the one body I've seen - namely:
template <size_t size> unsigned process_row(const unsigned (&grid)[size][size])
{
unsigned prodMax = 0;
for (int i = 0; i < size; ++i)
{
Max_consecutive_prod mcp;
for (int j = 0; j < size; ++j)
{
mcp.input(grid[i][j]);
}
if (mcp.result() > prodMax)
{
prodMax = mcp.result();
}
}
return prodMax;
}
The above can be split:
template <size_t size, template Visitor>
unsigned visit_row(const unsigned (&grid)[size][size], Visitor& visitor)
{
for (int i = 0; i < size; ++i)
{
for (int j = 0; j < size; ++j)
visitor.inner{grid[i][j]);
visitor.outer();
}
return visitor.result();
}
struct Visitor
{
unsigned prodMax;
Max_consecutive_prod mcp;
Visitor() : prodMax(0) { }
void inner(unsigned n) { mcp.input(n); }
void outer()
{
if (mcp.result() > prodMax) prodMax = mcp.result();
mcp = Max_consecutive_prod(); // reset for next time...
}
unsigned result() const { return prodMax; }
};
This way, the same Visitor class can be combined with your various grid-element iteration routines.