J'ai besoin d'un algorithme de recherche binaire compatible avec les conteneurs C++ STL, quelque chose comme std::binary_search
dans l'en-tête <algorithm>
de la bibliothèque standard, mais j'en ai besoin pour renvoyer l'itérateur qui pointe vers le résultat, pas un simple booléen me disant si l'élément existe.
(Sur une note de côté, à quoi diable pensait le comité habituel quand ils ont défini l'API pour binary_search ?!)
Ma principale préoccupation ici est que j'ai besoin de la vitesse d'une recherche binaire. Ainsi, même si je peux trouver les données avec d'autres algorithmes, comme mentionné ci-dessous, je souhaite profiter du fait que mes données sont triées pour bénéficier des avantages d'un binaire. recherche, pas une recherche linéaire.
jusqu'ici lower_bound
et upper_bound
échouent si la donnée est manquante:
//lousy pseudo code
vector(1,2,3,4,6,7,8,9,0) //notice no 5
iter = lower_bound_or_upper_bound(start,end,5)
iter != 5 && iter !=end //not returning end as usual, instead it'll return 4 or 6
Remarque: Je peux également utiliser un algorithme qui n'appartient pas à l'espace de noms std tant qu'il est compatible avec les conteneurs. Comme, disons, boost::binary_search
.
Il n’existe pas de telles fonctions, mais vous pouvez en écrire une simple avec std::lower_bound
, std::upper_bound
ou std::equal_range
.
Une simple implémentation pourrait être
template<class Iter, class T>
Iter binary_find(Iter begin, Iter end, T val)
{
// Finds the lower bound in at most log(last - first) + 1 comparisons
Iter i = std::lower_bound(begin, end, val);
if (i != end && !(val < *i))
return i; // found
else
return end; // not found
}
Une autre solution consisterait à utiliser un std::set
, qui garantit le classement des éléments et fournit une méthode iterator find(T key)
qui renvoie un itérateur à l'élément donné. Cependant, vos exigences pourraient ne pas être compatibles avec l'utilisation d'un ensemble (par exemple, si vous devez stocker le même élément plusieurs fois).
Vous devriez jeter un oeil à std::equal_range
. Il retournera une paire d'itérateurs à la plage de tous les résultats.
Il y en a un ensemble:
http://www.sgi.com/tech/stl/table_of_contents.html
Rechercher:
Sur une note séparée:
Ils pensaient probablement que la recherche de conteneurs pouvait entraîner plus d'un résultat. Mais parfois, il suffit de tester l’existence d’une version optimisée de Nice.
Si std :: lower_bound est trop bas pour votre goût, vous pouvez vérifier boost :: container :: flat_multiset . C'est un remplacement instantané de std :: multiset implémenté en tant que vecteur en utilisant la recherche binaire.
std :: lower_bound () :)
Vérifiez cette fonction, qBinaryFind :
RandomAccessIterator qBinaryFind ( RandomAccessIterator begin, RandomAccessIterator end, const T & value )
Effectue une recherche binaire de la plage [begin, end) et retourne la position d'une occurrence de valeur. S'il y a n'y a aucune occurrence de valeur, retourne fin.
Les éléments dans la plage [begin, end) doit être trié par ordre croissant; voir qSortir ().
S'il y a beaucoup d'occurrences du même valeur, l’un d’eux pourrait être revenu. Utilisez qLowerBound () ou qUpperBound () si vous avez besoin de plus de précision contrôle.
Exemple:
QVector<int> vect; vect << 3 << 3 << 6 << 6 << 6 << 8; QVector<int>::iterator i = qBinaryFind(vect.begin(), vect.end(), 6); // i == vect.begin() + 2 (or 3 or 4)
La fonction est incluse dans l'en-tête <QtAlgorithms>
qui fait partie de la bibliothèque Qt .
int BinarySearch(vector<int> array,int var)
{
//array should be sorted in ascending order in this case
int start=0;
int end=array.size()-1;
while(start<=end){
int mid=(start+end)/2;
if(array[mid]==var){
return mid;
}
else if(var<array[mid]){
end=mid-1;
}
else{
start=mid+1;
}
}
return 0;
}
Exemple: considérons un tableau, A = [1,2,3,4,5,6,7,8,9] Supposons que vous souhaitiez rechercher l'index de 3 Initialement, début = 0 et fin = 9-1 = 8 Maintenant, depuis début <= fin; milieu = 4; (array [mid] qui vaut 5)! = 3 Maintenant, 3 est situé à gauche de mid, il est inférieur à 5. Par conséquent, nous ne cherchons que la partie gauche du tableau Par conséquent, début = 0 et fin = 3; mid = 2.Depuis un tableau [mid] == 3, nous avons donc obtenu le nombre que nous recherchions. Par conséquent, nous retournons son indice qui est égal à mid.
L'implémentation la plus courte, se demandant pourquoi elle n'est pas incluse dans la bibliothèque standard:
template<class ForwardIt, class T, class Compare=std::less<>>
ForwardIt binary_find(ForwardIt first, ForwardIt last, const T& value, Compare comp={})
{
// Note: BOTH type T and the type after ForwardIt is dereferenced
// must be implicitly convertible to BOTH Type1 and Type2, used in Compare.
// This is stricter than lower_bound requirement (see above)
first = std::lower_bound(first, last, value, comp);
return first != last && !comp(value, *first) ? first : last;
}
Une solution renvoyant la position à l'intérieur de la plage pourrait être la suivante, en n'utilisant que des opérations sur les itérateurs (elle devrait fonctionner même si l'itérateur ne permet pas de calculer)
template <class InputIterator, typename T>
size_t BinarySearchPos(InputIterator first, InputIterator last, const T& val)
{
const InputIterator beginIt = first;
InputIterator element = first;
size_t p = 0;
size_t shift = 0;
while((first <= last))
{
p = std::distance(beginIt, first);
size_t u = std::distance(beginIt, last);
size_t m = (p+u)/2;
std::advance(element, m - shift);
shift = m;
if(*element == val)
return m; // value found at position m
if(val > *element)
first = element++;
else
last = element--;
}
// if you are here the value is not present in the list,
// however if there are the value should be at position u
// (here p==u)
return p;
}