In a binary heap, values are indeed ordered, and a search operation degenerates to a scan of the array if the value/key is >= last value in the array. If however the value you are searching is close to the first (i.e index close to 0), then you will be able to stop early and not scan the array looking for a value that is not there.
For example(C++), an implementation such as this for a Vector that holds the binary heap:
template <class Compare>
uint32_t SearchHeapImpl(const uint32_t idx, const T V, const Compare &cmp) const
{
if (slots[idx] == V)
return idx;
else if (cmp(slots[idx], V))
return UINT32_MAX;
const auto leftChild = 2 * idx + 1;
if (leftChild >= nElements)
return UINT32_MAX;
const auto i = SearchHeapImpl(leftChild, V, cmp);
if (i != UINT32_MAX)
return i;
const auto rightChild = leftChild + 1;
return rightChild >= nElements ? UINT32_MAX : SearchHeapImpl(rightChild, V, cmp);
}
template<class Compare = std::greater<T>>
uint32_t SearchHeap(const T V, const Compare cmp = Compare()) const
{
return nElements ? SearchHeapImpl(0, V, cmp) : UINT32_MAX;
}
will abort search early if cmp(slots[idx], V) == true
As others have mentioned, such data structures are suited for O(1) peek, and O(log n) insert and delete operations. A skip list or a self balancing binary tree(e.g red black trees) are usually a better alternative, if you need O(log n) search (you trade O(1) for peek, for O(log n) for search). Of course, they usually more complex, require more memory, and random access patterns may impact performance due to cache hit misses, etc. Win some, lose some.