c++ push back an array in a vector - c++

i have an array of 9 numbers and my functions in my number class are used to reorder the 9 numbers in the array without any duplicate of numbers and then to list the number of times the rand() function was called.
I now need to generate ten lists of the numbers and store them into a vector.
here is the code:
class numbers{
private:
int indexCount;
public:
void swap (int *a, int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
void printArray (int arr[], int n)
{
for (int i = 0; i < n; i++)
cout << arr[i] << " ";
cout << "random calls: " << indexCount <<endl;
}
void randomize (int arr[], int n)
{
indexCount=0;
srand (time(NULL));
for (int i = n - 1; i > 0; i--)
{
int j = rand() % (i + 1);
indexCount++;
swap(&arr[i], &arr[j]);
}
}
};
class numbersVector{
private:
vector <int>numberList;
public:
numbers num;
void storeInVector(int arr[], int n){
for (int i=0; i <10; i++){
num.randomize(arr,n);
num.printArray(arr,n);
numberList.push_back(arr[i]);
}
cout <<endl <<endl;
}
};
int main(){
numbers numbers;
numbersVector nv;
int arr[] = {1, 2, 3, 4, 5, 6, 0, 0, 0};
int n = sizeof(arr) / sizeof(arr[0]);
//numbers.randomize(arr, n);
// numbers.printArray(arr, n);
nv.storeInVector(arr,n);
return 0;
}
in my second class i loop over my functions in the first class to generate 10 list, i am now stuck on storing the randomised list into a vector.
My problem is, i can only store numbers from each list into the vector but i would like to store the 10 lists inside the vector.
EG
for (int i = 0; i <numberList.size(); i++)
{
cout <<numberList[i] <<endl;
}
i would want my output to be:
123456000 random calls: 8
02103654 random calls:8
and so on 10 times.
EDITING POST TO BE MORE CLEAR:
so i have an array
arr[] = {1,2,3,4,5,6,0,0,0}
after my randomise function i get a output like this
{2,1,0,0,6,0,4,3,5}
i then create a loop to run my randomise function 10 times.
ie
1)1,0,0,0,2,5,4,3,6
2)6,0,5,0,4,0,3,2,1
3)5,1,0,0,2,0,3,6,4
....
10)2,1,0,0,6,0,4,3,5
i would then like to store each generated list into a vector
IE
vector <int> numlist;
numList[1] = {1,0,0,0,2,5,4,3,6}
numList[2] = {6,0,5,0,4,0,3,2,1}
and so on

