how to use iterator in a recursive function - c++

im studying c++ primer, and in one exercise, i have to do a recursive function that prints the elements on a vector.
I did this:
void printVector(vector<int>::iterator it1, vector<int>::iterator it2) {
cout << *it1 << " ";
if (it1 != it2-1)
printVector((it1 + 1), it2);
}
is there another form to declare it, without the
if(it1!= ***IT2-1***)
i feel like its a mediocre solution couse i cant find another way.
thanks!!

Your function does not accept empty range, which it should, and it is a good idea to put exit condition into begin of a recursive function:
void printVector(vector<int>::iterator it1, vector<int>::iterator it2)
{
if( it1 == it2 ) return;
cout << *it1++ << " ";
printVector(it1, it2);
}

Yes.
void printVector(vector<int>::iterator begin, vector<int>::iterator end)
{
if (begin != end) {
cout << *begin << " ";
printVector(++begin, end)(;
}
}

Yes, you probably want to go at it in another way. It is pretty silly to do recursion when a simple loop will do. Instead, recursion is a tool to use in a more divide an conquer style. I.e. divide into two parts, then apply the same function to the first part and then to the second part.
Usually you then have some kind of cutoff point as to when you can actually do whatever it is you want to do, say for instance that you have less than N number of elements to work with or similar. This example is pretty contrived, because it only brings overhead to do it recursively.
template<class Iter>
void printVector(Iter begin, Iter end)
{
const auto dist = std::distance(begin, end);
if (0 == dist) {
return;
} else if (1 == dist) {
std::cout << *begin;
} else {
// Find the middle
auto pivot = begin + dist/2;
// Apply to first part
printVector(begin, pivot);
// Print separator
std::cout << " ";
// Apply to second part
printVector(pivot, end);
}
}
Please forgive any typos and other issues. Oh, I made it a template as well so that it accepts any random access iterators. That was mostly because it felt annoying to type vector<int>::iterator twice. That should probably be vector<int>::const_iterator by the way.

Related

std::map iterate through keys with index of key

I need to iterate through the keys of a map, but looking ahead to future keys. For example:
map<int, int> m;
vector<int> v;
for(map<int,int>::iterator it = m.begin(); it != m.end(); ++it) {
cout << it->first << "\n";
//is the next element equal to 3?
auto next = it++;
std::cout << "equals 3" << next==3 << std::endl
}
but sometimes I don't want to see the next element (n+1), maybe I want to see the n+10 element, etc. How do I do this? If my list has 100 elements, and I arrive at element 99, then 99+10 is gonna break evrything. Is there a way to test if my iterator can achieve n+10?
The best solution I thougth of is to keep track of an index i and see if I can call it + 10 (that is, if i+10<mapSize). Bus is there a more elegant way? Maybe testing if the n+10 iterator exists or something?
Map does not sound like the appropiate data type for your use case. Try switching to a container that supports random access
I think that your are looking for something like std::advance (Please see here), but with an additional check, if the advance operation was past the end or not.
We can use a small lambda to do this kind of check. Since it uses only an increment operation, it should work for all type of containers.
Please see the following example to illustrate the function:
#include <iostream>
#include <map>
#include <iterator>
using Type = std::map<int, int>;
using TypeIter = Type::iterator;
int main() {
// Lambda to advance a container iterator and check, if that was possible
auto advanceAndCheck = [](const Type& t, const TypeIter& ti, size_t advance) -> std::pair<bool, TypeIter>
{ TypeIter i{ ti }; while ((i != t.end()) && (advance--)) ++i; return { i != t.end(), i }; };
// Test data
Type m{ {1,1}, {2,2}, {3,3}, {4,4}, {5,5} , {6,6} };
// Iterate over container
for (TypeIter it = m.begin(); it != m.end(); ++it) {
// Show some values
std::cout << it->first << "\n";
// Test
{
// Advance and check
auto [OK, itn] = advanceAndCheck(m, it, 1);
if (OK && itn->first == 3) std::cout << "The next Element is 3\n";
}
{
// Advance and check
auto [OK, itn] = advanceAndCheck(m, it, 5);
if (OK && itn->first == 6) std::cout << "The 5th next Element is 6\n";
}
}
}

C++ changing order of vector using iter_swap

I'm passing in a vector with 20 items to the function below. My aim is to change the order of the items in the vector. If the list contains the items 1 2 3 4, I want the end result to be 4 3 2 1. Basically switching the first item with the last, and the second item with the second to last item.
template<typename T>
void changePosition(std::vector<T>& list)
{
std::cout << "Swapping \n";
for (int i = 0; i < list.size(); i++)
{
std::iter_swap(list.begin() + i, list.end() - i);
}
std::cout << "Swapped \n";
}
I just end up getting the error:
c++ vector iterator not dereferencable
Any ideas? I haven't found any samples that achieve what I'm trying to achieve.
std::reverse could indeed be used, the assignment I'm working on requires me to use iter_swap.
list.end() points one past the last element of the vector. So on the first iteration of your loop, list.end() - i will point one past the end, and cannot be dereferenced (or passed to iter_swap).
You should use list.end() - i - 1 instead so that it starts at the last element.
But once you fix this, you will run into another problem: Your code swaps each element twice, so nothing will change. You should stop at the middle of the vector to fix this.
Of course, the best way to reverse a vector is to use the standard function std::reverse instead of reinventing the wheel.
Maybe you should just use std::reverse
I managed to solve the issue with the following:
template<typename T>
void changePosition(std::vector<T>& list)
{
std::cout << "Swapping \n";
typedef std::vector<T>::iterator iterator;
iterator first = list.begin();
iterator last = list.end();
while ((first != last) && (first != --last))
{
std::iter_swap(first, last);
++first;
}
std::cout << "Swapped \n";
}
I doubt this is the best way to go about things but it got the job done. std::reverse should indeed be used by others trying to reverse a vector.
The only reason I resort to iter_swap is because of the assignment I'm working on requiring it.
You can use iter_swap . In fact std::reverse also uses iter_swap
#include<vector>
#include<iostream>
template<class BidirIt>
void reverseVector(BidirIt first, BidirIt last)
{
while ((first != last) && (first != --last)) {
std::iter_swap(first++, last);
}
}
int main()
{
std::vector<int> vec{1,2,3,4};
for(auto v:vec)
{
std::cout<<v<<" ";
}
std::cout<<"After reverting"<<"\n";
reverseVector(vec.begin(),vec.end());
for(auto v:vec)
{
std::cout<<v<<" ";
}
}
Output
1 2 3 4 After reverting
4 3 2 1 Program ended with exit code: 0

Looking for a string in two iterators in C++

In C++, I am aware that you can have multiple iterators. For example, if you had a function that wanted to see the first concurrence of a string in two iterators why would a code look something like this:
Iterator found_it(Iterator one, Iterator two){
while(one != two && (*one) != "Bob"){
one++;
}
return one;
}
*The question said one and two don't necessarily mean begin() and end() - that is what really gave me a mind**** and confusion :S*
Firstly, what happens if Bob was in iterator two? Because you are only returning iterator one? This is what is really confusing me at the moment.
Thanks
When two iterators used as a range for a function or a standard algorithm then the second iterator is not included in the range. That is you should consider the range like
[first, last )
If a function or algorithm like std::find returns the second iterator then it means that the range does not contain the target value.
If the second iterator was included in the range then a question arises what iterator to return when the target value is not found?
Consider for example your own function with the following its calls
template <class Iterator>
Iterator found_it(Iterator one, Iterator two){
while(one != two && (*one) != "Bob"){
one++;
}
return one;
}
//...
std::vector<std::string> v1 = { "Mary", "Bob" };
std::vector<std::string> v2 = { "Mary", "Peter" };
auto it1 = found_it( v1.begin(), v1.end() );
if ( it1 != v1.end() ) std::cout << *it1 << " is present in v1" << std::endl;
else std::cout << "Bob" << " is not present in v1" << std::endl;
auto it2 = found_it( v2.begin(), v2.end() );
if ( it2 != v2.end() ) std::cout << *it2 << " is present in v2" << std::endl;
else std::cout << "Bob" << " is not present in v2" << std::endl;
one and two are the beginning and end (really just beyond the end) of the range that you want to search. This might not be the same as begin() and end() on a container, if you wanted to search only a subrange, or if the iterators don't come from a container at all.
Note that one is changed within the loop; you're not necessarily returning the original value of one.
Your function could be rewritten equivalently like this:
Iterator found_it(Iterator begin, Iterator end) {
Iterator current = begin;
while (current != end && (*current) != "Bob"){
current++;
}
return current;
}
If "Bob" is at iterator two then it is out of the range you wish to search so it should not be found. The second iterator is one past the search range.
So you search from one up to, but not including, two.
When you want to search an entire container then you will pass begin() and end() as arguments to one and two. But iterators give you the flexibility to search for intermediate ranges within a container.
For example what if you want to find all the Bobs?
std::vector<std::string> names {"Tim", "Beryl", "Bob", "Danny", "Bob", "Lou"};
You can get the first one like this:
auto bob1 = fond_it(names.begin(), names.end());
You can get the second one like this:
auto bob2 = fond_it(bob1 + 1, names.end());
Notice you can start the search half way through using bob1 rather than at the beginning.

How is this recursive function automatically converted into iterative function?

I am reading on tail recursion as below
Tail recursion refers to a recursive call at the last line. Tail
recursion can be mechanically eliminated by enclosing the body in a
while loop and replacing the recursive call with one assignment per
function argument.
For example
void print(Iterator start, Iterator end, ostream& out=cout) {
if(start == end)
return;
out << *start++ << endl;
print(start, end, out);
}
is converted to iterative by above specification as
void print(Iterator start, Iterator end, ostream& out=cout) {
while(true) {
if(start == end)
return;
out << *start++ << endl;
}
}
In above passage it is mentioned that "replacing recursive call with one assignment per function argument, but in given example we didn't have any assignment?
Can any one explain and provide example for above explanation about how to translate recursive to iterative function?
The assignment is hidden in the increment operator:
start++;
is in fact an assignment:
start = start+1;
Actually, the example (part one) is not very good.
out << *start++ << endl;
print(start, end, out);
should be
out << *start << endl;
print( start+1, end, out);
I don't think, whatever passage you are referring is important; just focus on the main problem, where you want to convert a recursive function to a normal iterative function, which can be done (effortlessly) as,
void print(Iterator start, Iterator end, ostream& out=cout) {
while(start != end) {
out << *start++ << endl;
}
}
It is hidden a little in C++, but start++ is assigning a new value to each time in the loop.
What they are talking about is, that you assign the arguments of the tail function call to the parameter variables of this function invocation, but in this case it is not neccessary, as you are calling the function with the exact same arguments (because like others said, the change to the first argument start happened before the function call).
Actually, if done precisely, the iterative function should look like
void print(Iterator start, Iterator end, ostream& out=cout) {
while(true) {
if(start == end)
return;
out << *start++ << endl;
start = start;
end = end;
out = out;
}
}
But these assignments are completely unneccessary, even if conpectually correct.
The general conversion of recursive to iterative would look like this.
Original code:
void print(Iterator start, Iterator end, ostream& out=cout) {
if(start == end)
return;
out << *start++ << endl;
print(start, end, out);
}
Converted code:
void print(Iterator start, Iterator end, ostream& out=cout) {
while(true) {
if(start == end)
return;
out << *start << endl;
// One assignment per function argument for 'general' tail recursion
start = start + 1; // (1)
end = end; // (2)
out = out; // (3)
}
}
The three assignments as in the explanation are included. Assignment (1) is embedded in the start++, assignments (2) and (3) are optimized away.

Find nearest points in a vector

Given a sorted vector with a number of values, as in the following example:
std::vector<double> f;
f.pushback(10);
f.pushback(100);
f.pushback(1000);
f.pushback(10000);
I'm looking for the most elegant way to retrieve for any double d the two values that are immediately adjacent to it. For example, given the value "45", I'd like this to return "10" and "100".
I was looking at lower_bound and upper_bound, but they don't do what I want. Can you help?
EDIT: I've decided to post my own anser, as it is somewhat a composite of all the helpful answers that I got in this thread. I've voted up those answers which I thought were most helpful.
Thanks everyone,
Dave
You can grab both values (if they exist) in one call with equal_range(). It returns a std::pair of iterators, with first being the first location and second being the last location in which you could insert the value passed without violating ordering. To strictly meet your criteria, you'd have to decrement the iterator in first, after verifying that it wasn't equal to the vector's begin().
You can use STL's lower_bound to get want you want in a few lines of code. lower_bound uses binary search under the hood, so your runtime is O(log n).
double val = 45;
double lower, upper;
std::vector<double>::iterator it;
it = lower_bound(f.begin(), f.end(), val);
if (it == f.begin()) upper = *it; // no smaller value than val in vector
else if (it == f.end()) lower = *(it-1); // no bigger value than val in vector
else {
lower = *(it-1);
upper = *it;
}
You could simply use a binary search, which will run in O(log(n)).
Here is a Lua snippet (I don't have time to do it in C++, sorry) which does what you want, except for limit conditions (that you did not define anyway) :
function search(value, list, first, last)
if not first then first = 1; last = #list end
if last - first < 2 then
return list[first], list[last]
end
local median = math.ceil(first + (last - first)/2)
if list[median] > value then
return search(value, list, first, median)
else
return search(value, list, median, last)
end
end
local list = {1,10,100,1000}
print(search(arg[1] + 0, list))
It takes the value to search from the command line :
$ lua search.lua 10 # didn't know what to do in this case
10 100
$ lua search.lua 101
100 1000
$ lua search.lua 99
10 100
I'm going to post my own anser, and vote anyone up that helped me to reach it, since this is what I'll use in the end, and you've all helped me reach this conclusion. Comments are welcome.
std::pair<value_type, value_type> GetDivisions(const value_type& from) const
{
if (m_divisions.empty())
throw 0; // Can't help you if we're empty.
std::vector<value_type>::const_iterator it =
std::lower_bound(m_divisions.begin(), m_divisions.end(), from);
if (it == m_divisions.end())
return std::make_pair(m_divisions.back(), m_divisions.back());
else if (it == m_divisions.begin())
return std::make_pair(m_divisions.front(), m_divisions.front());
else
return std::make_pair(*(it - 1), *(it));
}
What if (in your case) d is less than the first element or more than the last? And how to deal with negative values? By the way: guaranteeing that your "d" lives between the first and the last value of your vector you can do like that:
// Your initializations
std::vector<double>::const_iterator sit = f.begin();
double upper, lower;
Here is the rest:
while ( *sit < d ) // if the element is still less than your d
++sit; // increase your iterator
upper = *sit; // here you get the upper value
lower = *(--sit); // and here your lower
Elegant enough? :/
You could do a search in your vector for your value (which would tell you where your value would be if it were in the vector) and then return the value before and after that location. So searching for 45 would tell you it should be at index=1 and then you would return 0 and 1 (depending on your implementation of the search, you'll either get the index of the smaller value or the index of the larger value, but this is easy to check with a couple boundary conditions). This should be able to run in O(log n) where n is the number of elements in your vector.
I would write something like this, didn't test if this compiles, but you get the idea:
template <typename Iterator>
std::pair<Iterator, Iterator> find_best_pair(Iterator first, Iterator last, const typename Iterator::value_type & val)
{
std::pair<Iterator, Iterator> result(last, last);
typename Iterator::difference_type size = std::distance(first, last);
if (size == 2)
{
// if the container is of size 2, the answer is the two elements
result.first = first;
result.first = first;
++result.first;
}
else
{
// must be of at lease size 3
if (size > 2)
{
Iterator second = first;
++second;
Iterator prev_last = last;
--prev_last;
Iterator it(std::lower_bound(second, last, val));
if (it != last)
{
result.first = it;
result.second = it;
if (it != prev_last)
{
// if this is not the previous last
// then the answer is (it, it + 1)
++result.second;
}
else
{
// if this the previous last
// then the answer is (it - 1, it)
--result.first;
}
}
}
}
return result;
}
I wrote up this little function, which seems to fit the more general case you wanted. I haven't tested it totally, but I did write a little test code (included).
#include <algorithm>
#include <iostream>
#include <vector>
template <class RandomAccessIt, class Container, class T>
std::pair<RandomAccessIt, RandomAccessIt> bracket_range(RandomAccessIt begin, RandomAccessIt end, Container& c, T val)
{
typename Container::iterator first;
typename Container::iterator second;
first = std::find(begin, end, val);
//Find the first value after this by iteration
second = first;
if (first == begin){ // Found the first element, so set this to end to indicate no lower values
first = end;
}
else if (first != end && first != begin) --first; //Set this to the first value before the found one, if the value was found
while (second != end && *second == val) ++second;
return std::make_pair(first,second);
}
int main(int argc, _TCHAR* argv[])
{
std::vector<int> values;
std::pair<std::vector<int>::iterator, std::vector<int>::iterator> vals;
for (int i = 1; i < 9; ++i) values.push_back(i);
for (int i = 0; i < 10; ++i){
vals = bracket_range(values.begin(), values.end(),values, i);
if (vals.first == values.end() && vals.second == values.end()){ // Not found at all
std::cout << i << " is not in the container." << std::endl;
}
else if (vals.first == values.end()){ // No value lower
std::cout << i << ": " << "None Lower," << *(vals.second) << std::endl;
}
else if (vals.second == values.end()) { // No value higher
std::cout << i << ": " << *(vals.first) << ", None Higher" << std::endl;
}
else{
std::cout << i << ": " << *(vals.first) << "," << *(vals.second) << std::endl;
}
}
return 0;
}
Based on the code that tunnuz posted, here you have some improvements regarding bound checking:
template<typename T>
void find_enclosing_values(const std::vector<T> &vec, const T &value, T &lower, T &upper, const T &invalid_value)
{
std::vector<T>::const_iterator it = vec.begin();
while (it != vec.end() && *it < value)
++it;
if(it != vec.end())
upper = *it;
else
upper = invalid_value;
if(it == vec.begin())
lower = invalid_value;
else
lower = *(--it);
}
Example of usage:
std::vector<int> v;
v.push_back(3);
v.push_back(7);
v.push_back(10);
int lower, upper;
find_enclosing_values(v, 4, lower, upper, -1);
std::cout<<"lower "<<lower<<" upper "<<upper<<std::endl;
If you have the ability to use some other data structure (not a vector), I'd suggest a B-tree. If you data is unchanging, I believe you can retrieve the result in constant time (logarithmic time at the worst).