I have a set of ints set something; of length 52.
I am using cycles to iterate through the set like this:
for(iterator A from 1st to 48th element)
for(iterator B from A+1 to 49th element)
for(iterator C from B+1 to 50th element)
for(iterator D from C+1 to 51th element)
for(iterator E from D+1 to 52th element)
{
//save the values from the actual positions in set in array[5]
}
First I tried to make it with an iterator but then I realised that it's not possible to start an iterator from the position of another iterator +1.
Then I tried to use pointers and jump through the values but I correctly assigned only the first value and then I can't jump on second etc.
My code was:
set<int> tableAll;
for(int i=4; i!=52; ++i)
tableAll.insert(i);
const int * flop1 = & * tableAll.begin();
cout << * flop1 << endl;
flop1++;
cout << * flop1 << endl;
When I cout the value of pointer flop1, I get 4 and that's ok, but when I increase it and again cout on screen, I get 0, then, 49, then 0, then 1, then 0 instead 5, 6, 7, 8 and 9.
So how to iterate through my set correctly? I assume using pointers will be faster then some iterator solution.
You absolutely can iterate from an offset from another iterator:
for (auto a(std::begin(mySet)), a_end(std::prev(std::end(mySet), 4));
a != a_end; ++a)
for (auto b(std::next(a)), b_end(std::next(a_end); b != b_end; ++b)
...
In C++03, you can write next and begin for compatibility:
template<typename Iterator> Iterator next(Iterator it, int n = 1) {
std::advance(it, n);
return it;
}
template<typename Iterator> Iterator prev(Iterator it, int n = 1) {
std::advance(it, -n);
return it;
}
for (std::set<int>::const_iterator a(mySet.begin()),
a_end(std::prev(mySet.end(), 4)); a != a_end; ++a)
for (std::set<int>::const_iterator b(std::next(a)),
b_end(std::next(a_end)); b != b_end; ++b)
...
This code is not optimal as it do unneeded iterator comparisions, but works and is simply:
set<int> tableAll;
for(int i=0; i!=52; ++i)
tableAll.insert(i);
for( set<int>::iterator iA=tableAll.begin(); iA != tableAll.end(); ++iA )
for( set<int>::iterator iB=iA; ++iB != tableAll.end(); )
for( set<int>::iterator iC=iB; ++iC != tableAll.end(); )
for( set<int>::iterator iD=iC; ++iD != tableAll.end(); )
for( set<int>::iterator iE=iD; ++iE != tableAll.end(); )
{
cout<<*iA<<' '<<*iB<<' '<<*iC<<' '<<*iD<<' '<<*iE<<endl;
}
I'd suggest to copy the set to a temporary std::vector.
All operations you do in the loops are natural for a vector and O(1) (except for the loops themselves of course)
That's easier to read, to write, and should run a lot faster.
Related
I'm relatively new to C++. I have been trying to use iterators to sort a vector. I'm using bubble sort. I don't want to know if my bubble sort implementation works or not, I just want to know what's crashing my program.
template<typename iter>
void bubbleSort(iter start, iter end) {
for (iter &j = end; j != start; j--) {
for (iter &i = start; i != end; i++) {
// std::cout << *i << std::endl;
if (*i > *(i + 1)) { // this line is where it stops
std::iter_swap(i, i + 1);
}
}
}
std::cout << "ended"; // this line never gets called
}
When the program stops, though, it doesn't show any exceptions. I also try-catched the part where it stopped, but it didn't go in the try catch. Also, whenever I un-comment the first printing line:
std::cout << *i << std::endl;
It prints 1168169449 forever. What is going wrong here?
I'm testing it like this:
std::vector<int> vector = {1, 2, 3, 6, 4, 5};
std::vector<int> temp = vector;
//std::sort(temp.begin(), temp.end());
bubbleSort(vector.begin(), vector.end());
for(auto& num : vector) {
std::cout << num << std::endl;
}
In that line you are dereferencing i + 1, in the last iteration of the cycle it will dereference .end() which invokes undefined behavior, .end() is one past the last element, it can't be dereferenced.
Quick fix is to make your stop condition i != end - 1.
This, though will not fix the the bubble sort implementation which would still be flawed for more complex sequences, take this sample vector:
std::vector<int> vector = {1, 2, 7, 3, 6, 4, 5};
As you can see here, it will not be sorted correctly.
A possible correction would be:
Demo
template<typename iter>
void bubbleSort(iter start, iter end) {
for (iter i = start + 1; i != end; i++) {
for (iter j = start; j != end - 1; j++) {
if (*i < *j) {
std::iter_swap(i, j);
}
}
}
std::cout << "ended" << std::endl;
}
This version, though it works as intended, could be optimized, you could do away with one of the copies at the cost of a slightly less readable code and optimize the number of iterations:
template<typename iter>
void bubbleSort(iter start, iter end) {
while(start != end) {
for (iter j = start; j != end; j++) {
if (*start > *j) {
std::iter_swap(start, j);
}
}
start++;
}
std::cout << "ended" << std::endl;
}
Another thing you could do is to add a condition do to avoid dereferencing and comparing values in the same position, removing some overhead whith less indirection calls.
//...
if(start == j){ // will compare the iterators and skip the loop if they are equal
continue;
}
//...
All things considered, I would use something like this:
template<typename iter>
void bubbleSort(iter start, iter end) {
for (iter i = start; i != end; i++) {
for (iter j = i; j != end; j++) {
if(i == j) {
continue;
}
if (*i > *j) {
std::iter_swap(i, j);
}
}
}
std::cout << "ended" << std::endl;
}
As said in the linked thread, performance is deppendant of several factors among which are the CPU architecture, the SO or the compiler, you must test these solutions and see which one gives you the best performance.
You can also use your compiler optimization options to adjust the compilation to your needs.
You are dereferencing the end iterator which you cannot dereference.
In your loop you go through each iterator until the end. Problem is, you plus the iterator each time. When the iterator is equal to end - 1 and you add that one to it you will receive end which you then dereference. This is undefined behaviour, thus the random number.
You could try changing the loop condition to be != end - 1 which would mean i + 1 could never be end.
Take a vector of vector of int's how do I print all of them from begin to end
for(row=v.begin();row!=v.end();row++){
for(col=row->begin();col!=row->end();col++){
//cout<<?
}
}
What should be used in inner for loop to print each element
Personally, I like iterating over vectors just using a simple for loop from 0 to size(), but this is how you would do it with iterators:
for(vector< vector<int> >::iterator row = v.begin(); row != v.end(); ++row) {
for(vector<int>::iterator col = row->begin(); col != row->end(); ++col) {
cout << *col;
}
}
See: Iteration over std::vector: unsigned vs signed index variable
v.begin() returns an iterator to the beginning of the sequence
v.end() returns an iterator to the element past the end of the sequence
You can loop through your structure using those iterators:
for(auto it_row =v.begin(); it_row!=v.end(); it_row++){
for(auto it_col=it_row->begin();it_col!=it_row->end();it_col++){
cout<<*it_col<<endl;
}
}
In order to deference (get the value) your iterator you need to use the following syntax: *it_col
I used auto (C++ 11) instead of explicitly putting the iterator type:
vector<vector<int>>::const_iterator it_row = v.begin()
vector<int>::const_iterator it_col = it_row->begin()
You can find more details about iterators here.
If you are using c++11 then, you can use range based for loop;
for (const auto & items : v)
for (const auto & item : items)
cout << item;
Is there a clean way to check if I am currently at the second to last element in an iteration in C++? As in:
for (vector::iterator it = v.begin(); it < v.end(); ++it)
{
if (it points to second to last element)
cout << "at second to last";
}
The easiest way would be to compare your iterator against one which does indeed point to the second-to-last. And an easy way to get that is:
vector::iterator secondLast = v.end() - 2;
Assuming of course that v.size() >= 2. But the above doesn't generalize to other container types, for which you could do this:
vector::iterator secondLast = (++v.rbegin()).base();
This should rewind from the last element one step, then convert to a regular (forward) iterator. This will work with other container types like lists.
Or perhaps clearer for the general solution:
vector::iterator secondLast = v.end();
std::advance(secondLast, -2);
Again this requires size of 2 and iterators of random access or bidirectional type.
And finally, a C++11 solution:
auto secondLast = std::prev(v.end(), 2);
Try something like this:
vector::iterator end = v.end(), stl;
bool has_stl = (v.size() >= 2);
if (has_stl) stl = end-2;
for (vector::iterator it = v.begin(); it < end; ++it)
{
if ((has_stl) && (it == stl))
cout << "at second to last";
}
You can do this with some containers:
#include <iostream>
#include <vector>
int main() {
std::vector<int> vec {1, 2, 3, 4, 5};
for (auto it = vec.begin(); it != vec.end(); it++) {
if (vec.end() - it == 3) {
std::cout << *it << std::endl;
}
}
return 0;
}
A solution below:
auto pos = std::next(std::begin(v), std::distance(std::begin(v), std::end(v))-2);
for (auto it = std::begin(v); it != std::end(v); ++it)
{
if (it == pos)
cout << "at second to last: " << *pos;
}
pos is now an iterator pointing to the second to last position, and the functions std::next and std::distance use the best implementation possible (i.e. constant complexity for random iterators, linear complexity for bidirectional/forward iterators).
I have an std::vector, let's say of integers for simplicity.
std::vector<int> ivec;
ivec.push_back(1);
ivec.push_back(2);
... //omitting some push back's 3 to 99
ivec.push_back(100);
The standard way to iterate is known
std::map<int>::iterator it;
for( it = ivec.begin(); it != ivec.end(); it++ )
print();
That iteration will print 1,2,3, ... 100.
I want to traverse all vector elements starting from a predefined index and not from it.begin().
I would like to print
3,4,5,6 ... 99, 100, 1, 2
Can you share your thoughts here?
It might ok to do it in two steps
for( it = ivec.begin()+index; it != ivec.end(); it++ ) and then (if index !=0)
for ( it = ivec.begin; it = it = ivec.begin() + (index-1); it++)
You can either:
develop an iterator class that wraps the vector::iterator and expose the behaviour you like (in particular: ++ checks for end() and replace it with begin() and adjust the other "border values")
fill the vector starting from 3 and wrap at 100, so that standard iteration will look as you want.
The choice depends on what else the vector is purposed and what else that iteration is needed.
I'll assume that you already have a starting iterator. How you get this depends on whether you are using an indexable (vector) type or a forward iterator only, or a keyed type. Then you can do a loop something like this:
type::iterator start_iter = /* something from collection, perhaps begin()+index */
type::iterator cur_iter = start_iter;
do
{
//do something with cur_iter
++cur_iter;
if( cur_iter == collection.end() )
cur_iter = collection.begin();
} while( cur_iter != start_iter );
That's the basic loop.
bool wrapped = false;
for (auto it = vec.begin() + index; (it != vec.begin() + index) || !wrapped; ++it)
{
if (it == vec.end())
{
it = vec.begin();
wrapped = true;
}
std::cout << *it;
}
I know this is a pretty old question, but nobody mentioned std::rotate, which I think, in some cases, can be the right tool for the job.
Modified example from http://www.cplusplus.com/reference/algorithm/rotate/:
#include <iostream> // std::cout
#include <algorithm> // std::rotate
#include <vector> // std::vector
int main () {
std::vector<int> myvector;
// set some values:
for (int i = 1; i < 10; ++i) myvector.push_back(i); // 1, 2, 3, ... 9
std::rotate(myvector.begin(), myvector.begin() + 2, myvector.end());
// 3, 4, 5, 6 ... 9, 1, 2
// print out content:
std::cout << "myvector contains:";
for (auto it = myvector.begin(); it != myvector.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}
cpp.sh/3rdru
Output:
myvector contains: 3 4 5 6 7 8 9 1 2
Note, since my_vector is modified by the std::rotate function, this is neither very efficient nor useful if you just want to iterate the vector once.
However, while this is probably not the best answer to this SO question, I hope it can still provide some value for people with similar issues.
A solution when using a random-access container is very simple, see the code below.
std::vector<int> v ({1,3,4,5,6,7,8,9,10}); /* c++11 */
...
for (int i = 2; i < (10+2); ++i)
std::cout << v[i % 10] << " ";
Method when using containers only having bidirectional/forward iterators:
std::list<int> l ({1,3,4,5,6,7,8,9,10}); /* c++11 */
Iter start = l.begin ();
std::advance (start, 4);
...
Iter it = start;
do {
std::cerr << *it << std::endl;
} while (
(it = ++it == l.end () ? l.begin () : it) != start
);
There are endless ways to do it, and probably all are (more or less) equivalent, so in the end it depends on personal preference and maybe coding style conventions. I would probably do it like:
std::cout << v[idx] << "\n";
for( auto it = v.begin() + idx + 1; it != v.begin()+idx; ++it )
{
if( it == v.end() ) it = v.begin();
std::cout << *it << "\n";
}
I have an assignment to merge two sorted vectors into a third sorted vector. I'm sure the solution to this problem is pretty simple, but my brain is fried at the moment and could use your help.
Basically vectors A and B have a size of 3. They will hold integers such as 1, 2, 3 and 4, 5, 6 respectively. I can't seem to get the syntax of my while loop correctly. I've tried making it a do/while loop, putting parentheses around the cases, and a few other things. It just doesn't seem to be reading the part after the &&.
The first for loop just makes the R vector have the right size. And the second for loop just displays the values of the R vector. The result should print out from 1-6, but I'm only seeing 1-3.
Any help would be appreciated!
void::combine(vector<int> A, vector<int> B, vector<int> R) {
int ia = 0, ib = 0, ir = 0;
for (int i = 0; i < A.size() + B.size(); i++) {
R.push_back(0);
}
while (ia != A.size() && ib != B.size()) {
if (A[ia] < B[ib]) {
R[ir] = A[ia];
ia += 1;
}
else {
R[ir] = B[ib];
ib += 1;
}
ir += 1;
}
for (int i = 0; i < R.size(); i++) {
cout << "L3[" << i << "] = " << R[i] << endl;
}
}
Assuming A contains [1,2,3] and B contains [4,5,6] as you say, this will not add any of the element in the B vector to the R vector.
This is because on the 4th iteration, ia == 3, and so the conjunctive condition is no longer true..
Try changing it to while(ia != A.size() || ib != B.size())
Probably you should avoid the loop altogether:
void combine(vector<int> const& A, vector<int> const& B, vector<int> & R) {
R.resize( A.size() + B.size() );
std::copy( A.begin(), A.end(), R.begin() );
std::copy( B.begin(), B.end(), R.begin()+A.size() );
std::sort( R.begin(), R.end() );
for ( int i = 0; i < R.size(); ++i )
{
cout << "L3[" << i << "] = " << R[i] << endl;
}
}
This is suboptimal as you are first copying and then ordering, but for a small size it will have no impact.
On the actual issues with your code: try to avoid pass-by-value, use resize instead of multiple push_back() to fix the size (note that if the R argument to your function was a non-empty vector then the final size would be bigger than you want). Consider using a return value instead of a reference argument --easier to read. You looped until the first of the counters reached the end, but left the rest of the elements in the other container without copying.
A manual implementation, using iterators would also be simpler:
typedef std::vector<int> vector_t;
vector_t combine( vector_t const & a, vector_t const & b ) {
vector_t r( a.size() + b.size() ); // [*]
vector_t::const_iterator ita = a.begin(), enda = a.end();
vector_t::const_iterator itb = b.begin(), endb = b.end();
vector_t::iterator itr = r.begin();
while ( ita != enda && itb != endb ) {
if ( *ita < *itb )
*itr++ = *ita++;
else
*itr++ = *itb++;
}
if ( ita != enda )
std::copy( ita, enda, itr );
else
std::copy( itb, endb, itr );
return r;
}
I don't know what you're trying to do in the while loop. But if you're just populating the vector R with the elements in A and B, without giving any regard to the order how they're added, then you can use insert function, as:
void::combine(const vector<int> &A, const vector<int> &B, vector<int>& R)
{
R.insert(R.end(), A.begin(), A.end());
R.insert(R.end(), B.begin(), B.end());
}
And if you want to order the vector R, then you can add the following line to the above function:
sort( R.begin(), R.end()); //sorts in increasing order.
You've to #include<algorithm> if you do so. If you want to sort in decreasing order then do this:
bool compare( int a, int b ) { return a > b; }
sort( R.begin(), R.end(), compare); //sorts in decreasing order.
First of all, this smells like a classic merge sort or a piece of it:
http://en.wikipedia.org/wiki/Merge_sort
The objective is to examine elements of the first vector, A, to elements of vector B, and append the elements to a resulting vector R, in order.
Thus if A[i] < B[j], append A[i] to R. With std::vector, there is no need to load the result vector with zeros before starting. See std::vector::push_back().
The following is untested code:
void Sort_Vector(const std::vector& A, const std::vector& B, std::vector& result)
{
unsigned int index_a = 0; // Point to first element in first vector.
unsigned int index_b = 0; // Point to first element in second vector.
result.clear(); // Clear all elements, so size == 0.
while ((index_a < A.size()) && (index_b < B.size())
{
if (A[index_a] < B[index_b])
{
result.push_back(A[index_a]);
++index_a;
}
else // B[index_b] <= A[index_a]
{
result.push_back(B[index_b]);
++index;
}
}
// Append any remaining elements to the result vector.
// Only one of the two loops should be executed,
// the other will fail the comparison expression
// and not execute.
for (; index_a < A.size(); ++index_a)
{
result.push_back(A[index_a]);
}
for (; index_b < B.size(); ++index_b)
{
result.push_back(B[index_b]);
}
return;
}
Notice the difference between my function's signature (parameters) and yours. I'm passing the source vectors as constant data and the result vector is passed by reference which enables my function to modify the caller's result vector.
Also, I'm lazy and using the std::vector::push_back() method. I believe this is more readable than assigning to an element in the result vector. The push_back method implies that I am appending to the vector. The assignment route may catch readers off-guard if they forget that a vector will expand in order resolve the assignment.
that's because of your && condition. as soon as ia == A.size(), the first part of the condition (ia != A.size()) will always evaluate to false and the ib part of your loop won't execute.
to fix it, you can change the condition to : (iA < A.size()) || (iB < B.size())
e.g. with 123 and 456 what is being done right now.
Initialize R to {0,0,0,0,0,0}
until all values from one vector are inserted into R compare candidates and insert smaller one into R, get next candidate from winner list.
and that's all - I don't know that is the purpose of the function if you'll write it I/We can provide solution otherwise just review 2nd point in above form.
The syntax is fine (the code wouldn't compile otherwise), but your loop condition isn't. Given your example A = { 1, 2, 3 } and B = { 4, 5, 6 }, the loop will enter the A[ia] < B[ib] branch three times and increment ia to 3. Once this happens, the first part of the loop condition, ia != A.size() won't be true, and so the loop ends.
Since you already know how many items you need to place in the result vector, I'd recommend replacing your while loop with a simple for one with the same body.