Lists aren't flattened in C++ as they are in some languages (notably perl). You need to specify where you want the elements in your new list inserted and which range you want to insert:
numberList.insert(numberList.end(), std::begin(new_list), std::end(new_list);
This would insert the full range of new_list at the end of your numberList.
Also: As #scohe001 mentioned, use <random> supported functions to get good randomization.
Example:
#include <random>
inline std::mt19937& generator() {
static thread_local std::mt19937 gen(std::random_device{}());
return gen;
}
//...
std::shuffle( numberList.begin(), numberList.end(), generator() );
Example after comments:
#include <algorithm>
#include <iostream>
#include <random>
#include <vector>
inline std::mt19937& generator() {
static thread_local std::mt19937 gen(std::random_device{}());
return gen;
}
int main() {
// a vector of vectors (not the most optimal but for this purpose, good enough)
std::vector<std::vector<int>> result;
std::vector<int> array{1, 2, 3, 4, 5, 6, 7, 8, 9};
for(int i = 0; i < 10; ++i) {
std::shuffle(array.begin(), array.end(), generator());
// pushing back an array (or better, a vector) into the vector
result.push_back(array);
}
//-- present the result
std::cout << result.size() << " random permutations (possibly duplicates):\n";
for(const auto& inner : result) {
for(int value : inner) {
std::cout << value << ' ';
}
std::cout << '\n';
}
}
Demo
If you can't use std::shuffle for some reason, you can make your own by adding a function to generate random numbers and then one to loop over the vector and swap random positions in it.
Example:
// generate a random number in the range [min, max]
template<typename T, std::enable_if_t<std::is_integral_v<T>>* = nullptr>
T my_rand(T min, T max) {
std::uniform_int_distribution<T> dist(min, max);
return dist(generator());
}
// a shuffle-like function
void shake_it(std::vector<int>& c) {
for(size_t i = 0; i < c.size(); ++i) {
std::swap(c[i], c[my_rand(0ul, c.size() - 1)]);
}
}
Then call it with shake_it(array); and it should be properly randomized.

Related

How do I generate 100 randomly selected permutations for an array with 16 elements?

I would like to generate 100 randomly selected permutations for an array with 16 elements.
The array = <1, 2, 3, . . . 16>
void printarray(int A[], int size)
{
int i, j;
for(i = 0; i < size; i++)
cout << endl << A[i];
cout << endl;
}
void swap(int *a, int *b)
{
int temp;
temp = *a;
*a = *b;
*b = temp;
}
void permutation(int *A, int start, int end)
{
if(start == end)
{
printarray(A, end + 1);
return;
}
int i;
for(i = start; i <= end; i++)
{
swap((A + i), (A + start));
permutation(A, start + 1, end);
swap((A + i), (A + start));
}
}
I used this to find all the permutations for an array with 4 elements, with the array = <1, 2, 3, 4>. However, I cannot use this to find 100 random permutations for the array with 16 elements.
Additionally, is there a program that I could use to find ALL permutations of the array A = <1, 2, 3, 4> AND only 100 random permutations of another array A = <1, 2, 3, ..., 16>?
This is a brute force approach, but each individual permutation can be stored in an instance of a sequence container allowing only unique values. And, all of the generated permutations can be stored in a set. Then your algorithm would be:
Create empty set of permutations.
Create empty permutation.
Push random values 1-16 into the permutation until its size reaches 16.
Insert permutation into the set.
If the size of the set is less than 100, go back to step (2).
UPDATE:
Here is an implementation that abuses std::unordered_set on coliru.
To do this properly you would need to implement your own container that combines properties of std::vector and std::set.
UPDATE 2:
Here is minimal implementation of unique_sequence container:
template<typename T>
struct unique_sequence
{
auto size() const { return v_.size(); }
auto begin() const { return v_.begin(); }
auto end() const { return v_.end(); }
void push_back(T e)
{
auto [ _, ins ] = s_.insert(e);
if(ins) v_.push_back(std::move(e));
}
auto operator<(const unique_sequence<T>& rhs) const { return v_ < rhs.v_; }
private:
std::vector<T> v_;
std::set<T> s_;
};
You can use it to store individual permutations and the entire set of permutations.
Then, your algorithm becomes:
std::random_device rd;
std::mt19937 gen{ rd() };
std::uniform_int_distribution<> dist{ 1, 16 };
unique_sequence< unique_sequence<int> > perms;
while(perms.size() < 100)
{
unique_sequence<int> perm;
while(perm.size() < 16) perm.push_back(dist(gen));
perms.push_back(std::move(perm));
}
And, here is complete implementation on coliru.
Simple and fast way to generate permutations is to use std::shuffle and std::next_permutation. Shuffle uses the efficient Fisher-Yates algorithm. Note that there are exactly 24 or 4! permutations in the {1,2,3,4} array.
#include <vector>
#include <algorithm>
#include <numeric>
#include <random>
#include <array>
#include <iostream>
template <typename T>
void print(std::vector<T>& v) // print vector of arrays
{
for (const auto& a : v)
{
for (auto x : a)
std::cout << x << ' ';
std::cout << '\n';
}
std::cout << '\n';
}
int main()
{
std::array<int, 4> a4{ 1, 2, 3, 4 }; // use std::iota for longer sequences
std::array<int, 16> a16{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
std::vector<std::array<int, 4>> a4_all;
a4_all.push_back(a4);
for (int i = 1; i < 2*3*4; i++) // there's 2*3*4=24 permuations
{
std::next_permutation(a4.begin(), a4.end());
a4_all.push_back(a4);
}
std::random_device rd;
std::mt19937 g(rd());
std::vector<std::array<int, 16>> vp100(100, a16);
for (int i = 0; i < 100; i++)
std::shuffle(vp100[i].begin(), vp100[i].end(), g); // shuffle is fastest
print(a4_all);
print(vp100);
}
Compiler Explorer

How do I print the following array to show number 1 - 1000000

I want to initialize an array and fill it from 1-1000000. How do I then print the array?
#include<iostream>
using namespace std;
const int holder = 1000000;
int main()
{
int i = 0;
int nums[holder] = {0};
for( int i = 0; i < holder; i++)
{
nums[i] = i+1;
}
return 0;
}
How about something like this:
// First create a vector containing holder elements
std::vector<int> nums(holder);
// Then set each element to the number from 1 to holder, inclusive
std::iota(begin(nums), end(nums), 1);
Then to print it:
// Print each number in the vector, separated by newlines
for (auto num : nums)
{
std::cout << num << '\n';
}
Many parts of this answer should really be part of any decent beginners book. The only "new" thing would be the std::iota call.

pushing back an array of objects into a vector c++

I have a class which takes an array and repopulates the array with the same numbers in random positions.
I now need generate a list that that generates 10 lists of the randomised array, which i believe i have done.
I done this by creating an array of my class object as seen in my code.
class numbers{
private:
int indexCount;
public:
void swap (int *a, int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
void printArray (int arr[], int n)
{
for (int i = 0; i < n; i++)
cout << arr[i] << " ";
cout << "random calls: " << indexCount <<endl;
}
void randomize (int arr[], int n)
{
indexCount=0;
for (int i = n - 1; i > 0; i--)
{
int j = rand() % (i + 1);
indexCount++;
swap(&arr[i], &arr[j]);
}
}
};
int main()
{
srand (time(NULL));
vector <int> list;
int i;
int arr[] = {1, 2, 3, 4, 5, 6, 0, 0, 0};
int n = sizeof(arr) / sizeof(arr[0]);
numbers a[10];
for (i=0; i <10;i++)
{
a[i].randomize(arr,n);
a[i].printArray(arr,n);
// list.push_back(a[i]);
}
return 0;
}
What i am trying to do is is push back the array of object a that contains each list into the list vector such that list[1] would contain {1,0,2,3,0,0,6,5,4} and list[2] would contain another set of numbers.
My question:
how could i push back the array of objects that contain the list of numbers into my vector.
for example:
input:
{1,2,3,4,5,6,0,0,0}
output after printing off the vector
list[0] contains {1,0,2,3,0,0,6,5,4}
list[1] contains {0,0,1,6,0,4,3,5,2}
...
list[9] contains {1,0,2,0,3,4,6,5,0}
A vector cannot be templated with a standard array (such as int a[10]). It can be templated with a pointer (such as int *) and it can be templated with another std::vector.
If you have an array, and you want to store the values of that array in a single index of a vector, you need to copy the elements of the array into the container in the vector. For a std::vector<int*> this looks like this:
std::vector<int*> array_vec;
int numbers[] = {1, 2, 3, 4, 5, 6, 0, 0, 20};
for (std::size_t i = 0; i < 10; i++)
{
int* temp = new int[sizeof(numbers)/sizeof(numbers[0])];
std::copy(&numbers[0], &numbers[9], temp);
array_vec.push_back(temp);
// change numbers so that it's different and we can see that reflected in the output
numbers[8] = i;
}
// print the elements from the vector
for (auto a : array_vec)
{
std::cout << "{ ";
for (std::size_t i = 0; i < 9; i++)
{
std::cout << a[i] << " ";
}
std::cout << "}\n";
}
// we need to delete the memory we allocated
for (auto a : array_vec)
delete[] a;
Note: I do not recommend this method, since it requires the use of new[] and delete[]. There is no reason in modern C++ that you should be manually managing memory like this, especially as a beginner.
The better solution is to use a std::vector<std::vector<int>>. No manual memory management. You take advantage of the std::vector<int> constructor that takes two iterators for int, a start and an end iterator, and emplace_back (instead of push_back):
std::vector<std::vector<int>> vector_vec;
int numbers[] = {1, 2, 3, 4, 5, 6, 0, 0, 20};
for (std::size_t i = 0; i < 10; i++)
{
// create a new std::vector<int> in vector_vec by calling its iterator constructor
vector_vec.emplace_back(numbers, numbers + 9);
numbers[8] = i;
}
// print the elements from the vector
for (auto& v : vector_vec)
{
std::cout << "{ ";
for (auto i : v)
{
std::cout << i << " ";
}
std::cout << "}\n";
}
Note: There is no need now to manually delete[] the memory, since the std::vector manages memory for us.
This answer does not address the issues with the class in your question. That will have to be answered in a different question, if you have one.
If you have questions about the std::vector class, its constructors, or its member functions, please see std::vector.

Minimum Swaps 2 - minimum number of swaps required to sort a vector in ascending order

I'm doing a fairly easy HackerRank test which asks the user to write a function which returns the minimum number of swaps needed to sort an unordered vector in ascending order, e.g.
Start: 1, 2, 5, 4, 3
End: 1, 2, 3, 4, 5
Minimum number of swaps: 1
I've written a function which works on 13/14 test cases, but is too slow for the final case.
#include<iostream>
#include<vector>
using namespace std;
int mimumumSwaps(vector<int> arr) {
int p = 0; // Represents the (index + 1) of arr, e.g. 1, 2, ..., arr.size() + 1
int swaps = 0;
for (vector<int>::iterator i = arr.begin(); i != arr.end(); ++i) {
p++;
if (*i == p) // Element is in the correct place
continue;
else{ // Iterate through the rest of arr until the correct element is found
for (vector<int>::iterator j = arr.begin() + p - 1; j != arr.end(); ++j) {
if (*j == p) {
// Swap the elements
double temp = *j;
*j = *i;
*i = temp;
swaps++;
break;
}
}
}
}
return swaps;
}
int main()
{
vector<int> arr = { 1, 2, 5, 4, 3 };
cout << mimumumSwaps(arr);
}
How would I speed this up further?
Are there any functions I could import which could speed up processes for me?
Is there a way to do this without actually swapping any elements and simply working out the min. swaps which I imagine would speed up the process time?
All permutations can be broken down into cyclic subsets. Find said subsets.
Rotating a subset of K elements by 1 takes K-1 swaps.
Walk array until you find an element out of place. Walk that cycle until it completes. Advance, skipping elements that you've put into a cycle already. Sum (size-1) for each cycle.
To skip, maintain an ordered or unordered set of unexamined items, and fast remove as you examine them.
I think that gives optimal swap count in O(n lg n) or so.
#include <bits/stdc++.h>
#include <vector>
#include <algorithm>
using namespace std;
int minimumSwaps(vector<int> arr)
{
int i,c,j,k,l;
j=c=0;
l=k=arr.size();
while (j<k)
{
i=0;
while (i<l)
{
if (arr[i]!=i+1)
{
swap(arr[i],arr[arr[i]-1]);
c++;
}
i++;
}
k=k/2;
j++;
}
return c;
}
int main()
{
int n,q;
cin >> n;
vector<int> arr;
for (int i = 0; i < n; i++)
{
cin>>q;
arr.push_back(q);
}
int res = minimumSwaps(arr);
cout << res << "\n";
return 0;
}

Vector inside vector (creating chromosomes)

I'm attempting to build a genetic algorithm that can take a certain amount of variables (say 4), and use these in a way so that you could have 2a + 3b + c*c + d = 16. I realise there are more efficient ways to calculate this, but I want to try and build a genetic algorithm to expand later.
I'm starting by trying to create "organisms" that can compete later. What I've done is this:
#include "stdafx.h"
#include <iostream>
#include <vector>
#include <random>
// Set population size
const int population_size = 10;
const int number_of_variables = 4;
int main()
{
// Generate random number
std::random_device rd;
std::mt19937 rng(rd()); // random-number engine (Mersenne-Twister in this case)
std::uniform_int_distribution<int> uni(-10, 10);
// Set gene values.
std::vector<int>chromosome;
std::vector<int>variables;
for (int i = 0; i < number_of_variables; ++i)
{
double rand_num = uni(rng);
variables.push_back (rand_num);
std::cout << variables[i] << "\n";
}
return 0;
}
What happens is it will fill up the number_of_variables vector, and output these just because that makes it clear for me that it's actually doing what I intend for it to do. What I want it to do however is to fill up each "chromosome" with one variables vector, so that for example chromosome 0 would have the values {1, 5, -5, 9} etc.
The following code obviously isn't working, but this is what I'd like it to do:
for (int j = 0; j < population_size; ++j)
{
for (int i = 0; i < number_of_variables; ++i)
{
double rand_num = uni(rng);
variables.push_back(rand_num);
}
chromosome.push_back(variables[j]);
std::cout << chromosome[j] << "\n";
}
Meaning it'd fill up the variables randomly, then chromosome1 would take those 4 values that "variables" took, and repeat. What actually happens is that (I think) it only takes the first value from "variables" and copies that into "chromosome" rather than all 4.
If anyone could help it'd be very much appreciated, I realise this might be simply a rookie mistake that is laughably simply in the eyes of someone more experienced with vectors (which would probably be 99% of the people on this website, hah).
Anyway, thanks :)
#include <iostream>
#include <vector>
#include <random>
// Set population size
const int population_size = 10;
const int number_of_variables = 4;
int main()
{
// Generate random number
std::random_device rd;
std::mt19937 rng(rd()); // random-number engine (Mersenne-Twister in this case)
std::uniform_int_distribution<int> uni(-10, 10);
// Set gene values.
std::vector< std::vector<int>>chromosome;
for( int kp = 0; kp < population_size; kp++ )
{
std::vector<int>variables;
for (int i = 0; i < number_of_variables; ++i)
{
double rand_num = uni(rng);
variables.push_back (rand_num);
}
chromosome.push_back( variables );
}
// display entire population
for( auto c : chromosome )
{
for( auto v : c )
{
std::cout << v << " ";
}
std::cout << "\n";
}
// display 4th member of population
for( auto v : chromosone[ 3 ] )
{
std::cout << v << " ";
}
std::cout << "\n";
return 0;
}
http://ideone.com/2jastJ
You can place a vector inside a vector with the syntax:
std::vector<std::vector<int>>
but you will need to make the outer vector large enough for num_variables.
#include <vector>
#include <cstdlib>
using Individual = std::vector<int>;
using Population = std::vector<Individual>;
// short for std::vector<std::vector<int>>;
const size_t number_of_variables = 8;
int main() {
Population population(10);
for (auto& individual : population) {
individual.resize(number_of_variables);
for (size_t j = 0; j < number_of_variables; ++j) {
individual[j] = j; // replace with random number
}
}
}
Live demo: http://ideone.com/pfufGt