Related
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.
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.
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";
}
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;
}
}
I'm trying to find the index of the last non-zero element in a std::vector<double>. If the last element in the vector is non-zero then it should return the index of that last element.
I believe I can use std::find_if_not, reverse iterators and std::distance, based on this:
std::find_if_not(amounts.rbegin(), amounts.rend(), 0.0)
where amounts is a std::vector<double>, but I'm having difficulty in combining this with std::distance and a forward iterator amounts.begin().
Also, is there a way I can introduce a predicate to compare on, say a tolerance of 1e-8?
I'm using C++11.
Example:
std::vector<double> v{1.32, 1.423, 2.543, 3.534, 4.2, 0};
auto result1 = std::find_if(std::rbegin(v), std::rend(v), [](auto& v) { return std::fabs(v - 0) > std::numeric_limits<double>::epsilon(); } );
if (result1 != std::rend(v)) {
std::cout << *result1 << "\n";
std::cout << std::distance(std::begin(v), (result1 + 1).base());
}
outputs:
4.2
4
[edit]
more explanation on:
std::fabs(v - 0) > std::numeric_limits<double>::epsilon(); }
in OP question there was:
Also, is there a way I can introduce a predicate to compare on, say a tolerance of 1e-8?
so this is such tolerance check, you can replace epsilon use with some other value.
A simple for loop can also do the trick, see live sample: http://ideone.com/dVNOKk
#include <iostream>
#include <vector>
int main() {
std::vector<int> v{1, 2, 3, 4, 1, 2, 3, 0, 4, 1, 2, 3, 4, 0, 0, 0};
for (int i = static_cast<int>(v.size()) - 1; i >= 0; --i) {
if (v.at(i) != 0) {
std::cout << "Last non-zero at: " << i << '\n';
break;
}
}
return 0;
}
Output: Last non-zero at: 12
but I'm having difficulty in combining this with std::distance and a forward iterator amounts.begin()
Reverse iterators have member function base that returns a non-reverse iterator with the relation &*(rit.base() - 1) == &*rit. So, you can use the following:
std::distance(amounts.begin(), found.base()) - 1;
Another option:
amounts.size() - std::distance(amounts.rbegin(), found) - 1
Also, is there a way I can introduce a predicate to compare on, say a tolerance of 1e-8?
Yes. In fact, you must use a predicate, even for the exact comparison, since that's what std::find_if_not expects as the third parameter (instead of value of an element).
I was trying to save some space by using a hashmap to represent a graph instead of adjacency matrix, I ran the same snippet using adjacency matrix, and everything worked fine, But as soon as I changed the data structure to a hashmap, it ran into in infinite loop, The infinite loop is because of the bsf function defined which returns a boolean value and more specifically the error is in line : if ((!visited[v]) && (rGraph[make_pair(u, v)] > 0)) somehow this if condition is not working fine while I represent the rGraph as a hashmap.
I would also like to know if using a hashmap to represent the graph is a preferred way ?
Here is the attached code:
bool bfs(map<pair<int, int>, int> rGraph, int s, int t, int parent[])
{
// Create a visited array and mark all vertices as not visited
bool visited[V];
memset(visited, 0, sizeof(visited));
// Create a queue, enqueue source vertex and mark source vertex
// as visited
queue <int> q;
q.push(s);
visited[s] = true;
parent[s] = -1;
// Standard BFS Loop
while (!q.empty())
{
int u = q.front();
q.pop();
for (int v=0; v<V; v++)
{
cout << "Value of graph at: " <<u << " , " << v << " : " << rGraph[make_pair(u, v)] << "\n";
//cout << "!visited[v] : " << (!visited[v]) << "rGraph[u][v] : " << rGraph[make_pair(u, v)] << "\n";
cout << "if condition : " << ((!visited[v]) && (rGraph[make_pair(u, v)] > 0)) << "\n";
if ((!visited[v]) && (rGraph[make_pair(u, v)] > 0))
{
q.push(v);
parent[v] = u;
visited[v] = true;
}
}
}
// If we reached sink in BFS starting from source, then return
// true, else false
return (visited[t] == true);
}
// Returns tne maximum flow from s to t in the given graph
int fordFulkerson(map<pair<int, int> , int> graph , int s, int t)
{
int u, v;
// Create a residual graph and fill the residual graph with
// given capacities in the original graph as residual capacities
// in residual graph
map<pair<int, int>, int>rGraph; // Residual graph where rGraph[i][j] indicates
// residual capacity of edge from i to j (if there
// is an edge. If rGraph[i][j] is 0, then there is not)
for (u = 0; u < V; u++){
for (v = 0; v < V; v++){
rGraph[make_pair(u, v)] = graph[make_pair(u, v)];
}
}
int parent[V]; // This array is filled by BFS and to store path
int max_flow = 0; // There is no flow initially
// Augment the flow while tere is path from source to sink
while (bfs(rGraph, s, t, parent))
{
// Find minimum residual capacity of the edhes along the
// path filled by BFS. Or we can say find the maximum flow
// through the path found.
int path_flow = INT_MAX;
for (v=t; v!=s; v=parent[v])
{
u = parent[v];
path_flow = min(path_flow, int(rGraph[make_pair(u, v)]));
}
// update residual capacities of the edges and reverse edges
// along the path
for (v=t; v != s; v=parent[v])
{
u = parent[v];
rGraph[make_pair(u, v)] -= path_flow;
rGraph[make_pair(u, v)] += path_flow;
}
// Add path flow to overall flow
max_flow += path_flow;
}
// Return the overall flow
return max_flow;
}
int main(){
map< pair<int, int>, int > graph;
graph[make_pair(0, 1)] = 16;
graph[make_pair(0, 2)] = 13;
graph[make_pair(1, 2)] = 10;
graph[make_pair(1, 3)] = 12;
graph[make_pair(2, 1)] = 4;
graph[make_pair(2, 4)] = 14;
graph[make_pair(3, 2)] = 9;
graph[make_pair(3, 5)] = 20;
graph[make_pair(4, 3)] = 7;
graph[make_pair(4, 5)] = 4;*/
cout << "The maximum possible flow is " << fordFulkerson(graph, 0, 5) << "\n";
return 0;
}
And the adjacency matrix looks like :
int graph[V][V] = { {0, 16, 13, 0, 0, 0},
{0, 0, 10, 12, 0, 0},
{0, 4, 0, 0, 14, 0},
{0, 0, 9, 0, 0, 20},
{0, 0, 0, 7, 0, 4},
{0, 0, 0, 0, 0, 0}};
First, just by looking at your code - you are not using hashmap - you are using map (read: red-black tree in most implementations). Equivalent of "hashmap" would be unordered_map. However, if you want to save memory - you have chosen the right container (unordered_map may consume more memory than map - unordered_map (hashmap) requires continuous region of memory for buckets: and of course all buckets are never occupied).
And now to problems:
When you do rGraph[make_pair(u, v)] you are potentially creating a new element in your map. Indexing operator returns (see cppreference):
reference to an existing element pointed by the index make_pair(u, v)
if the element pointed by make_pair(u, v) does not exist - it creates a new element under that index and returns you the reference to that new element.
If you want to check whether an element exists in the map / unordered_map you have to use the find method:
auto p = make_pair(u, v)];
auto iter = rGraph.find(p);
if(iter != rGraph.end())
{//element 'rGraph[p]' exists
}
else
{//element 'rGraph[p]' does not exist
}
You can also combine (potentially) inserting new element with checking whether the new element was actually created - this is usually more efficient than two separate insert and find (see cppreference):
auto p = make_pair(u, v)];
auto res = rGraph.insert(make_pair(p,1)); //insert value '1'
if(res.second)
{//new element was inserted
}
else
{//element already existed
}
//here res.first is an iterator pointing to the element rGraph[p] - newly inserted or not
You should use the count or find methods to check existence of items in the map, instead of the operator [] because it constructs a new item if it doesn't exist. So change
rGraph[make_pair(u, v)]>0
with
rGraph.count(make_pair(u, v))>0
Also, I might suggest passing any large object (such as the map) by reference. Also, as mentioned here, you can use "unordered_map" which is a hash table, instead of "map" which is a tree, since you don't need the map to be ordered.
This question has been asked before but I cannot find it for C++.
If I have a vector and I have a starting number, does std::algorithm provide me a way to find the next highest missing number?
I can obviously write this in a nested loop, I just cant shake the feeling that I'm reinventing the wheel.
For example, given: vector foo{13,8,3,6,10,1,7,0};
The starting number 0 should find 2.
The starting number 6 should find 9.
The starting number -2 should find -1.
EDIT:
Thus far all the solutions require sorting. This may in fact be required, but a temporary sorted vector would have to be created to accommodate this, as foo must remain unchanged.
At least as far as I know, there's no standard algorithm that directly implements exactly what you're asking for.
If you wanted to do it with something like O(N log N) complexity, you could start by sorting the input. Then use std::upper_bound to find the (last instance of) the number you've asked for (if present). From there, you'd find a number that differs from the previous by more than one. From there you'd scan for a difference greater than 1 between the consecutive numbers in the collection.
One way to do this in real code would be something like this:
#include <iostream>
#include <algorithm>
#include <vector>
#include <numeric>
#include <iterator>
int find_missing(std::vector<int> x, int number) {
std::sort(x.begin(), x.end());
auto pos = std::upper_bound(x.begin(), x.end(), number);
if (*pos - number > 1)
return number + 1;
else {
std::vector<int> diffs;
std::adjacent_difference(pos, x.end(), std::back_inserter(diffs));
auto pos2 = std::find_if(diffs.begin() + 1, diffs.end(), [](int x) { return x > 1; });
return *(pos + (pos2 - diffs.begin() - 1)) + 1;
}
}
int main() {
std::vector<int> x{ 13, 8, 3, 6, 10, 1,7, 0};
std::cout << find_missing(x, 0) << "\n";
std::cout << find_missing(x, 6) << "\n";
}
This is somewhat less than what you'd normally think of as optimal to provide the external appearance of a vector that can/does remain un-sorted (and unmodified in any way). I've done that by creating a copy of the vector, and sorting the copy inside the find_missing function. Thus, the original vector remains unmodified. The disadvantage is obvious: if the vector is large, copying it can/will be expensive. Furthermore, this ends up sorting the vector for every query instead of sorting once, then carrying out as many queries as desired on it.
So I thought I'd post an answer. I don't know anything in std::algorithm that accomplishes this directly, but in combination with vector<bool> you can do this in O(2N).
template <typename T>
T find_missing(const vector<T>& v, T elem){
vector<bool> range(v.size());
elem++;
for_each(v.begin(), v.end(), [&](const T& i){if((i >= elem && i - elem < range.size())range[i - elem] = true;});
auto result = distance(range.begin(), find(range.begin(), range.end(), false));
return result + elem;
}
First you need to sort the vector. Use std::sort for that.
std::lower_bound finds the first element that is greater or equal with a given element. (the elements have to be at least partially ordered)
From there you iterate while you have consecutive elements.
Dealing with duplicates: One way is the way I went: consider consecutive and equal elements when iterating. Another approach is to add a prerequisite that the vector / range contains unique elements. I chose the former because it avoids erasing elements.
Here is how you eliminate duplicates from a sorted vector:
v.erase(std::unique(v.begin(), v.end()), v.end());
My implementation:
// finds the first missing element in the vector v
// prerequisite: v must be sorted
auto firstMissing(std::vector<int> const &v, int elem) -> int {
auto low = std::lower_bound(std::begin(v), std::end(v), elem);
if (low == std::end(v) || *low != elem) {
return elem;
}
while (low + 1 != std::end(v) &&
(*low == *(low + 1) || *low + 1 == *(low + 1))) {
++low;
}
return *low + 1;
}
And a generalized version:
// finds the first missing element in the range [first, last)
// prerequisite: the range must be sorted
template <class It, class T = decltype(*std::declval<It>())>
auto firstMissing(It first, It last, T elem) -> T {
auto low = std::lower_bound(first, last, elem);
if (low == last || *low != elem) {
return elem;
}
while (std::next(low) != last &&
(*low == *std::next(low) || *low + 1 == *std::next(low))) {
std::advance(low, 1);
}
return *low + 1;
}
Test case:
int main() {
auto v = std::vector<int>{13, 8, 3, 6, 10, 1, 7, 7, 7, 0};
std::sort(v.begin(), v.end());
for (auto n : {-2, 0, 5, 6, 20}) {
cout << n << ": " << firstMissing(v, n) << endl;
}
return 0;
}
Result:
-2: -2
0: 2
5: 5
6: 9
20: 20
A note about sorting: From the OP's comments he was searching for a solution that wouldn't modify the vector.
You have to sort the vector for an efficient solution. If modifying the vector is not an option you could create a copy and work on it.
If you are hell-bent on not sorting, there is a brute force solution (very very inefficient - O(n^2)):
auto max = std::max_element(std::begin(v), std::end(v));
if (elem > *max) {
return elem;
}
auto i = elem;
while (std::find(std::begin(v), std::end(v), i) != std::end(v)) {
++i;
}
return i;
First solution:
Sort the vector. Find the starting number and see what number is next.
This will take O(NlogN) where N is the size of vector.
Second solution:
If the range of numbers is small e.g. (0,M) you can create boolean vector of size M. For each number of initial vector make the boolean of that index true. Later you can see next missing number by checking the boolean vector. This will take O(N) time and O(M) auxiliary memory.
I'm trying to find all the ranges [a,b] enclosing int values i, where a <= i <= b. I'm using set<std:pair<int,int>> for the set of ranges.
In the following, using equal range on a vector<int> yields the start and one past the end of the range.
When I do the same for a set<pair<int,int>>, the result starts and ends at one past the end of the range and therefore doesn't include the range enclosing the value.
#include <set>
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int ia[] = {1,2,3,4,5,6,7,8,9,10};
set<int> s1(begin(ia),end(ia));
auto range1 = s1.equal_range(5);
cout << *range1.first << " " << *range1.second << endl; //prints 5 6
pair<int,int> p[] = {make_pair(1,10),
make_pair(11,20),
make_pair(21,30),
make_pair(31,40)};
set<pair<int,int>> s(begin(p), end(p));
auto range = s.equal_range(make_pair(12,12));
cout << range.first->first << " " << range.first->second << endl; //prints 21 30, why?
cout << range.second->first << " " << range.second->second << endl; //prints 21 30
}
prints 5 6
21 30
21 30
Why does equal_range on the set<pair<int,int>> not include the range that encloses the value (12), namely [11.20]
equal_range is behaving completely correctly:
assert( std::make_pair(11, 20) < std::make_pair(12, 12) );
assert( std::make_pair(12, 12) < std::make_pair(21, 30) );
[11,20] is not a range, it's a pair. The pair [12,12] is not "within" another pair, that makes no sense to even say.
[12,12] is not "within" [11,20], it's greater than it. The less-than operator for std::pair compares the first elements first, and only if they're equal does it look at the second elements, so make_pair(11,x) is less than make_pair(12, y) for any x and y
So equal_range tells you that [12,12] would be inserted after [11,20] and before [21,30], which is correct.
If you want to treat pairs as ranges of values you need to write code to do that, not assume the built-in comparisons for pairs does that. You're actually trying to find an int 12 in a range of pairs of ints, but have written code to find a pair [12,12] in a range of pairs of ints. That's not the same thing.
It does not include [11, 20] in the range, because it doesn't include anything in the range. There are no equal elements to [12, 12], so it returns an empty range (represented by the half-open interval [x, x)).
BTW dereferencing the upper bound of the range may invoke undefined behavior, since that may be equal to s.end().
The pair [12, 12] is sorted after [11, 20] and before [21, 30].
std::set::equal_range() includes a range of equal elements. There is no equal element in your set (especially not [11, 20]), so equal_range() returns [21, 30], [21, 30].
equal_range is implemented as to call lower_bound first then call upper_bound to search the rest data set.
template <class ForwardIterator, class T>
pair<ForwardIterator,ForwardIterator>
equal_range ( ForwardIterator first, ForwardIterator last, const T& value )
{
ForwardIterator it = lower_bound (first,last,value);
return make_pair ( it, upper_bound(it,last,value) );
}
Look at your sample:
It calls lower_bound to locate the lower bound of value(which is pair(12,12), which arrives at
pair<int,int> p[] = {make_pair(1,10),
make_pair(11,20),
make_pair(21,30), // <--- lower_bound() points to here
make_pair(31,40)};
Then it calls upper_bound() to search on (21,30),(31,40) and it cound't find it, it returns (21,30)
http://www.cplusplus.com/reference/algorithm/upper_bound/
I don't think your std::set<std::pair<int, int> > won't help you much in intersecting it with your integer: You can find the s.lower_bound(std::make_pair(i + 1, i + 1) to cut off the search but all ranges starting at an index lower than i + 1 can potentially include the value i if the second boundary is large enough. What might help is if you know the maximum size of the ranges in which case you can bound the search towards the front by s.lower_bound(std::make_pair(i - max_range_size, i - max_range_size)). You'll need to inspect each of the ranges in turn to identify if your i falls into them:
auto it = s.lower_bound(std::make_pair(i - max_range_size, i - max_range_size));
auto upper = s.lower_bound(std::make_pair(i + 1, i + 1));
for (; it != upper; ++it) {
if (i < it->second) {
std::cout << "range includes " << i << ": "
<< [" << it.first << ", " << it->second << "]\n";
}
(or something like this...)