In my learning process about C++, I am having hard time understanding the best practice for initializing a vector in this particular setting:
struct Data {
vector<int> vec;
Data(const int k) {
for (int i = 0; i < k; i++) vec.push_back(0);
}
};
so that in the main function I just declare Data mydata(10); and mydata will have an attribute vector mydata.vec of k=10 elements.
However, I really find unefficient that one has to setup a for loop and fill mydata.vec element by element, so looking online I found other methods that honestly I did not understand. Anyway, I tried to replace that given constructor with
Data(const int k) {
vec.resize(k);
}
and
Data(const int k) : vec(k,0) {}
with either error messages about modified objects already deleted or segmentation faults happening during runtime. Would you please explain the most C++'ish or most efficient way to initialise a vector in such framework? Consider that for some reason I have little to no understanding about what an initialization list is.
EDIT:
Here I propose a minimal example directly taken from my code:
#include <iostream>
#include <vector>
using namespace std;
struct Data {
vector<unsigned int> mydata, count;
Data(const unsigned int k) {
for (unsigned int i = 0; i < 2 * k; i++) {
mydata.push_back(i + 1);
//count.push_back(0); // HERE 1
}
count.resize(k); // HERE 2
}
void update_stats(const unsigned int p) { count[mydata[0] - 1] += 1; }
};
void twist(Data& stuff, const unsigned int m) {
unsigned int temp;
for (unsigned int i = m; i < 2 * m; i++) {
temp = stuff.mydata[i];
stuff.mydata.erase(stuff.mydata.begin() + i);
stuff.mydata.insert(stuff.mydata.begin() + (i - m) * 2, temp);
}
stuff.update_stats(m);
}
int main() {
unsigned int p, k = 200;
Data stuff(k);
for (p = 1; p <= k; p++) twist(stuff, p);
for (p = k; p >= 1; p--) twist(stuff, p);
cout << stuff.count[stuff.mydata[0] - 1] << endl;
return 0;
}
I am sorry to not to do better in reducing further. This code produces a segmentation fault. However, commenting the HERE 2 line and using HERE 1 apparently saves the situation. I don't get why.
After the for loop
for (unsigned int i = 0; i < 2 * k; i++)
count.push_back(0);
the count vector will contain 2k zeros. But after count.resize(k) it will contain only k zeros.
Fixed constructor might look like this:
Data(const unsigned int k) : mydata(2 * k), count(2 * k, 0) {
std::iota(mydata.begin(), mydata.end(), 1u);
}
To assign sequentially increasing sequence to mydata, you can use std::iota algorithm. , 0 can be dropped without changing the behaviour, but you might want to be explicit about the initial value.
Semantics of these two constructors is very simple:
explicit vector(size_type count);
Constructs the container with count default-inserted instances of T. No copies are made.
vector(size_type count, const T& value);
Constructs the container with count copies of elements with value value.
For T = unsigned int, the "default-inserted instance" is just 0u.
Related
I am learning C++ with experiencein mostly Python, R and SQL.
The way arrays (and vectors which differes somehow from 1d-arrays? and matrices which are 2d-arrays?) work in C++ seems quite different as I cannot specify the size of dimension of the array with an argument from the function.
A toy-example of my goal is some thing like this:
Have a function my_2d_array which takes two arguments M and N and returns a matrix or 2d-array of dimension (MxN) with elements indicating the position of that element. E.g. calling my_2d_array(4,3) would return:
[[00, 01, 02],
[10, 11, 12],
[20, 21, 22],
[30, 31, 32]]
The main function should execute my_2d_array and be able to potentially perform calculations with the result or modify it.
This is my attempt (with errors):
int my_2d_array(int N, int M) {
int A[N][M];
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
std::string element = std::to_string(i) + std::to_string(j);
A[i][j] = element;
}
}
return A;
}
void main() {
int N, M;
N = 4;
M = 3;
int A[N][M] = my_2d_array(N, M);
// Print the array A
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
std::cout << A[i][j] << " ";
}
std::cout << "\n";
}
}
One (1) dimensional attempt of #JustLearning's suggestion:
int my_array(int N) {
std::array<int, N> A;
for (int i = 0; i < N; i++) {
A[i] = i;
}
return A;
}
int main() {
int N = 4;
int A[N] = my_array(N);
// Print the array A
for (int i = 0; i < N; i++) {
std::cout << A[i] << " ";
}
}
You can use a 2d vector like this
vector<vector int> A;
It works the same way as a 2d array
Welcome to C++! Your function my_2d_array has a couple of issues:
the return type is int, however you are attempting to return an array of ints.
the identifier of an array in C++ is actually a pointer to the first element of that array. Therefore, when you return A, you must be aware of how it should be passed to a new variable in the main part of the code. In particular, your code is passing a reference to a temporary variable A, which is not permitted or safe.
In addition, in C++, unless you know what you're doing, main should always return an int:
int main() { ... }
What is not clear from your question is whether you are attempting to implement your own "array" class, or simply want to use arrays already established in the standard. For the latter, std::array is a good place to start. The advantage is that you can return std::arrays from functions like you return ints or doubles.
std::arrays are good if you plan to work with arrays of fixed size, as the size becomes part of the type: std::array<int, 3> my_array;. Then you can fill it in manually or with member functions of the class (see dox linked above).
If for some reason you prefer to work with arrays of dynamical size (sizes that will change during running your program), std::vector is the way to go.
Finally, if you are actually learning C++ by attempting to implement a container MyArray, you should specify that in your question and be a bit more specific in what help you need.
Here's a working example in 1d:
#include <iostream>
#include <array>
template <int N>
std::array<int, N> my_array() {
std::array<int, N> A;
for (int i = 0; i < N; i++) {
A[i] = i;
}
return A;
}
int main() {
const int N = 4;
std::array<int, N> arr = my_array<N>();
// Print the array A
for (int i = 0; i < N; i++) {
std::cout << arr[i] << " ";
}
}
Since the size of a std::array is included it its type, you need to create a function template, which is basically a function that works for different types. (In C++, std::array<int, 3> and std::array<int, 4> are considered different types.)
In order to use this in main, the index is promoted to a const int, as plain ints can vary during run time, and therefore are not suitable for defining types. (In C++ jargon, look up constant expressions).
Finally, note that both the return type and the type of the variable that receives the value returned by the function must be std::array, not int as you tried in your 1d code.
Following your comment, I can see why you are confused in your attempts to use a matrix in code.
There are many types of containers in C++. Many of them you can find in the standard library (std::vector, std::list, std::set, ...), others you can create yourself or use other libraries. Plain arrays (like int a[5]) are a somewhat unique case because they come from C and are part of the language itself.
A plain array lives on the stack (not very important but you might want to read up on stack vs heap allocations), and refers to a contiguous region of memory.
If you declare some array a like int a[5], you get a region of 5 integers one after the other, and you can point to the first one by just writing a. You can access each of them using a[i] or, equivalently, *(a+i).
If you declare a like int a[5][3], you now get a region of 15 integers, but you can access them slightly differently, like a[i][j], which is equivalent to *(a+i*3+j).
The important thing to you here is that the sizes (5 and 3) must be compile-time constants, and you cannot change them at runtime.
The same is true for std::array: you could declare a like std::array<std::array<int, 3, 5> a and get a similar region of 15 integers, that you can access the same way, but with some convenience (for example you can return that type, whereas you cannot return a plain array type, only a pointer, losing the size information in the process).
My advice is not to think of these arrays as having dimensionality, but as simple containers that give you some memory to work with however you choose. You can very well declare a like std::array<int, 15> a and access elements in a 2D way by indexing like this: a[i*3+j]. Memory-wise, it's the same.
Now, if you want the ability to set the sizes at runtime, you can use std::vector in a similar way. Either you declare a like std::vector<std::vector<int>> a(5, std::vector<int>(3)) and deal with the nested vectors (that initialization creates 5 std::vector<int> of size 3 each), or you declare a as a single vector like std::vector<int> a(15) and index it like a[i*3+j]. You can even make your own class that wraps a vector and helps with the indexing.
Either way, it's rare in C++ to need a plain array, and you should generally use some kind of container, with std::vector being a good choice for a lot of things.
Here is an example of how your code would look like using vectors:
#include <vector>
#include <string>
#include <iostream>
std::vector<std::string> my_2d_array(int N, int M) {
std::vector<std::string> A(N*M);
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
std::string element = std::to_string(i) + std::to_string(j);
A[i*M+j] = element;
}
}
return A;
}
int main() {
int N, M;
N = 4;
M = 3;
std::vector<std::string> A = my_2d_array(N, M);
// Print the array A
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
std::cout << A[i*M+j] << " ";
}
std::cout << "\n";
}
}
And here is a very crude example of a Matrix class used to wrap the vectors:
#include <vector>
#include <string>
#include <iostream>
template<typename T>
class Matrix {
public:
Matrix(int rowCount, int columnCount) : v(rowCount*columnCount), columnCount(columnCount) {}
T& operator()(int row, int column) {
return v[row*columnCount + column];
}
private:
std::vector<T> v;
int columnCount;
};
Matrix<std::string> my_2d_array(int N, int M) {
Matrix<std::string> A(N, M);
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
std::string element = std::to_string(i) + std::to_string(j);
A(i, j) = element;
}
}
return A;
}
int main() {
int N, M;
N = 4;
M = 3;
Matrix<std::string> A = my_2d_array(N, M);
// Print the array A
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
std::cout << A(i, j) << " ";
}
std::cout << "\n";
}
}
Input : {10,9,8,7,6,5,4,3,2,1}
Output : {8,7,6,9,10,5,4,3,2,1}
I'm not sure what the issue is. I think it has something to do with the recursion in mergesort. I'm new to recursion so my understanding is not too good. Any hints?
#include <iostream>
void mergeSort(int a[], int w[], int n);
void merge(int a[], int w[], int n);
using namespace std;
void mergeSort(int a[], int t[], int n) {
if (n > 1) {
for (int i = 0; i < n/2; i++) {
t[i] = a[i];
}
mergeSort(a, t, n/2);
for (int i = n/2; i < n; i++) {
t[i] = a[i];
}
mergeSort(a, t, n/2);
merge(a, t, n/2);
}
}
void merge(int a[], int t[], int n) {
int leftIndex = 0, leftEnd = n/2;
int rightIndex = n/2, rightEnd = n;
int targetIndex = 0;
while (leftIndex < leftEnd && rightIndex < rightEnd) {
if (t[leftIndex] < t[rightIndex])
a[targetIndex++] = t[leftIndex++];
else
a[targetIndex++] = t[rightIndex++];
}
while (leftIndex < leftEnd) {
a[targetIndex++] = t[leftIndex++];
}
while (rightIndex < rightEnd) {
a[targetIndex++] = t[rightIndex++];
}
}
int main() {
const int SIZE = 10;
int a[] = {10,9,8,7,6,5,4,3,2,1};
int w[SIZE];
mergeSort(a,w,SIZE);
for (int i = 0; i < SIZE; i++) {
cout << a[i] << " ";
}
cout << endl;
}
The general problem is pointer confusion. One of the C language quirks that is not immediately obvious is that in
void mergeSort(int a[], int t[], int n);
both a and t are not arrays, but pointers. There is a special rule for this in the language standard. What this means is that in all instantiations of mergeSort on the call stack, t and a refer to the same areas of memory, and this means that every time you do something like
for (int i = 0; i < n/2; i++) {
t[i] = a[i];
}
you're changing the same region of memory. After you've done so and returned to the previous call frame, this region no longer contains the data you expect it to contain.
The way to solve this is to define a temporary local buffer where you need it, which is in merge. For example:
const int SIZE = 10;
// mergeSort is much simpler now:
void mergeSort(int a[], int n) {
if (n > 1) {
// sort the left side, then the right side
mergeSort(a , n / 2);
mergeSort(a + n / 2, n - n / 2);
// then merge them.
merge(a, n);
}
}
// Buffer work done in merge:
void merge(int a[], int n) {
// temporary buffer t, big enough to hold the left side
int t[SIZE];
int leftIndex = 0 , leftEnd = n / 2;
int rightIndex = n / 2, rightEnd = n ;
int targetIndex = 0;
// copy the left side of the target array into the temporary
// buffer so we can overwrite that left side without worrying
// about overwriting data we haven't yet merged
for(int i = leftIndex; i < leftEnd; ++i) {
t[i] = a[i];
}
// then merge the right side and the temporary buffer to
// the left side. By the time we start overwriting stuff on
// the right side, the values we're overwriting will have been
// merged somewhere into the left side, so this is okay.
while (leftIndex < leftEnd && rightIndex < rightEnd) {
if (t[leftIndex] < a[rightIndex]) {
a[targetIndex++] = t[leftIndex++];
} else {
a[targetIndex++] = a[rightIndex++];
}
}
// If there's stuff in the temporary buffer left over,
// copy it to the end of the target array. If stuff on the
// right is left over, it's already in the right place.
while (leftIndex < leftEnd) {
a[targetIndex++] = t[leftIndex++];
}
}
Before explaining the errors, let me first emphasize that a function argument like int a[] is nothing more than a pointer passed to the function. It points to a region of memory.
Now, mergesort requires some temporary memory and works by
copying the data to the temporary memory;
sorting each half of the data in temporary memory;
merging the two halves, whereby writing into the original array.
In step 2, the original array is not needed and can serve as temporary memory for the recursion.
In view of these facts, your code contains two errors:
You don't use the arrays t[] and a[] appropriately. The idea is that a[] is both input and output and t[] a temporary array. Internally, data are first copied to the temporary array, each half of which is sorted, before merging them fills the original array a[].
You don't sort the second half of the temporary array, but the first half twice.
A correct implementation is, for example,
void mergeSort(int*a, int*t, int n) {
if (n > 1) {
for (int i = 0; i < n; i++)
t[i] = a[i]; // copy to temporary
mergeSort(t , a , n/2); // sort 1st half of temporary
mergeSort(t+n/2, a+n/2, n-n/2); // sort 2nd half of temporary
merge(a, t, n);
}
}
Note that since t[] and a[] are pointers, the operation t+n/2 simply obtains the pointer to the second half of the array. The result of your code with this alteration is 1 2 3 4 5 6 7 8 9 10.
First of all, I don't want to use sort. This is just an illustration example. The main purpose of this question is that I want to:
find all possible combinations of m numbers out of n numbers and
process them, then return the unique processed result (since the
processed results of all possible combinations will be compared).
Question start at here
The following code get all possible combinations M numbers out of N numbers. Sum the M numbers and find the largest sum. In doing this I used a recursion function.
However, it seems that I must define a global variable to store the temporary largest sum. Is there any way to get rid of this global variable? For example, define the recursion function to return the largest sum... I don't want the global variable just become an argument &max_sum in the find_sum, since find_sum already have too many arguments.
#include <iostream>
#include <vector>
void find_sum(const std::vector<int>& ar, std::vector<int>& combine,
int index, int start);
int max_sum =0;
int main() {
int N = 10;
int M = 3;
std::vector<int> ar(N);
ar = {0,9,2,3,7,6,1,4,5,8};
int index = 0, start =0;
std::vector<int> combine(M);
find_sum(ar, combine, index, start);
std::cout << max_sum <<std::endl;
return 0;
}
void find_sum(const std::vector<int>& ar, std::vector<int>& combine,
int index, int start) {
if(index == combine.size()) {
int sum =0;
for(int i=0; i<index; ++i) {
sum += combine[i];
}
if(max_sum < sum) {
max_sum = sum;
}
return ;
}
for(int i = start;
i < ar.size() && ar.size()-i > combine.size()-index;
++i) {
combine[index] = ar[i];
find_sum(ar, combine, index+1, start+1);
}
}
An approach that scales well is to turn find_sum into a function object. The trick is to define a struct with an overloaded () operator that takes a certain set of parameters:
struct FindSum
{
void operator()(const std::vector<int>& ar, std::vector<int>& combine,
int index, int start){
/*ToDo - write the function here, a very explicit way of
/*engineering the recursion is to use this->operator()(...)*/
}
int max_sum; // I am now a member variable
};
Then instantiate FindSum find_sum;, set find_sum.max_sum if needed (perhaps even do that in a constructor), then call the overloaded () operator using find_sum(...).
This technique allows you to pass state into what essentially is a function.
From find_sum, return the so-far maximum sum (instead of void). That means that the recursion-terminating code would be:
if(index == combine.size()) {
int sum =0;
for(int i=0; i<index; ++i) {
sum += combine[i];
}
return sum;
}
and the recursive part would be
int max_sum = 0;
for(int i = start;
i < ar.size() && ar.size()-i > combine.size()-index;
++i) {
combine[index] = ar[i];
int thismaxsum = find_sum(ar, combine, index+1, start+1);
if(thismaxssum > max_sum)
max_sum = thismaxsum;
}
return max_sum;
So, the overall solution is:
#include <iostream>
#include <vector>
int find_sum(const std::vector<int>& ar, std::vector<int>& combine,
int index, int start);
int main() {
int N = 10;
int M = 3;
std::vector<int> ar(N);
ar = { 0,9,2,3,7,6,1,4,5,8 };
int index = 0, start = 0;
std::vector<int> combine(M);
int max_sum = find_sum(ar, combine, index, start);
std::cout << max_sum << std::endl;
return 0;
}
int find_sum(const std::vector<int>& ar, std::vector<int>& combine,
int index, int start)
{
if (index == combine.size())
{
int sum = 0;
for (int i = 0; i<index; ++i)
{
sum += combine[i];
}
return sum;
}
int max_sum = 0;
for (int i = start;
i < ar.size() && ar.size() - i > combine.size() - index;
++i)
{
combine[index] = ar[i];
int thismaxsum = find_sum(ar, combine, index + 1, start + 1);
if (thismaxsum > max_sum)
max_sum = thismaxsum;
}
return max_sum;
}
Global variables are much better then adding operands and variables to recursion functions because each operand and variable causes heap/stack trashing negatively impact performance and space usage risking stack overflow for higher recursions.
To avoid global variables (for code cosmetics and multi threading/instancing purposes) I usually use context or temp struct. For example like this:
// context type
struct f1_context
{
// here goes any former global variables and stuff you need
int n;
};
// recursive sub function
int f1_recursive(f1_context &ctx)
{
if (ctx.n==0) return 0;
if (ctx.n==1) return 1;
ctx.n--;
return (ctx.n+1)*f1_recursive(ctx.n);
}
// main API function call
int f1(int n)
{
// init context
f1_context ctx;
ctx.n=n;
// start recursion
return f1_recursion(ctx);
}
the f1(n) is factorial example. This way the operands are limited to single pointer to structure. Of coarse you can add any recursion tail operands after the context... the context is just for global and persistent stuff (even if I did use it for the recursion tail instead but that is not always possible).
I am trying to learn c++. I have created a vector class vec and I am trying to implement a method to compute the dot product.
It compiles fine but I get a segmentation error when running it. I have pinned the x(i) reference in the dot product method down as the cause, but I have no idea why. I gather it is something about accessing memory incorrectly, but I have no idea what I am doing incorrectly nor what the correct way would be.
My vector class:
class vec{
private:
vector<double> data;
int n; // size
public:
vec (int s) { n = s; data.reserve(n); }
double get(int i) { return data[i]; }
void set(int i, double val) { data[i] = val; }
int size() { return n; }
double operator[] (int i) { return get(i); }
double operator() (int i) { return get(i); }
double dot (vec x) {
assert(n == x.size());
int z = 0;
for (int i = 0; i < n; i++){
z += data[i] * x(i);
}
return z;
}
};
I am trying to use it like so:
int main(int argc, char *argv[]) {
vec x = vec(3);
x.set(0, 1);
x.set(1, 1);
x.set(2, 2);
vec y = vec(3);
y.set(0, 2);
y.set(1, 2);
y.set(2, 3);
double z = x.dot(y);
}
Change this:
data.reserve(n);
To this:
data.resize(n);
The reserve does not create the items in a vector. All it does is increase the capacity. To actually create n objects up front, you use resize.
Also on a side note, I highly suggest you not use extraneous variables such as n to keep track of a vector's size. Use the vector::size() function instead. The reason is that you're risking bugs if for some reason n is not updated correctly.
Thus this should be your constructor:
vec (int s) : data(s) {}
and dump the n member variable.
In this clause:
vec y = vec(3);
y.set(0, 2);
y.set(1, 2);
y.set(2, 3);
You're setting index 3, which is out of bounds of this vector. To fix it, either initialize vec to be of length 4, or index somewhere else. :)
You should also be resizing instead of reserving, but getting this wrong shouldn't cause a segfault. It should just confuse people.
I'm writing a program that counts all binary trees with n nodes and height k. Every node has 0 or 2 children. The program works but I wanted to add some memoization because the answer is always the same for some particular n and k.
I could create an multidimensional array of pairs but I already have my useful struct now. How could I declare and use this mem variable. I didn't find a good answer on this. I understand pointers but I would prefer a method without memory management.
This is an exercise from the USACO training program btw.
#include <iostream>
#include <fstream>
#include <string>
#include <cmath>
using namespace std;
struct state {
int down, half;
state(int d, int h) : down(d), half(h) {}
int valid() {
return down != -1 && half != -1;
}
};
state mem[200][100];
state cnt(int n, int k)
{
if (mem[n][k].valid())
return mem[n][k];
if (n == 1)
return state(k == 1, k != 1);
if (n > pow(2, k) - 1)
return state(-1, -1);
state total(0, 0);
for (int i = 1; i < n - 1; ++i) {
state left = cnt(i, k - 1);
state right = cnt(n - i - 1, k - 1);
if (left.valid() && right.valid()) {
total.down += left.down * right.down +
left.down * right.half +
left.half * right.down;
total.half += left.half * right.half;
}
}
return mem[n][k] = state(total.down % 9901, total.half % 9901);
}
int main()
{
ofstream fout ("nocows.out");
ifstream fin ("nocows.in");
int n, k;
fin >> n >> k;
for (int i = 0; i <= n; ++i)
for (int j = 0; j <= k; ++j)
mem[i][j] = state(-1, -1);
cout << cnt(n, k).down << endl;
return 0;
}
You can use a vector of vectors:
std::vector<std::vector<state> > mem;
You can dynamically add to it and needn't worry about size (although if you roughly know the size, you can pre-allocate it to avoid resizing), and also memory clean-up is automatic - when the vector goes out of scope, its components will also be deleted.
Your code doesn't work because you don't have a default constructor for state.
The thing is, when you write state mem[200][100]; the compiler will try to create 100*200 state objects, but it can't. To make this work, you'd need a default constructor in state:
struct state {
state() : down(0), half(0) {} //default constructor
int down, half;
state(int d, int h) : down(d), half(h) {}
int valid() {
return down != -1 && half != -1;
}
};