Despite what the description looks like, the complexity is linear , because the inner loop (if any) is repeated with a constant number of times (and does not depend on the amount of data).
Since you suggest that your data be in the form of an array (continuous and random indexing) and the use of nested loops, in fact, this is the easiest and easiest way to use all the optimization options and caching of the processor. No matter which โdynamically sortedโ container threshold works poorly, due to the distributed nature of the data.
I will most likely do
for(size_t i=5; i<N-5-1; ++i) { int good=0; //will count the successful comparisons for(size_t j=i-5; j<=i+5; ++j) { if(i==j) continue; //skip the i on i case if(array[j]==value) ++good; } if(good==10) do_stuff(i); }
The inner loop runs completely on cached data (and does not depend on N, so it does not contribute to complexity). Currently, the processor is probably faster than trying to somehow sort the data in a container with many (with non-contiguous storage).
Despite the elegance of many beginner / end approaches, the old KISS indexing wins.
You can parameterize the predicate array[j]==value , as well as 5 (and 10 == 2 * 5) at no cost (the template function will be built-in), which makes this even more general.
if you don't want to insert an inner loop, you can even do it faster with
for(size_t i=5; i<N-5-1; ++i) { int good=0; //will count the successful comparisons for(size_t j=i-5; j<i; ++j) good+=(array[j]==value); for(size_t j=i+1; j<=i+5; ++j) good+=(array[j]==value); if(good==10) do_stuff(i); }
If a loop of 11 elements is divided into two halves (avoiding the check j == i), and the increment on good "calculated" functionally, without branches. This will also lead to faster execution of predictive pipeline processors.
EDIT
It seems that I did not understand that one equal value (not all) is enough.
If this is the case, you can check good!=0 , but you can even shorten:
for(size_t i=5; i<N-5-1; ++i) { bool good=false; //will count the successful comparisons for(size_t j=i-5; j<i && !good; ++j) good|=(array[j]==value); for(size_t j=i+1; j<=i+5 && !good; ++j) good|=(array[j]==value); if(good) do_stuff(i); }
This will break the cycles as soon as a match is found, but makes the cycle more inconspicuous. Removing && !good will not trim the loops, but it can work to the end faster than checking for cropping or not.
If you shorten the loops, you can use = instead of |= , if you don't use the shortcut, using bool has no advantages: |= the compiler point is more complicated than +=