For this answer I am assuming that you've made an informed decision to use a std::vector
over the other containers available.
Do I really have to do a for-loop to loop through all the elements?
No, you do not have to roll a for
-loop to find an element. The idiomatic way of finding an element in a container is to use an algorithm from the standard library. Whether you should roll your own really depends on the situation.
To help you decide...
Alternative 1:
std::find()
requires a that there is a suitable equality comparator for your node
data type, which may be as simple as this:
bool operator ==(node const& l, node const& r)
{
return l.data == r.data;
}
Then, given a required
node
, you can search for the element. This returns an iterator (or a pointer if you're using a plain old array). If you need the index, this requires a little calculation:
auto i = std::find(v.begin(), v.end(), required);
if (i != v.end())
{
std::cout << i->data << " found at index " << i - v.begin() << std::endl;
}
else
{
std::cout << "Item not found" << std::endl;
}
Alternative 2:
If creating a node
is too expensive or you don't have an equality operator, a better approach would be to use std::find_if()
, which takes a predicate (here I use a lambda because it's succinct, but you could use a functor like in this answer):
// Alternative linear search, using a predicate...
auto i = std::find_if(v.begin(), v.end(), [](node const& n){return n.data == 444;});
if (i != v.end())
{
std::cout << i->data << " found at index " << i - v.begin() << std::endl;
}
else
{
std::cout << "Item not found" << std::endl;
}
Or is there a quicker way?
Again, it depends. std::find()
and std::find_if()
run in linear time (O(n)), the same as your for
-loop.
That said, using std::find()
or std::find_if()
won't involve random access or indexing into the container (they use iterators) but they may require a little bit of extra code compared with your for-
loop.
Alternative 3:
If running time is critical and your array is sorted (say with std::sort()
), you could perform a binary-search, which runs in logarithmic time (O(log n)). std::lower_bound()
implements a binary search for the first element that is not less than the given value. It does not take a predicate unfortunately but requires a suitable less-than comparator for your node
data type, such as:
bool operator <(node const& l, node const& r)
{
return l.data < r.data;
}
The invocation is similar to std::find()
and returns an iterator, but requires an extra check:
auto i = std::lower_bound(v.begin(), v.end(), required);
if (i != v.end() && i->data == required.data)
{
std::cout << i->data << " found at index " << i - v.begin() << std::endl;
}
else
{
std::cout << "Item not found" << std::endl;
}
These functions from the Algorithms Library work with any container supplying an iterator, so switching to another container from std::vector
would be quick and easy to test and to maintain.
The decision is yours!
[See a demonstration here.]