Ethan
Ethan

Reputation: 269

Using std::find() With Reverse Iterators

I'm having some trouble understanding how to use reverse iterators with the std::find() function. I believe that if I could see an example that completed the following task, I would be able to understand it perfectly.

So, suppose I have a std::vector I want to search through; however, I do not want to search the typical way. I want to find the first occurrence of a value starting at a certain index and heading towards the start of the vector. To illustrate:


    3 | 4 | 7| 4| 2| 6| 3|
    ^             ^
    |<------------| 
             start_point

Search: find first occurrence, given the above search layout, of 4

Expected Result: index 3

I'm rather sure that one would have to work with reverse iterators in this situation, but I can't figure out how to do it.

Upvotes: 11

Views: 23440

Answers (3)

Daniel Eisener
Daniel Eisener

Reputation: 333

If you're using a std::vector, or any other container that provides Random Access Iterators, you can advance an iterator just using arithmetic, like you would with a pointer. Your example vector has 7 elements, and you want to start at index 4, so you could get a normal iterator to that element just with:

auto i = v.begin() + 4;

For a reverse iterator, you're starting from the back of the vector, not the front, so to get the right offset you have to subtract the desired index+1 from the size, like so:

auto i = v.rbegin() + (v.size() - 5);

This'll be, in your example, 2, so the reverse iterator will start pointing to the last element, then move two spaces toward the beginning, reaching your desired start point.

Then, you can use std::find in the normal way:

auto found = std::find(v.rbegin() + (v.size() - 5), v.rend(), 4);
if(found == v.rend()) {
    std::cout << "No element found." << std::endl;
} else {
    std::cout << "Index " << (v.rend() - found) << std::endl;
}

Remember that, when testing the result of std::find to see if it found anything, you need to use rend(), not end(). When you compare reverse iterators to normal iterators, you're comparing the actual positions, not the offsets from the start, so v.rend() != v.end().

If you don't have Random Access Iterators (for example, in a std::list) you can't use pointer-style arithmetic, so you can instead use std::advance to advance iterators to a specific position and std::distance to get the distance between two iterators.

Upvotes: 9

Vlad from Moscow
Vlad from Moscow

Reputation: 310980

Try something like the following

#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>

int main()
{
    std::vector<int> v = { 3, 4, 7, 4, 2, 6, 3 };
    std::vector<int>::size_type pos = 4;

    auto it = std::find(std::next(v.rbegin(), v.size() - pos), v.rend(), 4);

    if (it != v.rend())
    {
        std::cout << std::distance(v.begin(), it.base() - 1) << std::endl;
    }

}

Upvotes: 4

Kerrek SB
Kerrek SB

Reputation: 477040

First you set the start position:

auto it = v.rbegin() + 2;  // two from the end

Then search:

auto kt = std::find(it, v.rend(), 4);

If kt == v.rend(), no element is found; otherwise we can compute the index from the front with a simple distance computation:

if (kt == v.rend()) {
  std::cerr << "Element 4 not found.\n";
  std::abort();
} else {
  auto n = std::distance(kt, v.rend()) - 1;
  std::cout << "Element 4 found at position v[" << n << "].\n";
}

Upvotes: 7

Related Questions