Dynamic Nested Loops (C++) - c++
Hello I am looking for a way to write this C++ Code in a general way, so that if a want 20 columns I will not have to write 20 for loops:
for(int i=1; i<6; i++) {
for(int j=i; j<6; j++) {
for(int k=j; k<6; k++) {
for(int m=k; m<6; m++) {
std::cout << i << j << k << m << std::endl;
}
}
}
}
It is important that my numbers follow a >= Order.
I am very grateful for any help.
This recursive function should work:
#include <iostream>
bool inc( int *indexes, int limit, int n )
{
if( ++indexes[n] < limit )
return true;
if( n == 0 ) return false;
if( inc( indexes, limit, n-1 ) ) {
indexes[n] = indexes[n-1];
return true;
}
return false;
}
int main()
{
const size_t N=3;
int indexes[N];
for( size_t i = 0; i < N; ++i ) indexes[i] = 1;
do {
for( size_t i = 0; i < N; ++i ) std::cout << indexes[i] << ' ';
std::cout << std::endl;
} while( inc( indexes, 6, N-1 ) );
return 0;
}
live example
The design here is simple. We take a std::vector each containing a dimension count and a std::vector containing a current index at each dimension.
advance advances the current bundle of dimension indexes by amt (default 1).
void advance( std::vector<size_t>& indexes, std::vector<size_t> const& counts, size_t amt=1 ) {
if (indexes.size() < counts.size())
indexes.resize(counts.size());
for (size_t i = 0; i < counts.size(); ++i ) {
indexes[i]+=amt;
if (indexes[i] < counts[i])
return;
assert(counts[i]!=0);
amt = indexes[i]/counts[i];
indexes[i] = indexes[i]%counts[i];
}
// past the end, don't advance:
indexes = counts;
}
which gives us an advance function for generic n dimensional coordinates.
Next, a filter that tests the restriction you want:
bool vector_ascending( std::vector<size_t> const& v ) {
for (size_t i = 1; (i < v.size()); ++i) {
if (v[i-1] < v[i]) {
return false;
}
}
return true;
}
then a for loop that uses the above:
void print_a_lot( std::vector<size_t> counts ) {
for( std::vector<size_t> v(counts.size()); v < counts; advance(v,counts)) {
// check validity
if (!vector_ascending(v))
continue;
for (size_t x : v)
std::cout << (x+1);
std::cout << std::endl;
}
}
live example.
No recursion needed.
The downside to the above is that it generates 6^20 elements, and then filters. We don't want to make that many elements.
void advance( std::vector<size_t>& indexes, std::vector<size_t> const& counts, size_t amt=1 ) {
if (indexes.size() < counts.size())
indexes.resize(counts.size());
for (size_t i = 0; i < counts.size(); ++i ) {
indexes[i]+=amt;
if (indexes[i] < counts[i])
{
size_t min = indexes[i];
// enforce <= ordering:
for (size_t j = i+i; j < counts.size(); ++j) {
if (indexes[j]<min)
indexes[j]=min;
else
break; // other elements already follow <= transitively
}
assert(vector_ascending(indexes));
return;
}
assert(counts[i]!=0);
amt = indexes[i]/counts[i];
indexes[i] = indexes[i]%counts[i];
}
// past the end, don't advance:
indexes = counts;
}
which should do it without the vector_ascending check in the previous version. (I left the assert in to do testing).
This function works for me, but do not call it with 20 if you want it to finish.
#include <list>
#include <iostream>
std::list<std::list<int>> fun (std::list<std::list<int>> inputlist, int counter)
{
if(counter == 0)
{
return inputlist;
}
else
{
std::list<std::list<int>> outputlist;
for(std::list<int> oldlist : inputlist)
{
for(int i = 1; i<6; i++)
{
std::list<int> newlist = oldlist;
newlist.push_back(i);
outputlist.push_back(newlist);
}
}
return fun(outputlist, counter - 1);
}
}
int main()
{
std::list<int> somelist;
std::list<std::list<int>> listlist;
listlist.push_back(somelist);
std::list<std::list<int>> manynumbers = fun (listlist,5);
for (std::list<int> somenumbers : manynumbers)
{
for(int k : somenumbers)
{
std::cout<<k;
}
std::cout<<std::endl;
}
return 0;
}
Same with Processing (java) here :
void loopFunction(int targetLevel, int actualLevel, int min, int max, String prefix){
/*
targetLevel is the wanted level (20 in your case)
actualLevel starts from 1
min starts from 1
max is the max number displayed (6 in your case)
prefix starts from blank
see usage bellow (in setup function)
*/
for(int m=min; m<max; m++) {
if(targetLevel==actualLevel)
{
println(prefix+ " " + m);
}
else
{
loopFunction(targetLevel, actualLevel+1,m,max,prefix+ " " + m);
}
}
}
void setup(){
loopFunction(10,1,1,6,"");
}
Well, I am not the fastest in writing answer... when I started there was no other answer. Anyhow, here is my version:
#include <iostream>
#include <vector>
using namespace std;
class Multiindex {
public:
typedef std::vector<int> Index;
Multiindex(int dims,int size) :
dims(dims),size(size),index(Index(dims,0)){}
void next(){
int j=dims-1;
while (nextAt(j) && j >= 0){j--;}
}
Index index;
bool hasNext(){return !(index[0]==size-1);}
private:
bool nextAt(int j){
index[j] = index[j]+1;
bool overflow = (index[j]==size);
if (!overflow && j < dims-1){std::fill(index.begin() + j + 1,index.end(),index[j]);}
return overflow;
}
int dims;
int size;
};
int main() {
Multiindex m(4,6);
while (m.hasNext()){
cout << m.index[0] << m.index[1] << m.index[2] << m.index[3] << endl;
m.next();
}
cout << m.index[0] << m.index[1] << m.index[2] << m.index[3] << endl;
return 0;
}
Related
Creating a 3D vector. C++
Help me please. I have a 3d vector. I need to make a new vector from this using existing internal indices. I hope the input and output information will be clear. Input: a = { { {1,1,1,1}, {2,2,2,2}, {3,3,3,3}, {4,4,4,4}, {5,5,5,5}, {6,6,6,6} }, { {10,10,10,10}, {20,20,20,20}, {30,30,30,30}, {40,40,40,40}, {50,50,50,50}, {60,60,60,60} }, { {100,100,100,100}, {200,200,200,200}, {300,300,300,300}, {400,400,400,400}, {500,500,500,500}, {600,600,600,600} }, }; Output: b = { {{ 1,1,1,1}, {10,10,10,10}, {100,100,100,100}}, {{ 2,2,2,2}, {20,20,20,20}, {200,200,200,200}}, {{ 3,3,3,3}, {30,30,30,30}, {300,300,300,300}}, {{ 4,4,4,4}, {40,40,40,40}, {400,400,400,400}}, {{ 5,5,5,5}, {50,50,50,50}, {500,500,500,500}}, {{ 6,6,6,6}, {60,60,60,60}, {600,600,600,600}}, } I don't know how to iterate over indices in a 3D array to create a new 3D array (Output). I want to create a 3D vector from the columns (n-indices) of an existing 3D vector. I have a 3D vector ('Input'). I need to make a 3D vector out of this ('Output'). #include <iostream> #include <vector> using namespace std; void show3D_vector(std::vector<std::vector<std::vector<double>>>& a); void show2D_vector(std::vector<std::vector<double>>& a); template<typename T> std::vector<std::vector<T>> SplitVector(const std::vector<T>& vec, size_t n); int main() { a = { { {1,1,1,1}, {2,2,2,2}, {3,3,3,3}, {4,4,4,4}, {5,5,5,5}, {6,6,6,6} }, { {10,10,10,10}, {20,20,20,20}, {30,30,30,30}, {40,40,40,40}, {50,50,50,50}, {60,60,60,60} }, { {100,100,100,100}, {200,200,200,200}, {300,300,300,300}, {400,400,400,400}, {500,500,500,500}, {600,600,600,600} }, }; } void show3D_vector(std::vector<std::vector<std::vector<double>>>& a) { for (double i = 0; i < a.size(); ++i) { for (double j = 0; j < a[i].size(); ++j) { for (double k = 0; k < a[i][j].size(); ++k) std::cout << a[i][j][k] << " "; std::cout << endl; } std::cout << endl; } } void show2D_vector(std::vector<std::vector<double>>& a) { for (int i = 0; i < a.size(); i++) { for (auto it = a[i].begin(); it != a[i].end(); it++) { std::cout << *it << " "; } std::cout << endl << endl; } } template<typename T> std::vector<std::vector<T>> SplitVector(const std::vector<T>& vec, size_t n) { std::vector<std::vector<T>> outVec; size_t length = vec.size() / n; size_t remain = vec.size() % n; size_t begin = 0; size_t end = 0; for (size_t i = 0; i < std::min(n, vec.size()); ++i) { end += (remain > 0) ? (length + !!(remain--)) : length; outVec.push_back(std::vector<T>(vec.begin() + begin, vec.begin() + end)); begin = end; } return outVec; } Thank you.
You can solve this matrix transpose more succinctly. for(const auto& a1 : a){ b.resize(a1.size()); auto b1 = b.begin(); for(const auto& a2 : a1){ b1->push_back(a2); b1++; } } output is {{1,1,1,1,},{10,10,10,10,},{100,100,100,100,},}, {{2,2,2,2,},{20,20,20,20,},{200,200,200,200,},}, {{3,3,3,3,},{30,30,30,30,},{300,300,300,300,},}, {{4,4,4,4,},{40,40,40,40,},{400,400,400,400,},}, {{5,5,5,5,},{50,50,50,50,},{500,500,500,500,},}, {{6,6,6,6,},{60,60,60,60,},{600,600,600,600,},},
Given your input and output in the example you posted, it seems to be just a transpose of the data, where n would be irrelevant. If this is the case, the following code does this: #include <vector> #include <iostream> void show3D_vector(std::vector<std::vector<std::vector<double>>>& a) { for (size_t i = 0; i < a.size(); ++i) { for (size_t j = 0; j < a[i].size(); ++j) { std::cout << "{"; for (size_t k = 0; k < a[i][j].size(); ++k) { if (k > 0) std::cout << ","; std::cout << a[i][j][k]; } std::cout << "} "; } std::cout << std::endl; } } template<typename T> std::vector<std::vector<std::vector<T>>> Transpose(const std::vector<std::vector<std::vector<T>>>& vec) { if (vec.empty()) return {}; // Construct the output vector std::vector<std::vector<std::vector<T>>> outVect(vec[0].size(), std::vector<std::vector<T>>(vec.size())); // transpose loop for (size_t row = 0; row < vec.size(); ++row) { for (size_t col = 0; col < vec[0].size(); ++col) outVect[col][row] = vec[row][col]; } return outVect; } int main() { std::vector<std::vector<std::vector<double>>> a = { { {1,1,1,1}, {2,2,2,2}, {3,3,3,3}, {4,4,4,4}, {5,5,5,5}, {6,6,6,6} }, { {10,10,10,10}, {20,20,20,20}, {30,30,30,30}, {40,40,40,40}, {50,50,50,50}, {60,60,60,60} }, { {100,100,100,100}, {200,200,200,200}, {300,300,300,300}, {400,400,400,400}, {500,500,500,500}, {600,600,600,600} }, }; auto b = Transpose(a); show3D_vector(b); } Output: {1,1,1,1} {10,10,10,10} {100,100,100,100} {2,2,2,2} {20,20,20,20} {200,200,200,200} {3,3,3,3} {30,30,30,30} {300,300,300,300} {4,4,4,4} {40,40,40,40} {400,400,400,400} {5,5,5,5} {50,50,50,50} {500,500,500,500} {6,6,6,6} {60,60,60,60} {600,600,600,600} The other issue is that your show3d_vector function uses an incorrect type for the for loop counter. It should be size_t, not double.
How to print to the console after every swap using any sorting algorithm?
In my Intro to Computer Science class I am beginning to learn the basics of sorting algorithms. So far, we have gone over Bubble, Selection, and Insertion Sort. After class today, the instructor has requested us to "enhance" the program by adding code to print out the vector/array after every swap during the sorting. I am at a complete loss as to how I would make this happen. I'm thinking something like : if (swapped) { cout << vec << " "; } but without even trying, I'm certain this wouldn't work. Any help is very much appreciated. Here's my code so far: #include <string> #include <cstdlib> #include <ctime> #include <vector> #include <algorithm> using namespace std; vector<int> createVec(int n) { unsigned seed = time(0); srand(seed); vector<int> vec; for (int i = 1; i <= n; ++i) { vec.push_back(rand() % 100 + 1); } return vec; } void showVec(vector<int> vec) { for (int n : vec) { cout << n << " "; } } void bubbleSort(vector<int> &vec) { int n = vec.size(); bool swapped = true; while (swapped) { swapped = false; for (int i = 1; i <= n-1; ++i) { if (vec[i-1] > vec[i]) { swap(vec[i-1], vec[i]); swapped = true; } } } } void selectionSort(vector<int> &vec) { int n = vec.size(); int maxIndex; for (int i = 0; i <= n-2; ++i) { maxIndex = i; for (int j = i+1; j <= n-1; ++j) { if (vec[j] < vec[maxIndex]) { maxIndex = j; } } swap(vec[i], vec[maxIndex]); } } int main() { vector<int> numbers = createVec(20); showVec(numbers); cout << endl; //bubbleSort(numbers); selectionSort(numbers); showVec(numbers); return 0; }
For example in the called function selectionSort substitute this statement swap(vec[i], vec[maxIndex]); for the following statement if ( i != maxIndex ) { swap(vec[i], vec[maxIndex]); showVec( vec ); cout << endl; } Also the function showVec should declare the parameter as having a constant referenced type void showVec( const vector<int> &vec) { for (int n : vec) { cout << n << " "; } }
pushing strings into multidimensional vector c++
I am currently trying to separate a string by the number 2 and pushing the sub characters that i get into a 2d vector, the problem is that every time I try, I get a segmentation fault when I try to push the second row of characters in the vector. After trying a few things, I think the problem lies in the vector "some" after I clear the content of the vector. It seems to me that after the clearing, I am no longer able to push values into the vector. I hope that somebody has any suggestions because I am stuck. std::string str = "11121112111"; std::vector<int> some; std::vector<std::vector<int> > somemore; for (unsigned int i = 0; i < str.length(); i++) { if (str[i] == '2') { somemore.push_back(some); some.clear(); } else { some.push_back(1); } } for (unsigned int i = 0; i <= 3; i++) { for (unsigned int j = 0; j <= 3; j++) { std::cout << somemore[i][j] << std::endl; } }
With c++11 and Boost you can make a much more elegant solution, without the need for loops with an incrementing index. #include <vector> #include <string> #include <iostream> #include <boost/algorithm/string/split.hpp> #include <boost/algorithm/string/classification.hpp> int main() { std::string str = "11121112111"; std::vector<std::string> string_vector; boost::split(string_vector, str, boost::is_any_of("2")); std::vector<std::vector<int>> int_vector; for (auto& s : string_vector) int_vector.push_back(std::vector<int>(s.size(), 1)); for (auto& v : int_vector) for (auto& i : v) std::cout << i << std::endl; return 0; }
I would change the last part: for(unsigned int i = 0; i <=3; i++) { for(unsigned int j = 0; j <=3; j++) { std::cout << somemore[i][j] << std::endl; } } Into this: for(unsigned int i = 0; i < somemore.size(); i++) { for(unsigned int j = 0; j < some.size(); j++) { std::cout << somemore[i][j] << std::endl; } } It is much safer.
As I already mentioned in comments, you have two problems in your code: You are not pushing the last some into somemore because there is no 2 at the end of str. Your last loops are too large - You have a 3x3 matrix but you expect a 4x4 since you go from 0 to 3. By the way, since you are only counting ones, you don't need some: std::string str = "11121112111"; std::vector<std::vector<int>> somemore; size_t count = 0; for (size_t = 0; i < str.length(); i++) { if (str[i] == '2') { somemore.push_back(std::vector<int>(count, 1)); count = 0; } else { ++count; } } for (size_t i = 0; i < somemore.size(); ++i) { for (size_t j = 0; j < somemore[i].size(); ++j) { std::cout << somemore[i][j] << std::endl; } } You could also replace the last two loops with iterators, or if you have c++11 available: for (const auto &s: somemore) { for (const auto &v: s) { std::cout << v << std::endl; } }
In this loop for(unsigned int i = 0; i < str.length(); i++) { if(str[i] == '2') { sommore.push_back(som); som.clear(); } else { som.push_back(1); } } where it is not clear whether som is the vector declared like std::vector<int> some; ^^^^^ the last part of the string std::string str = "11121112111"; ^^^ is ignored by vector sommore. So the vector contains only two elements that corresponds to two 2(s) in the string. As result these loops for(unsigned int i = 0; i <=3; i++) { for(unsigned int j = 0; j <=3; j++) { std::cout << sommore[i][j] << std::endl; } } that use the magic number 3 have undefined behaviour. Even if the vector and its sub-vectors contain 3 elements even in this case conditions i <=3 and j <=3 are wrong. You can adopt the following approach shown in this demonstratrive program #include <iostream> #include <string> #include <vector> int main() { std::vector<std::vector<int>> v; std::string str = "11121112111"; for ( std::string::size_type pos = 0; ( pos = str.find_first_not_of( "2", pos ) ) != std::string::npos; ) { auto n = str.find( "2", pos ); if ( n == std::string::npos ) n = str.size(); v.push_back( std::vector<int>( n - pos, 1 ) ); pos = n; } for ( const auto &row : v ) { for ( int x : row ) std::cout << x; std::cout << std::endl; } } The program output is 111 111 111
Is there any input for which selection sort outperforms bubble sort?
I mean like...partial, full or reverse sorted arrays. I have already tried the following: random, fully sorted, almost sorted, partially sorted, rever sorted and the count of bubble is lesser when it's fully sorted. In all other cases, it's the same. int selectionSort(int a[], int l, int r) { int count = 0; for (int i = l; i < r; i++) { int min = i; for (int j = i + 1; j <= r; j++) { if (a[j] < a[min]) min = j; count++; } if (i != min) swap(a[i], a[min]); } return count; } int bubbleSort(int a[], int l, int r) { int count = 0; bool flag = false; for (int i = l; i < r; i++) { for (int j = r; j > i; j--) { if (a[j-1] > a[j]) { if (flag == false) flag = true; swap(a[j - 1], a[j]); } count++; } if (flag == false) break; } return count; } The count returns the number of comparisons BTW.
Among simple average-case Θ(n2) algorithms, selection sort almost always outperforms bubble sort. Source: Wikipedia
I hinted at this already in comments, but here's some updated code for you that counts both comparisons and exchanges/swaps, and illustrates that for some random input the number of exchanges/swaps is where selection sort outperforms bubble sort. #include <iostream> #include <vector> #include <utility> #include <cassert> using namespace std; struct Stats { int swaps_ = 0, compares_ = 0; }; std::ostream& operator<<(std::ostream& os, const Stats& s) { return os << "{ swaps " << s.swaps_ << ", compares " << s.compares_ << " }"; } Stats selectionSort(std::vector<int>& a, int l, int r) { Stats stats; for (int i = l; i < r; i++) { int min = i; for (int j = i + 1; j <= r; j++) { if (a.at(j) < a.at(min)) min = j; ++stats.compares_; } if (i != min) { swap(a.at(i), a.at(min)); ++stats.swaps_; } } return stats; } Stats bubbleSort(std::vector<int>& a, int l, int r) { Stats stats; bool flag = false; for (int i = l; i < r; i++) { for (int j = r; j > i; j--) { if (a.at(j-1) > a.at(j)) { if (flag == false) flag = true; swap(a.at(j - 1), a.at(j)); ++stats.swaps_; } ++stats.compares_; } if (flag == false) break; } return stats; } int main() { std::vector<int> v1{ 4, 8, 3, 8, 10, -1, 3, 20, 5 }; std::vector<int> v1s = v1; std::cout << "sel " << selectionSort(v1s, 0, v1s.size() - 1); std::vector<int> v1b = v1; std::cout << ", bub " << bubbleSort(v1b, 0, v1b.size() - 1) << '\n'; assert(v1s == v1b); // always a good idea to check the code's doing what you expect... for (int i : v1s) std::cout << i << ' '; std::cout << '\n'; } Output: sel { swaps 6, compares 36 }, bub { swaps 15, compares 36 } -1 3 3 4 5 8 8 10 20 You can observe / copy / fork-and-edit / run the code online here.
Iterating over subsets of any size
I can iterate over the subsets of size 1 for( int a = 0; a < size; a++ ) { or subsets of size 2 for( int a1 = 0; a1 < size; a1++ ) { for( int a2 = a1+1; a2 < size; a2++ ) { or 3 for( int a1 = 0; a1 < size; a1++ ) { for( int a2 = a1+1; a2 < size; a2++ ) { for( int a3 = a2+1; a3 < size; a3++ ) { But how to do this for subsets of size n? This does the job, based on an answer by Adam Rosenfield void iterate(int *a, int i, int size, int n) { int start = 0; if( i > 0 ) start = a[i-1]+1; for(a[i] = start; a[i] < n; a[i]++) { if(i == n-1) { // a is the array of indices of size n for( int k = 0; k < size; k++ ) { printf("%d ",a[k]); } printf("\n"); } else iterate(a, i+1, size, n); } }
You can use recursion: void iterate(int *a, int i, int size, int n) { for(a[i] = 0; a[i] < size; a[i]++) { if(i == n-1) DoStuff(a, n); // a is the array of indices of size n else iterate(a, i+1, size, n); } } ... // Equivalent to 4 nested for loops int a[4]; iterate(a, 0, size, 4);
You likely could do this with some recursion.
Here is something I used for a similar problem. It does not use recursion; rather, it uses a vector of indexes. #include <vector> template<class T> class MultiForVar { std::vector<T> _begin, _end, _vars; inline int dim(){return _vars.size();} public: MultiForVar(std::vector<T> begin, std::vector<T> end) : _begin(begin), _end(end), _vars(_begin) { assert(begin.size() == end.size() and "Starting and ending vector<T> not the same size!" ); } MultiForVar& operator ++() { ++_vars[dim()-1]; for(int d = dim()-1; d > 0; --d) { if( _vars[d] >= _end[d] ) { _vars[d] = _begin[d]; ++_vars[d-1]; } } return *this; } bool done() { /*for(int d = 0; d < dim(); ++d) if( _vars[d] < _end[d] ) return false; return true;*/ return (_vars[0] >= _end[0]); } T operator[](int d) { return _vars.at(d); } int numDimensions(){ return dim(); } std::vector<T>& getRaw(){ return _vars; } };
If I understand what you're asking correctly, another way to do it is to use bit-wise operators: for(int i = 0; i < 1<<size; i++) { for(int j = 0; j < size; j++) { if(i & 1<<j) printf("%d ", a[j]); } printf("\n"); }
You need something the constructs the powerset of the original set. It's been a while since I've written that, but the psuedocode looks like Powerset(a, size) { if(size == 0) return emptyset subseta = Powerset(a, size-1) // Powerset of everything except last element subsetb = appendToAll(a[size-1], subseta) // appends the last element to every set in subseta return union(subseta, subsetb) }